1 /*
2  *  Copyright 2004 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "pc/media_session.h"
12 
13 #include <algorithm>
14 #include <functional>
15 #include <map>
16 #include <memory>
17 #include <set>
18 #include <unordered_map>
19 #include <utility>
20 
21 #include "absl/algorithm/container.h"
22 #include "absl/strings/match.h"
23 #include "absl/types/optional.h"
24 #include "api/crypto_params.h"
25 #include "media/base/h264_profile_level_id.h"
26 #include "media/base/media_constants.h"
27 #include "media/sctp/sctp_transport_internal.h"
28 #include "p2p/base/p2p_constants.h"
29 #include "pc/channel_manager.h"
30 #include "pc/media_protocol_names.h"
31 #include "pc/rtp_media_utils.h"
32 #include "pc/srtp_filter.h"
33 #include "pc/used_ids.h"
34 #include "rtc_base/checks.h"
35 #include "rtc_base/helpers.h"
36 #include "rtc_base/logging.h"
37 #include "rtc_base/third_party/base64/base64.h"
38 #include "rtc_base/unique_id_generator.h"
39 
40 namespace {
41 
42 using rtc::UniqueRandomIdGenerator;
43 using webrtc::RtpTransceiverDirection;
44 
45 const char kInline[] = "inline:";
46 
GetSupportedSdesCryptoSuiteNames(void (* func)(const webrtc::CryptoOptions &,std::vector<int> *),const webrtc::CryptoOptions & crypto_options,std::vector<std::string> * names)47 void GetSupportedSdesCryptoSuiteNames(
48     void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
49     const webrtc::CryptoOptions& crypto_options,
50     std::vector<std::string>* names) {
51   std::vector<int> crypto_suites;
52   func(crypto_options, &crypto_suites);
53   for (const auto crypto : crypto_suites) {
54     names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
55   }
56 }
57 
RtpExtensionFromCapability(const webrtc::RtpHeaderExtensionCapability & capability)58 webrtc::RtpExtension RtpExtensionFromCapability(
59     const webrtc::RtpHeaderExtensionCapability& capability) {
60   return webrtc::RtpExtension(capability.uri,
61                               capability.preferred_id.value_or(1));
62 }
63 
RtpHeaderExtensionsFromCapabilities(const std::vector<webrtc::RtpHeaderExtensionCapability> & capabilities)64 cricket::RtpHeaderExtensions RtpHeaderExtensionsFromCapabilities(
65     const std::vector<webrtc::RtpHeaderExtensionCapability>& capabilities) {
66   cricket::RtpHeaderExtensions exts;
67   for (const auto& capability : capabilities) {
68     exts.push_back(RtpExtensionFromCapability(capability));
69   }
70   return exts;
71 }
72 
73 std::vector<webrtc::RtpHeaderExtensionCapability>
UnstoppedRtpHeaderExtensionCapabilities(std::vector<webrtc::RtpHeaderExtensionCapability> capabilities)74 UnstoppedRtpHeaderExtensionCapabilities(
75     std::vector<webrtc::RtpHeaderExtensionCapability> capabilities) {
76   capabilities.erase(
77       std::remove_if(
78           capabilities.begin(), capabilities.end(),
79           [](const webrtc::RtpHeaderExtensionCapability& capability) {
80             return capability.direction == RtpTransceiverDirection::kStopped;
81           }),
82       capabilities.end());
83   return capabilities;
84 }
85 
IsCapabilityPresent(const webrtc::RtpHeaderExtensionCapability & capability,const cricket::RtpHeaderExtensions & extensions)86 bool IsCapabilityPresent(const webrtc::RtpHeaderExtensionCapability& capability,
87                          const cricket::RtpHeaderExtensions& extensions) {
88   return std::find_if(extensions.begin(), extensions.end(),
89                       [&capability](const webrtc::RtpExtension& extension) {
90                         return capability.uri == extension.uri;
91                       }) != extensions.end();
92 }
93 
UnstoppedOrPresentRtpHeaderExtensions(const std::vector<webrtc::RtpHeaderExtensionCapability> & capabilities,const cricket::RtpHeaderExtensions & unencrypted,const cricket::RtpHeaderExtensions & encrypted)94 cricket::RtpHeaderExtensions UnstoppedOrPresentRtpHeaderExtensions(
95     const std::vector<webrtc::RtpHeaderExtensionCapability>& capabilities,
96     const cricket::RtpHeaderExtensions& unencrypted,
97     const cricket::RtpHeaderExtensions& encrypted) {
98   cricket::RtpHeaderExtensions extensions;
99   for (const auto& capability : capabilities) {
100     if (capability.direction != RtpTransceiverDirection::kStopped ||
101         IsCapabilityPresent(capability, unencrypted) ||
102         IsCapabilityPresent(capability, encrypted)) {
103       extensions.push_back(RtpExtensionFromCapability(capability));
104     }
105   }
106   return extensions;
107 }
108 
109 }  // namespace
110 
111 namespace cricket {
112 
113 // RTP Profile names
114 // http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
115 // RFC4585
116 const char kMediaProtocolAvpf[] = "RTP/AVPF";
117 // RFC5124
118 const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
119 
120 // We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
121 // but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
122 const char kMediaProtocolSavpf[] = "RTP/SAVPF";
123 
124 // Note that the below functions support some protocol strings purely for
125 // legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
126 // and Interoperability.
127 
IsDtlsRtp(const std::string & protocol)128 static bool IsDtlsRtp(const std::string& protocol) {
129   // Most-likely values first.
130   return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
131          protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
132 }
133 
IsPlainRtp(const std::string & protocol)134 static bool IsPlainRtp(const std::string& protocol) {
135   // Most-likely values first.
136   return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
137          protocol == "RTP/SAVP" || protocol == "RTP/AVP";
138 }
139 
NegotiateRtpTransceiverDirection(RtpTransceiverDirection offer,RtpTransceiverDirection wants)140 static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
141     RtpTransceiverDirection offer,
142     RtpTransceiverDirection wants) {
143   bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
144   bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
145   bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
146   bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
147   return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
148                                                      offer_send && wants_recv);
149 }
150 
IsMediaContentOfType(const ContentInfo * content,MediaType media_type)151 static bool IsMediaContentOfType(const ContentInfo* content,
152                                  MediaType media_type) {
153   if (!content || !content->media_description()) {
154     return false;
155   }
156   return content->media_description()->type() == media_type;
157 }
158 
CreateCryptoParams(int tag,const std::string & cipher,CryptoParams * crypto_out)159 static bool CreateCryptoParams(int tag,
160                                const std::string& cipher,
161                                CryptoParams* crypto_out) {
162   int key_len;
163   int salt_len;
164   if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
165                                      &key_len, &salt_len)) {
166     return false;
167   }
168 
169   int master_key_len = key_len + salt_len;
170   std::string master_key;
171   if (!rtc::CreateRandomData(master_key_len, &master_key)) {
172     return false;
173   }
174 
175   RTC_CHECK_EQ(master_key_len, master_key.size());
176   std::string key = rtc::Base64::Encode(master_key);
177 
178   crypto_out->tag = tag;
179   crypto_out->cipher_suite = cipher;
180   crypto_out->key_params = kInline;
181   crypto_out->key_params += key;
182   return true;
183 }
184 
AddCryptoParams(const std::string & cipher_suite,CryptoParamsVec * cryptos_out)185 static bool AddCryptoParams(const std::string& cipher_suite,
186                             CryptoParamsVec* cryptos_out) {
187   int size = static_cast<int>(cryptos_out->size());
188 
189   cryptos_out->resize(size + 1);
190   return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
191 }
192 
AddMediaCryptos(const CryptoParamsVec & cryptos,MediaContentDescription * media)193 void AddMediaCryptos(const CryptoParamsVec& cryptos,
194                      MediaContentDescription* media) {
195   for (const CryptoParams& crypto : cryptos) {
196     media->AddCrypto(crypto);
197   }
198 }
199 
CreateMediaCryptos(const std::vector<std::string> & crypto_suites,MediaContentDescription * media)200 bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
201                         MediaContentDescription* media) {
202   CryptoParamsVec cryptos;
203   for (const std::string& crypto_suite : crypto_suites) {
204     if (!AddCryptoParams(crypto_suite, &cryptos)) {
205       return false;
206     }
207   }
208   AddMediaCryptos(cryptos, media);
209   return true;
210 }
211 
GetCryptos(const ContentInfo * content)212 const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
213   if (!content || !content->media_description()) {
214     return nullptr;
215   }
216   return &content->media_description()->cryptos();
217 }
218 
FindMatchingCrypto(const CryptoParamsVec & cryptos,const CryptoParams & crypto,CryptoParams * crypto_out)219 bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
220                         const CryptoParams& crypto,
221                         CryptoParams* crypto_out) {
222   auto it = absl::c_find_if(
223       cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
224   if (it == cryptos.end()) {
225     return false;
226   }
227   *crypto_out = *it;
228   return true;
229 }
230 
231 // For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
232 // low overhead.
GetSupportedAudioSdesCryptoSuites(const webrtc::CryptoOptions & crypto_options,std::vector<int> * crypto_suites)233 void GetSupportedAudioSdesCryptoSuites(
234     const webrtc::CryptoOptions& crypto_options,
235     std::vector<int>* crypto_suites) {
236   if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
237     crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
238   }
239   crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
240   if (crypto_options.srtp.enable_gcm_crypto_suites) {
241     crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
242     crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
243   }
244 }
245 
GetSupportedAudioSdesCryptoSuiteNames(const webrtc::CryptoOptions & crypto_options,std::vector<std::string> * crypto_suite_names)246 void GetSupportedAudioSdesCryptoSuiteNames(
247     const webrtc::CryptoOptions& crypto_options,
248     std::vector<std::string>* crypto_suite_names) {
249   GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
250                                    crypto_options, crypto_suite_names);
251 }
252 
GetSupportedVideoSdesCryptoSuites(const webrtc::CryptoOptions & crypto_options,std::vector<int> * crypto_suites)253 void GetSupportedVideoSdesCryptoSuites(
254     const webrtc::CryptoOptions& crypto_options,
255     std::vector<int>* crypto_suites) {
256   crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
257   if (crypto_options.srtp.enable_gcm_crypto_suites) {
258     crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
259     crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
260   }
261 }
262 
GetSupportedVideoSdesCryptoSuiteNames(const webrtc::CryptoOptions & crypto_options,std::vector<std::string> * crypto_suite_names)263 void GetSupportedVideoSdesCryptoSuiteNames(
264     const webrtc::CryptoOptions& crypto_options,
265     std::vector<std::string>* crypto_suite_names) {
266   GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
267                                    crypto_options, crypto_suite_names);
268 }
269 
GetSupportedDataSdesCryptoSuites(const webrtc::CryptoOptions & crypto_options,std::vector<int> * crypto_suites)270 void GetSupportedDataSdesCryptoSuites(
271     const webrtc::CryptoOptions& crypto_options,
272     std::vector<int>* crypto_suites) {
273   crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
274   if (crypto_options.srtp.enable_gcm_crypto_suites) {
275     crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
276     crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
277   }
278 }
279 
GetSupportedDataSdesCryptoSuiteNames(const webrtc::CryptoOptions & crypto_options,std::vector<std::string> * crypto_suite_names)280 void GetSupportedDataSdesCryptoSuiteNames(
281     const webrtc::CryptoOptions& crypto_options,
282     std::vector<std::string>* crypto_suite_names) {
283   GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
284                                    crypto_options, crypto_suite_names);
285 }
286 
287 // Support any GCM cipher (if enabled through options). For video support only
288 // 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
289 // bundle is enabled because it is low overhead.
290 // Pick the crypto in the list that is supported.
SelectCrypto(const MediaContentDescription * offer,bool bundle,const webrtc::CryptoOptions & crypto_options,CryptoParams * crypto_out)291 static bool SelectCrypto(const MediaContentDescription* offer,
292                          bool bundle,
293                          const webrtc::CryptoOptions& crypto_options,
294                          CryptoParams* crypto_out) {
295   bool audio = offer->type() == MEDIA_TYPE_AUDIO;
296   const CryptoParamsVec& cryptos = offer->cryptos();
297 
298   for (const CryptoParams& crypto : cryptos) {
299     if ((crypto_options.srtp.enable_gcm_crypto_suites &&
300          rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
301         rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
302         (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
303          !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
304       return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
305     }
306   }
307   return false;
308 }
309 
310 // Finds all StreamParams of all media types and attach them to stream_params.
GetCurrentStreamParams(const std::vector<const ContentInfo * > & active_local_contents)311 static StreamParamsVec GetCurrentStreamParams(
312     const std::vector<const ContentInfo*>& active_local_contents) {
313   StreamParamsVec stream_params;
314   for (const ContentInfo* content : active_local_contents) {
315     for (const StreamParams& params : content->media_description()->streams()) {
316       stream_params.push_back(params);
317     }
318   }
319   return stream_params;
320 }
321 
CreateStreamParamsForNewSenderWithSsrcs(const SenderOptions & sender,const std::string & rtcp_cname,bool include_rtx_streams,bool include_flexfec_stream,UniqueRandomIdGenerator * ssrc_generator)322 static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
323     const SenderOptions& sender,
324     const std::string& rtcp_cname,
325     bool include_rtx_streams,
326     bool include_flexfec_stream,
327     UniqueRandomIdGenerator* ssrc_generator) {
328   StreamParams result;
329   result.id = sender.track_id;
330 
331   // TODO(brandtr): Update when we support multistream protection.
332   if (include_flexfec_stream && sender.num_sim_layers > 1) {
333     include_flexfec_stream = false;
334     RTC_LOG(LS_WARNING)
335         << "Our FlexFEC implementation only supports protecting "
336            "a single media streams. This session has multiple "
337            "media streams however, so no FlexFEC SSRC will be generated.";
338   }
339 
340   result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
341                        include_flexfec_stream, ssrc_generator);
342 
343   result.cname = rtcp_cname;
344   result.set_stream_ids(sender.stream_ids);
345 
346   return result;
347 }
348 
ValidateSimulcastLayers(const std::vector<RidDescription> & rids,const SimulcastLayerList & simulcast_layers)349 static bool ValidateSimulcastLayers(
350     const std::vector<RidDescription>& rids,
351     const SimulcastLayerList& simulcast_layers) {
352   return absl::c_all_of(
353       simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
354         return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
355           return rid.rid == layer.rid;
356         });
357       });
358 }
359 
CreateStreamParamsForNewSenderWithRids(const SenderOptions & sender,const std::string & rtcp_cname)360 static StreamParams CreateStreamParamsForNewSenderWithRids(
361     const SenderOptions& sender,
362     const std::string& rtcp_cname) {
363   RTC_DCHECK(!sender.rids.empty());
364   RTC_DCHECK_EQ(sender.num_sim_layers, 0)
365       << "RIDs are the compliant way to indicate simulcast.";
366   RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
367   StreamParams result;
368   result.id = sender.track_id;
369   result.cname = rtcp_cname;
370   result.set_stream_ids(sender.stream_ids);
371 
372   // More than one rid should be signaled.
373   if (sender.rids.size() > 1) {
374     result.set_rids(sender.rids);
375   }
376 
377   return result;
378 }
379 
380 // Adds SimulcastDescription if indicated by the media description options.
381 // MediaContentDescription should already be set up with the send rids.
AddSimulcastToMediaDescription(const MediaDescriptionOptions & media_description_options,MediaContentDescription * description)382 static void AddSimulcastToMediaDescription(
383     const MediaDescriptionOptions& media_description_options,
384     MediaContentDescription* description) {
385   RTC_DCHECK(description);
386 
387   // Check if we are using RIDs in this scenario.
388   if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
389         return !params.has_rids();
390       })) {
391     return;
392   }
393 
394   RTC_DCHECK_EQ(1, description->streams().size())
395       << "RIDs are only supported in Unified Plan semantics.";
396   RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
397   RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
398              description->type() == MediaType::MEDIA_TYPE_VIDEO);
399 
400   // One RID or less indicates that simulcast is not needed.
401   if (description->streams()[0].rids().size() <= 1) {
402     return;
403   }
404 
405   // Only negotiate the send layers.
406   SimulcastDescription simulcast;
407   simulcast.send_layers() =
408       media_description_options.sender_options[0].simulcast_layers;
409   description->set_simulcast_description(simulcast);
410 }
411 
412 // Adds a StreamParams for each SenderOptions in |sender_options| to
413 // content_description.
414 // |current_params| - All currently known StreamParams of any media type.
415 template <class C>
AddStreamParams(const std::vector<SenderOptions> & sender_options,const std::string & rtcp_cname,UniqueRandomIdGenerator * ssrc_generator,StreamParamsVec * current_streams,MediaContentDescriptionImpl<C> * content_description)416 static bool AddStreamParams(
417     const std::vector<SenderOptions>& sender_options,
418     const std::string& rtcp_cname,
419     UniqueRandomIdGenerator* ssrc_generator,
420     StreamParamsVec* current_streams,
421     MediaContentDescriptionImpl<C>* content_description) {
422   // SCTP streams are not negotiated using SDP/ContentDescriptions.
423   if (IsSctpProtocol(content_description->protocol())) {
424     return true;
425   }
426 
427   const bool include_rtx_streams =
428       ContainsRtxCodec(content_description->codecs());
429 
430   const bool include_flexfec_stream =
431       ContainsFlexfecCodec(content_description->codecs());
432 
433   for (const SenderOptions& sender : sender_options) {
434     // groupid is empty for StreamParams generated using
435     // MediaSessionDescriptionFactory.
436     StreamParams* param =
437         GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
438     if (!param) {
439       // This is a new sender.
440       StreamParams stream_param =
441           sender.rids.empty()
442               ?
443               // Signal SSRCs and legacy simulcast (if requested).
444               CreateStreamParamsForNewSenderWithSsrcs(
445                   sender, rtcp_cname, include_rtx_streams,
446                   include_flexfec_stream, ssrc_generator)
447               :
448               // Signal RIDs and spec-compliant simulcast (if requested).
449               CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
450 
451       content_description->AddStream(stream_param);
452 
453       // Store the new StreamParams in current_streams.
454       // This is necessary so that we can use the CNAME for other media types.
455       current_streams->push_back(stream_param);
456     } else {
457       // Use existing generated SSRCs/groups, but update the sync_label if
458       // necessary. This may be needed if a MediaStreamTrack was moved from one
459       // MediaStream to another.
460       param->set_stream_ids(sender.stream_ids);
461       content_description->AddStream(*param);
462     }
463   }
464   return true;
465 }
466 
467 // Updates the transport infos of the |sdesc| according to the given
468 // |bundle_group|. The transport infos of the content names within the
469 // |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
470 // first content within the |bundle_group|.
UpdateTransportInfoForBundle(const ContentGroup & bundle_group,SessionDescription * sdesc)471 static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
472                                          SessionDescription* sdesc) {
473   // The bundle should not be empty.
474   if (!sdesc || !bundle_group.FirstContentName()) {
475     return false;
476   }
477 
478   // We should definitely have a transport for the first content.
479   const std::string& selected_content_name = *bundle_group.FirstContentName();
480   const TransportInfo* selected_transport_info =
481       sdesc->GetTransportInfoByName(selected_content_name);
482   if (!selected_transport_info) {
483     return false;
484   }
485 
486   // Set the other contents to use the same ICE credentials.
487   const std::string& selected_ufrag =
488       selected_transport_info->description.ice_ufrag;
489   const std::string& selected_pwd =
490       selected_transport_info->description.ice_pwd;
491   ConnectionRole selected_connection_role =
492       selected_transport_info->description.connection_role;
493   for (TransportInfo& transport_info : sdesc->transport_infos()) {
494     if (bundle_group.HasContentName(transport_info.content_name) &&
495         transport_info.content_name != selected_content_name) {
496       transport_info.description.ice_ufrag = selected_ufrag;
497       transport_info.description.ice_pwd = selected_pwd;
498       transport_info.description.connection_role = selected_connection_role;
499     }
500   }
501   return true;
502 }
503 
504 // Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
505 // sets it to |cryptos|.
GetCryptosByName(const SessionDescription * sdesc,const std::string & content_name,CryptoParamsVec * cryptos)506 static bool GetCryptosByName(const SessionDescription* sdesc,
507                              const std::string& content_name,
508                              CryptoParamsVec* cryptos) {
509   if (!sdesc || !cryptos) {
510     return false;
511   }
512   const ContentInfo* content = sdesc->GetContentByName(content_name);
513   if (!content || !content->media_description()) {
514     return false;
515   }
516   *cryptos = content->media_description()->cryptos();
517   return true;
518 }
519 
520 // Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
521 // which are not available in |filter|.
PruneCryptos(const CryptoParamsVec & filter,CryptoParamsVec * target_cryptos)522 static void PruneCryptos(const CryptoParamsVec& filter,
523                          CryptoParamsVec* target_cryptos) {
524   if (!target_cryptos) {
525     return;
526   }
527 
528   target_cryptos->erase(
529       std::remove_if(target_cryptos->begin(), target_cryptos->end(),
530                      // Returns true if the |crypto|'s cipher_suite is not
531                      // found in |filter|.
532                      [&filter](const CryptoParams& crypto) {
533                        for (const CryptoParams& entry : filter) {
534                          if (entry.cipher_suite == crypto.cipher_suite)
535                            return false;
536                        }
537                        return true;
538                      }),
539       target_cryptos->end());
540 }
541 
IsRtpContent(SessionDescription * sdesc,const std::string & content_name)542 static bool IsRtpContent(SessionDescription* sdesc,
543                          const std::string& content_name) {
544   bool is_rtp = false;
545   ContentInfo* content = sdesc->GetContentByName(content_name);
546   if (content && content->media_description()) {
547     is_rtp = IsRtpProtocol(content->media_description()->protocol());
548   }
549   return is_rtp;
550 }
551 
552 // Updates the crypto parameters of the |sdesc| according to the given
553 // |bundle_group|. The crypto parameters of all the contents within the
554 // |bundle_group| should be updated to use the common subset of the
555 // available cryptos.
UpdateCryptoParamsForBundle(const ContentGroup & bundle_group,SessionDescription * sdesc)556 static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
557                                         SessionDescription* sdesc) {
558   // The bundle should not be empty.
559   if (!sdesc || !bundle_group.FirstContentName()) {
560     return false;
561   }
562 
563   bool common_cryptos_needed = false;
564   // Get the common cryptos.
565   const ContentNames& content_names = bundle_group.content_names();
566   CryptoParamsVec common_cryptos;
567   bool first = true;
568   for (const std::string& content_name : content_names) {
569     if (!IsRtpContent(sdesc, content_name)) {
570       continue;
571     }
572     // The common cryptos are needed if any of the content does not have DTLS
573     // enabled.
574     if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
575       common_cryptos_needed = true;
576     }
577     if (first) {
578       first = false;
579       // Initial the common_cryptos with the first content in the bundle group.
580       if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
581         return false;
582       }
583       if (common_cryptos.empty()) {
584         // If there's no crypto params, we should just return.
585         return true;
586       }
587     } else {
588       CryptoParamsVec cryptos;
589       if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
590         return false;
591       }
592       PruneCryptos(cryptos, &common_cryptos);
593     }
594   }
595 
596   if (common_cryptos.empty() && common_cryptos_needed) {
597     return false;
598   }
599 
600   // Update to use the common cryptos.
601   for (const std::string& content_name : content_names) {
602     if (!IsRtpContent(sdesc, content_name)) {
603       continue;
604     }
605     ContentInfo* content = sdesc->GetContentByName(content_name);
606     if (IsMediaContent(content)) {
607       MediaContentDescription* media_desc = content->media_description();
608       if (!media_desc) {
609         return false;
610       }
611       media_desc->set_cryptos(common_cryptos);
612     }
613   }
614   return true;
615 }
616 
GetActiveContents(const SessionDescription & description,const MediaSessionOptions & session_options)617 static std::vector<const ContentInfo*> GetActiveContents(
618     const SessionDescription& description,
619     const MediaSessionOptions& session_options) {
620   std::vector<const ContentInfo*> active_contents;
621   for (size_t i = 0; i < description.contents().size(); ++i) {
622     RTC_DCHECK_LT(i, session_options.media_description_options.size());
623     const ContentInfo& content = description.contents()[i];
624     const MediaDescriptionOptions& media_options =
625         session_options.media_description_options[i];
626     if (!content.rejected && !media_options.stopped &&
627         content.name == media_options.mid) {
628       active_contents.push_back(&content);
629     }
630   }
631   return active_contents;
632 }
633 
634 template <class C>
ContainsRtxCodec(const std::vector<C> & codecs)635 static bool ContainsRtxCodec(const std::vector<C>& codecs) {
636   for (const auto& codec : codecs) {
637     if (IsRtxCodec(codec)) {
638       return true;
639     }
640   }
641   return false;
642 }
643 
644 template <class C>
IsRtxCodec(const C & codec)645 static bool IsRtxCodec(const C& codec) {
646   return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
647 }
648 
649 template <class C>
ContainsFlexfecCodec(const std::vector<C> & codecs)650 static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
651   for (const auto& codec : codecs) {
652     if (IsFlexfecCodec(codec)) {
653       return true;
654     }
655   }
656   return false;
657 }
658 
659 template <class C>
IsFlexfecCodec(const C & codec)660 static bool IsFlexfecCodec(const C& codec) {
661   return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
662 }
663 
664 // Create a media content to be offered for the given |sender_options|,
665 // according to the given options.rtcp_mux, session_options.is_muc, codecs,
666 // secure_transport, crypto, and current_streams. If we don't currently have
667 // crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
668 // created (according to crypto_suites). The created content is added to the
669 // offer.
CreateContentOffer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const SecurePolicy & secure_policy,const CryptoParamsVec * current_cryptos,const std::vector<std::string> & crypto_suites,const RtpHeaderExtensions & rtp_extensions,UniqueRandomIdGenerator * ssrc_generator,StreamParamsVec * current_streams,MediaContentDescription * offer)670 static bool CreateContentOffer(
671     const MediaDescriptionOptions& media_description_options,
672     const MediaSessionOptions& session_options,
673     const SecurePolicy& secure_policy,
674     const CryptoParamsVec* current_cryptos,
675     const std::vector<std::string>& crypto_suites,
676     const RtpHeaderExtensions& rtp_extensions,
677     UniqueRandomIdGenerator* ssrc_generator,
678     StreamParamsVec* current_streams,
679     MediaContentDescription* offer) {
680   offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
681   if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
682     offer->set_rtcp_reduced_size(true);
683   }
684 
685   // Build the vector of header extensions with directions for this
686   // media_description's options.
687   RtpHeaderExtensions extensions;
688   for (auto extension_with_id : rtp_extensions) {
689     for (const auto& extension : media_description_options.header_extensions) {
690       if (extension_with_id.uri == extension.uri) {
691         // TODO(crbug.com/1051821): Configure the extension direction from
692         // the information in the media_description_options extension
693         // capability.
694         extensions.push_back(extension_with_id);
695       }
696     }
697   }
698   offer->set_rtp_header_extensions(extensions);
699 
700   AddSimulcastToMediaDescription(media_description_options, offer);
701 
702   if (secure_policy != SEC_DISABLED) {
703     if (current_cryptos) {
704       AddMediaCryptos(*current_cryptos, offer);
705     }
706     if (offer->cryptos().empty()) {
707       if (!CreateMediaCryptos(crypto_suites, offer)) {
708         return false;
709       }
710     }
711   }
712 
713   if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
714     return false;
715   }
716   return true;
717 }
718 template <class C>
CreateMediaContentOffer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const std::vector<C> & codecs,const SecurePolicy & secure_policy,const CryptoParamsVec * current_cryptos,const std::vector<std::string> & crypto_suites,const RtpHeaderExtensions & rtp_extensions,UniqueRandomIdGenerator * ssrc_generator,StreamParamsVec * current_streams,MediaContentDescriptionImpl<C> * offer)719 static bool CreateMediaContentOffer(
720     const MediaDescriptionOptions& media_description_options,
721     const MediaSessionOptions& session_options,
722     const std::vector<C>& codecs,
723     const SecurePolicy& secure_policy,
724     const CryptoParamsVec* current_cryptos,
725     const std::vector<std::string>& crypto_suites,
726     const RtpHeaderExtensions& rtp_extensions,
727     UniqueRandomIdGenerator* ssrc_generator,
728     StreamParamsVec* current_streams,
729     MediaContentDescriptionImpl<C>* offer) {
730   offer->AddCodecs(codecs);
731   if (!AddStreamParams(media_description_options.sender_options,
732                        session_options.rtcp_cname, ssrc_generator,
733                        current_streams, offer)) {
734     return false;
735   }
736 
737   return CreateContentOffer(media_description_options, session_options,
738                             secure_policy, current_cryptos, crypto_suites,
739                             rtp_extensions, ssrc_generator, current_streams,
740                             offer);
741 }
742 
743 template <class C>
ReferencedCodecsMatch(const std::vector<C> & codecs1,const int codec1_id,const std::vector<C> & codecs2,const int codec2_id)744 static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
745                                   const int codec1_id,
746                                   const std::vector<C>& codecs2,
747                                   const int codec2_id) {
748   const C* codec1 = FindCodecById(codecs1, codec1_id);
749   const C* codec2 = FindCodecById(codecs2, codec2_id);
750   return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
751 }
752 
753 template <class C>
NegotiatePacketization(const C & local_codec,const C & remote_codec,C * negotiated_codec)754 static void NegotiatePacketization(const C& local_codec,
755                                    const C& remote_codec,
756                                    C* negotiated_codec) {}
757 
758 template <>
NegotiatePacketization(const VideoCodec & local_codec,const VideoCodec & remote_codec,VideoCodec * negotiated_codec)759 void NegotiatePacketization(const VideoCodec& local_codec,
760                             const VideoCodec& remote_codec,
761                             VideoCodec* negotiated_codec) {
762   negotiated_codec->packetization =
763       VideoCodec::IntersectPacketization(local_codec, remote_codec);
764 }
765 
766 template <class C>
NegotiateCodecs(const std::vector<C> & local_codecs,const std::vector<C> & offered_codecs,std::vector<C> * negotiated_codecs,bool keep_offer_order)767 static void NegotiateCodecs(const std::vector<C>& local_codecs,
768                             const std::vector<C>& offered_codecs,
769                             std::vector<C>* negotiated_codecs,
770                             bool keep_offer_order) {
771   for (const C& ours : local_codecs) {
772     C theirs;
773     // Note that we intentionally only find one matching codec for each of our
774     // local codecs, in case the remote offer contains duplicate codecs.
775     if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
776       C negotiated = ours;
777       NegotiatePacketization(ours, theirs, &negotiated);
778       negotiated.IntersectFeedbackParams(theirs);
779       if (IsRtxCodec(negotiated)) {
780         const auto apt_it =
781             theirs.params.find(kCodecParamAssociatedPayloadType);
782         // FindMatchingCodec shouldn't return something with no apt value.
783         RTC_DCHECK(apt_it != theirs.params.end());
784         negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
785       }
786       if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
787         webrtc::H264::GenerateProfileLevelIdForAnswer(
788             ours.params, theirs.params, &negotiated.params);
789       }
790       negotiated.id = theirs.id;
791       negotiated.name = theirs.name;
792       negotiated_codecs->push_back(std::move(negotiated));
793     }
794   }
795   if (keep_offer_order) {
796     // RFC3264: Although the answerer MAY list the formats in their desired
797     // order of preference, it is RECOMMENDED that unless there is a
798     // specific reason, the answerer list formats in the same relative order
799     // they were present in the offer.
800     // This can be skipped when the transceiver has any codec preferences.
801     std::unordered_map<int, int> payload_type_preferences;
802     int preference = static_cast<int>(offered_codecs.size() + 1);
803     for (const C& codec : offered_codecs) {
804       payload_type_preferences[codec.id] = preference--;
805     }
806     absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
807                                                                  const C& b) {
808       return payload_type_preferences[a.id] > payload_type_preferences[b.id];
809     });
810   }
811 }
812 
813 // Finds a codec in |codecs2| that matches |codec_to_match|, which is
814 // a member of |codecs1|. If |codec_to_match| is an RTX codec, both
815 // the codecs themselves and their associated codecs must match.
816 template <class C>
FindMatchingCodec(const std::vector<C> & codecs1,const std::vector<C> & codecs2,const C & codec_to_match,C * found_codec)817 static bool FindMatchingCodec(const std::vector<C>& codecs1,
818                               const std::vector<C>& codecs2,
819                               const C& codec_to_match,
820                               C* found_codec) {
821   // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
822   // codecs' associated codecs correctly. If not, that's a programming error.
823   RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
824     return &codec == &codec_to_match;
825   }));
826   for (const C& potential_match : codecs2) {
827     if (potential_match.Matches(codec_to_match)) {
828       if (IsRtxCodec(codec_to_match)) {
829         int apt_value_1 = 0;
830         int apt_value_2 = 0;
831         if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
832                                      &apt_value_1) ||
833             !potential_match.GetParam(kCodecParamAssociatedPayloadType,
834                                       &apt_value_2)) {
835           RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
836           continue;
837         }
838         if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
839                                    apt_value_2)) {
840           continue;
841         }
842       }
843       if (found_codec) {
844         *found_codec = potential_match;
845       }
846       return true;
847     }
848   }
849   return false;
850 }
851 
852 // Find the codec in |codec_list| that |rtx_codec| is associated with.
853 template <class C>
GetAssociatedCodec(const std::vector<C> & codec_list,const C & rtx_codec)854 static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
855                                    const C& rtx_codec) {
856   std::string associated_pt_str;
857   if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
858                           &associated_pt_str)) {
859     RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
860                         << " is missing an associated payload type.";
861     return nullptr;
862   }
863 
864   int associated_pt;
865   if (!rtc::FromString(associated_pt_str, &associated_pt)) {
866     RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
867                         << " of RTX codec " << rtx_codec.name
868                         << " to an integer.";
869     return nullptr;
870   }
871 
872   // Find the associated reference codec for the reference RTX codec.
873   const C* associated_codec = FindCodecById(codec_list, associated_pt);
874   if (!associated_codec) {
875     RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
876                         << associated_pt << " for RTX codec " << rtx_codec.name
877                         << ".";
878   }
879   return associated_codec;
880 }
881 
882 // Adds all codecs from |reference_codecs| to |offered_codecs| that don't
883 // already exist in |offered_codecs| and ensure the payload types don't
884 // collide.
885 template <class C>
MergeCodecs(const std::vector<C> & reference_codecs,std::vector<C> * offered_codecs,UsedPayloadTypes * used_pltypes)886 static void MergeCodecs(const std::vector<C>& reference_codecs,
887                         std::vector<C>* offered_codecs,
888                         UsedPayloadTypes* used_pltypes) {
889   // Add all new codecs that are not RTX codecs.
890   for (const C& reference_codec : reference_codecs) {
891     if (!IsRtxCodec(reference_codec) &&
892         !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
893                               reference_codec, nullptr)) {
894       C codec = reference_codec;
895       used_pltypes->FindAndSetIdUsed(&codec);
896       offered_codecs->push_back(codec);
897     }
898   }
899 
900   // Add all new RTX codecs.
901   for (const C& reference_codec : reference_codecs) {
902     if (IsRtxCodec(reference_codec) &&
903         !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
904                               reference_codec, nullptr)) {
905       C rtx_codec = reference_codec;
906       const C* associated_codec =
907           GetAssociatedCodec(reference_codecs, rtx_codec);
908       if (!associated_codec) {
909         continue;
910       }
911       // Find a codec in the offered list that matches the reference codec.
912       // Its payload type may be different than the reference codec.
913       C matching_codec;
914       if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
915                                 *associated_codec, &matching_codec)) {
916         RTC_LOG(LS_WARNING)
917             << "Couldn't find matching " << associated_codec->name << " codec.";
918         continue;
919       }
920 
921       rtx_codec.params[kCodecParamAssociatedPayloadType] =
922           rtc::ToString(matching_codec.id);
923       used_pltypes->FindAndSetIdUsed(&rtx_codec);
924       offered_codecs->push_back(rtx_codec);
925     }
926   }
927 }
928 
929 template <typename Codecs>
MatchCodecPreference(const std::vector<webrtc::RtpCodecCapability> & codec_preferences,const Codecs & codecs)930 static Codecs MatchCodecPreference(
931     const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
932     const Codecs& codecs) {
933   Codecs filtered_codecs;
934   std::set<std::string> kept_codecs_ids;
935   bool want_rtx = false;
936 
937   for (const auto& codec_preference : codec_preferences) {
938     auto found_codec = absl::c_find_if(
939         codecs, [&codec_preference](const typename Codecs::value_type& codec) {
940           webrtc::RtpCodecParameters codec_parameters =
941               codec.ToCodecParameters();
942           return codec_parameters.name == codec_preference.name &&
943                  codec_parameters.kind == codec_preference.kind &&
944                  codec_parameters.num_channels ==
945                      codec_preference.num_channels &&
946                  codec_parameters.clock_rate == codec_preference.clock_rate &&
947                  codec_parameters.parameters == codec_preference.parameters;
948         });
949 
950     if (found_codec != codecs.end()) {
951       filtered_codecs.push_back(*found_codec);
952       kept_codecs_ids.insert(std::to_string(found_codec->id));
953     } else if (IsRtxCodec(codec_preference)) {
954       want_rtx = true;
955     }
956   }
957 
958   if (want_rtx) {
959     for (const auto& codec : codecs) {
960       if (IsRtxCodec(codec)) {
961         const auto apt =
962             codec.params.find(cricket::kCodecParamAssociatedPayloadType);
963         if (apt != codec.params.end() &&
964             kept_codecs_ids.count(apt->second) > 0) {
965           filtered_codecs.push_back(codec);
966         }
967       }
968     }
969   }
970 
971   return filtered_codecs;
972 }
973 
FindByUriAndEncryption(const RtpHeaderExtensions & extensions,const webrtc::RtpExtension & ext_to_match,webrtc::RtpExtension * found_extension)974 static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
975                                    const webrtc::RtpExtension& ext_to_match,
976                                    webrtc::RtpExtension* found_extension) {
977   auto it = absl::c_find_if(
978       extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
979         // We assume that all URIs are given in a canonical
980         // format.
981         return extension.uri == ext_to_match.uri &&
982                extension.encrypt == ext_to_match.encrypt;
983       });
984   if (it == extensions.end()) {
985     return false;
986   }
987   if (found_extension) {
988     *found_extension = *it;
989   }
990   return true;
991 }
992 
FindByUri(const RtpHeaderExtensions & extensions,const webrtc::RtpExtension & ext_to_match,webrtc::RtpExtension * found_extension)993 static bool FindByUri(const RtpHeaderExtensions& extensions,
994                       const webrtc::RtpExtension& ext_to_match,
995                       webrtc::RtpExtension* found_extension) {
996   // We assume that all URIs are given in a canonical format.
997   const webrtc::RtpExtension* found =
998       webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
999                                                      ext_to_match.uri);
1000   if (!found) {
1001     return false;
1002   }
1003   if (found_extension) {
1004     *found_extension = *found;
1005   }
1006   return true;
1007 }
1008 
FindByUriWithEncryptionPreference(const RtpHeaderExtensions & extensions,absl::string_view uri_to_match,bool encryption_preference,webrtc::RtpExtension * found_extension)1009 static bool FindByUriWithEncryptionPreference(
1010     const RtpHeaderExtensions& extensions,
1011     absl::string_view uri_to_match,
1012     bool encryption_preference,
1013     webrtc::RtpExtension* found_extension) {
1014   const webrtc::RtpExtension* unencrypted_extension = nullptr;
1015   for (const webrtc::RtpExtension& extension : extensions) {
1016     // We assume that all URIs are given in a canonical format.
1017     if (extension.uri == uri_to_match) {
1018       if (!encryption_preference || extension.encrypt) {
1019         if (found_extension) {
1020           *found_extension = extension;
1021         }
1022         return true;
1023       }
1024       unencrypted_extension = &extension;
1025     }
1026   }
1027   if (unencrypted_extension) {
1028     if (found_extension) {
1029       *found_extension = *unencrypted_extension;
1030     }
1031     return true;
1032   }
1033   return false;
1034 }
1035 
1036 // Adds all extensions from |reference_extensions| to |offered_extensions| that
1037 // don't already exist in |offered_extensions| and ensure the IDs don't
1038 // collide. If an extension is added, it's also added to |regular_extensions| or
1039 // |encrypted_extensions|, and if the extension is in |regular_extensions| or
1040 // |encrypted_extensions|, its ID is marked as used in |used_ids|.
1041 // |offered_extensions| is for either audio or video while |regular_extensions|
1042 // and |encrypted_extensions| are used for both audio and video. There could be
1043 // overlap between audio extensions and video extensions.
MergeRtpHdrExts(const RtpHeaderExtensions & reference_extensions,RtpHeaderExtensions * offered_extensions,RtpHeaderExtensions * regular_extensions,RtpHeaderExtensions * encrypted_extensions,UsedRtpHeaderExtensionIds * used_ids)1044 static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1045                             RtpHeaderExtensions* offered_extensions,
1046                             RtpHeaderExtensions* regular_extensions,
1047                             RtpHeaderExtensions* encrypted_extensions,
1048                             UsedRtpHeaderExtensionIds* used_ids) {
1049   for (auto reference_extension : reference_extensions) {
1050     if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1051                                 nullptr)) {
1052       webrtc::RtpExtension existing;
1053       if (reference_extension.encrypt) {
1054         if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1055                                    &existing)) {
1056           offered_extensions->push_back(existing);
1057         } else {
1058           used_ids->FindAndSetIdUsed(&reference_extension);
1059           encrypted_extensions->push_back(reference_extension);
1060           offered_extensions->push_back(reference_extension);
1061         }
1062       } else {
1063         if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1064                                    &existing)) {
1065           offered_extensions->push_back(existing);
1066         } else {
1067           used_ids->FindAndSetIdUsed(&reference_extension);
1068           regular_extensions->push_back(reference_extension);
1069           offered_extensions->push_back(reference_extension);
1070         }
1071       }
1072     }
1073   }
1074 }
1075 
AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions * extensions,RtpHeaderExtensions * all_extensions,UsedRtpHeaderExtensionIds * used_ids)1076 static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1077                                           RtpHeaderExtensions* all_extensions,
1078                                           UsedRtpHeaderExtensionIds* used_ids) {
1079   RtpHeaderExtensions encrypted_extensions;
1080   for (const webrtc::RtpExtension& extension : *extensions) {
1081     webrtc::RtpExtension existing;
1082     // Don't add encrypted extensions again that were already included in a
1083     // previous offer or regular extensions that are also included as encrypted
1084     // extensions.
1085     if (extension.encrypt ||
1086         !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1087         (FindByUriWithEncryptionPreference(*extensions, extension.uri, true,
1088                                            &existing) &&
1089          existing.encrypt)) {
1090       continue;
1091     }
1092 
1093     if (FindByUri(*all_extensions, extension, &existing)) {
1094       encrypted_extensions.push_back(existing);
1095     } else {
1096       webrtc::RtpExtension encrypted(extension);
1097       encrypted.encrypt = true;
1098       used_ids->FindAndSetIdUsed(&encrypted);
1099       all_extensions->push_back(encrypted);
1100       encrypted_extensions.push_back(encrypted);
1101     }
1102   }
1103   extensions->insert(extensions->end(), encrypted_extensions.begin(),
1104                      encrypted_extensions.end());
1105 }
1106 
NegotiateRtpHeaderExtensions(const RtpHeaderExtensions & local_extensions,const RtpHeaderExtensions & offered_extensions,bool enable_encrypted_rtp_header_extensions,RtpHeaderExtensions * negotiated_extensions)1107 static void NegotiateRtpHeaderExtensions(
1108     const RtpHeaderExtensions& local_extensions,
1109     const RtpHeaderExtensions& offered_extensions,
1110     bool enable_encrypted_rtp_header_extensions,
1111     RtpHeaderExtensions* negotiated_extensions) {
1112   // TransportSequenceNumberV2 is not offered by default. The special logic for
1113   // the TransportSequenceNumber extensions works as follows:
1114   // Offer       Answer
1115   // V1          V1 if in local_extensions.
1116   // V1 and V2   V2 regardless of local_extensions.
1117   // V2          V2 regardless of local_extensions.
1118   const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1119       webrtc::RtpExtension::FindHeaderExtensionByUri(
1120           offered_extensions,
1121           webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1122 
1123   bool frame_descriptor_in_local = false;
1124   bool dependency_descriptor_in_local = false;
1125   bool abs_capture_time_in_local = false;
1126 
1127   for (const webrtc::RtpExtension& ours : local_extensions) {
1128     if (ours.uri == webrtc::RtpExtension::kGenericFrameDescriptorUri00)
1129       frame_descriptor_in_local = true;
1130     else if (ours.uri == webrtc::RtpExtension::kDependencyDescriptorUri)
1131       dependency_descriptor_in_local = true;
1132     else if (ours.uri == webrtc::RtpExtension::kAbsoluteCaptureTimeUri)
1133       abs_capture_time_in_local = true;
1134     webrtc::RtpExtension theirs;
1135     if (FindByUriWithEncryptionPreference(
1136             offered_extensions, ours.uri,
1137             enable_encrypted_rtp_header_extensions, &theirs)) {
1138       if (transport_sequence_number_v2_offer &&
1139           ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1140         // Don't respond to
1141         // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1142         // if we get an offer including
1143         // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
1144         continue;
1145       } else {
1146         // We respond with their RTP header extension id.
1147         negotiated_extensions->push_back(theirs);
1148       }
1149     }
1150   }
1151 
1152   if (transport_sequence_number_v2_offer) {
1153     // Respond that we support kTransportSequenceNumberV2Uri.
1154     negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1155   }
1156 
1157   // Frame descriptors support. If the extension is not present locally, but is
1158   // in the offer, we add it to the list.
1159   webrtc::RtpExtension theirs;
1160   if (!dependency_descriptor_in_local &&
1161       FindByUriWithEncryptionPreference(
1162           offered_extensions, webrtc::RtpExtension::kDependencyDescriptorUri,
1163           enable_encrypted_rtp_header_extensions, &theirs)) {
1164     negotiated_extensions->push_back(theirs);
1165   }
1166   if (!frame_descriptor_in_local &&
1167       FindByUriWithEncryptionPreference(
1168           offered_extensions,
1169           webrtc::RtpExtension::kGenericFrameDescriptorUri00,
1170           enable_encrypted_rtp_header_extensions, &theirs)) {
1171     negotiated_extensions->push_back(theirs);
1172   }
1173 
1174   // Absolute capture time support. If the extension is not present locally, but
1175   // is in the offer, we add it to the list.
1176   if (!abs_capture_time_in_local &&
1177       FindByUriWithEncryptionPreference(
1178           offered_extensions, webrtc::RtpExtension::kAbsoluteCaptureTimeUri,
1179           enable_encrypted_rtp_header_extensions, &theirs)) {
1180     negotiated_extensions->push_back(theirs);
1181   }
1182 }
1183 
StripCNCodecs(AudioCodecs * audio_codecs)1184 static void StripCNCodecs(AudioCodecs* audio_codecs) {
1185   audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1186                                      [](const AudioCodec& codec) {
1187                                        return absl::EqualsIgnoreCase(
1188                                            codec.name, kComfortNoiseCodecName);
1189                                      }),
1190                       audio_codecs->end());
1191 }
1192 
1193 template <class C>
SetCodecsInAnswer(const MediaContentDescriptionImpl<C> * offer,const std::vector<C> & local_codecs,const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,UniqueRandomIdGenerator * ssrc_generator,StreamParamsVec * current_streams,MediaContentDescriptionImpl<C> * answer)1194 static bool SetCodecsInAnswer(
1195     const MediaContentDescriptionImpl<C>* offer,
1196     const std::vector<C>& local_codecs,
1197     const MediaDescriptionOptions& media_description_options,
1198     const MediaSessionOptions& session_options,
1199     UniqueRandomIdGenerator* ssrc_generator,
1200     StreamParamsVec* current_streams,
1201     MediaContentDescriptionImpl<C>* answer) {
1202   std::vector<C> negotiated_codecs;
1203   NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1204                   media_description_options.codec_preferences.empty());
1205   answer->AddCodecs(negotiated_codecs);
1206   answer->set_protocol(offer->protocol());
1207   if (!AddStreamParams(media_description_options.sender_options,
1208                        session_options.rtcp_cname, ssrc_generator,
1209                        current_streams, answer)) {
1210     return false;  // Something went seriously wrong.
1211   }
1212   return true;
1213 }
1214 
1215 // Create a media content to be answered for the given |sender_options|
1216 // according to the given session_options.rtcp_mux, session_options.streams,
1217 // codecs, crypto, and current_streams.  If we don't currently have crypto (in
1218 // current_cryptos) and it is enabled (in secure_policy), crypto is created
1219 // (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1220 // negotiated with the offer. If the negotiation fails, this method returns
1221 // false.  The created content is added to the offer.
CreateMediaContentAnswer(const MediaContentDescription * offer,const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const SecurePolicy & sdes_policy,const CryptoParamsVec * current_cryptos,const RtpHeaderExtensions & local_rtp_extensions,UniqueRandomIdGenerator * ssrc_generator,bool enable_encrypted_rtp_header_extensions,StreamParamsVec * current_streams,bool bundle_enabled,MediaContentDescription * answer)1222 static bool CreateMediaContentAnswer(
1223     const MediaContentDescription* offer,
1224     const MediaDescriptionOptions& media_description_options,
1225     const MediaSessionOptions& session_options,
1226     const SecurePolicy& sdes_policy,
1227     const CryptoParamsVec* current_cryptos,
1228     const RtpHeaderExtensions& local_rtp_extensions,
1229     UniqueRandomIdGenerator* ssrc_generator,
1230     bool enable_encrypted_rtp_header_extensions,
1231     StreamParamsVec* current_streams,
1232     bool bundle_enabled,
1233     MediaContentDescription* answer) {
1234   answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
1235   RtpHeaderExtensions negotiated_rtp_extensions;
1236   NegotiateRtpHeaderExtensions(
1237       local_rtp_extensions, offer->rtp_header_extensions(),
1238       enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
1239   answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1240 
1241   answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
1242   if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1243     answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1244   }
1245 
1246   answer->set_remote_estimate(offer->remote_estimate());
1247 
1248   if (sdes_policy != SEC_DISABLED) {
1249     CryptoParams crypto;
1250     if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1251                      &crypto)) {
1252       if (current_cryptos) {
1253         FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1254       }
1255       answer->AddCrypto(crypto);
1256     }
1257   }
1258 
1259   if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
1260     return false;
1261   }
1262 
1263   AddSimulcastToMediaDescription(media_description_options, answer);
1264 
1265   answer->set_direction(NegotiateRtpTransceiverDirection(
1266       offer->direction(), media_description_options.direction));
1267 
1268   return true;
1269 }
1270 
IsMediaProtocolSupported(MediaType type,const std::string & protocol,bool secure_transport)1271 static bool IsMediaProtocolSupported(MediaType type,
1272                                      const std::string& protocol,
1273                                      bool secure_transport) {
1274   // Since not all applications serialize and deserialize the media protocol,
1275   // we will have to accept |protocol| to be empty.
1276   if (protocol.empty()) {
1277     return true;
1278   }
1279 
1280   if (type == MEDIA_TYPE_DATA) {
1281     // Check for SCTP, but also for RTP for RTP-based data channels.
1282     // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1283     if (secure_transport) {
1284       // Most likely scenarios first.
1285       return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1286              IsPlainRtp(protocol);
1287     } else {
1288       return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1289     }
1290   }
1291 
1292   // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1293   // JSEP specifies.
1294   if (secure_transport) {
1295     // Most likely scenarios first.
1296     return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1297   } else {
1298     return IsPlainRtp(protocol);
1299   }
1300 }
1301 
SetMediaProtocol(bool secure_transport,MediaContentDescription * desc)1302 static void SetMediaProtocol(bool secure_transport,
1303                              MediaContentDescription* desc) {
1304   if (!desc->cryptos().empty())
1305     desc->set_protocol(kMediaProtocolSavpf);
1306   else if (secure_transport)
1307     desc->set_protocol(kMediaProtocolDtlsSavpf);
1308   else
1309     desc->set_protocol(kMediaProtocolAvpf);
1310 }
1311 
1312 // Gets the TransportInfo of the given |content_name| from the
1313 // |current_description|. If doesn't exist, returns a new one.
GetTransportDescription(const std::string & content_name,const SessionDescription * current_description)1314 static const TransportDescription* GetTransportDescription(
1315     const std::string& content_name,
1316     const SessionDescription* current_description) {
1317   const TransportDescription* desc = NULL;
1318   if (current_description) {
1319     const TransportInfo* info =
1320         current_description->GetTransportInfoByName(content_name);
1321     if (info) {
1322       desc = &info->description;
1323     }
1324   }
1325   return desc;
1326 }
1327 
1328 // Gets the current DTLS state from the transport description.
IsDtlsActive(const ContentInfo * content,const SessionDescription * current_description)1329 static bool IsDtlsActive(const ContentInfo* content,
1330                          const SessionDescription* current_description) {
1331   if (!content) {
1332     return false;
1333   }
1334 
1335   size_t msection_index = content - &current_description->contents()[0];
1336 
1337   if (current_description->transport_infos().size() <= msection_index) {
1338     return false;
1339   }
1340 
1341   return current_description->transport_infos()[msection_index]
1342       .description.secure();
1343 }
1344 
AddAudioSender(const std::string & track_id,const std::vector<std::string> & stream_ids)1345 void MediaDescriptionOptions::AddAudioSender(
1346     const std::string& track_id,
1347     const std::vector<std::string>& stream_ids) {
1348   RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
1349   AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
1350 }
1351 
AddVideoSender(const std::string & track_id,const std::vector<std::string> & stream_ids,const std::vector<RidDescription> & rids,const SimulcastLayerList & simulcast_layers,int num_sim_layers)1352 void MediaDescriptionOptions::AddVideoSender(
1353     const std::string& track_id,
1354     const std::vector<std::string>& stream_ids,
1355     const std::vector<RidDescription>& rids,
1356     const SimulcastLayerList& simulcast_layers,
1357     int num_sim_layers) {
1358   RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
1359   RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1360       << "RIDs are the compliant way to indicate simulcast.";
1361   RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1362   AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1363                     num_sim_layers);
1364 }
1365 
AddRtpDataChannel(const std::string & track_id,const std::string & stream_id)1366 void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1367                                                 const std::string& stream_id) {
1368   RTC_DCHECK(type == MEDIA_TYPE_DATA);
1369   // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1370   // than one stream?
1371   AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
1372 }
1373 
AddSenderInternal(const std::string & track_id,const std::vector<std::string> & stream_ids,const std::vector<RidDescription> & rids,const SimulcastLayerList & simulcast_layers,int num_sim_layers)1374 void MediaDescriptionOptions::AddSenderInternal(
1375     const std::string& track_id,
1376     const std::vector<std::string>& stream_ids,
1377     const std::vector<RidDescription>& rids,
1378     const SimulcastLayerList& simulcast_layers,
1379     int num_sim_layers) {
1380   // TODO(steveanton): Support any number of stream ids.
1381   RTC_CHECK(stream_ids.size() == 1U);
1382   SenderOptions options;
1383   options.track_id = track_id;
1384   options.stream_ids = stream_ids;
1385   options.simulcast_layers = simulcast_layers;
1386   options.rids = rids;
1387   options.num_sim_layers = num_sim_layers;
1388   sender_options.push_back(options);
1389 }
1390 
HasMediaDescription(MediaType type) const1391 bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1392   return absl::c_any_of(
1393       media_description_options,
1394       [type](const MediaDescriptionOptions& t) { return t.type == type; });
1395 }
1396 
MediaSessionDescriptionFactory(const TransportDescriptionFactory * transport_desc_factory,rtc::UniqueRandomIdGenerator * ssrc_generator)1397 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1398     const TransportDescriptionFactory* transport_desc_factory,
1399     rtc::UniqueRandomIdGenerator* ssrc_generator)
1400     : ssrc_generator_(ssrc_generator),
1401       transport_desc_factory_(transport_desc_factory) {
1402   RTC_DCHECK(ssrc_generator_);
1403 }
1404 
MediaSessionDescriptionFactory(ChannelManager * channel_manager,const TransportDescriptionFactory * transport_desc_factory,rtc::UniqueRandomIdGenerator * ssrc_generator)1405 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1406     ChannelManager* channel_manager,
1407     const TransportDescriptionFactory* transport_desc_factory,
1408     rtc::UniqueRandomIdGenerator* ssrc_generator)
1409     : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
1410   channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1411   channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
1412   channel_manager->GetSupportedVideoSendCodecs(&video_send_codecs_);
1413   channel_manager->GetSupportedVideoReceiveCodecs(&video_recv_codecs_);
1414   channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
1415   ComputeAudioCodecsIntersectionAndUnion();
1416   ComputeVideoCodecsIntersectionAndUnion();
1417 }
1418 
audio_sendrecv_codecs() const1419 const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1420     const {
1421   return audio_sendrecv_codecs_;
1422 }
1423 
audio_send_codecs() const1424 const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1425   return audio_send_codecs_;
1426 }
1427 
audio_recv_codecs() const1428 const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1429   return audio_recv_codecs_;
1430 }
1431 
set_audio_codecs(const AudioCodecs & send_codecs,const AudioCodecs & recv_codecs)1432 void MediaSessionDescriptionFactory::set_audio_codecs(
1433     const AudioCodecs& send_codecs,
1434     const AudioCodecs& recv_codecs) {
1435   audio_send_codecs_ = send_codecs;
1436   audio_recv_codecs_ = recv_codecs;
1437   ComputeAudioCodecsIntersectionAndUnion();
1438 }
1439 
video_sendrecv_codecs() const1440 const VideoCodecs& MediaSessionDescriptionFactory::video_sendrecv_codecs()
1441     const {
1442   return video_sendrecv_codecs_;
1443 }
1444 
video_send_codecs() const1445 const VideoCodecs& MediaSessionDescriptionFactory::video_send_codecs() const {
1446   return video_send_codecs_;
1447 }
1448 
video_recv_codecs() const1449 const VideoCodecs& MediaSessionDescriptionFactory::video_recv_codecs() const {
1450   return video_recv_codecs_;
1451 }
1452 
set_video_codecs(const VideoCodecs & send_codecs,const VideoCodecs & recv_codecs)1453 void MediaSessionDescriptionFactory::set_video_codecs(
1454     const VideoCodecs& send_codecs,
1455     const VideoCodecs& recv_codecs) {
1456   video_send_codecs_ = send_codecs;
1457   video_recv_codecs_ = recv_codecs;
1458   ComputeVideoCodecsIntersectionAndUnion();
1459 }
1460 
RemoveUnifiedPlanExtensions(RtpHeaderExtensions * extensions)1461 static void RemoveUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1462   RTC_DCHECK(extensions);
1463 
1464   extensions->erase(
1465       std::remove_if(extensions->begin(), extensions->end(),
1466                      [](auto extension) {
1467                        return extension.uri == webrtc::RtpExtension::kMidUri ||
1468                               extension.uri == webrtc::RtpExtension::kRidUri ||
1469                               extension.uri ==
1470                                   webrtc::RtpExtension::kRepairedRidUri;
1471                      }),
1472       extensions->end());
1473 }
1474 
1475 RtpHeaderExtensions
filtered_rtp_header_extensions(RtpHeaderExtensions extensions) const1476 MediaSessionDescriptionFactory::filtered_rtp_header_extensions(
1477     RtpHeaderExtensions extensions) const {
1478   if (!is_unified_plan_) {
1479     RemoveUnifiedPlanExtensions(&extensions);
1480   }
1481   return extensions;
1482 }
1483 
CreateOffer(const MediaSessionOptions & session_options,const SessionDescription * current_description) const1484 std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
1485     const MediaSessionOptions& session_options,
1486     const SessionDescription* current_description) const {
1487   // Must have options for each existing section.
1488   if (current_description) {
1489     RTC_DCHECK_LE(current_description->contents().size(),
1490                   session_options.media_description_options.size());
1491   }
1492 
1493   IceCredentialsIterator ice_credentials(
1494       session_options.pooled_ice_credentials);
1495 
1496   std::vector<const ContentInfo*> current_active_contents;
1497   if (current_description) {
1498     current_active_contents =
1499         GetActiveContents(*current_description, session_options);
1500   }
1501 
1502   StreamParamsVec current_streams =
1503       GetCurrentStreamParams(current_active_contents);
1504 
1505   AudioCodecs offer_audio_codecs;
1506   VideoCodecs offer_video_codecs;
1507   RtpDataCodecs offer_rtp_data_codecs;
1508   GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
1509                     &offer_video_codecs, &offer_rtp_data_codecs);
1510 
1511   if (!session_options.vad_enabled) {
1512     // If application doesn't want CN codecs in offer.
1513     StripCNCodecs(&offer_audio_codecs);
1514   }
1515   AudioVideoRtpHeaderExtensions extensions_with_ids =
1516       GetOfferedRtpHeaderExtensionsWithIds(
1517           current_active_contents, session_options.offer_extmap_allow_mixed,
1518           session_options.media_description_options);
1519 
1520   auto offer = std::make_unique<SessionDescription>();
1521 
1522   // Iterate through the media description options, matching with existing media
1523   // descriptions in |current_description|.
1524   size_t msection_index = 0;
1525   for (const MediaDescriptionOptions& media_description_options :
1526        session_options.media_description_options) {
1527     const ContentInfo* current_content = nullptr;
1528     if (current_description &&
1529         msection_index < current_description->contents().size()) {
1530       current_content = &current_description->contents()[msection_index];
1531       // Media type must match unless this media section is being recycled.
1532       RTC_DCHECK(current_content->name != media_description_options.mid ||
1533                  IsMediaContentOfType(current_content,
1534                                       media_description_options.type));
1535     }
1536     switch (media_description_options.type) {
1537       case MEDIA_TYPE_AUDIO:
1538         if (!AddAudioContentForOffer(media_description_options, session_options,
1539                                      current_content, current_description,
1540                                      extensions_with_ids.audio,
1541                                      offer_audio_codecs, &current_streams,
1542                                      offer.get(), &ice_credentials)) {
1543           return nullptr;
1544         }
1545         break;
1546       case MEDIA_TYPE_VIDEO:
1547         if (!AddVideoContentForOffer(media_description_options, session_options,
1548                                      current_content, current_description,
1549                                      extensions_with_ids.video,
1550                                      offer_video_codecs, &current_streams,
1551                                      offer.get(), &ice_credentials)) {
1552           return nullptr;
1553         }
1554         break;
1555       case MEDIA_TYPE_DATA:
1556         if (!AddDataContentForOffer(media_description_options, session_options,
1557                                     current_content, current_description,
1558                                     offer_rtp_data_codecs, &current_streams,
1559                                     offer.get(), &ice_credentials)) {
1560           return nullptr;
1561         }
1562         break;
1563       default:
1564         RTC_NOTREACHED();
1565     }
1566     ++msection_index;
1567   }
1568 
1569   // Bundle the contents together, if we've been asked to do so, and update any
1570   // parameters that need to be tweaked for BUNDLE.
1571   if (session_options.bundle_enabled) {
1572     ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
1573     for (const ContentInfo& content : offer->contents()) {
1574       if (content.rejected) {
1575         continue;
1576       }
1577       // TODO(deadbeef): There are conditions that make bundling two media
1578       // descriptions together illegal. For example, they use the same payload
1579       // type to represent different codecs, or same IDs for different header
1580       // extensions. We need to detect this and not try to bundle those media
1581       // descriptions together.
1582       offer_bundle.AddContentName(content.name);
1583     }
1584     if (!offer_bundle.content_names().empty()) {
1585       offer->AddGroup(offer_bundle);
1586       if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1587         RTC_LOG(LS_ERROR)
1588             << "CreateOffer failed to UpdateTransportInfoForBundle.";
1589         return nullptr;
1590       }
1591       if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1592         RTC_LOG(LS_ERROR)
1593             << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1594         return nullptr;
1595       }
1596     }
1597   }
1598 
1599   // The following determines how to signal MSIDs to ensure compatibility with
1600   // older endpoints (in particular, older Plan B endpoints).
1601   if (is_unified_plan_) {
1602     // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1603     // Plan answerers will look at a=msid and Plan B answerers will look at the
1604     // a=ssrc MSID line.
1605     offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1606                               cricket::kMsidSignalingSsrcAttribute);
1607   } else {
1608     // Plan B always signals MSID using a=ssrc lines.
1609     offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1610   }
1611 
1612   offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1613 
1614   return offer;
1615 }
1616 
1617 std::unique_ptr<SessionDescription>
CreateAnswer(const SessionDescription * offer,const MediaSessionOptions & session_options,const SessionDescription * current_description) const1618 MediaSessionDescriptionFactory::CreateAnswer(
1619     const SessionDescription* offer,
1620     const MediaSessionOptions& session_options,
1621     const SessionDescription* current_description) const {
1622   if (!offer) {
1623     return nullptr;
1624   }
1625 
1626   // Must have options for exactly as many sections as in the offer.
1627   RTC_DCHECK_EQ(offer->contents().size(),
1628                 session_options.media_description_options.size());
1629 
1630   IceCredentialsIterator ice_credentials(
1631       session_options.pooled_ice_credentials);
1632 
1633   std::vector<const ContentInfo*> current_active_contents;
1634   if (current_description) {
1635     current_active_contents =
1636         GetActiveContents(*current_description, session_options);
1637   }
1638 
1639   StreamParamsVec current_streams =
1640       GetCurrentStreamParams(current_active_contents);
1641 
1642   // Get list of all possible codecs that respects existing payload type
1643   // mappings and uses a single payload type space.
1644   //
1645   // Note that these lists may be further filtered for each m= section; this
1646   // step is done just to establish the payload type mappings shared by all
1647   // sections.
1648   AudioCodecs answer_audio_codecs;
1649   VideoCodecs answer_video_codecs;
1650   RtpDataCodecs answer_rtp_data_codecs;
1651   GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
1652                      &answer_video_codecs, &answer_rtp_data_codecs);
1653 
1654   if (!session_options.vad_enabled) {
1655     // If application doesn't want CN codecs in answer.
1656     StripCNCodecs(&answer_audio_codecs);
1657   }
1658 
1659   auto answer = std::make_unique<SessionDescription>();
1660 
1661   // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1662   // group in the answer with the appropriate content names.
1663   const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1664   ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1665   // Transport info shared by the bundle group.
1666   std::unique_ptr<TransportInfo> bundle_transport;
1667 
1668   answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1669 
1670   // Iterate through the media description options, matching with existing
1671   // media descriptions in |current_description|.
1672   size_t msection_index = 0;
1673   for (const MediaDescriptionOptions& media_description_options :
1674        session_options.media_description_options) {
1675     const ContentInfo* offer_content = &offer->contents()[msection_index];
1676     // Media types and MIDs must match between the remote offer and the
1677     // MediaDescriptionOptions.
1678     RTC_DCHECK(
1679         IsMediaContentOfType(offer_content, media_description_options.type));
1680     RTC_DCHECK(media_description_options.mid == offer_content->name);
1681     const ContentInfo* current_content = nullptr;
1682     if (current_description &&
1683         msection_index < current_description->contents().size()) {
1684       current_content = &current_description->contents()[msection_index];
1685     }
1686     RtpHeaderExtensions header_extensions = RtpHeaderExtensionsFromCapabilities(
1687         UnstoppedRtpHeaderExtensionCapabilities(
1688             media_description_options.header_extensions));
1689     switch (media_description_options.type) {
1690       case MEDIA_TYPE_AUDIO:
1691         if (!AddAudioContentForAnswer(
1692                 media_description_options, session_options, offer_content,
1693                 offer, current_content, current_description,
1694                 bundle_transport.get(), answer_audio_codecs, header_extensions,
1695                 &current_streams, answer.get(), &ice_credentials)) {
1696           return nullptr;
1697         }
1698         break;
1699       case MEDIA_TYPE_VIDEO:
1700         if (!AddVideoContentForAnswer(
1701                 media_description_options, session_options, offer_content,
1702                 offer, current_content, current_description,
1703                 bundle_transport.get(), answer_video_codecs, header_extensions,
1704                 &current_streams, answer.get(), &ice_credentials)) {
1705           return nullptr;
1706         }
1707         break;
1708       case MEDIA_TYPE_DATA:
1709         if (!AddDataContentForAnswer(
1710                 media_description_options, session_options, offer_content,
1711                 offer, current_content, current_description,
1712                 bundle_transport.get(), answer_rtp_data_codecs,
1713                 &current_streams, answer.get(), &ice_credentials)) {
1714           return nullptr;
1715         }
1716         break;
1717       default:
1718         RTC_NOTREACHED();
1719     }
1720     ++msection_index;
1721     // See if we can add the newly generated m= section to the BUNDLE group in
1722     // the answer.
1723     ContentInfo& added = answer->contents().back();
1724     if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
1725         offer_bundle->HasContentName(added.name)) {
1726       answer_bundle.AddContentName(added.name);
1727       bundle_transport.reset(
1728           new TransportInfo(*answer->GetTransportInfoByName(added.name)));
1729     }
1730   }
1731 
1732   // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1733   // it's empty. RFC5888 says:
1734   //
1735   //   A SIP entity that receives an offer that contains an "a=group" line
1736   //   with semantics that are understood MUST return an answer that
1737   //   contains an "a=group" line with the same semantics.
1738   if (offer_bundle) {
1739     answer->AddGroup(answer_bundle);
1740   }
1741 
1742   if (answer_bundle.FirstContentName()) {
1743     // Share the same ICE credentials and crypto params across all contents,
1744     // as BUNDLE requires.
1745     if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
1746       RTC_LOG(LS_ERROR)
1747           << "CreateAnswer failed to UpdateTransportInfoForBundle.";
1748       return NULL;
1749     }
1750 
1751     if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
1752       RTC_LOG(LS_ERROR)
1753           << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
1754       return NULL;
1755     }
1756   }
1757 
1758   // The following determines how to signal MSIDs to ensure compatibility with
1759   // older endpoints (in particular, older Plan B endpoints).
1760   if (is_unified_plan_) {
1761     // Unified Plan needs to look at what the offer included to find the most
1762     // compatible answer.
1763     if (offer->msid_signaling() == 0) {
1764       // We end up here in one of three cases:
1765       // 1. An empty offer. We'll reply with an empty answer so it doesn't
1766       //    matter what we pick here.
1767       // 2. A data channel only offer. We won't add any MSIDs to the answer so
1768       //    it also doesn't matter what we pick here.
1769       // 3. Media that's either sendonly or inactive from the remote endpoint.
1770       //    We don't have any information to say whether the endpoint is Plan B
1771       //    or Unified Plan, so be conservative and send both.
1772       answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1773                                  cricket::kMsidSignalingSsrcAttribute);
1774     } else if (offer->msid_signaling() ==
1775                (cricket::kMsidSignalingMediaSection |
1776                 cricket::kMsidSignalingSsrcAttribute)) {
1777       // If both a=msid and a=ssrc MSID signaling methods were used, we're
1778       // probably talking to a Unified Plan endpoint so respond with just
1779       // a=msid.
1780       answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1781     } else {
1782       // Otherwise, it's clear which method the offerer is using so repeat that
1783       // back to them.
1784       answer->set_msid_signaling(offer->msid_signaling());
1785     }
1786   } else {
1787     // Plan B always signals MSID using a=ssrc lines.
1788     answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1789   }
1790 
1791   return answer;
1792 }
1793 
GetAudioCodecsForOffer(const RtpTransceiverDirection & direction) const1794 const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1795     const RtpTransceiverDirection& direction) const {
1796   switch (direction) {
1797     // If stream is inactive - generate list as if sendrecv.
1798     case RtpTransceiverDirection::kSendRecv:
1799     case RtpTransceiverDirection::kInactive:
1800       return audio_sendrecv_codecs_;
1801     case RtpTransceiverDirection::kSendOnly:
1802       return audio_send_codecs_;
1803     case RtpTransceiverDirection::kRecvOnly:
1804       return audio_recv_codecs_;
1805     case RtpTransceiverDirection::kStopped:
1806       RTC_NOTREACHED();
1807       return audio_sendrecv_codecs_;
1808   }
1809 }
1810 
GetAudioCodecsForAnswer(const RtpTransceiverDirection & offer,const RtpTransceiverDirection & answer) const1811 const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1812     const RtpTransceiverDirection& offer,
1813     const RtpTransceiverDirection& answer) const {
1814   switch (answer) {
1815     // For inactive and sendrecv answers, generate lists as if we were to accept
1816     // the offer's direction. See RFC 3264 Section 6.1.
1817     case RtpTransceiverDirection::kSendRecv:
1818     case RtpTransceiverDirection::kInactive:
1819       return GetAudioCodecsForOffer(
1820           webrtc::RtpTransceiverDirectionReversed(offer));
1821     case RtpTransceiverDirection::kSendOnly:
1822       return audio_send_codecs_;
1823     case RtpTransceiverDirection::kRecvOnly:
1824       return audio_recv_codecs_;
1825     case RtpTransceiverDirection::kStopped:
1826       RTC_NOTREACHED();
1827       return audio_sendrecv_codecs_;
1828   }
1829 }
1830 
GetVideoCodecsForOffer(const RtpTransceiverDirection & direction) const1831 const VideoCodecs& MediaSessionDescriptionFactory::GetVideoCodecsForOffer(
1832     const RtpTransceiverDirection& direction) const {
1833   switch (direction) {
1834     // If stream is inactive - generate list as if sendrecv.
1835     case RtpTransceiverDirection::kSendRecv:
1836     case RtpTransceiverDirection::kInactive:
1837       return video_sendrecv_codecs_;
1838     case RtpTransceiverDirection::kSendOnly:
1839       return video_send_codecs_;
1840     case RtpTransceiverDirection::kRecvOnly:
1841       return video_recv_codecs_;
1842     case RtpTransceiverDirection::kStopped:
1843       RTC_NOTREACHED();
1844       return video_sendrecv_codecs_;
1845   }
1846 }
1847 
GetVideoCodecsForAnswer(const RtpTransceiverDirection & offer,const RtpTransceiverDirection & answer) const1848 const VideoCodecs& MediaSessionDescriptionFactory::GetVideoCodecsForAnswer(
1849     const RtpTransceiverDirection& offer,
1850     const RtpTransceiverDirection& answer) const {
1851   switch (answer) {
1852     // For inactive and sendrecv answers, generate lists as if we were to accept
1853     // the offer's direction. See RFC 3264 Section 6.1.
1854     case RtpTransceiverDirection::kSendRecv:
1855     case RtpTransceiverDirection::kInactive:
1856       return GetVideoCodecsForOffer(
1857           webrtc::RtpTransceiverDirectionReversed(offer));
1858     case RtpTransceiverDirection::kSendOnly:
1859       return video_send_codecs_;
1860     case RtpTransceiverDirection::kRecvOnly:
1861       return video_recv_codecs_;
1862     case RtpTransceiverDirection::kStopped:
1863       RTC_NOTREACHED();
1864       return video_sendrecv_codecs_;
1865   }
1866 }
1867 
MergeCodecsFromDescription(const std::vector<const ContentInfo * > & current_active_contents,AudioCodecs * audio_codecs,VideoCodecs * video_codecs,RtpDataCodecs * rtp_data_codecs,UsedPayloadTypes * used_pltypes)1868 void MergeCodecsFromDescription(
1869     const std::vector<const ContentInfo*>& current_active_contents,
1870     AudioCodecs* audio_codecs,
1871     VideoCodecs* video_codecs,
1872     RtpDataCodecs* rtp_data_codecs,
1873     UsedPayloadTypes* used_pltypes) {
1874   for (const ContentInfo* content : current_active_contents) {
1875     if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1876       const AudioContentDescription* audio =
1877           content->media_description()->as_audio();
1878       MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
1879     } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1880       const VideoContentDescription* video =
1881           content->media_description()->as_video();
1882       MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
1883     } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
1884       const RtpDataContentDescription* data =
1885           content->media_description()->as_rtp_data();
1886       if (data) {
1887         // Only relevant for RTP datachannels
1888         MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1889                                   used_pltypes);
1890       }
1891     }
1892   }
1893 }
1894 
1895 // Getting codecs for an offer involves these steps:
1896 //
1897 // 1. Construct payload type -> codec mappings for current description.
1898 // 2. Add any reference codecs that weren't already present
1899 // 3. For each individual media description (m= section), filter codecs based
1900 //    on the directional attribute (happens in another method).
GetCodecsForOffer(const std::vector<const ContentInfo * > & current_active_contents,AudioCodecs * audio_codecs,VideoCodecs * video_codecs,RtpDataCodecs * rtp_data_codecs) const1901 void MediaSessionDescriptionFactory::GetCodecsForOffer(
1902     const std::vector<const ContentInfo*>& current_active_contents,
1903     AudioCodecs* audio_codecs,
1904     VideoCodecs* video_codecs,
1905     RtpDataCodecs* rtp_data_codecs) const {
1906   // First - get all codecs from the current description if the media type
1907   // is used. Add them to |used_pltypes| so the payload type is not reused if a
1908   // new media type is added.
1909   UsedPayloadTypes used_pltypes;
1910   MergeCodecsFromDescription(current_active_contents, audio_codecs,
1911                              video_codecs, rtp_data_codecs, &used_pltypes);
1912 
1913   // Add our codecs that are not in the current description.
1914   MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1915   MergeCodecs<VideoCodec>(all_video_codecs_, video_codecs, &used_pltypes);
1916   MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
1917 }
1918 
1919 // Getting codecs for an answer involves these steps:
1920 //
1921 // 1. Construct payload type -> codec mappings for current description.
1922 // 2. Add any codecs from the offer that weren't already present.
1923 // 3. Add any remaining codecs that weren't already present.
1924 // 4. For each individual media description (m= section), filter codecs based
1925 //    on the directional attribute (happens in another method).
GetCodecsForAnswer(const std::vector<const ContentInfo * > & current_active_contents,const SessionDescription & remote_offer,AudioCodecs * audio_codecs,VideoCodecs * video_codecs,RtpDataCodecs * rtp_data_codecs) const1926 void MediaSessionDescriptionFactory::GetCodecsForAnswer(
1927     const std::vector<const ContentInfo*>& current_active_contents,
1928     const SessionDescription& remote_offer,
1929     AudioCodecs* audio_codecs,
1930     VideoCodecs* video_codecs,
1931     RtpDataCodecs* rtp_data_codecs) const {
1932   // First - get all codecs from the current description if the media type
1933   // is used. Add them to |used_pltypes| so the payload type is not reused if a
1934   // new media type is added.
1935   UsedPayloadTypes used_pltypes;
1936   MergeCodecsFromDescription(current_active_contents, audio_codecs,
1937                              video_codecs, rtp_data_codecs, &used_pltypes);
1938 
1939   // Second - filter out codecs that we don't support at all and should ignore.
1940   AudioCodecs filtered_offered_audio_codecs;
1941   VideoCodecs filtered_offered_video_codecs;
1942   RtpDataCodecs filtered_offered_rtp_data_codecs;
1943   for (const ContentInfo& content : remote_offer.contents()) {
1944     if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1945       const AudioContentDescription* audio =
1946           content.media_description()->as_audio();
1947       for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1948         if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1949                                            filtered_offered_audio_codecs,
1950                                            offered_audio_codec, nullptr) &&
1951             FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1952                                           offered_audio_codec, nullptr)) {
1953           filtered_offered_audio_codecs.push_back(offered_audio_codec);
1954         }
1955       }
1956     } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1957       const VideoContentDescription* video =
1958           content.media_description()->as_video();
1959       for (const VideoCodec& offered_video_codec : video->codecs()) {
1960         if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1961                                            filtered_offered_video_codecs,
1962                                            offered_video_codec, nullptr) &&
1963             FindMatchingCodec<VideoCodec>(video->codecs(), all_video_codecs_,
1964                                           offered_video_codec, nullptr)) {
1965           filtered_offered_video_codecs.push_back(offered_video_codec);
1966         }
1967       }
1968     } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1969       const RtpDataContentDescription* data =
1970           content.media_description()->as_rtp_data();
1971       if (data) {
1972         // RTP data. This part is inactive for SCTP data.
1973         for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1974           if (!FindMatchingCodec<RtpDataCodec>(
1975                   data->codecs(), filtered_offered_rtp_data_codecs,
1976                   offered_rtp_data_codec, nullptr) &&
1977               FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1978                                               offered_rtp_data_codec,
1979                                               nullptr)) {
1980             filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1981           }
1982         }
1983       }
1984     }
1985   }
1986 
1987   // Add codecs that are not in the current description but were in
1988   // |remote_offer|.
1989   MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1990                           &used_pltypes);
1991   MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1992                           &used_pltypes);
1993   MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
1994                          &used_pltypes);
1995 }
1996 
1997 MediaSessionDescriptionFactory::AudioVideoRtpHeaderExtensions
GetOfferedRtpHeaderExtensionsWithIds(const std::vector<const ContentInfo * > & current_active_contents,bool extmap_allow_mixed,const std::vector<MediaDescriptionOptions> & media_description_options) const1998 MediaSessionDescriptionFactory::GetOfferedRtpHeaderExtensionsWithIds(
1999     const std::vector<const ContentInfo*>& current_active_contents,
2000     bool extmap_allow_mixed,
2001     const std::vector<MediaDescriptionOptions>& media_description_options)
2002     const {
2003   // All header extensions allocated from the same range to avoid potential
2004   // issues when using BUNDLE.
2005 
2006   // Strictly speaking the SDP attribute extmap_allow_mixed signals that the
2007   // receiver supports an RTP stream where one- and two-byte RTP header
2008   // extensions are mixed. For backwards compatibility reasons it's used in
2009   // WebRTC to signal that two-byte RTP header extensions are supported.
2010   UsedRtpHeaderExtensionIds used_ids(
2011       extmap_allow_mixed ? UsedRtpHeaderExtensionIds::IdDomain::kTwoByteAllowed
2012                          : UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly);
2013   RtpHeaderExtensions all_regular_extensions;
2014   RtpHeaderExtensions all_encrypted_extensions;
2015 
2016   AudioVideoRtpHeaderExtensions offered_extensions;
2017   // First - get all extensions from the current description if the media type
2018   // is used.
2019   // Add them to |used_ids| so the local ids are not reused if a new media
2020   // type is added.
2021   for (const ContentInfo* content : current_active_contents) {
2022     if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
2023       const AudioContentDescription* audio =
2024           content->media_description()->as_audio();
2025       MergeRtpHdrExts(audio->rtp_header_extensions(), &offered_extensions.audio,
2026                       &all_regular_extensions, &all_encrypted_extensions,
2027                       &used_ids);
2028     } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
2029       const VideoContentDescription* video =
2030           content->media_description()->as_video();
2031       MergeRtpHdrExts(video->rtp_header_extensions(), &offered_extensions.video,
2032                       &all_regular_extensions, &all_encrypted_extensions,
2033                       &used_ids);
2034     }
2035   }
2036 
2037   // Add all encountered header extensions in the media description options that
2038   // are not in the current description.
2039 
2040   for (const auto& entry : media_description_options) {
2041     RtpHeaderExtensions filtered_extensions =
2042         filtered_rtp_header_extensions(UnstoppedOrPresentRtpHeaderExtensions(
2043             entry.header_extensions, all_regular_extensions,
2044             all_encrypted_extensions));
2045     if (entry.type == MEDIA_TYPE_AUDIO)
2046       MergeRtpHdrExts(filtered_extensions, &offered_extensions.audio,
2047                       &all_regular_extensions, &all_encrypted_extensions,
2048                       &used_ids);
2049     else if (entry.type == MEDIA_TYPE_VIDEO)
2050       MergeRtpHdrExts(filtered_extensions, &offered_extensions.video,
2051                       &all_regular_extensions, &all_encrypted_extensions,
2052                       &used_ids);
2053   }
2054   // TODO(jbauch): Support adding encrypted header extensions to existing
2055   // sessions.
2056   if (enable_encrypted_rtp_header_extensions_ &&
2057       current_active_contents.empty()) {
2058     AddEncryptedVersionsOfHdrExts(&offered_extensions.audio,
2059                                   &all_encrypted_extensions, &used_ids);
2060     AddEncryptedVersionsOfHdrExts(&offered_extensions.video,
2061                                   &all_encrypted_extensions, &used_ids);
2062   }
2063   return offered_extensions;
2064 }
2065 
AddTransportOffer(const std::string & content_name,const TransportOptions & transport_options,const SessionDescription * current_desc,SessionDescription * offer_desc,IceCredentialsIterator * ice_credentials) const2066 bool MediaSessionDescriptionFactory::AddTransportOffer(
2067     const std::string& content_name,
2068     const TransportOptions& transport_options,
2069     const SessionDescription* current_desc,
2070     SessionDescription* offer_desc,
2071     IceCredentialsIterator* ice_credentials) const {
2072   if (!transport_desc_factory_)
2073     return false;
2074   const TransportDescription* current_tdesc =
2075       GetTransportDescription(content_name, current_desc);
2076   std::unique_ptr<TransportDescription> new_tdesc(
2077       transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
2078                                            ice_credentials));
2079   if (!new_tdesc) {
2080     RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
2081                       << content_name;
2082   }
2083   offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
2084   return true;
2085 }
2086 
2087 std::unique_ptr<TransportDescription>
CreateTransportAnswer(const std::string & content_name,const SessionDescription * offer_desc,const TransportOptions & transport_options,const SessionDescription * current_desc,bool require_transport_attributes,IceCredentialsIterator * ice_credentials) const2088 MediaSessionDescriptionFactory::CreateTransportAnswer(
2089     const std::string& content_name,
2090     const SessionDescription* offer_desc,
2091     const TransportOptions& transport_options,
2092     const SessionDescription* current_desc,
2093     bool require_transport_attributes,
2094     IceCredentialsIterator* ice_credentials) const {
2095   if (!transport_desc_factory_)
2096     return NULL;
2097   const TransportDescription* offer_tdesc =
2098       GetTransportDescription(content_name, offer_desc);
2099   const TransportDescription* current_tdesc =
2100       GetTransportDescription(content_name, current_desc);
2101   return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
2102                                                require_transport_attributes,
2103                                                current_tdesc, ice_credentials);
2104 }
2105 
AddTransportAnswer(const std::string & content_name,const TransportDescription & transport_desc,SessionDescription * answer_desc) const2106 bool MediaSessionDescriptionFactory::AddTransportAnswer(
2107     const std::string& content_name,
2108     const TransportDescription& transport_desc,
2109     SessionDescription* answer_desc) const {
2110   answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
2111   return true;
2112 }
2113 
2114 // |audio_codecs| = set of all possible codecs that can be used, with correct
2115 // payload type mappings
2116 //
2117 // |supported_audio_codecs| = set of codecs that are supported for the direction
2118 // of this m= section
2119 //
2120 // acd->codecs() = set of previously negotiated codecs for this m= section
2121 //
2122 // The payload types should come from audio_codecs, but the order should come
2123 // from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2124 // change existing codec priority, and that new codecs are added with the right
2125 // priority.
AddAudioContentForOffer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * current_content,const SessionDescription * current_description,const RtpHeaderExtensions & audio_rtp_extensions,const AudioCodecs & audio_codecs,StreamParamsVec * current_streams,SessionDescription * desc,IceCredentialsIterator * ice_credentials) const2126 bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
2127     const MediaDescriptionOptions& media_description_options,
2128     const MediaSessionOptions& session_options,
2129     const ContentInfo* current_content,
2130     const SessionDescription* current_description,
2131     const RtpHeaderExtensions& audio_rtp_extensions,
2132     const AudioCodecs& audio_codecs,
2133     StreamParamsVec* current_streams,
2134     SessionDescription* desc,
2135     IceCredentialsIterator* ice_credentials) const {
2136   // Filter audio_codecs (which includes all codecs, with correctly remapped
2137   // payload types) based on transceiver direction.
2138   const AudioCodecs& supported_audio_codecs =
2139       GetAudioCodecsForOffer(media_description_options.direction);
2140 
2141   AudioCodecs filtered_codecs;
2142 
2143   if (!media_description_options.codec_preferences.empty()) {
2144     // Add the codecs from the current transceiver's codec preferences.
2145     // They override any existing codecs from previous negotiations.
2146     filtered_codecs = MatchCodecPreference(
2147         media_description_options.codec_preferences, supported_audio_codecs);
2148   } else {
2149     // Add the codecs from current content if it exists and is not rejected nor
2150     // recycled.
2151     if (current_content && !current_content->rejected &&
2152         current_content->name == media_description_options.mid) {
2153       RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2154       const AudioContentDescription* acd =
2155           current_content->media_description()->as_audio();
2156       for (const AudioCodec& codec : acd->codecs()) {
2157         if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2158                                           nullptr)) {
2159           filtered_codecs.push_back(codec);
2160         }
2161       }
2162     }
2163     // Add other supported audio codecs.
2164     AudioCodec found_codec;
2165     for (const AudioCodec& codec : supported_audio_codecs) {
2166       if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2167                                         codec, &found_codec) &&
2168           !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2169                                          filtered_codecs, codec, nullptr)) {
2170         // Use the |found_codec| from |audio_codecs| because it has the
2171         // correctly mapped payload type.
2172         filtered_codecs.push_back(found_codec);
2173       }
2174     }
2175   }
2176 
2177   cricket::SecurePolicy sdes_policy =
2178       IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2179                                                          : secure();
2180 
2181   auto audio = std::make_unique<AudioContentDescription>();
2182   std::vector<std::string> crypto_suites;
2183   GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2184                                         &crypto_suites);
2185   if (!CreateMediaContentOffer(media_description_options, session_options,
2186                                filtered_codecs, sdes_policy,
2187                                GetCryptos(current_content), crypto_suites,
2188                                audio_rtp_extensions, ssrc_generator_,
2189                                current_streams, audio.get())) {
2190     return false;
2191   }
2192 
2193   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2194   SetMediaProtocol(secure_transport, audio.get());
2195 
2196   audio->set_direction(media_description_options.direction);
2197 
2198   desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
2199                    media_description_options.stopped, std::move(audio));
2200   if (!AddTransportOffer(media_description_options.mid,
2201                          media_description_options.transport_options,
2202                          current_description, desc, ice_credentials)) {
2203     return false;
2204   }
2205 
2206   return true;
2207 }
2208 
2209 // TODO(kron): This function is very similar to AddAudioContentForOffer.
2210 // Refactor to reuse shared code.
AddVideoContentForOffer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * current_content,const SessionDescription * current_description,const RtpHeaderExtensions & video_rtp_extensions,const VideoCodecs & video_codecs,StreamParamsVec * current_streams,SessionDescription * desc,IceCredentialsIterator * ice_credentials) const2211 bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
2212     const MediaDescriptionOptions& media_description_options,
2213     const MediaSessionOptions& session_options,
2214     const ContentInfo* current_content,
2215     const SessionDescription* current_description,
2216     const RtpHeaderExtensions& video_rtp_extensions,
2217     const VideoCodecs& video_codecs,
2218     StreamParamsVec* current_streams,
2219     SessionDescription* desc,
2220     IceCredentialsIterator* ice_credentials) const {
2221   // Filter video_codecs (which includes all codecs, with correctly remapped
2222   // payload types) based on transceiver direction.
2223   const VideoCodecs& supported_video_codecs =
2224       GetVideoCodecsForOffer(media_description_options.direction);
2225 
2226   VideoCodecs filtered_codecs;
2227 
2228   if (!media_description_options.codec_preferences.empty()) {
2229     // Add the codecs from the current transceiver's codec preferences.
2230     // They override any existing codecs from previous negotiations.
2231     filtered_codecs = MatchCodecPreference(
2232         media_description_options.codec_preferences, supported_video_codecs);
2233   } else {
2234     // Add the codecs from current content if it exists and is not rejected nor
2235     // recycled.
2236     if (current_content && !current_content->rejected &&
2237         current_content->name == media_description_options.mid) {
2238       RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2239       const VideoContentDescription* vcd =
2240           current_content->media_description()->as_video();
2241       for (const VideoCodec& codec : vcd->codecs()) {
2242         if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2243                                           nullptr)) {
2244           filtered_codecs.push_back(codec);
2245         }
2246       }
2247     }
2248     // Add other supported video codecs.
2249     VideoCodec found_codec;
2250     for (const VideoCodec& codec : supported_video_codecs) {
2251       if (FindMatchingCodec<VideoCodec>(supported_video_codecs, video_codecs,
2252                                         codec, &found_codec) &&
2253           !FindMatchingCodec<VideoCodec>(supported_video_codecs,
2254                                          filtered_codecs, codec, nullptr)) {
2255         // Use the |found_codec| from |video_codecs| because it has the
2256         // correctly mapped payload type.
2257         filtered_codecs.push_back(found_codec);
2258       }
2259     }
2260   }
2261 
2262   if (session_options.raw_packetization_for_video) {
2263     for (VideoCodec& codec : filtered_codecs) {
2264       if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2265         codec.packetization = kPacketizationParamRaw;
2266       }
2267     }
2268   }
2269 
2270   cricket::SecurePolicy sdes_policy =
2271       IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2272                                                          : secure();
2273   auto video = std::make_unique<VideoContentDescription>();
2274   std::vector<std::string> crypto_suites;
2275   GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2276                                         &crypto_suites);
2277   if (!CreateMediaContentOffer(media_description_options, session_options,
2278                                filtered_codecs, sdes_policy,
2279                                GetCryptos(current_content), crypto_suites,
2280                                video_rtp_extensions, ssrc_generator_,
2281                                current_streams, video.get())) {
2282     return false;
2283   }
2284 
2285   video->set_bandwidth(kAutoBandwidth);
2286 
2287   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2288   SetMediaProtocol(secure_transport, video.get());
2289 
2290   video->set_direction(media_description_options.direction);
2291 
2292   desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
2293                    media_description_options.stopped, std::move(video));
2294   if (!AddTransportOffer(media_description_options.mid,
2295                          media_description_options.transport_options,
2296                          current_description, desc, ice_credentials)) {
2297     return false;
2298   }
2299 
2300   return true;
2301 }
2302 
AddSctpDataContentForOffer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * current_content,const SessionDescription * current_description,StreamParamsVec * current_streams,SessionDescription * desc,IceCredentialsIterator * ice_credentials) const2303 bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2304     const MediaDescriptionOptions& media_description_options,
2305     const MediaSessionOptions& session_options,
2306     const ContentInfo* current_content,
2307     const SessionDescription* current_description,
2308     StreamParamsVec* current_streams,
2309     SessionDescription* desc,
2310     IceCredentialsIterator* ice_credentials) const {
2311   auto data = std::make_unique<SctpDataContentDescription>();
2312 
2313   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2314 
2315   cricket::SecurePolicy sdes_policy =
2316       IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2317                                                          : secure();
2318   std::vector<std::string> crypto_suites;
2319   // SDES doesn't make sense for SCTP, so we disable it, and we only
2320   // get SDES crypto suites for RTP-based data channels.
2321   sdes_policy = cricket::SEC_DISABLED;
2322   // Unlike SetMediaProtocol below, we need to set the protocol
2323   // before we call CreateMediaContentOffer.  Otherwise,
2324   // CreateMediaContentOffer won't know this is SCTP and will
2325   // generate SSRCs rather than SIDs.
2326   data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
2327                                       : kMediaProtocolSctp);
2328   data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
2329   data->set_max_message_size(kSctpSendBufferSize);
2330 
2331   if (!CreateContentOffer(media_description_options, session_options,
2332                           sdes_policy, GetCryptos(current_content),
2333                           crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2334                           current_streams, data.get())) {
2335     return false;
2336   }
2337 
2338   desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
2339                    media_description_options.stopped, std::move(data));
2340   if (!AddTransportOffer(media_description_options.mid,
2341                          media_description_options.transport_options,
2342                          current_description, desc, ice_credentials)) {
2343     return false;
2344   }
2345   return true;
2346 }
2347 
AddRtpDataContentForOffer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * current_content,const SessionDescription * current_description,const RtpDataCodecs & rtp_data_codecs,StreamParamsVec * current_streams,SessionDescription * desc,IceCredentialsIterator * ice_credentials) const2348 bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2349     const MediaDescriptionOptions& media_description_options,
2350     const MediaSessionOptions& session_options,
2351     const ContentInfo* current_content,
2352     const SessionDescription* current_description,
2353     const RtpDataCodecs& rtp_data_codecs,
2354     StreamParamsVec* current_streams,
2355     SessionDescription* desc,
2356     IceCredentialsIterator* ice_credentials) const {
2357   auto data = std::make_unique<RtpDataContentDescription>();
2358   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2359 
2360   cricket::SecurePolicy sdes_policy =
2361       IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2362                                                          : secure();
2363   std::vector<std::string> crypto_suites;
2364   GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2365                                        &crypto_suites);
2366   if (!CreateMediaContentOffer(media_description_options, session_options,
2367                                rtp_data_codecs, sdes_policy,
2368                                GetCryptos(current_content), crypto_suites,
2369                                RtpHeaderExtensions(), ssrc_generator_,
2370                                current_streams, data.get())) {
2371     return false;
2372   }
2373 
2374   data->set_bandwidth(kDataMaxBandwidth);
2375   SetMediaProtocol(secure_transport, data.get());
2376   desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
2377                    media_description_options.stopped, std::move(data));
2378   if (!AddTransportOffer(media_description_options.mid,
2379                          media_description_options.transport_options,
2380                          current_description, desc, ice_credentials)) {
2381     return false;
2382   }
2383   return true;
2384 }
2385 
AddDataContentForOffer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * current_content,const SessionDescription * current_description,const RtpDataCodecs & rtp_data_codecs,StreamParamsVec * current_streams,SessionDescription * desc,IceCredentialsIterator * ice_credentials) const2386 bool MediaSessionDescriptionFactory::AddDataContentForOffer(
2387     const MediaDescriptionOptions& media_description_options,
2388     const MediaSessionOptions& session_options,
2389     const ContentInfo* current_content,
2390     const SessionDescription* current_description,
2391     const RtpDataCodecs& rtp_data_codecs,
2392     StreamParamsVec* current_streams,
2393     SessionDescription* desc,
2394     IceCredentialsIterator* ice_credentials) const {
2395   bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2396   // If the DataChannel type is not specified, use the DataChannel type in
2397   // the current description.
2398   if (session_options.data_channel_type == DCT_NONE && current_content) {
2399     RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
2400     is_sctp = (current_content->media_description()->protocol() ==
2401                kMediaProtocolSctp);
2402   }
2403   if (is_sctp) {
2404     return AddSctpDataContentForOffer(
2405         media_description_options, session_options, current_content,
2406         current_description, current_streams, desc, ice_credentials);
2407   } else {
2408     return AddRtpDataContentForOffer(media_description_options, session_options,
2409                                      current_content, current_description,
2410                                      rtp_data_codecs, current_streams, desc,
2411                                      ice_credentials);
2412   }
2413 }
2414 
2415 // |audio_codecs| = set of all possible codecs that can be used, with correct
2416 // payload type mappings
2417 //
2418 // |supported_audio_codecs| = set of codecs that are supported for the direction
2419 // of this m= section
2420 //
2421 // acd->codecs() = set of previously negotiated codecs for this m= section
2422 //
2423 // The payload types should come from audio_codecs, but the order should come
2424 // from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2425 // change existing codec priority, and that new codecs are added with the right
2426 // priority.
AddAudioContentForAnswer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * offer_content,const SessionDescription * offer_description,const ContentInfo * current_content,const SessionDescription * current_description,const TransportInfo * bundle_transport,const AudioCodecs & audio_codecs,const RtpHeaderExtensions & default_audio_rtp_header_extensions,StreamParamsVec * current_streams,SessionDescription * answer,IceCredentialsIterator * ice_credentials) const2427 bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
2428     const MediaDescriptionOptions& media_description_options,
2429     const MediaSessionOptions& session_options,
2430     const ContentInfo* offer_content,
2431     const SessionDescription* offer_description,
2432     const ContentInfo* current_content,
2433     const SessionDescription* current_description,
2434     const TransportInfo* bundle_transport,
2435     const AudioCodecs& audio_codecs,
2436     const RtpHeaderExtensions& default_audio_rtp_header_extensions,
2437     StreamParamsVec* current_streams,
2438     SessionDescription* answer,
2439     IceCredentialsIterator* ice_credentials) const {
2440   RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
2441   const AudioContentDescription* offer_audio_description =
2442       offer_content->media_description()->as_audio();
2443 
2444   std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
2445       media_description_options.mid, offer_description,
2446       media_description_options.transport_options, current_description,
2447       bundle_transport != nullptr, ice_credentials);
2448   if (!audio_transport) {
2449     return false;
2450   }
2451 
2452   // Pick codecs based on the requested communications direction in the offer
2453   // and the selected direction in the answer.
2454   // Note these will be filtered one final time in CreateMediaContentAnswer.
2455   auto wants_rtd = media_description_options.direction;
2456   auto offer_rtd = offer_audio_description->direction();
2457   auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
2458   AudioCodecs supported_audio_codecs =
2459       GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2460 
2461   AudioCodecs filtered_codecs;
2462 
2463   if (!media_description_options.codec_preferences.empty()) {
2464     filtered_codecs = MatchCodecPreference(
2465         media_description_options.codec_preferences, supported_audio_codecs);
2466   } else {
2467     // Add the codecs from current content if it exists and is not rejected nor
2468     // recycled.
2469     if (current_content && !current_content->rejected &&
2470         current_content->name == media_description_options.mid) {
2471       RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2472       const AudioContentDescription* acd =
2473           current_content->media_description()->as_audio();
2474       for (const AudioCodec& codec : acd->codecs()) {
2475         if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2476                                           nullptr)) {
2477           filtered_codecs.push_back(codec);
2478         }
2479       }
2480     }
2481     // Add other supported audio codecs.
2482     for (const AudioCodec& codec : supported_audio_codecs) {
2483       if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2484                                         codec, nullptr) &&
2485           !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2486                                          filtered_codecs, codec, nullptr)) {
2487         // We should use the local codec with local parameters and the codec id
2488         // would be correctly mapped in |NegotiateCodecs|.
2489         filtered_codecs.push_back(codec);
2490       }
2491     }
2492   }
2493 
2494   bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2495                         session_options.bundle_enabled;
2496   auto audio_answer = std::make_unique<AudioContentDescription>();
2497   // Do not require or create SDES cryptos if DTLS is used.
2498   cricket::SecurePolicy sdes_policy =
2499       audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2500   if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2501                          media_description_options, session_options,
2502                          ssrc_generator_, current_streams,
2503                          audio_answer.get())) {
2504     return false;
2505   }
2506   if (!CreateMediaContentAnswer(
2507           offer_audio_description, media_description_options, session_options,
2508           sdes_policy, GetCryptos(current_content),
2509           filtered_rtp_header_extensions(default_audio_rtp_header_extensions),
2510           ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2511           current_streams, bundle_enabled, audio_answer.get())) {
2512     return false;  // Fails the session setup.
2513   }
2514 
2515   bool secure = bundle_transport ? bundle_transport->description.secure()
2516                                  : audio_transport->secure();
2517   bool rejected = media_description_options.stopped ||
2518                   offer_content->rejected ||
2519                   !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2520                                             audio_answer->protocol(), secure);
2521   if (!AddTransportAnswer(media_description_options.mid,
2522                           *(audio_transport.get()), answer)) {
2523     return false;
2524   }
2525 
2526   if (rejected) {
2527     RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2528                      << "' being rejected in answer.";
2529   }
2530 
2531   answer->AddContent(media_description_options.mid, offer_content->type,
2532                      rejected, std::move(audio_answer));
2533   return true;
2534 }
2535 
2536 // TODO(kron): This function is very similar to AddAudioContentForAnswer.
2537 // Refactor to reuse shared code.
AddVideoContentForAnswer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * offer_content,const SessionDescription * offer_description,const ContentInfo * current_content,const SessionDescription * current_description,const TransportInfo * bundle_transport,const VideoCodecs & video_codecs,const RtpHeaderExtensions & default_video_rtp_header_extensions,StreamParamsVec * current_streams,SessionDescription * answer,IceCredentialsIterator * ice_credentials) const2538 bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
2539     const MediaDescriptionOptions& media_description_options,
2540     const MediaSessionOptions& session_options,
2541     const ContentInfo* offer_content,
2542     const SessionDescription* offer_description,
2543     const ContentInfo* current_content,
2544     const SessionDescription* current_description,
2545     const TransportInfo* bundle_transport,
2546     const VideoCodecs& video_codecs,
2547     const RtpHeaderExtensions& default_video_rtp_header_extensions,
2548     StreamParamsVec* current_streams,
2549     SessionDescription* answer,
2550     IceCredentialsIterator* ice_credentials) const {
2551   RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
2552   const VideoContentDescription* offer_video_description =
2553       offer_content->media_description()->as_video();
2554 
2555   std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
2556       media_description_options.mid, offer_description,
2557       media_description_options.transport_options, current_description,
2558       bundle_transport != nullptr, ice_credentials);
2559   if (!video_transport) {
2560     return false;
2561   }
2562 
2563   // Pick codecs based on the requested communications direction in the offer
2564   // and the selected direction in the answer.
2565   // Note these will be filtered one final time in CreateMediaContentAnswer.
2566   auto wants_rtd = media_description_options.direction;
2567   auto offer_rtd = offer_video_description->direction();
2568   auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
2569   VideoCodecs supported_video_codecs =
2570       GetVideoCodecsForAnswer(offer_rtd, answer_rtd);
2571 
2572   VideoCodecs filtered_codecs;
2573 
2574   if (!media_description_options.codec_preferences.empty()) {
2575     filtered_codecs = MatchCodecPreference(
2576         media_description_options.codec_preferences, supported_video_codecs);
2577   } else {
2578     // Add the codecs from current content if it exists and is not rejected nor
2579     // recycled.
2580     if (current_content && !current_content->rejected &&
2581         current_content->name == media_description_options.mid) {
2582       RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2583       const VideoContentDescription* vcd =
2584           current_content->media_description()->as_video();
2585       for (const VideoCodec& codec : vcd->codecs()) {
2586         if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2587                                           nullptr)) {
2588           filtered_codecs.push_back(codec);
2589         }
2590       }
2591     }
2592     // Add other supported video codecs.
2593     for (const VideoCodec& codec : supported_video_codecs) {
2594       if (FindMatchingCodec<VideoCodec>(supported_video_codecs, video_codecs,
2595                                         codec, nullptr) &&
2596           !FindMatchingCodec<VideoCodec>(supported_video_codecs,
2597                                          filtered_codecs, codec, nullptr)) {
2598         // We should use the local codec with local parameters and the codec id
2599         // would be correctly mapped in |NegotiateCodecs|.
2600         filtered_codecs.push_back(codec);
2601       }
2602     }
2603   }
2604 
2605   if (session_options.raw_packetization_for_video) {
2606     for (VideoCodec& codec : filtered_codecs) {
2607       if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2608         codec.packetization = kPacketizationParamRaw;
2609       }
2610     }
2611   }
2612 
2613   bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2614                         session_options.bundle_enabled;
2615   auto video_answer = std::make_unique<VideoContentDescription>();
2616   // Do not require or create SDES cryptos if DTLS is used.
2617   cricket::SecurePolicy sdes_policy =
2618       video_transport->secure() ? cricket::SEC_DISABLED : secure();
2619   if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2620                          media_description_options, session_options,
2621                          ssrc_generator_, current_streams,
2622                          video_answer.get())) {
2623     return false;
2624   }
2625   if (!CreateMediaContentAnswer(
2626           offer_video_description, media_description_options, session_options,
2627           sdes_policy, GetCryptos(current_content),
2628           filtered_rtp_header_extensions(default_video_rtp_header_extensions),
2629           ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2630           current_streams, bundle_enabled, video_answer.get())) {
2631     return false;  // Failed the sessin setup.
2632   }
2633   bool secure = bundle_transport ? bundle_transport->description.secure()
2634                                  : video_transport->secure();
2635   bool rejected = media_description_options.stopped ||
2636                   offer_content->rejected ||
2637                   !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2638                                             video_answer->protocol(), secure);
2639   if (!AddTransportAnswer(media_description_options.mid,
2640                           *(video_transport.get()), answer)) {
2641     return false;
2642   }
2643 
2644   if (!rejected) {
2645     video_answer->set_bandwidth(kAutoBandwidth);
2646   } else {
2647     RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2648                      << "' being rejected in answer.";
2649   }
2650   answer->AddContent(media_description_options.mid, offer_content->type,
2651                      rejected, std::move(video_answer));
2652   return true;
2653 }
2654 
AddDataContentForAnswer(const MediaDescriptionOptions & media_description_options,const MediaSessionOptions & session_options,const ContentInfo * offer_content,const SessionDescription * offer_description,const ContentInfo * current_content,const SessionDescription * current_description,const TransportInfo * bundle_transport,const RtpDataCodecs & rtp_data_codecs,StreamParamsVec * current_streams,SessionDescription * answer,IceCredentialsIterator * ice_credentials) const2655 bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
2656     const MediaDescriptionOptions& media_description_options,
2657     const MediaSessionOptions& session_options,
2658     const ContentInfo* offer_content,
2659     const SessionDescription* offer_description,
2660     const ContentInfo* current_content,
2661     const SessionDescription* current_description,
2662     const TransportInfo* bundle_transport,
2663     const RtpDataCodecs& rtp_data_codecs,
2664     StreamParamsVec* current_streams,
2665     SessionDescription* answer,
2666     IceCredentialsIterator* ice_credentials) const {
2667   std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
2668       media_description_options.mid, offer_description,
2669       media_description_options.transport_options, current_description,
2670       bundle_transport != nullptr, ice_credentials);
2671   if (!data_transport) {
2672     return false;
2673   }
2674 
2675   // Do not require or create SDES cryptos if DTLS is used.
2676   cricket::SecurePolicy sdes_policy =
2677       data_transport->secure() ? cricket::SEC_DISABLED : secure();
2678   bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2679                         session_options.bundle_enabled;
2680   RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2681   std::unique_ptr<MediaContentDescription> data_answer;
2682   if (offer_content->media_description()->as_sctp()) {
2683     // SCTP data content
2684     data_answer = std::make_unique<SctpDataContentDescription>();
2685     const SctpDataContentDescription* offer_data_description =
2686         offer_content->media_description()->as_sctp();
2687     // Respond with the offerer's proto, whatever it is.
2688     data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
2689     // Respond with our max message size or the remote max messsage size,
2690     // whichever is smaller.
2691     // 0 is treated specially - it means "I can accept any size". Since
2692     // we do not implement infinite size messages, reply with
2693     // kSctpSendBufferSize.
2694     if (offer_data_description->max_message_size() == 0) {
2695       data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
2696     } else {
2697       data_answer->as_sctp()->set_max_message_size(std::min(
2698           offer_data_description->max_message_size(), kSctpSendBufferSize));
2699     }
2700     if (!CreateMediaContentAnswer(
2701             offer_data_description, media_description_options, session_options,
2702             sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2703             ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2704             current_streams, bundle_enabled, data_answer.get())) {
2705       return false;  // Fails the session setup.
2706     }
2707     // Respond with sctpmap if the offer uses sctpmap.
2708     bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2709     data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2710   } else {
2711     // RTP offer
2712     data_answer = std::make_unique<RtpDataContentDescription>();
2713 
2714     const RtpDataContentDescription* offer_data_description =
2715         offer_content->media_description()->as_rtp_data();
2716     RTC_CHECK(offer_data_description);
2717     if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2718                            media_description_options, session_options,
2719                            ssrc_generator_, current_streams,
2720                            data_answer->as_rtp_data())) {
2721       return false;
2722     }
2723     if (!CreateMediaContentAnswer(
2724             offer_data_description, media_description_options, session_options,
2725             sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2726             ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2727             current_streams, bundle_enabled, data_answer.get())) {
2728       return false;  // Fails the session setup.
2729     }
2730   }
2731 
2732   bool secure = bundle_transport ? bundle_transport->description.secure()
2733                                  : data_transport->secure();
2734 
2735   bool rejected = session_options.data_channel_type == DCT_NONE ||
2736                   media_description_options.stopped ||
2737                   offer_content->rejected ||
2738                   !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2739                                             data_answer->protocol(), secure);
2740   if (!AddTransportAnswer(media_description_options.mid,
2741                           *(data_transport.get()), answer)) {
2742     return false;
2743   }
2744 
2745   if (!rejected) {
2746     data_answer->set_bandwidth(kDataMaxBandwidth);
2747   } else {
2748     // RFC 3264
2749     // The answer MUST contain the same number of m-lines as the offer.
2750     RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
2751   }
2752   answer->AddContent(media_description_options.mid, offer_content->type,
2753                      rejected, std::move(data_answer));
2754   return true;
2755 }
2756 
ComputeAudioCodecsIntersectionAndUnion()2757 void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2758   audio_sendrecv_codecs_.clear();
2759   all_audio_codecs_.clear();
2760   // Compute the audio codecs union.
2761   for (const AudioCodec& send : audio_send_codecs_) {
2762     all_audio_codecs_.push_back(send);
2763     if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2764                                        send, nullptr)) {
2765       // It doesn't make sense to have an RTX codec we support sending but not
2766       // receiving.
2767       RTC_DCHECK(!IsRtxCodec(send));
2768     }
2769   }
2770   for (const AudioCodec& recv : audio_recv_codecs_) {
2771     if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2772                                        recv, nullptr)) {
2773       all_audio_codecs_.push_back(recv);
2774     }
2775   }
2776   // Use NegotiateCodecs to merge our codec lists, since the operation is
2777   // essentially the same. Put send_codecs as the offered_codecs, which is the
2778   // order we'd like to follow. The reasoning is that encoding is usually more
2779   // expensive than decoding, and prioritizing a codec in the send list probably
2780   // means it's a codec we can handle efficiently.
2781   NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2782                   &audio_sendrecv_codecs_, true);
2783 }
2784 
ComputeVideoCodecsIntersectionAndUnion()2785 void MediaSessionDescriptionFactory::ComputeVideoCodecsIntersectionAndUnion() {
2786   video_sendrecv_codecs_.clear();
2787   all_video_codecs_.clear();
2788   // Compute the video codecs union.
2789   for (const VideoCodec& send : video_send_codecs_) {
2790     all_video_codecs_.push_back(send);
2791     if (!FindMatchingCodec<VideoCodec>(video_send_codecs_, video_recv_codecs_,
2792                                        send, nullptr)) {
2793       // TODO(kron): This check is violated by the unit test:
2794       // MediaSessionDescriptionFactoryTest.RtxWithoutApt
2795       // Remove either the test or the check.
2796 
2797       // It doesn't make sense to have an RTX codec we support sending but not
2798       // receiving.
2799       // RTC_DCHECK(!IsRtxCodec(send));
2800     }
2801   }
2802   for (const VideoCodec& recv : video_recv_codecs_) {
2803     if (!FindMatchingCodec<VideoCodec>(video_recv_codecs_, video_send_codecs_,
2804                                        recv, nullptr)) {
2805       all_video_codecs_.push_back(recv);
2806     }
2807   }
2808   // Use NegotiateCodecs to merge our codec lists, since the operation is
2809   // essentially the same. Put send_codecs as the offered_codecs, which is the
2810   // order we'd like to follow. The reasoning is that encoding is usually more
2811   // expensive than decoding, and prioritizing a codec in the send list probably
2812   // means it's a codec we can handle efficiently.
2813   NegotiateCodecs(video_recv_codecs_, video_send_codecs_,
2814                   &video_sendrecv_codecs_, true);
2815 }
2816 
IsMediaContent(const ContentInfo * content)2817 bool IsMediaContent(const ContentInfo* content) {
2818   return (content && (content->type == MediaProtocolType::kRtp ||
2819                       content->type == MediaProtocolType::kSctp));
2820 }
2821 
IsAudioContent(const ContentInfo * content)2822 bool IsAudioContent(const ContentInfo* content) {
2823   return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2824 }
2825 
IsVideoContent(const ContentInfo * content)2826 bool IsVideoContent(const ContentInfo* content) {
2827   return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2828 }
2829 
IsDataContent(const ContentInfo * content)2830 bool IsDataContent(const ContentInfo* content) {
2831   return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2832 }
2833 
GetFirstMediaContent(const ContentInfos & contents,MediaType media_type)2834 const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2835                                         MediaType media_type) {
2836   for (const ContentInfo& content : contents) {
2837     if (IsMediaContentOfType(&content, media_type)) {
2838       return &content;
2839     }
2840   }
2841   return nullptr;
2842 }
2843 
GetFirstAudioContent(const ContentInfos & contents)2844 const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2845   return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2846 }
2847 
GetFirstVideoContent(const ContentInfos & contents)2848 const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2849   return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2850 }
2851 
GetFirstDataContent(const ContentInfos & contents)2852 const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2853   return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2854 }
2855 
GetFirstMediaContent(const SessionDescription * sdesc,MediaType media_type)2856 const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2857                                         MediaType media_type) {
2858   if (sdesc == nullptr) {
2859     return nullptr;
2860   }
2861 
2862   return GetFirstMediaContent(sdesc->contents(), media_type);
2863 }
2864 
GetFirstAudioContent(const SessionDescription * sdesc)2865 const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2866   return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2867 }
2868 
GetFirstVideoContent(const SessionDescription * sdesc)2869 const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2870   return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2871 }
2872 
GetFirstDataContent(const SessionDescription * sdesc)2873 const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2874   return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2875 }
2876 
GetFirstMediaContentDescription(const SessionDescription * sdesc,MediaType media_type)2877 const MediaContentDescription* GetFirstMediaContentDescription(
2878     const SessionDescription* sdesc,
2879     MediaType media_type) {
2880   const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2881   return (content ? content->media_description() : nullptr);
2882 }
2883 
GetFirstAudioContentDescription(const SessionDescription * sdesc)2884 const AudioContentDescription* GetFirstAudioContentDescription(
2885     const SessionDescription* sdesc) {
2886   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2887   return desc ? desc->as_audio() : nullptr;
2888 }
2889 
GetFirstVideoContentDescription(const SessionDescription * sdesc)2890 const VideoContentDescription* GetFirstVideoContentDescription(
2891     const SessionDescription* sdesc) {
2892   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2893   return desc ? desc->as_video() : nullptr;
2894 }
2895 
GetFirstRtpDataContentDescription(const SessionDescription * sdesc)2896 const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2897     const SessionDescription* sdesc) {
2898   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2899   return desc ? desc->as_rtp_data() : nullptr;
2900 }
2901 
GetFirstSctpDataContentDescription(const SessionDescription * sdesc)2902 const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2903     const SessionDescription* sdesc) {
2904   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2905   return desc ? desc->as_sctp() : nullptr;
2906 }
2907 
2908 //
2909 // Non-const versions of the above functions.
2910 //
2911 
GetFirstMediaContent(ContentInfos * contents,MediaType media_type)2912 ContentInfo* GetFirstMediaContent(ContentInfos* contents,
2913                                   MediaType media_type) {
2914   for (ContentInfo& content : *contents) {
2915     if (IsMediaContentOfType(&content, media_type)) {
2916       return &content;
2917     }
2918   }
2919   return nullptr;
2920 }
2921 
GetFirstAudioContent(ContentInfos * contents)2922 ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
2923   return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2924 }
2925 
GetFirstVideoContent(ContentInfos * contents)2926 ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
2927   return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2928 }
2929 
GetFirstDataContent(ContentInfos * contents)2930 ContentInfo* GetFirstDataContent(ContentInfos* contents) {
2931   return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2932 }
2933 
GetFirstMediaContent(SessionDescription * sdesc,MediaType media_type)2934 ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2935                                   MediaType media_type) {
2936   if (sdesc == nullptr) {
2937     return nullptr;
2938   }
2939 
2940   return GetFirstMediaContent(&sdesc->contents(), media_type);
2941 }
2942 
GetFirstAudioContent(SessionDescription * sdesc)2943 ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2944   return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2945 }
2946 
GetFirstVideoContent(SessionDescription * sdesc)2947 ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2948   return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2949 }
2950 
GetFirstDataContent(SessionDescription * sdesc)2951 ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2952   return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2953 }
2954 
GetFirstMediaContentDescription(SessionDescription * sdesc,MediaType media_type)2955 MediaContentDescription* GetFirstMediaContentDescription(
2956     SessionDescription* sdesc,
2957     MediaType media_type) {
2958   ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2959   return (content ? content->media_description() : nullptr);
2960 }
2961 
GetFirstAudioContentDescription(SessionDescription * sdesc)2962 AudioContentDescription* GetFirstAudioContentDescription(
2963     SessionDescription* sdesc) {
2964   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2965   return desc ? desc->as_audio() : nullptr;
2966 }
2967 
GetFirstVideoContentDescription(SessionDescription * sdesc)2968 VideoContentDescription* GetFirstVideoContentDescription(
2969     SessionDescription* sdesc) {
2970   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2971   return desc ? desc->as_video() : nullptr;
2972 }
2973 
GetFirstRtpDataContentDescription(SessionDescription * sdesc)2974 RtpDataContentDescription* GetFirstRtpDataContentDescription(
2975     SessionDescription* sdesc) {
2976   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2977   return desc ? desc->as_rtp_data() : nullptr;
2978 }
2979 
GetFirstSctpDataContentDescription(SessionDescription * sdesc)2980 SctpDataContentDescription* GetFirstSctpDataContentDescription(
2981     SessionDescription* sdesc) {
2982   auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2983   return desc ? desc->as_sctp() : nullptr;
2984 }
2985 
2986 }  // namespace cricket
2987