blob: 5ca662c8fc7c1b8e1c148e961370f9903f9259a6 [file] [log] [blame]
Steve Anton6e634bf2017-11-13 10:44:53 -08001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/rtp_transceiver.h"
Steve Anton6e634bf2017-11-13 10:44:53 -080012
Harald Alvestrandc24a2182022-02-23 13:44:59 +000013#include <algorithm>
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000014#include <iterator>
Steve Anton6e634bf2017-11-13 10:44:53 -080015#include <string>
Markus Handell0357b3e2020-03-16 13:40:51 +010016#include <utility>
Markus Handell5932fe12020-12-17 22:19:40 +010017#include <vector>
Steve Anton6e634bf2017-11-13 10:44:53 -080018
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Harald Alvestrand485457f2022-05-23 08:46:57 +000020#include "absl/memory/memory.h"
Harald Alvestrand8f429922022-05-04 10:32:30 +000021#include "api/peer_connection_interface.h"
Markus Handell0357b3e2020-03-16 13:40:51 +010022#include "api/rtp_parameters.h"
Artem Titovd15a5752021-02-10 14:31:24 +010023#include "api/sequence_checker.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000024#include "media/base/codec.h"
25#include "media/base/media_constants.h"
Harald Alvestrand8101e7b2022-05-23 14:57:47 +000026#include "media/base/media_engine.h"
Harald Alvestrand8f429922022-05-04 10:32:30 +000027#include "pc/channel.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "pc/rtp_media_utils.h"
Markus Handell5932fe12020-12-17 22:19:40 +010029#include "pc/session_description.h"
Yves Gerey3e707812018-11-28 16:47:49 +010030#include "rtc_base/checks.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000031#include "rtc_base/location.h"
Yves Gerey3e707812018-11-28 16:47:49 +010032#include "rtc_base/logging.h"
Tommi99c8a802021-04-27 15:00:00 +020033#include "rtc_base/task_utils/to_queued_task.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000034#include "rtc_base/thread.h"
Steve Antondcc3c022017-12-22 16:02:54 -080035
Steve Anton6e634bf2017-11-13 10:44:53 -080036namespace webrtc {
Johannes Kron3e983682020-03-29 22:17:00 +020037namespace {
38template <class T>
39RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
40 const std::vector<T>& send_codecs,
41 const std::vector<T>& recv_codecs) {
42 // If the intersection between codecs and
43 // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
44 // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
45 // RED or FEC codecs or is an empty set, throw InvalidModificationError.
46 // This ensures that we always have something to offer, regardless of
47 // transceiver.direction.
48
49 if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
50 return codec.name != cricket::kRtxCodecName &&
51 codec.name != cricket::kRedCodecName &&
52 codec.name != cricket::kFlexfecCodecName &&
53 absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
54 return recv_codec.MatchesCapability(codec);
55 });
56 })) {
57 return RTCError(RTCErrorType::INVALID_MODIFICATION,
58 "Invalid codec preferences: Missing codec from recv "
59 "codec capabilities.");
60 }
61
62 if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
63 return codec.name != cricket::kRtxCodecName &&
64 codec.name != cricket::kRedCodecName &&
65 codec.name != cricket::kFlexfecCodecName &&
66 absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
67 return send_codec.MatchesCapability(codec);
68 });
69 })) {
70 return RTCError(RTCErrorType::INVALID_MODIFICATION,
71 "Invalid codec preferences: Missing codec from send "
72 "codec capabilities.");
73 }
74
75 // Let codecCapabilities be the union of
76 // RTCRtpSender.getCapabilities(kind).codecs and
77 // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
78 // codec is not in codecCapabilities, throw InvalidModificationError.
79 for (const auto& codec_preference : codecs) {
80 bool is_recv_codec =
81 absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
82 return codec.MatchesCapability(codec_preference);
83 });
84
85 bool is_send_codec =
86 absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
87 return codec.MatchesCapability(codec_preference);
88 });
89
90 if (!is_recv_codec && !is_send_codec) {
91 return RTCError(
92 RTCErrorType::INVALID_MODIFICATION,
93 std::string("Invalid codec preferences: invalid codec with name \"") +
94 codec_preference.name + "\".");
95 }
96 }
97
98 // Check we have a real codec (not just rtx, red or fec)
99 if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
100 return codec.name == cricket::kRtxCodecName ||
101 codec.name == cricket::kRedCodecName ||
102 codec.name == cricket::kUlpfecCodecName;
103 })) {
104 return RTCError(RTCErrorType::INVALID_MODIFICATION,
105 "Invalid codec preferences: codec list must have a non "
106 "RTX, RED or FEC entry.");
107 }
108
109 return RTCError::OK();
110}
111
Harald Alvestrand6060df52020-08-11 09:54:02 +0200112TaskQueueBase* GetCurrentTaskQueueOrThread() {
113 TaskQueueBase* current = TaskQueueBase::Current();
114 if (!current)
115 current = rtc::ThreadManager::Instance()->CurrentThread();
116 return current;
117}
118
Johannes Kron3e983682020-03-29 22:17:00 +0200119} // namespace
Steve Anton6e634bf2017-11-13 10:44:53 -0800120
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000121RtpTransceiver::RtpTransceiver(cricket::MediaType media_type,
122 ConnectionContext* context)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200123 : thread_(GetCurrentTaskQueueOrThread()),
124 unified_plan_(false),
Tommi99c8a802021-04-27 15:00:00 +0200125 media_type_(media_type),
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000126 context_(context) {
Steve Anton6e634bf2017-11-13 10:44:53 -0800127 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
128 media_type == cricket::MEDIA_TYPE_VIDEO);
129}
130
Steve Anton79e79602017-11-20 10:25:56 -0800131RtpTransceiver::RtpTransceiver(
132 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
133 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200134 receiver,
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000135 ConnectionContext* context,
Harald Alvestrand280054f2020-11-10 13:12:53 +0000136 std::vector<RtpHeaderExtensionCapability> header_extensions_offered,
137 std::function<void()> on_negotiation_needed)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200138 : thread_(GetCurrentTaskQueueOrThread()),
139 unified_plan_(true),
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200140 media_type_(sender->media_type()),
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000141 context_(context),
Harald Alvestrand280054f2020-11-10 13:12:53 +0000142 header_extensions_to_offer_(std::move(header_extensions_offered)),
143 on_negotiation_needed_(std::move(on_negotiation_needed)) {
Steve Anton79e79602017-11-20 10:25:56 -0800144 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
145 media_type_ == cricket::MEDIA_TYPE_VIDEO);
146 RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
147 senders_.push_back(sender);
148 receivers_.push_back(receiver);
149}
150
Steve Anton6e634bf2017-11-13 10:44:53 -0800151RtpTransceiver::~RtpTransceiver() {
Tommi99c8a802021-04-27 15:00:00 +0200152 // TODO(tommi): On Android, when running PeerConnectionClientTest (e.g.
153 // PeerConnectionClientTest#testCameraSwitch), the instance doesn't get
154 // deleted on `thread_`. See if we can fix that.
Harald Alvestrand85466662021-04-19 21:21:36 +0000155 if (!stopped_) {
156 RTC_DCHECK_RUN_ON(thread_);
157 StopInternal();
158 }
Tomas Gunnarsson16de2162022-01-26 10:21:57 +0100159
Harald Alvestrand8f429922022-05-04 10:32:30 +0000160 RTC_CHECK(!channel_) << "Missing call to ClearChannel?";
161}
162
163RTCError RtpTransceiver::CreateChannel(
164 absl::string_view mid,
165 Call* call_ptr,
166 const cricket::MediaConfig& media_config,
167 bool srtp_required,
168 CryptoOptions crypto_options,
169 const cricket::AudioOptions& audio_options,
170 const cricket::VideoOptions& video_options,
171 VideoBitrateAllocatorFactory* video_bitrate_allocator_factory,
172 std::function<RtpTransportInternal*(absl::string_view)> transport_lookup) {
173 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000174 if (!media_engine()) {
Harald Alvestrand8f429922022-05-04 10:32:30 +0000175 // TODO(hta): Must be a better way
176 return RTCError(RTCErrorType::INTERNAL_ERROR,
177 "No media engine for mid=" + std::string(mid));
178 }
179 std::unique_ptr<cricket::ChannelInterface> new_channel;
180 if (media_type() == cricket::MEDIA_TYPE_AUDIO) {
181 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
182 // the worker thread. We shouldn't be using the `call_ptr_` hack here but
183 // simply be on the worker thread and use `call_` (update upstream code).
Harald Alvestrand485457f2022-05-23 08:46:57 +0000184 RTC_DCHECK(call_ptr);
185 RTC_DCHECK(media_engine());
186 // TODO(bugs.webrtc.org/11992): Remove this workaround after updates in
187 // PeerConnection and add the expectation that we're already on the right
188 // thread.
189 new_channel =
190 context()
191 ->worker_thread()
192 ->Invoke<std::unique_ptr<cricket::VoiceChannel>>(
193 RTC_FROM_HERE, [&]() -> std::unique_ptr<cricket::VoiceChannel> {
194 RTC_DCHECK_RUN_ON(context()->worker_thread());
Harald Alvestrand8f429922022-05-04 10:32:30 +0000195
Harald Alvestrand485457f2022-05-23 08:46:57 +0000196 cricket::VoiceMediaChannel* media_channel =
197 media_engine()->voice().CreateMediaChannel(
198 call_ptr, media_config, audio_options,
199 crypto_options);
200 if (!media_channel) {
201 return nullptr;
202 }
203
204 auto voice_channel = std::make_unique<cricket::VoiceChannel>(
205 context()->worker_thread(), context()->network_thread(),
206 context()->signaling_thread(),
207 absl::WrapUnique(media_channel), mid, srtp_required,
208 crypto_options, context()->ssrc_generator());
209
210 return voice_channel;
211 });
Harald Alvestrand8f429922022-05-04 10:32:30 +0000212 } else {
213 RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, media_type());
214
215 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
216 // the worker thread. We shouldn't be using the `call_ptr_` hack here but
217 // simply be on the worker thread and use `call_` (update upstream code).
Harald Alvestrand485457f2022-05-23 08:46:57 +0000218 new_channel =
219 context()
220 ->worker_thread()
221 ->Invoke<std::unique_ptr<cricket::VideoChannel>>(
222 RTC_FROM_HERE, [&]() -> std::unique_ptr<cricket::VideoChannel> {
223 RTC_DCHECK_RUN_ON(context()->worker_thread());
224 cricket::VideoMediaChannel* media_channel =
225 media_engine()->video().CreateMediaChannel(
226 call_ptr, media_config, video_options, crypto_options,
227 video_bitrate_allocator_factory);
228 if (!media_channel) {
229 return nullptr;
230 }
231
232 auto video_channel = std::make_unique<cricket::VideoChannel>(
233 context()->worker_thread(), context()->network_thread(),
234 context()->signaling_thread(),
235 absl::WrapUnique(media_channel), mid, srtp_required,
236 crypto_options, context()->ssrc_generator());
237
238 return video_channel;
239 });
Harald Alvestrand8f429922022-05-04 10:32:30 +0000240 }
241 if (!new_channel) {
242 // TODO(hta): Must be a better way
243 return RTCError(RTCErrorType::INTERNAL_ERROR,
244 "Failed to create channel for mid=" + std::string(mid));
245 }
246 SetChannel(std::move(new_channel), transport_lookup);
247 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800248}
249
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100250void RtpTransceiver::SetChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000251 std::unique_ptr<cricket::ChannelInterface> channel,
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100252 std::function<RtpTransportInternal*(const std::string&)> transport_lookup) {
Tommi99c8a802021-04-27 15:00:00 +0200253 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000254 RTC_DCHECK(channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000255 RTC_DCHECK(transport_lookup);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000256 RTC_DCHECK(!channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000257 // Cannot set a channel on a stopped transceiver.
Harald Alvestranddaee8702022-04-29 11:42:55 +0000258 if (stopped_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800259 return;
260 }
261
Tommife041642021-04-07 10:08:28 +0200262 RTC_LOG_THREAD_BLOCK_COUNT();
263
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000264 RTC_DCHECK_EQ(media_type(), channel->media_type());
265 signaling_thread_safety_ = PendingTaskSafetyFlag::Create();
Steve Anton60776752018-01-10 11:51:34 -0800266
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000267 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
268
Tommi99c8a802021-04-27 15:00:00 +0200269 // An alternative to this, could be to require SetChannel to be called
270 // on the network thread. The channel object operates for the most part
271 // on the network thread, as part of its initialization being on the network
272 // thread is required, so setting a channel object as part of the construction
273 // (without thread hopping) might be the more efficient thing to do than
274 // how SetChannel works today.
275 // Similarly, if the channel() accessor is limited to the network thread, that
276 // helps with keeping the channel implementation requirements being met and
277 // avoids synchronization for accessing the pointer or network related state.
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000278 context()->network_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000279 if (channel_) {
280 channel_->SetFirstPacketReceivedCallback(nullptr);
281 channel_->SetRtpTransport(nullptr);
282 channel_to_delete = std::move(channel_);
283 }
284
285 channel_ = std::move(channel);
Steve Anton60776752018-01-10 11:51:34 -0800286
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000287 channel_->SetRtpTransport(transport_lookup(channel_->mid()));
288 channel_->SetFirstPacketReceivedCallback(
289 [thread = thread_, flag = signaling_thread_safety_, this]() mutable {
290 thread->PostTask(ToQueuedTask(std::move(flag),
291 [this]() { OnFirstPacketReceived(); }));
292 });
Tommi99c8a802021-04-27 15:00:00 +0200293 });
Harald Alvestranddaee8702022-04-29 11:42:55 +0000294 PushNewMediaChannelAndDeleteChannel(nullptr);
Tommi6589def2022-02-17 23:36:47 +0100295
296 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
Steve Anton6e634bf2017-11-13 10:44:53 -0800297}
298
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000299void RtpTransceiver::ClearChannel() {
300 RTC_DCHECK_RUN_ON(thread_);
301
302 if (!channel_) {
303 return;
304 }
305
306 RTC_LOG_THREAD_BLOCK_COUNT();
307
308 if (channel_) {
309 signaling_thread_safety_->SetNotAlive();
310 signaling_thread_safety_ = nullptr;
311 }
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000312 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000313
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000314 context()->network_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000315 if (channel_) {
316 channel_->SetFirstPacketReceivedCallback(nullptr);
317 channel_->SetRtpTransport(nullptr);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000318 channel_to_delete = std::move(channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000319 }
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000320 });
321
322 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000323 PushNewMediaChannelAndDeleteChannel(std::move(channel_to_delete));
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000324
325 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
326}
327
Harald Alvestranddaee8702022-04-29 11:42:55 +0000328void RtpTransceiver::PushNewMediaChannelAndDeleteChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000329 std::unique_ptr<cricket::ChannelInterface> channel_to_delete) {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000330 // The clumsy combination of pushing down media channel and deleting
331 // the channel is due to the desire to do both things in one Invoke().
332 if (!channel_to_delete && senders_.empty() && receivers_.empty()) {
333 return;
334 }
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000335 context()->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000336 // Push down the new media_channel, if any, otherwise clear it.
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000337 auto* media_channel = channel_ ? channel_->media_channel() : nullptr;
338 for (const auto& sender : senders_) {
339 sender->internal()->SetMediaChannel(media_channel);
340 }
341
342 for (const auto& receiver : receivers_) {
343 receiver->internal()->SetMediaChannel(media_channel);
344 }
345
346 // Destroy the channel, if we had one, now _after_ updating the receivers
347 // who might have had references to the previous channel.
348 if (channel_to_delete) {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000349 channel_to_delete.reset(nullptr);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000350 }
351 });
352}
353
Steve Anton6e634bf2017-11-13 10:44:53 -0800354void RtpTransceiver::AddSender(
355 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
Tommi99c8a802021-04-27 15:00:00 +0200356 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800357 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800358 RTC_DCHECK(!unified_plan_);
359 RTC_DCHECK(sender);
Steve Anton69470252018-02-09 11:43:08 -0800360 RTC_DCHECK_EQ(media_type(), sender->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800361 RTC_DCHECK(!absl::c_linear_search(senders_, sender));
Steve Anton6e634bf2017-11-13 10:44:53 -0800362 senders_.push_back(sender);
363}
364
365bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
366 RTC_DCHECK(!unified_plan_);
367 if (sender) {
368 RTC_DCHECK_EQ(media_type(), sender->media_type());
369 }
Steve Anton64b626b2019-01-28 17:25:26 -0800370 auto it = absl::c_find(senders_, sender);
Steve Anton6e634bf2017-11-13 10:44:53 -0800371 if (it == senders_.end()) {
372 return false;
373 }
374 (*it)->internal()->Stop();
375 senders_.erase(it);
376 return true;
377}
378
379void RtpTransceiver::AddReceiver(
380 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
381 receiver) {
Tommi99c8a802021-04-27 15:00:00 +0200382 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800383 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800384 RTC_DCHECK(!unified_plan_);
385 RTC_DCHECK(receiver);
Steve Anton69470252018-02-09 11:43:08 -0800386 RTC_DCHECK_EQ(media_type(), receiver->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800387 RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
Steve Anton6e634bf2017-11-13 10:44:53 -0800388 receivers_.push_back(receiver);
389}
390
391bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
Tommi6589def2022-02-17 23:36:47 +0100392 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800393 RTC_DCHECK(!unified_plan_);
394 if (receiver) {
395 RTC_DCHECK_EQ(media_type(), receiver->media_type());
396 }
Steve Anton64b626b2019-01-28 17:25:26 -0800397 auto it = absl::c_find(receivers_, receiver);
Steve Anton6e634bf2017-11-13 10:44:53 -0800398 if (it == receivers_.end()) {
399 return false;
400 }
Tommi6589def2022-02-17 23:36:47 +0100401
Steve Anton6e634bf2017-11-13 10:44:53 -0800402 (*it)->internal()->Stop();
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000403 context()->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Tommi6589def2022-02-17 23:36:47 +0100404 // `Stop()` will clear the receiver's pointer to the media channel.
405 (*it)->internal()->SetMediaChannel(nullptr);
406 });
407
Steve Anton6e634bf2017-11-13 10:44:53 -0800408 receivers_.erase(it);
409 return true;
410}
411
Steve Antonf9381f02017-12-14 10:23:57 -0800412rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
413 RTC_DCHECK(unified_plan_);
414 RTC_CHECK_EQ(1u, senders_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100415 return rtc::scoped_refptr<RtpSenderInternal>(senders_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800416}
417
418rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
419 const {
420 RTC_DCHECK(unified_plan_);
421 RTC_CHECK_EQ(1u, receivers_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100422 return rtc::scoped_refptr<RtpReceiverInternal>(receivers_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800423}
424
Steve Anton69470252018-02-09 11:43:08 -0800425cricket::MediaType RtpTransceiver::media_type() const {
426 return media_type_;
427}
428
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200429absl::optional<std::string> RtpTransceiver::mid() const {
Steve Anton6e634bf2017-11-13 10:44:53 -0800430 return mid_;
431}
432
Tommi99c8a802021-04-27 15:00:00 +0200433void RtpTransceiver::OnFirstPacketReceived() {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100434 for (const auto& receiver : receivers_) {
Steve Anton60776752018-01-10 11:51:34 -0800435 receiver->internal()->NotifyFirstPacketReceived();
436 }
437}
438
Steve Anton6e634bf2017-11-13 10:44:53 -0800439rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
440 RTC_DCHECK(unified_plan_);
441 RTC_CHECK_EQ(1u, senders_.size());
442 return senders_[0];
443}
444
445rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
446 RTC_DCHECK(unified_plan_);
447 RTC_CHECK_EQ(1u, receivers_.size());
448 return receivers_[0];
449}
450
Steve Antondcc3c022017-12-22 16:02:54 -0800451void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
Steve Anton3d954a62018-04-02 11:27:23 -0700452 RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
453 << ") current direction from "
454 << (current_direction_ ? RtpTransceiverDirectionToString(
455 *current_direction_)
456 : "<not set>")
457 << " to " << RtpTransceiverDirectionToString(direction)
458 << ".";
Steve Antondcc3c022017-12-22 16:02:54 -0800459 current_direction_ = direction;
460 if (RtpTransceiverDirectionHasSend(*current_direction_)) {
461 has_ever_been_used_to_send_ = true;
462 }
463}
464
Henrik Boström0a162762022-05-02 15:47:52 +0200465void RtpTransceiver::set_fired_direction(
466 absl::optional<RtpTransceiverDirection> direction) {
Steve Anton0f5400a2018-07-17 14:25:36 -0700467 fired_direction_ = direction;
468}
469
Steve Anton6e634bf2017-11-13 10:44:53 -0800470bool RtpTransceiver::stopped() const {
Tommi99c8a802021-04-27 15:00:00 +0200471 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800472 return stopped_;
473}
474
Harald Alvestrand6060df52020-08-11 09:54:02 +0200475bool RtpTransceiver::stopping() const {
476 RTC_DCHECK_RUN_ON(thread_);
477 return stopping_;
478}
479
Steve Anton6e634bf2017-11-13 10:44:53 -0800480RtpTransceiverDirection RtpTransceiver::direction() const {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200481 if (unified_plan_ && stopping())
482 return webrtc::RtpTransceiverDirection::kStopped;
483
Steve Anton6e634bf2017-11-13 10:44:53 -0800484 return direction_;
485}
486
Harald Alvestrand6060df52020-08-11 09:54:02 +0200487RTCError RtpTransceiver::SetDirectionWithError(
488 RtpTransceiverDirection new_direction) {
489 if (unified_plan_ && stopping()) {
490 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
491 "Cannot set direction on a stopping transceiver.");
Steve Anton52d86772018-02-20 15:48:12 -0800492 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200493 if (new_direction == direction_)
494 return RTCError::OK();
495
496 if (new_direction == RtpTransceiverDirection::kStopped) {
497 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
498 "The set direction 'stopped' is invalid.");
Steve Anton52d86772018-02-20 15:48:12 -0800499 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200500
Steve Anton52d86772018-02-20 15:48:12 -0800501 direction_ = new_direction;
Harald Alvestrand280054f2020-11-10 13:12:53 +0000502 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200503
504 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800505}
506
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200507absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
Steve Anton6e634bf2017-11-13 10:44:53 -0800508 const {
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000509 if (unified_plan_ && stopped())
Harald Alvestrand6060df52020-08-11 09:54:02 +0200510 return webrtc::RtpTransceiverDirection::kStopped;
511
Steve Anton6e634bf2017-11-13 10:44:53 -0800512 return current_direction_;
513}
514
Steve Anton0f5400a2018-07-17 14:25:36 -0700515absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
516 const {
517 return fired_direction_;
518}
519
Harald Alvestrand6060df52020-08-11 09:54:02 +0200520void RtpTransceiver::StopSendingAndReceiving() {
521 // 1. Let sender be transceiver.[[Sender]].
522 // 2. Let receiver be transceiver.[[Receiver]].
523 //
524 // 3. Stop sending media with sender.
525 //
Tommi6589def2022-02-17 23:36:47 +0100526 RTC_DCHECK_RUN_ON(thread_);
527
Harald Alvestrand6060df52020-08-11 09:54:02 +0200528 // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
529 // specified in [RFC3550].
Harald Alvestrand6060df52020-08-11 09:54:02 +0200530 for (const auto& sender : senders_)
Steve Anton6e634bf2017-11-13 10:44:53 -0800531 sender->internal()->Stop();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200532
Tommi6589def2022-02-17 23:36:47 +0100533 // Signal to receiver sources that we're stopping.
Harald Alvestrand6060df52020-08-11 09:54:02 +0200534 for (const auto& receiver : receivers_)
Tommi6589def2022-02-17 23:36:47 +0100535 receiver->internal()->Stop();
536
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000537 context()->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Tommi6589def2022-02-17 23:36:47 +0100538 // 5 Stop receiving media with receiver.
539 for (const auto& receiver : receivers_)
540 receiver->internal()->SetMediaChannel(nullptr);
541 });
Harald Alvestrand6060df52020-08-11 09:54:02 +0200542
543 stopping_ = true;
544 direction_ = webrtc::RtpTransceiverDirection::kInactive;
545}
546
547RTCError RtpTransceiver::StopStandard() {
548 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000549 // If we're on Plan B, do what Stop() used to do there.
550 if (!unified_plan_) {
551 StopInternal();
552 return RTCError::OK();
553 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200554 // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
555 // invoked.
556 //
557 // 2. Let connection be the RTCPeerConnection object associated with
558 // transceiver.
559 //
560 // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
561 if (is_pc_closed_) {
562 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
563 "PeerConnection is closed.");
Harald Alvestranda88c9772020-08-10 18:06:09 +0000564 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200565
566 // 4. If transceiver.[[Stopping]] is true, abort these steps.
567 if (stopping_)
568 return RTCError::OK();
569
570 // 5. Stop sending and receiving given transceiver, and update the
571 // negotiation-needed flag for connection.
572 StopSendingAndReceiving();
Harald Alvestrand280054f2020-11-10 13:12:53 +0000573 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200574
575 return RTCError::OK();
576}
577
578void RtpTransceiver::StopInternal() {
Harald Alvestrand85466662021-04-19 21:21:36 +0000579 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000580 StopTransceiverProcedure();
581}
582
583void RtpTransceiver::StopTransceiverProcedure() {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200584 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000585 // As specified in the "Stop the RTCRtpTransceiver" procedure
Harald Alvestrand6060df52020-08-11 09:54:02 +0200586 // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
587 // transceiver.
588 if (!stopping_)
589 StopSendingAndReceiving();
590
591 // 2. Set transceiver.[[Stopped]] to true.
Steve Anton6e634bf2017-11-13 10:44:53 -0800592 stopped_ = true;
Harald Alvestrand6060df52020-08-11 09:54:02 +0200593
594 // Signal the updated change to the senders.
595 for (const auto& sender : senders_)
596 sender->internal()->SetTransceiverAsStopped();
597
598 // 3. Set transceiver.[[Receptive]] to false.
599 // 4. Set transceiver.[[CurrentDirection]] to null.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200600 current_direction_ = absl::nullopt;
Steve Anton6e634bf2017-11-13 10:44:53 -0800601}
602
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200603RTCError RtpTransceiver::SetCodecPreferences(
604 rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
605 RTC_DCHECK(unified_plan_);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200606 // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
607 // to codecs and abort these steps.
608 if (codec_capabilities.empty()) {
609 codec_preferences_.clear();
610 return RTCError::OK();
611 }
612
613 // 4. Remove any duplicate values in codecs.
614 std::vector<RtpCodecCapability> codecs;
615 absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
616 [&codecs](const RtpCodecCapability& codec) {
617 return absl::c_linear_search(codecs, codec);
618 });
619
Johannes Kron3e983682020-03-29 22:17:00 +0200620 // 6. to 8.
621 RTCError result;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200622 if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200623 std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000624 send_codecs = media_engine()->voice().send_codecs();
625 recv_codecs = media_engine()->voice().recv_codecs();
Johannes Kron3e983682020-03-29 22:17:00 +0200626 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200627 } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
Johannes Kron3e983682020-03-29 22:17:00 +0200628 std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000629 send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
630 recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
Johannes Kron3e983682020-03-29 22:17:00 +0200631 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200632 }
633
Johannes Kron3e983682020-03-29 22:17:00 +0200634 if (result.ok()) {
635 codec_preferences_ = codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200636 }
637
Johannes Kron3e983682020-03-29 22:17:00 +0200638 return result;
Steve Anton6e634bf2017-11-13 10:44:53 -0800639}
640
Markus Handell0357b3e2020-03-16 13:40:51 +0100641std::vector<RtpHeaderExtensionCapability>
642RtpTransceiver::HeaderExtensionsToOffer() const {
Markus Handell755c65d2020-06-24 01:06:10 +0200643 return header_extensions_to_offer_;
644}
645
Markus Handell5932fe12020-12-17 22:19:40 +0100646std::vector<RtpHeaderExtensionCapability>
647RtpTransceiver::HeaderExtensionsNegotiated() const {
Tommicc7a3682021-05-04 14:59:38 +0200648 RTC_DCHECK_RUN_ON(thread_);
Markus Handell5932fe12020-12-17 22:19:40 +0100649 std::vector<RtpHeaderExtensionCapability> result;
Tommicc7a3682021-05-04 14:59:38 +0200650 for (const auto& ext : negotiated_header_extensions_) {
Markus Handell5932fe12020-12-17 22:19:40 +0100651 result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
652 }
653 return result;
654}
655
Markus Handell755c65d2020-06-24 01:06:10 +0200656RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
657 rtc::ArrayView<const RtpHeaderExtensionCapability>
658 header_extensions_to_offer) {
659 for (const auto& entry : header_extensions_to_offer) {
660 // Handle unsupported requests for mandatory extensions as per
661 // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
662 // Note:
663 // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
664 // this has to be checked on a higher level. We naturally error out
665 // in the handling of Step 2.2 if an unset URI is encountered.
666
667 // Step 2.2.
668 // Handle unknown extensions.
669 auto it = std::find_if(
670 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
671 [&entry](const auto& offered) { return entry.uri == offered.uri; });
672 if (it == header_extensions_to_offer_.end()) {
Markus Handellc17bca72021-01-14 17:08:01 +0100673 return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
Markus Handell755c65d2020-06-24 01:06:10 +0200674 "Attempted to modify an unoffered extension.");
675 }
676
677 // Step 2.4-2.5.
678 // - Use of the transceiver interface indicates unified plan is in effect,
679 // hence the MID extension needs to be enabled.
680 // - Also handle the mandatory video orientation extensions.
681 if ((entry.uri == RtpExtension::kMidUri ||
682 entry.uri == RtpExtension::kVideoRotationUri) &&
683 entry.direction != RtpTransceiverDirection::kSendRecv) {
684 return RTCError(RTCErrorType::INVALID_MODIFICATION,
685 "Attempted to stop a mandatory extension.");
686 }
687 }
688
689 // Apply mutation after error checking.
690 for (const auto& entry : header_extensions_to_offer) {
691 auto it = std::find_if(
692 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
693 [&entry](const auto& offered) { return entry.uri == offered.uri; });
694 it->direction = entry.direction;
695 }
696
697 return RTCError::OK();
Markus Handell0357b3e2020-03-16 13:40:51 +0100698}
699
Tommicc7a3682021-05-04 14:59:38 +0200700void RtpTransceiver::OnNegotiationUpdate(
701 SdpType sdp_type,
702 const cricket::MediaContentDescription* content) {
703 RTC_DCHECK_RUN_ON(thread_);
704 RTC_DCHECK(content);
705 if (sdp_type == SdpType::kAnswer)
706 negotiated_header_extensions_ = content->rtp_header_extensions();
707}
708
Harald Alvestrand6060df52020-08-11 09:54:02 +0200709void RtpTransceiver::SetPeerConnectionClosed() {
710 is_pc_closed_ = true;
711}
712
Steve Anton6e634bf2017-11-13 10:44:53 -0800713} // namespace webrtc