diff --git a/media/BUILD.gn b/media/BUILD.gn index 223a7de4e7..d6c3ba58e2 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -373,6 +373,7 @@ rtc_library("codec") { "../rtc_base/system:rtc_export", "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/container:inlined_vector", + "//third_party/abseil-cpp/absl/functional:any_invocable", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/strings:str_format", "//third_party/abseil-cpp/absl/strings:string_view", diff --git a/media/base/codec_comparators.cc b/media/base/codec_comparators.cc index a6be486c2a..207f093a76 100644 --- a/media/base/codec_comparators.cc +++ b/media/base/codec_comparators.cc @@ -15,6 +15,7 @@ #include #include "absl/algorithm/container.h" +#include "absl/functional/any_invocable.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" #include "api/rtp_parameters.h" @@ -136,6 +137,84 @@ bool ReferencedCodecsMatch(const std::vector& codecs1, return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2); } +bool MatchesWithReferenceAttributesAndComparator( + const Codec& codec_to_match, + const Codec& potential_match, + absl::AnyInvocable reference_comparator) { + if (!MatchesWithCodecRules(codec_to_match, potential_match)) { + return false; + } + Codec::ResiliencyType resiliency_type = codec_to_match.GetResiliencyType(); + if (resiliency_type == Codec::ResiliencyType::kRtx) { + int apt_value_1 = 0; + int apt_value_2 = 0; + if (!codec_to_match.GetParam(cricket::kCodecParamAssociatedPayloadType, + &apt_value_1) || + !potential_match.GetParam(cricket::kCodecParamAssociatedPayloadType, + &apt_value_2)) { + RTC_LOG(LS_WARNING) << "RTX missing associated payload type."; + return false; + } + if (reference_comparator(apt_value_1, apt_value_2)) { + return true; + } + return false; + } + if (resiliency_type == Codec::ResiliencyType::kRed) { + auto red_parameters_1 = + codec_to_match.params.find(cricket::kCodecParamNotInNameValueFormat); + auto red_parameters_2 = + potential_match.params.find(cricket::kCodecParamNotInNameValueFormat); + bool has_parameters_1 = red_parameters_1 != codec_to_match.params.end(); + bool has_parameters_2 = red_parameters_2 != potential_match.params.end(); + // If codec_to_match has unassigned PT and no parameter, + // we assume that it'll be assigned later and return a match. + // Note - this should be deleted. It's untidy. + if (potential_match.id == Codec::kIdNotSet && !has_parameters_2) { + return true; + } + if (codec_to_match.id == Codec::kIdNotSet && !has_parameters_1) { + return true; + } + if (has_parameters_1 && has_parameters_2) { + // Different levels of redundancy between offer and answer are + // since RED is considered to be declarative. + std::vector redundant_payloads_1 = + rtc::split(red_parameters_1->second, '/'); + std::vector redundant_payloads_2 = + rtc::split(red_parameters_2->second, '/'); + if (redundant_payloads_1.size() > 0 && redundant_payloads_2.size() > 0) { + // Mixed reference codecs (i.e. 111/112) are not supported. + for (size_t i = 1; i < redundant_payloads_1.size(); i++) { + if (redundant_payloads_1[i] != redundant_payloads_1[0]) { + return false; + } + } + for (size_t i = 1; i < redundant_payloads_2.size(); i++) { + if (redundant_payloads_2[i] != redundant_payloads_2[0]) { + return false; + } + } + int red_value_1; + int red_value_2; + if (rtc::FromString(redundant_payloads_1[0], &red_value_1) && + rtc::FromString(redundant_payloads_2[0], &red_value_2)) { + if (reference_comparator(red_value_1, red_value_2)) { + return true; + } + } + return false; + } + } + if (!has_parameters_1 && !has_parameters_2) { + // Both parameters are missing. Happens for video RED. + return true; + } + return false; + } + return true; // Not a codec with a PT-valued reference. +} + } // namespace bool MatchesWithCodecRules(const Codec& left_codec, const Codec& right_codec) { @@ -212,79 +291,11 @@ std::optional FindMatchingCodec(const std::vector& codecs1, return &codec == &codec_to_match; })); for (const Codec& potential_match : codecs2) { - if (potential_match.Matches(codec_to_match)) { - if (codec_to_match.GetResiliencyType() == Codec::ResiliencyType::kRtx) { - int apt_value_1 = 0; - int apt_value_2 = 0; - if (!codec_to_match.GetParam(cricket::kCodecParamAssociatedPayloadType, - &apt_value_1) || - !potential_match.GetParam(cricket::kCodecParamAssociatedPayloadType, - &apt_value_2)) { - RTC_LOG(LS_WARNING) << "RTX missing associated payload type."; - continue; - } - if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2, - apt_value_2)) { - continue; - } - } else if (codec_to_match.GetResiliencyType() == - Codec::ResiliencyType::kRed) { - auto red_parameters_1 = codec_to_match.params.find( - cricket::kCodecParamNotInNameValueFormat); - auto red_parameters_2 = potential_match.params.find( - cricket::kCodecParamNotInNameValueFormat); - bool has_parameters_1 = red_parameters_1 != codec_to_match.params.end(); - bool has_parameters_2 = - red_parameters_2 != potential_match.params.end(); - // If codec_to_match has unassigned PT and no parameter, - // we assume that it'll be assigned later and return a match. - if (potential_match.id == Codec::kIdNotSet && !has_parameters_2) { - return potential_match; - } - if (codec_to_match.id == Codec::kIdNotSet && !has_parameters_1) { - return potential_match; - } - if (has_parameters_1 && has_parameters_2) { - // Mixed reference codecs (i.e. 111/112) are not supported. - // Different levels of redundancy between offer and answer are - // since RED is considered to be declarative. - std::vector redundant_payloads_1 = - rtc::split(red_parameters_1->second, '/'); - std::vector redundant_payloads_2 = - rtc::split(red_parameters_2->second, '/'); - if (redundant_payloads_1.size() > 0 && - redundant_payloads_2.size() > 0) { - bool consistent = true; - for (size_t i = 1; i < redundant_payloads_1.size(); i++) { - if (redundant_payloads_1[i] != redundant_payloads_1[0]) { - consistent = false; - break; - } - } - for (size_t i = 1; i < redundant_payloads_2.size(); i++) { - if (redundant_payloads_2[i] != redundant_payloads_2[0]) { - consistent = false; - break; - } - } - if (!consistent) { - continue; - } - - int red_value_1; - int red_value_2; - if (rtc::FromString(redundant_payloads_1[0], &red_value_1) && - rtc::FromString(redundant_payloads_2[0], &red_value_2)) { - if (!ReferencedCodecsMatch(codecs1, red_value_1, codecs2, - red_value_2)) { - continue; - } - } - } - } else if (has_parameters_1 != has_parameters_2) { - continue; - } - } + if (MatchesWithReferenceAttributesAndComparator( + codec_to_match, potential_match, + [&codecs1, &codecs2](int a, int b) { + return ReferencedCodecsMatch(codecs1, a, codecs2, b); + })) { return potential_match; } } diff --git a/media/base/codec_comparators.h b/media/base/codec_comparators.h index e36e93557a..2c96d6a3d6 100644 --- a/media/base/codec_comparators.h +++ b/media/base/codec_comparators.h @@ -29,6 +29,10 @@ bool MatchesWithCodecRules(const cricket::Codec& left_codec, // Finds a codec in `codecs2` that matches `codec_to_match`, which is // a member of `codecs1`. If `codec_to_match` is an RED or RTX codec, both // the codecs themselves and their associated codecs must match. +// The purpose of this function is that codecs1 and codecs2 are different +// PT numbering spaces, and it is trying to find the codec in codecs2 +// that has the same functionality as `codec_to_match` so that its PT +// can be used in place of the original. std::optional FindMatchingCodec( const std::vector& codecs1, const std::vector& codecs2,