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