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 ¤t_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