1 /*
2 * Copyright 2020 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "pc/sdp_offer_answer.h"
12
13 #include <algorithm>
14 #include <iterator>
15 #include <map>
16 #include <queue>
17 #include <type_traits>
18 #include <utility>
19
20 #include "absl/algorithm/container.h"
21 #include "absl/memory/memory.h"
22 #include "absl/strings/string_view.h"
23 #include "api/array_view.h"
24 #include "api/crypto/crypto_options.h"
25 #include "api/data_channel_interface.h"
26 #include "api/dtls_transport_interface.h"
27 #include "api/media_stream_proxy.h"
28 #include "api/rtp_parameters.h"
29 #include "api/rtp_receiver_interface.h"
30 #include "api/rtp_sender_interface.h"
31 #include "api/video/builtin_video_bitrate_allocator_factory.h"
32 #include "media/base/codec.h"
33 #include "media/base/media_engine.h"
34 #include "media/base/rid_description.h"
35 #include "p2p/base/p2p_constants.h"
36 #include "p2p/base/p2p_transport_channel.h"
37 #include "p2p/base/port.h"
38 #include "p2p/base/transport_description.h"
39 #include "p2p/base/transport_description_factory.h"
40 #include "p2p/base/transport_info.h"
41 #include "pc/data_channel_utils.h"
42 #include "pc/media_protocol_names.h"
43 #include "pc/media_stream.h"
44 #include "pc/peer_connection.h"
45 #include "pc/peer_connection_message_handler.h"
46 #include "pc/rtp_data_channel.h"
47 #include "pc/rtp_media_utils.h"
48 #include "pc/rtp_sender.h"
49 #include "pc/rtp_transport_internal.h"
50 #include "pc/sctp_transport.h"
51 #include "pc/simulcast_description.h"
52 #include "pc/stats_collector.h"
53 #include "pc/usage_pattern.h"
54 #include "pc/webrtc_session_description_factory.h"
55 #include "rtc_base/helpers.h"
56 #include "rtc_base/location.h"
57 #include "rtc_base/logging.h"
58 #include "rtc_base/ref_counted_object.h"
59 #include "rtc_base/rtc_certificate.h"
60 #include "rtc_base/socket_address.h"
61 #include "rtc_base/ssl_stream_adapter.h"
62 #include "rtc_base/string_encode.h"
63 #include "rtc_base/strings/string_builder.h"
64 #include "rtc_base/third_party/sigslot/sigslot.h"
65 #include "rtc_base/trace_event.h"
66 #include "system_wrappers/include/metrics.h"
67
68 using cricket::ContentInfo;
69 using cricket::ContentInfos;
70 using cricket::MediaContentDescription;
71 using cricket::MediaProtocolType;
72 using cricket::RidDescription;
73 using cricket::RidDirection;
74 using cricket::SessionDescription;
75 using cricket::SimulcastDescription;
76 using cricket::SimulcastLayer;
77 using cricket::SimulcastLayerList;
78 using cricket::StreamParams;
79 using cricket::TransportInfo;
80
81 using cricket::LOCAL_PORT_TYPE;
82 using cricket::PRFLX_PORT_TYPE;
83 using cricket::RELAY_PORT_TYPE;
84 using cricket::STUN_PORT_TYPE;
85
86 namespace webrtc {
87
88 namespace {
89
90 typedef webrtc::PeerConnectionInterface::RTCOfferAnswerOptions
91 RTCOfferAnswerOptions;
92
93 // Error messages
94 const char kInvalidSdp[] = "Invalid session description.";
95 const char kInvalidCandidates[] = "Description contains invalid candidates.";
96 const char kBundleWithoutRtcpMux[] =
97 "rtcp-mux must be enabled when BUNDLE "
98 "is enabled.";
99 const char kMlineMismatchInAnswer[] =
100 "The order of m-lines in answer doesn't match order in offer. Rejecting "
101 "answer.";
102 const char kMlineMismatchInSubsequentOffer[] =
103 "The order of m-lines in subsequent offer doesn't match order from "
104 "previous offer/answer.";
105 const char kSdpWithoutIceUfragPwd[] =
106 "Called with SDP without ice-ufrag and ice-pwd.";
107 const char kSdpWithoutDtlsFingerprint[] =
108 "Called with SDP without DTLS fingerprint.";
109 const char kSdpWithoutSdesCrypto[] = "Called with SDP without SDES crypto.";
110
111 const char kSessionError[] = "Session error code: ";
112 const char kSessionErrorDesc[] = "Session error description: ";
113
114 // UMA metric names.
115 const char kSimulcastVersionApplyLocalDescription[] =
116 "WebRTC.PeerConnection.Simulcast.ApplyLocalDescription";
117 const char kSimulcastVersionApplyRemoteDescription[] =
118 "WebRTC.PeerConnection.Simulcast.ApplyRemoteDescription";
119 const char kSimulcastDisabled[] = "WebRTC.PeerConnection.Simulcast.Disabled";
120
121 // The length of RTCP CNAMEs.
122 static const int kRtcpCnameLength = 16;
123
124 const char kDefaultStreamId[] = "default";
125 // NOTE: Duplicated in peer_connection.cc:
126 static const char kDefaultAudioSenderId[] = "defaulta0";
127 static const char kDefaultVideoSenderId[] = "defaultv0";
128
NoteAddIceCandidateResult(int result)129 void NoteAddIceCandidateResult(int result) {
130 RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.AddIceCandidate", result,
131 kAddIceCandidateMax);
132 }
133
NoteKeyProtocolAndMedia(KeyExchangeProtocolType protocol_type,cricket::MediaType media_type)134 void NoteKeyProtocolAndMedia(KeyExchangeProtocolType protocol_type,
135 cricket::MediaType media_type) {
136 // Array of structs needed to map {KeyExchangeProtocolType,
137 // cricket::MediaType} to KeyExchangeProtocolMedia without using std::map in
138 // order to avoid -Wglobal-constructors and -Wexit-time-destructors.
139 static constexpr struct {
140 KeyExchangeProtocolType protocol_type;
141 cricket::MediaType media_type;
142 KeyExchangeProtocolMedia protocol_media;
143 } kEnumCounterKeyProtocolMediaMap[] = {
144 {kEnumCounterKeyProtocolDtls, cricket::MEDIA_TYPE_AUDIO,
145 kEnumCounterKeyProtocolMediaTypeDtlsAudio},
146 {kEnumCounterKeyProtocolDtls, cricket::MEDIA_TYPE_VIDEO,
147 kEnumCounterKeyProtocolMediaTypeDtlsVideo},
148 {kEnumCounterKeyProtocolDtls, cricket::MEDIA_TYPE_DATA,
149 kEnumCounterKeyProtocolMediaTypeDtlsData},
150 {kEnumCounterKeyProtocolSdes, cricket::MEDIA_TYPE_AUDIO,
151 kEnumCounterKeyProtocolMediaTypeSdesAudio},
152 {kEnumCounterKeyProtocolSdes, cricket::MEDIA_TYPE_VIDEO,
153 kEnumCounterKeyProtocolMediaTypeSdesVideo},
154 {kEnumCounterKeyProtocolSdes, cricket::MEDIA_TYPE_DATA,
155 kEnumCounterKeyProtocolMediaTypeSdesData},
156 };
157
158 RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.KeyProtocol", protocol_type,
159 kEnumCounterKeyProtocolMax);
160
161 for (const auto& i : kEnumCounterKeyProtocolMediaMap) {
162 if (i.protocol_type == protocol_type && i.media_type == media_type) {
163 RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.KeyProtocolByMedia",
164 i.protocol_media,
165 kEnumCounterKeyProtocolMediaTypeMax);
166 }
167 }
168 }
169
170 // Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd).
CheckForRemoteIceRestart(const SessionDescriptionInterface * old_desc,const SessionDescriptionInterface * new_desc,const std::string & content_name)171 bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc,
172 const SessionDescriptionInterface* new_desc,
173 const std::string& content_name) {
174 if (!old_desc) {
175 return false;
176 }
177 const SessionDescription* new_sd = new_desc->description();
178 const SessionDescription* old_sd = old_desc->description();
179 const ContentInfo* cinfo = new_sd->GetContentByName(content_name);
180 if (!cinfo || cinfo->rejected) {
181 return false;
182 }
183 // If the content isn't rejected, check if ufrag and password has changed.
184 const cricket::TransportDescription* new_transport_desc =
185 new_sd->GetTransportDescriptionByName(content_name);
186 const cricket::TransportDescription* old_transport_desc =
187 old_sd->GetTransportDescriptionByName(content_name);
188 if (!new_transport_desc || !old_transport_desc) {
189 // No transport description exists. This is not an ICE restart.
190 return false;
191 }
192 if (cricket::IceCredentialsChanged(
193 old_transport_desc->ice_ufrag, old_transport_desc->ice_pwd,
194 new_transport_desc->ice_ufrag, new_transport_desc->ice_pwd)) {
195 RTC_LOG(LS_INFO) << "Remote peer requests ICE restart for " << content_name
196 << ".";
197 return true;
198 }
199 return false;
200 }
201
202 // Generates a string error message for SetLocalDescription/SetRemoteDescription
203 // from an RTCError.
GetSetDescriptionErrorMessage(cricket::ContentSource source,SdpType type,const RTCError & error)204 std::string GetSetDescriptionErrorMessage(cricket::ContentSource source,
205 SdpType type,
206 const RTCError& error) {
207 rtc::StringBuilder oss;
208 oss << "Failed to set " << (source == cricket::CS_LOCAL ? "local" : "remote")
209 << " " << SdpTypeToString(type) << " sdp: " << error.message();
210 return oss.Release();
211 }
212
GetStreamIdsString(rtc::ArrayView<const std::string> stream_ids)213 std::string GetStreamIdsString(rtc::ArrayView<const std::string> stream_ids) {
214 std::string output = "streams=[";
215 const char* separator = "";
216 for (const auto& stream_id : stream_ids) {
217 output.append(separator).append(stream_id);
218 separator = ", ";
219 }
220 output.append("]");
221 return output;
222 }
223
ReportSimulcastApiVersion(const char * name,const SessionDescription & session)224 void ReportSimulcastApiVersion(const char* name,
225 const SessionDescription& session) {
226 bool has_legacy = false;
227 bool has_spec_compliant = false;
228 for (const ContentInfo& content : session.contents()) {
229 if (!content.media_description()) {
230 continue;
231 }
232 has_spec_compliant |= content.media_description()->HasSimulcast();
233 for (const StreamParams& sp : content.media_description()->streams()) {
234 has_legacy |= sp.has_ssrc_group(cricket::kSimSsrcGroupSemantics);
235 }
236 }
237
238 if (has_legacy) {
239 RTC_HISTOGRAM_ENUMERATION(name, kSimulcastApiVersionLegacy,
240 kSimulcastApiVersionMax);
241 }
242 if (has_spec_compliant) {
243 RTC_HISTOGRAM_ENUMERATION(name, kSimulcastApiVersionSpecCompliant,
244 kSimulcastApiVersionMax);
245 }
246 if (!has_legacy && !has_spec_compliant) {
247 RTC_HISTOGRAM_ENUMERATION(name, kSimulcastApiVersionNone,
248 kSimulcastApiVersionMax);
249 }
250 }
251
FindTransceiverMSection(RtpTransceiverProxyWithInternal<RtpTransceiver> * transceiver,const SessionDescriptionInterface * session_description)252 const ContentInfo* FindTransceiverMSection(
253 RtpTransceiverProxyWithInternal<RtpTransceiver>* transceiver,
254 const SessionDescriptionInterface* session_description) {
255 return transceiver->mid()
256 ? session_description->description()->GetContentByName(
257 *transceiver->mid())
258 : nullptr;
259 }
260
261 // If the direction is "recvonly" or "inactive", treat the description
262 // as containing no streams.
263 // See: https://code.google.com/p/webrtc/issues/detail?id=5054
GetActiveStreams(const cricket::MediaContentDescription * desc)264 std::vector<cricket::StreamParams> GetActiveStreams(
265 const cricket::MediaContentDescription* desc) {
266 return RtpTransceiverDirectionHasSend(desc->direction())
267 ? desc->streams()
268 : std::vector<cricket::StreamParams>();
269 }
270
271 // Logic to decide if an m= section can be recycled. This means that the new
272 // m= section is not rejected, but the old local or remote m= section is
273 // rejected. |old_content_one| and |old_content_two| refer to the m= section
274 // of the old remote and old local descriptions in no particular order.
275 // We need to check both the old local and remote because either
276 // could be the most current from the latest negotation.
IsMediaSectionBeingRecycled(SdpType type,const ContentInfo & content,const ContentInfo * old_content_one,const ContentInfo * old_content_two)277 bool IsMediaSectionBeingRecycled(SdpType type,
278 const ContentInfo& content,
279 const ContentInfo* old_content_one,
280 const ContentInfo* old_content_two) {
281 return type == SdpType::kOffer && !content.rejected &&
282 ((old_content_one && old_content_one->rejected) ||
283 (old_content_two && old_content_two->rejected));
284 }
285
286 // Verify that the order of media sections in |new_desc| matches
287 // |current_desc|. The number of m= sections in |new_desc| should be no
288 // less than |current_desc|. In the case of checking an answer's
289 // |new_desc|, the |current_desc| is the last offer that was set as the
290 // local or remote. In the case of checking an offer's |new_desc| we
291 // check against the local and remote descriptions stored from the last
292 // negotiation, because either of these could be the most up to date for
293 // possible rejected m sections. These are the |current_desc| and
294 // |secondary_current_desc|.
MediaSectionsInSameOrder(const SessionDescription & current_desc,const SessionDescription * secondary_current_desc,const SessionDescription & new_desc,const SdpType type)295 bool MediaSectionsInSameOrder(const SessionDescription& current_desc,
296 const SessionDescription* secondary_current_desc,
297 const SessionDescription& new_desc,
298 const SdpType type) {
299 if (current_desc.contents().size() > new_desc.contents().size()) {
300 return false;
301 }
302
303 for (size_t i = 0; i < current_desc.contents().size(); ++i) {
304 const cricket::ContentInfo* secondary_content_info = nullptr;
305 if (secondary_current_desc &&
306 i < secondary_current_desc->contents().size()) {
307 secondary_content_info = &secondary_current_desc->contents()[i];
308 }
309 if (IsMediaSectionBeingRecycled(type, new_desc.contents()[i],
310 ¤t_desc.contents()[i],
311 secondary_content_info)) {
312 // For new offer descriptions, if the media section can be recycled, it's
313 // valid for the MID and media type to change.
314 continue;
315 }
316 if (new_desc.contents()[i].name != current_desc.contents()[i].name) {
317 return false;
318 }
319 const MediaContentDescription* new_desc_mdesc =
320 new_desc.contents()[i].media_description();
321 const MediaContentDescription* current_desc_mdesc =
322 current_desc.contents()[i].media_description();
323 if (new_desc_mdesc->type() != current_desc_mdesc->type()) {
324 return false;
325 }
326 }
327 return true;
328 }
329
MediaSectionsHaveSameCount(const SessionDescription & desc1,const SessionDescription & desc2)330 bool MediaSectionsHaveSameCount(const SessionDescription& desc1,
331 const SessionDescription& desc2) {
332 return desc1.contents().size() == desc2.contents().size();
333 }
334 // Checks that each non-rejected content has SDES crypto keys or a DTLS
335 // fingerprint, unless it's in a BUNDLE group, in which case only the
336 // BUNDLE-tag section (first media section/description in the BUNDLE group)
337 // needs a ufrag and pwd. Mismatches, such as replying with a DTLS fingerprint
338 // to SDES keys, will be caught in JsepTransport negotiation, and backstopped
339 // by Channel's |srtp_required| check.
VerifyCrypto(const SessionDescription * desc,bool dtls_enabled)340 RTCError VerifyCrypto(const SessionDescription* desc, bool dtls_enabled) {
341 const cricket::ContentGroup* bundle =
342 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
343 for (const cricket::ContentInfo& content_info : desc->contents()) {
344 if (content_info.rejected) {
345 continue;
346 }
347 // Note what media is used with each crypto protocol, for all sections.
348 NoteKeyProtocolAndMedia(dtls_enabled ? webrtc::kEnumCounterKeyProtocolDtls
349 : webrtc::kEnumCounterKeyProtocolSdes,
350 content_info.media_description()->type());
351 const std::string& mid = content_info.name;
352 if (bundle && bundle->HasContentName(mid) &&
353 mid != *(bundle->FirstContentName())) {
354 // This isn't the first media section in the BUNDLE group, so it's not
355 // required to have crypto attributes, since only the crypto attributes
356 // from the first section actually get used.
357 continue;
358 }
359
360 // If the content isn't rejected or bundled into another m= section, crypto
361 // must be present.
362 const MediaContentDescription* media = content_info.media_description();
363 const TransportInfo* tinfo = desc->GetTransportInfoByName(mid);
364 if (!media || !tinfo) {
365 // Something is not right.
366 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, kInvalidSdp);
367 }
368 if (dtls_enabled) {
369 if (!tinfo->description.identity_fingerprint) {
370 RTC_LOG(LS_WARNING)
371 << "Session description must have DTLS fingerprint if "
372 "DTLS enabled.";
373 return RTCError(RTCErrorType::INVALID_PARAMETER,
374 kSdpWithoutDtlsFingerprint);
375 }
376 } else {
377 if (media->cryptos().empty()) {
378 RTC_LOG(LS_WARNING)
379 << "Session description must have SDES when DTLS disabled.";
380 return RTCError(RTCErrorType::INVALID_PARAMETER, kSdpWithoutSdesCrypto);
381 }
382 }
383 }
384 return RTCError::OK();
385 }
386
387 // Checks that each non-rejected content has ice-ufrag and ice-pwd set, unless
388 // it's in a BUNDLE group, in which case only the BUNDLE-tag section (first
389 // media section/description in the BUNDLE group) needs a ufrag and pwd.
VerifyIceUfragPwdPresent(const SessionDescription * desc)390 bool VerifyIceUfragPwdPresent(const SessionDescription* desc) {
391 const cricket::ContentGroup* bundle =
392 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
393 for (const cricket::ContentInfo& content_info : desc->contents()) {
394 if (content_info.rejected) {
395 continue;
396 }
397 const std::string& mid = content_info.name;
398 if (bundle && bundle->HasContentName(mid) &&
399 mid != *(bundle->FirstContentName())) {
400 // This isn't the first media section in the BUNDLE group, so it's not
401 // required to have ufrag/password, since only the ufrag/password from
402 // the first section actually get used.
403 continue;
404 }
405
406 // If the content isn't rejected or bundled into another m= section,
407 // ice-ufrag and ice-pwd must be present.
408 const TransportInfo* tinfo = desc->GetTransportInfoByName(mid);
409 if (!tinfo) {
410 // Something is not right.
411 RTC_LOG(LS_ERROR) << kInvalidSdp;
412 return false;
413 }
414 if (tinfo->description.ice_ufrag.empty() ||
415 tinfo->description.ice_pwd.empty()) {
416 RTC_LOG(LS_ERROR) << "Session description must have ice ufrag and pwd.";
417 return false;
418 }
419 }
420 return true;
421 }
422
ValidateMids(const cricket::SessionDescription & description)423 static RTCError ValidateMids(const cricket::SessionDescription& description) {
424 std::set<std::string> mids;
425 for (const cricket::ContentInfo& content : description.contents()) {
426 if (content.name.empty()) {
427 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
428 "A media section is missing a MID attribute.");
429 }
430 if (!mids.insert(content.name).second) {
431 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
432 "Duplicate a=mid value '" + content.name + "'.");
433 }
434 }
435 return RTCError::OK();
436 }
437
IsValidOfferToReceiveMedia(int value)438 bool IsValidOfferToReceiveMedia(int value) {
439 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
440 return (value >= Options::kUndefined) &&
441 (value <= Options::kMaxOfferToReceiveMedia);
442 }
443
ValidateOfferAnswerOptions(const PeerConnectionInterface::RTCOfferAnswerOptions & rtc_options)444 bool ValidateOfferAnswerOptions(
445 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options) {
446 return IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) &&
447 IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video);
448 }
449
450 // Map internal signaling state name to spec name:
451 // https://w3c.github.io/webrtc-pc/#rtcsignalingstate-enum
GetSignalingStateString(PeerConnectionInterface::SignalingState state)452 std::string GetSignalingStateString(
453 PeerConnectionInterface::SignalingState state) {
454 switch (state) {
455 case PeerConnectionInterface::kStable:
456 return "stable";
457 case PeerConnectionInterface::kHaveLocalOffer:
458 return "have-local-offer";
459 case PeerConnectionInterface::kHaveLocalPrAnswer:
460 return "have-local-pranswer";
461 case PeerConnectionInterface::kHaveRemoteOffer:
462 return "have-remote-offer";
463 case PeerConnectionInterface::kHaveRemotePrAnswer:
464 return "have-remote-pranswer";
465 case PeerConnectionInterface::kClosed:
466 return "closed";
467 }
468 RTC_NOTREACHED();
469 return "";
470 }
471
472 // This method will extract any send encodings that were sent by the remote
473 // connection. This is currently only relevant for Simulcast scenario (where
474 // the number of layers may be communicated by the server).
GetSendEncodingsFromRemoteDescription(const MediaContentDescription & desc)475 static std::vector<RtpEncodingParameters> GetSendEncodingsFromRemoteDescription(
476 const MediaContentDescription& desc) {
477 if (!desc.HasSimulcast()) {
478 return {};
479 }
480 std::vector<RtpEncodingParameters> result;
481 const SimulcastDescription& simulcast = desc.simulcast_description();
482
483 // This is a remote description, the parameters we are after should appear
484 // as receive streams.
485 for (const auto& alternatives : simulcast.receive_layers()) {
486 RTC_DCHECK(!alternatives.empty());
487 // There is currently no way to specify or choose from alternatives.
488 // We will always use the first alternative, which is the most preferred.
489 const SimulcastLayer& layer = alternatives[0];
490 RtpEncodingParameters parameters;
491 parameters.rid = layer.rid;
492 parameters.active = !layer.is_paused;
493 result.push_back(parameters);
494 }
495
496 return result;
497 }
498
UpdateSimulcastLayerStatusInSender(const std::vector<SimulcastLayer> & layers,rtc::scoped_refptr<RtpSenderInternal> sender)499 static RTCError UpdateSimulcastLayerStatusInSender(
500 const std::vector<SimulcastLayer>& layers,
501 rtc::scoped_refptr<RtpSenderInternal> sender) {
502 RTC_DCHECK(sender);
503 RtpParameters parameters = sender->GetParametersInternal();
504 std::vector<std::string> disabled_layers;
505
506 // The simulcast envelope cannot be changed, only the status of the streams.
507 // So we will iterate over the send encodings rather than the layers.
508 for (RtpEncodingParameters& encoding : parameters.encodings) {
509 auto iter = std::find_if(layers.begin(), layers.end(),
510 [&encoding](const SimulcastLayer& layer) {
511 return layer.rid == encoding.rid;
512 });
513 // A layer that cannot be found may have been removed by the remote party.
514 if (iter == layers.end()) {
515 disabled_layers.push_back(encoding.rid);
516 continue;
517 }
518
519 encoding.active = !iter->is_paused;
520 }
521
522 RTCError result = sender->SetParametersInternal(parameters);
523 if (result.ok()) {
524 result = sender->DisableEncodingLayers(disabled_layers);
525 }
526
527 return result;
528 }
529
SimulcastIsRejected(const ContentInfo * local_content,const MediaContentDescription & answer_media_desc)530 static bool SimulcastIsRejected(
531 const ContentInfo* local_content,
532 const MediaContentDescription& answer_media_desc) {
533 bool simulcast_offered = local_content &&
534 local_content->media_description() &&
535 local_content->media_description()->HasSimulcast();
536 bool simulcast_answered = answer_media_desc.HasSimulcast();
537 bool rids_supported = RtpExtension::FindHeaderExtensionByUri(
538 answer_media_desc.rtp_header_extensions(), RtpExtension::kRidUri);
539 return simulcast_offered && (!simulcast_answered || !rids_supported);
540 }
541
DisableSimulcastInSender(rtc::scoped_refptr<RtpSenderInternal> sender)542 static RTCError DisableSimulcastInSender(
543 rtc::scoped_refptr<RtpSenderInternal> sender) {
544 RTC_DCHECK(sender);
545 RtpParameters parameters = sender->GetParametersInternal();
546 if (parameters.encodings.size() <= 1) {
547 return RTCError::OK();
548 }
549
550 std::vector<std::string> disabled_layers;
551 std::transform(
552 parameters.encodings.begin() + 1, parameters.encodings.end(),
553 std::back_inserter(disabled_layers),
554 [](const RtpEncodingParameters& encoding) { return encoding.rid; });
555 return sender->DisableEncodingLayers(disabled_layers);
556 }
557
558 // The SDP parser used to populate these values by default for the 'content
559 // name' if an a=mid line was absent.
GetDefaultMidForPlanB(cricket::MediaType media_type)560 static absl::string_view GetDefaultMidForPlanB(cricket::MediaType media_type) {
561 switch (media_type) {
562 case cricket::MEDIA_TYPE_AUDIO:
563 return cricket::CN_AUDIO;
564 case cricket::MEDIA_TYPE_VIDEO:
565 return cricket::CN_VIDEO;
566 case cricket::MEDIA_TYPE_DATA:
567 return cricket::CN_DATA;
568 case cricket::MEDIA_TYPE_UNSUPPORTED:
569 return "not supported";
570 }
571 RTC_NOTREACHED();
572 return "";
573 }
574
575 // Add options to |[audio/video]_media_description_options| from |senders|.
AddPlanBRtpSenderOptions(const std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>> & senders,cricket::MediaDescriptionOptions * audio_media_description_options,cricket::MediaDescriptionOptions * video_media_description_options,int num_sim_layers)576 void AddPlanBRtpSenderOptions(
577 const std::vector<rtc::scoped_refptr<
578 RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders,
579 cricket::MediaDescriptionOptions* audio_media_description_options,
580 cricket::MediaDescriptionOptions* video_media_description_options,
581 int num_sim_layers) {
582 for (const auto& sender : senders) {
583 if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
584 if (audio_media_description_options) {
585 audio_media_description_options->AddAudioSender(
586 sender->id(), sender->internal()->stream_ids());
587 }
588 } else {
589 RTC_DCHECK(sender->media_type() == cricket::MEDIA_TYPE_VIDEO);
590 if (video_media_description_options) {
591 video_media_description_options->AddVideoSender(
592 sender->id(), sender->internal()->stream_ids(), {},
593 SimulcastLayerList(), num_sim_layers);
594 }
595 }
596 }
597 }
598
599 static cricket::MediaDescriptionOptions
GetMediaDescriptionOptionsForTransceiver(rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>> transceiver,const std::string & mid,bool is_create_offer)600 GetMediaDescriptionOptionsForTransceiver(
601 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
602 transceiver,
603 const std::string& mid,
604 bool is_create_offer) {
605 // NOTE: a stopping transceiver should be treated as a stopped one in
606 // createOffer as specified in
607 // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createoffer.
608 bool stopped =
609 is_create_offer ? transceiver->stopping() : transceiver->stopped();
610 cricket::MediaDescriptionOptions media_description_options(
611 transceiver->media_type(), mid, transceiver->direction(), stopped);
612 media_description_options.codec_preferences =
613 transceiver->codec_preferences();
614 media_description_options.header_extensions =
615 transceiver->HeaderExtensionsToOffer();
616 // This behavior is specified in JSEP. The gist is that:
617 // 1. The MSID is included if the RtpTransceiver's direction is sendonly or
618 // sendrecv.
619 // 2. If the MSID is included, then it must be included in any subsequent
620 // offer/answer exactly the same until the RtpTransceiver is stopped.
621 if (stopped || (!RtpTransceiverDirectionHasSend(transceiver->direction()) &&
622 !transceiver->internal()->has_ever_been_used_to_send())) {
623 return media_description_options;
624 }
625
626 cricket::SenderOptions sender_options;
627 sender_options.track_id = transceiver->sender()->id();
628 sender_options.stream_ids = transceiver->sender()->stream_ids();
629
630 // The following sets up RIDs and Simulcast.
631 // RIDs are included if Simulcast is requested or if any RID was specified.
632 RtpParameters send_parameters =
633 transceiver->internal()->sender_internal()->GetParametersInternal();
634 bool has_rids = std::any_of(send_parameters.encodings.begin(),
635 send_parameters.encodings.end(),
636 [](const RtpEncodingParameters& encoding) {
637 return !encoding.rid.empty();
638 });
639
640 std::vector<RidDescription> send_rids;
641 SimulcastLayerList send_layers;
642 for (const RtpEncodingParameters& encoding : send_parameters.encodings) {
643 if (encoding.rid.empty()) {
644 continue;
645 }
646 send_rids.push_back(RidDescription(encoding.rid, RidDirection::kSend));
647 send_layers.AddLayer(SimulcastLayer(encoding.rid, !encoding.active));
648 }
649
650 if (has_rids) {
651 sender_options.rids = send_rids;
652 }
653
654 sender_options.simulcast_layers = send_layers;
655 // When RIDs are configured, we must set num_sim_layers to 0 to.
656 // Otherwise, num_sim_layers must be 1 because either there is no
657 // simulcast, or simulcast is acheived by munging the SDP.
658 sender_options.num_sim_layers = has_rids ? 0 : 1;
659 media_description_options.sender_options.push_back(sender_options);
660
661 return media_description_options;
662 }
663
664 // Returns the ContentInfo at mline index |i|, or null if none exists.
GetContentByIndex(const SessionDescriptionInterface * sdesc,size_t i)665 static const ContentInfo* GetContentByIndex(
666 const SessionDescriptionInterface* sdesc,
667 size_t i) {
668 if (!sdesc) {
669 return nullptr;
670 }
671 const ContentInfos& contents = sdesc->description()->contents();
672 return (i < contents.size() ? &contents[i] : nullptr);
673 }
674
675 // From |rtc_options|, fill parts of |session_options| shared by all generated
676 // m= sectionss (in other words, nothing that involves a map/array).
ExtractSharedMediaSessionOptions(const PeerConnectionInterface::RTCOfferAnswerOptions & rtc_options,cricket::MediaSessionOptions * session_options)677 void ExtractSharedMediaSessionOptions(
678 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
679 cricket::MediaSessionOptions* session_options) {
680 session_options->vad_enabled = rtc_options.voice_activity_detection;
681 session_options->bundle_enabled = rtc_options.use_rtp_mux;
682 session_options->raw_packetization_for_video =
683 rtc_options.raw_packetization_for_video;
684 }
685
686 // Generate a RTCP CNAME when a PeerConnection is created.
GenerateRtcpCname()687 std::string GenerateRtcpCname() {
688 std::string cname;
689 if (!rtc::CreateRandomString(kRtcpCnameLength, &cname)) {
690 RTC_LOG(LS_ERROR) << "Failed to generate CNAME.";
691 RTC_NOTREACHED();
692 }
693 return cname;
694 }
695
696 // Add options to |session_options| from |rtp_data_channels|.
AddRtpDataChannelOptions(const std::map<std::string,rtc::scoped_refptr<RtpDataChannel>> & rtp_data_channels,cricket::MediaDescriptionOptions * data_media_description_options)697 void AddRtpDataChannelOptions(
698 const std::map<std::string, rtc::scoped_refptr<RtpDataChannel>>&
699 rtp_data_channels,
700 cricket::MediaDescriptionOptions* data_media_description_options) {
701 if (!data_media_description_options) {
702 return;
703 }
704 // Check for data channels.
705 for (const auto& kv : rtp_data_channels) {
706 const RtpDataChannel* channel = kv.second;
707 if (channel->state() == RtpDataChannel::kConnecting ||
708 channel->state() == RtpDataChannel::kOpen) {
709 // Legacy RTP data channels are signaled with the track/stream ID set to
710 // the data channel's label.
711 data_media_description_options->AddRtpDataChannel(channel->label(),
712 channel->label());
713 }
714 }
715 }
716
717 // Check if we can send |new_stream| on a PeerConnection.
CanAddLocalMediaStream(webrtc::StreamCollectionInterface * current_streams,webrtc::MediaStreamInterface * new_stream)718 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
719 webrtc::MediaStreamInterface* new_stream) {
720 if (!new_stream || !current_streams) {
721 return false;
722 }
723 if (current_streams->find(new_stream->id()) != nullptr) {
724 RTC_LOG(LS_ERROR) << "MediaStream with ID " << new_stream->id()
725 << " is already added.";
726 return false;
727 }
728 return true;
729 }
730
LookupDtlsTransportByMid(rtc::Thread * network_thread,JsepTransportController * controller,const std::string & mid)731 rtc::scoped_refptr<webrtc::DtlsTransport> LookupDtlsTransportByMid(
732 rtc::Thread* network_thread,
733 JsepTransportController* controller,
734 const std::string& mid) {
735 // TODO(tommi): Can we post this (and associated operations where this
736 // function is called) to the network thread and avoid this Invoke?
737 // We might be able to simplify a few things if we set the transport on
738 // the network thread and then update the implementation to check that
739 // the set_ and relevant get methods are always called on the network
740 // thread (we'll need to update proxy maps).
741 return network_thread->Invoke<rtc::scoped_refptr<webrtc::DtlsTransport>>(
742 RTC_FROM_HERE,
743 [controller, &mid] { return controller->LookupDtlsTransportByMid(mid); });
744 }
745
746 } // namespace
747
748 // Used by parameterless SetLocalDescription() to create an offer or answer.
749 // Upon completion of creating the session description, SetLocalDescription() is
750 // invoked with the result.
751 class SdpOfferAnswerHandler::ImplicitCreateSessionDescriptionObserver
752 : public CreateSessionDescriptionObserver {
753 public:
ImplicitCreateSessionDescriptionObserver(rtc::WeakPtr<SdpOfferAnswerHandler> sdp_handler,rtc::scoped_refptr<SetLocalDescriptionObserverInterface> set_local_description_observer)754 ImplicitCreateSessionDescriptionObserver(
755 rtc::WeakPtr<SdpOfferAnswerHandler> sdp_handler,
756 rtc::scoped_refptr<SetLocalDescriptionObserverInterface>
757 set_local_description_observer)
758 : sdp_handler_(std::move(sdp_handler)),
759 set_local_description_observer_(
760 std::move(set_local_description_observer)) {}
~ImplicitCreateSessionDescriptionObserver()761 ~ImplicitCreateSessionDescriptionObserver() override {
762 RTC_DCHECK(was_called_);
763 }
764
SetOperationCompleteCallback(std::function<void ()> operation_complete_callback)765 void SetOperationCompleteCallback(
766 std::function<void()> operation_complete_callback) {
767 operation_complete_callback_ = std::move(operation_complete_callback);
768 }
769
was_called() const770 bool was_called() const { return was_called_; }
771
OnSuccess(SessionDescriptionInterface * desc_ptr)772 void OnSuccess(SessionDescriptionInterface* desc_ptr) override {
773 RTC_DCHECK(!was_called_);
774 std::unique_ptr<SessionDescriptionInterface> desc(desc_ptr);
775 was_called_ = true;
776
777 // Abort early if |pc_| is no longer valid.
778 if (!sdp_handler_) {
779 operation_complete_callback_();
780 return;
781 }
782 // DoSetLocalDescription() is a synchronous operation that invokes
783 // |set_local_description_observer_| with the result.
784 sdp_handler_->DoSetLocalDescription(
785 std::move(desc), std::move(set_local_description_observer_));
786 operation_complete_callback_();
787 }
788
OnFailure(RTCError error)789 void OnFailure(RTCError error) override {
790 RTC_DCHECK(!was_called_);
791 was_called_ = true;
792 set_local_description_observer_->OnSetLocalDescriptionComplete(RTCError(
793 error.type(), std::string("SetLocalDescription failed to create "
794 "session description - ") +
795 error.message()));
796 operation_complete_callback_();
797 }
798
799 private:
800 bool was_called_ = false;
801 rtc::WeakPtr<SdpOfferAnswerHandler> sdp_handler_;
802 rtc::scoped_refptr<SetLocalDescriptionObserverInterface>
803 set_local_description_observer_;
804 std::function<void()> operation_complete_callback_;
805 };
806
807 // Wraps a CreateSessionDescriptionObserver and an OperationsChain operation
808 // complete callback. When the observer is invoked, the wrapped observer is
809 // invoked followed by invoking the completion callback.
810 class CreateSessionDescriptionObserverOperationWrapper
811 : public CreateSessionDescriptionObserver {
812 public:
CreateSessionDescriptionObserverOperationWrapper(rtc::scoped_refptr<CreateSessionDescriptionObserver> observer,std::function<void ()> operation_complete_callback)813 CreateSessionDescriptionObserverOperationWrapper(
814 rtc::scoped_refptr<CreateSessionDescriptionObserver> observer,
815 std::function<void()> operation_complete_callback)
816 : observer_(std::move(observer)),
817 operation_complete_callback_(std::move(operation_complete_callback)) {
818 RTC_DCHECK(observer_);
819 }
~CreateSessionDescriptionObserverOperationWrapper()820 ~CreateSessionDescriptionObserverOperationWrapper() override {
821 #if RTC_DCHECK_IS_ON
822 RTC_DCHECK(was_called_);
823 #endif
824 }
825
OnSuccess(SessionDescriptionInterface * desc)826 void OnSuccess(SessionDescriptionInterface* desc) override {
827 #if RTC_DCHECK_IS_ON
828 RTC_DCHECK(!was_called_);
829 was_called_ = true;
830 #endif // RTC_DCHECK_IS_ON
831 // Completing the operation before invoking the observer allows the observer
832 // to execute SetLocalDescription() without delay.
833 operation_complete_callback_();
834 observer_->OnSuccess(desc);
835 }
836
OnFailure(RTCError error)837 void OnFailure(RTCError error) override {
838 #if RTC_DCHECK_IS_ON
839 RTC_DCHECK(!was_called_);
840 was_called_ = true;
841 #endif // RTC_DCHECK_IS_ON
842 operation_complete_callback_();
843 observer_->OnFailure(std::move(error));
844 }
845
846 private:
847 #if RTC_DCHECK_IS_ON
848 bool was_called_ = false;
849 #endif // RTC_DCHECK_IS_ON
850 rtc::scoped_refptr<CreateSessionDescriptionObserver> observer_;
851 std::function<void()> operation_complete_callback_;
852 };
853
854 // Wrapper for SetSessionDescriptionObserver that invokes the success or failure
855 // callback in a posted message handled by the peer connection. This introduces
856 // a delay that prevents recursive API calls by the observer, but this also
857 // means that the PeerConnection can be modified before the observer sees the
858 // result of the operation. This is ill-advised for synchronizing states.
859 //
860 // Implements both the SetLocalDescriptionObserverInterface and the
861 // SetRemoteDescriptionObserverInterface.
862 class SdpOfferAnswerHandler::SetSessionDescriptionObserverAdapter
863 : public SetLocalDescriptionObserverInterface,
864 public SetRemoteDescriptionObserverInterface {
865 public:
SetSessionDescriptionObserverAdapter(rtc::WeakPtr<SdpOfferAnswerHandler> handler,rtc::scoped_refptr<SetSessionDescriptionObserver> inner_observer)866 SetSessionDescriptionObserverAdapter(
867 rtc::WeakPtr<SdpOfferAnswerHandler> handler,
868 rtc::scoped_refptr<SetSessionDescriptionObserver> inner_observer)
869 : handler_(std::move(handler)),
870 inner_observer_(std::move(inner_observer)) {}
871
872 // SetLocalDescriptionObserverInterface implementation.
OnSetLocalDescriptionComplete(RTCError error)873 void OnSetLocalDescriptionComplete(RTCError error) override {
874 OnSetDescriptionComplete(std::move(error));
875 }
876 // SetRemoteDescriptionObserverInterface implementation.
OnSetRemoteDescriptionComplete(RTCError error)877 void OnSetRemoteDescriptionComplete(RTCError error) override {
878 OnSetDescriptionComplete(std::move(error));
879 }
880
881 private:
OnSetDescriptionComplete(RTCError error)882 void OnSetDescriptionComplete(RTCError error) {
883 if (!handler_)
884 return;
885 if (error.ok()) {
886 handler_->pc_->message_handler()->PostSetSessionDescriptionSuccess(
887 inner_observer_);
888 } else {
889 handler_->pc_->message_handler()->PostSetSessionDescriptionFailure(
890 inner_observer_, std::move(error));
891 }
892 }
893
894 rtc::WeakPtr<SdpOfferAnswerHandler> handler_;
895 rtc::scoped_refptr<SetSessionDescriptionObserver> inner_observer_;
896 };
897
898 class SdpOfferAnswerHandler::LocalIceCredentialsToReplace {
899 public:
900 // Sets the ICE credentials that need restarting to the ICE credentials of
901 // the current and pending descriptions.
SetIceCredentialsFromLocalDescriptions(const SessionDescriptionInterface * current_local_description,const SessionDescriptionInterface * pending_local_description)902 void SetIceCredentialsFromLocalDescriptions(
903 const SessionDescriptionInterface* current_local_description,
904 const SessionDescriptionInterface* pending_local_description) {
905 ice_credentials_.clear();
906 if (current_local_description) {
907 AppendIceCredentialsFromSessionDescription(*current_local_description);
908 }
909 if (pending_local_description) {
910 AppendIceCredentialsFromSessionDescription(*pending_local_description);
911 }
912 }
913
ClearIceCredentials()914 void ClearIceCredentials() { ice_credentials_.clear(); }
915
916 // Returns true if we have ICE credentials that need restarting.
HasIceCredentials() const917 bool HasIceCredentials() const { return !ice_credentials_.empty(); }
918
919 // Returns true if |local_description| shares no ICE credentials with the
920 // ICE credentials that need restarting.
SatisfiesIceRestart(const SessionDescriptionInterface & local_description) const921 bool SatisfiesIceRestart(
922 const SessionDescriptionInterface& local_description) const {
923 for (const auto& transport_info :
924 local_description.description()->transport_infos()) {
925 if (ice_credentials_.find(std::make_pair(
926 transport_info.description.ice_ufrag,
927 transport_info.description.ice_pwd)) != ice_credentials_.end()) {
928 return false;
929 }
930 }
931 return true;
932 }
933
934 private:
AppendIceCredentialsFromSessionDescription(const SessionDescriptionInterface & desc)935 void AppendIceCredentialsFromSessionDescription(
936 const SessionDescriptionInterface& desc) {
937 for (const auto& transport_info : desc.description()->transport_infos()) {
938 ice_credentials_.insert(
939 std::make_pair(transport_info.description.ice_ufrag,
940 transport_info.description.ice_pwd));
941 }
942 }
943
944 std::set<std::pair<std::string, std::string>> ice_credentials_;
945 };
946
SdpOfferAnswerHandler(PeerConnection * pc)947 SdpOfferAnswerHandler::SdpOfferAnswerHandler(PeerConnection* pc)
948 : pc_(pc),
949 local_streams_(StreamCollection::Create()),
950 remote_streams_(StreamCollection::Create()),
951 operations_chain_(rtc::OperationsChain::Create()),
952 rtcp_cname_(GenerateRtcpCname()),
953 local_ice_credentials_to_replace_(new LocalIceCredentialsToReplace()),
954 weak_ptr_factory_(this) {
955 operations_chain_->SetOnChainEmptyCallback(
956 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr()]() {
957 if (!this_weak_ptr)
958 return;
959 this_weak_ptr->OnOperationsChainEmpty();
960 });
961 }
962
~SdpOfferAnswerHandler()963 SdpOfferAnswerHandler::~SdpOfferAnswerHandler() {}
964
965 // Static
Create(PeerConnection * pc,const PeerConnectionInterface::RTCConfiguration & configuration,PeerConnectionDependencies & dependencies)966 std::unique_ptr<SdpOfferAnswerHandler> SdpOfferAnswerHandler::Create(
967 PeerConnection* pc,
968 const PeerConnectionInterface::RTCConfiguration& configuration,
969 PeerConnectionDependencies& dependencies) {
970 auto handler = absl::WrapUnique(new SdpOfferAnswerHandler(pc));
971 handler->Initialize(configuration, dependencies);
972 return handler;
973 }
974
Initialize(const PeerConnectionInterface::RTCConfiguration & configuration,PeerConnectionDependencies & dependencies)975 void SdpOfferAnswerHandler::Initialize(
976 const PeerConnectionInterface::RTCConfiguration& configuration,
977 PeerConnectionDependencies& dependencies) {
978 RTC_DCHECK_RUN_ON(signaling_thread());
979 video_options_.screencast_min_bitrate_kbps =
980 configuration.screencast_min_bitrate;
981 audio_options_.combined_audio_video_bwe =
982 configuration.combined_audio_video_bwe;
983
984 audio_options_.audio_jitter_buffer_max_packets =
985 configuration.audio_jitter_buffer_max_packets;
986
987 audio_options_.audio_jitter_buffer_fast_accelerate =
988 configuration.audio_jitter_buffer_fast_accelerate;
989
990 audio_options_.audio_jitter_buffer_min_delay_ms =
991 configuration.audio_jitter_buffer_min_delay_ms;
992
993 audio_options_.audio_jitter_buffer_enable_rtx_handling =
994 configuration.audio_jitter_buffer_enable_rtx_handling;
995
996 // Obtain a certificate from RTCConfiguration if any were provided (optional).
997 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
998 if (!configuration.certificates.empty()) {
999 // TODO(hbos,torbjorng): Decide on certificate-selection strategy instead of
1000 // just picking the first one. The decision should be made based on the DTLS
1001 // handshake. The DTLS negotiations need to know about all certificates.
1002 certificate = configuration.certificates[0];
1003 }
1004
1005 webrtc_session_desc_factory_ =
1006 std::make_unique<WebRtcSessionDescriptionFactory>(
1007 signaling_thread(), channel_manager(), this, pc_->session_id(),
1008 pc_->dtls_enabled(), std::move(dependencies.cert_generator),
1009 certificate, &ssrc_generator_,
1010 [this](const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
1011 transport_controller()->SetLocalCertificate(certificate);
1012 });
1013
1014 if (pc_->options()->disable_encryption) {
1015 webrtc_session_desc_factory_->SetSdesPolicy(cricket::SEC_DISABLED);
1016 }
1017
1018 webrtc_session_desc_factory_->set_enable_encrypted_rtp_header_extensions(
1019 pc_->GetCryptoOptions().srtp.enable_encrypted_rtp_header_extensions);
1020 webrtc_session_desc_factory_->set_is_unified_plan(IsUnifiedPlan());
1021
1022 if (dependencies.video_bitrate_allocator_factory) {
1023 video_bitrate_allocator_factory_ =
1024 std::move(dependencies.video_bitrate_allocator_factory);
1025 } else {
1026 video_bitrate_allocator_factory_ =
1027 CreateBuiltinVideoBitrateAllocatorFactory();
1028 }
1029 }
1030
1031 // ==================================================================
1032 // Access to pc_ variables
channel_manager() const1033 cricket::ChannelManager* SdpOfferAnswerHandler::channel_manager() const {
1034 return pc_->channel_manager();
1035 }
transceivers()1036 TransceiverList* SdpOfferAnswerHandler::transceivers() {
1037 if (!pc_->rtp_manager()) {
1038 return nullptr;
1039 }
1040 return pc_->rtp_manager()->transceivers();
1041 }
transceivers() const1042 const TransceiverList* SdpOfferAnswerHandler::transceivers() const {
1043 if (!pc_->rtp_manager()) {
1044 return nullptr;
1045 }
1046 return pc_->rtp_manager()->transceivers();
1047 }
transport_controller()1048 JsepTransportController* SdpOfferAnswerHandler::transport_controller() {
1049 return pc_->transport_controller();
1050 }
transport_controller() const1051 const JsepTransportController* SdpOfferAnswerHandler::transport_controller()
1052 const {
1053 return pc_->transport_controller();
1054 }
data_channel_controller()1055 DataChannelController* SdpOfferAnswerHandler::data_channel_controller() {
1056 return pc_->data_channel_controller();
1057 }
data_channel_controller() const1058 const DataChannelController* SdpOfferAnswerHandler::data_channel_controller()
1059 const {
1060 return pc_->data_channel_controller();
1061 }
port_allocator()1062 cricket::PortAllocator* SdpOfferAnswerHandler::port_allocator() {
1063 return pc_->port_allocator();
1064 }
port_allocator() const1065 const cricket::PortAllocator* SdpOfferAnswerHandler::port_allocator() const {
1066 return pc_->port_allocator();
1067 }
rtp_manager()1068 RtpTransmissionManager* SdpOfferAnswerHandler::rtp_manager() {
1069 return pc_->rtp_manager();
1070 }
rtp_manager() const1071 const RtpTransmissionManager* SdpOfferAnswerHandler::rtp_manager() const {
1072 return pc_->rtp_manager();
1073 }
1074
1075 // ===================================================================
1076
PrepareForShutdown()1077 void SdpOfferAnswerHandler::PrepareForShutdown() {
1078 RTC_DCHECK_RUN_ON(signaling_thread());
1079 weak_ptr_factory_.InvalidateWeakPtrs();
1080 }
1081
Close()1082 void SdpOfferAnswerHandler::Close() {
1083 ChangeSignalingState(PeerConnectionInterface::kClosed);
1084 }
1085
RestartIce()1086 void SdpOfferAnswerHandler::RestartIce() {
1087 RTC_DCHECK_RUN_ON(signaling_thread());
1088 local_ice_credentials_to_replace_->SetIceCredentialsFromLocalDescriptions(
1089 current_local_description(), pending_local_description());
1090 UpdateNegotiationNeeded();
1091 }
1092
signaling_thread() const1093 rtc::Thread* SdpOfferAnswerHandler::signaling_thread() const {
1094 return pc_->signaling_thread();
1095 }
1096
CreateOffer(CreateSessionDescriptionObserver * observer,const PeerConnectionInterface::RTCOfferAnswerOptions & options)1097 void SdpOfferAnswerHandler::CreateOffer(
1098 CreateSessionDescriptionObserver* observer,
1099 const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
1100 RTC_DCHECK_RUN_ON(signaling_thread());
1101 // Chain this operation. If asynchronous operations are pending on the chain,
1102 // this operation will be queued to be invoked, otherwise the contents of the
1103 // lambda will execute immediately.
1104 operations_chain_->ChainOperation(
1105 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
1106 observer_refptr =
1107 rtc::scoped_refptr<CreateSessionDescriptionObserver>(observer),
1108 options](std::function<void()> operations_chain_callback) {
1109 // Abort early if |this_weak_ptr| is no longer valid.
1110 if (!this_weak_ptr) {
1111 observer_refptr->OnFailure(
1112 RTCError(RTCErrorType::INTERNAL_ERROR,
1113 "CreateOffer failed because the session was shut down"));
1114 operations_chain_callback();
1115 return;
1116 }
1117 // The operation completes asynchronously when the wrapper is invoked.
1118 rtc::scoped_refptr<CreateSessionDescriptionObserverOperationWrapper>
1119 observer_wrapper(new rtc::RefCountedObject<
1120 CreateSessionDescriptionObserverOperationWrapper>(
1121 std::move(observer_refptr),
1122 std::move(operations_chain_callback)));
1123 this_weak_ptr->DoCreateOffer(options, observer_wrapper);
1124 });
1125 }
1126
SetLocalDescription(SetSessionDescriptionObserver * observer,SessionDescriptionInterface * desc_ptr)1127 void SdpOfferAnswerHandler::SetLocalDescription(
1128 SetSessionDescriptionObserver* observer,
1129 SessionDescriptionInterface* desc_ptr) {
1130 RTC_DCHECK_RUN_ON(signaling_thread());
1131 // Chain this operation. If asynchronous operations are pending on the chain,
1132 // this operation will be queued to be invoked, otherwise the contents of the
1133 // lambda will execute immediately.
1134 operations_chain_->ChainOperation(
1135 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
1136 observer_refptr =
1137 rtc::scoped_refptr<SetSessionDescriptionObserver>(observer),
1138 desc = std::unique_ptr<SessionDescriptionInterface>(desc_ptr)](
1139 std::function<void()> operations_chain_callback) mutable {
1140 // Abort early if |this_weak_ptr| is no longer valid.
1141 if (!this_weak_ptr) {
1142 // For consistency with SetSessionDescriptionObserverAdapter whose
1143 // posted messages doesn't get processed when the PC is destroyed, we
1144 // do not inform |observer_refptr| that the operation failed.
1145 operations_chain_callback();
1146 return;
1147 }
1148 // SetSessionDescriptionObserverAdapter takes care of making sure the
1149 // |observer_refptr| is invoked in a posted message.
1150 this_weak_ptr->DoSetLocalDescription(
1151 std::move(desc),
1152 rtc::scoped_refptr<SetLocalDescriptionObserverInterface>(
1153 new rtc::RefCountedObject<SetSessionDescriptionObserverAdapter>(
1154 this_weak_ptr, observer_refptr)));
1155 // For backwards-compatability reasons, we declare the operation as
1156 // completed here (rather than in a post), so that the operation chain
1157 // is not blocked by this operation when the observer is invoked. This
1158 // allows the observer to trigger subsequent offer/answer operations
1159 // synchronously if the operation chain is now empty.
1160 operations_chain_callback();
1161 });
1162 }
1163
SetLocalDescription(std::unique_ptr<SessionDescriptionInterface> desc,rtc::scoped_refptr<SetLocalDescriptionObserverInterface> observer)1164 void SdpOfferAnswerHandler::SetLocalDescription(
1165 std::unique_ptr<SessionDescriptionInterface> desc,
1166 rtc::scoped_refptr<SetLocalDescriptionObserverInterface> observer) {
1167 RTC_DCHECK_RUN_ON(signaling_thread());
1168 // Chain this operation. If asynchronous operations are pending on the chain,
1169 // this operation will be queued to be invoked, otherwise the contents of the
1170 // lambda will execute immediately.
1171 operations_chain_->ChainOperation(
1172 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(), observer,
1173 desc = std::move(desc)](
1174 std::function<void()> operations_chain_callback) mutable {
1175 // Abort early if |this_weak_ptr| is no longer valid.
1176 if (!this_weak_ptr) {
1177 observer->OnSetLocalDescriptionComplete(RTCError(
1178 RTCErrorType::INTERNAL_ERROR,
1179 "SetLocalDescription failed because the session was shut down"));
1180 operations_chain_callback();
1181 return;
1182 }
1183 this_weak_ptr->DoSetLocalDescription(std::move(desc), observer);
1184 // DoSetLocalDescription() is implemented as a synchronous operation.
1185 // The |observer| will already have been informed that it completed, and
1186 // we can mark this operation as complete without any loose ends.
1187 operations_chain_callback();
1188 });
1189 }
1190
SetLocalDescription(SetSessionDescriptionObserver * observer)1191 void SdpOfferAnswerHandler::SetLocalDescription(
1192 SetSessionDescriptionObserver* observer) {
1193 RTC_DCHECK_RUN_ON(signaling_thread());
1194 SetLocalDescription(
1195 new rtc::RefCountedObject<SetSessionDescriptionObserverAdapter>(
1196 weak_ptr_factory_.GetWeakPtr(), observer));
1197 }
1198
SetLocalDescription(rtc::scoped_refptr<SetLocalDescriptionObserverInterface> observer)1199 void SdpOfferAnswerHandler::SetLocalDescription(
1200 rtc::scoped_refptr<SetLocalDescriptionObserverInterface> observer) {
1201 RTC_DCHECK_RUN_ON(signaling_thread());
1202 // The |create_sdp_observer| handles performing DoSetLocalDescription() with
1203 // the resulting description as well as completing the operation.
1204 rtc::scoped_refptr<ImplicitCreateSessionDescriptionObserver>
1205 create_sdp_observer(
1206 new rtc::RefCountedObject<ImplicitCreateSessionDescriptionObserver>(
1207 weak_ptr_factory_.GetWeakPtr(), observer));
1208 // Chain this operation. If asynchronous operations are pending on the chain,
1209 // this operation will be queued to be invoked, otherwise the contents of the
1210 // lambda will execute immediately.
1211 operations_chain_->ChainOperation(
1212 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
1213 create_sdp_observer](std::function<void()> operations_chain_callback) {
1214 // The |create_sdp_observer| is responsible for completing the
1215 // operation.
1216 create_sdp_observer->SetOperationCompleteCallback(
1217 std::move(operations_chain_callback));
1218 // Abort early if |this_weak_ptr| is no longer valid. This triggers the
1219 // same code path as if DoCreateOffer() or DoCreateAnswer() failed.
1220 if (!this_weak_ptr) {
1221 create_sdp_observer->OnFailure(RTCError(
1222 RTCErrorType::INTERNAL_ERROR,
1223 "SetLocalDescription failed because the session was shut down"));
1224 return;
1225 }
1226 switch (this_weak_ptr->signaling_state()) {
1227 case PeerConnectionInterface::kStable:
1228 case PeerConnectionInterface::kHaveLocalOffer:
1229 case PeerConnectionInterface::kHaveRemotePrAnswer:
1230 // TODO(hbos): If [LastCreatedOffer] exists and still represents the
1231 // current state of the system, use that instead of creating another
1232 // offer.
1233 this_weak_ptr->DoCreateOffer(
1234 PeerConnectionInterface::RTCOfferAnswerOptions(),
1235 create_sdp_observer);
1236 break;
1237 case PeerConnectionInterface::kHaveLocalPrAnswer:
1238 case PeerConnectionInterface::kHaveRemoteOffer:
1239 // TODO(hbos): If [LastCreatedAnswer] exists and still represents
1240 // the current state of the system, use that instead of creating
1241 // another answer.
1242 this_weak_ptr->DoCreateAnswer(
1243 PeerConnectionInterface::RTCOfferAnswerOptions(),
1244 create_sdp_observer);
1245 break;
1246 case PeerConnectionInterface::kClosed:
1247 create_sdp_observer->OnFailure(RTCError(
1248 RTCErrorType::INVALID_STATE,
1249 "SetLocalDescription called when PeerConnection is closed."));
1250 break;
1251 }
1252 });
1253 }
1254
ApplyLocalDescription(std::unique_ptr<SessionDescriptionInterface> desc)1255 RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
1256 std::unique_ptr<SessionDescriptionInterface> desc) {
1257 RTC_DCHECK_RUN_ON(signaling_thread());
1258 RTC_DCHECK(desc);
1259
1260 // Update stats here so that we have the most recent stats for tracks and
1261 // streams that might be removed by updating the session description.
1262 pc_->stats()->UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
1263
1264 // Take a reference to the old local description since it's used below to
1265 // compare against the new local description. When setting the new local
1266 // description, grab ownership of the replaced session description in case it
1267 // is the same as |old_local_description|, to keep it alive for the duration
1268 // of the method.
1269 const SessionDescriptionInterface* old_local_description =
1270 local_description();
1271 std::unique_ptr<SessionDescriptionInterface> replaced_local_description;
1272 SdpType type = desc->GetType();
1273 if (type == SdpType::kAnswer) {
1274 replaced_local_description = pending_local_description_
1275 ? std::move(pending_local_description_)
1276 : std::move(current_local_description_);
1277 current_local_description_ = std::move(desc);
1278 pending_local_description_ = nullptr;
1279 current_remote_description_ = std::move(pending_remote_description_);
1280 } else {
1281 replaced_local_description = std::move(pending_local_description_);
1282 pending_local_description_ = std::move(desc);
1283 }
1284 // The session description to apply now must be accessed by
1285 // |local_description()|.
1286 RTC_DCHECK(local_description());
1287
1288 // Report statistics about any use of simulcast.
1289 ReportSimulcastApiVersion(kSimulcastVersionApplyLocalDescription,
1290 *local_description()->description());
1291
1292 if (!is_caller_) {
1293 if (remote_description()) {
1294 // Remote description was applied first, so this PC is the callee.
1295 is_caller_ = false;
1296 } else {
1297 // Local description is applied first, so this PC is the caller.
1298 is_caller_ = true;
1299 }
1300 }
1301
1302 RTCError error = PushdownTransportDescription(cricket::CS_LOCAL, type);
1303 if (!error.ok()) {
1304 return error;
1305 }
1306
1307 if (IsUnifiedPlan()) {
1308 RTCError error = UpdateTransceiversAndDataChannels(
1309 cricket::CS_LOCAL, *local_description(), old_local_description,
1310 remote_description());
1311 if (!error.ok()) {
1312 return error;
1313 }
1314 std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list;
1315 std::vector<rtc::scoped_refptr<MediaStreamInterface>> removed_streams;
1316 for (const auto& transceiver : transceivers()->List()) {
1317 if (transceiver->stopped()) {
1318 continue;
1319 }
1320
1321 // 2.2.7.1.1.(6-9): Set sender and receiver's transport slots.
1322 // Note that code paths that don't set MID won't be able to use
1323 // information about DTLS transports.
1324 if (transceiver->mid()) {
1325 auto dtls_transport = LookupDtlsTransportByMid(
1326 pc_->network_thread(), transport_controller(), *transceiver->mid());
1327 transceiver->internal()->sender_internal()->set_transport(
1328 dtls_transport);
1329 transceiver->internal()->receiver_internal()->set_transport(
1330 dtls_transport);
1331 }
1332
1333 const ContentInfo* content =
1334 FindMediaSectionForTransceiver(transceiver, local_description());
1335 if (!content) {
1336 continue;
1337 }
1338 const MediaContentDescription* media_desc = content->media_description();
1339 // 2.2.7.1.6: If description is of type "answer" or "pranswer", then run
1340 // the following steps:
1341 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
1342 // 2.2.7.1.6.1: If direction is "sendonly" or "inactive", and
1343 // transceiver's [[FiredDirection]] slot is either "sendrecv" or
1344 // "recvonly", process the removal of a remote track for the media
1345 // description, given transceiver, removeList, and muteTracks.
1346 if (!RtpTransceiverDirectionHasRecv(media_desc->direction()) &&
1347 (transceiver->internal()->fired_direction() &&
1348 RtpTransceiverDirectionHasRecv(
1349 *transceiver->internal()->fired_direction()))) {
1350 ProcessRemovalOfRemoteTrack(transceiver, &remove_list,
1351 &removed_streams);
1352 }
1353 // 2.2.7.1.6.2: Set transceiver's [[CurrentDirection]] and
1354 // [[FiredDirection]] slots to direction.
1355 transceiver->internal()->set_current_direction(media_desc->direction());
1356 transceiver->internal()->set_fired_direction(media_desc->direction());
1357 }
1358 }
1359 auto observer = pc_->Observer();
1360 for (const auto& transceiver : remove_list) {
1361 observer->OnRemoveTrack(transceiver->receiver());
1362 }
1363 for (const auto& stream : removed_streams) {
1364 observer->OnRemoveStream(stream);
1365 }
1366 } else {
1367 // Media channels will be created only when offer is set. These may use new
1368 // transports just created by PushdownTransportDescription.
1369 if (type == SdpType::kOffer) {
1370 // TODO(bugs.webrtc.org/4676) - Handle CreateChannel failure, as new local
1371 // description is applied. Restore back to old description.
1372 RTCError error = CreateChannels(*local_description()->description());
1373 if (!error.ok()) {
1374 return error;
1375 }
1376 }
1377 // Remove unused channels if MediaContentDescription is rejected.
1378 RemoveUnusedChannels(local_description()->description());
1379 }
1380
1381 error = UpdateSessionState(type, cricket::CS_LOCAL,
1382 local_description()->description());
1383 if (!error.ok()) {
1384 return error;
1385 }
1386
1387 if (remote_description()) {
1388 // Now that we have a local description, we can push down remote candidates.
1389 UseCandidatesInSessionDescription(remote_description());
1390 }
1391
1392 pending_ice_restarts_.clear();
1393 if (session_error() != SessionError::kNone) {
1394 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, GetSessionErrorMsg());
1395 }
1396
1397 // If setting the description decided our SSL role, allocate any necessary
1398 // SCTP sids.
1399 rtc::SSLRole role;
1400 if (IsSctpLike(pc_->data_channel_type()) && pc_->GetSctpSslRole(&role)) {
1401 data_channel_controller()->AllocateSctpSids(role);
1402 }
1403
1404 if (IsUnifiedPlan()) {
1405 for (const auto& transceiver : transceivers()->List()) {
1406 if (transceiver->stopped()) {
1407 continue;
1408 }
1409 const ContentInfo* content =
1410 FindMediaSectionForTransceiver(transceiver, local_description());
1411 if (!content) {
1412 continue;
1413 }
1414 cricket::ChannelInterface* channel = transceiver->internal()->channel();
1415 if (content->rejected || !channel || channel->local_streams().empty()) {
1416 // 0 is a special value meaning "this sender has no associated send
1417 // stream". Need to call this so the sender won't attempt to configure
1418 // a no longer existing stream and run into DCHECKs in the lower
1419 // layers.
1420 transceiver->internal()->sender_internal()->SetSsrc(0);
1421 } else {
1422 // Get the StreamParams from the channel which could generate SSRCs.
1423 const std::vector<StreamParams>& streams = channel->local_streams();
1424 transceiver->internal()->sender_internal()->set_stream_ids(
1425 streams[0].stream_ids());
1426 auto encodings =
1427 transceiver->internal()->sender_internal()->init_send_encodings();
1428 transceiver->internal()->sender_internal()->SetSsrc(
1429 streams[0].first_ssrc());
1430 if (!encodings.empty()) {
1431 transceivers()
1432 ->StableState(transceiver)
1433 ->SetInitSendEncodings(encodings);
1434 }
1435 }
1436 }
1437 } else {
1438 // Plan B semantics.
1439
1440 // Update state and SSRC of local MediaStreams and DataChannels based on the
1441 // local session description.
1442 const cricket::ContentInfo* audio_content =
1443 GetFirstAudioContent(local_description()->description());
1444 if (audio_content) {
1445 if (audio_content->rejected) {
1446 RemoveSenders(cricket::MEDIA_TYPE_AUDIO);
1447 } else {
1448 const cricket::AudioContentDescription* audio_desc =
1449 audio_content->media_description()->as_audio();
1450 UpdateLocalSenders(audio_desc->streams(), audio_desc->type());
1451 }
1452 }
1453
1454 const cricket::ContentInfo* video_content =
1455 GetFirstVideoContent(local_description()->description());
1456 if (video_content) {
1457 if (video_content->rejected) {
1458 RemoveSenders(cricket::MEDIA_TYPE_VIDEO);
1459 } else {
1460 const cricket::VideoContentDescription* video_desc =
1461 video_content->media_description()->as_video();
1462 UpdateLocalSenders(video_desc->streams(), video_desc->type());
1463 }
1464 }
1465 }
1466
1467 const cricket::ContentInfo* data_content =
1468 GetFirstDataContent(local_description()->description());
1469 if (data_content) {
1470 const cricket::RtpDataContentDescription* rtp_data_desc =
1471 data_content->media_description()->as_rtp_data();
1472 // rtp_data_desc will be null if this is an SCTP description.
1473 if (rtp_data_desc) {
1474 data_channel_controller()->UpdateLocalRtpDataChannels(
1475 rtp_data_desc->streams());
1476 }
1477 }
1478
1479 if (type == SdpType::kAnswer &&
1480 local_ice_credentials_to_replace_->SatisfiesIceRestart(
1481 *current_local_description_)) {
1482 local_ice_credentials_to_replace_->ClearIceCredentials();
1483 }
1484
1485 return RTCError::OK();
1486 }
1487
SetRemoteDescription(SetSessionDescriptionObserver * observer,SessionDescriptionInterface * desc_ptr)1488 void SdpOfferAnswerHandler::SetRemoteDescription(
1489 SetSessionDescriptionObserver* observer,
1490 SessionDescriptionInterface* desc_ptr) {
1491 RTC_DCHECK_RUN_ON(signaling_thread());
1492 // Chain this operation. If asynchronous operations are pending on the chain,
1493 // this operation will be queued to be invoked, otherwise the contents of the
1494 // lambda will execute immediately.
1495 operations_chain_->ChainOperation(
1496 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
1497 observer_refptr =
1498 rtc::scoped_refptr<SetSessionDescriptionObserver>(observer),
1499 desc = std::unique_ptr<SessionDescriptionInterface>(desc_ptr)](
1500 std::function<void()> operations_chain_callback) mutable {
1501 // Abort early if |this_weak_ptr| is no longer valid.
1502 if (!this_weak_ptr) {
1503 // For consistency with SetSessionDescriptionObserverAdapter whose
1504 // posted messages doesn't get processed when the PC is destroyed, we
1505 // do not inform |observer_refptr| that the operation failed.
1506 operations_chain_callback();
1507 return;
1508 }
1509 // SetSessionDescriptionObserverAdapter takes care of making sure the
1510 // |observer_refptr| is invoked in a posted message.
1511 this_weak_ptr->DoSetRemoteDescription(
1512 std::move(desc),
1513 rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>(
1514 new rtc::RefCountedObject<SetSessionDescriptionObserverAdapter>(
1515 this_weak_ptr, observer_refptr)));
1516 // For backwards-compatability reasons, we declare the operation as
1517 // completed here (rather than in a post), so that the operation chain
1518 // is not blocked by this operation when the observer is invoked. This
1519 // allows the observer to trigger subsequent offer/answer operations
1520 // synchronously if the operation chain is now empty.
1521 operations_chain_callback();
1522 });
1523 }
1524
SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc,rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer)1525 void SdpOfferAnswerHandler::SetRemoteDescription(
1526 std::unique_ptr<SessionDescriptionInterface> desc,
1527 rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer) {
1528 RTC_DCHECK_RUN_ON(signaling_thread());
1529 // Chain this operation. If asynchronous operations are pending on the chain,
1530 // this operation will be queued to be invoked, otherwise the contents of the
1531 // lambda will execute immediately.
1532 operations_chain_->ChainOperation(
1533 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(), observer,
1534 desc = std::move(desc)](
1535 std::function<void()> operations_chain_callback) mutable {
1536 // Abort early if |this_weak_ptr| is no longer valid.
1537 if (!this_weak_ptr) {
1538 observer->OnSetRemoteDescriptionComplete(RTCError(
1539 RTCErrorType::INTERNAL_ERROR,
1540 "SetRemoteDescription failed because the session was shut down"));
1541 operations_chain_callback();
1542 return;
1543 }
1544 this_weak_ptr->DoSetRemoteDescription(std::move(desc),
1545 std::move(observer));
1546 // DoSetRemoteDescription() is implemented as a synchronous operation.
1547 // The |observer| will already have been informed that it completed, and
1548 // we can mark this operation as complete without any loose ends.
1549 operations_chain_callback();
1550 });
1551 }
1552
ApplyRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc)1553 RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
1554 std::unique_ptr<SessionDescriptionInterface> desc) {
1555 RTC_DCHECK_RUN_ON(signaling_thread());
1556 RTC_DCHECK(desc);
1557
1558 // Update stats here so that we have the most recent stats for tracks and
1559 // streams that might be removed by updating the session description.
1560 pc_->stats()->UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
1561
1562 // Take a reference to the old remote description since it's used below to
1563 // compare against the new remote description. When setting the new remote
1564 // description, grab ownership of the replaced session description in case it
1565 // is the same as |old_remote_description|, to keep it alive for the duration
1566 // of the method.
1567 const SessionDescriptionInterface* old_remote_description =
1568 remote_description();
1569 std::unique_ptr<SessionDescriptionInterface> replaced_remote_description;
1570 SdpType type = desc->GetType();
1571 if (type == SdpType::kAnswer) {
1572 replaced_remote_description = pending_remote_description_
1573 ? std::move(pending_remote_description_)
1574 : std::move(current_remote_description_);
1575 current_remote_description_ = std::move(desc);
1576 pending_remote_description_ = nullptr;
1577 current_local_description_ = std::move(pending_local_description_);
1578 } else {
1579 replaced_remote_description = std::move(pending_remote_description_);
1580 pending_remote_description_ = std::move(desc);
1581 }
1582 // The session description to apply now must be accessed by
1583 // |remote_description()|.
1584 RTC_DCHECK(remote_description());
1585
1586 // Report statistics about any use of simulcast.
1587 ReportSimulcastApiVersion(kSimulcastVersionApplyRemoteDescription,
1588 *remote_description()->description());
1589
1590 RTCError error = PushdownTransportDescription(cricket::CS_REMOTE, type);
1591 if (!error.ok()) {
1592 return error;
1593 }
1594 // Transport and Media channels will be created only when offer is set.
1595 if (IsUnifiedPlan()) {
1596 RTCError error = UpdateTransceiversAndDataChannels(
1597 cricket::CS_REMOTE, *remote_description(), local_description(),
1598 old_remote_description);
1599 if (!error.ok()) {
1600 return error;
1601 }
1602 } else {
1603 // Media channels will be created only when offer is set. These may use new
1604 // transports just created by PushdownTransportDescription.
1605 if (type == SdpType::kOffer) {
1606 // TODO(mallinath) - Handle CreateChannel failure, as new local
1607 // description is applied. Restore back to old description.
1608 RTCError error = CreateChannels(*remote_description()->description());
1609 if (!error.ok()) {
1610 return error;
1611 }
1612 }
1613 // Remove unused channels if MediaContentDescription is rejected.
1614 RemoveUnusedChannels(remote_description()->description());
1615 }
1616
1617 // NOTE: Candidates allocation will be initiated only when
1618 // SetLocalDescription is called.
1619 error = UpdateSessionState(type, cricket::CS_REMOTE,
1620 remote_description()->description());
1621 if (!error.ok()) {
1622 return error;
1623 }
1624
1625 if (local_description() &&
1626 !UseCandidatesInSessionDescription(remote_description())) {
1627 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, kInvalidCandidates);
1628 }
1629
1630 if (old_remote_description) {
1631 for (const cricket::ContentInfo& content :
1632 old_remote_description->description()->contents()) {
1633 // Check if this new SessionDescription contains new ICE ufrag and
1634 // password that indicates the remote peer requests an ICE restart.
1635 // TODO(deadbeef): When we start storing both the current and pending
1636 // remote description, this should reset pending_ice_restarts and compare
1637 // against the current description.
1638 if (CheckForRemoteIceRestart(old_remote_description, remote_description(),
1639 content.name)) {
1640 if (type == SdpType::kOffer) {
1641 pending_ice_restarts_.insert(content.name);
1642 }
1643 } else {
1644 // We retain all received candidates only if ICE is not restarted.
1645 // When ICE is restarted, all previous candidates belong to an old
1646 // generation and should not be kept.
1647 // TODO(deadbeef): This goes against the W3C spec which says the remote
1648 // description should only contain candidates from the last set remote
1649 // description plus any candidates added since then. We should remove
1650 // this once we're sure it won't break anything.
1651 WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
1652 old_remote_description, content.name, mutable_remote_description());
1653 }
1654 }
1655 }
1656
1657 if (session_error() != SessionError::kNone) {
1658 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, GetSessionErrorMsg());
1659 }
1660
1661 // Set the the ICE connection state to connecting since the connection may
1662 // become writable with peer reflexive candidates before any remote candidate
1663 // is signaled.
1664 // TODO(pthatcher): This is a short-term solution for crbug/446908. A real fix
1665 // is to have a new signal the indicates a change in checking state from the
1666 // transport and expose a new checking() member from transport that can be
1667 // read to determine the current checking state. The existing SignalConnecting
1668 // actually means "gathering candidates", so cannot be be used here.
1669 if (remote_description()->GetType() != SdpType::kOffer &&
1670 remote_description()->number_of_mediasections() > 0u &&
1671 pc_->ice_connection_state() ==
1672 PeerConnectionInterface::kIceConnectionNew) {
1673 pc_->SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
1674 }
1675
1676 // If setting the description decided our SSL role, allocate any necessary
1677 // SCTP sids.
1678 rtc::SSLRole role;
1679 if (IsSctpLike(pc_->data_channel_type()) && pc_->GetSctpSslRole(&role)) {
1680 data_channel_controller()->AllocateSctpSids(role);
1681 }
1682
1683 if (IsUnifiedPlan()) {
1684 std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
1685 now_receiving_transceivers;
1686 std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list;
1687 std::vector<rtc::scoped_refptr<MediaStreamInterface>> added_streams;
1688 std::vector<rtc::scoped_refptr<MediaStreamInterface>> removed_streams;
1689 for (const auto& transceiver : transceivers()->List()) {
1690 const ContentInfo* content =
1691 FindMediaSectionForTransceiver(transceiver, remote_description());
1692 if (!content) {
1693 continue;
1694 }
1695 const MediaContentDescription* media_desc = content->media_description();
1696 RtpTransceiverDirection local_direction =
1697 RtpTransceiverDirectionReversed(media_desc->direction());
1698 // Roughly the same as steps 2.2.8.6 of section 4.4.1.6 "Set the
1699 // RTCSessionDescription: Set the associated remote streams given
1700 // transceiver.[[Receiver]], msids, addList, and removeList".
1701 // https://w3c.github.io/webrtc-pc/#set-the-rtcsessiondescription
1702 if (RtpTransceiverDirectionHasRecv(local_direction)) {
1703 std::vector<std::string> stream_ids;
1704 if (!media_desc->streams().empty()) {
1705 // The remote description has signaled the stream IDs.
1706 stream_ids = media_desc->streams()[0].stream_ids();
1707 }
1708 transceivers()
1709 ->StableState(transceiver)
1710 ->SetRemoteStreamIdsIfUnset(transceiver->receiver()->stream_ids());
1711
1712 RTC_LOG(LS_INFO) << "Processing the MSIDs for MID=" << content->name
1713 << " (" << GetStreamIdsString(stream_ids) << ").";
1714 SetAssociatedRemoteStreams(transceiver->internal()->receiver_internal(),
1715 stream_ids, &added_streams,
1716 &removed_streams);
1717 // From the WebRTC specification, steps 2.2.8.5/6 of section 4.4.1.6
1718 // "Set the RTCSessionDescription: If direction is sendrecv or recvonly,
1719 // and transceiver's current direction is neither sendrecv nor recvonly,
1720 // process the addition of a remote track for the media description.
1721 if (!transceiver->fired_direction() ||
1722 !RtpTransceiverDirectionHasRecv(*transceiver->fired_direction())) {
1723 RTC_LOG(LS_INFO)
1724 << "Processing the addition of a remote track for MID="
1725 << content->name << ".";
1726 now_receiving_transceivers.push_back(transceiver);
1727 }
1728 }
1729 // 2.2.8.1.9: If direction is "sendonly" or "inactive", and transceiver's
1730 // [[FiredDirection]] slot is either "sendrecv" or "recvonly", process the
1731 // removal of a remote track for the media description, given transceiver,
1732 // removeList, and muteTracks.
1733 if (!RtpTransceiverDirectionHasRecv(local_direction) &&
1734 (transceiver->fired_direction() &&
1735 RtpTransceiverDirectionHasRecv(*transceiver->fired_direction()))) {
1736 ProcessRemovalOfRemoteTrack(transceiver, &remove_list,
1737 &removed_streams);
1738 }
1739 // 2.2.8.1.10: Set transceiver's [[FiredDirection]] slot to direction.
1740 transceiver->internal()->set_fired_direction(local_direction);
1741 // 2.2.8.1.11: If description is of type "answer" or "pranswer", then run
1742 // the following steps:
1743 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
1744 // 2.2.8.1.11.1: Set transceiver's [[CurrentDirection]] slot to
1745 // direction.
1746 transceiver->internal()->set_current_direction(local_direction);
1747 // 2.2.8.1.11.[3-6]: Set the transport internal slots.
1748 if (transceiver->mid()) {
1749 auto dtls_transport = LookupDtlsTransportByMid(pc_->network_thread(),
1750 transport_controller(),
1751 *transceiver->mid());
1752 transceiver->internal()->sender_internal()->set_transport(
1753 dtls_transport);
1754 transceiver->internal()->receiver_internal()->set_transport(
1755 dtls_transport);
1756 }
1757 }
1758 // 2.2.8.1.12: If the media description is rejected, and transceiver is
1759 // not already stopped, stop the RTCRtpTransceiver transceiver.
1760 if (content->rejected && !transceiver->stopped()) {
1761 RTC_LOG(LS_INFO) << "Stopping transceiver for MID=" << content->name
1762 << " since the media section was rejected.";
1763 transceiver->internal()->StopTransceiverProcedure();
1764 }
1765 if (!content->rejected &&
1766 RtpTransceiverDirectionHasRecv(local_direction)) {
1767 if (!media_desc->streams().empty() &&
1768 media_desc->streams()[0].has_ssrcs()) {
1769 uint32_t ssrc = media_desc->streams()[0].first_ssrc();
1770 transceiver->internal()->receiver_internal()->SetupMediaChannel(ssrc);
1771 } else {
1772 transceiver->internal()
1773 ->receiver_internal()
1774 ->SetupUnsignaledMediaChannel();
1775 }
1776 }
1777 }
1778 // Once all processing has finished, fire off callbacks.
1779 auto observer = pc_->Observer();
1780 for (const auto& transceiver : now_receiving_transceivers) {
1781 pc_->stats()->AddTrack(transceiver->receiver()->track());
1782 observer->OnTrack(transceiver);
1783 observer->OnAddTrack(transceiver->receiver(),
1784 transceiver->receiver()->streams());
1785 }
1786 for (const auto& stream : added_streams) {
1787 observer->OnAddStream(stream);
1788 }
1789 for (const auto& transceiver : remove_list) {
1790 observer->OnRemoveTrack(transceiver->receiver());
1791 }
1792 for (const auto& stream : removed_streams) {
1793 observer->OnRemoveStream(stream);
1794 }
1795 }
1796
1797 const cricket::ContentInfo* audio_content =
1798 GetFirstAudioContent(remote_description()->description());
1799 const cricket::ContentInfo* video_content =
1800 GetFirstVideoContent(remote_description()->description());
1801 const cricket::AudioContentDescription* audio_desc =
1802 GetFirstAudioContentDescription(remote_description()->description());
1803 const cricket::VideoContentDescription* video_desc =
1804 GetFirstVideoContentDescription(remote_description()->description());
1805 const cricket::RtpDataContentDescription* rtp_data_desc =
1806 GetFirstRtpDataContentDescription(remote_description()->description());
1807
1808 // Check if the descriptions include streams, just in case the peer supports
1809 // MSID, but doesn't indicate so with "a=msid-semantic".
1810 if (remote_description()->description()->msid_supported() ||
1811 (audio_desc && !audio_desc->streams().empty()) ||
1812 (video_desc && !video_desc->streams().empty())) {
1813 remote_peer_supports_msid_ = true;
1814 }
1815
1816 // We wait to signal new streams until we finish processing the description,
1817 // since only at that point will new streams have all their tracks.
1818 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1819
1820 if (!IsUnifiedPlan()) {
1821 // TODO(steveanton): When removing RTP senders/receivers in response to a
1822 // rejected media section, there is some cleanup logic that expects the
1823 // voice/ video channel to still be set. But in this method the voice/video
1824 // channel would have been destroyed by the SetRemoteDescription caller
1825 // above so the cleanup that relies on them fails to run. The RemoveSenders
1826 // calls should be moved to right before the DestroyChannel calls to fix
1827 // this.
1828
1829 // Find all audio rtp streams and create corresponding remote AudioTracks
1830 // and MediaStreams.
1831 if (audio_content) {
1832 if (audio_content->rejected) {
1833 RemoveSenders(cricket::MEDIA_TYPE_AUDIO);
1834 } else {
1835 bool default_audio_track_needed =
1836 !remote_peer_supports_msid_ &&
1837 RtpTransceiverDirectionHasSend(audio_desc->direction());
1838 UpdateRemoteSendersList(GetActiveStreams(audio_desc),
1839 default_audio_track_needed, audio_desc->type(),
1840 new_streams);
1841 }
1842 }
1843
1844 // Find all video rtp streams and create corresponding remote VideoTracks
1845 // and MediaStreams.
1846 if (video_content) {
1847 if (video_content->rejected) {
1848 RemoveSenders(cricket::MEDIA_TYPE_VIDEO);
1849 } else {
1850 bool default_video_track_needed =
1851 !remote_peer_supports_msid_ &&
1852 RtpTransceiverDirectionHasSend(video_desc->direction());
1853 UpdateRemoteSendersList(GetActiveStreams(video_desc),
1854 default_video_track_needed, video_desc->type(),
1855 new_streams);
1856 }
1857 }
1858
1859 // If this is an RTP data transport, update the DataChannels with the
1860 // information from the remote peer.
1861 if (rtp_data_desc) {
1862 data_channel_controller()->UpdateRemoteRtpDataChannels(
1863 GetActiveStreams(rtp_data_desc));
1864 }
1865
1866 // Iterate new_streams and notify the observer about new MediaStreams.
1867 auto observer = pc_->Observer();
1868 for (size_t i = 0; i < new_streams->count(); ++i) {
1869 MediaStreamInterface* new_stream = new_streams->at(i);
1870 pc_->stats()->AddStream(new_stream);
1871 observer->OnAddStream(
1872 rtc::scoped_refptr<MediaStreamInterface>(new_stream));
1873 }
1874
1875 UpdateEndedRemoteMediaStreams();
1876 }
1877
1878 if (type == SdpType::kAnswer &&
1879 local_ice_credentials_to_replace_->SatisfiesIceRestart(
1880 *current_local_description_)) {
1881 local_ice_credentials_to_replace_->ClearIceCredentials();
1882 }
1883
1884 return RTCError::OK();
1885 }
1886
DoSetLocalDescription(std::unique_ptr<SessionDescriptionInterface> desc,rtc::scoped_refptr<SetLocalDescriptionObserverInterface> observer)1887 void SdpOfferAnswerHandler::DoSetLocalDescription(
1888 std::unique_ptr<SessionDescriptionInterface> desc,
1889 rtc::scoped_refptr<SetLocalDescriptionObserverInterface> observer) {
1890 RTC_DCHECK_RUN_ON(signaling_thread());
1891 TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::DoSetLocalDescription");
1892
1893 if (!observer) {
1894 RTC_LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
1895 return;
1896 }
1897
1898 if (!desc) {
1899 observer->OnSetLocalDescriptionComplete(
1900 RTCError(RTCErrorType::INTERNAL_ERROR, "SessionDescription is NULL."));
1901 return;
1902 }
1903
1904 // If a session error has occurred the PeerConnection is in a possibly
1905 // inconsistent state so fail right away.
1906 if (session_error() != SessionError::kNone) {
1907 std::string error_message = GetSessionErrorMsg();
1908 RTC_LOG(LS_ERROR) << "SetLocalDescription: " << error_message;
1909 observer->OnSetLocalDescriptionComplete(
1910 RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
1911 return;
1912 }
1913
1914 // For SLD we support only explicit rollback.
1915 if (desc->GetType() == SdpType::kRollback) {
1916 if (IsUnifiedPlan()) {
1917 observer->OnSetLocalDescriptionComplete(Rollback(desc->GetType()));
1918 } else {
1919 observer->OnSetLocalDescriptionComplete(
1920 RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
1921 "Rollback not supported in Plan B"));
1922 }
1923 return;
1924 }
1925
1926 RTCError error = ValidateSessionDescription(desc.get(), cricket::CS_LOCAL);
1927 if (!error.ok()) {
1928 std::string error_message = GetSetDescriptionErrorMessage(
1929 cricket::CS_LOCAL, desc->GetType(), error);
1930 RTC_LOG(LS_ERROR) << error_message;
1931 observer->OnSetLocalDescriptionComplete(
1932 RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
1933 return;
1934 }
1935
1936 // Grab the description type before moving ownership to ApplyLocalDescription,
1937 // which may destroy it before returning.
1938 const SdpType type = desc->GetType();
1939
1940 error = ApplyLocalDescription(std::move(desc));
1941 // |desc| may be destroyed at this point.
1942
1943 if (!error.ok()) {
1944 // If ApplyLocalDescription fails, the PeerConnection could be in an
1945 // inconsistent state, so act conservatively here and set the session error
1946 // so that future calls to SetLocalDescription/SetRemoteDescription fail.
1947 SetSessionError(SessionError::kContent, error.message());
1948 std::string error_message =
1949 GetSetDescriptionErrorMessage(cricket::CS_LOCAL, type, error);
1950 RTC_LOG(LS_ERROR) << error_message;
1951 observer->OnSetLocalDescriptionComplete(
1952 RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
1953 return;
1954 }
1955 RTC_DCHECK(local_description());
1956
1957 if (local_description()->GetType() == SdpType::kAnswer) {
1958 RemoveStoppedTransceivers();
1959
1960 // TODO(deadbeef): We already had to hop to the network thread for
1961 // MaybeStartGathering...
1962 pc_->network_thread()->Invoke<void>(
1963 RTC_FROM_HERE, [this] { port_allocator()->DiscardCandidatePool(); });
1964 // Make UMA notes about what was agreed to.
1965 ReportNegotiatedSdpSemantics(*local_description());
1966 }
1967
1968 observer->OnSetLocalDescriptionComplete(RTCError::OK());
1969 pc_->NoteUsageEvent(UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED);
1970
1971 // Check if negotiation is needed. We must do this after informing the
1972 // observer that SetLocalDescription() has completed to ensure negotiation is
1973 // not needed prior to the promise resolving.
1974 if (IsUnifiedPlan()) {
1975 bool was_negotiation_needed = is_negotiation_needed_;
1976 UpdateNegotiationNeeded();
1977 if (signaling_state() == PeerConnectionInterface::kStable &&
1978 was_negotiation_needed && is_negotiation_needed_) {
1979 // Legacy version.
1980 pc_->Observer()->OnRenegotiationNeeded();
1981 // Spec-compliant version; the event may get invalidated before firing.
1982 GenerateNegotiationNeededEvent();
1983 }
1984 }
1985
1986 // MaybeStartGathering needs to be called after informing the observer so that
1987 // we don't signal any candidates before signaling that SetLocalDescription
1988 // completed.
1989 transport_controller()->MaybeStartGathering();
1990 }
1991
DoCreateOffer(const PeerConnectionInterface::RTCOfferAnswerOptions & options,rtc::scoped_refptr<CreateSessionDescriptionObserver> observer)1992 void SdpOfferAnswerHandler::DoCreateOffer(
1993 const PeerConnectionInterface::RTCOfferAnswerOptions& options,
1994 rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {
1995 RTC_DCHECK_RUN_ON(signaling_thread());
1996 TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::DoCreateOffer");
1997
1998 if (!observer) {
1999 RTC_LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
2000 return;
2001 }
2002
2003 if (pc_->IsClosed()) {
2004 std::string error = "CreateOffer called when PeerConnection is closed.";
2005 RTC_LOG(LS_ERROR) << error;
2006 pc_->message_handler()->PostCreateSessionDescriptionFailure(
2007 observer, RTCError(RTCErrorType::INVALID_STATE, std::move(error)));
2008 return;
2009 }
2010
2011 // If a session error has occurred the PeerConnection is in a possibly
2012 // inconsistent state so fail right away.
2013 if (session_error() != SessionError::kNone) {
2014 std::string error_message = GetSessionErrorMsg();
2015 RTC_LOG(LS_ERROR) << "CreateOffer: " << error_message;
2016 pc_->message_handler()->PostCreateSessionDescriptionFailure(
2017 observer,
2018 RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
2019 return;
2020 }
2021
2022 if (!ValidateOfferAnswerOptions(options)) {
2023 std::string error = "CreateOffer called with invalid options.";
2024 RTC_LOG(LS_ERROR) << error;
2025 pc_->message_handler()->PostCreateSessionDescriptionFailure(
2026 observer, RTCError(RTCErrorType::INVALID_PARAMETER, std::move(error)));
2027 return;
2028 }
2029
2030 // Legacy handling for offer_to_receive_audio and offer_to_receive_video.
2031 // Specified in WebRTC section 4.4.3.2 "Legacy configuration extensions".
2032 if (IsUnifiedPlan()) {
2033 RTCError error = HandleLegacyOfferOptions(options);
2034 if (!error.ok()) {
2035 pc_->message_handler()->PostCreateSessionDescriptionFailure(
2036 observer, std::move(error));
2037 return;
2038 }
2039 }
2040
2041 cricket::MediaSessionOptions session_options;
2042 GetOptionsForOffer(options, &session_options);
2043 webrtc_session_desc_factory_->CreateOffer(observer, options, session_options);
2044 }
2045
CreateAnswer(CreateSessionDescriptionObserver * observer,const PeerConnectionInterface::RTCOfferAnswerOptions & options)2046 void SdpOfferAnswerHandler::CreateAnswer(
2047 CreateSessionDescriptionObserver* observer,
2048 const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
2049 RTC_DCHECK_RUN_ON(signaling_thread());
2050 // Chain this operation. If asynchronous operations are pending on the chain,
2051 // this operation will be queued to be invoked, otherwise the contents of the
2052 // lambda will execute immediately.
2053 operations_chain_->ChainOperation(
2054 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
2055 observer_refptr =
2056 rtc::scoped_refptr<CreateSessionDescriptionObserver>(observer),
2057 options](std::function<void()> operations_chain_callback) {
2058 // Abort early if |this_weak_ptr| is no longer valid.
2059 if (!this_weak_ptr) {
2060 observer_refptr->OnFailure(RTCError(
2061 RTCErrorType::INTERNAL_ERROR,
2062 "CreateAnswer failed because the session was shut down"));
2063 operations_chain_callback();
2064 return;
2065 }
2066 // The operation completes asynchronously when the wrapper is invoked.
2067 rtc::scoped_refptr<CreateSessionDescriptionObserverOperationWrapper>
2068 observer_wrapper(new rtc::RefCountedObject<
2069 CreateSessionDescriptionObserverOperationWrapper>(
2070 std::move(observer_refptr),
2071 std::move(operations_chain_callback)));
2072 this_weak_ptr->DoCreateAnswer(options, observer_wrapper);
2073 });
2074 }
2075
DoCreateAnswer(const PeerConnectionInterface::RTCOfferAnswerOptions & options,rtc::scoped_refptr<CreateSessionDescriptionObserver> observer)2076 void SdpOfferAnswerHandler::DoCreateAnswer(
2077 const PeerConnectionInterface::RTCOfferAnswerOptions& options,
2078 rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {
2079 RTC_DCHECK_RUN_ON(signaling_thread());
2080 TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::DoCreateAnswer");
2081 if (!observer) {
2082 RTC_LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
2083 return;
2084 }
2085
2086 // If a session error has occurred the PeerConnection is in a possibly
2087 // inconsistent state so fail right away.
2088 if (session_error() != SessionError::kNone) {
2089 std::string error_message = GetSessionErrorMsg();
2090 RTC_LOG(LS_ERROR) << "CreateAnswer: " << error_message;
2091 pc_->message_handler()->PostCreateSessionDescriptionFailure(
2092 observer,
2093 RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
2094 return;
2095 }
2096
2097 if (!(signaling_state_ == PeerConnectionInterface::kHaveRemoteOffer ||
2098 signaling_state_ == PeerConnectionInterface::kHaveLocalPrAnswer)) {
2099 std::string error =
2100 "PeerConnection cannot create an answer in a state other than "
2101 "have-remote-offer or have-local-pranswer.";
2102 RTC_LOG(LS_ERROR) << error;
2103 pc_->message_handler()->PostCreateSessionDescriptionFailure(
2104 observer, RTCError(RTCErrorType::INVALID_STATE, std::move(error)));
2105 return;
2106 }
2107
2108 // The remote description should be set if we're in the right state.
2109 RTC_DCHECK(remote_description());
2110
2111 if (IsUnifiedPlan()) {
2112 if (options.offer_to_receive_audio !=
2113 PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
2114 RTC_LOG(LS_WARNING) << "CreateAnswer: offer_to_receive_audio is not "
2115 "supported with Unified Plan semantics. Use the "
2116 "RtpTransceiver API instead.";
2117 }
2118 if (options.offer_to_receive_video !=
2119 PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
2120 RTC_LOG(LS_WARNING) << "CreateAnswer: offer_to_receive_video is not "
2121 "supported with Unified Plan semantics. Use the "
2122 "RtpTransceiver API instead.";
2123 }
2124 }
2125
2126 cricket::MediaSessionOptions session_options;
2127 GetOptionsForAnswer(options, &session_options);
2128 webrtc_session_desc_factory_->CreateAnswer(observer, session_options);
2129 }
2130
DoSetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc,rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer)2131 void SdpOfferAnswerHandler::DoSetRemoteDescription(
2132 std::unique_ptr<SessionDescriptionInterface> desc,
2133 rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer) {
2134 RTC_DCHECK_RUN_ON(signaling_thread());
2135 TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::DoSetRemoteDescription");
2136
2137 if (!observer) {
2138 RTC_LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
2139 return;
2140 }
2141
2142 if (!desc) {
2143 observer->OnSetRemoteDescriptionComplete(RTCError(
2144 RTCErrorType::INVALID_PARAMETER, "SessionDescription is NULL."));
2145 return;
2146 }
2147
2148 // If a session error has occurred the PeerConnection is in a possibly
2149 // inconsistent state so fail right away.
2150 if (session_error() != SessionError::kNone) {
2151 std::string error_message = GetSessionErrorMsg();
2152 RTC_LOG(LS_ERROR) << "SetRemoteDescription: " << error_message;
2153 observer->OnSetRemoteDescriptionComplete(
2154 RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
2155 return;
2156 }
2157 if (IsUnifiedPlan()) {
2158 if (pc_->configuration()->enable_implicit_rollback) {
2159 if (desc->GetType() == SdpType::kOffer &&
2160 signaling_state() == PeerConnectionInterface::kHaveLocalOffer) {
2161 Rollback(desc->GetType());
2162 }
2163 }
2164 // Explicit rollback.
2165 if (desc->GetType() == SdpType::kRollback) {
2166 observer->OnSetRemoteDescriptionComplete(Rollback(desc->GetType()));
2167 return;
2168 }
2169 } else if (desc->GetType() == SdpType::kRollback) {
2170 observer->OnSetRemoteDescriptionComplete(
2171 RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
2172 "Rollback not supported in Plan B"));
2173 return;
2174 }
2175 if (desc->GetType() == SdpType::kOffer ||
2176 desc->GetType() == SdpType::kAnswer) {
2177 // Report to UMA the format of the received offer or answer.
2178 pc_->ReportSdpFormatReceived(*desc);
2179 pc_->ReportSdpBundleUsage(*desc);
2180 }
2181
2182 // Handle remote descriptions missing a=mid lines for interop with legacy end
2183 // points.
2184 FillInMissingRemoteMids(desc->description());
2185
2186 RTCError error = ValidateSessionDescription(desc.get(), cricket::CS_REMOTE);
2187 if (!error.ok()) {
2188 std::string error_message = GetSetDescriptionErrorMessage(
2189 cricket::CS_REMOTE, desc->GetType(), error);
2190 RTC_LOG(LS_ERROR) << error_message;
2191 observer->OnSetRemoteDescriptionComplete(
2192 RTCError(error.type(), std::move(error_message)));
2193 return;
2194 }
2195
2196 // Grab the description type before moving ownership to
2197 // ApplyRemoteDescription, which may destroy it before returning.
2198 const SdpType type = desc->GetType();
2199
2200 error = ApplyRemoteDescription(std::move(desc));
2201 // |desc| may be destroyed at this point.
2202
2203 if (!error.ok()) {
2204 // If ApplyRemoteDescription fails, the PeerConnection could be in an
2205 // inconsistent state, so act conservatively here and set the session error
2206 // so that future calls to SetLocalDescription/SetRemoteDescription fail.
2207 SetSessionError(SessionError::kContent, error.message());
2208 std::string error_message =
2209 GetSetDescriptionErrorMessage(cricket::CS_REMOTE, type, error);
2210 RTC_LOG(LS_ERROR) << error_message;
2211 observer->OnSetRemoteDescriptionComplete(
2212 RTCError(error.type(), std::move(error_message)));
2213 return;
2214 }
2215 RTC_DCHECK(remote_description());
2216
2217 if (type == SdpType::kAnswer) {
2218 RemoveStoppedTransceivers();
2219 // TODO(deadbeef): We already had to hop to the network thread for
2220 // MaybeStartGathering...
2221 pc_->network_thread()->Invoke<void>(
2222 RTC_FROM_HERE, [this] { port_allocator()->DiscardCandidatePool(); });
2223 // Make UMA notes about what was agreed to.
2224 ReportNegotiatedSdpSemantics(*remote_description());
2225 }
2226
2227 observer->OnSetRemoteDescriptionComplete(RTCError::OK());
2228 pc_->NoteUsageEvent(UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED);
2229
2230 // Check if negotiation is needed. We must do this after informing the
2231 // observer that SetRemoteDescription() has completed to ensure negotiation is
2232 // not needed prior to the promise resolving.
2233 if (IsUnifiedPlan()) {
2234 bool was_negotiation_needed = is_negotiation_needed_;
2235 UpdateNegotiationNeeded();
2236 if (signaling_state() == PeerConnectionInterface::kStable &&
2237 was_negotiation_needed && is_negotiation_needed_) {
2238 // Legacy version.
2239 pc_->Observer()->OnRenegotiationNeeded();
2240 // Spec-compliant version; the event may get invalidated before firing.
2241 GenerateNegotiationNeededEvent();
2242 }
2243 }
2244 }
2245
SetAssociatedRemoteStreams(rtc::scoped_refptr<RtpReceiverInternal> receiver,const std::vector<std::string> & stream_ids,std::vector<rtc::scoped_refptr<MediaStreamInterface>> * added_streams,std::vector<rtc::scoped_refptr<MediaStreamInterface>> * removed_streams)2246 void SdpOfferAnswerHandler::SetAssociatedRemoteStreams(
2247 rtc::scoped_refptr<RtpReceiverInternal> receiver,
2248 const std::vector<std::string>& stream_ids,
2249 std::vector<rtc::scoped_refptr<MediaStreamInterface>>* added_streams,
2250 std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
2251 RTC_DCHECK_RUN_ON(signaling_thread());
2252 std::vector<rtc::scoped_refptr<MediaStreamInterface>> media_streams;
2253 for (const std::string& stream_id : stream_ids) {
2254 rtc::scoped_refptr<MediaStreamInterface> stream =
2255 remote_streams_->find(stream_id);
2256 if (!stream) {
2257 stream = MediaStreamProxy::Create(rtc::Thread::Current(),
2258 MediaStream::Create(stream_id));
2259 remote_streams_->AddStream(stream);
2260 added_streams->push_back(stream);
2261 }
2262 media_streams.push_back(stream);
2263 }
2264 // Special case: "a=msid" missing, use random stream ID.
2265 if (media_streams.empty() &&
2266 !(remote_description()->description()->msid_signaling() &
2267 cricket::kMsidSignalingMediaSection)) {
2268 if (!missing_msid_default_stream_) {
2269 missing_msid_default_stream_ = MediaStreamProxy::Create(
2270 rtc::Thread::Current(), MediaStream::Create(rtc::CreateRandomUuid()));
2271 added_streams->push_back(missing_msid_default_stream_);
2272 }
2273 media_streams.push_back(missing_msid_default_stream_);
2274 }
2275 std::vector<rtc::scoped_refptr<MediaStreamInterface>> previous_streams =
2276 receiver->streams();
2277 // SetStreams() will add/remove the receiver's track to/from the streams. This
2278 // differs from the spec - the spec uses an "addList" and "removeList" to
2279 // update the stream-track relationships in a later step. We do this earlier,
2280 // changing the order of things, but the end-result is the same.
2281 // TODO(hbos): When we remove remote_streams(), use set_stream_ids()
2282 // instead. https://crbug.com/webrtc/9480
2283 receiver->SetStreams(media_streams);
2284 RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
2285 }
2286
AddIceCandidate(const IceCandidateInterface * ice_candidate)2287 bool SdpOfferAnswerHandler::AddIceCandidate(
2288 const IceCandidateInterface* ice_candidate) {
2289 const AddIceCandidateResult result = AddIceCandidateInternal(ice_candidate);
2290 NoteAddIceCandidateResult(result);
2291 // If the return value is kAddIceCandidateFailNotReady, the candidate has been
2292 // added, although not 'ready', but that's a success.
2293 return result == kAddIceCandidateSuccess ||
2294 result == kAddIceCandidateFailNotReady;
2295 }
2296
AddIceCandidateInternal(const IceCandidateInterface * ice_candidate)2297 AddIceCandidateResult SdpOfferAnswerHandler::AddIceCandidateInternal(
2298 const IceCandidateInterface* ice_candidate) {
2299 RTC_DCHECK_RUN_ON(signaling_thread());
2300 TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::AddIceCandidate");
2301 if (pc_->IsClosed()) {
2302 RTC_LOG(LS_ERROR) << "AddIceCandidate: PeerConnection is closed.";
2303 return kAddIceCandidateFailClosed;
2304 }
2305
2306 if (!remote_description()) {
2307 RTC_LOG(LS_ERROR) << "AddIceCandidate: ICE candidates can't be added "
2308 "without any remote session description.";
2309 return kAddIceCandidateFailNoRemoteDescription;
2310 }
2311
2312 if (!ice_candidate) {
2313 RTC_LOG(LS_ERROR) << "AddIceCandidate: Candidate is null.";
2314 return kAddIceCandidateFailNullCandidate;
2315 }
2316
2317 bool valid = false;
2318 bool ready = ReadyToUseRemoteCandidate(ice_candidate, nullptr, &valid);
2319 if (!valid) {
2320 return kAddIceCandidateFailNotValid;
2321 }
2322
2323 // Add this candidate to the remote session description.
2324 if (!mutable_remote_description()->AddCandidate(ice_candidate)) {
2325 RTC_LOG(LS_ERROR) << "AddIceCandidate: Candidate cannot be used.";
2326 return kAddIceCandidateFailInAddition;
2327 }
2328
2329 if (!ready) {
2330 RTC_LOG(LS_INFO) << "AddIceCandidate: Not ready to use candidate.";
2331 return kAddIceCandidateFailNotReady;
2332 }
2333
2334 if (!UseCandidate(ice_candidate)) {
2335 return kAddIceCandidateFailNotUsable;
2336 }
2337
2338 pc_->NoteUsageEvent(UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED);
2339
2340 return kAddIceCandidateSuccess;
2341 }
2342
AddIceCandidate(std::unique_ptr<IceCandidateInterface> candidate,std::function<void (RTCError)> callback)2343 void SdpOfferAnswerHandler::AddIceCandidate(
2344 std::unique_ptr<IceCandidateInterface> candidate,
2345 std::function<void(RTCError)> callback) {
2346 RTC_DCHECK_RUN_ON(signaling_thread());
2347 // Chain this operation. If asynchronous operations are pending on the chain,
2348 // this operation will be queued to be invoked, otherwise the contents of the
2349 // lambda will execute immediately.
2350 operations_chain_->ChainOperation(
2351 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
2352 candidate = std::move(candidate), callback = std::move(callback)](
2353 std::function<void()> operations_chain_callback) {
2354 auto result =
2355 this_weak_ptr
2356 ? this_weak_ptr->AddIceCandidateInternal(candidate.get())
2357 : kAddIceCandidateFailClosed;
2358 NoteAddIceCandidateResult(result);
2359 operations_chain_callback();
2360 if (result == kAddIceCandidateFailClosed) {
2361 callback(RTCError(
2362 RTCErrorType::INVALID_STATE,
2363 "AddIceCandidate failed because the session was shut down"));
2364 } else if (result != kAddIceCandidateSuccess &&
2365 result != kAddIceCandidateFailNotReady) {
2366 // Fail with an error type and message consistent with Chromium.
2367 // TODO(hbos): Fail with error types according to spec.
2368 callback(RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
2369 "Error processing ICE candidate"));
2370 } else {
2371 callback(RTCError::OK());
2372 }
2373 });
2374 }
2375
RemoveIceCandidates(const std::vector<cricket::Candidate> & candidates)2376 bool SdpOfferAnswerHandler::RemoveIceCandidates(
2377 const std::vector<cricket::Candidate>& candidates) {
2378 TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::RemoveIceCandidates");
2379 RTC_DCHECK_RUN_ON(signaling_thread());
2380 if (pc_->IsClosed()) {
2381 RTC_LOG(LS_ERROR) << "RemoveIceCandidates: PeerConnection is closed.";
2382 return false;
2383 }
2384
2385 if (!remote_description()) {
2386 RTC_LOG(LS_ERROR) << "RemoveIceCandidates: ICE candidates can't be removed "
2387 "without any remote session description.";
2388 return false;
2389 }
2390
2391 if (candidates.empty()) {
2392 RTC_LOG(LS_ERROR) << "RemoveIceCandidates: candidates are empty.";
2393 return false;
2394 }
2395
2396 size_t number_removed =
2397 mutable_remote_description()->RemoveCandidates(candidates);
2398 if (number_removed != candidates.size()) {
2399 RTC_LOG(LS_ERROR)
2400 << "RemoveIceCandidates: Failed to remove candidates. Requested "
2401 << candidates.size() << " but only " << number_removed
2402 << " are removed.";
2403 }
2404
2405 // Remove the candidates from the transport controller.
2406 RTCError error = transport_controller()->RemoveRemoteCandidates(candidates);
2407 if (!error.ok()) {
2408 RTC_LOG(LS_ERROR)
2409 << "RemoveIceCandidates: Error when removing remote candidates: "
2410 << error.message();
2411 }
2412 return true;
2413 }
2414
AddLocalIceCandidate(const JsepIceCandidate * candidate)2415 void SdpOfferAnswerHandler::AddLocalIceCandidate(
2416 const JsepIceCandidate* candidate) {
2417 RTC_DCHECK_RUN_ON(signaling_thread());
2418 if (local_description()) {
2419 mutable_local_description()->AddCandidate(candidate);
2420 }
2421 }
2422
RemoveLocalIceCandidates(const std::vector<cricket::Candidate> & candidates)2423 void SdpOfferAnswerHandler::RemoveLocalIceCandidates(
2424 const std::vector<cricket::Candidate>& candidates) {
2425 RTC_DCHECK_RUN_ON(signaling_thread());
2426 if (local_description()) {
2427 mutable_local_description()->RemoveCandidates(candidates);
2428 }
2429 }
2430
local_description() const2431 const SessionDescriptionInterface* SdpOfferAnswerHandler::local_description()
2432 const {
2433 RTC_DCHECK_RUN_ON(signaling_thread());
2434 return pending_local_description_ ? pending_local_description_.get()
2435 : current_local_description_.get();
2436 }
2437
remote_description() const2438 const SessionDescriptionInterface* SdpOfferAnswerHandler::remote_description()
2439 const {
2440 RTC_DCHECK_RUN_ON(signaling_thread());
2441 return pending_remote_description_ ? pending_remote_description_.get()
2442 : current_remote_description_.get();
2443 }
2444
2445 const SessionDescriptionInterface*
current_local_description() const2446 SdpOfferAnswerHandler::current_local_description() const {
2447 RTC_DCHECK_RUN_ON(signaling_thread());
2448 return current_local_description_.get();
2449 }
2450
2451 const SessionDescriptionInterface*
current_remote_description() const2452 SdpOfferAnswerHandler::current_remote_description() const {
2453 RTC_DCHECK_RUN_ON(signaling_thread());
2454 return current_remote_description_.get();
2455 }
2456
2457 const SessionDescriptionInterface*
pending_local_description() const2458 SdpOfferAnswerHandler::pending_local_description() const {
2459 RTC_DCHECK_RUN_ON(signaling_thread());
2460 return pending_local_description_.get();
2461 }
2462
2463 const SessionDescriptionInterface*
pending_remote_description() const2464 SdpOfferAnswerHandler::pending_remote_description() const {
2465 RTC_DCHECK_RUN_ON(signaling_thread());
2466 return pending_remote_description_.get();
2467 }
2468
signaling_state() const2469 PeerConnectionInterface::SignalingState SdpOfferAnswerHandler::signaling_state()
2470 const {
2471 RTC_DCHECK_RUN_ON(signaling_thread());
2472 return signaling_state_;
2473 }
2474
ChangeSignalingState(PeerConnectionInterface::SignalingState signaling_state)2475 void SdpOfferAnswerHandler::ChangeSignalingState(
2476 PeerConnectionInterface::SignalingState signaling_state) {
2477 RTC_DCHECK_RUN_ON(signaling_thread());
2478 if (signaling_state_ == signaling_state) {
2479 return;
2480 }
2481 RTC_LOG(LS_INFO) << "Session: " << pc_->session_id() << " Old state: "
2482 << GetSignalingStateString(signaling_state_)
2483 << " New state: "
2484 << GetSignalingStateString(signaling_state);
2485 signaling_state_ = signaling_state;
2486 pc_->Observer()->OnSignalingChange(signaling_state_);
2487 }
2488
UpdateSessionState(SdpType type,cricket::ContentSource source,const cricket::SessionDescription * description)2489 RTCError SdpOfferAnswerHandler::UpdateSessionState(
2490 SdpType type,
2491 cricket::ContentSource source,
2492 const cricket::SessionDescription* description) {
2493 RTC_DCHECK_RUN_ON(signaling_thread());
2494
2495 // If there's already a pending error then no state transition should happen.
2496 // But all call-sites should be verifying this before calling us!
2497 RTC_DCHECK(session_error() == SessionError::kNone);
2498
2499 // If this is answer-ish we're ready to let media flow.
2500 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
2501 EnableSending();
2502 }
2503
2504 // Update the signaling state according to the specified state machine (see
2505 // https://w3c.github.io/webrtc-pc/#rtcsignalingstate-enum).
2506 if (type == SdpType::kOffer) {
2507 ChangeSignalingState(source == cricket::CS_LOCAL
2508 ? PeerConnectionInterface::kHaveLocalOffer
2509 : PeerConnectionInterface::kHaveRemoteOffer);
2510 } else if (type == SdpType::kPrAnswer) {
2511 ChangeSignalingState(source == cricket::CS_LOCAL
2512 ? PeerConnectionInterface::kHaveLocalPrAnswer
2513 : PeerConnectionInterface::kHaveRemotePrAnswer);
2514 } else {
2515 RTC_DCHECK(type == SdpType::kAnswer);
2516 ChangeSignalingState(PeerConnectionInterface::kStable);
2517 transceivers()->DiscardStableStates();
2518 have_pending_rtp_data_channel_ = false;
2519 }
2520
2521 // Update internal objects according to the session description's media
2522 // descriptions.
2523 RTCError error = PushdownMediaDescription(type, source);
2524 if (!error.ok()) {
2525 return error;
2526 }
2527
2528 return RTCError::OK();
2529 }
2530
ShouldFireNegotiationNeededEvent(uint32_t event_id)2531 bool SdpOfferAnswerHandler::ShouldFireNegotiationNeededEvent(
2532 uint32_t event_id) {
2533 RTC_DCHECK_RUN_ON(signaling_thread());
2534 // Plan B? Always fire to conform with useless legacy behavior.
2535 if (!IsUnifiedPlan()) {
2536 return true;
2537 }
2538 // The event ID has been invalidated. Either negotiation is no longer needed
2539 // or a newer negotiation needed event has been generated.
2540 if (event_id != negotiation_needed_event_id_) {
2541 return false;
2542 }
2543 // The chain is no longer empty, update negotiation needed when it becomes
2544 // empty. This should generate a newer negotiation needed event, making this
2545 // one obsolete.
2546 if (!operations_chain_->IsEmpty()) {
2547 // Since we just suppressed an event that would have been fired, if
2548 // negotiation is still needed by the time the chain becomes empty again, we
2549 // must make sure to generate another event if negotiation is needed then.
2550 // This happens when |is_negotiation_needed_| goes from false to true, so we
2551 // set it to false until UpdateNegotiationNeeded() is called.
2552 is_negotiation_needed_ = false;
2553 update_negotiation_needed_on_empty_chain_ = true;
2554 return false;
2555 }
2556 // We must not fire if the signaling state is no longer "stable". If
2557 // negotiation is still needed when we return to "stable", a new negotiation
2558 // needed event will be generated, so this one can safely be suppressed.
2559 if (signaling_state_ != PeerConnectionInterface::kStable) {
2560 return false;
2561 }
2562 // All checks have passed - please fire "negotiationneeded" now!
2563 return true;
2564 }
2565
2566 rtc::scoped_refptr<StreamCollectionInterface>
local_streams()2567 SdpOfferAnswerHandler::local_streams() {
2568 RTC_DCHECK_RUN_ON(signaling_thread());
2569 RTC_CHECK(!IsUnifiedPlan()) << "local_streams is not available with Unified "
2570 "Plan SdpSemantics. Please use GetSenders "
2571 "instead.";
2572 return local_streams_;
2573 }
2574
2575 rtc::scoped_refptr<StreamCollectionInterface>
remote_streams()2576 SdpOfferAnswerHandler::remote_streams() {
2577 RTC_DCHECK_RUN_ON(signaling_thread());
2578 RTC_CHECK(!IsUnifiedPlan()) << "remote_streams is not available with Unified "
2579 "Plan SdpSemantics. Please use GetReceivers "
2580 "instead.";
2581 return remote_streams_;
2582 }
2583
AddStream(MediaStreamInterface * local_stream)2584 bool SdpOfferAnswerHandler::AddStream(MediaStreamInterface* local_stream) {
2585 RTC_DCHECK_RUN_ON(signaling_thread());
2586 RTC_CHECK(!IsUnifiedPlan()) << "AddStream is not available with Unified Plan "
2587 "SdpSemantics. Please use AddTrack instead.";
2588 if (pc_->IsClosed()) {
2589 return false;
2590 }
2591 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
2592 return false;
2593 }
2594
2595 local_streams_->AddStream(local_stream);
2596 MediaStreamObserver* observer = new MediaStreamObserver(local_stream);
2597 observer->SignalAudioTrackAdded.connect(
2598 this, &SdpOfferAnswerHandler::OnAudioTrackAdded);
2599 observer->SignalAudioTrackRemoved.connect(
2600 this, &SdpOfferAnswerHandler::OnAudioTrackRemoved);
2601 observer->SignalVideoTrackAdded.connect(
2602 this, &SdpOfferAnswerHandler::OnVideoTrackAdded);
2603 observer->SignalVideoTrackRemoved.connect(
2604 this, &SdpOfferAnswerHandler::OnVideoTrackRemoved);
2605 stream_observers_.push_back(std::unique_ptr<MediaStreamObserver>(observer));
2606
2607 for (const auto& track : local_stream->GetAudioTracks()) {
2608 rtp_manager()->AddAudioTrack(track.get(), local_stream);
2609 }
2610 for (const auto& track : local_stream->GetVideoTracks()) {
2611 rtp_manager()->AddVideoTrack(track.get(), local_stream);
2612 }
2613
2614 pc_->stats()->AddStream(local_stream);
2615 UpdateNegotiationNeeded();
2616 return true;
2617 }
2618
RemoveStream(MediaStreamInterface * local_stream)2619 void SdpOfferAnswerHandler::RemoveStream(MediaStreamInterface* local_stream) {
2620 RTC_DCHECK_RUN_ON(signaling_thread());
2621 RTC_CHECK(!IsUnifiedPlan()) << "RemoveStream is not available with Unified "
2622 "Plan SdpSemantics. Please use RemoveTrack "
2623 "instead.";
2624 TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
2625 if (!pc_->IsClosed()) {
2626 for (const auto& track : local_stream->GetAudioTracks()) {
2627 rtp_manager()->RemoveAudioTrack(track.get(), local_stream);
2628 }
2629 for (const auto& track : local_stream->GetVideoTracks()) {
2630 rtp_manager()->RemoveVideoTrack(track.get(), local_stream);
2631 }
2632 }
2633 local_streams_->RemoveStream(local_stream);
2634 stream_observers_.erase(
2635 std::remove_if(
2636 stream_observers_.begin(), stream_observers_.end(),
2637 [local_stream](const std::unique_ptr<MediaStreamObserver>& observer) {
2638 return observer->stream()->id().compare(local_stream->id()) == 0;
2639 }),
2640 stream_observers_.end());
2641
2642 if (pc_->IsClosed()) {
2643 return;
2644 }
2645 UpdateNegotiationNeeded();
2646 }
2647
OnAudioTrackAdded(AudioTrackInterface * track,MediaStreamInterface * stream)2648 void SdpOfferAnswerHandler::OnAudioTrackAdded(AudioTrackInterface* track,
2649 MediaStreamInterface* stream) {
2650 if (pc_->IsClosed()) {
2651 return;
2652 }
2653 rtp_manager()->AddAudioTrack(track, stream);
2654 UpdateNegotiationNeeded();
2655 }
2656
OnAudioTrackRemoved(AudioTrackInterface * track,MediaStreamInterface * stream)2657 void SdpOfferAnswerHandler::OnAudioTrackRemoved(AudioTrackInterface* track,
2658 MediaStreamInterface* stream) {
2659 if (pc_->IsClosed()) {
2660 return;
2661 }
2662 rtp_manager()->RemoveAudioTrack(track, stream);
2663 UpdateNegotiationNeeded();
2664 }
2665
OnVideoTrackAdded(VideoTrackInterface * track,MediaStreamInterface * stream)2666 void SdpOfferAnswerHandler::OnVideoTrackAdded(VideoTrackInterface* track,
2667 MediaStreamInterface* stream) {
2668 if (pc_->IsClosed()) {
2669 return;
2670 }
2671 rtp_manager()->AddVideoTrack(track, stream);
2672 UpdateNegotiationNeeded();
2673 }
2674
OnVideoTrackRemoved(VideoTrackInterface * track,MediaStreamInterface * stream)2675 void SdpOfferAnswerHandler::OnVideoTrackRemoved(VideoTrackInterface* track,
2676 MediaStreamInterface* stream) {
2677 if (pc_->IsClosed()) {
2678 return;
2679 }
2680 rtp_manager()->RemoveVideoTrack(track, stream);
2681 UpdateNegotiationNeeded();
2682 }
2683
Rollback(SdpType desc_type)2684 RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) {
2685 auto state = signaling_state();
2686 if (state != PeerConnectionInterface::kHaveLocalOffer &&
2687 state != PeerConnectionInterface::kHaveRemoteOffer) {
2688 return RTCError(RTCErrorType::INVALID_STATE,
2689 "Called in wrong signalingState: " +
2690 GetSignalingStateString(signaling_state()));
2691 }
2692 RTC_DCHECK_RUN_ON(signaling_thread());
2693 RTC_DCHECK(IsUnifiedPlan());
2694 std::vector<rtc::scoped_refptr<MediaStreamInterface>> all_added_streams;
2695 std::vector<rtc::scoped_refptr<MediaStreamInterface>> all_removed_streams;
2696 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> removed_receivers;
2697
2698 for (auto&& transceivers_stable_state_pair : transceivers()->StableStates()) {
2699 auto transceiver = transceivers_stable_state_pair.first;
2700 auto state = transceivers_stable_state_pair.second;
2701
2702 if (state.remote_stream_ids()) {
2703 std::vector<rtc::scoped_refptr<MediaStreamInterface>> added_streams;
2704 std::vector<rtc::scoped_refptr<MediaStreamInterface>> removed_streams;
2705 SetAssociatedRemoteStreams(transceiver->internal()->receiver_internal(),
2706 state.remote_stream_ids().value(),
2707 &added_streams, &removed_streams);
2708 all_added_streams.insert(all_added_streams.end(), added_streams.begin(),
2709 added_streams.end());
2710 all_removed_streams.insert(all_removed_streams.end(),
2711 removed_streams.begin(),
2712 removed_streams.end());
2713 if (!state.has_m_section() && !state.newly_created()) {
2714 continue;
2715 }
2716 }
2717
2718 RTC_DCHECK(transceiver->internal()->mid().has_value());
2719 DestroyTransceiverChannel(transceiver);
2720
2721 if (signaling_state() == PeerConnectionInterface::kHaveRemoteOffer &&
2722 transceiver->receiver()) {
2723 removed_receivers.push_back(transceiver->receiver());
2724 }
2725 if (state.newly_created()) {
2726 if (transceiver->internal()->reused_for_addtrack()) {
2727 transceiver->internal()->set_created_by_addtrack(true);
2728 } else {
2729 transceivers()->Remove(transceiver);
2730 }
2731 }
2732 if (state.init_send_encodings()) {
2733 transceiver->internal()->sender_internal()->set_init_send_encodings(
2734 state.init_send_encodings().value());
2735 }
2736 transceiver->internal()->sender_internal()->set_transport(nullptr);
2737 transceiver->internal()->receiver_internal()->set_transport(nullptr);
2738 transceiver->internal()->set_mid(state.mid());
2739 transceiver->internal()->set_mline_index(state.mline_index());
2740 }
2741 transport_controller()->RollbackTransports();
2742 if (have_pending_rtp_data_channel_) {
2743 DestroyDataChannelTransport();
2744 have_pending_rtp_data_channel_ = false;
2745 }
2746 transceivers()->DiscardStableStates();
2747 pending_local_description_.reset();
2748 pending_remote_description_.reset();
2749 ChangeSignalingState(PeerConnectionInterface::kStable);
2750
2751 // Once all processing has finished, fire off callbacks.
2752 for (const auto& receiver : removed_receivers) {
2753 pc_->Observer()->OnRemoveTrack(receiver);
2754 }
2755 for (const auto& stream : all_added_streams) {
2756 pc_->Observer()->OnAddStream(stream);
2757 }
2758 for (const auto& stream : all_removed_streams) {
2759 pc_->Observer()->OnRemoveStream(stream);
2760 }
2761
2762 // The assumption is that in case of implicit rollback UpdateNegotiationNeeded
2763 // gets called in SetRemoteDescription.
2764 if (desc_type == SdpType::kRollback) {
2765 UpdateNegotiationNeeded();
2766 if (is_negotiation_needed_) {
2767 // Legacy version.
2768 pc_->Observer()->OnRenegotiationNeeded();
2769 // Spec-compliant version; the event may get invalidated before firing.
2770 GenerateNegotiationNeededEvent();
2771 }
2772 }
2773 return RTCError::OK();
2774 }
2775
IsUnifiedPlan() const2776 bool SdpOfferAnswerHandler::IsUnifiedPlan() const {
2777 return pc_->IsUnifiedPlan();
2778 }
2779
OnOperationsChainEmpty()2780 void SdpOfferAnswerHandler::OnOperationsChainEmpty() {
2781 RTC_DCHECK_RUN_ON(signaling_thread());
2782 if (pc_->IsClosed() || !update_negotiation_needed_on_empty_chain_)
2783 return;
2784 update_negotiation_needed_on_empty_chain_ = false;
2785 // Firing when chain is empty is only supported in Unified Plan to avoid Plan
2786 // B regressions. (In Plan B, onnegotiationneeded is already broken anyway, so
2787 // firing it even more might just be confusing.)
2788 if (IsUnifiedPlan()) {
2789 UpdateNegotiationNeeded();
2790 }
2791 }
2792
is_caller()2793 absl::optional<bool> SdpOfferAnswerHandler::is_caller() {
2794 RTC_DCHECK_RUN_ON(signaling_thread());
2795 return is_caller_;
2796 }
2797
HasNewIceCredentials()2798 bool SdpOfferAnswerHandler::HasNewIceCredentials() {
2799 RTC_DCHECK_RUN_ON(signaling_thread());
2800 return local_ice_credentials_to_replace_->HasIceCredentials();
2801 }
2802
IceRestartPending(const std::string & content_name) const2803 bool SdpOfferAnswerHandler::IceRestartPending(
2804 const std::string& content_name) const {
2805 RTC_DCHECK_RUN_ON(signaling_thread());
2806 return pending_ice_restarts_.find(content_name) !=
2807 pending_ice_restarts_.end();
2808 }
2809
NeedsIceRestart(const std::string & content_name) const2810 bool SdpOfferAnswerHandler::NeedsIceRestart(
2811 const std::string& content_name) const {
2812 return pc_->NeedsIceRestart(content_name);
2813 }
2814
GetDtlsRole(const std::string & mid) const2815 absl::optional<rtc::SSLRole> SdpOfferAnswerHandler::GetDtlsRole(
2816 const std::string& mid) const {
2817 return transport_controller()->GetDtlsRole(mid);
2818 }
2819
UpdateNegotiationNeeded()2820 void SdpOfferAnswerHandler::UpdateNegotiationNeeded() {
2821 RTC_DCHECK_RUN_ON(signaling_thread());
2822 if (!IsUnifiedPlan()) {
2823 pc_->Observer()->OnRenegotiationNeeded();
2824 GenerateNegotiationNeededEvent();
2825 return;
2826 }
2827
2828 // In the spec, a task is queued here to run the following steps - this is
2829 // meant to ensure we do not fire onnegotiationneeded prematurely if multiple
2830 // changes are being made at once. In order to support Chromium's
2831 // implementation where the JavaScript representation of the PeerConnection
2832 // lives on a separate thread though, the queuing of a task is instead
2833 // performed by the PeerConnectionObserver posting from the signaling thread
2834 // to the JavaScript main thread that negotiation is needed. And because the
2835 // Operations Chain lives on the WebRTC signaling thread,
2836 // ShouldFireNegotiationNeededEvent() must be called before firing the event
2837 // to ensure the Operations Chain is still empty and the event has not been
2838 // invalidated.
2839
2840 // If connection's [[IsClosed]] slot is true, abort these steps.
2841 if (pc_->IsClosed())
2842 return;
2843
2844 // If connection's signaling state is not "stable", abort these steps.
2845 if (signaling_state() != PeerConnectionInterface::kStable)
2846 return;
2847
2848 // NOTE
2849 // The negotiation-needed flag will be updated once the state transitions to
2850 // "stable", as part of the steps for setting an RTCSessionDescription.
2851
2852 // If the result of checking if negotiation is needed is false, clear the
2853 // negotiation-needed flag by setting connection's [[NegotiationNeeded]] slot
2854 // to false, and abort these steps.
2855 bool is_negotiation_needed = CheckIfNegotiationIsNeeded();
2856 if (!is_negotiation_needed) {
2857 is_negotiation_needed_ = false;
2858 // Invalidate any negotiation needed event that may previosuly have been
2859 // generated.
2860 ++negotiation_needed_event_id_;
2861 return;
2862 }
2863
2864 // If connection's [[NegotiationNeeded]] slot is already true, abort these
2865 // steps.
2866 if (is_negotiation_needed_)
2867 return;
2868
2869 // Set connection's [[NegotiationNeeded]] slot to true.
2870 is_negotiation_needed_ = true;
2871
2872 // Queue a task that runs the following steps:
2873 // If connection's [[IsClosed]] slot is true, abort these steps.
2874 // If connection's [[NegotiationNeeded]] slot is false, abort these steps.
2875 // Fire an event named negotiationneeded at connection.
2876 pc_->Observer()->OnRenegotiationNeeded();
2877 // Fire the spec-compliant version; when ShouldFireNegotiationNeededEvent() is
2878 // used in the task queued by the observer, this event will only fire when the
2879 // chain is empty.
2880 GenerateNegotiationNeededEvent();
2881 }
2882
CheckIfNegotiationIsNeeded()2883 bool SdpOfferAnswerHandler::CheckIfNegotiationIsNeeded() {
2884 RTC_DCHECK_RUN_ON(signaling_thread());
2885 // 1. If any implementation-specific negotiation is required, as described at
2886 // the start of this section, return true.
2887
2888 // 2. If connection.[[LocalIceCredentialsToReplace]] is not empty, return
2889 // true.
2890 if (local_ice_credentials_to_replace_->HasIceCredentials()) {
2891 return true;
2892 }
2893
2894 // 3. Let description be connection.[[CurrentLocalDescription]].
2895 const SessionDescriptionInterface* description = current_local_description();
2896 if (!description)
2897 return true;
2898
2899 // 4. If connection has created any RTCDataChannels, and no m= section in
2900 // description has been negotiated yet for data, return true.
2901 if (data_channel_controller()->HasSctpDataChannels()) {
2902 if (!cricket::GetFirstDataContent(description->description()->contents()))
2903 return true;
2904 }
2905
2906 // 5. For each transceiver in connection's set of transceivers, perform the
2907 // following checks:
2908 for (const auto& transceiver : transceivers()->List()) {
2909 const ContentInfo* current_local_msection =
2910 FindTransceiverMSection(transceiver.get(), description);
2911
2912 const ContentInfo* current_remote_msection = FindTransceiverMSection(
2913 transceiver.get(), current_remote_description());
2914
2915 // 5.4 If transceiver is stopped and is associated with an m= section,
2916 // but the associated m= section is not yet rejected in
2917 // connection.[[CurrentLocalDescription]] or
2918 // connection.[[CurrentRemoteDescription]], return true.
2919 if (transceiver->stopped()) {
2920 RTC_DCHECK(transceiver->stopping());
2921 if (current_local_msection && !current_local_msection->rejected &&
2922 ((current_remote_msection && !current_remote_msection->rejected) ||
2923 !current_remote_msection)) {
2924 return true;
2925 }
2926 continue;
2927 }
2928
2929 // 5.1 If transceiver.[[Stopping]] is true and transceiver.[[Stopped]] is
2930 // false, return true.
2931 if (transceiver->stopping() && !transceiver->stopped())
2932 return true;
2933
2934 // 5.2 If transceiver isn't stopped and isn't yet associated with an m=
2935 // section in description, return true.
2936 if (!current_local_msection)
2937 return true;
2938
2939 const MediaContentDescription* current_local_media_description =
2940 current_local_msection->media_description();
2941 // 5.3 If transceiver isn't stopped and is associated with an m= section
2942 // in description then perform the following checks:
2943
2944 // 5.3.1 If transceiver.[[Direction]] is "sendrecv" or "sendonly", and the
2945 // associated m= section in description either doesn't contain a single
2946 // "a=msid" line, or the number of MSIDs from the "a=msid" lines in this
2947 // m= section, or the MSID values themselves, differ from what is in
2948 // transceiver.sender.[[AssociatedMediaStreamIds]], return true.
2949 if (RtpTransceiverDirectionHasSend(transceiver->direction())) {
2950 if (current_local_media_description->streams().size() == 0)
2951 return true;
2952
2953 std::vector<std::string> msection_msids;
2954 for (const auto& stream : current_local_media_description->streams()) {
2955 for (const std::string& msid : stream.stream_ids())
2956 msection_msids.push_back(msid);
2957 }
2958
2959 std::vector<std::string> transceiver_msids =
2960 transceiver->sender()->stream_ids();
2961 if (msection_msids.size() != transceiver_msids.size())
2962 return true;
2963
2964 absl::c_sort(transceiver_msids);
2965 absl::c_sort(msection_msids);
2966 if (transceiver_msids != msection_msids)
2967 return true;
2968 }
2969
2970 // 5.3.2 If description is of type "offer", and the direction of the
2971 // associated m= section in neither connection.[[CurrentLocalDescription]]
2972 // nor connection.[[CurrentRemoteDescription]] matches
2973 // transceiver.[[Direction]], return true.
2974 if (description->GetType() == SdpType::kOffer) {
2975 if (!current_remote_description())
2976 return true;
2977
2978 if (!current_remote_msection)
2979 return true;
2980
2981 RtpTransceiverDirection current_local_direction =
2982 current_local_media_description->direction();
2983 RtpTransceiverDirection current_remote_direction =
2984 current_remote_msection->media_description()->direction();
2985 if (transceiver->direction() != current_local_direction &&
2986 transceiver->direction() !=
2987 RtpTransceiverDirectionReversed(current_remote_direction)) {
2988 return true;
2989 }
2990 }
2991
2992 // 5.3.3 If description is of type "answer", and the direction of the
2993 // associated m= section in the description does not match
2994 // transceiver.[[Direction]] intersected with the offered direction (as
2995 // described in [JSEP] (section 5.3.1.)), return true.
2996 if (description->GetType() == SdpType::kAnswer) {
2997 if (!remote_description())
2998 return true;
2999
3000 const ContentInfo* offered_remote_msection =
3001 FindTransceiverMSection(transceiver.get(), remote_description());
3002
3003 RtpTransceiverDirection offered_direction =
3004 offered_remote_msection
3005 ? offered_remote_msection->media_description()->direction()
3006 : RtpTransceiverDirection::kInactive;
3007
3008 if (current_local_media_description->direction() !=
3009 (RtpTransceiverDirectionIntersection(
3010 transceiver->direction(),
3011 RtpTransceiverDirectionReversed(offered_direction)))) {
3012 return true;
3013 }
3014 }
3015 }
3016
3017 // If all the preceding checks were performed and true was not returned,
3018 // nothing remains to be negotiated; return false.
3019 return false;
3020 }
3021
GenerateNegotiationNeededEvent()3022 void SdpOfferAnswerHandler::GenerateNegotiationNeededEvent() {
3023 RTC_DCHECK_RUN_ON(signaling_thread());
3024 ++negotiation_needed_event_id_;
3025 pc_->Observer()->OnNegotiationNeededEvent(negotiation_needed_event_id_);
3026 }
3027
ValidateSessionDescription(const SessionDescriptionInterface * sdesc,cricket::ContentSource source)3028 RTCError SdpOfferAnswerHandler::ValidateSessionDescription(
3029 const SessionDescriptionInterface* sdesc,
3030 cricket::ContentSource source) {
3031 if (session_error() != SessionError::kNone) {
3032 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, GetSessionErrorMsg());
3033 }
3034
3035 if (!sdesc || !sdesc->description()) {
3036 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, kInvalidSdp);
3037 }
3038
3039 SdpType type = sdesc->GetType();
3040 if ((source == cricket::CS_LOCAL && !ExpectSetLocalDescription(type)) ||
3041 (source == cricket::CS_REMOTE && !ExpectSetRemoteDescription(type))) {
3042 LOG_AND_RETURN_ERROR(
3043 RTCErrorType::INVALID_STATE,
3044 "Called in wrong state: " + GetSignalingStateString(signaling_state()));
3045 }
3046
3047 RTCError error = ValidateMids(*sdesc->description());
3048 if (!error.ok()) {
3049 return error;
3050 }
3051
3052 // Verify crypto settings.
3053 std::string crypto_error;
3054 if (webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED ||
3055 pc_->dtls_enabled()) {
3056 RTCError crypto_error =
3057 VerifyCrypto(sdesc->description(), pc_->dtls_enabled());
3058 if (!crypto_error.ok()) {
3059 return crypto_error;
3060 }
3061 }
3062
3063 // Verify ice-ufrag and ice-pwd.
3064 if (!VerifyIceUfragPwdPresent(sdesc->description())) {
3065 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
3066 kSdpWithoutIceUfragPwd);
3067 }
3068
3069 if (!pc_->ValidateBundleSettings(sdesc->description())) {
3070 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
3071 kBundleWithoutRtcpMux);
3072 }
3073
3074 // TODO(skvlad): When the local rtcp-mux policy is Require, reject any
3075 // m-lines that do not rtcp-mux enabled.
3076
3077 // Verify m-lines in Answer when compared against Offer.
3078 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
3079 // With an answer we want to compare the new answer session description with
3080 // the offer's session description from the current negotiation.
3081 const cricket::SessionDescription* offer_desc =
3082 (source == cricket::CS_LOCAL) ? remote_description()->description()
3083 : local_description()->description();
3084 if (!MediaSectionsHaveSameCount(*offer_desc, *sdesc->description()) ||
3085 !MediaSectionsInSameOrder(*offer_desc, nullptr, *sdesc->description(),
3086 type)) {
3087 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
3088 kMlineMismatchInAnswer);
3089 }
3090 } else {
3091 // The re-offers should respect the order of m= sections in current
3092 // description. See RFC3264 Section 8 paragraph 4 for more details.
3093 // With a re-offer, either the current local or current remote descriptions
3094 // could be the most up to date, so we would like to check against both of
3095 // them if they exist. It could be the case that one of them has a 0 port
3096 // for a media section, but the other does not. This is important to check
3097 // against in the case that we are recycling an m= section.
3098 const cricket::SessionDescription* current_desc = nullptr;
3099 const cricket::SessionDescription* secondary_current_desc = nullptr;
3100 if (local_description()) {
3101 current_desc = local_description()->description();
3102 if (remote_description()) {
3103 secondary_current_desc = remote_description()->description();
3104 }
3105 } else if (remote_description()) {
3106 current_desc = remote_description()->description();
3107 }
3108 if (current_desc &&
3109 !MediaSectionsInSameOrder(*current_desc, secondary_current_desc,
3110 *sdesc->description(), type)) {
3111 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
3112 kMlineMismatchInSubsequentOffer);
3113 }
3114 }
3115
3116 if (IsUnifiedPlan()) {
3117 // Ensure that each audio and video media section has at most one
3118 // "StreamParams". This will return an error if receiving a session
3119 // description from a "Plan B" endpoint which adds multiple tracks of the
3120 // same type. With Unified Plan, there can only be at most one track per
3121 // media section.
3122 for (const ContentInfo& content : sdesc->description()->contents()) {
3123 const MediaContentDescription& desc = *content.media_description();
3124 if ((desc.type() == cricket::MEDIA_TYPE_AUDIO ||
3125 desc.type() == cricket::MEDIA_TYPE_VIDEO) &&
3126 desc.streams().size() > 1u) {
3127 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
3128 "Media section has more than one track specified "
3129 "with a=ssrc lines which is not supported with "
3130 "Unified Plan.");
3131 }
3132 }
3133 }
3134
3135 return RTCError::OK();
3136 }
3137
UpdateTransceiversAndDataChannels(cricket::ContentSource source,const SessionDescriptionInterface & new_session,const SessionDescriptionInterface * old_local_description,const SessionDescriptionInterface * old_remote_description)3138 RTCError SdpOfferAnswerHandler::UpdateTransceiversAndDataChannels(
3139 cricket::ContentSource source,
3140 const SessionDescriptionInterface& new_session,
3141 const SessionDescriptionInterface* old_local_description,
3142 const SessionDescriptionInterface* old_remote_description) {
3143 RTC_DCHECK_RUN_ON(signaling_thread());
3144 RTC_DCHECK(IsUnifiedPlan());
3145
3146 const cricket::ContentGroup* bundle_group = nullptr;
3147 if (new_session.GetType() == SdpType::kOffer) {
3148 auto bundle_group_or_error =
3149 GetEarlyBundleGroup(*new_session.description());
3150 if (!bundle_group_or_error.ok()) {
3151 return bundle_group_or_error.MoveError();
3152 }
3153 bundle_group = bundle_group_or_error.MoveValue();
3154 }
3155
3156 const ContentInfos& new_contents = new_session.description()->contents();
3157 for (size_t i = 0; i < new_contents.size(); ++i) {
3158 const cricket::ContentInfo& new_content = new_contents[i];
3159 cricket::MediaType media_type = new_content.media_description()->type();
3160 mid_generator_.AddKnownId(new_content.name);
3161 if (media_type == cricket::MEDIA_TYPE_AUDIO ||
3162 media_type == cricket::MEDIA_TYPE_VIDEO) {
3163 const cricket::ContentInfo* old_local_content = nullptr;
3164 if (old_local_description &&
3165 i < old_local_description->description()->contents().size()) {
3166 old_local_content =
3167 &old_local_description->description()->contents()[i];
3168 }
3169 const cricket::ContentInfo* old_remote_content = nullptr;
3170 if (old_remote_description &&
3171 i < old_remote_description->description()->contents().size()) {
3172 old_remote_content =
3173 &old_remote_description->description()->contents()[i];
3174 }
3175 auto transceiver_or_error =
3176 AssociateTransceiver(source, new_session.GetType(), i, new_content,
3177 old_local_content, old_remote_content);
3178 if (!transceiver_or_error.ok()) {
3179 // In the case where a transceiver is rejected locally, we don't
3180 // expect to find a transceiver, but might find it in the case
3181 // where state is still "stopping", not "stopped".
3182 if (new_content.rejected) {
3183 continue;
3184 }
3185 return transceiver_or_error.MoveError();
3186 }
3187 auto transceiver = transceiver_or_error.MoveValue();
3188 RTCError error =
3189 UpdateTransceiverChannel(transceiver, new_content, bundle_group);
3190 if (!error.ok()) {
3191 return error;
3192 }
3193 } else if (media_type == cricket::MEDIA_TYPE_DATA) {
3194 if (pc_->GetDataMid() && new_content.name != *(pc_->GetDataMid())) {
3195 // Ignore all but the first data section.
3196 RTC_LOG(LS_INFO) << "Ignoring data media section with MID="
3197 << new_content.name;
3198 continue;
3199 }
3200 RTCError error = UpdateDataChannel(source, new_content, bundle_group);
3201 if (!error.ok()) {
3202 return error;
3203 }
3204 } else if (media_type == cricket::MEDIA_TYPE_UNSUPPORTED) {
3205 RTC_LOG(LS_INFO) << "Ignoring unsupported media type";
3206 } else {
3207 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
3208 "Unknown section type.");
3209 }
3210 }
3211
3212 return RTCError::OK();
3213 }
3214
3215 RTCErrorOr<rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
AssociateTransceiver(cricket::ContentSource source,SdpType type,size_t mline_index,const ContentInfo & content,const ContentInfo * old_local_content,const ContentInfo * old_remote_content)3216 SdpOfferAnswerHandler::AssociateTransceiver(
3217 cricket::ContentSource source,
3218 SdpType type,
3219 size_t mline_index,
3220 const ContentInfo& content,
3221 const ContentInfo* old_local_content,
3222 const ContentInfo* old_remote_content) {
3223 RTC_DCHECK(IsUnifiedPlan());
3224 #if RTC_DCHECK_IS_ON
3225 // If this is an offer then the m= section might be recycled. If the m=
3226 // section is being recycled (defined as: rejected in the current local or
3227 // remote description and not rejected in new description), the transceiver
3228 // should have been removed by RemoveStoppedtransceivers()->
3229 if (IsMediaSectionBeingRecycled(type, content, old_local_content,
3230 old_remote_content)) {
3231 const std::string& old_mid =
3232 (old_local_content && old_local_content->rejected)
3233 ? old_local_content->name
3234 : old_remote_content->name;
3235 auto old_transceiver = transceivers()->FindByMid(old_mid);
3236 // The transceiver should be disassociated in RemoveStoppedTransceivers()
3237 RTC_DCHECK(!old_transceiver);
3238 }
3239 #endif
3240
3241 const MediaContentDescription* media_desc = content.media_description();
3242 auto transceiver = transceivers()->FindByMid(content.name);
3243 if (source == cricket::CS_LOCAL) {
3244 // Find the RtpTransceiver that corresponds to this m= section, using the
3245 // mapping between transceivers and m= section indices established when
3246 // creating the offer.
3247 if (!transceiver) {
3248 transceiver = transceivers()->FindByMLineIndex(mline_index);
3249 }
3250 if (!transceiver) {
3251 // This may happen normally when media sections are rejected.
3252 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
3253 "Transceiver not found based on m-line index");
3254 }
3255 } else {
3256 RTC_DCHECK_EQ(source, cricket::CS_REMOTE);
3257 // If the m= section is sendrecv or recvonly, and there are RtpTransceivers
3258 // of the same type...
3259 // When simulcast is requested, a transceiver cannot be associated because
3260 // AddTrack cannot be called to initialize it.
3261 if (!transceiver &&
3262 RtpTransceiverDirectionHasRecv(media_desc->direction()) &&
3263 !media_desc->HasSimulcast()) {
3264 transceiver = FindAvailableTransceiverToReceive(media_desc->type());
3265 }
3266 // If no RtpTransceiver was found in the previous step, create one with a
3267 // recvonly direction.
3268 if (!transceiver) {
3269 RTC_LOG(LS_INFO) << "Adding "
3270 << cricket::MediaTypeToString(media_desc->type())
3271 << " transceiver for MID=" << content.name
3272 << " at i=" << mline_index
3273 << " in response to the remote description.";
3274 std::string sender_id = rtc::CreateRandomUuid();
3275 std::vector<RtpEncodingParameters> send_encodings =
3276 GetSendEncodingsFromRemoteDescription(*media_desc);
3277 auto sender = rtp_manager()->CreateSender(media_desc->type(), sender_id,
3278 nullptr, {}, send_encodings);
3279 std::string receiver_id;
3280 if (!media_desc->streams().empty()) {
3281 receiver_id = media_desc->streams()[0].id;
3282 } else {
3283 receiver_id = rtc::CreateRandomUuid();
3284 }
3285 auto receiver =
3286 rtp_manager()->CreateReceiver(media_desc->type(), receiver_id);
3287 transceiver = rtp_manager()->CreateAndAddTransceiver(sender, receiver);
3288 transceiver->internal()->set_direction(
3289 RtpTransceiverDirection::kRecvOnly);
3290 if (type == SdpType::kOffer) {
3291 transceivers()->StableState(transceiver)->set_newly_created();
3292 }
3293 }
3294
3295 RTC_DCHECK(transceiver);
3296
3297 // Check if the offer indicated simulcast but the answer rejected it.
3298 // This can happen when simulcast is not supported on the remote party.
3299 if (SimulcastIsRejected(old_local_content, *media_desc)) {
3300 RTC_HISTOGRAM_BOOLEAN(kSimulcastDisabled, true);
3301 RTCError error =
3302 DisableSimulcastInSender(transceiver->internal()->sender_internal());
3303 if (!error.ok()) {
3304 RTC_LOG(LS_ERROR) << "Failed to remove rejected simulcast.";
3305 return std::move(error);
3306 }
3307 }
3308 }
3309
3310 if (transceiver->media_type() != media_desc->type()) {
3311 LOG_AND_RETURN_ERROR(
3312 RTCErrorType::INVALID_PARAMETER,
3313 "Transceiver type does not match media description type.");
3314 }
3315
3316 if (media_desc->HasSimulcast()) {
3317 std::vector<SimulcastLayer> layers =
3318 source == cricket::CS_LOCAL
3319 ? media_desc->simulcast_description().send_layers().GetAllLayers()
3320 : media_desc->simulcast_description()
3321 .receive_layers()
3322 .GetAllLayers();
3323 RTCError error = UpdateSimulcastLayerStatusInSender(
3324 layers, transceiver->internal()->sender_internal());
3325 if (!error.ok()) {
3326 RTC_LOG(LS_ERROR) << "Failed updating status for simulcast layers.";
3327 return std::move(error);
3328 }
3329 }
3330 if (type == SdpType::kOffer) {
3331 bool state_changes = transceiver->internal()->mid() != content.name ||
3332 transceiver->internal()->mline_index() != mline_index;
3333 if (state_changes) {
3334 transceivers()
3335 ->StableState(transceiver)
3336 ->SetMSectionIfUnset(transceiver->internal()->mid(),
3337 transceiver->internal()->mline_index());
3338 }
3339 }
3340 // Associate the found or created RtpTransceiver with the m= section by
3341 // setting the value of the RtpTransceiver's mid property to the MID of the m=
3342 // section, and establish a mapping between the transceiver and the index of
3343 // the m= section.
3344 transceiver->internal()->set_mid(content.name);
3345 transceiver->internal()->set_mline_index(mline_index);
3346 return std::move(transceiver);
3347 }
3348
3349 RTCErrorOr<const cricket::ContentGroup*>
GetEarlyBundleGroup(const SessionDescription & desc) const3350 SdpOfferAnswerHandler::GetEarlyBundleGroup(
3351 const SessionDescription& desc) const {
3352 const cricket::ContentGroup* bundle_group = nullptr;
3353 if (pc_->configuration()->bundle_policy ==
3354 PeerConnectionInterface::kBundlePolicyMaxBundle) {
3355 bundle_group = desc.GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
3356 if (!bundle_group) {
3357 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
3358 "max-bundle configured but session description "
3359 "has no BUNDLE group");
3360 }
3361 }
3362 return bundle_group;
3363 }
3364
UpdateTransceiverChannel(rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>> transceiver,const cricket::ContentInfo & content,const cricket::ContentGroup * bundle_group)3365 RTCError SdpOfferAnswerHandler::UpdateTransceiverChannel(
3366 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
3367 transceiver,
3368 const cricket::ContentInfo& content,
3369 const cricket::ContentGroup* bundle_group) {
3370 RTC_DCHECK(IsUnifiedPlan());
3371 RTC_DCHECK(transceiver);
3372 cricket::ChannelInterface* channel = transceiver->internal()->channel();
3373 if (content.rejected) {
3374 if (channel) {
3375 transceiver->internal()->SetChannel(nullptr);
3376 DestroyChannelInterface(channel);
3377 }
3378 } else {
3379 if (!channel) {
3380 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
3381 channel = CreateVoiceChannel(content.name);
3382 } else {
3383 RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, transceiver->media_type());
3384 channel = CreateVideoChannel(content.name);
3385 }
3386 if (!channel) {
3387 LOG_AND_RETURN_ERROR(
3388 RTCErrorType::INTERNAL_ERROR,
3389 "Failed to create channel for mid=" + content.name);
3390 }
3391 transceiver->internal()->SetChannel(channel);
3392 }
3393 }
3394 return RTCError::OK();
3395 }
3396
UpdateDataChannel(cricket::ContentSource source,const cricket::ContentInfo & content,const cricket::ContentGroup * bundle_group)3397 RTCError SdpOfferAnswerHandler::UpdateDataChannel(
3398 cricket::ContentSource source,
3399 const cricket::ContentInfo& content,
3400 const cricket::ContentGroup* bundle_group) {
3401 if (pc_->data_channel_type() == cricket::DCT_NONE) {
3402 // If data channels are disabled, ignore this media section. CreateAnswer
3403 // will take care of rejecting it.
3404 return RTCError::OK();
3405 }
3406 if (content.rejected) {
3407 RTC_LOG(LS_INFO) << "Rejected data channel, mid=" << content.mid();
3408 DestroyDataChannelTransport();
3409 } else {
3410 if (!data_channel_controller()->rtp_data_channel() &&
3411 !data_channel_controller()->data_channel_transport()) {
3412 RTC_LOG(LS_INFO) << "Creating data channel, mid=" << content.mid();
3413 if (!CreateDataChannel(content.name)) {
3414 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
3415 "Failed to create data channel.");
3416 }
3417 }
3418 if (source == cricket::CS_REMOTE) {
3419 const MediaContentDescription* data_desc = content.media_description();
3420 if (data_desc && cricket::IsRtpProtocol(data_desc->protocol())) {
3421 data_channel_controller()->UpdateRemoteRtpDataChannels(
3422 GetActiveStreams(data_desc));
3423 }
3424 }
3425 }
3426 return RTCError::OK();
3427 }
3428
ExpectSetLocalDescription(SdpType type)3429 bool SdpOfferAnswerHandler::ExpectSetLocalDescription(SdpType type) {
3430 PeerConnectionInterface::SignalingState state = signaling_state();
3431 if (type == SdpType::kOffer) {
3432 return (state == PeerConnectionInterface::kStable) ||
3433 (state == PeerConnectionInterface::kHaveLocalOffer);
3434 } else {
3435 RTC_DCHECK(type == SdpType::kPrAnswer || type == SdpType::kAnswer);
3436 return (state == PeerConnectionInterface::kHaveRemoteOffer) ||
3437 (state == PeerConnectionInterface::kHaveLocalPrAnswer);
3438 }
3439 }
3440
ExpectSetRemoteDescription(SdpType type)3441 bool SdpOfferAnswerHandler::ExpectSetRemoteDescription(SdpType type) {
3442 PeerConnectionInterface::SignalingState state = signaling_state();
3443 if (type == SdpType::kOffer) {
3444 return (state == PeerConnectionInterface::kStable) ||
3445 (state == PeerConnectionInterface::kHaveRemoteOffer);
3446 } else {
3447 RTC_DCHECK(type == SdpType::kPrAnswer || type == SdpType::kAnswer);
3448 return (state == PeerConnectionInterface::kHaveLocalOffer) ||
3449 (state == PeerConnectionInterface::kHaveRemotePrAnswer);
3450 }
3451 }
3452
FillInMissingRemoteMids(cricket::SessionDescription * new_remote_description)3453 void SdpOfferAnswerHandler::FillInMissingRemoteMids(
3454 cricket::SessionDescription* new_remote_description) {
3455 RTC_DCHECK_RUN_ON(signaling_thread());
3456 RTC_DCHECK(new_remote_description);
3457 const cricket::ContentInfos no_infos;
3458 const cricket::ContentInfos& local_contents =
3459 (local_description() ? local_description()->description()->contents()
3460 : no_infos);
3461 const cricket::ContentInfos& remote_contents =
3462 (remote_description() ? remote_description()->description()->contents()
3463 : no_infos);
3464 for (size_t i = 0; i < new_remote_description->contents().size(); ++i) {
3465 cricket::ContentInfo& content = new_remote_description->contents()[i];
3466 if (!content.name.empty()) {
3467 continue;
3468 }
3469 std::string new_mid;
3470 absl::string_view source_explanation;
3471 if (IsUnifiedPlan()) {
3472 if (i < local_contents.size()) {
3473 new_mid = local_contents[i].name;
3474 source_explanation = "from the matching local media section";
3475 } else if (i < remote_contents.size()) {
3476 new_mid = remote_contents[i].name;
3477 source_explanation = "from the matching previous remote media section";
3478 } else {
3479 new_mid = mid_generator_.GenerateString();
3480 source_explanation = "generated just now";
3481 }
3482 } else {
3483 new_mid = std::string(
3484 GetDefaultMidForPlanB(content.media_description()->type()));
3485 source_explanation = "to match pre-existing behavior";
3486 }
3487 RTC_DCHECK(!new_mid.empty());
3488 content.name = new_mid;
3489 new_remote_description->transport_infos()[i].content_name = new_mid;
3490 RTC_LOG(LS_INFO) << "SetRemoteDescription: Remote media section at i=" << i
3491 << " is missing an a=mid line. Filling in the value '"
3492 << new_mid << "' " << source_explanation << ".";
3493 }
3494 }
3495
3496 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
FindAvailableTransceiverToReceive(cricket::MediaType media_type) const3497 SdpOfferAnswerHandler::FindAvailableTransceiverToReceive(
3498 cricket::MediaType media_type) const {
3499 RTC_DCHECK_RUN_ON(signaling_thread());
3500 RTC_DCHECK(IsUnifiedPlan());
3501 // From JSEP section 5.10 (Applying a Remote Description):
3502 // If the m= section is sendrecv or recvonly, and there are RtpTransceivers of
3503 // the same type that were added to the PeerConnection by addTrack and are not
3504 // associated with any m= section and are not stopped, find the first such
3505 // RtpTransceiver.
3506 for (auto transceiver : transceivers()->List()) {
3507 if (transceiver->media_type() == media_type &&
3508 transceiver->internal()->created_by_addtrack() && !transceiver->mid() &&
3509 !transceiver->stopped()) {
3510 return transceiver;
3511 }
3512 }
3513 return nullptr;
3514 }
3515
3516 const cricket::ContentInfo*
FindMediaSectionForTransceiver(rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>> transceiver,const SessionDescriptionInterface * sdesc) const3517 SdpOfferAnswerHandler::FindMediaSectionForTransceiver(
3518 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
3519 transceiver,
3520 const SessionDescriptionInterface* sdesc) const {
3521 RTC_DCHECK_RUN_ON(signaling_thread());
3522 RTC_DCHECK(transceiver);
3523 RTC_DCHECK(sdesc);
3524 if (IsUnifiedPlan()) {
3525 if (!transceiver->internal()->mid()) {
3526 // This transceiver is not associated with a media section yet.
3527 return nullptr;
3528 }
3529 return sdesc->description()->GetContentByName(
3530 *transceiver->internal()->mid());
3531 } else {
3532 // Plan B only allows at most one audio and one video section, so use the
3533 // first media section of that type.
3534 return cricket::GetFirstMediaContent(sdesc->description()->contents(),
3535 transceiver->media_type());
3536 }
3537 }
3538
GetOptionsForOffer(const PeerConnectionInterface::RTCOfferAnswerOptions & offer_answer_options,cricket::MediaSessionOptions * session_options)3539 void SdpOfferAnswerHandler::GetOptionsForOffer(
3540 const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
3541 cricket::MediaSessionOptions* session_options) {
3542 RTC_DCHECK_RUN_ON(signaling_thread());
3543 ExtractSharedMediaSessionOptions(offer_answer_options, session_options);
3544
3545 if (IsUnifiedPlan()) {
3546 GetOptionsForUnifiedPlanOffer(offer_answer_options, session_options);
3547 } else {
3548 GetOptionsForPlanBOffer(offer_answer_options, session_options);
3549 }
3550
3551 // Intentionally unset the data channel type for RTP data channel with the
3552 // second condition. Otherwise the RTP data channels would be successfully
3553 // negotiated by default and the unit tests in WebRtcDataBrowserTest will fail
3554 // when building with chromium. We want to leave RTP data channels broken, so
3555 // people won't try to use them.
3556 if (data_channel_controller()->HasRtpDataChannels() ||
3557 pc_->data_channel_type() != cricket::DCT_RTP) {
3558 session_options->data_channel_type = pc_->data_channel_type();
3559 }
3560
3561 // Apply ICE restart flag and renomination flag.
3562 bool ice_restart = offer_answer_options.ice_restart || HasNewIceCredentials();
3563 for (auto& options : session_options->media_description_options) {
3564 options.transport_options.ice_restart = ice_restart;
3565 options.transport_options.enable_ice_renomination =
3566 pc_->configuration()->enable_ice_renomination;
3567 }
3568
3569 session_options->rtcp_cname = rtcp_cname_;
3570 session_options->crypto_options = pc_->GetCryptoOptions();
3571 session_options->pooled_ice_credentials =
3572 pc_->network_thread()->Invoke<std::vector<cricket::IceParameters>>(
3573 RTC_FROM_HERE,
3574 [this] { return port_allocator()->GetPooledIceCredentials(); });
3575 session_options->offer_extmap_allow_mixed =
3576 pc_->configuration()->offer_extmap_allow_mixed;
3577
3578 // Allow fallback for using obsolete SCTP syntax.
3579 // Note that the default in |session_options| is true, while
3580 // the default in |options| is false.
3581 session_options->use_obsolete_sctp_sdp =
3582 offer_answer_options.use_obsolete_sctp_sdp;
3583 }
3584
GetOptionsForPlanBOffer(const PeerConnectionInterface::RTCOfferAnswerOptions & offer_answer_options,cricket::MediaSessionOptions * session_options)3585 void SdpOfferAnswerHandler::GetOptionsForPlanBOffer(
3586 const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
3587 cricket::MediaSessionOptions* session_options) {
3588 // Figure out transceiver directional preferences.
3589 bool send_audio =
3590 !rtp_manager()->GetAudioTransceiver()->internal()->senders().empty();
3591 bool send_video =
3592 !rtp_manager()->GetVideoTransceiver()->internal()->senders().empty();
3593
3594 // By default, generate sendrecv/recvonly m= sections.
3595 bool recv_audio = true;
3596 bool recv_video = true;
3597
3598 // By default, only offer a new m= section if we have media to send with it.
3599 bool offer_new_audio_description = send_audio;
3600 bool offer_new_video_description = send_video;
3601 bool offer_new_data_description =
3602 data_channel_controller()->HasDataChannels();
3603
3604 // The "offer_to_receive_X" options allow those defaults to be overridden.
3605 if (offer_answer_options.offer_to_receive_audio !=
3606 PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
3607 recv_audio = (offer_answer_options.offer_to_receive_audio > 0);
3608 offer_new_audio_description =
3609 offer_new_audio_description ||
3610 (offer_answer_options.offer_to_receive_audio > 0);
3611 }
3612 if (offer_answer_options.offer_to_receive_video !=
3613 RTCOfferAnswerOptions::kUndefined) {
3614 recv_video = (offer_answer_options.offer_to_receive_video > 0);
3615 offer_new_video_description =
3616 offer_new_video_description ||
3617 (offer_answer_options.offer_to_receive_video > 0);
3618 }
3619
3620 absl::optional<size_t> audio_index;
3621 absl::optional<size_t> video_index;
3622 absl::optional<size_t> data_index;
3623 // If a current description exists, generate m= sections in the same order,
3624 // using the first audio/video/data section that appears and rejecting
3625 // extraneous ones.
3626 if (local_description()) {
3627 GenerateMediaDescriptionOptions(
3628 local_description(),
3629 RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
3630 RtpTransceiverDirectionFromSendRecv(send_video, recv_video),
3631 &audio_index, &video_index, &data_index, session_options);
3632 }
3633
3634 // Add audio/video/data m= sections to the end if needed.
3635 if (!audio_index && offer_new_audio_description) {
3636 cricket::MediaDescriptionOptions options(
3637 cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
3638 RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio), false);
3639 options.header_extensions =
3640 channel_manager()->GetSupportedAudioRtpHeaderExtensions();
3641 session_options->media_description_options.push_back(options);
3642 audio_index = session_options->media_description_options.size() - 1;
3643 }
3644 if (!video_index && offer_new_video_description) {
3645 cricket::MediaDescriptionOptions options(
3646 cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
3647 RtpTransceiverDirectionFromSendRecv(send_video, recv_video), false);
3648 options.header_extensions =
3649 channel_manager()->GetSupportedVideoRtpHeaderExtensions();
3650 session_options->media_description_options.push_back(options);
3651 video_index = session_options->media_description_options.size() - 1;
3652 }
3653 if (!data_index && offer_new_data_description) {
3654 session_options->media_description_options.push_back(
3655 GetMediaDescriptionOptionsForActiveData(cricket::CN_DATA));
3656 data_index = session_options->media_description_options.size() - 1;
3657 }
3658
3659 cricket::MediaDescriptionOptions* audio_media_description_options =
3660 !audio_index ? nullptr
3661 : &session_options->media_description_options[*audio_index];
3662 cricket::MediaDescriptionOptions* video_media_description_options =
3663 !video_index ? nullptr
3664 : &session_options->media_description_options[*video_index];
3665
3666 AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(),
3667 audio_media_description_options,
3668 video_media_description_options,
3669 offer_answer_options.num_simulcast_layers);
3670 }
3671
GetOptionsForUnifiedPlanOffer(const RTCOfferAnswerOptions & offer_answer_options,cricket::MediaSessionOptions * session_options)3672 void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer(
3673 const RTCOfferAnswerOptions& offer_answer_options,
3674 cricket::MediaSessionOptions* session_options) {
3675 // Rules for generating an offer are dictated by JSEP sections 5.2.1 (Initial
3676 // Offers) and 5.2.2 (Subsequent Offers).
3677 RTC_DCHECK_EQ(session_options->media_description_options.size(), 0);
3678 const ContentInfos no_infos;
3679 const ContentInfos& local_contents =
3680 (local_description() ? local_description()->description()->contents()
3681 : no_infos);
3682 const ContentInfos& remote_contents =
3683 (remote_description() ? remote_description()->description()->contents()
3684 : no_infos);
3685 // The mline indices that can be recycled. New transceivers should reuse these
3686 // slots first.
3687 std::queue<size_t> recycleable_mline_indices;
3688 // First, go through each media section that exists in either the local or
3689 // remote description and generate a media section in this offer for the
3690 // associated transceiver. If a media section can be recycled, generate a
3691 // default, rejected media section here that can be later overwritten.
3692 for (size_t i = 0;
3693 i < std::max(local_contents.size(), remote_contents.size()); ++i) {
3694 // Either |local_content| or |remote_content| is non-null.
3695 const ContentInfo* local_content =
3696 (i < local_contents.size() ? &local_contents[i] : nullptr);
3697 const ContentInfo* current_local_content =
3698 GetContentByIndex(current_local_description(), i);
3699 const ContentInfo* remote_content =
3700 (i < remote_contents.size() ? &remote_contents[i] : nullptr);
3701 const ContentInfo* current_remote_content =
3702 GetContentByIndex(current_remote_description(), i);
3703 bool had_been_rejected =
3704 (current_local_content && current_local_content->rejected) ||
3705 (current_remote_content && current_remote_content->rejected);
3706 const std::string& mid =
3707 (local_content ? local_content->name : remote_content->name);
3708 cricket::MediaType media_type =
3709 (local_content ? local_content->media_description()->type()
3710 : remote_content->media_description()->type());
3711 if (media_type == cricket::MEDIA_TYPE_AUDIO ||
3712 media_type == cricket::MEDIA_TYPE_VIDEO) {
3713 // A media section is considered eligible for recycling if it is marked as
3714 // rejected in either the current local or current remote description.
3715 auto transceiver = transceivers()->FindByMid(mid);
3716 if (!transceiver) {
3717 // No associated transceiver. The media section has been stopped.
3718 recycleable_mline_indices.push(i);
3719 session_options->media_description_options.push_back(
3720 cricket::MediaDescriptionOptions(media_type, mid,
3721 RtpTransceiverDirection::kInactive,
3722 /*stopped=*/true));
3723 } else {
3724 // NOTE: a stopping transceiver should be treated as a stopped one in
3725 // createOffer as specified in
3726 // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createoffer.
3727 if (had_been_rejected && transceiver->stopping()) {
3728 session_options->media_description_options.push_back(
3729 cricket::MediaDescriptionOptions(
3730 transceiver->media_type(), mid,
3731 RtpTransceiverDirection::kInactive,
3732 /*stopped=*/true));
3733 recycleable_mline_indices.push(i);
3734 } else {
3735 session_options->media_description_options.push_back(
3736 GetMediaDescriptionOptionsForTransceiver(
3737 transceiver, mid,
3738 /*is_create_offer=*/true));
3739 // CreateOffer shouldn't really cause any state changes in
3740 // PeerConnection, but we need a way to match new transceivers to new
3741 // media sections in SetLocalDescription and JSEP specifies this is
3742 // done by recording the index of the media section generated for the
3743 // transceiver in the offer.
3744 transceiver->internal()->set_mline_index(i);
3745 }
3746 }
3747 } else if (media_type == cricket::MEDIA_TYPE_UNSUPPORTED) {
3748 RTC_DCHECK(local_content->rejected);
3749 session_options->media_description_options.push_back(
3750 cricket::MediaDescriptionOptions(media_type, mid,
3751 RtpTransceiverDirection::kInactive,
3752 /*stopped=*/true));
3753 } else {
3754 RTC_CHECK_EQ(cricket::MEDIA_TYPE_DATA, media_type);
3755 if (had_been_rejected) {
3756 session_options->media_description_options.push_back(
3757 GetMediaDescriptionOptionsForRejectedData(mid));
3758 } else {
3759 RTC_CHECK(pc_->GetDataMid());
3760 if (mid == *(pc_->GetDataMid())) {
3761 session_options->media_description_options.push_back(
3762 GetMediaDescriptionOptionsForActiveData(mid));
3763 } else {
3764 session_options->media_description_options.push_back(
3765 GetMediaDescriptionOptionsForRejectedData(mid));
3766 }
3767 }
3768 }
3769 }
3770
3771 // Next, look for transceivers that are newly added (that is, are not stopped
3772 // and not associated). Reuse media sections marked as recyclable first,
3773 // otherwise append to the end of the offer. New media sections should be
3774 // added in the order they were added to the PeerConnection.
3775 for (const auto& transceiver : transceivers()->List()) {
3776 if (transceiver->mid() || transceiver->stopping()) {
3777 continue;
3778 }
3779 size_t mline_index;
3780 if (!recycleable_mline_indices.empty()) {
3781 mline_index = recycleable_mline_indices.front();
3782 recycleable_mline_indices.pop();
3783 session_options->media_description_options[mline_index] =
3784 GetMediaDescriptionOptionsForTransceiver(
3785 transceiver, mid_generator_.GenerateString(),
3786 /*is_create_offer=*/true);
3787 } else {
3788 mline_index = session_options->media_description_options.size();
3789 session_options->media_description_options.push_back(
3790 GetMediaDescriptionOptionsForTransceiver(
3791 transceiver, mid_generator_.GenerateString(),
3792 /*is_create_offer=*/true));
3793 }
3794 // See comment above for why CreateOffer changes the transceiver's state.
3795 transceiver->internal()->set_mline_index(mline_index);
3796 }
3797 // Lastly, add a m-section if we have local data channels and an m section
3798 // does not already exist.
3799 if (!pc_->GetDataMid() && data_channel_controller()->HasDataChannels()) {
3800 session_options->media_description_options.push_back(
3801 GetMediaDescriptionOptionsForActiveData(
3802 mid_generator_.GenerateString()));
3803 }
3804 }
3805
GetOptionsForAnswer(const RTCOfferAnswerOptions & offer_answer_options,cricket::MediaSessionOptions * session_options)3806 void SdpOfferAnswerHandler::GetOptionsForAnswer(
3807 const RTCOfferAnswerOptions& offer_answer_options,
3808 cricket::MediaSessionOptions* session_options) {
3809 RTC_DCHECK_RUN_ON(signaling_thread());
3810 ExtractSharedMediaSessionOptions(offer_answer_options, session_options);
3811
3812 if (IsUnifiedPlan()) {
3813 GetOptionsForUnifiedPlanAnswer(offer_answer_options, session_options);
3814 } else {
3815 GetOptionsForPlanBAnswer(offer_answer_options, session_options);
3816 }
3817
3818 // Intentionally unset the data channel type for RTP data channel. Otherwise
3819 // the RTP data channels would be successfully negotiated by default and the
3820 // unit tests in WebRtcDataBrowserTest will fail when building with chromium.
3821 // We want to leave RTP data channels broken, so people won't try to use them.
3822 if (data_channel_controller()->HasRtpDataChannels() ||
3823 pc_->data_channel_type() != cricket::DCT_RTP) {
3824 session_options->data_channel_type = pc_->data_channel_type();
3825 }
3826
3827 // Apply ICE renomination flag.
3828 for (auto& options : session_options->media_description_options) {
3829 options.transport_options.enable_ice_renomination =
3830 pc_->configuration()->enable_ice_renomination;
3831 }
3832
3833 session_options->rtcp_cname = rtcp_cname_;
3834 session_options->crypto_options = pc_->GetCryptoOptions();
3835 session_options->pooled_ice_credentials =
3836 pc_->network_thread()->Invoke<std::vector<cricket::IceParameters>>(
3837 RTC_FROM_HERE,
3838 [this] { return port_allocator()->GetPooledIceCredentials(); });
3839 }
3840
GetOptionsForPlanBAnswer(const PeerConnectionInterface::RTCOfferAnswerOptions & offer_answer_options,cricket::MediaSessionOptions * session_options)3841 void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer(
3842 const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
3843 cricket::MediaSessionOptions* session_options) {
3844 // Figure out transceiver directional preferences.
3845 bool send_audio =
3846 !rtp_manager()->GetAudioTransceiver()->internal()->senders().empty();
3847 bool send_video =
3848 !rtp_manager()->GetVideoTransceiver()->internal()->senders().empty();
3849
3850 // By default, generate sendrecv/recvonly m= sections. The direction is also
3851 // restricted by the direction in the offer.
3852 bool recv_audio = true;
3853 bool recv_video = true;
3854
3855 // The "offer_to_receive_X" options allow those defaults to be overridden.
3856 if (offer_answer_options.offer_to_receive_audio !=
3857 RTCOfferAnswerOptions::kUndefined) {
3858 recv_audio = (offer_answer_options.offer_to_receive_audio > 0);
3859 }
3860 if (offer_answer_options.offer_to_receive_video !=
3861 RTCOfferAnswerOptions::kUndefined) {
3862 recv_video = (offer_answer_options.offer_to_receive_video > 0);
3863 }
3864
3865 absl::optional<size_t> audio_index;
3866 absl::optional<size_t> video_index;
3867 absl::optional<size_t> data_index;
3868
3869 // Generate m= sections that match those in the offer.
3870 // Note that mediasession.cc will handle intersection our preferred
3871 // direction with the offered direction.
3872 GenerateMediaDescriptionOptions(
3873 remote_description(),
3874 RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
3875 RtpTransceiverDirectionFromSendRecv(send_video, recv_video), &audio_index,
3876 &video_index, &data_index, session_options);
3877
3878 cricket::MediaDescriptionOptions* audio_media_description_options =
3879 !audio_index ? nullptr
3880 : &session_options->media_description_options[*audio_index];
3881 cricket::MediaDescriptionOptions* video_media_description_options =
3882 !video_index ? nullptr
3883 : &session_options->media_description_options[*video_index];
3884
3885 AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(),
3886 audio_media_description_options,
3887 video_media_description_options,
3888 offer_answer_options.num_simulcast_layers);
3889 }
3890
GetOptionsForUnifiedPlanAnswer(const PeerConnectionInterface::RTCOfferAnswerOptions & offer_answer_options,cricket::MediaSessionOptions * session_options)3891 void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanAnswer(
3892 const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
3893 cricket::MediaSessionOptions* session_options) {
3894 // Rules for generating an answer are dictated by JSEP sections 5.3.1 (Initial
3895 // Answers) and 5.3.2 (Subsequent Answers).
3896 RTC_DCHECK(remote_description());
3897 RTC_DCHECK(remote_description()->GetType() == SdpType::kOffer);
3898 for (const ContentInfo& content :
3899 remote_description()->description()->contents()) {
3900 cricket::MediaType media_type = content.media_description()->type();
3901 if (media_type == cricket::MEDIA_TYPE_AUDIO ||
3902 media_type == cricket::MEDIA_TYPE_VIDEO) {
3903 auto transceiver = transceivers()->FindByMid(content.name);
3904 if (transceiver) {
3905 session_options->media_description_options.push_back(
3906 GetMediaDescriptionOptionsForTransceiver(
3907 transceiver, content.name,
3908 /*is_create_offer=*/false));
3909 } else {
3910 // This should only happen with rejected transceivers.
3911 RTC_DCHECK(content.rejected);
3912 session_options->media_description_options.push_back(
3913 cricket::MediaDescriptionOptions(media_type, content.name,
3914 RtpTransceiverDirection::kInactive,
3915 /*stopped=*/true));
3916 }
3917 } else if (media_type == cricket::MEDIA_TYPE_UNSUPPORTED) {
3918 RTC_DCHECK(content.rejected);
3919 session_options->media_description_options.push_back(
3920 cricket::MediaDescriptionOptions(media_type, content.name,
3921 RtpTransceiverDirection::kInactive,
3922 /*stopped=*/true));
3923 } else {
3924 RTC_CHECK_EQ(cricket::MEDIA_TYPE_DATA, media_type);
3925 // Reject all data sections if data channels are disabled.
3926 // Reject a data section if it has already been rejected.
3927 // Reject all data sections except for the first one.
3928 if (pc_->data_channel_type() == cricket::DCT_NONE || content.rejected ||
3929 content.name != *(pc_->GetDataMid())) {
3930 session_options->media_description_options.push_back(
3931 GetMediaDescriptionOptionsForRejectedData(content.name));
3932 } else {
3933 session_options->media_description_options.push_back(
3934 GetMediaDescriptionOptionsForActiveData(content.name));
3935 }
3936 }
3937 }
3938 }
3939
SessionErrorToString(SessionError error) const3940 const char* SdpOfferAnswerHandler::SessionErrorToString(
3941 SessionError error) const {
3942 switch (error) {
3943 case SessionError::kNone:
3944 return "ERROR_NONE";
3945 case SessionError::kContent:
3946 return "ERROR_CONTENT";
3947 case SessionError::kTransport:
3948 return "ERROR_TRANSPORT";
3949 }
3950 RTC_NOTREACHED();
3951 return "";
3952 }
3953
GetSessionErrorMsg()3954 std::string SdpOfferAnswerHandler::GetSessionErrorMsg() {
3955 RTC_DCHECK_RUN_ON(signaling_thread());
3956 rtc::StringBuilder desc;
3957 desc << kSessionError << SessionErrorToString(session_error()) << ". ";
3958 desc << kSessionErrorDesc << session_error_desc() << ".";
3959 return desc.Release();
3960 }
3961
SetSessionError(SessionError error,const std::string & error_desc)3962 void SdpOfferAnswerHandler::SetSessionError(SessionError error,
3963 const std::string& error_desc) {
3964 RTC_DCHECK_RUN_ON(signaling_thread());
3965 if (error != session_error_) {
3966 session_error_ = error;
3967 session_error_desc_ = error_desc;
3968 }
3969 }
3970
HandleLegacyOfferOptions(const PeerConnectionInterface::RTCOfferAnswerOptions & options)3971 RTCError SdpOfferAnswerHandler::HandleLegacyOfferOptions(
3972 const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
3973 RTC_DCHECK_RUN_ON(signaling_thread());
3974 RTC_DCHECK(IsUnifiedPlan());
3975
3976 if (options.offer_to_receive_audio == 0) {
3977 RemoveRecvDirectionFromReceivingTransceiversOfType(
3978 cricket::MEDIA_TYPE_AUDIO);
3979 } else if (options.offer_to_receive_audio == 1) {
3980 AddUpToOneReceivingTransceiverOfType(cricket::MEDIA_TYPE_AUDIO);
3981 } else if (options.offer_to_receive_audio > 1) {
3982 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER,
3983 "offer_to_receive_audio > 1 is not supported.");
3984 }
3985
3986 if (options.offer_to_receive_video == 0) {
3987 RemoveRecvDirectionFromReceivingTransceiversOfType(
3988 cricket::MEDIA_TYPE_VIDEO);
3989 } else if (options.offer_to_receive_video == 1) {
3990 AddUpToOneReceivingTransceiverOfType(cricket::MEDIA_TYPE_VIDEO);
3991 } else if (options.offer_to_receive_video > 1) {
3992 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER,
3993 "offer_to_receive_video > 1 is not supported.");
3994 }
3995
3996 return RTCError::OK();
3997 }
3998
RemoveRecvDirectionFromReceivingTransceiversOfType(cricket::MediaType media_type)3999 void SdpOfferAnswerHandler::RemoveRecvDirectionFromReceivingTransceiversOfType(
4000 cricket::MediaType media_type) {
4001 for (const auto& transceiver : GetReceivingTransceiversOfType(media_type)) {
4002 RtpTransceiverDirection new_direction =
4003 RtpTransceiverDirectionWithRecvSet(transceiver->direction(), false);
4004 if (new_direction != transceiver->direction()) {
4005 RTC_LOG(LS_INFO) << "Changing " << cricket::MediaTypeToString(media_type)
4006 << " transceiver (MID="
4007 << transceiver->mid().value_or("<not set>") << ") from "
4008 << RtpTransceiverDirectionToString(
4009 transceiver->direction())
4010 << " to "
4011 << RtpTransceiverDirectionToString(new_direction)
4012 << " since CreateOffer specified offer_to_receive=0";
4013 transceiver->internal()->set_direction(new_direction);
4014 }
4015 }
4016 }
4017
AddUpToOneReceivingTransceiverOfType(cricket::MediaType media_type)4018 void SdpOfferAnswerHandler::AddUpToOneReceivingTransceiverOfType(
4019 cricket::MediaType media_type) {
4020 RTC_DCHECK_RUN_ON(signaling_thread());
4021 if (GetReceivingTransceiversOfType(media_type).empty()) {
4022 RTC_LOG(LS_INFO)
4023 << "Adding one recvonly " << cricket::MediaTypeToString(media_type)
4024 << " transceiver since CreateOffer specified offer_to_receive=1";
4025 RtpTransceiverInit init;
4026 init.direction = RtpTransceiverDirection::kRecvOnly;
4027 pc_->AddTransceiver(media_type, nullptr, init,
4028 /*update_negotiation_needed=*/false);
4029 }
4030 }
4031
4032 std::vector<rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
GetReceivingTransceiversOfType(cricket::MediaType media_type)4033 SdpOfferAnswerHandler::GetReceivingTransceiversOfType(
4034 cricket::MediaType media_type) {
4035 std::vector<
4036 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
4037 receiving_transceivers;
4038 for (const auto& transceiver : transceivers()->List()) {
4039 if (!transceiver->stopped() && transceiver->media_type() == media_type &&
4040 RtpTransceiverDirectionHasRecv(transceiver->direction())) {
4041 receiving_transceivers.push_back(transceiver);
4042 }
4043 }
4044 return receiving_transceivers;
4045 }
4046
ProcessRemovalOfRemoteTrack(rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>> transceiver,std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> * remove_list,std::vector<rtc::scoped_refptr<MediaStreamInterface>> * removed_streams)4047 void SdpOfferAnswerHandler::ProcessRemovalOfRemoteTrack(
4048 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
4049 transceiver,
4050 std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>* remove_list,
4051 std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
4052 RTC_DCHECK(transceiver->mid());
4053 RTC_LOG(LS_INFO) << "Processing the removal of a track for MID="
4054 << *transceiver->mid();
4055 std::vector<rtc::scoped_refptr<MediaStreamInterface>> previous_streams =
4056 transceiver->internal()->receiver_internal()->streams();
4057 // This will remove the remote track from the streams.
4058 transceiver->internal()->receiver_internal()->set_stream_ids({});
4059 remove_list->push_back(transceiver);
4060 RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
4061 }
4062
RemoveRemoteStreamsIfEmpty(const std::vector<rtc::scoped_refptr<MediaStreamInterface>> & remote_streams,std::vector<rtc::scoped_refptr<MediaStreamInterface>> * removed_streams)4063 void SdpOfferAnswerHandler::RemoveRemoteStreamsIfEmpty(
4064 const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& remote_streams,
4065 std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
4066 RTC_DCHECK_RUN_ON(signaling_thread());
4067 // TODO(https://crbug.com/webrtc/9480): When we use stream IDs instead of
4068 // streams, see if the stream was removed by checking if this was the last
4069 // receiver with that stream ID.
4070 for (const auto& remote_stream : remote_streams) {
4071 if (remote_stream->GetAudioTracks().empty() &&
4072 remote_stream->GetVideoTracks().empty()) {
4073 remote_streams_->RemoveStream(remote_stream);
4074 removed_streams->push_back(remote_stream);
4075 }
4076 }
4077 }
4078
RemoveSenders(cricket::MediaType media_type)4079 void SdpOfferAnswerHandler::RemoveSenders(cricket::MediaType media_type) {
4080 RTC_DCHECK_RUN_ON(signaling_thread());
4081 UpdateLocalSenders(std::vector<cricket::StreamParams>(), media_type);
4082 UpdateRemoteSendersList(std::vector<cricket::StreamParams>(), false,
4083 media_type, nullptr);
4084 }
4085
UpdateLocalSenders(const std::vector<cricket::StreamParams> & streams,cricket::MediaType media_type)4086 void SdpOfferAnswerHandler::UpdateLocalSenders(
4087 const std::vector<cricket::StreamParams>& streams,
4088 cricket::MediaType media_type) {
4089 RTC_DCHECK_RUN_ON(signaling_thread());
4090 std::vector<RtpSenderInfo>* current_senders =
4091 rtp_manager()->GetLocalSenderInfos(media_type);
4092
4093 // Find removed tracks. I.e., tracks where the track id, stream id or ssrc
4094 // don't match the new StreamParam.
4095 for (auto sender_it = current_senders->begin();
4096 sender_it != current_senders->end();
4097 /* incremented manually */) {
4098 const RtpSenderInfo& info = *sender_it;
4099 const cricket::StreamParams* params =
4100 cricket::GetStreamBySsrc(streams, info.first_ssrc);
4101 if (!params || params->id != info.sender_id ||
4102 params->first_stream_id() != info.stream_id) {
4103 rtp_manager()->OnLocalSenderRemoved(info, media_type);
4104 sender_it = current_senders->erase(sender_it);
4105 } else {
4106 ++sender_it;
4107 }
4108 }
4109
4110 // Find new and active senders.
4111 for (const cricket::StreamParams& params : streams) {
4112 // The sync_label is the MediaStream label and the |stream.id| is the
4113 // sender id.
4114 const std::string& stream_id = params.first_stream_id();
4115 const std::string& sender_id = params.id;
4116 uint32_t ssrc = params.first_ssrc();
4117 const RtpSenderInfo* sender_info =
4118 rtp_manager()->FindSenderInfo(*current_senders, stream_id, sender_id);
4119 if (!sender_info) {
4120 current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc));
4121 rtp_manager()->OnLocalSenderAdded(current_senders->back(), media_type);
4122 }
4123 }
4124 }
4125
UpdateRemoteSendersList(const cricket::StreamParamsVec & streams,bool default_sender_needed,cricket::MediaType media_type,StreamCollection * new_streams)4126 void SdpOfferAnswerHandler::UpdateRemoteSendersList(
4127 const cricket::StreamParamsVec& streams,
4128 bool default_sender_needed,
4129 cricket::MediaType media_type,
4130 StreamCollection* new_streams) {
4131 RTC_DCHECK_RUN_ON(signaling_thread());
4132 RTC_DCHECK(!IsUnifiedPlan());
4133
4134 std::vector<RtpSenderInfo>* current_senders =
4135 rtp_manager()->GetRemoteSenderInfos(media_type);
4136
4137 // Find removed senders. I.e., senders where the sender id or ssrc don't match
4138 // the new StreamParam.
4139 for (auto sender_it = current_senders->begin();
4140 sender_it != current_senders->end();
4141 /* incremented manually */) {
4142 const RtpSenderInfo& info = *sender_it;
4143 const cricket::StreamParams* params =
4144 cricket::GetStreamBySsrc(streams, info.first_ssrc);
4145 std::string params_stream_id;
4146 if (params) {
4147 params_stream_id =
4148 (!params->first_stream_id().empty() ? params->first_stream_id()
4149 : kDefaultStreamId);
4150 }
4151 bool sender_exists = params && params->id == info.sender_id &&
4152 params_stream_id == info.stream_id;
4153 // If this is a default track, and we still need it, don't remove it.
4154 if ((info.stream_id == kDefaultStreamId && default_sender_needed) ||
4155 sender_exists) {
4156 ++sender_it;
4157 } else {
4158 rtp_manager()->OnRemoteSenderRemoved(
4159 info, remote_streams_->find(info.stream_id), media_type);
4160 sender_it = current_senders->erase(sender_it);
4161 }
4162 }
4163
4164 // Find new and active senders.
4165 for (const cricket::StreamParams& params : streams) {
4166 if (!params.has_ssrcs()) {
4167 // The remote endpoint has streams, but didn't signal ssrcs. For an active
4168 // sender, this means it is coming from a Unified Plan endpoint,so we just
4169 // create a default.
4170 default_sender_needed = true;
4171 break;
4172 }
4173
4174 // |params.id| is the sender id and the stream id uses the first of
4175 // |params.stream_ids|. The remote description could come from a Unified
4176 // Plan endpoint, with multiple or no stream_ids() signaled. Since this is
4177 // not supported in Plan B, we just take the first here and create the
4178 // default stream ID if none is specified.
4179 const std::string& stream_id =
4180 (!params.first_stream_id().empty() ? params.first_stream_id()
4181 : kDefaultStreamId);
4182 const std::string& sender_id = params.id;
4183 uint32_t ssrc = params.first_ssrc();
4184
4185 rtc::scoped_refptr<MediaStreamInterface> stream =
4186 remote_streams_->find(stream_id);
4187 if (!stream) {
4188 // This is a new MediaStream. Create a new remote MediaStream.
4189 stream = MediaStreamProxy::Create(rtc::Thread::Current(),
4190 MediaStream::Create(stream_id));
4191 remote_streams_->AddStream(stream);
4192 new_streams->AddStream(stream);
4193 }
4194
4195 const RtpSenderInfo* sender_info =
4196 rtp_manager()->FindSenderInfo(*current_senders, stream_id, sender_id);
4197 if (!sender_info) {
4198 current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc));
4199 rtp_manager()->OnRemoteSenderAdded(current_senders->back(), stream,
4200 media_type);
4201 }
4202 }
4203
4204 // Add default sender if necessary.
4205 if (default_sender_needed) {
4206 rtc::scoped_refptr<MediaStreamInterface> default_stream =
4207 remote_streams_->find(kDefaultStreamId);
4208 if (!default_stream) {
4209 // Create the new default MediaStream.
4210 default_stream = MediaStreamProxy::Create(
4211 rtc::Thread::Current(), MediaStream::Create(kDefaultStreamId));
4212 remote_streams_->AddStream(default_stream);
4213 new_streams->AddStream(default_stream);
4214 }
4215 std::string default_sender_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
4216 ? kDefaultAudioSenderId
4217 : kDefaultVideoSenderId;
4218 const RtpSenderInfo* default_sender_info = rtp_manager()->FindSenderInfo(
4219 *current_senders, kDefaultStreamId, default_sender_id);
4220 if (!default_sender_info) {
4221 current_senders->push_back(
4222 RtpSenderInfo(kDefaultStreamId, default_sender_id, /*ssrc=*/0));
4223 rtp_manager()->OnRemoteSenderAdded(current_senders->back(),
4224 default_stream, media_type);
4225 }
4226 }
4227 }
4228
EnableSending()4229 void SdpOfferAnswerHandler::EnableSending() {
4230 RTC_DCHECK_RUN_ON(signaling_thread());
4231 for (const auto& transceiver : transceivers()->List()) {
4232 cricket::ChannelInterface* channel = transceiver->internal()->channel();
4233 if (channel && !channel->enabled()) {
4234 channel->Enable(true);
4235 }
4236 }
4237
4238 if (data_channel_controller()->rtp_data_channel() &&
4239 !data_channel_controller()->rtp_data_channel()->enabled()) {
4240 data_channel_controller()->rtp_data_channel()->Enable(true);
4241 }
4242 }
4243
PushdownMediaDescription(SdpType type,cricket::ContentSource source)4244 RTCError SdpOfferAnswerHandler::PushdownMediaDescription(
4245 SdpType type,
4246 cricket::ContentSource source) {
4247 const SessionDescriptionInterface* sdesc =
4248 (source == cricket::CS_LOCAL ? local_description()
4249 : remote_description());
4250 RTC_DCHECK_RUN_ON(signaling_thread());
4251 RTC_DCHECK(sdesc);
4252
4253 if (!UpdatePayloadTypeDemuxingState(source)) {
4254 // Note that this is never expected to fail, since RtpDemuxer doesn't return
4255 // an error when changing payload type demux criteria, which is all this
4256 // does.
4257 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
4258 "Failed to update payload type demuxing state.");
4259 }
4260
4261 // Push down the new SDP media section for each audio/video transceiver.
4262 for (const auto& transceiver : transceivers()->List()) {
4263 const ContentInfo* content_info =
4264 FindMediaSectionForTransceiver(transceiver, sdesc);
4265 cricket::ChannelInterface* channel = transceiver->internal()->channel();
4266 if (!channel || !content_info || content_info->rejected) {
4267 continue;
4268 }
4269 const MediaContentDescription* content_desc =
4270 content_info->media_description();
4271 if (!content_desc) {
4272 continue;
4273 }
4274 std::string error;
4275 bool success = (source == cricket::CS_LOCAL)
4276 ? channel->SetLocalContent(content_desc, type, &error)
4277 : channel->SetRemoteContent(content_desc, type, &error);
4278 if (!success) {
4279 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
4280 }
4281 }
4282
4283 // If using the RtpDataChannel, push down the new SDP section for it too.
4284 if (data_channel_controller()->rtp_data_channel()) {
4285 const ContentInfo* data_content =
4286 cricket::GetFirstDataContent(sdesc->description());
4287 if (data_content && !data_content->rejected) {
4288 const MediaContentDescription* data_desc =
4289 data_content->media_description();
4290 if (data_desc) {
4291 std::string error;
4292 bool success = (source == cricket::CS_LOCAL)
4293 ? data_channel_controller()
4294 ->rtp_data_channel()
4295 ->SetLocalContent(data_desc, type, &error)
4296 : data_channel_controller()
4297 ->rtp_data_channel()
4298 ->SetRemoteContent(data_desc, type, &error);
4299 if (!success) {
4300 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
4301 }
4302 }
4303 }
4304 }
4305
4306 // Need complete offer/answer with an SCTP m= section before starting SCTP,
4307 // according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
4308 if (pc_->sctp_mid() && local_description() && remote_description()) {
4309 auto local_sctp_description = cricket::GetFirstSctpDataContentDescription(
4310 local_description()->description());
4311 auto remote_sctp_description = cricket::GetFirstSctpDataContentDescription(
4312 remote_description()->description());
4313 if (local_sctp_description && remote_sctp_description) {
4314 int max_message_size;
4315 // A remote max message size of zero means "any size supported".
4316 // We configure the connection with our own max message size.
4317 if (remote_sctp_description->max_message_size() == 0) {
4318 max_message_size = local_sctp_description->max_message_size();
4319 } else {
4320 max_message_size =
4321 std::min(local_sctp_description->max_message_size(),
4322 remote_sctp_description->max_message_size());
4323 }
4324 pc_->StartSctpTransport(local_sctp_description->port(),
4325 remote_sctp_description->port(),
4326 max_message_size);
4327 }
4328 }
4329
4330 return RTCError::OK();
4331 }
4332
PushdownTransportDescription(cricket::ContentSource source,SdpType type)4333 RTCError SdpOfferAnswerHandler::PushdownTransportDescription(
4334 cricket::ContentSource source,
4335 SdpType type) {
4336 RTC_DCHECK_RUN_ON(signaling_thread());
4337
4338 if (source == cricket::CS_LOCAL) {
4339 const SessionDescriptionInterface* sdesc = local_description();
4340 RTC_DCHECK(sdesc);
4341 return transport_controller()->SetLocalDescription(type,
4342 sdesc->description());
4343 } else {
4344 const SessionDescriptionInterface* sdesc = remote_description();
4345 RTC_DCHECK(sdesc);
4346 return transport_controller()->SetRemoteDescription(type,
4347 sdesc->description());
4348 }
4349 }
4350
RemoveStoppedTransceivers()4351 void SdpOfferAnswerHandler::RemoveStoppedTransceivers() {
4352 RTC_DCHECK_RUN_ON(signaling_thread());
4353 // 3.2.10.1: For each transceiver in the connection's set of transceivers
4354 // run the following steps:
4355 if (!IsUnifiedPlan())
4356 return;
4357 // Traverse a copy of the transceiver list.
4358 auto transceiver_list = transceivers()->List();
4359 for (auto transceiver : transceiver_list) {
4360 // 3.2.10.1.1: If transceiver is stopped, associated with an m= section
4361 // and the associated m= section is rejected in
4362 // connection.[[CurrentLocalDescription]] or
4363 // connection.[[CurrentRemoteDescription]], remove the
4364 // transceiver from the connection's set of transceivers.
4365 if (!transceiver->stopped()) {
4366 continue;
4367 }
4368 const ContentInfo* local_content =
4369 FindMediaSectionForTransceiver(transceiver, local_description());
4370 const ContentInfo* remote_content =
4371 FindMediaSectionForTransceiver(transceiver, remote_description());
4372 if ((local_content && local_content->rejected) ||
4373 (remote_content && remote_content->rejected)) {
4374 RTC_LOG(LS_INFO) << "Dissociating transceiver"
4375 << " since the media section is being recycled.";
4376 transceiver->internal()->set_mid(absl::nullopt);
4377 transceiver->internal()->set_mline_index(absl::nullopt);
4378 transceivers()->Remove(transceiver);
4379 continue;
4380 }
4381 if (!local_content && !remote_content) {
4382 // TODO(bugs.webrtc.org/11973): Consider if this should be removed already
4383 // See https://github.com/w3c/webrtc-pc/issues/2576
4384 RTC_LOG(LS_INFO)
4385 << "Dropping stopped transceiver that was never associated";
4386 transceivers()->Remove(transceiver);
4387 continue;
4388 }
4389 }
4390 }
4391
RemoveUnusedChannels(const SessionDescription * desc)4392 void SdpOfferAnswerHandler::RemoveUnusedChannels(
4393 const SessionDescription* desc) {
4394 RTC_DCHECK_RUN_ON(signaling_thread());
4395 // Destroy video channel first since it may have a pointer to the
4396 // voice channel.
4397 const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc);
4398 if (!video_info || video_info->rejected) {
4399 DestroyTransceiverChannel(rtp_manager()->GetVideoTransceiver());
4400 }
4401
4402 const cricket::ContentInfo* audio_info = cricket::GetFirstAudioContent(desc);
4403 if (!audio_info || audio_info->rejected) {
4404 DestroyTransceiverChannel(rtp_manager()->GetAudioTransceiver());
4405 }
4406
4407 const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc);
4408 if (!data_info || data_info->rejected) {
4409 DestroyDataChannelTransport();
4410 }
4411 }
4412
ReportNegotiatedSdpSemantics(const SessionDescriptionInterface & answer)4413 void SdpOfferAnswerHandler::ReportNegotiatedSdpSemantics(
4414 const SessionDescriptionInterface& answer) {
4415 SdpSemanticNegotiated semantics_negotiated;
4416 switch (answer.description()->msid_signaling()) {
4417 case 0:
4418 semantics_negotiated = kSdpSemanticNegotiatedNone;
4419 break;
4420 case cricket::kMsidSignalingMediaSection:
4421 semantics_negotiated = kSdpSemanticNegotiatedUnifiedPlan;
4422 break;
4423 case cricket::kMsidSignalingSsrcAttribute:
4424 semantics_negotiated = kSdpSemanticNegotiatedPlanB;
4425 break;
4426 case cricket::kMsidSignalingMediaSection |
4427 cricket::kMsidSignalingSsrcAttribute:
4428 semantics_negotiated = kSdpSemanticNegotiatedMixed;
4429 break;
4430 default:
4431 RTC_NOTREACHED();
4432 }
4433 RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SdpSemanticNegotiated",
4434 semantics_negotiated, kSdpSemanticNegotiatedMax);
4435 }
4436
UpdateEndedRemoteMediaStreams()4437 void SdpOfferAnswerHandler::UpdateEndedRemoteMediaStreams() {
4438 RTC_DCHECK_RUN_ON(signaling_thread());
4439 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
4440 for (size_t i = 0; i < remote_streams_->count(); ++i) {
4441 MediaStreamInterface* stream = remote_streams_->at(i);
4442 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
4443 streams_to_remove.push_back(stream);
4444 }
4445 }
4446
4447 for (auto& stream : streams_to_remove) {
4448 remote_streams_->RemoveStream(stream);
4449 pc_->Observer()->OnRemoveStream(std::move(stream));
4450 }
4451 }
4452
UseCandidatesInSessionDescription(const SessionDescriptionInterface * remote_desc)4453 bool SdpOfferAnswerHandler::UseCandidatesInSessionDescription(
4454 const SessionDescriptionInterface* remote_desc) {
4455 RTC_DCHECK_RUN_ON(signaling_thread());
4456 if (!remote_desc) {
4457 return true;
4458 }
4459 bool ret = true;
4460
4461 for (size_t m = 0; m < remote_desc->number_of_mediasections(); ++m) {
4462 const IceCandidateCollection* candidates = remote_desc->candidates(m);
4463 for (size_t n = 0; n < candidates->count(); ++n) {
4464 const IceCandidateInterface* candidate = candidates->at(n);
4465 bool valid = false;
4466 if (!ReadyToUseRemoteCandidate(candidate, remote_desc, &valid)) {
4467 if (valid) {
4468 RTC_LOG(LS_INFO)
4469 << "UseCandidatesInSessionDescription: Not ready to use "
4470 "candidate.";
4471 }
4472 continue;
4473 }
4474 ret = UseCandidate(candidate);
4475 if (!ret) {
4476 break;
4477 }
4478 }
4479 }
4480 return ret;
4481 }
4482
UseCandidate(const IceCandidateInterface * candidate)4483 bool SdpOfferAnswerHandler::UseCandidate(
4484 const IceCandidateInterface* candidate) {
4485 RTC_DCHECK_RUN_ON(signaling_thread());
4486
4487 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
4488
4489 RTCErrorOr<const cricket::ContentInfo*> result =
4490 FindContentInfo(remote_description(), candidate);
4491 if (!result.ok())
4492 return false;
4493
4494 const cricket::Candidate& c = candidate->candidate();
4495 RTCError error = cricket::VerifyCandidate(c);
4496 if (!error.ok()) {
4497 RTC_LOG(LS_WARNING) << "Invalid candidate: " << c.ToString();
4498 return true;
4499 }
4500
4501 pc_->AddRemoteCandidate(result.value()->name, c);
4502
4503 return true;
4504 }
4505
4506 // We need to check the local/remote description for the Transport instead of
4507 // the session, because a new Transport added during renegotiation may have
4508 // them unset while the session has them set from the previous negotiation.
4509 // Not doing so may trigger the auto generation of transport description and
4510 // mess up DTLS identity information, ICE credential, etc.
ReadyToUseRemoteCandidate(const IceCandidateInterface * candidate,const SessionDescriptionInterface * remote_desc,bool * valid)4511 bool SdpOfferAnswerHandler::ReadyToUseRemoteCandidate(
4512 const IceCandidateInterface* candidate,
4513 const SessionDescriptionInterface* remote_desc,
4514 bool* valid) {
4515 RTC_DCHECK_RUN_ON(signaling_thread());
4516 *valid = true;
4517
4518 const SessionDescriptionInterface* current_remote_desc =
4519 remote_desc ? remote_desc : remote_description();
4520
4521 if (!current_remote_desc) {
4522 return false;
4523 }
4524
4525 RTCErrorOr<const cricket::ContentInfo*> result =
4526 FindContentInfo(current_remote_desc, candidate);
4527 if (!result.ok()) {
4528 RTC_LOG(LS_ERROR) << "ReadyToUseRemoteCandidate: Invalid candidate. "
4529 << result.error().message();
4530
4531 *valid = false;
4532 return false;
4533 }
4534
4535 return true;
4536 }
4537
FindContentInfo(const SessionDescriptionInterface * description,const IceCandidateInterface * candidate)4538 RTCErrorOr<const cricket::ContentInfo*> SdpOfferAnswerHandler::FindContentInfo(
4539 const SessionDescriptionInterface* description,
4540 const IceCandidateInterface* candidate) {
4541 if (!candidate->sdp_mid().empty()) {
4542 auto& contents = description->description()->contents();
4543 auto it = absl::c_find_if(
4544 contents, [candidate](const cricket::ContentInfo& content_info) {
4545 return content_info.mid() == candidate->sdp_mid();
4546 });
4547 if (it == contents.end()) {
4548 return RTCError(
4549 RTCErrorType::INVALID_PARAMETER,
4550 "Mid " + candidate->sdp_mid() +
4551 " specified but no media section with that mid found.");
4552 } else {
4553 return &*it;
4554 }
4555 } else if (candidate->sdp_mline_index() >= 0) {
4556 size_t mediacontent_index =
4557 static_cast<size_t>(candidate->sdp_mline_index());
4558 size_t content_size = description->description()->contents().size();
4559 if (mediacontent_index < content_size) {
4560 return &description->description()->contents()[mediacontent_index];
4561 } else {
4562 return RTCError(RTCErrorType::INVALID_RANGE,
4563 "Media line index (" +
4564 rtc::ToString(candidate->sdp_mline_index()) +
4565 ") out of range (number of mlines: " +
4566 rtc::ToString(content_size) + ").");
4567 }
4568 }
4569
4570 return RTCError(RTCErrorType::INVALID_PARAMETER,
4571 "Neither sdp_mline_index nor sdp_mid specified.");
4572 }
4573
CreateChannels(const SessionDescription & desc)4574 RTCError SdpOfferAnswerHandler::CreateChannels(const SessionDescription& desc) {
4575 // Creating the media channels. Transports should already have been created
4576 // at this point.
4577 RTC_DCHECK_RUN_ON(signaling_thread());
4578 const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(&desc);
4579 if (voice && !voice->rejected &&
4580 !rtp_manager()->GetAudioTransceiver()->internal()->channel()) {
4581 cricket::VoiceChannel* voice_channel = CreateVoiceChannel(voice->name);
4582 if (!voice_channel) {
4583 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
4584 "Failed to create voice channel.");
4585 }
4586 rtp_manager()->GetAudioTransceiver()->internal()->SetChannel(voice_channel);
4587 }
4588
4589 const cricket::ContentInfo* video = cricket::GetFirstVideoContent(&desc);
4590 if (video && !video->rejected &&
4591 !rtp_manager()->GetVideoTransceiver()->internal()->channel()) {
4592 cricket::VideoChannel* video_channel = CreateVideoChannel(video->name);
4593 if (!video_channel) {
4594 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
4595 "Failed to create video channel.");
4596 }
4597 rtp_manager()->GetVideoTransceiver()->internal()->SetChannel(video_channel);
4598 }
4599
4600 const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc);
4601 if (pc_->data_channel_type() != cricket::DCT_NONE && data &&
4602 !data->rejected && !data_channel_controller()->rtp_data_channel() &&
4603 !data_channel_controller()->data_channel_transport()) {
4604 if (!CreateDataChannel(data->name)) {
4605 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
4606 "Failed to create data channel.");
4607 }
4608 }
4609
4610 return RTCError::OK();
4611 }
4612
4613 // TODO(steveanton): Perhaps this should be managed by the RtpTransceiver.
CreateVoiceChannel(const std::string & mid)4614 cricket::VoiceChannel* SdpOfferAnswerHandler::CreateVoiceChannel(
4615 const std::string& mid) {
4616 RTC_DCHECK_RUN_ON(signaling_thread());
4617 RtpTransportInternal* rtp_transport = pc_->GetRtpTransport(mid);
4618
4619 // TODO(bugs.webrtc.org/11992): CreateVoiceChannel internally switches to the
4620 // worker thread. We shouldn't be using the |call_ptr_| hack here but simply
4621 // be on the worker thread and use |call_| (update upstream code).
4622 cricket::VoiceChannel* voice_channel = channel_manager()->CreateVoiceChannel(
4623 pc_->call_ptr(), pc_->configuration()->media_config, rtp_transport,
4624 signaling_thread(), mid, pc_->SrtpRequired(), pc_->GetCryptoOptions(),
4625 &ssrc_generator_, audio_options());
4626
4627 if (!voice_channel) {
4628 return nullptr;
4629 }
4630 voice_channel->SignalSentPacket().connect(pc_,
4631 &PeerConnection::OnSentPacket_w);
4632 return voice_channel;
4633 }
4634
4635 // TODO(steveanton): Perhaps this should be managed by the RtpTransceiver.
CreateVideoChannel(const std::string & mid)4636 cricket::VideoChannel* SdpOfferAnswerHandler::CreateVideoChannel(
4637 const std::string& mid) {
4638 RTC_DCHECK_RUN_ON(signaling_thread());
4639 // NOTE: This involves a non-ideal hop (Invoke) over to the network thread.
4640 RtpTransportInternal* rtp_transport = pc_->GetRtpTransport(mid);
4641
4642 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to the
4643 // worker thread. We shouldn't be using the |call_ptr_| hack here but simply
4644 // be on the worker thread and use |call_| (update upstream code).
4645 cricket::VideoChannel* video_channel = channel_manager()->CreateVideoChannel(
4646 pc_->call_ptr(), pc_->configuration()->media_config, rtp_transport,
4647 signaling_thread(), mid, pc_->SrtpRequired(), pc_->GetCryptoOptions(),
4648 &ssrc_generator_, video_options(),
4649 video_bitrate_allocator_factory_.get());
4650 if (!video_channel) {
4651 return nullptr;
4652 }
4653 video_channel->SignalSentPacket().connect(pc_,
4654 &PeerConnection::OnSentPacket_w);
4655 return video_channel;
4656 }
4657
CreateDataChannel(const std::string & mid)4658 bool SdpOfferAnswerHandler::CreateDataChannel(const std::string& mid) {
4659 RTC_DCHECK_RUN_ON(signaling_thread());
4660 switch (pc_->data_channel_type()) {
4661 case cricket::DCT_SCTP:
4662 if (pc_->network_thread()->Invoke<bool>(RTC_FROM_HERE, [this, &mid] {
4663 RTC_DCHECK_RUN_ON(pc_->network_thread());
4664 return pc_->SetupDataChannelTransport_n(mid);
4665 })) {
4666 pc_->SetSctpDataMid(mid);
4667 } else {
4668 return false;
4669 }
4670 return true;
4671 case cricket::DCT_RTP:
4672 default:
4673 RtpTransportInternal* rtp_transport = pc_->GetRtpTransport(mid);
4674 cricket::RtpDataChannel* data_channel =
4675 channel_manager()->CreateRtpDataChannel(
4676 pc_->configuration()->media_config, rtp_transport,
4677 signaling_thread(), mid, pc_->SrtpRequired(),
4678 pc_->GetCryptoOptions(), &ssrc_generator_);
4679 if (!data_channel)
4680 return false;
4681
4682 pc_->network_thread()->Invoke<void>(RTC_FROM_HERE, [this, data_channel] {
4683 RTC_DCHECK_RUN_ON(pc_->network_thread());
4684 pc_->SetupRtpDataChannelTransport_n(data_channel);
4685 });
4686 have_pending_rtp_data_channel_ = true;
4687 return true;
4688 }
4689 return false;
4690 }
4691
DestroyTransceiverChannel(rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>> transceiver)4692 void SdpOfferAnswerHandler::DestroyTransceiverChannel(
4693 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
4694 transceiver) {
4695 RTC_DCHECK(transceiver);
4696 RTC_LOG_THREAD_BLOCK_COUNT();
4697
4698 // TODO(tommi): We're currently on the signaling thread.
4699 // There are multiple hops to the worker ahead.
4700 // Consider if we can make the call to SetChannel() on the worker thread
4701 // (and require that to be the context it's always called in) and also
4702 // call DestroyChannelInterface there, since it also needs to hop to the
4703 // worker.
4704
4705 cricket::ChannelInterface* channel = transceiver->internal()->channel();
4706 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(0);
4707 if (channel) {
4708 // TODO(tommi): VideoRtpReceiver::SetMediaChannel blocks and jumps to the
4709 // worker thread. When being set to nullptr, there are additional blocking
4710 // calls to e.g. ClearRecordableEncodedFrameCallback which triggers another
4711 // blocking call or Stop() for video channels.
4712 transceiver->internal()->SetChannel(nullptr);
4713 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
4714 // TODO(tommi): All channel objects end up getting deleted on the
4715 // worker thread. Can DestroyTransceiverChannel be purely posted to the
4716 // worker?
4717 DestroyChannelInterface(channel);
4718 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(3);
4719 }
4720 }
4721
DestroyDataChannelTransport()4722 void SdpOfferAnswerHandler::DestroyDataChannelTransport() {
4723 RTC_DCHECK_RUN_ON(signaling_thread());
4724 const bool has_sctp = pc_->sctp_mid().has_value();
4725 auto* rtp_data_channel = data_channel_controller()->rtp_data_channel();
4726
4727 if (has_sctp || rtp_data_channel)
4728 data_channel_controller()->OnTransportChannelClosed();
4729
4730 pc_->network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
4731 RTC_DCHECK_RUN_ON(pc_->network_thread());
4732 pc_->TeardownDataChannelTransport_n();
4733 });
4734
4735 if (has_sctp)
4736 pc_->ResetSctpDataMid();
4737
4738 if (rtp_data_channel)
4739 DestroyChannelInterface(rtp_data_channel);
4740 }
4741
DestroyChannelInterface(cricket::ChannelInterface * channel)4742 void SdpOfferAnswerHandler::DestroyChannelInterface(
4743 cricket::ChannelInterface* channel) {
4744 // TODO(bugs.webrtc.org/11992): All the below methods should be called on the
4745 // worker thread. (they switch internally anyway). Change
4746 // DestroyChannelInterface to either be called on the worker thread, or do
4747 // this asynchronously on the worker.
4748 RTC_DCHECK(channel);
4749
4750 RTC_LOG_THREAD_BLOCK_COUNT();
4751
4752 switch (channel->media_type()) {
4753 case cricket::MEDIA_TYPE_AUDIO:
4754 channel_manager()->DestroyVoiceChannel(
4755 static_cast<cricket::VoiceChannel*>(channel));
4756 break;
4757 case cricket::MEDIA_TYPE_VIDEO:
4758 channel_manager()->DestroyVideoChannel(
4759 static_cast<cricket::VideoChannel*>(channel));
4760 break;
4761 case cricket::MEDIA_TYPE_DATA:
4762 channel_manager()->DestroyRtpDataChannel(
4763 static_cast<cricket::RtpDataChannel*>(channel));
4764 break;
4765 default:
4766 RTC_NOTREACHED() << "Unknown media type: " << channel->media_type();
4767 break;
4768 }
4769
4770 // TODO(tommi): Figure out why we can get 2 blocking calls when running
4771 // PeerConnectionCryptoTest.CreateAnswerWithDifferentSslRoles.
4772 // and 3 when running
4773 // PeerConnectionCryptoTest.CreateAnswerWithDifferentSslRoles
4774 // RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
4775 }
4776
DestroyAllChannels()4777 void SdpOfferAnswerHandler::DestroyAllChannels() {
4778 RTC_DCHECK_RUN_ON(signaling_thread());
4779 if (!transceivers()) {
4780 return;
4781 }
4782
4783 RTC_LOG_THREAD_BLOCK_COUNT();
4784
4785 // Destroy video channels first since they may have a pointer to a voice
4786 // channel.
4787 auto list = transceivers()->List();
4788 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(0);
4789
4790 for (const auto& transceiver : list) {
4791 if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
4792 DestroyTransceiverChannel(transceiver);
4793 }
4794 }
4795 for (const auto& transceiver : list) {
4796 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
4797 DestroyTransceiverChannel(transceiver);
4798 }
4799 }
4800
4801 DestroyDataChannelTransport();
4802 }
4803
GenerateMediaDescriptionOptions(const SessionDescriptionInterface * session_desc,RtpTransceiverDirection audio_direction,RtpTransceiverDirection video_direction,absl::optional<size_t> * audio_index,absl::optional<size_t> * video_index,absl::optional<size_t> * data_index,cricket::MediaSessionOptions * session_options)4804 void SdpOfferAnswerHandler::GenerateMediaDescriptionOptions(
4805 const SessionDescriptionInterface* session_desc,
4806 RtpTransceiverDirection audio_direction,
4807 RtpTransceiverDirection video_direction,
4808 absl::optional<size_t>* audio_index,
4809 absl::optional<size_t>* video_index,
4810 absl::optional<size_t>* data_index,
4811 cricket::MediaSessionOptions* session_options) {
4812 RTC_DCHECK_RUN_ON(signaling_thread());
4813 for (const cricket::ContentInfo& content :
4814 session_desc->description()->contents()) {
4815 if (IsAudioContent(&content)) {
4816 // If we already have an audio m= section, reject this extra one.
4817 if (*audio_index) {
4818 session_options->media_description_options.push_back(
4819 cricket::MediaDescriptionOptions(
4820 cricket::MEDIA_TYPE_AUDIO, content.name,
4821 RtpTransceiverDirection::kInactive, /*stopped=*/true));
4822 } else {
4823 bool stopped = (audio_direction == RtpTransceiverDirection::kInactive);
4824 session_options->media_description_options.push_back(
4825 cricket::MediaDescriptionOptions(cricket::MEDIA_TYPE_AUDIO,
4826 content.name, audio_direction,
4827 stopped));
4828 *audio_index = session_options->media_description_options.size() - 1;
4829 }
4830 session_options->media_description_options.back().header_extensions =
4831 channel_manager()->GetSupportedAudioRtpHeaderExtensions();
4832 } else if (IsVideoContent(&content)) {
4833 // If we already have an video m= section, reject this extra one.
4834 if (*video_index) {
4835 session_options->media_description_options.push_back(
4836 cricket::MediaDescriptionOptions(
4837 cricket::MEDIA_TYPE_VIDEO, content.name,
4838 RtpTransceiverDirection::kInactive, /*stopped=*/true));
4839 } else {
4840 bool stopped = (video_direction == RtpTransceiverDirection::kInactive);
4841 session_options->media_description_options.push_back(
4842 cricket::MediaDescriptionOptions(cricket::MEDIA_TYPE_VIDEO,
4843 content.name, video_direction,
4844 stopped));
4845 *video_index = session_options->media_description_options.size() - 1;
4846 }
4847 session_options->media_description_options.back().header_extensions =
4848 channel_manager()->GetSupportedVideoRtpHeaderExtensions();
4849 } else if (IsUnsupportedContent(&content)) {
4850 session_options->media_description_options.push_back(
4851 cricket::MediaDescriptionOptions(cricket::MEDIA_TYPE_UNSUPPORTED,
4852 content.name,
4853 RtpTransceiverDirection::kInactive,
4854 /*stopped=*/true));
4855 } else {
4856 RTC_DCHECK(IsDataContent(&content));
4857 // If we already have an data m= section, reject this extra one.
4858 if (*data_index) {
4859 session_options->media_description_options.push_back(
4860 GetMediaDescriptionOptionsForRejectedData(content.name));
4861 } else {
4862 session_options->media_description_options.push_back(
4863 GetMediaDescriptionOptionsForActiveData(content.name));
4864 *data_index = session_options->media_description_options.size() - 1;
4865 }
4866 }
4867 }
4868 }
4869
4870 cricket::MediaDescriptionOptions
GetMediaDescriptionOptionsForActiveData(const std::string & mid) const4871 SdpOfferAnswerHandler::GetMediaDescriptionOptionsForActiveData(
4872 const std::string& mid) const {
4873 RTC_DCHECK_RUN_ON(signaling_thread());
4874 // Direction for data sections is meaningless, but legacy endpoints might
4875 // expect sendrecv.
4876 cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
4877 RtpTransceiverDirection::kSendRecv,
4878 /*stopped=*/false);
4879 AddRtpDataChannelOptions(*(data_channel_controller()->rtp_data_channels()),
4880 &options);
4881 return options;
4882 }
4883
4884 cricket::MediaDescriptionOptions
GetMediaDescriptionOptionsForRejectedData(const std::string & mid) const4885 SdpOfferAnswerHandler::GetMediaDescriptionOptionsForRejectedData(
4886 const std::string& mid) const {
4887 RTC_DCHECK_RUN_ON(signaling_thread());
4888 cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
4889 RtpTransceiverDirection::kInactive,
4890 /*stopped=*/true);
4891 AddRtpDataChannelOptions(*(data_channel_controller()->rtp_data_channels()),
4892 &options);
4893 return options;
4894 }
4895
UpdatePayloadTypeDemuxingState(cricket::ContentSource source)4896 bool SdpOfferAnswerHandler::UpdatePayloadTypeDemuxingState(
4897 cricket::ContentSource source) {
4898 RTC_DCHECK_RUN_ON(signaling_thread());
4899 // We may need to delete any created default streams and disable creation of
4900 // new ones on the basis of payload type. This is needed to avoid SSRC
4901 // collisions in Call's RtpDemuxer, in the case that a transceiver has
4902 // created a default stream, and then some other channel gets the SSRC
4903 // signaled in the corresponding Unified Plan "m=" section. Specifically, we
4904 // need to disable payload type based demuxing when two bundled "m=" sections
4905 // are using the same payload type(s). For more context
4906 // see https://bugs.chromium.org/p/webrtc/issues/detail?id=11477
4907 const SessionDescriptionInterface* sdesc =
4908 (source == cricket::CS_LOCAL ? local_description()
4909 : remote_description());
4910 const cricket::ContentGroup* bundle_group =
4911 sdesc->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
4912 std::set<int> audio_payload_types;
4913 std::set<int> video_payload_types;
4914 bool pt_demuxing_enabled_audio = true;
4915 bool pt_demuxing_enabled_video = true;
4916 for (auto& content_info : sdesc->description()->contents()) {
4917 // If this m= section isn't bundled, it's safe to demux by payload type
4918 // since other m= sections using the same payload type will also be using
4919 // different transports.
4920 if (!bundle_group || !bundle_group->HasContentName(content_info.name)) {
4921 continue;
4922 }
4923 if (content_info.rejected ||
4924 (source == cricket::ContentSource::CS_LOCAL &&
4925 !RtpTransceiverDirectionHasRecv(
4926 content_info.media_description()->direction())) ||
4927 (source == cricket::ContentSource::CS_REMOTE &&
4928 !RtpTransceiverDirectionHasSend(
4929 content_info.media_description()->direction()))) {
4930 // Ignore transceivers that are not receiving.
4931 continue;
4932 }
4933 switch (content_info.media_description()->type()) {
4934 case cricket::MediaType::MEDIA_TYPE_AUDIO: {
4935 const cricket::AudioContentDescription* audio_desc =
4936 content_info.media_description()->as_audio();
4937 for (const cricket::AudioCodec& audio : audio_desc->codecs()) {
4938 if (audio_payload_types.count(audio.id)) {
4939 // Two m= sections are using the same payload type, thus demuxing
4940 // by payload type is not possible.
4941 pt_demuxing_enabled_audio = false;
4942 }
4943 audio_payload_types.insert(audio.id);
4944 }
4945 break;
4946 }
4947 case cricket::MediaType::MEDIA_TYPE_VIDEO: {
4948 const cricket::VideoContentDescription* video_desc =
4949 content_info.media_description()->as_video();
4950 for (const cricket::VideoCodec& video : video_desc->codecs()) {
4951 if (video_payload_types.count(video.id)) {
4952 // Two m= sections are using the same payload type, thus demuxing
4953 // by payload type is not possible.
4954 pt_demuxing_enabled_video = false;
4955 }
4956 video_payload_types.insert(video.id);
4957 }
4958 break;
4959 }
4960 default:
4961 // Ignore data channels.
4962 continue;
4963 }
4964 }
4965
4966 // Gather all updates ahead of time so that all channels can be updated in a
4967 // single Invoke; necessary due to thread guards.
4968 std::vector<std::pair<RtpTransceiverDirection, cricket::ChannelInterface*>>
4969 channels_to_update;
4970 for (const auto& transceiver : transceivers()->List()) {
4971 cricket::ChannelInterface* channel = transceiver->internal()->channel();
4972 const ContentInfo* content =
4973 FindMediaSectionForTransceiver(transceiver, sdesc);
4974 if (!channel || !content) {
4975 continue;
4976 }
4977 RtpTransceiverDirection local_direction =
4978 content->media_description()->direction();
4979 if (source == cricket::CS_REMOTE) {
4980 local_direction = RtpTransceiverDirectionReversed(local_direction);
4981 }
4982 channels_to_update.emplace_back(local_direction,
4983 transceiver->internal()->channel());
4984 }
4985
4986 if (channels_to_update.empty()) {
4987 return true;
4988 }
4989 return pc_->worker_thread()->Invoke<bool>(
4990 RTC_FROM_HERE, [&channels_to_update, bundle_group,
4991 pt_demuxing_enabled_audio, pt_demuxing_enabled_video]() {
4992 for (const auto& it : channels_to_update) {
4993 RtpTransceiverDirection local_direction = it.first;
4994 cricket::ChannelInterface* channel = it.second;
4995 cricket::MediaType media_type = channel->media_type();
4996 bool in_bundle_group = (bundle_group && bundle_group->HasContentName(
4997 channel->content_name()));
4998 if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO) {
4999 if (!channel->SetPayloadTypeDemuxingEnabled(
5000 (!in_bundle_group || pt_demuxing_enabled_audio) &&
5001 RtpTransceiverDirectionHasRecv(local_direction))) {
5002 return false;
5003 }
5004 } else if (media_type == cricket::MediaType::MEDIA_TYPE_VIDEO) {
5005 if (!channel->SetPayloadTypeDemuxingEnabled(
5006 (!in_bundle_group || pt_demuxing_enabled_video) &&
5007 RtpTransceiverDirectionHasRecv(local_direction))) {
5008 return false;
5009 }
5010 }
5011 }
5012 return true;
5013 });
5014 }
5015
5016 } // namespace webrtc
5017