Fix payload type allocation issues for Audio RED and MID recycling.

This CL addresses several issues identified while enabling the
WebRTC-PayloadTypesInTransport field trial:
- Enforce media type equality in codec matching to prevent Audio/Video
RED collisions.
- Relax RED matching rules to allow negotiation with unlinked RED codecs.
- Validate media type during MID recycling in CodecVendor to prevent
incorrect codec merging.
- Update documentation with the video implementation strategy.

Bug: webrtc:360058654
Change-Id: I1ecbdad2179d346b3682875d823889aa076e353e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/453001
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#47113}
diff --git a/g3doc/todo/payload_type_redesign.md b/g3doc/todo/payload_type_redesign.md
new file mode 100644
index 0000000..5fa5f12
--- /dev/null
+++ b/g3doc/todo/payload_type_redesign.md
@@ -0,0 +1,127 @@
+# Payload type allocation redesign
+
+## Background: What a payload type is
+
+The payload type is a property of a codec that is established between a sender
+and a receiver using SDP offer/answer.
+
+Each end of the connection independently indicates the list of codecs it is
+willing to send and/or receive, and assigns a payload type to each. It is
+conventional but not required to use the same payload types in an answer as
+those suggested in an offer.
+
+For SDP sendonly media sections, it indicates a willingness to send; for
+recvonly media sections, it indicates a willingness to receive; for sendrecv
+media sections, it indicates a willingness to receive AND a willingness to send.
+Presence in a media section does not guarantee that it will be used. (RFC 3264)
+
+## Current allocation strategy
+
+The payload types are assigned by the VideoEngine and VoiceEngine according to a
+fixed list. If the assignments collide with already established payload types,
+the assignments are munged in the CodecVendor class so that there are no
+colliding payload types.
+
+The PayloadTypeRecorder class records what payload types are assigned - there is
+one case (PR-answer followed by a later Answer that has different PTs) where
+they are changed, but otherwise, once the PayloadTypeRecorder has assigned them,
+that PT is permanent for that transport and that direction.
+
+Picking a payload type is done in the PayloadTypePicker class. This is preloaded
+with some assignments, so that if a PT is free, the commonly used PT for that
+codec can be used.
+
+## Desired future strategy
+
+There should be no assignment of payload types in VideoEngine and VoiceEngine.
+Payload types should be picked only when creating an offer or answer; they are
+assigned permanently in SetLocalDescription / SetRemoteDescription.
+
+Once an assignment is made, it should never need to change (apart from the case
+noted above).
+
+## Dealing with resiliency mechanisms
+
+Resiliency mechanisms (RED, RTX) are signaled using "codecs", and are
+traditionally represented as such within the library. They associate with the
+codec they are resiliency for by using the "apt=" parameter in their a=fmtp
+lines. However, this complicates assignment, since that parameter cannot be
+filled in until the payload type for the "protected" codec is assigned.
+
+## Backwards compatibility issues
+
+Experience has shown that changing the PT allocation strategy often trips up
+applications that have depended on the result of the old allocation strategy, so
+user-visible changes should be avoided. One example is that it's preferred (but
+not strictly required) to have the RTX PT assigned the PT number of 1 more than
+the PT of the codec it refers to.
+
+## Current implementation status
+
+The new strategy is implemented for audio codecs. Several issues that caused
+test failures when enabling the `WebRTC-PayloadTypesInTransport` field trial
+have been identified and fixed:
+
+- **Audio/Video RED Collision:** RED codecs of different media types were
+  incorrectly matching, leading to payload type conflicts.
+  `MatchesWithCodecRules` now enforces media type equality.
+- **MID Recycling:** When a MID was recycled for a different media type (e.g.,
+  Audio -> Video), `CodecVendor` was incorrectly merging codecs from the old
+  description. This has been fixed by validating the media type before merging.
+- **RED Matching Logic:** Relaxed the matching rules for RED to allow
+  negotiation to proceed even when parameters (linking RED to primary codecs)
+  are not yet populated, as this linking now happens late in the `CodecVendor`.
+
+The new strategy is not yet implemented for video codecs.
+
+## Implementation Strategy for Video
+
+The goal is to transition video codec handling to the same late-assignment model
+used for audio.
+
+### 1. Unified Codec Collection
+
+- Implement `VideoCodecsFromFactory` in `pc/typed_codec_vendor.cc`. This will
+  query the `VideoEncoderFactory` and `VideoDecoderFactory` to gather supported
+  `SdpVideoFormat`s.
+- These codecs will be initialized with `kIdNotSet`, allowing
+  `SdpPayloadTypeSuggester` to assign payload types only during the creation of
+  an offer or answer.
+
+### 2. Payload Type Suggester Integration
+
+- Ensure `PayloadTypePicker` has a complete list of preferred payload types for
+  video codecs (VP8, VP9, H.264, AV1, etc.) to maintain stable and conventional
+  assignments.
+- Update `CodecVendor` to use the unassigned video codec list when the
+  `WebRTC-PayloadTypesInTransport` trial is active.
+
+### 3. Resiliency and Parameter Linking
+
+- Refine `MergeCodecs` and `AssignCodecIdsAndLinkRed` to handle video-specific
+  resiliency:
+  - **RTX:** Correctly link RTX codecs to their primary video codecs by matching
+    names and specific parameters (like `profile-level-id` for H.264).
+  - **RED/ULPFEC:** Ensure parameters for video redundancy are correctly
+    populated once the primary codec PTs are assigned.
+
+### 4. Verification and Testing
+
+- **Integration Tests:** Enable the `WebRTC-PayloadTypesInTransport` trial in
+  `peerconnection_unittests` and `rtc_unittests` to identify any video-specific
+  regressions.
+- **Stable PT Tests:** Add coverage to ensure that payload types remain stable
+  across renegotiations, even when the order of codecs in the transceiver
+  preferences changes.
+- **MID Recycling:** Verify that MID recycling for video-to-audio and vice-versa
+  works correctly without PT collisions or crashes.
+
+## Desired next steps
+
+Analyze the current situation. (Done)
+
+### Test, isolate and fix failures
+
+The identified failures in `PeerConnectionEncodingsIntegrationTest` and
+`PeerConnectionIntegrationTest` have been resolved. Next, focus on implementing
+the video strategy outlined above.
diff --git a/media/base/codec_comparators.cc b/media/base/codec_comparators.cc
index 9da9d4a..cb67f67 100644
--- a/media/base/codec_comparators.cc
+++ b/media/base/codec_comparators.cc
@@ -163,15 +163,7 @@
         potential_match.params.find(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 OK
       // since RED is considered to be declarative.
@@ -203,7 +195,16 @@
       return true;
     }
     if (!has_parameters_1 && !has_parameters_2) {
-      // Both parameters are missing. Happens for video RED.
+      return true;
+    }
+    // Exactly one lacks parameters.
+    // Allow match if it is an audio RED codec and at least one of the
+    // codecs has an unassigned payload type or they have the same ID.
+    if (codec_to_match.type == Codec::Type::kAudio &&
+        codec_to_match.name == kRedCodecName &&
+        (codec_to_match.id == Codec::kIdNotSet ||
+         potential_match.id == Codec::kIdNotSet ||
+         codec_to_match.id == potential_match.id)) {
       return true;
     }
     return false;
