1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2017 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/rtp_transceiver.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <iterator>
15*d9f75844SAndroid Build Coastguard Worker #include <string>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker #include <vector>
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
20*d9f75844SAndroid Build Coastguard Worker #include "absl/memory/memory.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/peer_connection_interface.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/rtp_parameters.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/sequence_checker.h"
24*d9f75844SAndroid Build Coastguard Worker #include "media/base/codec.h"
25*d9f75844SAndroid Build Coastguard Worker #include "media/base/media_constants.h"
26*d9f75844SAndroid Build Coastguard Worker #include "media/base/media_engine.h"
27*d9f75844SAndroid Build Coastguard Worker #include "pc/channel.h"
28*d9f75844SAndroid Build Coastguard Worker #include "pc/rtp_media_utils.h"
29*d9f75844SAndroid Build Coastguard Worker #include "pc/session_description.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread.h"
33*d9f75844SAndroid Build Coastguard Worker
34*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
35*d9f75844SAndroid Build Coastguard Worker namespace {
36*d9f75844SAndroid Build Coastguard Worker template <class T>
VerifyCodecPreferences(const std::vector<RtpCodecCapability> & codecs,const std::vector<T> & send_codecs,const std::vector<T> & recv_codecs)37*d9f75844SAndroid Build Coastguard Worker RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
38*d9f75844SAndroid Build Coastguard Worker const std::vector<T>& send_codecs,
39*d9f75844SAndroid Build Coastguard Worker const std::vector<T>& recv_codecs) {
40*d9f75844SAndroid Build Coastguard Worker // If the intersection between codecs and
41*d9f75844SAndroid Build Coastguard Worker // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
42*d9f75844SAndroid Build Coastguard Worker // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
43*d9f75844SAndroid Build Coastguard Worker // RED or FEC codecs or is an empty set, throw InvalidModificationError.
44*d9f75844SAndroid Build Coastguard Worker // This ensures that we always have something to offer, regardless of
45*d9f75844SAndroid Build Coastguard Worker // transceiver.direction.
46*d9f75844SAndroid Build Coastguard Worker
47*d9f75844SAndroid Build Coastguard Worker if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
48*d9f75844SAndroid Build Coastguard Worker return codec.name != cricket::kRtxCodecName &&
49*d9f75844SAndroid Build Coastguard Worker codec.name != cricket::kRedCodecName &&
50*d9f75844SAndroid Build Coastguard Worker codec.name != cricket::kFlexfecCodecName &&
51*d9f75844SAndroid Build Coastguard Worker absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
52*d9f75844SAndroid Build Coastguard Worker return recv_codec.MatchesCapability(codec);
53*d9f75844SAndroid Build Coastguard Worker });
54*d9f75844SAndroid Build Coastguard Worker })) {
55*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_MODIFICATION,
56*d9f75844SAndroid Build Coastguard Worker "Invalid codec preferences: Missing codec from recv "
57*d9f75844SAndroid Build Coastguard Worker "codec capabilities.");
58*d9f75844SAndroid Build Coastguard Worker }
59*d9f75844SAndroid Build Coastguard Worker
60*d9f75844SAndroid Build Coastguard Worker if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
61*d9f75844SAndroid Build Coastguard Worker return codec.name != cricket::kRtxCodecName &&
62*d9f75844SAndroid Build Coastguard Worker codec.name != cricket::kRedCodecName &&
63*d9f75844SAndroid Build Coastguard Worker codec.name != cricket::kFlexfecCodecName &&
64*d9f75844SAndroid Build Coastguard Worker absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
65*d9f75844SAndroid Build Coastguard Worker return send_codec.MatchesCapability(codec);
66*d9f75844SAndroid Build Coastguard Worker });
67*d9f75844SAndroid Build Coastguard Worker })) {
68*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_MODIFICATION,
69*d9f75844SAndroid Build Coastguard Worker "Invalid codec preferences: Missing codec from send "
70*d9f75844SAndroid Build Coastguard Worker "codec capabilities.");
71*d9f75844SAndroid Build Coastguard Worker }
72*d9f75844SAndroid Build Coastguard Worker
73*d9f75844SAndroid Build Coastguard Worker // Let codecCapabilities be the union of
74*d9f75844SAndroid Build Coastguard Worker // RTCRtpSender.getCapabilities(kind).codecs and
75*d9f75844SAndroid Build Coastguard Worker // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
76*d9f75844SAndroid Build Coastguard Worker // codec is not in codecCapabilities, throw InvalidModificationError.
77*d9f75844SAndroid Build Coastguard Worker for (const auto& codec_preference : codecs) {
78*d9f75844SAndroid Build Coastguard Worker bool is_recv_codec =
79*d9f75844SAndroid Build Coastguard Worker absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
80*d9f75844SAndroid Build Coastguard Worker return codec.MatchesCapability(codec_preference);
81*d9f75844SAndroid Build Coastguard Worker });
82*d9f75844SAndroid Build Coastguard Worker
83*d9f75844SAndroid Build Coastguard Worker bool is_send_codec =
84*d9f75844SAndroid Build Coastguard Worker absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
85*d9f75844SAndroid Build Coastguard Worker return codec.MatchesCapability(codec_preference);
86*d9f75844SAndroid Build Coastguard Worker });
87*d9f75844SAndroid Build Coastguard Worker
88*d9f75844SAndroid Build Coastguard Worker if (!is_recv_codec && !is_send_codec) {
89*d9f75844SAndroid Build Coastguard Worker return RTCError(
90*d9f75844SAndroid Build Coastguard Worker RTCErrorType::INVALID_MODIFICATION,
91*d9f75844SAndroid Build Coastguard Worker std::string("Invalid codec preferences: invalid codec with name \"") +
92*d9f75844SAndroid Build Coastguard Worker codec_preference.name + "\".");
93*d9f75844SAndroid Build Coastguard Worker }
94*d9f75844SAndroid Build Coastguard Worker }
95*d9f75844SAndroid Build Coastguard Worker
96*d9f75844SAndroid Build Coastguard Worker // Check we have a real codec (not just rtx, red or fec)
97*d9f75844SAndroid Build Coastguard Worker if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
98*d9f75844SAndroid Build Coastguard Worker return codec.name == cricket::kRtxCodecName ||
99*d9f75844SAndroid Build Coastguard Worker codec.name == cricket::kRedCodecName ||
100*d9f75844SAndroid Build Coastguard Worker codec.name == cricket::kUlpfecCodecName;
101*d9f75844SAndroid Build Coastguard Worker })) {
102*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_MODIFICATION,
103*d9f75844SAndroid Build Coastguard Worker "Invalid codec preferences: codec list must have a non "
104*d9f75844SAndroid Build Coastguard Worker "RTX, RED or FEC entry.");
105*d9f75844SAndroid Build Coastguard Worker }
106*d9f75844SAndroid Build Coastguard Worker
107*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
108*d9f75844SAndroid Build Coastguard Worker }
109*d9f75844SAndroid Build Coastguard Worker
110*d9f75844SAndroid Build Coastguard Worker // Matches the list of codecs as capabilities (potentially without SVC related
111*d9f75844SAndroid Build Coastguard Worker // information) to the list of send codecs and returns the list of codecs with
112*d9f75844SAndroid Build Coastguard Worker // all the SVC related information.
MatchCodecPreferences(const std::vector<RtpCodecCapability> & codecs,const std::vector<cricket::VideoCodec> & send_codecs)113*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::VideoCodec> MatchCodecPreferences(
114*d9f75844SAndroid Build Coastguard Worker const std::vector<RtpCodecCapability>& codecs,
115*d9f75844SAndroid Build Coastguard Worker const std::vector<cricket::VideoCodec>& send_codecs) {
116*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::VideoCodec> result;
117*d9f75844SAndroid Build Coastguard Worker
118*d9f75844SAndroid Build Coastguard Worker for (const auto& codec_preference : codecs) {
119*d9f75844SAndroid Build Coastguard Worker for (const cricket::VideoCodec& send_codec : send_codecs) {
120*d9f75844SAndroid Build Coastguard Worker if (send_codec.MatchesCapability(codec_preference)) {
121*d9f75844SAndroid Build Coastguard Worker result.push_back(send_codec);
122*d9f75844SAndroid Build Coastguard Worker }
123*d9f75844SAndroid Build Coastguard Worker }
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker
126*d9f75844SAndroid Build Coastguard Worker return result;
127*d9f75844SAndroid Build Coastguard Worker }
128*d9f75844SAndroid Build Coastguard Worker
GetCurrentTaskQueueOrThread()129*d9f75844SAndroid Build Coastguard Worker TaskQueueBase* GetCurrentTaskQueueOrThread() {
130*d9f75844SAndroid Build Coastguard Worker TaskQueueBase* current = TaskQueueBase::Current();
131*d9f75844SAndroid Build Coastguard Worker if (!current)
132*d9f75844SAndroid Build Coastguard Worker current = rtc::ThreadManager::Instance()->CurrentThread();
133*d9f75844SAndroid Build Coastguard Worker return current;
134*d9f75844SAndroid Build Coastguard Worker }
135*d9f75844SAndroid Build Coastguard Worker
136*d9f75844SAndroid Build Coastguard Worker } // namespace
137*d9f75844SAndroid Build Coastguard Worker
RtpTransceiver(cricket::MediaType media_type,ConnectionContext * context)138*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::RtpTransceiver(cricket::MediaType media_type,
139*d9f75844SAndroid Build Coastguard Worker ConnectionContext* context)
140*d9f75844SAndroid Build Coastguard Worker : thread_(GetCurrentTaskQueueOrThread()),
141*d9f75844SAndroid Build Coastguard Worker unified_plan_(false),
142*d9f75844SAndroid Build Coastguard Worker media_type_(media_type),
143*d9f75844SAndroid Build Coastguard Worker context_(context) {
144*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
145*d9f75844SAndroid Build Coastguard Worker media_type == cricket::MEDIA_TYPE_VIDEO);
146*d9f75844SAndroid Build Coastguard Worker }
147*d9f75844SAndroid Build Coastguard Worker
RtpTransceiver(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver,ConnectionContext * context,std::vector<RtpHeaderExtensionCapability> header_extensions_offered,std::function<void ()> on_negotiation_needed)148*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::RtpTransceiver(
149*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
150*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
151*d9f75844SAndroid Build Coastguard Worker receiver,
152*d9f75844SAndroid Build Coastguard Worker ConnectionContext* context,
153*d9f75844SAndroid Build Coastguard Worker std::vector<RtpHeaderExtensionCapability> header_extensions_offered,
154*d9f75844SAndroid Build Coastguard Worker std::function<void()> on_negotiation_needed)
155*d9f75844SAndroid Build Coastguard Worker : thread_(GetCurrentTaskQueueOrThread()),
156*d9f75844SAndroid Build Coastguard Worker unified_plan_(true),
157*d9f75844SAndroid Build Coastguard Worker media_type_(sender->media_type()),
158*d9f75844SAndroid Build Coastguard Worker context_(context),
159*d9f75844SAndroid Build Coastguard Worker header_extensions_to_offer_(std::move(header_extensions_offered)),
160*d9f75844SAndroid Build Coastguard Worker on_negotiation_needed_(std::move(on_negotiation_needed)) {
161*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
162*d9f75844SAndroid Build Coastguard Worker media_type_ == cricket::MEDIA_TYPE_VIDEO);
163*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
164*d9f75844SAndroid Build Coastguard Worker if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO)
165*d9f75844SAndroid Build Coastguard Worker sender->internal()->SetVideoCodecPreferences(
166*d9f75844SAndroid Build Coastguard Worker media_engine()->video().send_codecs(false));
167*d9f75844SAndroid Build Coastguard Worker senders_.push_back(sender);
168*d9f75844SAndroid Build Coastguard Worker receivers_.push_back(receiver);
169*d9f75844SAndroid Build Coastguard Worker }
170*d9f75844SAndroid Build Coastguard Worker
~RtpTransceiver()171*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::~RtpTransceiver() {
172*d9f75844SAndroid Build Coastguard Worker // TODO(tommi): On Android, when running PeerConnectionClientTest (e.g.
173*d9f75844SAndroid Build Coastguard Worker // PeerConnectionClientTest#testCameraSwitch), the instance doesn't get
174*d9f75844SAndroid Build Coastguard Worker // deleted on `thread_`. See if we can fix that.
175*d9f75844SAndroid Build Coastguard Worker if (!stopped_) {
176*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
177*d9f75844SAndroid Build Coastguard Worker StopInternal();
178*d9f75844SAndroid Build Coastguard Worker }
179*d9f75844SAndroid Build Coastguard Worker
180*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(!channel_) << "Missing call to ClearChannel?";
181*d9f75844SAndroid Build Coastguard Worker }
182*d9f75844SAndroid Build Coastguard Worker
CreateChannel(absl::string_view mid,Call * call_ptr,const cricket::MediaConfig & media_config,bool srtp_required,CryptoOptions crypto_options,const cricket::AudioOptions & audio_options,const cricket::VideoOptions & video_options,VideoBitrateAllocatorFactory * video_bitrate_allocator_factory,std::function<RtpTransportInternal * (absl::string_view)> transport_lookup)183*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::CreateChannel(
184*d9f75844SAndroid Build Coastguard Worker absl::string_view mid,
185*d9f75844SAndroid Build Coastguard Worker Call* call_ptr,
186*d9f75844SAndroid Build Coastguard Worker const cricket::MediaConfig& media_config,
187*d9f75844SAndroid Build Coastguard Worker bool srtp_required,
188*d9f75844SAndroid Build Coastguard Worker CryptoOptions crypto_options,
189*d9f75844SAndroid Build Coastguard Worker const cricket::AudioOptions& audio_options,
190*d9f75844SAndroid Build Coastguard Worker const cricket::VideoOptions& video_options,
191*d9f75844SAndroid Build Coastguard Worker VideoBitrateAllocatorFactory* video_bitrate_allocator_factory,
192*d9f75844SAndroid Build Coastguard Worker std::function<RtpTransportInternal*(absl::string_view)> transport_lookup) {
193*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
194*d9f75844SAndroid Build Coastguard Worker if (!media_engine()) {
195*d9f75844SAndroid Build Coastguard Worker // TODO(hta): Must be a better way
196*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INTERNAL_ERROR,
197*d9f75844SAndroid Build Coastguard Worker "No media engine for mid=" + std::string(mid));
198*d9f75844SAndroid Build Coastguard Worker }
199*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::ChannelInterface> new_channel;
200*d9f75844SAndroid Build Coastguard Worker if (media_type() == cricket::MEDIA_TYPE_AUDIO) {
201*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
202*d9f75844SAndroid Build Coastguard Worker // the worker thread. We shouldn't be using the `call_ptr_` hack here but
203*d9f75844SAndroid Build Coastguard Worker // simply be on the worker thread and use `call_` (update upstream code).
204*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(call_ptr);
205*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(media_engine());
206*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/11992): Remove this workaround after updates in
207*d9f75844SAndroid Build Coastguard Worker // PeerConnection and add the expectation that we're already on the right
208*d9f75844SAndroid Build Coastguard Worker // thread.
209*d9f75844SAndroid Build Coastguard Worker context()->worker_thread()->BlockingCall([&] {
210*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(context()->worker_thread());
211*d9f75844SAndroid Build Coastguard Worker
212*d9f75844SAndroid Build Coastguard Worker cricket::VoiceMediaChannel* media_channel =
213*d9f75844SAndroid Build Coastguard Worker media_engine()->voice().CreateMediaChannel(
214*d9f75844SAndroid Build Coastguard Worker call_ptr, media_config, audio_options, crypto_options);
215*d9f75844SAndroid Build Coastguard Worker if (!media_channel) {
216*d9f75844SAndroid Build Coastguard Worker return;
217*d9f75844SAndroid Build Coastguard Worker }
218*d9f75844SAndroid Build Coastguard Worker
219*d9f75844SAndroid Build Coastguard Worker new_channel = std::make_unique<cricket::VoiceChannel>(
220*d9f75844SAndroid Build Coastguard Worker context()->worker_thread(), context()->network_thread(),
221*d9f75844SAndroid Build Coastguard Worker context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
222*d9f75844SAndroid Build Coastguard Worker srtp_required, crypto_options, context()->ssrc_generator());
223*d9f75844SAndroid Build Coastguard Worker });
224*d9f75844SAndroid Build Coastguard Worker } else {
225*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, media_type());
226*d9f75844SAndroid Build Coastguard Worker
227*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
228*d9f75844SAndroid Build Coastguard Worker // the worker thread. We shouldn't be using the `call_ptr_` hack here but
229*d9f75844SAndroid Build Coastguard Worker // simply be on the worker thread and use `call_` (update upstream code).
230*d9f75844SAndroid Build Coastguard Worker context()->worker_thread()->BlockingCall([&] {
231*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(context()->worker_thread());
232*d9f75844SAndroid Build Coastguard Worker cricket::VideoMediaChannel* media_channel =
233*d9f75844SAndroid Build Coastguard Worker media_engine()->video().CreateMediaChannel(
234*d9f75844SAndroid Build Coastguard Worker call_ptr, media_config, video_options, crypto_options,
235*d9f75844SAndroid Build Coastguard Worker video_bitrate_allocator_factory);
236*d9f75844SAndroid Build Coastguard Worker if (!media_channel) {
237*d9f75844SAndroid Build Coastguard Worker return;
238*d9f75844SAndroid Build Coastguard Worker }
239*d9f75844SAndroid Build Coastguard Worker
240*d9f75844SAndroid Build Coastguard Worker new_channel = std::make_unique<cricket::VideoChannel>(
241*d9f75844SAndroid Build Coastguard Worker context()->worker_thread(), context()->network_thread(),
242*d9f75844SAndroid Build Coastguard Worker context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
243*d9f75844SAndroid Build Coastguard Worker srtp_required, crypto_options, context()->ssrc_generator());
244*d9f75844SAndroid Build Coastguard Worker });
245*d9f75844SAndroid Build Coastguard Worker }
246*d9f75844SAndroid Build Coastguard Worker if (!new_channel) {
247*d9f75844SAndroid Build Coastguard Worker // TODO(hta): Must be a better way
248*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INTERNAL_ERROR,
249*d9f75844SAndroid Build Coastguard Worker "Failed to create channel for mid=" + std::string(mid));
250*d9f75844SAndroid Build Coastguard Worker }
251*d9f75844SAndroid Build Coastguard Worker SetChannel(std::move(new_channel), transport_lookup);
252*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
253*d9f75844SAndroid Build Coastguard Worker }
254*d9f75844SAndroid Build Coastguard Worker
SetChannel(std::unique_ptr<cricket::ChannelInterface> channel,std::function<RtpTransportInternal * (const std::string &)> transport_lookup)255*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::SetChannel(
256*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::ChannelInterface> channel,
257*d9f75844SAndroid Build Coastguard Worker std::function<RtpTransportInternal*(const std::string&)> transport_lookup) {
258*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
259*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(channel);
260*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(transport_lookup);
261*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!channel_);
262*d9f75844SAndroid Build Coastguard Worker // Cannot set a channel on a stopped transceiver.
263*d9f75844SAndroid Build Coastguard Worker if (stopped_) {
264*d9f75844SAndroid Build Coastguard Worker return;
265*d9f75844SAndroid Build Coastguard Worker }
266*d9f75844SAndroid Build Coastguard Worker
267*d9f75844SAndroid Build Coastguard Worker RTC_LOG_THREAD_BLOCK_COUNT();
268*d9f75844SAndroid Build Coastguard Worker
269*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(media_type(), channel->media_type());
270*d9f75844SAndroid Build Coastguard Worker signaling_thread_safety_ = PendingTaskSafetyFlag::Create();
271*d9f75844SAndroid Build Coastguard Worker
272*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
273*d9f75844SAndroid Build Coastguard Worker
274*d9f75844SAndroid Build Coastguard Worker // An alternative to this, could be to require SetChannel to be called
275*d9f75844SAndroid Build Coastguard Worker // on the network thread. The channel object operates for the most part
276*d9f75844SAndroid Build Coastguard Worker // on the network thread, as part of its initialization being on the network
277*d9f75844SAndroid Build Coastguard Worker // thread is required, so setting a channel object as part of the construction
278*d9f75844SAndroid Build Coastguard Worker // (without thread hopping) might be the more efficient thing to do than
279*d9f75844SAndroid Build Coastguard Worker // how SetChannel works today.
280*d9f75844SAndroid Build Coastguard Worker // Similarly, if the channel() accessor is limited to the network thread, that
281*d9f75844SAndroid Build Coastguard Worker // helps with keeping the channel implementation requirements being met and
282*d9f75844SAndroid Build Coastguard Worker // avoids synchronization for accessing the pointer or network related state.
283*d9f75844SAndroid Build Coastguard Worker context()->network_thread()->BlockingCall([&]() {
284*d9f75844SAndroid Build Coastguard Worker if (channel_) {
285*d9f75844SAndroid Build Coastguard Worker channel_->SetFirstPacketReceivedCallback(nullptr);
286*d9f75844SAndroid Build Coastguard Worker channel_->SetRtpTransport(nullptr);
287*d9f75844SAndroid Build Coastguard Worker channel_to_delete = std::move(channel_);
288*d9f75844SAndroid Build Coastguard Worker }
289*d9f75844SAndroid Build Coastguard Worker
290*d9f75844SAndroid Build Coastguard Worker channel_ = std::move(channel);
291*d9f75844SAndroid Build Coastguard Worker
292*d9f75844SAndroid Build Coastguard Worker channel_->SetRtpTransport(transport_lookup(channel_->mid()));
293*d9f75844SAndroid Build Coastguard Worker channel_->SetFirstPacketReceivedCallback(
294*d9f75844SAndroid Build Coastguard Worker [thread = thread_, flag = signaling_thread_safety_, this]() mutable {
295*d9f75844SAndroid Build Coastguard Worker thread->PostTask(
296*d9f75844SAndroid Build Coastguard Worker SafeTask(std::move(flag), [this]() { OnFirstPacketReceived(); }));
297*d9f75844SAndroid Build Coastguard Worker });
298*d9f75844SAndroid Build Coastguard Worker });
299*d9f75844SAndroid Build Coastguard Worker PushNewMediaChannelAndDeleteChannel(nullptr);
300*d9f75844SAndroid Build Coastguard Worker
301*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
302*d9f75844SAndroid Build Coastguard Worker }
303*d9f75844SAndroid Build Coastguard Worker
ClearChannel()304*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::ClearChannel() {
305*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
306*d9f75844SAndroid Build Coastguard Worker
307*d9f75844SAndroid Build Coastguard Worker if (!channel_) {
308*d9f75844SAndroid Build Coastguard Worker return;
309*d9f75844SAndroid Build Coastguard Worker }
310*d9f75844SAndroid Build Coastguard Worker
311*d9f75844SAndroid Build Coastguard Worker RTC_LOG_THREAD_BLOCK_COUNT();
312*d9f75844SAndroid Build Coastguard Worker
313*d9f75844SAndroid Build Coastguard Worker if (channel_) {
314*d9f75844SAndroid Build Coastguard Worker signaling_thread_safety_->SetNotAlive();
315*d9f75844SAndroid Build Coastguard Worker signaling_thread_safety_ = nullptr;
316*d9f75844SAndroid Build Coastguard Worker }
317*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
318*d9f75844SAndroid Build Coastguard Worker
319*d9f75844SAndroid Build Coastguard Worker context()->network_thread()->BlockingCall([&]() {
320*d9f75844SAndroid Build Coastguard Worker if (channel_) {
321*d9f75844SAndroid Build Coastguard Worker channel_->SetFirstPacketReceivedCallback(nullptr);
322*d9f75844SAndroid Build Coastguard Worker channel_->SetRtpTransport(nullptr);
323*d9f75844SAndroid Build Coastguard Worker channel_to_delete = std::move(channel_);
324*d9f75844SAndroid Build Coastguard Worker }
325*d9f75844SAndroid Build Coastguard Worker });
326*d9f75844SAndroid Build Coastguard Worker
327*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
328*d9f75844SAndroid Build Coastguard Worker PushNewMediaChannelAndDeleteChannel(std::move(channel_to_delete));
329*d9f75844SAndroid Build Coastguard Worker
330*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
331*d9f75844SAndroid Build Coastguard Worker }
332*d9f75844SAndroid Build Coastguard Worker
PushNewMediaChannelAndDeleteChannel(std::unique_ptr<cricket::ChannelInterface> channel_to_delete)333*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::PushNewMediaChannelAndDeleteChannel(
334*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::ChannelInterface> channel_to_delete) {
335*d9f75844SAndroid Build Coastguard Worker // The clumsy combination of pushing down media channel and deleting
336*d9f75844SAndroid Build Coastguard Worker // the channel is due to the desire to do both things in one Invoke().
337*d9f75844SAndroid Build Coastguard Worker if (!channel_to_delete && senders_.empty() && receivers_.empty()) {
338*d9f75844SAndroid Build Coastguard Worker return;
339*d9f75844SAndroid Build Coastguard Worker }
340*d9f75844SAndroid Build Coastguard Worker context()->worker_thread()->BlockingCall([&]() {
341*d9f75844SAndroid Build Coastguard Worker // Push down the new media_channel, if any, otherwise clear it.
342*d9f75844SAndroid Build Coastguard Worker auto* media_channel = channel_ ? channel_->media_channel() : nullptr;
343*d9f75844SAndroid Build Coastguard Worker for (const auto& sender : senders_) {
344*d9f75844SAndroid Build Coastguard Worker sender->internal()->SetMediaChannel(media_channel);
345*d9f75844SAndroid Build Coastguard Worker }
346*d9f75844SAndroid Build Coastguard Worker
347*d9f75844SAndroid Build Coastguard Worker for (const auto& receiver : receivers_) {
348*d9f75844SAndroid Build Coastguard Worker receiver->internal()->SetMediaChannel(media_channel);
349*d9f75844SAndroid Build Coastguard Worker }
350*d9f75844SAndroid Build Coastguard Worker
351*d9f75844SAndroid Build Coastguard Worker // Destroy the channel, if we had one, now _after_ updating the receivers
352*d9f75844SAndroid Build Coastguard Worker // who might have had references to the previous channel.
353*d9f75844SAndroid Build Coastguard Worker if (channel_to_delete) {
354*d9f75844SAndroid Build Coastguard Worker channel_to_delete.reset(nullptr);
355*d9f75844SAndroid Build Coastguard Worker }
356*d9f75844SAndroid Build Coastguard Worker });
357*d9f75844SAndroid Build Coastguard Worker }
358*d9f75844SAndroid Build Coastguard Worker
AddSender(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender)359*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::AddSender(
360*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
361*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
362*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!stopped_);
363*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!unified_plan_);
364*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(sender);
365*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(media_type(), sender->media_type());
366*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!absl::c_linear_search(senders_, sender));
367*d9f75844SAndroid Build Coastguard Worker if (media_type() == cricket::MEDIA_TYPE_VIDEO) {
368*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::VideoCodec> send_codecs =
369*d9f75844SAndroid Build Coastguard Worker media_engine()->video().send_codecs(false);
370*d9f75844SAndroid Build Coastguard Worker sender->internal()->SetVideoCodecPreferences(
371*d9f75844SAndroid Build Coastguard Worker codec_preferences_.empty()
372*d9f75844SAndroid Build Coastguard Worker ? send_codecs
373*d9f75844SAndroid Build Coastguard Worker : MatchCodecPreferences(codec_preferences_, send_codecs));
374*d9f75844SAndroid Build Coastguard Worker }
375*d9f75844SAndroid Build Coastguard Worker senders_.push_back(sender);
376*d9f75844SAndroid Build Coastguard Worker }
377*d9f75844SAndroid Build Coastguard Worker
RemoveSender(RtpSenderInterface * sender)378*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
379*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!unified_plan_);
380*d9f75844SAndroid Build Coastguard Worker if (sender) {
381*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(media_type(), sender->media_type());
382*d9f75844SAndroid Build Coastguard Worker }
383*d9f75844SAndroid Build Coastguard Worker auto it = absl::c_find(senders_, sender);
384*d9f75844SAndroid Build Coastguard Worker if (it == senders_.end()) {
385*d9f75844SAndroid Build Coastguard Worker return false;
386*d9f75844SAndroid Build Coastguard Worker }
387*d9f75844SAndroid Build Coastguard Worker (*it)->internal()->Stop();
388*d9f75844SAndroid Build Coastguard Worker senders_.erase(it);
389*d9f75844SAndroid Build Coastguard Worker return true;
390*d9f75844SAndroid Build Coastguard Worker }
391*d9f75844SAndroid Build Coastguard Worker
AddReceiver(rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver)392*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::AddReceiver(
393*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
394*d9f75844SAndroid Build Coastguard Worker receiver) {
395*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
396*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!stopped_);
397*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!unified_plan_);
398*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(receiver);
399*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(media_type(), receiver->media_type());
400*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
401*d9f75844SAndroid Build Coastguard Worker receivers_.push_back(receiver);
402*d9f75844SAndroid Build Coastguard Worker }
403*d9f75844SAndroid Build Coastguard Worker
RemoveReceiver(RtpReceiverInterface * receiver)404*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
405*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
406*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!unified_plan_);
407*d9f75844SAndroid Build Coastguard Worker if (receiver) {
408*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(media_type(), receiver->media_type());
409*d9f75844SAndroid Build Coastguard Worker }
410*d9f75844SAndroid Build Coastguard Worker auto it = absl::c_find(receivers_, receiver);
411*d9f75844SAndroid Build Coastguard Worker if (it == receivers_.end()) {
412*d9f75844SAndroid Build Coastguard Worker return false;
413*d9f75844SAndroid Build Coastguard Worker }
414*d9f75844SAndroid Build Coastguard Worker
415*d9f75844SAndroid Build Coastguard Worker (*it)->internal()->Stop();
416*d9f75844SAndroid Build Coastguard Worker context()->worker_thread()->BlockingCall([&]() {
417*d9f75844SAndroid Build Coastguard Worker // `Stop()` will clear the receiver's pointer to the media channel.
418*d9f75844SAndroid Build Coastguard Worker (*it)->internal()->SetMediaChannel(nullptr);
419*d9f75844SAndroid Build Coastguard Worker });
420*d9f75844SAndroid Build Coastguard Worker
421*d9f75844SAndroid Build Coastguard Worker receivers_.erase(it);
422*d9f75844SAndroid Build Coastguard Worker return true;
423*d9f75844SAndroid Build Coastguard Worker }
424*d9f75844SAndroid Build Coastguard Worker
sender_internal() const425*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
426*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(unified_plan_);
427*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(1u, senders_.size());
428*d9f75844SAndroid Build Coastguard Worker return rtc::scoped_refptr<RtpSenderInternal>(senders_[0]->internal());
429*d9f75844SAndroid Build Coastguard Worker }
430*d9f75844SAndroid Build Coastguard Worker
receiver_internal() const431*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
432*d9f75844SAndroid Build Coastguard Worker const {
433*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(unified_plan_);
434*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(1u, receivers_.size());
435*d9f75844SAndroid Build Coastguard Worker return rtc::scoped_refptr<RtpReceiverInternal>(receivers_[0]->internal());
436*d9f75844SAndroid Build Coastguard Worker }
437*d9f75844SAndroid Build Coastguard Worker
media_type() const438*d9f75844SAndroid Build Coastguard Worker cricket::MediaType RtpTransceiver::media_type() const {
439*d9f75844SAndroid Build Coastguard Worker return media_type_;
440*d9f75844SAndroid Build Coastguard Worker }
441*d9f75844SAndroid Build Coastguard Worker
mid() const442*d9f75844SAndroid Build Coastguard Worker absl::optional<std::string> RtpTransceiver::mid() const {
443*d9f75844SAndroid Build Coastguard Worker return mid_;
444*d9f75844SAndroid Build Coastguard Worker }
445*d9f75844SAndroid Build Coastguard Worker
OnFirstPacketReceived()446*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::OnFirstPacketReceived() {
447*d9f75844SAndroid Build Coastguard Worker for (const auto& receiver : receivers_) {
448*d9f75844SAndroid Build Coastguard Worker receiver->internal()->NotifyFirstPacketReceived();
449*d9f75844SAndroid Build Coastguard Worker }
450*d9f75844SAndroid Build Coastguard Worker }
451*d9f75844SAndroid Build Coastguard Worker
sender() const452*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
453*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(unified_plan_);
454*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(1u, senders_.size());
455*d9f75844SAndroid Build Coastguard Worker return senders_[0];
456*d9f75844SAndroid Build Coastguard Worker }
457*d9f75844SAndroid Build Coastguard Worker
receiver() const458*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
459*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(unified_plan_);
460*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(1u, receivers_.size());
461*d9f75844SAndroid Build Coastguard Worker return receivers_[0];
462*d9f75844SAndroid Build Coastguard Worker }
463*d9f75844SAndroid Build Coastguard Worker
set_current_direction(RtpTransceiverDirection direction)464*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
465*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
466*d9f75844SAndroid Build Coastguard Worker << ") current direction from "
467*d9f75844SAndroid Build Coastguard Worker << (current_direction_ ? RtpTransceiverDirectionToString(
468*d9f75844SAndroid Build Coastguard Worker *current_direction_)
469*d9f75844SAndroid Build Coastguard Worker : "<not set>")
470*d9f75844SAndroid Build Coastguard Worker << " to " << RtpTransceiverDirectionToString(direction)
471*d9f75844SAndroid Build Coastguard Worker << ".";
472*d9f75844SAndroid Build Coastguard Worker current_direction_ = direction;
473*d9f75844SAndroid Build Coastguard Worker if (RtpTransceiverDirectionHasSend(*current_direction_)) {
474*d9f75844SAndroid Build Coastguard Worker has_ever_been_used_to_send_ = true;
475*d9f75844SAndroid Build Coastguard Worker }
476*d9f75844SAndroid Build Coastguard Worker }
477*d9f75844SAndroid Build Coastguard Worker
set_fired_direction(absl::optional<RtpTransceiverDirection> direction)478*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::set_fired_direction(
479*d9f75844SAndroid Build Coastguard Worker absl::optional<RtpTransceiverDirection> direction) {
480*d9f75844SAndroid Build Coastguard Worker fired_direction_ = direction;
481*d9f75844SAndroid Build Coastguard Worker }
482*d9f75844SAndroid Build Coastguard Worker
stopped() const483*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::stopped() const {
484*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
485*d9f75844SAndroid Build Coastguard Worker return stopped_;
486*d9f75844SAndroid Build Coastguard Worker }
487*d9f75844SAndroid Build Coastguard Worker
stopping() const488*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::stopping() const {
489*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
490*d9f75844SAndroid Build Coastguard Worker return stopping_;
491*d9f75844SAndroid Build Coastguard Worker }
492*d9f75844SAndroid Build Coastguard Worker
direction() const493*d9f75844SAndroid Build Coastguard Worker RtpTransceiverDirection RtpTransceiver::direction() const {
494*d9f75844SAndroid Build Coastguard Worker if (unified_plan_ && stopping())
495*d9f75844SAndroid Build Coastguard Worker return webrtc::RtpTransceiverDirection::kStopped;
496*d9f75844SAndroid Build Coastguard Worker
497*d9f75844SAndroid Build Coastguard Worker return direction_;
498*d9f75844SAndroid Build Coastguard Worker }
499*d9f75844SAndroid Build Coastguard Worker
SetDirectionWithError(RtpTransceiverDirection new_direction)500*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::SetDirectionWithError(
501*d9f75844SAndroid Build Coastguard Worker RtpTransceiverDirection new_direction) {
502*d9f75844SAndroid Build Coastguard Worker if (unified_plan_ && stopping()) {
503*d9f75844SAndroid Build Coastguard Worker LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
504*d9f75844SAndroid Build Coastguard Worker "Cannot set direction on a stopping transceiver.");
505*d9f75844SAndroid Build Coastguard Worker }
506*d9f75844SAndroid Build Coastguard Worker if (new_direction == direction_)
507*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
508*d9f75844SAndroid Build Coastguard Worker
509*d9f75844SAndroid Build Coastguard Worker if (new_direction == RtpTransceiverDirection::kStopped) {
510*d9f75844SAndroid Build Coastguard Worker LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
511*d9f75844SAndroid Build Coastguard Worker "The set direction 'stopped' is invalid.");
512*d9f75844SAndroid Build Coastguard Worker }
513*d9f75844SAndroid Build Coastguard Worker
514*d9f75844SAndroid Build Coastguard Worker direction_ = new_direction;
515*d9f75844SAndroid Build Coastguard Worker on_negotiation_needed_();
516*d9f75844SAndroid Build Coastguard Worker
517*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
518*d9f75844SAndroid Build Coastguard Worker }
519*d9f75844SAndroid Build Coastguard Worker
current_direction() const520*d9f75844SAndroid Build Coastguard Worker absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
521*d9f75844SAndroid Build Coastguard Worker const {
522*d9f75844SAndroid Build Coastguard Worker if (unified_plan_ && stopped())
523*d9f75844SAndroid Build Coastguard Worker return webrtc::RtpTransceiverDirection::kStopped;
524*d9f75844SAndroid Build Coastguard Worker
525*d9f75844SAndroid Build Coastguard Worker return current_direction_;
526*d9f75844SAndroid Build Coastguard Worker }
527*d9f75844SAndroid Build Coastguard Worker
fired_direction() const528*d9f75844SAndroid Build Coastguard Worker absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
529*d9f75844SAndroid Build Coastguard Worker const {
530*d9f75844SAndroid Build Coastguard Worker return fired_direction_;
531*d9f75844SAndroid Build Coastguard Worker }
532*d9f75844SAndroid Build Coastguard Worker
StopSendingAndReceiving()533*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::StopSendingAndReceiving() {
534*d9f75844SAndroid Build Coastguard Worker // 1. Let sender be transceiver.[[Sender]].
535*d9f75844SAndroid Build Coastguard Worker // 2. Let receiver be transceiver.[[Receiver]].
536*d9f75844SAndroid Build Coastguard Worker //
537*d9f75844SAndroid Build Coastguard Worker // 3. Stop sending media with sender.
538*d9f75844SAndroid Build Coastguard Worker //
539*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
540*d9f75844SAndroid Build Coastguard Worker
541*d9f75844SAndroid Build Coastguard Worker // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
542*d9f75844SAndroid Build Coastguard Worker // specified in [RFC3550].
543*d9f75844SAndroid Build Coastguard Worker for (const auto& sender : senders_)
544*d9f75844SAndroid Build Coastguard Worker sender->internal()->Stop();
545*d9f75844SAndroid Build Coastguard Worker
546*d9f75844SAndroid Build Coastguard Worker // Signal to receiver sources that we're stopping.
547*d9f75844SAndroid Build Coastguard Worker for (const auto& receiver : receivers_)
548*d9f75844SAndroid Build Coastguard Worker receiver->internal()->Stop();
549*d9f75844SAndroid Build Coastguard Worker
550*d9f75844SAndroid Build Coastguard Worker context()->worker_thread()->BlockingCall([&]() {
551*d9f75844SAndroid Build Coastguard Worker // 5 Stop receiving media with receiver.
552*d9f75844SAndroid Build Coastguard Worker for (const auto& receiver : receivers_)
553*d9f75844SAndroid Build Coastguard Worker receiver->internal()->SetMediaChannel(nullptr);
554*d9f75844SAndroid Build Coastguard Worker });
555*d9f75844SAndroid Build Coastguard Worker
556*d9f75844SAndroid Build Coastguard Worker stopping_ = true;
557*d9f75844SAndroid Build Coastguard Worker direction_ = webrtc::RtpTransceiverDirection::kInactive;
558*d9f75844SAndroid Build Coastguard Worker }
559*d9f75844SAndroid Build Coastguard Worker
StopStandard()560*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::StopStandard() {
561*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
562*d9f75844SAndroid Build Coastguard Worker // If we're on Plan B, do what Stop() used to do there.
563*d9f75844SAndroid Build Coastguard Worker if (!unified_plan_) {
564*d9f75844SAndroid Build Coastguard Worker StopInternal();
565*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
566*d9f75844SAndroid Build Coastguard Worker }
567*d9f75844SAndroid Build Coastguard Worker // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
568*d9f75844SAndroid Build Coastguard Worker // invoked.
569*d9f75844SAndroid Build Coastguard Worker //
570*d9f75844SAndroid Build Coastguard Worker // 2. Let connection be the RTCPeerConnection object associated with
571*d9f75844SAndroid Build Coastguard Worker // transceiver.
572*d9f75844SAndroid Build Coastguard Worker //
573*d9f75844SAndroid Build Coastguard Worker // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
574*d9f75844SAndroid Build Coastguard Worker if (is_pc_closed_) {
575*d9f75844SAndroid Build Coastguard Worker LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
576*d9f75844SAndroid Build Coastguard Worker "PeerConnection is closed.");
577*d9f75844SAndroid Build Coastguard Worker }
578*d9f75844SAndroid Build Coastguard Worker
579*d9f75844SAndroid Build Coastguard Worker // 4. If transceiver.[[Stopping]] is true, abort these steps.
580*d9f75844SAndroid Build Coastguard Worker if (stopping_)
581*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
582*d9f75844SAndroid Build Coastguard Worker
583*d9f75844SAndroid Build Coastguard Worker // 5. Stop sending and receiving given transceiver, and update the
584*d9f75844SAndroid Build Coastguard Worker // negotiation-needed flag for connection.
585*d9f75844SAndroid Build Coastguard Worker StopSendingAndReceiving();
586*d9f75844SAndroid Build Coastguard Worker on_negotiation_needed_();
587*d9f75844SAndroid Build Coastguard Worker
588*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
589*d9f75844SAndroid Build Coastguard Worker }
590*d9f75844SAndroid Build Coastguard Worker
StopInternal()591*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::StopInternal() {
592*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
593*d9f75844SAndroid Build Coastguard Worker StopTransceiverProcedure();
594*d9f75844SAndroid Build Coastguard Worker }
595*d9f75844SAndroid Build Coastguard Worker
StopTransceiverProcedure()596*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::StopTransceiverProcedure() {
597*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
598*d9f75844SAndroid Build Coastguard Worker // As specified in the "Stop the RTCRtpTransceiver" procedure
599*d9f75844SAndroid Build Coastguard Worker // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
600*d9f75844SAndroid Build Coastguard Worker // transceiver.
601*d9f75844SAndroid Build Coastguard Worker if (!stopping_)
602*d9f75844SAndroid Build Coastguard Worker StopSendingAndReceiving();
603*d9f75844SAndroid Build Coastguard Worker
604*d9f75844SAndroid Build Coastguard Worker // 2. Set transceiver.[[Stopped]] to true.
605*d9f75844SAndroid Build Coastguard Worker stopped_ = true;
606*d9f75844SAndroid Build Coastguard Worker
607*d9f75844SAndroid Build Coastguard Worker // Signal the updated change to the senders.
608*d9f75844SAndroid Build Coastguard Worker for (const auto& sender : senders_)
609*d9f75844SAndroid Build Coastguard Worker sender->internal()->SetTransceiverAsStopped();
610*d9f75844SAndroid Build Coastguard Worker
611*d9f75844SAndroid Build Coastguard Worker // 3. Set transceiver.[[Receptive]] to false.
612*d9f75844SAndroid Build Coastguard Worker // 4. Set transceiver.[[CurrentDirection]] to null.
613*d9f75844SAndroid Build Coastguard Worker current_direction_ = absl::nullopt;
614*d9f75844SAndroid Build Coastguard Worker }
615*d9f75844SAndroid Build Coastguard Worker
SetCodecPreferences(rtc::ArrayView<RtpCodecCapability> codec_capabilities)616*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::SetCodecPreferences(
617*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
618*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(unified_plan_);
619*d9f75844SAndroid Build Coastguard Worker // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
620*d9f75844SAndroid Build Coastguard Worker // to codecs and abort these steps.
621*d9f75844SAndroid Build Coastguard Worker if (codec_capabilities.empty()) {
622*d9f75844SAndroid Build Coastguard Worker codec_preferences_.clear();
623*d9f75844SAndroid Build Coastguard Worker if (media_type() == cricket::MEDIA_TYPE_VIDEO)
624*d9f75844SAndroid Build Coastguard Worker senders_.front()->internal()->SetVideoCodecPreferences(
625*d9f75844SAndroid Build Coastguard Worker media_engine()->video().send_codecs(false));
626*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
627*d9f75844SAndroid Build Coastguard Worker }
628*d9f75844SAndroid Build Coastguard Worker
629*d9f75844SAndroid Build Coastguard Worker // 4. Remove any duplicate values in codecs.
630*d9f75844SAndroid Build Coastguard Worker std::vector<RtpCodecCapability> codecs;
631*d9f75844SAndroid Build Coastguard Worker absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
632*d9f75844SAndroid Build Coastguard Worker [&codecs](const RtpCodecCapability& codec) {
633*d9f75844SAndroid Build Coastguard Worker return absl::c_linear_search(codecs, codec);
634*d9f75844SAndroid Build Coastguard Worker });
635*d9f75844SAndroid Build Coastguard Worker
636*d9f75844SAndroid Build Coastguard Worker // 6. to 8.
637*d9f75844SAndroid Build Coastguard Worker RTCError result;
638*d9f75844SAndroid Build Coastguard Worker if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
639*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
640*d9f75844SAndroid Build Coastguard Worker send_codecs = media_engine()->voice().send_codecs();
641*d9f75844SAndroid Build Coastguard Worker recv_codecs = media_engine()->voice().recv_codecs();
642*d9f75844SAndroid Build Coastguard Worker result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
643*d9f75844SAndroid Build Coastguard Worker } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
644*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
645*d9f75844SAndroid Build Coastguard Worker send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
646*d9f75844SAndroid Build Coastguard Worker recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
647*d9f75844SAndroid Build Coastguard Worker result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
648*d9f75844SAndroid Build Coastguard Worker
649*d9f75844SAndroid Build Coastguard Worker if (result.ok()) {
650*d9f75844SAndroid Build Coastguard Worker senders_.front()->internal()->SetVideoCodecPreferences(
651*d9f75844SAndroid Build Coastguard Worker MatchCodecPreferences(codecs, send_codecs));
652*d9f75844SAndroid Build Coastguard Worker }
653*d9f75844SAndroid Build Coastguard Worker }
654*d9f75844SAndroid Build Coastguard Worker
655*d9f75844SAndroid Build Coastguard Worker if (result.ok()) {
656*d9f75844SAndroid Build Coastguard Worker codec_preferences_ = codecs;
657*d9f75844SAndroid Build Coastguard Worker }
658*d9f75844SAndroid Build Coastguard Worker
659*d9f75844SAndroid Build Coastguard Worker return result;
660*d9f75844SAndroid Build Coastguard Worker }
661*d9f75844SAndroid Build Coastguard Worker
662*d9f75844SAndroid Build Coastguard Worker std::vector<RtpHeaderExtensionCapability>
HeaderExtensionsToOffer() const663*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::HeaderExtensionsToOffer() const {
664*d9f75844SAndroid Build Coastguard Worker return header_extensions_to_offer_;
665*d9f75844SAndroid Build Coastguard Worker }
666*d9f75844SAndroid Build Coastguard Worker
667*d9f75844SAndroid Build Coastguard Worker std::vector<RtpHeaderExtensionCapability>
HeaderExtensionsNegotiated() const668*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::HeaderExtensionsNegotiated() const {
669*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
670*d9f75844SAndroid Build Coastguard Worker std::vector<RtpHeaderExtensionCapability> result;
671*d9f75844SAndroid Build Coastguard Worker for (const auto& ext : negotiated_header_extensions_) {
672*d9f75844SAndroid Build Coastguard Worker result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
673*d9f75844SAndroid Build Coastguard Worker }
674*d9f75844SAndroid Build Coastguard Worker return result;
675*d9f75844SAndroid Build Coastguard Worker }
676*d9f75844SAndroid Build Coastguard Worker
SetOfferedRtpHeaderExtensions(rtc::ArrayView<const RtpHeaderExtensionCapability> header_extensions_to_offer)677*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
678*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const RtpHeaderExtensionCapability>
679*d9f75844SAndroid Build Coastguard Worker header_extensions_to_offer) {
680*d9f75844SAndroid Build Coastguard Worker for (const auto& entry : header_extensions_to_offer) {
681*d9f75844SAndroid Build Coastguard Worker // Handle unsupported requests for mandatory extensions as per
682*d9f75844SAndroid Build Coastguard Worker // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
683*d9f75844SAndroid Build Coastguard Worker // Note:
684*d9f75844SAndroid Build Coastguard Worker // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
685*d9f75844SAndroid Build Coastguard Worker // this has to be checked on a higher level. We naturally error out
686*d9f75844SAndroid Build Coastguard Worker // in the handling of Step 2.2 if an unset URI is encountered.
687*d9f75844SAndroid Build Coastguard Worker
688*d9f75844SAndroid Build Coastguard Worker // Step 2.2.
689*d9f75844SAndroid Build Coastguard Worker // Handle unknown extensions.
690*d9f75844SAndroid Build Coastguard Worker auto it = std::find_if(
691*d9f75844SAndroid Build Coastguard Worker header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
692*d9f75844SAndroid Build Coastguard Worker [&entry](const auto& offered) { return entry.uri == offered.uri; });
693*d9f75844SAndroid Build Coastguard Worker if (it == header_extensions_to_offer_.end()) {
694*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
695*d9f75844SAndroid Build Coastguard Worker "Attempted to modify an unoffered extension.");
696*d9f75844SAndroid Build Coastguard Worker }
697*d9f75844SAndroid Build Coastguard Worker
698*d9f75844SAndroid Build Coastguard Worker // Step 2.4-2.5.
699*d9f75844SAndroid Build Coastguard Worker // - Use of the transceiver interface indicates unified plan is in effect,
700*d9f75844SAndroid Build Coastguard Worker // hence the MID extension needs to be enabled.
701*d9f75844SAndroid Build Coastguard Worker // - Also handle the mandatory video orientation extensions.
702*d9f75844SAndroid Build Coastguard Worker if ((entry.uri == RtpExtension::kMidUri ||
703*d9f75844SAndroid Build Coastguard Worker entry.uri == RtpExtension::kVideoRotationUri) &&
704*d9f75844SAndroid Build Coastguard Worker entry.direction != RtpTransceiverDirection::kSendRecv) {
705*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_MODIFICATION,
706*d9f75844SAndroid Build Coastguard Worker "Attempted to stop a mandatory extension.");
707*d9f75844SAndroid Build Coastguard Worker }
708*d9f75844SAndroid Build Coastguard Worker }
709*d9f75844SAndroid Build Coastguard Worker
710*d9f75844SAndroid Build Coastguard Worker // Apply mutation after error checking.
711*d9f75844SAndroid Build Coastguard Worker for (const auto& entry : header_extensions_to_offer) {
712*d9f75844SAndroid Build Coastguard Worker auto it = std::find_if(
713*d9f75844SAndroid Build Coastguard Worker header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
714*d9f75844SAndroid Build Coastguard Worker [&entry](const auto& offered) { return entry.uri == offered.uri; });
715*d9f75844SAndroid Build Coastguard Worker it->direction = entry.direction;
716*d9f75844SAndroid Build Coastguard Worker }
717*d9f75844SAndroid Build Coastguard Worker
718*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
719*d9f75844SAndroid Build Coastguard Worker }
720*d9f75844SAndroid Build Coastguard Worker
OnNegotiationUpdate(SdpType sdp_type,const cricket::MediaContentDescription * content)721*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::OnNegotiationUpdate(
722*d9f75844SAndroid Build Coastguard Worker SdpType sdp_type,
723*d9f75844SAndroid Build Coastguard Worker const cricket::MediaContentDescription* content) {
724*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(thread_);
725*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(content);
726*d9f75844SAndroid Build Coastguard Worker if (sdp_type == SdpType::kAnswer)
727*d9f75844SAndroid Build Coastguard Worker negotiated_header_extensions_ = content->rtp_header_extensions();
728*d9f75844SAndroid Build Coastguard Worker }
729*d9f75844SAndroid Build Coastguard Worker
SetPeerConnectionClosed()730*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::SetPeerConnectionClosed() {
731*d9f75844SAndroid Build Coastguard Worker is_pc_closed_ = true;
732*d9f75844SAndroid Build Coastguard Worker }
733*d9f75844SAndroid Build Coastguard Worker
734*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
735