Reduce usage of audio/video codec specifics

BUG=webrtc:15214

Change-Id: I8e68ac149af53529321ab44776c62afe4cc2f61e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/324020
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40960}
This commit is contained in:
Philipp Hancke 2023-10-18 09:23:55 +02:00 committed by WebRTC LUCI CQ
parent 8c1f122452
commit b527699a53
6 changed files with 72 additions and 114 deletions

View File

@ -902,7 +902,7 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
bool criteria_modified = false;
if (webrtc::RtpTransceiverDirectionHasRecv(content->direction())) {
for (const AudioCodec& codec : content->as_audio()->codecs()) {
for (const Codec& codec : content->codecs()) {
if (MaybeAddHandledPayloadType(codec.id)) {
criteria_modified = true;
}
@ -911,7 +911,7 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
last_recv_params_ = recv_params;
if (!UpdateLocalStreams_w(content->as_audio()->streams(), type, error_desc)) {
if (!UpdateLocalStreams_w(content->streams(), type, error_desc)) {
RTC_DCHECK(!error_desc.empty());
return false;
}
@ -1095,7 +1095,7 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
bool criteria_modified = false;
if (webrtc::RtpTransceiverDirectionHasRecv(content->direction())) {
for (const VideoCodec& codec : content->as_video()->codecs()) {
for (const Codec& codec : content->codecs()) {
if (MaybeAddHandledPayloadType(codec.id))
criteria_modified = true;
}

View File

@ -62,15 +62,14 @@ using ::testing::Field;
using ::webrtc::RtpTransceiverDirection;
using ::webrtc::SdpType;
const cricket::AudioCodec kPcmuCodec =
const cricket::Codec kPcmuCodec =
cricket::CreateAudioCodec(0, "PCMU", 64000, 1);
const cricket::AudioCodec kPcmaCodec =
const cricket::Codec kPcmaCodec =
cricket::CreateAudioCodec(8, "PCMA", 64000, 1);
const cricket::AudioCodec kIsacCodec =
const cricket::Codec kIsacCodec =
cricket::CreateAudioCodec(103, "ISAC", 40000, 1);
const cricket::VideoCodec kH264Codec = cricket::CreateVideoCodec(97, "H264");
const cricket::VideoCodec kH264SvcCodec =
cricket::CreateVideoCodec(99, "H264-SVC");
const cricket::Codec kH264Codec = cricket::CreateVideoCodec(97, "H264");
const cricket::Codec kH264SvcCodec = cricket::CreateVideoCodec(99, "H264-SVC");
const uint32_t kSsrc1 = 0x1111;
const uint32_t kSsrc2 = 0x2222;
const uint32_t kSsrc3 = 0x3333;
@ -86,7 +85,6 @@ template <class ChannelT,
class MediaSendChannelInterfaceT,
class MediaReceiveChannelInterfaceT,
class ContentT,
class CodecT,
class MediaInfoT,
class OptionsT>
class Traits {
@ -97,7 +95,6 @@ class Traits {
typedef MediaSendChannelInterfaceT MediaSendChannelInterface;
typedef MediaReceiveChannelInterfaceT MediaReceiveChannelInterface;
typedef ContentT Content;
typedef CodecT Codec;
typedef MediaInfoT MediaInfo;
typedef OptionsT Options;
};
@ -108,7 +105,6 @@ class VoiceTraits : public Traits<cricket::VoiceChannel,
cricket::VoiceMediaSendChannelInterface,
cricket::VoiceMediaReceiveChannelInterface,
cricket::AudioContentDescription,
cricket::AudioCodec,
cricket::VoiceMediaInfo,
cricket::AudioOptions> {};
@ -118,7 +114,6 @@ class VideoTraits : public Traits<cricket::VideoChannel,
cricket::VideoMediaSendChannelInterface,
cricket::VideoMediaReceiveChannelInterface,
cricket::VideoContentDescription,
cricket::VideoCodec,
cricket::VideoMediaInfo,
cricket::VideoOptions> {};
@ -507,8 +502,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
bool CheckNoRtp2() { return media_send_channel2_impl()->CheckNoRtp(); }
void CreateContent(int flags,
const cricket::AudioCodec& audio_codec,
const cricket::VideoCodec& video_codec,
const cricket::Codec& audio_codec,
const cricket::Codec& video_codec,
typename T::Content* content) {
// overridden in specialized classes
}
@ -544,10 +539,6 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
std::unique_ptr<rtc::Thread> thread_;
};
bool CodecMatches(const typename T::Codec& c1, const typename T::Codec& c2) {
return false; // overridden in specialized classes
}
cricket::CandidatePairInterface* last_selected_candidate_pair() {
return last_selected_candidate_pair_;
}
@ -613,8 +604,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
EXPECT_EQ(0U, media_send_channel1_impl()->send_codecs().size());
EXPECT_TRUE(channel1_->SetRemoteContent(&content, SdpType::kAnswer, err));
ASSERT_EQ(1U, media_send_channel1_impl()->send_codecs().size());
EXPECT_TRUE(CodecMatches(content.codecs()[0],
media_send_channel1_impl()->send_codecs()[0]));
EXPECT_EQ(content.codecs()[0],
media_send_channel1_impl()->send_codecs()[0]);
}
// Test that SetLocalContent and SetRemoteContent properly configure
@ -661,8 +652,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
EXPECT_EQ(0U, media_send_channel1_impl()->send_codecs().size());
EXPECT_TRUE(channel1_->SetRemoteContent(&content, SdpType::kAnswer, err));
ASSERT_EQ(1U, media_send_channel1_impl()->send_codecs().size());
EXPECT_TRUE(CodecMatches(content.codecs()[0],
media_send_channel1_impl()->send_codecs()[0]));
EXPECT_EQ(content.codecs()[0],
media_send_channel1_impl()->send_codecs()[0]);
}
// Test that SetLocalContent and SetRemoteContent properly set RTCP
@ -1562,8 +1553,8 @@ std::unique_ptr<cricket::VoiceChannel> ChannelTest<VoiceTraits>::CreateChannel(
template <>
void ChannelTest<VoiceTraits>::CreateContent(
int flags,
const cricket::AudioCodec& audio_codec,
const cricket::VideoCodec& video_codec,
const cricket::Codec& audio_codec,
const cricket::Codec& video_codec,
cricket::AudioContentDescription* audio) {
audio->AddCodec(audio_codec);
audio->set_rtcp_mux((flags & RTCP_MUX) != 0);
@ -1576,13 +1567,6 @@ void ChannelTest<VoiceTraits>::CopyContent(
*audio = source;
}
template <>
bool ChannelTest<VoiceTraits>::CodecMatches(const cricket::AudioCodec& c1,
const cricket::AudioCodec& c2) {
return c1.name == c2.name && c1.clockrate == c2.clockrate &&
c1.bitrate == c2.bitrate && c1.channels == c2.channels;
}
template <>
void ChannelTest<VoiceTraits>::AddLegacyStreamInContent(
uint32_t ssrc,
@ -1649,8 +1633,8 @@ std::unique_ptr<cricket::VideoChannel> ChannelTest<VideoTraits>::CreateChannel(
template <>
void ChannelTest<VideoTraits>::CreateContent(
int flags,
const cricket::AudioCodec& audio_codec,
const cricket::VideoCodec& video_codec,
const cricket::Codec& audio_codec,
const cricket::Codec& video_codec,
cricket::VideoContentDescription* video) {
video->AddCodec(video_codec);
video->set_rtcp_mux((flags & RTCP_MUX) != 0);
@ -1663,12 +1647,6 @@ void ChannelTest<VideoTraits>::CopyContent(
*video = source;
}
template <>
bool ChannelTest<VideoTraits>::CodecMatches(const cricket::VideoCodec& c1,
const cricket::VideoCodec& c2) {
return c1.name == c2.name;
}
template <>
void ChannelTest<VideoTraits>::AddLegacyStreamInContent(
uint32_t ssrc,

View File

@ -2032,13 +2032,11 @@ void MergeCodecsFromDescription(
const webrtc::FieldTrialsView* field_trials) {
for (const ContentInfo* content : current_active_contents) {
if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
const AudioContentDescription* audio =
content->media_description()->as_audio();
MergeCodecs(audio->codecs(), audio_codecs, used_pltypes, field_trials);
MergeCodecs(content->media_description()->codecs(), audio_codecs,
used_pltypes, field_trials);
} else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
const VideoContentDescription* video =
content->media_description()->as_video();
MergeCodecs(video->codecs(), video_codecs, used_pltypes, field_trials);
MergeCodecs(content->media_description()->codecs(), video_codecs,
used_pltypes, field_trials);
}
}
}
@ -2093,23 +2091,21 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer(
VideoCodecs filtered_offered_video_codecs;
for (const ContentInfo& content : remote_offer.contents()) {
if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
const AudioContentDescription* audio =
content.media_description()->as_audio();
for (const AudioCodec& offered_audio_codec : audio->codecs()) {
if (!FindMatchingCodec(audio->codecs(), filtered_offered_audio_codecs,
std::vector<Codec> offered_codecs = content.media_description()->codecs();
for (const Codec& offered_audio_codec : offered_codecs) {
if (!FindMatchingCodec(offered_codecs, filtered_offered_audio_codecs,
offered_audio_codec, field_trials) &&
FindMatchingCodec(audio->codecs(), all_audio_codecs_,
FindMatchingCodec(offered_codecs, all_audio_codecs_,
offered_audio_codec, field_trials)) {
filtered_offered_audio_codecs.push_back(offered_audio_codec);
}
}
} else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
const VideoContentDescription* video =
content.media_description()->as_video();
for (const VideoCodec& offered_video_codec : video->codecs()) {
if (!FindMatchingCodec(video->codecs(), filtered_offered_video_codecs,
std::vector<Codec> offered_codecs = content.media_description()->codecs();
for (const Codec& offered_video_codec : offered_codecs) {
if (!FindMatchingCodec(offered_codecs, filtered_offered_video_codecs,
offered_video_codec, field_trials) &&
FindMatchingCodec(video->codecs(), all_video_codecs_,
FindMatchingCodec(offered_codecs, all_video_codecs_,
offered_video_codec, field_trials)) {
filtered_offered_video_codecs.push_back(offered_video_codec);
}
@ -2151,17 +2147,13 @@ MediaSessionDescriptionFactory::GetOfferedRtpHeaderExtensionsWithIds(
// type is added.
for (const ContentInfo* content : current_active_contents) {
if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
const AudioContentDescription* audio =
content->media_description()->as_audio();
MergeRtpHdrExts(audio->rtp_header_extensions(), &offered_extensions.audio,
&all_regular_extensions, &all_encrypted_extensions,
&used_ids);
MergeRtpHdrExts(content->media_description()->rtp_header_extensions(),
&offered_extensions.audio, &all_regular_extensions,
&all_encrypted_extensions, &used_ids);
} else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
const VideoContentDescription* video =
content->media_description()->as_video();
MergeRtpHdrExts(video->rtp_header_extensions(), &offered_extensions.video,
&all_regular_extensions, &all_encrypted_extensions,
&used_ids);
MergeRtpHdrExts(content->media_description()->rtp_header_extensions(),
&offered_extensions.video, &all_regular_extensions,
&all_encrypted_extensions, &used_ids);
}
}

View File

@ -673,10 +673,7 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test {
bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
RTC_DCHECK(content);
RTC_CHECK(content->media_description());
const cricket::AudioContentDescription* audio_desc =
content->media_description()->as_audio();
RTC_CHECK(audio_desc);
for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
for (const cricket::Codec& codec : content->media_description()->codecs()) {
if (codec.name == "CN") {
return false;
}

View File

@ -1442,7 +1442,7 @@ void BuildMediaLine(const cricket::MediaType media_type,
media_type == cricket::MEDIA_TYPE_VIDEO) {
type = media_type == cricket::MEDIA_TYPE_AUDIO ? kMediaTypeAudio
: kMediaTypeVideo;
for (const cricket::VideoCodec& codec : media_desc->codecs()) {
for (const cricket::Codec& codec : media_desc->codecs()) {
fmt.append(" ");
fmt.append(rtc::ToString(codec.id));
}
@ -2598,7 +2598,7 @@ static const StaticPayloadAudioCodec kStaticPayloadAudioCodecs[] = {
};
void MaybeCreateStaticPayloadAudioCodecs(const std::vector<int>& fmts,
AudioContentDescription* media_desc) {
MediaContentDescription* media_desc) {
if (!media_desc) {
return;
}
@ -2941,7 +2941,7 @@ void UpdateCodec(MediaContentDescription* content_desc,
// Adds or updates existing video codec corresponding to `payload_type`
// according to `packetization`.
void UpdateVideoCodecPacketization(VideoContentDescription* video_desc,
void UpdateVideoCodecPacketization(MediaContentDescription* desc,
int payload_type,
absl::string_view packetization) {
if (packetization != cricket::kPacketizationParamRaw) {
@ -2950,10 +2950,10 @@ void UpdateVideoCodecPacketization(VideoContentDescription* video_desc,
}
// Codec might already have been populated (from rtpmap).
cricket::VideoCodec codec = GetCodecWithPayloadType(
video_desc->type(), video_desc->codecs(), payload_type);
cricket::Codec codec =
GetCodecWithPayloadType(desc->type(), desc->codecs(), payload_type);
codec.packetization = std::string(packetization);
AddOrReplaceCodec(video_desc, codec);
AddOrReplaceCodec(desc, codec);
}
absl::optional<cricket::Codec> PopWildcardCodec(
@ -2984,16 +2984,16 @@ void UpdateFromWildcardCodecs(cricket::MediaContentDescription* desc) {
void AddAudioAttribute(const std::string& name,
absl::string_view value,
AudioContentDescription* audio_desc) {
RTC_DCHECK(audio_desc);
MediaContentDescription* desc) {
RTC_DCHECK(desc);
if (value.empty()) {
return;
}
std::vector<cricket::AudioCodec> codecs = audio_desc->codecs();
for (cricket::AudioCodec& codec : codecs) {
std::vector<cricket::Codec> codecs = desc->codecs();
for (cricket::Codec& codec : codecs) {
codec.params[name] = std::string(value);
}
audio_desc->set_codecs(codecs);
desc->set_codecs(codecs);
}
bool ParseContent(absl::string_view message,
@ -3014,7 +3014,7 @@ bool ParseContent(absl::string_view message,
RTC_DCHECK(transport != NULL);
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
MaybeCreateStaticPayloadAudioCodecs(payload_types, media_desc->as_audio());
MaybeCreateStaticPayloadAudioCodecs(payload_types, media_desc);
}
// The media level "ice-ufrag" and "ice-pwd".
@ -3405,10 +3405,8 @@ bool ParseContent(absl::string_view message,
return ParseFailed("Failed to parse codecs correctly.", error);
}
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string,
media_desc->as_audio());
AddAudioAttribute(kCodecParamPTime, ptime_as_string,
media_desc->as_audio());
AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string, media_desc);
AddAudioAttribute(kCodecParamPTime, ptime_as_string, media_desc);
}
// RFC 5245
@ -3571,29 +3569,29 @@ void UpdateCodec(int payload_type,
int clockrate,
int bitrate,
size_t channels,
AudioContentDescription* audio_desc) {
MediaContentDescription* desc) {
// Codec may already be populated with (only) optional parameters
// (from an fmtp).
cricket::Codec codec = GetCodecWithPayloadType(
audio_desc->type(), audio_desc->codecs(), payload_type);
cricket::Codec codec =
GetCodecWithPayloadType(desc->type(), desc->codecs(), payload_type);
codec.name = std::string(name);
codec.clockrate = clockrate;
codec.bitrate = bitrate;
codec.channels = channels;
AddOrReplaceCodec(audio_desc, codec);
AddOrReplaceCodec(desc, codec);
}
// Updates or creates a new codec entry in the video description according to
// `name`, `width`, `height`, and `framerate`.
void UpdateCodec(int payload_type,
absl::string_view name,
VideoContentDescription* video_desc) {
MediaContentDescription* desc) {
// Codec may already be populated with (only) optional parameters
// (from an fmtp).
cricket::Codec codec = GetCodecWithPayloadType(
video_desc->type(), video_desc->codecs(), payload_type);
cricket::Codec codec =
GetCodecWithPayloadType(desc->type(), desc->codecs(), payload_type);
codec.name = std::string(name);
AddOrReplaceCodec(video_desc, codec);
AddOrReplaceCodec(desc, codec);
}
bool ParseRtpmapAttribute(absl::string_view line,
@ -3656,7 +3654,7 @@ bool ParseRtpmapAttribute(absl::string_view line,
return ParseFailed(line, description.Release(), error);
}
}
UpdateCodec(payload_type, encoding_name, media_desc->as_video());
UpdateCodec(payload_type, encoding_name, media_desc);
} else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
// RFC 4566
// For audio streams, <encoding parameters> indicates the number
@ -3689,7 +3687,7 @@ bool ParseRtpmapAttribute(absl::string_view line,
}
}
UpdateCodec(payload_type, encoding_name, clock_rate, 0, channels,
media_desc->as_audio());
media_desc);
}
return true;
}
@ -3790,8 +3788,7 @@ bool ParsePacketizationAttribute(absl::string_view line,
return false;
}
absl::string_view packetization = packetization_fields[1];
UpdateVideoCodecPacketization(media_desc->as_video(), payload_type,
packetization);
UpdateVideoCodecPacketization(media_desc, payload_type, packetization);
return true;
}

View File

@ -55,7 +55,6 @@
#endif
#include "pc/webrtc_sdp.h"
using cricket::AudioCodec;
using cricket::AudioContentDescription;
using cricket::Candidate;
using cricket::ContentGroup;
@ -77,7 +76,6 @@ using cricket::StreamParams;
using cricket::STUN_PORT_TYPE;
using cricket::TransportDescription;
using cricket::TransportInfo;
using cricket::VideoCodec;
using cricket::VideoContentDescription;
using ::testing::ElementsAre;
using ::testing::Field;
@ -91,9 +89,6 @@ using webrtc::SdpParseError;
using webrtc::SdpType;
using webrtc::SessionDescriptionInterface;
typedef std::vector<AudioCodec> AudioCodecs;
typedef std::vector<Candidate> Candidates;
static const uint32_t kDefaultSctpPort = 5000;
static const uint16_t kUnusualSctpPort = 9556;
static const char kSessionTime[] = "t=0 0\r\n";
@ -1885,7 +1880,7 @@ class WebRtcSdpTest : public ::testing::Test {
GetFirstAudioContentDescription(jdesc_output->description());
ASSERT_TRUE(acd);
ASSERT_FALSE(acd->codecs().empty());
cricket::AudioCodec opus = acd->codecs()[0];
cricket::Codec opus = acd->codecs()[0];
EXPECT_EQ("opus", opus.name);
EXPECT_EQ(111, opus.id);
VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
@ -1894,13 +1889,12 @@ class WebRtcSdpTest : public ::testing::Test {
VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
VerifyCodecParameter(opus.params, "maxaveragebitrate",
params.maxaveragebitrate);
for (size_t i = 0; i < acd->codecs().size(); ++i) {
cricket::AudioCodec codec = acd->codecs()[i];
for (const auto& codec : acd->codecs()) {
VerifyCodecParameter(codec.params, "ptime", params.ptime);
VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
}
cricket::AudioCodec dtmf = acd->codecs()[3];
cricket::Codec dtmf = acd->codecs()[3];
EXPECT_EQ("telephone-event", dtmf.name);
EXPECT_EQ(105, dtmf.id);
EXPECT_EQ(3u,
@ -1958,7 +1952,7 @@ class WebRtcSdpTest : public ::testing::Test {
GetFirstAudioContentDescription(jdesc_output->description());
ASSERT_TRUE(acd);
ASSERT_FALSE(acd->codecs().empty());
cricket::AudioCodec opus = acd->codecs()[0];
cricket::Codec opus = acd->codecs()[0];
EXPECT_EQ(111, opus.id);
EXPECT_TRUE(opus.HasFeedbackParam(cricket::FeedbackParam(
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
@ -2013,7 +2007,7 @@ class WebRtcSdpTest : public ::testing::Test {
AudioContentDescription* audio_desc_;
VideoContentDescription* video_desc_;
SctpDataContentDescription* sctp_desc_;
Candidates candidates_;
std::vector<Candidate> candidates_;
std::unique_ptr<IceCandidateInterface> jcandidate_;
JsepSessionDescription jdesc_;
};
@ -2432,7 +2426,7 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
cricket::AudioContentDescription* audio =
cricket::GetFirstAudioContentDescription(jdesc.description());
AudioCodecs ref_codecs;
cricket::AudioCodecs ref_codecs;
// The codecs in the AudioContentDescription should be in the same order as
// the payload types (<fmt>s) on the m= line.
ref_codecs.push_back(cricket::CreateAudioCodec(0, "PCMU", 8000, 1));
@ -2456,7 +2450,7 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
cricket::AudioContentDescription* audio =
cricket::GetFirstAudioContentDescription(jdesc.description());
cricket::AudioCodec g729 = audio->codecs()[0];
cricket::Codec g729 = audio->codecs()[0];
EXPECT_EQ("G729", g729.name);
EXPECT_EQ(8000, g729.clockrate);
EXPECT_EQ(18, g729.id);
@ -2464,7 +2458,7 @@ TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
ASSERT_TRUE(found != g729.params.end());
EXPECT_EQ(found->second, "yes");
cricket::AudioCodec isac = audio->codecs()[1];
cricket::Codec isac = audio->codecs()[1];
EXPECT_EQ("ISAC", isac.name);
EXPECT_EQ(103, isac.id);
EXPECT_EQ(16000, isac.clockrate);
@ -3405,7 +3399,7 @@ TEST_F(WebRtcSdpTest, DeserializePacketizationAttributeWithIllegalValue) {
GetFirstAudioContentDescription(jdesc_output.description());
ASSERT_TRUE(acd);
ASSERT_THAT(acd->codecs(), testing::SizeIs(1));
cricket::AudioCodec opus = acd->codecs()[0];
cricket::Codec opus = acd->codecs()[0];
EXPECT_EQ(opus.name, "opus");
EXPECT_EQ(opus.id, 111);
@ -3483,7 +3477,7 @@ TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithTelephoneEvent) {
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
cricket::AudioCodecs codecs = acd->codecs();
cricket::AudioCodec dtmf =
cricket::Codec dtmf =
cricket::CreateAudioCodec(105, "telephone-event", 8000, 1);
dtmf.params[""] = "0-15";
codecs.push_back(dtmf);