@@ -295,6 +296,11 @@
        right_codec.id <= kLowerDynamicRangeMax) ||
       (right_codec.id >= kUpperDynamicRangeMin &&
        right_codec.id <= kUpperDynamicRangeMax);
+
+  if (left_codec.type != right_codec.type) {
+    return false;
+  }
+
   bool matches_id;
   if ((is_id_in_dynamic_range && is_codec_id_in_dynamic_range) ||
       left_codec.id == Codec::kIdNotSet || right_codec.id == Codec::kIdNotSet) {
@@ -360,12 +366,22 @@
 bool IsSameRtpCodec(const Codec& codec, const RtpCodec& rtp_codec) {
   RtpCodecParameters rtp_codec2 = codec.ToCodecParameters();
 
-  return absl::EqualsIgnoreCase(rtp_codec.name, rtp_codec2.name) &&
-         rtp_codec.kind == rtp_codec2.kind &&
-         rtp_codec.num_channels == rtp_codec2.num_channels &&
-         rtp_codec.clock_rate == rtp_codec2.clock_rate &&
-         InsertDefaultParams(rtp_codec.name, rtp_codec.parameters) ==
-             InsertDefaultParams(rtp_codec2.name, rtp_codec2.parameters);
+  if (!absl::EqualsIgnoreCase(rtp_codec.name, rtp_codec2.name) ||
+      rtp_codec.kind != rtp_codec2.kind ||
+      rtp_codec.num_channels != rtp_codec2.num_channels ||
+      rtp_codec.clock_rate != rtp_codec2.clock_rate) {
+    return false;
+  }
+
+  // audio/RED should ignore the parameters which specify payload types so
+  // can not be compared.
+  if (rtp_codec.kind == MediaType::AUDIO &&
+      absl::EqualsIgnoreCase(rtp_codec.name, kRedCodecName)) {
+    return true;
+  }
+
+  return InsertDefaultParams(rtp_codec.name, rtp_codec.parameters) ==
+         InsertDefaultParams(rtp_codec2.name, rtp_codec2.parameters);
 }
 
 bool IsSameRtpCodecIgnoringLevel(const Codec& codec,
@@ -393,7 +409,8 @@
   }
   // audio/RED should ignore the parameters which specify payload types so
   // can not be compared.
-  if (rtp_codec.kind == MediaType::AUDIO && rtp_codec.name == kRedCodecName) {
+  if (rtp_codec.kind == MediaType::AUDIO &&
+      absl::EqualsIgnoreCase(rtp_codec.name, kRedCodecName)) {
     return true;
   }
 
diff --git a/media/base/codec_comparators_unittest.cc b/media/base/codec_comparators_unittest.cc
index 2f78042..0487656 100644
--- a/media/base/codec_comparators_unittest.cc
+++ b/media/base/codec_comparators_unittest.cc
@@ -105,6 +105,63 @@
   EXPECT_FALSE(MatchesWithReferenceAttributes(codec_1, codec_5));
 }
 
+TEST(CodecComparatorsTest, RedParametersMismatch) {
+  Codec with_params = CreateAudioCodec(101, kRedCodecName, 48000, 2);
+  with_params.SetParam(kCodecParamNotInNameValueFormat, "111/111");
+
+  Codec no_params = CreateAudioCodec(102, kRedCodecName, 48000, 2);
+
+  // Case 1: Exactly one lacks parameters, both have IDs -> SHOULD NOT match for
+  // audio RED.
+  EXPECT_FALSE(MatchesWithReferenceAttributes(with_params, no_params));
+  EXPECT_FALSE(MatchesWithReferenceAttributes(no_params, with_params));
+
+  // Case 2: Exactly one lacks parameters, the one WITHOUT parameters is
+  // unassigned -> SHOULD match.
+  // This is the case with late assignment.
+  Codec no_params_unassigned = no_params;
+  no_params_unassigned.id = Codec::kIdNotSet;
+  EXPECT_TRUE(
+      MatchesWithReferenceAttributes(with_params, no_params_unassigned));
+  EXPECT_TRUE(
+      MatchesWithReferenceAttributes(no_params_unassigned, with_params));
+
+  // Case 3: Exactly one lacks parameters, the one WITH parameters is
+  // unassigned -> SHOULD match for audio RED because one side is unassigned.
+  Codec with_params_unassigned = with_params;
+  with_params_unassigned.id = Codec::kIdNotSet;
+  EXPECT_TRUE(
+      MatchesWithReferenceAttributes(with_params_unassigned, no_params));
+  EXPECT_TRUE(
+      MatchesWithReferenceAttributes(no_params, with_params_unassigned));
+
+  // Case 4: Exactly one lacks parameters, both are unassigned -> SHOULD match.
+  EXPECT_TRUE(MatchesWithReferenceAttributes(with_params_unassigned,
+                                             no_params_unassigned));
+  EXPECT_TRUE(MatchesWithReferenceAttributes(no_params_unassigned,
+                                             with_params_unassigned));
+
+  // Case 5: Both lack parameters -> SHOULD match.
+  Codec no_params_2 = CreateAudioCodec(103, kRedCodecName, 48000, 2);
+  EXPECT_TRUE(MatchesWithReferenceAttributes(no_params, no_params_2));
+
+  // A video RED codec should not match any audio RED codec,
+  // independent of parameters.
+  Codec video_red_codec = CreateVideoCodec(107, kRedCodecName);
+  EXPECT_FALSE(MatchesWithReferenceAttributes(no_params, video_red_codec));
+  EXPECT_FALSE(MatchesWithReferenceAttributes(with_params, video_red_codec));
+
+  // Two video RED codecs with different IDs and one lacking parameters
+  // should NOT match.
+  Codec video_red_with_params = CreateVideoCodec(108, kRedCodecName);
+  video_red_with_params.SetParam(kCodecParamNotInNameValueFormat, "120/120");
+  Codec video_red_no_params = CreateVideoCodec(109, kRedCodecName);
+  EXPECT_FALSE(MatchesWithReferenceAttributes(video_red_with_params,
+                                              video_red_no_params));
+  EXPECT_FALSE(MatchesWithReferenceAttributes(video_red_no_params,
+                                              video_red_with_params));
+}
+
 struct TestParams {
   std::string name;
   SdpVideoFormat codec1;
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 9863aa6..4315b46 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -407,6 +407,7 @@
     ":typed_codec_vendor",
     ":used_ids",
     "../api:field_trials_view",
+    "../api:payload_type",
     "../api:rtc_error",
     "../api:rtp_parameters",
     "../api:rtp_transceiver_direction",
diff --git a/pc/codec_vendor.cc b/pc/codec_vendor.cc
index 1d865fd..50f3ef8 100644
--- a/pc/codec_vendor.cc
+++ b/pc/codec_vendor.cc
@@ -23,6 +23,7 @@
 #include "absl/strings/string_view.h"
 #include "api/field_trials_view.h"
 #include "api/media_types.h"
+#include "api/payload_type.h"
 #include "api/rtc_error.h"
 #include "api/rtp_parameters.h"
 #include "api/rtp_transceiver_direction.h"
@@ -620,7 +621,8 @@
   CodecList codecs;
   std::string mid = media_description_options.mid;
   // If current content exists and is not being recycled, use its codecs.
-  if (current_content && current_content->mid() == mid) {
+  if (current_content && current_content->mid() == mid &&
+      IsMediaContentOfType(current_content, media_description_options.type)) {
     RTCErrorOr<CodecList> checked_codec_list =
         CodecList::Create(current_content->media_description()->codecs());
     if (!checked_codec_list.ok()) {
@@ -758,7 +760,8 @@
   RTC_LOG_THREAD_BLOCK_COUNT();
   CodecList codecs;
   std::string mid = media_description_options.mid;
-  if (current_content && current_content->mid() == mid) {
+  if (current_content && current_content->mid() == mid &&
+      IsMediaContentOfType(current_content, media_description_options.type)) {
     RTCErrorOr<CodecList> checked_codec_list =
         CodecList::Create(current_content->media_description()->codecs());
     if (!checked_codec_list.ok()) {
diff --git a/pc/peer_connection_encodings_integrationtest.cc b/pc/peer_connection_encodings_integrationtest.cc
index 6b84d6b..9b9ee25 100644
--- a/pc/peer_connection_encodings_integrationtest.cc
+++ b/pc/peer_connection_encodings_integrationtest.cc
@@ -2130,6 +2130,64 @@
 }
 
 TEST_F(PeerConnectionEncodingsIntegrationTest,
+       EncodingParametersRedEnabledBeforeNegotiationAudioWithFieldTrial) {
+  scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper =
+      CreatePc("WebRTC-PayloadTypesInTransport/Enabled/");
+  scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper =
+      CreatePc("WebRTC-PayloadTypesInTransport/Enabled/");
+  ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
+
+  std::vector<RtpCodecCapability> send_codecs =
+      local_pc_wrapper->pc_factory()
+          ->GetRtpSenderCapabilities(MediaType::AUDIO)
+          .codecs;
+
+  std::optional<RtpCodecCapability> opus =
+      local_pc_wrapper->FindFirstSendCodecWithName(MediaType::AUDIO, "opus");
+  ASSERT_TRUE(opus);
+
+  std::optional<RtpCodecCapability> red =
+      local_pc_wrapper->FindFirstSendCodecWithName(MediaType::AUDIO, "red");
+  ASSERT_TRUE(red);
+
+  RtpTransceiverInit init;
+  init.direction = RtpTransceiverDirection::kSendOnly;
+  RtpEncodingParameters encoding_parameters;
+  encoding_parameters.codec = opus;
+  init.send_encodings.push_back(encoding_parameters);
+
+  auto transceiver_or_error =
+      local_pc_wrapper->pc()->AddTransceiver(MediaType::AUDIO, init);
+  ASSERT_TRUE(transceiver_or_error.ok());
+  scoped_refptr<RtpTransceiverInterface> audio_transceiver =
+      transceiver_or_error.MoveValue();
+
+  // Preferring RED over Opus should enable RED with Opus encoding.
+  send_codecs[0] = red.value();
+  send_codecs[1] = opus.value();
+
+  ASSERT_TRUE(audio_transceiver->SetCodecPreferences(send_codecs).ok());
+  NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
+  local_pc_wrapper->WaitForConnection();
+  remote_pc_wrapper->WaitForConnection();
+
+  RtpParameters parameters = audio_transceiver->sender()->GetParameters();
+  EXPECT_EQ(parameters.encodings[0].codec, opus);
+  EXPECT_EQ(parameters.codecs[0].name, red->name);
+
+  // Check that it's possible to switch back to Opus without RED.
+  send_codecs[0] = opus.value();
+  send_codecs[1] = red.value();
+
+  ASSERT_TRUE(audio_transceiver->SetCodecPreferences(send_codecs).ok());
+  NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
+
+  parameters = audio_transceiver->sender()->GetParameters();
+  EXPECT_EQ(parameters.encodings[0].codec, opus);
+  EXPECT_EQ(parameters.codecs[0].name, opus->name);
+}
+
+TEST_F(PeerConnectionEncodingsIntegrationTest,
        SetParametersRejectsScalabilityModeForSelectedCodec) {
   scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
 
diff --git a/pc/peer_connection_media_unittest.cc b/pc/peer_connection_media_unittest.cc
index 3890be2..a4671c9 100644
--- a/pc/peer_connection_media_unittest.cc
+++ b/pc/peer_connection_media_unittest.cc
@@ -1376,10 +1376,10 @@
       CreateAudioCodec(120, "foo", kDefaultAudioClockRateHz, 1));
   callee_fake_codecs.push_back(
       CreateAudioCodec(121, kRedCodecName, kDefaultAudioClockRateHz, 1));
-  callee_fake_codecs.push_back(
-      CreateAudioCodec(122, "bar", kDefaultAudioClockRateHz, 1));
   callee_fake_codecs.back().SetParam(kCodecParamNotInNameValueFormat,
                                      "122/122");
+  callee_fake_codecs.push_back(
+      CreateAudioCodec(122, "bar", kDefaultAudioClockRateHz, 1));
   auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
   callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
   auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
diff --git a/pc/peer_connection_stability_integrationtest.cc b/pc/peer_connection_stability_integrationtest.cc
index 8d30522..3acfd99 100644
--- a/pc/peer_connection_stability_integrationtest.cc
+++ b/pc/peer_connection_stability_integrationtest.cc
@@ -949,5 +949,554 @@
               ElementsAreArray(this_golden.callee_remote));
 }
 
+TEST_F(PeerConnectionIntegrationTest,
+       BasicOfferAnswerPayloadTypesStableWithFieldTrial) {
+  SetFieldTrials("WebRTC-PayloadTypesInTransport/Enabled/");
+  FactorySignature factory_signature;
+  ASSERT_THAT(factory_signature.id(),
+              Not(Eq(FactorySignature::Id::kNotRecognized)));
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignalingForSdpOnly();
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  // Start offer/answer exchange and wait for it to complete.
+  caller()->CreateAndSetAndSignalOffer();
+
+  ASSERT_THAT(
+      WaitUntil([&] { return SignalingStateStable(); }, ::testing::IsTrue()),
+      IsRtcOk());
+
+  // Extract PT and codec from all media sections, and check that they
+  // are stable (what was expected).
+  // Maintenance: In order to get a new golden set of strings, make the list
+  // empty and run. Gmock will output a valid C++ array initializer for you.
+
+  std::vector<ResultingCodecList> golden_answers = {
+      {.factory_id = FactorySignature::Id::kWebRtcTipOfTree,
+       .caller_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]",
+            "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]",
+            "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]",
+            "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]",
+            "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 "
+            "[103:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42001f]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 "
+            "[107:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42001f]",
+            "2 [108:video/rtx/90000/0;apt=107]",
+            "2 "
+            "[109:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42e01f]",
+            "2 [114:video/rtx/90000/0;apt=109]",
+            "2 "
+            "[115:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42e01f]",
+            "2 [116:video/rtx/90000/0;apt=115]",
+            "2 "
+            "[117:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "4d001f]",
+            "2 [118:video/rtx/90000/0;apt=117]",
+            "2 "
+            "[39:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "4d001f]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [45:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [46:video/rtx/90000/0;apt=45]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [119:video/red/90000/0]",
+            "2 [120:video/rtx/90000/0;apt=119]",
+            "2 [121:video/ulpfec/90000/0]"},
+       .caller_remote =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]",
+            "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]",
+            "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]",
+            "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]",
+            "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 "
+            "[103:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42001f]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 "
+            "[107:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42001f]",
+            "2 [108:video/rtx/90000/0;apt=107]",
+            "2 "
+            "[109:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42e01f]",
+            "2 [114:video/rtx/90000/0;apt=109]",
+            "2 "
+            "[115:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42e01f]",
+            "2 [116:video/rtx/90000/0;apt=115]",
+            "2 "
+            "[117:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "4d001f]",
+            "2 [118:video/rtx/90000/0;apt=117]",
+            "2 "
+            "[39:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "4d001f]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [45:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [46:video/rtx/90000/0;apt=45]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [119:video/red/90000/0]",
+            "2 [120:video/rtx/90000/0;apt=119]",
+            "2 [121:video/ulpfec/90000/0]"},
+       .callee_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]",
+            "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]",
+            "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]",
+            "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]",
+            "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 "
+            "[103:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42001f]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 "
+            "[107:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42001f]",
+            "2 [108:video/rtx/90000/0;apt=107]",
+            "2 "
+            "[109:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42e01f]",
+            "2 [114:video/rtx/90000/0;apt=109]",
+            "2 "
+            "[115:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42e01f]",
+            "2 [116:video/rtx/90000/0;apt=115]",
+            "2 "
+            "[117:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "4d001f]",
+            "2 [118:video/rtx/90000/0;apt=117]",
+            "2 "
+            "[39:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "4d001f]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [45:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [46:video/rtx/90000/0;apt=45]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [119:video/red/90000/0]",
+            "2 [120:video/rtx/90000/0;apt=119]",
+            "2 [121:video/ulpfec/90000/0]"},
+       .callee_remote =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]",
+            "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]",
+            "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]",
+            "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]",
+            "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 "
+            "[103:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42001f]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 "
+            "[107:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42001f]",
+            "2 [108:video/rtx/90000/0;apt=107]",
+            "2 "
+            "[109:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "42e01f]",
+            "2 [114:video/rtx/90000/0;apt=109]",
+            "2 "
+            "[115:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "42e01f]",
+            "2 [116:video/rtx/90000/0;apt=115]",
+            "2 "
+            "[117:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+            "4d001f]",
+            "2 [118:video/rtx/90000/0;apt=117]",
+            "2 "
+            "[39:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+            "4d001f]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [45:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [46:video/rtx/90000/0;apt=45]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [119:video/red/90000/0]",
+            "2 [120:video/rtx/90000/0;apt=119]",
+            "2 [121:video/ulpfec/90000/0]"}},
+
+      {.factory_id = FactorySignature::Id::kWebRtcMoreConfigs1,
+       .caller_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]", "2 [103:video/red/90000/0]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 [107:video/ulpfec/90000/0]"},
+       .caller_remote =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]", "2 [103:video/red/90000/0]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 [107:video/ulpfec/90000/0]"},
+       .callee_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]", "2 [103:video/red/90000/0]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 [107:video/ulpfec/90000/0]"},
+       .callee_remote =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [100:video/VP9/90000/0;profile-id=2]",
+            "2 [101:video/rtx/90000/0;apt=100]", "2 [103:video/red/90000/0]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 [107:video/ulpfec/90000/0]"}},
+      {.factory_id = FactorySignature::Id::kWebRtcAndroid,
+       .caller_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]", "2 [100:video/red/90000/0]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [103:video/ulpfec/90000/0]"},
+       .caller_remote =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]", "2 [100:video/red/90000/0]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [103:video/ulpfec/90000/0]"},
+       .callee_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]", "2 [100:video/red/90000/0]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [103:video/ulpfec/90000/0]"},
+       .callee_remote =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]", "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]", "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]", "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]", "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 [39:video/AV1/90000/0;level-idx=5;profile=0;tier=0]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]", "2 [100:video/red/90000/0]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 [103:video/ulpfec/90000/0]"}},
+      {.factory_id = FactorySignature::Id::kGoogleInternal,
+       .caller_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]",
+            "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]",
+            "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]",
+            "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]",
+            "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 "
+            "[100:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=42001f]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 "
+            "[103:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=42001f]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 "
+            "[107:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=42e01f]",
+            "2 [108:video/rtx/90000/0;apt=107]",
+            "2 "
+            "[109:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=42e01f]",
+            "2 [114:video/rtx/90000/0;apt=109]",
+            "2 "
+            "[115:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=4d001f]",
+            "2 [116:video/rtx/90000/0;apt=115]",
+            "2 "
+            "[39:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=4d001f]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [117:video/red/90000/0]",
+            "2 [118:video/rtx/90000/0;apt=117]",
+            "2 [119:video/ulpfec/90000/0]"},
+       .caller_remote =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]",
+            "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]",
+            "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]",
+            "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]",
+            "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 "
+            "[100:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=42001f]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 "
+            "[103:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=42001f]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 "
+            "[107:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=42e01f]",
+            "2 [108:video/rtx/90000/0;apt=107]",
+            "2 "
+            "[109:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=42e01f]",
+            "2 [114:video/rtx/90000/0;apt=109]",
+            "2 "
+            "[115:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=4d001f]",
+            "2 [116:video/rtx/90000/0;apt=115]",
+            "2 "
+            "[39:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=4d001f]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [117:video/red/90000/0]",
+            "2 [118:video/rtx/90000/0;apt=117]",
+            "2 [119:video/ulpfec/90000/0]"},
+       .callee_local =
+           {"1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+            "1 [63:audio/red/48000/2;=111/111]",
+            "1 [9:audio/G722/8000/1]",
+            "1 [0:audio/PCMU/8000/1]",
+            "1 [8:audio/PCMA/8000/1]",
+            "1 [13:audio/CN/8000/1]",
+            "1 [110:audio/telephone-event/48000/1]",
+            "1 [126:audio/telephone-event/8000/1]",
+            "2 [96:video/VP8/90000/0]",
+            "2 [97:video/rtx/90000/0;apt=96]",
+            "2 "
+            "[100:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=42001f]",
+            "2 [101:video/rtx/90000/0;apt=100]",
+            "2 "
+            "[103:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=42001f]",
+            "2 [104:video/rtx/90000/0;apt=103]",
+            "2 "
+            "[107:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=42e01f]",
+            "2 [108:video/rtx/90000/0;apt=107]",
+            "2 "
+            "[109:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=42e01f]",
+            "2 [114:video/rtx/90000/0;apt=109]",
+            "2 "
+            "[115:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-"
+            "id=4d001f]",
+            "2 [116:video/rtx/90000/0;apt=115]",
+            "2 "
+            "[39:video/H264/90000/"
+            "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-"
+            "id=4d001f]",
+            "2 [40:video/rtx/90000/0;apt=39]",
+            "2 [98:video/VP9/90000/0;profile-id=0]",
+            "2 [99:video/rtx/90000/0;apt=98]",
+            "2 [117:video/red/90000/0]",
+            "2 [118:video/rtx/90000/0;apt=117]",
+            "2 [119:video/ulpfec/90000/0]"},
+       .callee_remote = {
+           "1 [111:audio/opus/48000/2;minptime=10;useinbandfec=1]",
+           "1 [63:audio/red/48000/2;=111/111]",
+           "1 [9:audio/G722/8000/1]",
+           "1 [0:audio/PCMU/8000/1]",
+           "1 [8:audio/PCMA/8000/1]",
+           "1 [13:audio/CN/8000/1]",
+           "1 [110:audio/telephone-event/48000/1]",
+           "1 [126:audio/telephone-event/8000/1]",
+           "2 [96:video/VP8/90000/0]",
+           "2 [97:video/rtx/90000/0;apt=96]",
+           "2 "
+           "[100:video/H264/90000/"
+           "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+           "42001f]",
+           "2 [101:video/rtx/90000/0;apt=100]",
+           "2 "
+           "[103:video/H264/90000/"
+           "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+           "42001f]",
+           "2 [104:video/rtx/90000/0;apt=103]",
+           "2 "
+           "[107:video/H264/90000/"
+           "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+           "42e01f]",
+           "2 [108:video/rtx/90000/0;apt=107]",
+           "2 "
+           "[109:video/H264/90000/"
+           "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+           "42e01f]",
+           "2 [114:video/rtx/90000/0;apt=109]",
+           "2 "
+           "[115:video/H264/90000/"
+           "0;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+           "4d001f]",
+           "2 [116:video/rtx/90000/0;apt=115]",
+           "2 "
+           "[39:video/H264/90000/"
+           "0;level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+           "4d001f]",
+           "2 [40:video/rtx/90000/0;apt=39]",
+           "2 [98:video/VP9/90000/0;profile-id=0]",
+           "2 [99:video/rtx/90000/0;apt=98]",
+           "2 [117:video/red/90000/0]",
+           "2 [118:video/rtx/90000/0;apt=117]",
+           "2 [119:video/ulpfec/90000/0]"}}};
+  auto this_golden_it =
+      std::find_if(golden_answers.begin(), golden_answers.end(),
+                   [&](const ResultingCodecList& candidate) {
+                     return candidate.factory_id == factory_signature.id();
+                   });
+  ASSERT_THAT(this_golden_it, Not(Eq(golden_answers.end())))
+      << "Add this result set to golden_answers:\n"
+      << DumpAsResultingCodecList(
+             factory_signature.id(),
+             CodecList(*caller()->pc()->local_description()),
+             CodecList(*caller()->pc()->remote_description()),
+             CodecList(*callee()->pc()->local_description()),
+             CodecList(*callee()->pc()->remote_description()));
+
+  const ResultingCodecList& this_golden = *this_golden_it;
+  EXPECT_THAT(CodecList(*caller()->pc()->local_description()),
+              ElementsAreArray(this_golden.caller_local));
+  EXPECT_THAT(CodecList(*caller()->pc()->remote_description()),
+              ElementsAreArray(this_golden.caller_remote));
+  EXPECT_THAT(CodecList(*callee()->pc()->local_description()),
+              ElementsAreArray(this_golden.callee_local));
+  EXPECT_THAT(CodecList(*callee()->pc()->remote_description()),
+              ElementsAreArray(this_golden.callee_remote));
+}
+
 }  // namespace
 }  // namespace webrtc