@@ -166,94 +166,6 @@ const Codec* GetAssociatedCodecForRed(const CodecList& codec_list,
166166// Adds all codecs from `reference_codecs` to `offered_codecs` that don't
167167// already exist in `offered_codecs` and ensure the payload types don't
168168// 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
257169void MergeCodecs (const CodecList& reference_codecs,
258170 CodecList& offered_codecs,
259171 UsedPayloadTypes* used_pltypes) {
@@ -405,6 +317,43 @@ CodecList MatchCodecPreference(
405317 return filtered_codecs;
406318}
407319
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+
408357void NegotiatePacketization (const Codec& local_codec,
409358 const Codec& remote_codec,
410359 Codec* negotiated_codec) {
@@ -624,25 +573,8 @@ webrtc::RTCErrorOr<std::vector<Codec>> CodecVendor::GetNegotiatedCodecsForOffer(
624573 const MediaDescriptionOptions& media_description_options,
625574 const MediaSessionOptions& session_options,
626575 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) {
646578 CodecList filtered_codecs;
647579 CodecList supported_codecs =
648580 media_description_options.type == webrtc::MediaType::AUDIO
@@ -743,7 +675,7 @@ webrtc::RTCErrorOr<std::vector<Codec>> CodecVendor::GetNegotiatedCodecsForOffer(
743675 }
744676 filtered_codecs = codecs_from_arg.MoveValue ();
745677 }
746- AssignCodecIdsAndLinkRed (&pt_suggester, mid,
678+ AssignCodecIdsAndLinkRed (&pt_suggester, media_description_options. mid ,
747679 filtered_codecs.writable_codecs ());
748680 return filtered_codecs.codecs ();
749681}
@@ -755,23 +687,8 @@ webrtc::RTCErrorOr<Codecs> CodecVendor::GetNegotiatedCodecsForAnswer(
755687 webrtc::RtpTransceiverDirection answer_rtd,
756688 const webrtc::ContentInfo* current_content,
757689 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) {
775692 CodecList filtered_codecs;
776693 CodecList negotiated_codecs;
777694 if (media_description_options.codecs_to_include .empty ()) {
@@ -805,8 +722,20 @@ webrtc::RTCErrorOr<Codecs> CodecVendor::GetNegotiatedCodecsForAnswer(
805722 }
806723 }
807724 }
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);
810739 }
811740
812741 if (media_description_options.type == webrtc::MediaType::AUDIO &&
@@ -892,6 +821,107 @@ void CodecVendor::set_video_codecs(const CodecList& send_codecs,
892821 video_send_codecs_.set_codecs (send_codecs);
893822 video_recv_codecs_.set_codecs (recv_codecs);
894823}
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+ }
895925
896926CodecList CodecVendor::GetVideoCodecsForOffer (
897927 const RtpTransceiverDirection& direction) const {
@@ -964,19 +994,9 @@ CodecList CodecVendor::GetAudioCodecsForAnswer(
964994}
965995
966996CodecList 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 ());
9801000}
9811001
9821002CodecList CodecVendor::all_audio_codecs () const {
0 commit comments