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