diff --git a/media/base/codec.cc b/media/base/codec.cc index 7ce7947720..73b93c6560 100644 --- a/media/base/codec.cc +++ b/media/base/codec.cc @@ -15,6 +15,7 @@ #include "api/video_codecs/av1_profile.h" #include "api/video_codecs/h264_profile_level_id.h" #include "api/video_codecs/vp9_profile.h" +#include "media/base/media_constants.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/string_encode.h" @@ -114,10 +115,27 @@ bool FeedbackParams::HasDuplicateEntries() const { return false; } -Codec::Codec(int id, const std::string& name, int clockrate) - : id(id), name(name), clockrate(clockrate) {} +Codec::Codec(Type type, int id, const std::string& name, int clockrate) + : Codec(type, id, name, clockrate, 0) {} +Codec::Codec(Type type, + int id, + const std::string& name, + int clockrate, + size_t channels) + : type(type), + id(id), + name(name), + clockrate(clockrate), + bitrate(0), + channels(channels) {} -Codec::Codec() : id(0), clockrate(0) {} +Codec::Codec(Type type) : Codec(type, 0, "", 0) {} + +Codec::Codec(const webrtc::SdpVideoFormat& c) + : Codec(Type::kVideo, 0, c.name, kVideoCodecClockrate) { + params = c.parameters; + scalability_modes = c.scalability_modes; +} Codec::Codec(const Codec& c) = default; Codec::Codec(Codec&& c) = default; @@ -126,15 +144,19 @@ Codec& Codec::operator=(const Codec& c) = default; Codec& Codec::operator=(Codec&& c) = default; bool Codec::operator==(const Codec& c) const { - return this->id == c.id && // id is reserved in objective-c + return type == c.type && this->id == c.id && // id is reserved in objective-c name == c.name && clockrate == c.clockrate && params == c.params && - feedback_params == c.feedback_params; + feedback_params == c.feedback_params && + (type == Type::kAudio + ? (bitrate == c.bitrate && channels == c.channels) + : (packetization == c.packetization)); } bool Codec::Matches(const Codec& codec, const webrtc::FieldTrialsView* field_trials) const { // Match the codec id/name based on the typical static/dynamic name rules. // Matching is case-insensitive. + // We support the ranges [96, 127] and more recently [35, 65]. // https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1 // Within those ranges we match by codec name, outside by codec id. @@ -151,9 +173,36 @@ bool Codec::Matches(const Codec& codec, (codec.id >= kLowerDynamicRangeMin && codec.id <= kLowerDynamicRangeMax) || (codec.id >= kUpperDynamicRangeMin && codec.id <= kUpperDynamicRangeMax); - return is_id_in_dynamic_range && is_codec_id_in_dynamic_range - ? (absl::EqualsIgnoreCase(name, codec.name)) - : (id == codec.id); + bool matches_id = is_id_in_dynamic_range && is_codec_id_in_dynamic_range + ? (absl::EqualsIgnoreCase(name, codec.name)) + : (id == codec.id); + + auto matches_type_specific = [&]() { + switch (type) { + case Type::kAudio: + // If a nonzero clockrate is specified, it must match the actual + // clockrate. If a nonzero bitrate is specified, it must match the + // actual bitrate, unless the codec is VBR (0), where we just force the + // supplied value. The number of channels must match exactly, with the + // exception that channels=0 is treated synonymously as channels=1, per + // RFC 4566 section 6: " [The channels] parameter is OPTIONAL and may be + // omitted if the number of channels is one." + // Preference is ignored. + // TODO(juberti): Treat a zero clockrate as 8000Hz, the RTP default + // clockrate. + return ((codec.clockrate == 0 /*&& clockrate == 8000*/) || + clockrate == codec.clockrate) && + (codec.bitrate == 0 || bitrate <= 0 || + bitrate == codec.bitrate) && + ((codec.channels < 2 && channels < 2) || + channels == codec.channels); + + case Type::kVideo: + return IsSameCodecSpecific(name, params, codec.name, codec.params); + } + }; + + return matches_id && matches_type_specific(); } bool Codec::MatchesCapability( @@ -213,79 +262,105 @@ webrtc::RtpCodecParameters Codec::ToCodecParameters() const { codec_params.name = name; codec_params.clock_rate = clockrate; codec_params.parameters.insert(params.begin(), params.end()); + + switch (type) { + case Type::kAudio: { + codec_params.num_channels = static_cast(channels); + codec_params.kind = MEDIA_TYPE_AUDIO; + break; + } + case Type::kVideo: { + codec_params.kind = MEDIA_TYPE_VIDEO; + break; + } + } + return codec_params; } +bool Codec::IsMediaCodec() const { + return !IsResiliencyCodec(); +} + +bool Codec::IsResiliencyCodec() const { + return GetResiliencyType() != ResiliencyType::kNone; +} + +Codec::ResiliencyType Codec::GetResiliencyType() const { + if (absl::EqualsIgnoreCase(name, kRedCodecName)) { + return ResiliencyType::kRed; + } + if (absl::EqualsIgnoreCase(name, kUlpfecCodecName)) { + return ResiliencyType::kUlpfec; + } + if (absl::EqualsIgnoreCase(name, kFlexfecCodecName)) { + return ResiliencyType::kFlexfec; + } + if (absl::EqualsIgnoreCase(name, kRtxCodecName)) { + return ResiliencyType::kRtx; + } + return ResiliencyType::kNone; +} + +bool Codec::ValidateCodecFormat() const { + if (id < 0 || id > 127) { + RTC_LOG(LS_ERROR) << "Codec with invalid payload type: " << ToString(); + return false; + } + if (IsResiliencyCodec()) { + return true; + } + + int min_bitrate = -1; + int max_bitrate = -1; + if (GetParam(kCodecParamMinBitrate, &min_bitrate) && + GetParam(kCodecParamMaxBitrate, &max_bitrate)) { + if (max_bitrate < min_bitrate) { + RTC_LOG(LS_ERROR) << "Codec with max < min bitrate: " << ToString(); + return false; + } + } + return true; +} + AudioCodec::AudioCodec(int id, const std::string& name, int clockrate, - int bitrate, + int unused_bitrate, size_t channels) - : Codec(id, name, clockrate), bitrate(bitrate), channels(channels) {} + : Codec(Type::kAudio, id, name, clockrate, channels) {} -AudioCodec::AudioCodec() : Codec(), bitrate(0), channels(0) {} +AudioCodec::AudioCodec() : Codec(Type::kAudio) {} AudioCodec::AudioCodec(const AudioCodec& c) = default; AudioCodec::AudioCodec(AudioCodec&& c) = default; AudioCodec& AudioCodec::operator=(const AudioCodec& c) = default; AudioCodec& AudioCodec::operator=(AudioCodec&& c) = default; -bool AudioCodec::operator==(const AudioCodec& c) const { - return bitrate == c.bitrate && channels == c.channels && Codec::operator==(c); -} - -bool AudioCodec::Matches(const AudioCodec& codec, - const webrtc::FieldTrialsView* field_trials) const { - // If a nonzero clockrate is specified, it must match the actual clockrate. - // If a nonzero bitrate is specified, it must match the actual bitrate, - // unless the codec is VBR (0), where we just force the supplied value. - // The number of channels must match exactly, with the exception - // that channels=0 is treated synonymously as channels=1, per RFC - // 4566 section 6: " [The channels] parameter is OPTIONAL and may be - // omitted if the number of channels is one." - // Preference is ignored. - // TODO(juberti): Treat a zero clockrate as 8000Hz, the RTP default clockrate. - return Codec::Matches(codec, field_trials) && - ((codec.clockrate == 0 /*&& clockrate == 8000*/) || - clockrate == codec.clockrate) && - (codec.bitrate == 0 || bitrate <= 0 || bitrate == codec.bitrate) && - ((codec.channels < 2 && channels < 2) || channels == codec.channels); -} - -std::string AudioCodec::ToString() const { +std::string Codec::ToString() const { char buf[256]; - rtc::SimpleStringBuilder sb(buf); - sb << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate - << ":" << channels << "]"; - return sb.str(); -} -webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const { - webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters(); - codec_params.num_channels = static_cast(channels); - codec_params.kind = MEDIA_TYPE_AUDIO; - return codec_params; -} - -std::string VideoCodec::ToString() const { - char buf[256]; rtc::SimpleStringBuilder sb(buf); - sb << "VideoCodec[" << id << ":" << name; - if (packetization.has_value()) { - sb << ":" << *packetization; + switch (type) { + case Type::kAudio: { + sb << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" + << bitrate << ":" << channels << "]"; + break; + } + case Type::kVideo: { + sb << "VideoCodec[" << id << ":" << name; + if (packetization.has_value()) { + sb << ":" << *packetization; + } + sb << "]"; + break; + } } - sb << "]"; return sb.str(); } -webrtc::RtpCodecParameters VideoCodec::ToCodecParameters() const { - webrtc::RtpCodecParameters codec_params = Codec::ToCodecParameters(); - codec_params.kind = MEDIA_TYPE_VIDEO; - return codec_params; -} - VideoCodec::VideoCodec(int id, const std::string& name) - : Codec(id, name, kVideoCodecClockrate) { + : Codec(Type::kVideo, id, name, kVideoCodecClockrate) { SetDefaultParameters(); } @@ -293,15 +368,11 @@ VideoCodec::VideoCodec(const std::string& name) : VideoCodec(0 /* id */, name) { SetDefaultParameters(); } -VideoCodec::VideoCodec() : Codec() { +VideoCodec::VideoCodec() : Codec(Type::kVideo) { clockrate = kVideoCodecClockrate; } -VideoCodec::VideoCodec(const webrtc::SdpVideoFormat& c) - : Codec(0 /* id */, c.name, kVideoCodecClockrate) { - params = c.parameters; - scalability_modes = c.scalability_modes; -} +VideoCodec::VideoCodec(const webrtc::SdpVideoFormat& c) : Codec(c) {} VideoCodec::VideoCodec(const VideoCodec& c) = default; VideoCodec::VideoCodec(VideoCodec&& c) = default; @@ -318,27 +389,13 @@ void VideoCodec::SetDefaultParameters() { } } -bool VideoCodec::operator==(const VideoCodec& c) const { - return Codec::operator==(c) && packetization == c.packetization; -} - -bool VideoCodec::Matches(const VideoCodec& other, - const webrtc::FieldTrialsView* field_trials) const { - return Codec::Matches(other, field_trials) && - IsSameCodecSpecific(name, params, other.name, other.params); -} - -absl::optional VideoCodec::IntersectPacketization( - const VideoCodec& local_codec, - const VideoCodec& remote_codec) { - if (local_codec.packetization == remote_codec.packetization) { - return local_codec.packetization; - } - return absl::nullopt; -} - VideoCodec VideoCodec::CreateRtxCodec(int rtx_payload_type, int associated_payload_type) { + return CreateVideoRtxCodec(rtx_payload_type, associated_payload_type); +} + +VideoCodec CreateVideoRtxCodec(int rtx_payload_type, + int associated_payload_type) { VideoCodec rtx_codec(rtx_payload_type, kRtxCodecName); rtx_codec.SetParam(kCodecParamAssociatedPayloadType, associated_payload_type); return rtx_codec; @@ -361,28 +418,6 @@ VideoCodec::CodecType VideoCodec::GetCodecType() const { return CODEC_VIDEO; } -bool VideoCodec::ValidateCodecFormat() const { - if (id < 0 || id > 127) { - RTC_LOG(LS_ERROR) << "Codec with invalid payload type: " << ToString(); - return false; - } - if (GetCodecType() != CODEC_VIDEO) { - return true; - } - - // Video validation from here on. - int min_bitrate = -1; - int max_bitrate = -1; - if (GetParam(kCodecParamMinBitrate, &min_bitrate) && - GetParam(kCodecParamMaxBitrate, &max_bitrate)) { - if (max_bitrate < min_bitrate) { - RTC_LOG(LS_ERROR) << "Codec with max < min bitrate: " << ToString(); - return false; - } - } - return true; -} - bool HasLntf(const Codec& codec) { return codec.HasFeedbackParam( FeedbackParam(kRtcpFbParamLntf, kParamValueEmpty)); @@ -461,4 +496,19 @@ void AddH264ConstrainedBaselineProfileToSupportedFormats( } } +AudioCodec CreateAudioCodec(int id, + const std::string& name, + int clockrate, + size_t channels) { + return AudioCodec(id, name, clockrate, 0, channels); +} + +VideoCodec CreateVideoCodec(const std::string& name) { + return VideoCodec(name); +} + +VideoCodec CreateVideoCodec(int id, const std::string& name) { + return VideoCodec(id, name); +} + } // namespace cricket diff --git a/media/base/codec.h b/media/base/codec.h index f0ed25123c..29ebef7971 100644 --- a/media/base/codec.h +++ b/media/base/codec.h @@ -67,17 +67,48 @@ class FeedbackParams { }; struct RTC_EXPORT Codec { + enum class Type { + kAudio, + kVideo, + }; + + enum class ResiliencyType { + kNone, + kRed, + kUlpfec, + kFlexfec, + kRtx, + }; + + Type type; int id; std::string name; int clockrate; + + // Audio only + // Can be used to override the target bitrate in the encoder. + // TODO(orphis): Remove in favor of alternative APIs + int bitrate; + size_t channels; + + // Video only + absl::optional packetization; + absl::InlinedVector + scalability_modes; + // Non key-value parameters such as the telephone-event "0‐15" are // represented using an empty string as key, i.e. {"": "0-15"}. CodecParameterMap params; FeedbackParams feedback_params; + Codec(const Codec& c); + Codec(Codec&& c); + virtual ~Codec(); - // Indicates if this codec is compatible with the specified codec. + // Indicates if this codec is compatible with the specified codec by + // checking the assigned id and profile values for the relevant video codecs. + // H264 levels are not compared. bool Matches(const Codec& codec, const webrtc::FieldTrialsView* field_trials = nullptr) const; bool MatchesCapability(const webrtc::RtpCodecCapability& capability) const; @@ -102,6 +133,19 @@ struct RTC_EXPORT Codec { virtual webrtc::RtpCodecParameters ToCodecParameters() const; + // The codec represent an actual media codec, and not a resiliency codec. + bool IsMediaCodec() const; + // The codec represent a resiliency codec such as RED, RTX or FEC variants. + bool IsResiliencyCodec() const; + ResiliencyType GetResiliencyType() const; + + // Validates a VideoCodec's payload type, dimensions and bitrates etc. If they + // don't make sense (such as max < min bitrate), and error is logged and + // ValidateCodecFormat returns false. + bool ValidateCodecFormat() const; + + std::string ToString() const; + Codec& operator=(const Codec& c); Codec& operator=(Codec&& c); @@ -110,24 +154,24 @@ struct RTC_EXPORT Codec { bool operator!=(const Codec& c) const { return !(*this == c); } protected: - // A Codec can't be created without a subclass. - // Creates a codec with the given parameters. - Codec(int id, const std::string& name, int clockrate); // Creates an empty codec. - Codec(); - Codec(const Codec& c); - Codec(Codec&& c); + explicit Codec(Type type); + // Creates a codec with the given parameters. + Codec(Type type, int id, const std::string& name, int clockrate); + Codec(Type type, + int id, + const std::string& name, + int clockrate, + size_t channels); + explicit Codec(const webrtc::SdpVideoFormat& c); }; struct AudioCodec : public Codec { - int bitrate; - size_t channels; - // Creates a codec with the given parameters. AudioCodec(int id, const std::string& name, int clockrate, - int bitrate, + int unused_bitrate, size_t channels); // Creates an empty codec. AudioCodec(); @@ -135,27 +179,11 @@ struct AudioCodec : public Codec { AudioCodec(AudioCodec&& c); ~AudioCodec() override = default; - // Indicates if this codec is compatible with the specified codec. - bool Matches(const AudioCodec& codec, - const webrtc::FieldTrialsView* field_trials = nullptr) const; - - std::string ToString() const; - - webrtc::RtpCodecParameters ToCodecParameters() const override; - AudioCodec& operator=(const AudioCodec& c); AudioCodec& operator=(AudioCodec&& c); - - bool operator==(const AudioCodec& c) const; - - bool operator!=(const AudioCodec& c) const { return !(*this == c); } }; struct RTC_EXPORT VideoCodec : public Codec { - absl::optional packetization; - absl::InlinedVector - scalability_modes; - // Creates a codec with the given parameters. VideoCodec(int id, const std::string& name); // Creates a codec with the given name and empty id. @@ -167,32 +195,13 @@ struct RTC_EXPORT VideoCodec : public Codec { VideoCodec(VideoCodec&& c); ~VideoCodec() override = default; - // Indicates if this video codec is the same as the other video codec, e.g. if - // they are both VP8 or VP9, or if they are both H264 with the same H264 - // profile. H264 levels however are not compared. - bool Matches(const VideoCodec& codec, - const webrtc::FieldTrialsView* field_trials = nullptr) const; - - std::string ToString() const; - - webrtc::RtpCodecParameters ToCodecParameters() const override; - VideoCodec& operator=(const VideoCodec& c); VideoCodec& operator=(VideoCodec&& c); - bool operator==(const VideoCodec& c) const; + [[deprecated]] static VideoCodec CreateRtxCodec(int rtx_payload_type, + int associated_payload_type); - bool operator!=(const VideoCodec& c) const { return !(*this == c); } - - // Return packetization which both `local_codec` and `remote_codec` support. - static absl::optional IntersectPacketization( - const VideoCodec& local_codec, - const VideoCodec& remote_codec); - - static VideoCodec CreateRtxCodec(int rtx_payload_type, - int associated_payload_type); - - enum CodecType { + enum [[deprecated]] CodecType { CODEC_VIDEO, CODEC_RED, CODEC_ULPFEC, @@ -200,16 +209,21 @@ struct RTC_EXPORT VideoCodec : public Codec { CODEC_RTX, }; - CodecType GetCodecType() const; - // Validates a VideoCodec's payload type, dimensions and bitrates etc. If they - // don't make sense (such as max < min bitrate), and error is logged and - // ValidateCodecFormat returns false. - bool ValidateCodecFormat() const; + [[deprecated]] CodecType GetCodecType() const; private: void SetDefaultParameters(); }; +AudioCodec CreateAudioCodec(int id, + const std::string& name, + int clockrate, + size_t channels); +VideoCodec CreateVideoCodec(const std::string& name); +VideoCodec CreateVideoCodec(int id, const std::string& name); +VideoCodec CreateVideoRtxCodec(int rtx_payload_type, + int associated_payload_type); + // Get the codec setting associated with `payload_type`. If there // is no codec associated with that payload type it returns nullptr. template diff --git a/media/base/codec_unittest.cc b/media/base/codec_unittest.cc index 2851c60e08..e6205ccef1 100644 --- a/media/base/codec_unittest.cc +++ b/media/base/codec_unittest.cc @@ -29,8 +29,8 @@ using cricket::VideoCodec; class TestCodec : public Codec { public: TestCodec(int id, const std::string& name, int clockrate) - : Codec(id, name, clockrate) {} - TestCodec() : Codec() {} + : Codec(Type::kAudio, id, name, clockrate) {} + TestCodec() : Codec(Type::kAudio) {} TestCodec(const TestCodec& c) = default; TestCodec& operator=(const TestCodec& c) = default; }; @@ -74,6 +74,7 @@ TEST(CodecTest, TestAudioCodecOperators) { AudioCodec c2(96, "x", 44100, 20000, 2); AudioCodec c3(96, "A", 48000, 20000, 2); AudioCodec c4(96, "A", 44100, 10000, 2); + c4.bitrate = 10000; AudioCodec c5(96, "A", 44100, 20000, 1); EXPECT_NE(c0, c1); EXPECT_NE(c0, c2); @@ -182,17 +183,6 @@ TEST(CodecTest, TestVideoCodecOperators) { EXPECT_TRUE(c13 == c10); } -TEST(CodecTest, TestVideoCodecIntersectPacketization) { - VideoCodec c1; - c1.packetization = "raw"; - VideoCodec c2; - c2.packetization = "raw"; - VideoCodec c3; - - EXPECT_EQ(VideoCodec::IntersectPacketization(c1, c2), "raw"); - EXPECT_EQ(VideoCodec::IntersectPacketization(c1, c3), absl::nullopt); -} - TEST(CodecTest, TestVideoCodecEqualsWithDifferentPacketization) { VideoCodec c0(100, cricket::kVp8CodecName); VideoCodec c1(100, cricket::kVp8CodecName); @@ -351,7 +341,7 @@ TEST(CodecTest, TestH264CodecMatches) { } TEST(CodecTest, TestSetParamGetParamAndRemoveParam) { - AudioCodec codec; + AudioCodec codec = cricket::CreateAudioCodec(0, "foo", 22222, 2); codec.SetParam("a", "1"); codec.SetParam("b", "x"); @@ -397,17 +387,18 @@ TEST(CodecTest, TestGetCodecType) { const VideoCodec ulpfec_codec(96, "ulpFeC"); const VideoCodec flexfec_codec(96, "FlExFeC-03"); const VideoCodec red_codec(96, "ReD"); - EXPECT_EQ(VideoCodec::CODEC_VIDEO, codec.GetCodecType()); - EXPECT_EQ(VideoCodec::CODEC_RTX, rtx_codec.GetCodecType()); - EXPECT_EQ(VideoCodec::CODEC_ULPFEC, ulpfec_codec.GetCodecType()); - EXPECT_EQ(VideoCodec::CODEC_FLEXFEC, flexfec_codec.GetCodecType()); - EXPECT_EQ(VideoCodec::CODEC_RED, red_codec.GetCodecType()); + EXPECT_TRUE(codec.IsMediaCodec()); + EXPECT_EQ(codec.GetResiliencyType(), Codec::ResiliencyType::kNone); + EXPECT_EQ(rtx_codec.GetResiliencyType(), Codec::ResiliencyType::kRtx); + EXPECT_EQ(ulpfec_codec.GetResiliencyType(), Codec::ResiliencyType::kUlpfec); + EXPECT_EQ(flexfec_codec.GetResiliencyType(), Codec::ResiliencyType::kFlexfec); + EXPECT_EQ(red_codec.GetResiliencyType(), Codec::ResiliencyType::kRed); } TEST(CodecTest, TestCreateRtxCodec) { - VideoCodec rtx_codec = VideoCodec::CreateRtxCodec(96, 120); + VideoCodec rtx_codec = cricket::CreateVideoRtxCodec(96, 120); EXPECT_EQ(96, rtx_codec.id); - EXPECT_EQ(VideoCodec::CODEC_RTX, rtx_codec.GetCodecType()); + EXPECT_EQ(rtx_codec.GetResiliencyType(), Codec::ResiliencyType::kRtx); int associated_payload_type; ASSERT_TRUE(rtx_codec.GetParam(kCodecParamAssociatedPayloadType, &associated_payload_type)); diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index f07ff1a305..3a229f8078 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -46,6 +46,7 @@ #include "call/rtp_transport_controller_send_interface.h" #include "common_video/frame_counts.h" #include "common_video/include/quality_limitation_reason.h" +#include "media/base/codec.h" #include "media/base/media_constants.h" #include "media/base/rid_description.h" #include "media/base/rtp_utils.h" @@ -259,10 +260,10 @@ std::vector GetPayloadTypesAndDefaultCodecs( if (IsCodecValidForLowerRange(codec) || payload_type_upper >= kLastDynamicPayloadTypeUpperRange) { output_codecs.push_back( - VideoCodec::CreateRtxCodec(payload_type_lower++, codec.id)); + cricket::CreateVideoRtxCodec(payload_type_lower++, codec.id)); } else { output_codecs.push_back( - VideoCodec::CreateRtxCodec(payload_type_upper++, codec.id)); + cricket::CreateVideoRtxCodec(payload_type_upper++, codec.id)); } } } @@ -289,7 +290,7 @@ static bool ValidateCodecFormats(const std::vector& codecs) { if (!codecs[i].ValidateCodecFormat()) { return false; } - if (codecs[i].GetCodecType() == VideoCodec::CODEC_VIDEO) { + if (codecs[i].IsMediaCodec()) { has_video = true; } } @@ -522,7 +523,7 @@ std::vector MapCodecs( } std::vector video_codecs; - std::map payload_codec_type; + std::map payload_codec_type; // `rtx_mapping` maps video payload type to rtx payload type. std::map rtx_mapping; std::map rtx_time_mapping; @@ -538,10 +539,10 @@ std::vector MapCodecs( << in_codec.ToString(); return {}; } - payload_codec_type[payload_type] = in_codec.GetCodecType(); + payload_codec_type[payload_type] = in_codec.GetResiliencyType(); - switch (in_codec.GetCodecType()) { - case VideoCodec::CODEC_RED: { + switch (in_codec.GetResiliencyType()) { + case Codec::ResiliencyType::kRed: { if (ulpfec_config.red_payload_type != -1) { RTC_LOG(LS_ERROR) << "Duplicate RED codec: ignoring PT=" << payload_type @@ -553,7 +554,7 @@ std::vector MapCodecs( break; } - case VideoCodec::CODEC_ULPFEC: { + case Codec::ResiliencyType::kUlpfec: { if (ulpfec_config.ulpfec_payload_type != -1) { RTC_LOG(LS_ERROR) << "Duplicate ULPFEC codec: ignoring PT=" << payload_type @@ -565,7 +566,7 @@ std::vector MapCodecs( break; } - case VideoCodec::CODEC_FLEXFEC: { + case Codec::ResiliencyType::kFlexfec: { if (flexfec_payload_type) { RTC_LOG(LS_ERROR) << "Duplicate FLEXFEC codec: ignoring PT=" << payload_type @@ -577,7 +578,7 @@ std::vector MapCodecs( break; } - case VideoCodec::CODEC_RTX: { + case Codec::ResiliencyType::kRtx: { int associated_payload_type; if (!in_codec.GetParam(kCodecParamAssociatedPayloadType, &associated_payload_type) || @@ -595,7 +596,7 @@ std::vector MapCodecs( break; } - case VideoCodec::CODEC_VIDEO: { + case Codec::ResiliencyType::kNone: { video_codecs.emplace_back(); video_codecs.back().codec = in_codec; break; @@ -617,9 +618,9 @@ std::vector MapCodecs( << " which is not in the codec list."; return {}; } - const VideoCodec::CodecType associated_codec_type = it->second; - if (associated_codec_type != VideoCodec::CODEC_VIDEO && - associated_codec_type != VideoCodec::CODEC_RED) { + const Codec::ResiliencyType associated_codec_type = it->second; + if (associated_codec_type != Codec::ResiliencyType::kNone && + associated_codec_type != Codec::ResiliencyType::kRed) { RTC_LOG(LS_ERROR) << "RTX PT=" << rtx_payload_type << " not mapped to regular video codec or RED codec (PT=" diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc index 3be1dc5b34..ec9de84d66 100644 --- a/media/engine/webrtc_video_engine_unittest.cc +++ b/media/engine/webrtc_video_engine_unittest.cc @@ -4675,7 +4675,7 @@ TEST_F(WebRtcVideoChannelTest, EXPECT_FALSE(FindCodecById(engine_.send_codecs(), kUnusedPayloadType1)); EXPECT_FALSE(FindCodecById(engine_.send_codecs(), kUnusedPayloadType2)); { - cricket::VideoCodec rtx_codec = cricket::VideoCodec::CreateRtxCodec( + cricket::VideoCodec rtx_codec = cricket::CreateVideoRtxCodec( kUnusedPayloadType1, GetEngineCodec("VP8").id); cricket::VideoSendParameters parameters; parameters.codecs.push_back(GetEngineCodec("VP8")); @@ -4683,8 +4683,8 @@ TEST_F(WebRtcVideoChannelTest, ASSERT_TRUE(channel_->SetSendParameters(parameters)); } { - cricket::VideoCodec rtx_codec = cricket::VideoCodec::CreateRtxCodec( - kUnusedPayloadType1, kUnusedPayloadType2); + cricket::VideoCodec rtx_codec = + cricket::CreateVideoRtxCodec(kUnusedPayloadType1, kUnusedPayloadType2); cricket::VideoSendParameters parameters; parameters.codecs.push_back(GetEngineCodec("VP8")); parameters.codecs.push_back(rtx_codec); @@ -7323,8 +7323,8 @@ void WebRtcVideoChannelTest::TestReceiveUnsignaledSsrcPacket( EXPECT_FALSE(FindCodecById(engine_.recv_codecs(), kRedRtxPayloadType)); // Add a RED RTX codec. - VideoCodec red_rtx_codec = - VideoCodec::CreateRtxCodec(kRedRtxPayloadType, GetEngineCodec("red").id); + VideoCodec red_rtx_codec = cricket::CreateVideoRtxCodec( + kRedRtxPayloadType, GetEngineCodec("red").id); recv_parameters_.codecs.push_back(red_rtx_codec); EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_)); diff --git a/pc/media_session.cc b/pc/media_session.cc index 274d7ce8b2..5b387f2093 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -759,7 +759,9 @@ void NegotiatePacketization(const VideoCodec& local_codec, const VideoCodec& remote_codec, VideoCodec* negotiated_codec) { negotiated_codec->packetization = - VideoCodec::IntersectPacketization(local_codec, remote_codec); + (local_codec.packetization == remote_codec.packetization) + ? local_codec.packetization + : absl::nullopt; } template @@ -2479,7 +2481,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer( if (session_options.raw_packetization_for_video) { for (VideoCodec& codec : filtered_codecs) { - if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) { + if (codec.IsMediaCodec()) { codec.packetization = kPacketizationParamRaw; } } @@ -2812,7 +2814,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( if (session_options.raw_packetization_for_video) { for (VideoCodec& codec : filtered_codecs) { - if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) { + if (codec.IsMediaCodec()) { codec.packetization = kPacketizationParamRaw; } } diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc index 6ba5032092..c209dbdbba 100644 --- a/pc/media_session_unittest.cc +++ b/pc/media_session_unittest.cc @@ -23,6 +23,7 @@ #include "absl/algorithm/container.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "api/candidate.h" #include "api/crypto_params.h" #include "media/base/codec.h" @@ -2948,12 +2949,14 @@ TEST_F(MediaSessionDescriptionFactoryTest, &opts); std::vector f1_codecs = MAKE_VECTOR(kVideoCodecs1); // This creates rtx for H264 with the payload type `f1_` uses. - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), + &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); std::vector f2_codecs = MAKE_VECTOR(kVideoCodecs2); // This creates rtx for H264 with the payload type `f2_` uses. - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs2[0].id), + &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); std::unique_ptr offer = f1_.CreateOffer(opts, NULL); @@ -2965,7 +2968,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, GetFirstVideoContentDescription(answer.get()); std::vector expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer); - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), &expected_codecs); EXPECT_EQ(expected_codecs, vcd->codecs()); @@ -3000,12 +3003,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, // trigger the issue. cricket::VideoCodec vp8_offerer(100, "VP8"); cricket::VideoCodec vp8_offerer_rtx = - VideoCodec::CreateRtxCodec(101, vp8_offerer.id); + cricket::CreateVideoRtxCodec(101, vp8_offerer.id); cricket::VideoCodec vp8_answerer(110, "VP8"); cricket::VideoCodec vp8_answerer_rtx = - VideoCodec::CreateRtxCodec(111, vp8_answerer.id); + cricket::CreateVideoRtxCodec(111, vp8_answerer.id); cricket::VideoCodec vp9(120, "VP9"); - cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id); + cricket::VideoCodec vp9_rtx = cricket::CreateVideoRtxCodec(121, vp9.id); std::vector f1_codecs = {vp8_offerer, vp8_offerer_rtx}; // We also specifically cause the answerer to prefer VP9, such that if it @@ -3048,7 +3051,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) { std::vector f1_codecs = MAKE_VECTOR(kVideoCodecs1); // This creates rtx for H264 with the payload type `f1_` uses. - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), + &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); MediaSessionOptions opts; @@ -3073,7 +3077,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, std::vector f2_codecs = MAKE_VECTOR(kVideoCodecs2); int used_pl_type = acd->codecs()[0].id; f2_codecs[0].id = used_pl_type; // Set the payload type for H264. - AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, used_pl_type), &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); std::unique_ptr updated_offer( @@ -3109,7 +3113,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, std::vector f2_codecs = MAKE_VECTOR(kVideoCodecs2); // This creates rtx for H264 with the payload type `f2_` uses. - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs2[0].id), + &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); @@ -3135,7 +3140,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, // New offer should attempt to add H263, and RTX for H264. expected_codecs.push_back(kVideoCodecs2[1]); - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id), + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs1[1].id), &expected_codecs); EXPECT_EQ(expected_codecs, updated_vcd->codecs()); } @@ -3153,7 +3158,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) { std::vector f2_codecs = MAKE_VECTOR(kVideoCodecs2); // This creates RTX for H264 with the payload type `f2_` uses. - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs2[0].id), + &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); std::unique_ptr offer = f1_.CreateOffer(opts, NULL); @@ -3191,12 +3197,14 @@ TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) { &opts); std::vector f1_codecs = MAKE_VECTOR(kVideoCodecs1); // This creates RTX for H264 in sender. - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), + &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); std::vector f2_codecs = MAKE_VECTOR(kVideoCodecs2); // This creates RTX for H263 in receiver. - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs2[1].id), + &f2_codecs); f2_.set_video_codecs(f2_codecs, f2_codecs); std::unique_ptr offer = f1_.CreateOffer(opts, NULL); @@ -3221,16 +3229,19 @@ TEST_F(MediaSessionDescriptionFactoryTest, &opts); std::vector f1_codecs = MAKE_VECTOR(kVideoCodecs1); // This creates RTX for H264-SVC in sender. - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs1[0].id), + &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); // This creates RTX for H264 in sender. - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), + &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); std::vector f2_codecs = MAKE_VECTOR(kVideoCodecs2); // This creates RTX for H264 in receiver. - AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(124, kVideoCodecs2[0].id), + &f2_codecs); f2_.set_video_codecs(f2_codecs, f1_codecs); // H264-SVC codec is removed in the answer, therefore, associated RTX codec @@ -3242,7 +3253,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, const VideoContentDescription* vcd = GetFirstVideoContentDescription(answer.get()); std::vector expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer); - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), &expected_codecs); EXPECT_EQ(expected_codecs, vcd->codecs()); @@ -3257,7 +3268,8 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) { &opts); std::vector f1_codecs = MAKE_VECTOR(kVideoCodecs1); // This creates RTX for H264 for the offerer. - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), + &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); @@ -3266,12 +3278,13 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) { GetFirstVideoContentDescription(offer.get()); std::vector expected_codecs = MAKE_VECTOR(kVideoCodecs1); - AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), + AddRtxCodec(cricket::CreateVideoRtxCodec(126, kVideoCodecs1[1].id), &expected_codecs); EXPECT_EQ(expected_codecs, vcd->codecs()); // Now, attempt to add RTX for H264-SVC. - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs1[0].id), + &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); std::unique_ptr updated_offer( @@ -3279,7 +3292,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) { ASSERT_TRUE(updated_offer); vcd = GetFirstVideoContentDescription(updated_offer.get()); - AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), + AddRtxCodec(cricket::CreateVideoRtxCodec(125, kVideoCodecs1[0].id), &expected_codecs); EXPECT_EQ(expected_codecs, vcd->codecs()); } @@ -3298,7 +3311,7 @@ TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) { // Use a single real codec, and then add RTX for it. std::vector f1_codecs; f1_codecs.push_back(VideoCodec(97, "H264")); - AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs); + AddRtxCodec(cricket::CreateVideoRtxCodec(125, 97), &f1_codecs); f1_.set_video_codecs(f1_codecs, f1_codecs); // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there @@ -4226,6 +4239,76 @@ TEST_F(MediaSessionDescriptionFactoryTest, EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id); } +// Test verifying that negotiating codecs with the same packetization retains +// the packetization value. +TEST_F(MediaSessionDescriptionFactoryTest, PacketizationIsEqual) { + std::vector f1_codecs = {cricket::CreateVideoCodec(96, "H264")}; + f1_codecs.back().packetization = "raw"; + f1_.set_video_codecs(f1_codecs, f1_codecs); + + std::vector f2_codecs = {cricket::CreateVideoCodec(96, "H264")}; + f2_codecs.back().packetization = "raw"; + f2_.set_video_codecs(f2_codecs, f2_codecs); + + MediaSessionOptions opts; + AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1", + RtpTransceiverDirection::kSendRecv, kActive, + &opts); + + // Create an offer with two video sections using same codecs. + std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + ASSERT_TRUE(offer); + ASSERT_EQ(1u, offer->contents().size()); + const VideoContentDescription* vcd1 = + offer->contents()[0].media_description()->as_video(); + ASSERT_EQ(1u, vcd1->codecs().size()); + EXPECT_EQ(vcd1->codecs()[0].packetization, "raw"); + + // Create answer and negotiate the codecs. + std::unique_ptr answer = + f2_.CreateAnswer(offer.get(), opts, nullptr); + ASSERT_TRUE(answer); + ASSERT_EQ(1u, answer->contents().size()); + vcd1 = answer->contents()[0].media_description()->as_video(); + ASSERT_EQ(1u, vcd1->codecs().size()); + EXPECT_EQ(vcd1->codecs()[0].packetization, "raw"); +} + +// Test verifying that negotiating codecs with different packetization removes +// the packetization value. +TEST_F(MediaSessionDescriptionFactoryTest, PacketizationIsDifferent) { + std::vector f1_codecs = {cricket::CreateVideoCodec(96, "H264")}; + f1_codecs.back().packetization = "raw"; + f1_.set_video_codecs(f1_codecs, f1_codecs); + + std::vector f2_codecs = {cricket::CreateVideoCodec(96, "H264")}; + f2_codecs.back().packetization = "notraw"; + f2_.set_video_codecs(f2_codecs, f2_codecs); + + MediaSessionOptions opts; + AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1", + RtpTransceiverDirection::kSendRecv, kActive, + &opts); + + // Create an offer with two video sections using same codecs. + std::unique_ptr offer = f1_.CreateOffer(opts, nullptr); + ASSERT_TRUE(offer); + ASSERT_EQ(1u, offer->contents().size()); + const VideoContentDescription* vcd1 = + offer->contents()[0].media_description()->as_video(); + ASSERT_EQ(1u, vcd1->codecs().size()); + EXPECT_EQ(vcd1->codecs()[0].packetization, "raw"); + + // Create answer and negotiate the codecs. + std::unique_ptr answer = + f2_.CreateAnswer(offer.get(), opts, nullptr); + ASSERT_TRUE(answer); + ASSERT_EQ(1u, answer->contents().size()); + vcd1 = answer->contents()[0].media_description()->as_video(); + ASSERT_EQ(1u, vcd1->codecs().size()); + EXPECT_EQ(vcd1->codecs()[0].packetization, absl::nullopt); +} + // Test that the codec preference order per media section is respected in // subsequent offer. TEST_F(MediaSessionDescriptionFactoryTest, diff --git a/pc/peer_connection_media_unittest.cc b/pc/peer_connection_media_unittest.cc index 7ed47dbce2..c4545360b6 100644 --- a/pc/peer_connection_media_unittest.cc +++ b/pc/peer_connection_media_unittest.cc @@ -613,7 +613,7 @@ TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) { auto* offer_description = cricket::GetFirstVideoContentDescription(offer->description()); for (const auto& codec : offer_description->codecs()) { - if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) { + if (codec.IsMediaCodec()) { EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw); } } @@ -624,7 +624,7 @@ TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) { auto* answer_description = cricket::GetFirstVideoContentDescription(answer->description()); for (const auto& codec : answer_description->codecs()) { - if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) { + if (codec.IsMediaCodec()) { EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw); } } diff --git a/pc/rtp_parameters_conversion_unittest.cc b/pc/rtp_parameters_conversion_unittest.cc index 50d90e1c30..250743bbbf 100644 --- a/pc/rtp_parameters_conversion_unittest.cc +++ b/pc/rtp_parameters_conversion_unittest.cc @@ -15,6 +15,7 @@ #include #include "api/media_types.h" +#include "media/base/codec.h" #include "test/gmock.h" #include "test/gtest.h" @@ -396,11 +397,8 @@ TEST(RtpParametersConversionTest, ToRtcpFeedbackErrors) { } TEST(RtpParametersConversionTest, ToAudioRtpCodecCapability) { - cricket::AudioCodec cricket_codec; - cricket_codec.name = "foo"; - cricket_codec.id = 50; - cricket_codec.clockrate = 22222; - cricket_codec.channels = 4; + cricket::AudioCodec cricket_codec = + cricket::CreateAudioCodec(50, "foo", 22222, 4); cricket_codec.params["foo"] = "bar"; cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc")); RtpCodecCapability codec = ToRtpCodecCapability(cricket_codec); @@ -468,11 +466,8 @@ TEST(RtpParametersConversionTest, ToRtpEncodingsWithMultipleStreamParams) { } TEST(RtpParametersConversionTest, ToAudioRtpCodecParameters) { - cricket::AudioCodec cricket_codec; - cricket_codec.name = "foo"; - cricket_codec.id = 50; - cricket_codec.clockrate = 22222; - cricket_codec.channels = 4; + cricket::AudioCodec cricket_codec = + cricket::CreateAudioCodec(50, "foo", 22222, 4); cricket_codec.params["foo"] = "bar"; cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc")); RtpCodecParameters codec = ToRtpCodecParameters(cricket_codec); @@ -518,11 +513,8 @@ TEST(RtpParametersConversionTest, ToVideoRtpCodecParameters) { // An unknown feedback param should just be ignored. TEST(RtpParametersConversionTest, ToRtpCodecCapabilityUnknownFeedbackParam) { - cricket::AudioCodec cricket_codec; - cricket_codec.name = "foo"; - cricket_codec.id = 50; - cricket_codec.clockrate = 22222; - cricket_codec.channels = 4; + cricket::AudioCodec cricket_codec = + cricket::CreateAudioCodec(50, "foo", 22222, 4); cricket_codec.params["foo"] = "bar"; cricket_codec.feedback_params.Add({"unknown", "param"}); cricket_codec.feedback_params.Add(cricket::FeedbackParam("transport-cc"));