@@ -166,94 +166,6 @@ const Codec* GetAssociatedCodecForRed(const CodecList& codec_list,
166
166
// Adds all codecs from `reference_codecs` to `offered_codecs` that don't
167
167
// already exist in `offered_codecs` and ensure the payload types don't
168
168
// collide.
169
- RTCError MergeCodecs (const CodecList& reference_codecs,
170
- const std::string& mid,
171
- CodecList& offered_codecs,
172
- PayloadTypeSuggester& pt_suggester) {
173
- // Add all new codecs that are not RTX/RED codecs.
174
- // The two-pass splitting of the loops means preferring payload types
175
- // of actual codecs with respect to collisions.
176
- for (const Codec& reference_codec : reference_codecs) {
177
- if (reference_codec.GetResiliencyType () != Codec::ResiliencyType::kRtx &&
178
- reference_codec.GetResiliencyType () != Codec::ResiliencyType::kRed &&
179
- !FindMatchingCodec (reference_codecs, offered_codecs, reference_codec)) {
180
- Codec codec = reference_codec;
181
- RTCErrorOr<webrtc::PayloadType> suggestion =
182
- pt_suggester.SuggestPayloadType (mid, codec);
183
- if (!suggestion.ok ()) {
184
- return suggestion.MoveError ();
185
- }
186
- codec.id = suggestion.value ();
187
- offered_codecs.push_back (codec);
188
- }
189
- }
190
-
191
- // Add all new RTX or RED codecs.
192
- for (const Codec& reference_codec : reference_codecs) {
193
- if (reference_codec.GetResiliencyType () == Codec::ResiliencyType::kRtx &&
194
- !FindMatchingCodec (reference_codecs, offered_codecs, reference_codec)) {
195
- Codec rtx_codec = reference_codec;
196
- const Codec* associated_codec =
197
- GetAssociatedCodecForRtx (reference_codecs, rtx_codec);
198
- if (!associated_codec) {
199
- continue ;
200
- }
201
- // Find a codec in the offered list that matches the reference codec.
202
- // Its payload type may be different than the reference codec.
203
- std::optional<Codec> matching_codec = FindMatchingCodec (
204
- reference_codecs, offered_codecs, *associated_codec);
205
- if (!matching_codec) {
206
- RTC_LOG (LS_WARNING)
207
- << " Couldn't find matching " << associated_codec->name << " codec." ;
208
- continue ;
209
- }
210
-
211
- rtx_codec.params [kCodecParamAssociatedPayloadType ] =
212
- rtc::ToString (matching_codec->id );
213
- RTCErrorOr<webrtc::PayloadType> suggestion =
214
- pt_suggester.SuggestPayloadType (mid, rtx_codec);
215
- if (!suggestion.ok ()) {
216
- return suggestion.MoveError ();
217
- }
218
- rtx_codec.id = suggestion.value ();
219
- offered_codecs.push_back (rtx_codec);
220
- } else if (reference_codec.GetResiliencyType () ==
221
- Codec::ResiliencyType::kRed &&
222
- !FindMatchingCodec (reference_codecs, offered_codecs,
223
- reference_codec)) {
224
- Codec red_codec = reference_codec;
225
- const Codec* associated_codec =
226
- GetAssociatedCodecForRed (reference_codecs, red_codec);
227
- if (associated_codec) {
228
- std::optional<Codec> matching_codec = FindMatchingCodec (
229
- reference_codecs, offered_codecs, *associated_codec);
230
- if (!matching_codec) {
231
- RTC_LOG (LS_WARNING) << " Couldn't find matching "
232
- << associated_codec->name << " codec." ;
233
- continue ;
234
- }
235
-
236
- red_codec.params [kCodecParamNotInNameValueFormat ] =
237
- rtc::ToString (matching_codec->id ) + " /" +
238
- rtc::ToString (matching_codec->id );
239
- }
240
- RTCErrorOr<webrtc::PayloadType> suggestion =
241
- pt_suggester.SuggestPayloadType (mid, red_codec);
242
- if (!suggestion.ok ()) {
243
- return suggestion.MoveError ();
244
- }
245
- red_codec.id = suggestion.value ();
246
- offered_codecs.push_back (red_codec);
247
- }
248
- }
249
- offered_codecs.CheckConsistency ();
250
- return RTCError::OK ();
251
- }
252
-
253
- // Adds all codecs from `reference_codecs` to `offered_codecs` that don't
254
- // already exist in `offered_codecs` and ensure the payload types don't
255
- // collide.
256
- // OLD VERSION - uses UsedPayloadTypes
257
169
void MergeCodecs (const CodecList& reference_codecs,
258
170
CodecList& offered_codecs,
259
171
UsedPayloadTypes* used_pltypes) {
@@ -405,6 +317,43 @@ CodecList MatchCodecPreference(
405
317
return filtered_codecs;
406
318
}
407
319
320
+ // Compute the union of `codecs1` and `codecs2`.
321
+ CodecList ComputeCodecsUnion (const CodecList codecs1, const CodecList codecs2) {
322
+ CodecList all_codecs;
323
+ UsedPayloadTypes used_payload_types;
324
+ for (const Codec& codec : codecs1) {
325
+ Codec codec_mutable = codec;
326
+ used_payload_types.FindAndSetIdUsed (&codec_mutable);
327
+ all_codecs.push_back (codec_mutable);
328
+ }
329
+
330
+ // Use MergeCodecs to merge the second half of our list as it already checks
331
+ // and fixes problems with duplicate payload types.
332
+ MergeCodecs (codecs2, all_codecs, &used_payload_types);
333
+
334
+ return all_codecs;
335
+ }
336
+
337
+ RTCError MergeCodecsFromDescription (
338
+ const std::vector<const webrtc::ContentInfo*>& current_active_contents,
339
+ CodecList& audio_codecs,
340
+ CodecList& video_codecs,
341
+ UsedPayloadTypes* used_pltypes) {
342
+ for (const ContentInfo* content : current_active_contents) {
343
+ RTCErrorOr<CodecList> checked_codec_list =
344
+ CodecList::Create (content->media_description ()->codecs ());
345
+ if (!checked_codec_list.ok ()) {
346
+ RTC_LOG (LS_ERROR) << checked_codec_list.error ();
347
+ }
348
+ if (IsMediaContentOfType (content, webrtc::MediaType::AUDIO)) {
349
+ MergeCodecs (checked_codec_list.value (), audio_codecs, used_pltypes);
350
+ } else if (IsMediaContentOfType (content, webrtc::MediaType::VIDEO)) {
351
+ MergeCodecs (checked_codec_list.value (), video_codecs, used_pltypes);
352
+ }
353
+ }
354
+ return RTCError::OK ();
355
+ }
356
+
408
357
void NegotiatePacketization (const Codec& local_codec,
409
358
const Codec& remote_codec,
410
359
Codec* negotiated_codec) {
@@ -624,25 +573,8 @@ webrtc::RTCErrorOr<std::vector<Codec>> CodecVendor::GetNegotiatedCodecsForOffer(
624
573
const MediaDescriptionOptions& media_description_options,
625
574
const MediaSessionOptions& session_options,
626
575
const webrtc::ContentInfo* current_content,
627
- PayloadTypeSuggester& pt_suggester) {
628
- CodecList codecs;
629
- std::string mid = media_description_options.mid ;
630
- // If current content exists and is not being recycled, use its codecs.
631
- if (current_content && current_content->mid () == mid) {
632
- RTCErrorOr<CodecList> checked_codec_list =
633
- CodecList::Create (current_content->media_description ()->codecs ());
634
- if (!checked_codec_list.ok ()) {
635
- return checked_codec_list.MoveError ();
636
- }
637
- // Use MergeCodecs in order to handle PT clashes.
638
- MergeCodecs (checked_codec_list.value (), mid, codecs, pt_suggester);
639
- }
640
- // Add our codecs that are not in the current description.
641
- if (media_description_options.type == webrtc::MediaType::AUDIO) {
642
- MergeCodecs (all_audio_codecs (), mid, codecs, pt_suggester);
643
- } else {
644
- MergeCodecs (all_video_codecs (), mid, codecs, pt_suggester);
645
- }
576
+ PayloadTypeSuggester& pt_suggester,
577
+ const CodecList& codecs) {
646
578
CodecList filtered_codecs;
647
579
CodecList supported_codecs =
648
580
media_description_options.type == webrtc::MediaType::AUDIO
@@ -743,7 +675,7 @@ webrtc::RTCErrorOr<std::vector<Codec>> CodecVendor::GetNegotiatedCodecsForOffer(
743
675
}
744
676
filtered_codecs = codecs_from_arg.MoveValue ();
745
677
}
746
- AssignCodecIdsAndLinkRed (&pt_suggester, mid,
678
+ AssignCodecIdsAndLinkRed (&pt_suggester, media_description_options. mid ,
747
679
filtered_codecs.writable_codecs ());
748
680
return filtered_codecs.codecs ();
749
681
}
@@ -755,23 +687,8 @@ webrtc::RTCErrorOr<Codecs> CodecVendor::GetNegotiatedCodecsForAnswer(
755
687
webrtc::RtpTransceiverDirection answer_rtd,
756
688
const webrtc::ContentInfo* current_content,
757
689
const std::vector<Codec> codecs_from_offer,
758
- PayloadTypeSuggester& pt_suggester) {
759
- CodecList codecs;
760
- std::string mid = media_description_options.mid ;
761
- if (current_content && current_content->mid () == mid) {
762
- RTCErrorOr<CodecList> checked_codec_list =
763
- CodecList::Create (current_content->media_description ()->codecs ());
764
- if (!checked_codec_list.ok ()) {
765
- return checked_codec_list.MoveError ();
766
- }
767
- MergeCodecs (checked_codec_list.value (), mid, codecs, pt_suggester);
768
- }
769
- // Add all our supported codecs
770
- if (media_description_options.type == webrtc::MediaType::AUDIO) {
771
- MergeCodecs (all_audio_codecs (), mid, codecs, pt_suggester);
772
- } else {
773
- MergeCodecs (all_video_codecs (), mid, codecs, pt_suggester);
774
- }
690
+ PayloadTypeSuggester& pt_suggester,
691
+ const CodecList& codecs) {
775
692
CodecList filtered_codecs;
776
693
CodecList negotiated_codecs;
777
694
if (media_description_options.codecs_to_include .empty ()) {
@@ -805,8 +722,20 @@ webrtc::RTCErrorOr<Codecs> CodecVendor::GetNegotiatedCodecsForAnswer(
805
722
}
806
723
}
807
724
}
808
- // Merge other_codecs into filtered_codecs, resolving PT conflicts.
809
- MergeCodecs (supported_codecs, mid, filtered_codecs, pt_suggester);
725
+ // Add other supported codecs.
726
+ CodecList other_codecs;
727
+ for (const Codec& codec : supported_codecs) {
728
+ if (FindMatchingCodec (supported_codecs, codecs, codec) &&
729
+ !FindMatchingCodec (supported_codecs, filtered_codecs, codec)) {
730
+ // We should use the local codec with local parameters and the codec
731
+ // id would be correctly mapped in `NegotiateCodecs`.
732
+ other_codecs.push_back (codec);
733
+ }
734
+ }
735
+
736
+ // Use ComputeCodecsUnion to avoid having duplicate payload IDs.
737
+ // This is a no-op for audio until RTX is added.
738
+ filtered_codecs = ComputeCodecsUnion (filtered_codecs, other_codecs);
810
739
}
811
740
812
741
if (media_description_options.type == webrtc::MediaType::AUDIO &&
@@ -892,6 +821,107 @@ void CodecVendor::set_video_codecs(const CodecList& send_codecs,
892
821
video_send_codecs_.set_codecs (send_codecs);
893
822
video_recv_codecs_.set_codecs (recv_codecs);
894
823
}
824
+ // Getting codecs for an offer involves these steps:
825
+ //
826
+ // 1. Construct payload type -> codec mappings for current description.
827
+ // 2. Add any reference codecs that weren't already present
828
+ // 3. For each individual media description (m= section), filter codecs based
829
+ // on the directional attribute (happens in another method).
830
+ RTCError CodecVendor::GetCodecsForOffer (
831
+ const std::vector<const webrtc::ContentInfo*>& current_active_contents,
832
+ CodecList& audio_codecs,
833
+ CodecList& video_codecs) const {
834
+ // First - get all codecs from the current description if the media type
835
+ // is used. Add them to `used_pltypes` so the payload type is not reused if a
836
+ // new media type is added.
837
+ UsedPayloadTypes used_pltypes;
838
+ auto error = MergeCodecsFromDescription (current_active_contents, audio_codecs,
839
+ video_codecs, &used_pltypes);
840
+ if (!error.ok ()) {
841
+ return error;
842
+ }
843
+ // Add our codecs that are not in the current description.
844
+ MergeCodecs (all_audio_codecs (), audio_codecs, &used_pltypes);
845
+ MergeCodecs (all_video_codecs (), video_codecs, &used_pltypes);
846
+ return RTCError::OK ();
847
+ }
848
+
849
+ // Getting codecs for an answer involves these steps:
850
+ //
851
+ // 1. Construct payload type -> codec mappings for current description.
852
+ // 2. Add any codecs from the offer that weren't already present.
853
+ // 3. Add any remaining codecs that weren't already present.
854
+ // 4. For each individual media description (m= section), filter codecs based
855
+ // on the directional attribute (happens in another method).
856
+ RTCError CodecVendor::GetCodecsForAnswer (
857
+ const std::vector<const webrtc::ContentInfo*>& current_active_contents,
858
+ const webrtc::SessionDescription& remote_offer,
859
+ CodecList& audio_codecs,
860
+ CodecList& video_codecs) const {
861
+ // First - get all codecs from the current description if the media type
862
+ // is used. Add them to `used_pltypes` so the payload type is not reused if a
863
+ // new media type is added.
864
+ UsedPayloadTypes used_pltypes;
865
+ RTCError error = MergeCodecsFromDescription (
866
+ current_active_contents, audio_codecs, video_codecs, &used_pltypes);
867
+ if (!error.ok ()) {
868
+ return error;
869
+ }
870
+ // Second - filter out codecs that we don't support at all and should ignore.
871
+ CodecList filtered_offered_audio_codecs;
872
+ CodecList filtered_offered_video_codecs;
873
+ for (const ContentInfo& content : remote_offer.contents ()) {
874
+ RTCErrorOr<CodecList> offered_codecs =
875
+ CodecList::Create (content.media_description ()->codecs ());
876
+ if (!offered_codecs.ok ()) {
877
+ return offered_codecs.MoveError ();
878
+ }
879
+ if (IsMediaContentOfType (&content, webrtc::MediaType::AUDIO)) {
880
+ for (const Codec& offered_audio_codec : offered_codecs.value ()) {
881
+ if (!FindMatchingCodec (offered_codecs.value (),
882
+ filtered_offered_audio_codecs,
883
+ offered_audio_codec) &&
884
+ FindMatchingCodec (offered_codecs.value (), all_audio_codecs (),
885
+ offered_audio_codec)) {
886
+ filtered_offered_audio_codecs.push_back (offered_audio_codec);
887
+ }
888
+ }
889
+ } else if (IsMediaContentOfType (&content, webrtc::MediaType::VIDEO)) {
890
+ std::vector<Codec> pending_rtx_codecs;
891
+ for (const Codec& offered_video_codec : offered_codecs.value ()) {
892
+ if (!FindMatchingCodec (offered_codecs.value (),
893
+ filtered_offered_video_codecs,
894
+ offered_video_codec) &&
895
+ FindMatchingCodec (offered_codecs.value (), all_video_codecs (),
896
+ offered_video_codec)) {
897
+ // Special case: If it's an RTX codec, and the APT points to
898
+ // a codec that is not yet in the codec list, put it aside.
899
+ if (offered_video_codec.GetResiliencyType () ==
900
+ Codec::ResiliencyType::kRtx &&
901
+ !GetAssociatedCodecForRtx (filtered_offered_video_codecs,
902
+ offered_video_codec)) {
903
+ pending_rtx_codecs.push_back (offered_video_codec);
904
+ continue ;
905
+ }
906
+ filtered_offered_video_codecs.push_back (offered_video_codec);
907
+ }
908
+ }
909
+ // If the associated codec showed up later in the codec list,
910
+ // append the corresponding RTX codec.
911
+ for (const Codec& codec : pending_rtx_codecs) {
912
+ if (GetAssociatedCodecForRtx (filtered_offered_video_codecs, codec)) {
913
+ filtered_offered_video_codecs.push_back (codec);
914
+ }
915
+ }
916
+ }
917
+ }
918
+
919
+ // Add codecs that are not in the current description but were in
920
+ // `remote_offer`.
921
+ MergeCodecs (filtered_offered_audio_codecs, audio_codecs, &used_pltypes);
922
+ MergeCodecs (filtered_offered_video_codecs, video_codecs, &used_pltypes);
923
+ return RTCError::OK ();
924
+ }
895
925
896
926
CodecList CodecVendor::GetVideoCodecsForOffer (
897
927
const RtpTransceiverDirection& direction) const {
@@ -964,19 +994,9 @@ CodecList CodecVendor::GetAudioCodecsForAnswer(
964
994
}
965
995
966
996
CodecList CodecVendor::all_video_codecs () const {
967
- CodecList all_codecs;
968
- UsedPayloadTypes used_payload_types;
969
- for (const Codec& codec : video_recv_codecs_.codecs ()) {
970
- Codec codec_mutable = codec;
971
- used_payload_types.FindAndSetIdUsed (&codec_mutable);
972
- all_codecs.push_back (codec_mutable);
973
- }
974
-
975
- // Use MergeCodecs to merge the second half of our list as it already checks
976
- // and fixes problems with duplicate payload types.
977
- MergeCodecs (video_send_codecs_.codecs (), all_codecs, &used_payload_types);
978
-
979
- return all_codecs;
997
+ // Use ComputeCodecsUnion to avoid having duplicate payload IDs
998
+ return ComputeCodecsUnion (video_recv_codecs_.codecs (),
999
+ video_send_codecs_.codecs ());
980
1000
}
981
1001
982
1002
CodecList CodecVendor::all_audio_codecs () const {
0 commit comments