blob: 653b441abab7ea8e2610a304957bcbe1f6b716c7 [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 Alvestrand8f429922022-05-04 10:32:30 +000020#include "api/peer_connection_interface.h"
Markus Handell0357b3e2020-03-16 13:40:51 +010021#include "api/rtp_parameters.h"
Artem Titovd15a5752021-02-10 14:31:24 +010022#include "api/sequence_checker.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000023#include "media/base/codec.h"
24#include "media/base/media_constants.h"
Harald Alvestrand8f429922022-05-04 10:32:30 +000025#include "pc/channel.h"
Florent Castelli2d9d82e2019-04-23 19:25:51 +020026#include "pc/channel_manager.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "pc/rtp_media_utils.h"
Markus Handell5932fe12020-12-17 22:19:40 +010028#include "pc/session_description.h"
Yves Gerey3e707812018-11-28 16:47:49 +010029#include "rtc_base/checks.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000030#include "rtc_base/location.h"
Yves Gerey3e707812018-11-28 16:47:49 +010031#include "rtc_base/logging.h"
Tommi99c8a802021-04-27 15:00:00 +020032#include "rtc_base/task_utils/to_queued_task.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000033#include "rtc_base/thread.h"
Steve Antondcc3c022017-12-22 16:02:54 -080034
Steve Anton6e634bf2017-11-13 10:44:53 -080035namespace webrtc {
Johannes Kron3e983682020-03-29 22:17:00 +020036namespace {
37template <class T>
38RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
39 const std::vector<T>& send_codecs,
40 const std::vector<T>& recv_codecs) {
41 // If the intersection between codecs and
42 // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
43 // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
44 // RED or FEC codecs or is an empty set, throw InvalidModificationError.
45 // This ensures that we always have something to offer, regardless of
46 // transceiver.direction.
47
48 if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
49 return codec.name != cricket::kRtxCodecName &&
50 codec.name != cricket::kRedCodecName &&
51 codec.name != cricket::kFlexfecCodecName &&
52 absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
53 return recv_codec.MatchesCapability(codec);
54 });
55 })) {
56 return RTCError(RTCErrorType::INVALID_MODIFICATION,
57 "Invalid codec preferences: Missing codec from recv "
58 "codec capabilities.");
59 }
60
61 if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
62 return codec.name != cricket::kRtxCodecName &&
63 codec.name != cricket::kRedCodecName &&
64 codec.name != cricket::kFlexfecCodecName &&
65 absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
66 return send_codec.MatchesCapability(codec);
67 });
68 })) {
69 return RTCError(RTCErrorType::INVALID_MODIFICATION,
70 "Invalid codec preferences: Missing codec from send "
71 "codec capabilities.");
72 }
73
74 // Let codecCapabilities be the union of
75 // RTCRtpSender.getCapabilities(kind).codecs and
76 // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
77 // codec is not in codecCapabilities, throw InvalidModificationError.
78 for (const auto& codec_preference : codecs) {
79 bool is_recv_codec =
80 absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
81 return codec.MatchesCapability(codec_preference);
82 });
83
84 bool is_send_codec =
85 absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
86 return codec.MatchesCapability(codec_preference);
87 });
88
89 if (!is_recv_codec && !is_send_codec) {
90 return RTCError(
91 RTCErrorType::INVALID_MODIFICATION,
92 std::string("Invalid codec preferences: invalid codec with name \"") +
93 codec_preference.name + "\".");
94 }
95 }
96
97 // Check we have a real codec (not just rtx, red or fec)
98 if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
99 return codec.name == cricket::kRtxCodecName ||
100 codec.name == cricket::kRedCodecName ||
101 codec.name == cricket::kUlpfecCodecName;
102 })) {
103 return RTCError(RTCErrorType::INVALID_MODIFICATION,
104 "Invalid codec preferences: codec list must have a non "
105 "RTX, RED or FEC entry.");
106 }
107
108 return RTCError::OK();
109}
110
Harald Alvestrand6060df52020-08-11 09:54:02 +0200111TaskQueueBase* GetCurrentTaskQueueOrThread() {
112 TaskQueueBase* current = TaskQueueBase::Current();
113 if (!current)
114 current = rtc::ThreadManager::Instance()->CurrentThread();
115 return current;
116}
117
Johannes Kron3e983682020-03-29 22:17:00 +0200118} // namespace
Steve Anton6e634bf2017-11-13 10:44:53 -0800119
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000120RtpTransceiver::RtpTransceiver(cricket::MediaType media_type,
121 ConnectionContext* context)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200122 : thread_(GetCurrentTaskQueueOrThread()),
123 unified_plan_(false),
Tommi99c8a802021-04-27 15:00:00 +0200124 media_type_(media_type),
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000125 context_(context) {
Steve Anton6e634bf2017-11-13 10:44:53 -0800126 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
127 media_type == cricket::MEDIA_TYPE_VIDEO);
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000128 RTC_DCHECK(context_->channel_manager());
Steve Anton6e634bf2017-11-13 10:44:53 -0800129}
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());
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000147 RTC_DCHECK(context_->channel_manager());
Steve Anton79e79602017-11-20 10:25:56 -0800148 senders_.push_back(sender);
149 receivers_.push_back(receiver);
150}
151
Steve Anton6e634bf2017-11-13 10:44:53 -0800152RtpTransceiver::~RtpTransceiver() {
Tommi99c8a802021-04-27 15:00:00 +0200153 // TODO(tommi): On Android, when running PeerConnectionClientTest (e.g.
154 // PeerConnectionClientTest#testCameraSwitch), the instance doesn't get
155 // deleted on `thread_`. See if we can fix that.
Harald Alvestrand85466662021-04-19 21:21:36 +0000156 if (!stopped_) {
157 RTC_DCHECK_RUN_ON(thread_);
158 StopInternal();
159 }
Tomas Gunnarsson16de2162022-01-26 10:21:57 +0100160
Harald Alvestrand8f429922022-05-04 10:32:30 +0000161 RTC_CHECK(!channel_) << "Missing call to ClearChannel?";
162}
163
164RTCError RtpTransceiver::CreateChannel(
165 absl::string_view mid,
166 Call* call_ptr,
167 const cricket::MediaConfig& media_config,
168 bool srtp_required,
169 CryptoOptions crypto_options,
170 const cricket::AudioOptions& audio_options,
171 const cricket::VideoOptions& video_options,
172 VideoBitrateAllocatorFactory* video_bitrate_allocator_factory,
173 std::function<RtpTransportInternal*(absl::string_view)> transport_lookup) {
174 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000175 if (!media_engine()) {
Harald Alvestrand8f429922022-05-04 10:32:30 +0000176 // TODO(hta): Must be a better way
177 return RTCError(RTCErrorType::INTERNAL_ERROR,
178 "No media engine for mid=" + std::string(mid));
179 }
180 std::unique_ptr<cricket::ChannelInterface> new_channel;
181 if (media_type() == cricket::MEDIA_TYPE_AUDIO) {
182 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
183 // the worker thread. We shouldn't be using the `call_ptr_` hack here but
184 // simply be on the worker thread and use `call_` (update upstream code).
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000185 new_channel = channel_manager()->CreateVoiceChannel(
Harald Alvestrand8f429922022-05-04 10:32:30 +0000186 call_ptr, media_config, mid, srtp_required, crypto_options,
187 audio_options);
188
189 } else {
190 RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, media_type());
191
192 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
193 // the worker thread. We shouldn't be using the `call_ptr_` hack here but
194 // simply be on the worker thread and use `call_` (update upstream code).
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000195 new_channel = channel_manager()->CreateVideoChannel(
Harald Alvestrand8f429922022-05-04 10:32:30 +0000196 call_ptr, media_config, mid, srtp_required, crypto_options,
197 video_options, video_bitrate_allocator_factory);
198 }
199 if (!new_channel) {
200 // TODO(hta): Must be a better way
201 return RTCError(RTCErrorType::INTERNAL_ERROR,
202 "Failed to create channel for mid=" + std::string(mid));
203 }
204 SetChannel(std::move(new_channel), transport_lookup);
205 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800206}
207
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100208void RtpTransceiver::SetChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000209 std::unique_ptr<cricket::ChannelInterface> channel,
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100210 std::function<RtpTransportInternal*(const std::string&)> transport_lookup) {
Tommi99c8a802021-04-27 15:00:00 +0200211 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000212 RTC_DCHECK(channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000213 RTC_DCHECK(transport_lookup);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000214 RTC_DCHECK(!channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000215 // Cannot set a channel on a stopped transceiver.
Harald Alvestranddaee8702022-04-29 11:42:55 +0000216 if (stopped_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800217 return;
218 }
219
Tommife041642021-04-07 10:08:28 +0200220 RTC_LOG_THREAD_BLOCK_COUNT();
221
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000222 RTC_DCHECK_EQ(media_type(), channel->media_type());
223 signaling_thread_safety_ = PendingTaskSafetyFlag::Create();
Steve Anton60776752018-01-10 11:51:34 -0800224
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000225 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
226
Tommi99c8a802021-04-27 15:00:00 +0200227 // An alternative to this, could be to require SetChannel to be called
228 // on the network thread. The channel object operates for the most part
229 // on the network thread, as part of its initialization being on the network
230 // thread is required, so setting a channel object as part of the construction
231 // (without thread hopping) might be the more efficient thing to do than
232 // how SetChannel works today.
233 // Similarly, if the channel() accessor is limited to the network thread, that
234 // helps with keeping the channel implementation requirements being met and
235 // avoids synchronization for accessing the pointer or network related state.
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000236 context()->network_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000237 if (channel_) {
238 channel_->SetFirstPacketReceivedCallback(nullptr);
239 channel_->SetRtpTransport(nullptr);
240 channel_to_delete = std::move(channel_);
241 }
242
243 channel_ = std::move(channel);
Steve Anton60776752018-01-10 11:51:34 -0800244
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000245 channel_->SetRtpTransport(transport_lookup(channel_->mid()));
246 channel_->SetFirstPacketReceivedCallback(
247 [thread = thread_, flag = signaling_thread_safety_, this]() mutable {
248 thread->PostTask(ToQueuedTask(std::move(flag),
249 [this]() { OnFirstPacketReceived(); }));
250 });
Tommi99c8a802021-04-27 15:00:00 +0200251 });
Harald Alvestranddaee8702022-04-29 11:42:55 +0000252 PushNewMediaChannelAndDeleteChannel(nullptr);
Tommi6589def2022-02-17 23:36:47 +0100253
254 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
Steve Anton6e634bf2017-11-13 10:44:53 -0800255}
256
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000257void RtpTransceiver::ClearChannel() {
258 RTC_DCHECK_RUN_ON(thread_);
259
260 if (!channel_) {
261 return;
262 }
263
264 RTC_LOG_THREAD_BLOCK_COUNT();
265
266 if (channel_) {
267 signaling_thread_safety_->SetNotAlive();
268 signaling_thread_safety_ = nullptr;
269 }
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000270 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000271
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000272 context()->network_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000273 if (channel_) {
274 channel_->SetFirstPacketReceivedCallback(nullptr);
275 channel_->SetRtpTransport(nullptr);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000276 channel_to_delete = std::move(channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000277 }
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000278 });
279
280 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000281 PushNewMediaChannelAndDeleteChannel(std::move(channel_to_delete));
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000282
283 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
284}
285
Harald Alvestranddaee8702022-04-29 11:42:55 +0000286void RtpTransceiver::PushNewMediaChannelAndDeleteChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000287 std::unique_ptr<cricket::ChannelInterface> channel_to_delete) {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000288 // The clumsy combination of pushing down media channel and deleting
289 // the channel is due to the desire to do both things in one Invoke().
290 if (!channel_to_delete && senders_.empty() && receivers_.empty()) {
291 return;
292 }
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000293 context()->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000294 // Push down the new media_channel, if any, otherwise clear it.
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000295 auto* media_channel = channel_ ? channel_->media_channel() : nullptr;
296 for (const auto& sender : senders_) {
297 sender->internal()->SetMediaChannel(media_channel);
298 }
299
300 for (const auto& receiver : receivers_) {
301 receiver->internal()->SetMediaChannel(media_channel);
302 }
303
304 // Destroy the channel, if we had one, now _after_ updating the receivers
305 // who might have had references to the previous channel.
306 if (channel_to_delete) {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000307 channel_to_delete.reset(nullptr);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000308 }
309 });
310}
311
Steve Anton6e634bf2017-11-13 10:44:53 -0800312void RtpTransceiver::AddSender(
313 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
Tommi99c8a802021-04-27 15:00:00 +0200314 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800315 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800316 RTC_DCHECK(!unified_plan_);
317 RTC_DCHECK(sender);
Steve Anton69470252018-02-09 11:43:08 -0800318 RTC_DCHECK_EQ(media_type(), sender->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800319 RTC_DCHECK(!absl::c_linear_search(senders_, sender));
Steve Anton6e634bf2017-11-13 10:44:53 -0800320 senders_.push_back(sender);
321}
322
323bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
324 RTC_DCHECK(!unified_plan_);
325 if (sender) {
326 RTC_DCHECK_EQ(media_type(), sender->media_type());
327 }
Steve Anton64b626b2019-01-28 17:25:26 -0800328 auto it = absl::c_find(senders_, sender);
Steve Anton6e634bf2017-11-13 10:44:53 -0800329 if (it == senders_.end()) {
330 return false;
331 }
332 (*it)->internal()->Stop();
333 senders_.erase(it);
334 return true;
335}
336
337void RtpTransceiver::AddReceiver(
338 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
339 receiver) {
Tommi99c8a802021-04-27 15:00:00 +0200340 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800341 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800342 RTC_DCHECK(!unified_plan_);
343 RTC_DCHECK(receiver);
Steve Anton69470252018-02-09 11:43:08 -0800344 RTC_DCHECK_EQ(media_type(), receiver->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800345 RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
Steve Anton6e634bf2017-11-13 10:44:53 -0800346 receivers_.push_back(receiver);
347}
348
349bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
Tommi6589def2022-02-17 23:36:47 +0100350 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800351 RTC_DCHECK(!unified_plan_);
352 if (receiver) {
353 RTC_DCHECK_EQ(media_type(), receiver->media_type());
354 }
Steve Anton64b626b2019-01-28 17:25:26 -0800355 auto it = absl::c_find(receivers_, receiver);
Steve Anton6e634bf2017-11-13 10:44:53 -0800356 if (it == receivers_.end()) {
357 return false;
358 }
Tommi6589def2022-02-17 23:36:47 +0100359
Steve Anton6e634bf2017-11-13 10:44:53 -0800360 (*it)->internal()->Stop();
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000361 context()->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Tommi6589def2022-02-17 23:36:47 +0100362 // `Stop()` will clear the receiver's pointer to the media channel.
363 (*it)->internal()->SetMediaChannel(nullptr);
364 });
365
Steve Anton6e634bf2017-11-13 10:44:53 -0800366 receivers_.erase(it);
367 return true;
368}
369
Steve Antonf9381f02017-12-14 10:23:57 -0800370rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
371 RTC_DCHECK(unified_plan_);
372 RTC_CHECK_EQ(1u, senders_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100373 return rtc::scoped_refptr<RtpSenderInternal>(senders_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800374}
375
376rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
377 const {
378 RTC_DCHECK(unified_plan_);
379 RTC_CHECK_EQ(1u, receivers_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100380 return rtc::scoped_refptr<RtpReceiverInternal>(receivers_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800381}
382
Steve Anton69470252018-02-09 11:43:08 -0800383cricket::MediaType RtpTransceiver::media_type() const {
384 return media_type_;
385}
386
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200387absl::optional<std::string> RtpTransceiver::mid() const {
Steve Anton6e634bf2017-11-13 10:44:53 -0800388 return mid_;
389}
390
Tommi99c8a802021-04-27 15:00:00 +0200391void RtpTransceiver::OnFirstPacketReceived() {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100392 for (const auto& receiver : receivers_) {
Steve Anton60776752018-01-10 11:51:34 -0800393 receiver->internal()->NotifyFirstPacketReceived();
394 }
395}
396
Steve Anton6e634bf2017-11-13 10:44:53 -0800397rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
398 RTC_DCHECK(unified_plan_);
399 RTC_CHECK_EQ(1u, senders_.size());
400 return senders_[0];
401}
402
403rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
404 RTC_DCHECK(unified_plan_);
405 RTC_CHECK_EQ(1u, receivers_.size());
406 return receivers_[0];
407}
408
Steve Antondcc3c022017-12-22 16:02:54 -0800409void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
Steve Anton3d954a62018-04-02 11:27:23 -0700410 RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
411 << ") current direction from "
412 << (current_direction_ ? RtpTransceiverDirectionToString(
413 *current_direction_)
414 : "<not set>")
415 << " to " << RtpTransceiverDirectionToString(direction)
416 << ".";
Steve Antondcc3c022017-12-22 16:02:54 -0800417 current_direction_ = direction;
418 if (RtpTransceiverDirectionHasSend(*current_direction_)) {
419 has_ever_been_used_to_send_ = true;
420 }
421}
422
Henrik Boström0a162762022-05-02 15:47:52 +0200423void RtpTransceiver::set_fired_direction(
424 absl::optional<RtpTransceiverDirection> direction) {
Steve Anton0f5400a2018-07-17 14:25:36 -0700425 fired_direction_ = direction;
426}
427
Steve Anton6e634bf2017-11-13 10:44:53 -0800428bool RtpTransceiver::stopped() const {
Tommi99c8a802021-04-27 15:00:00 +0200429 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800430 return stopped_;
431}
432
Harald Alvestrand6060df52020-08-11 09:54:02 +0200433bool RtpTransceiver::stopping() const {
434 RTC_DCHECK_RUN_ON(thread_);
435 return stopping_;
436}
437
Steve Anton6e634bf2017-11-13 10:44:53 -0800438RtpTransceiverDirection RtpTransceiver::direction() const {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200439 if (unified_plan_ && stopping())
440 return webrtc::RtpTransceiverDirection::kStopped;
441
Steve Anton6e634bf2017-11-13 10:44:53 -0800442 return direction_;
443}
444
Harald Alvestrand6060df52020-08-11 09:54:02 +0200445RTCError RtpTransceiver::SetDirectionWithError(
446 RtpTransceiverDirection new_direction) {
447 if (unified_plan_ && stopping()) {
448 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
449 "Cannot set direction on a stopping transceiver.");
Steve Anton52d86772018-02-20 15:48:12 -0800450 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200451 if (new_direction == direction_)
452 return RTCError::OK();
453
454 if (new_direction == RtpTransceiverDirection::kStopped) {
455 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
456 "The set direction 'stopped' is invalid.");
Steve Anton52d86772018-02-20 15:48:12 -0800457 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200458
Steve Anton52d86772018-02-20 15:48:12 -0800459 direction_ = new_direction;
Harald Alvestrand280054f2020-11-10 13:12:53 +0000460 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200461
462 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800463}
464
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200465absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
Steve Anton6e634bf2017-11-13 10:44:53 -0800466 const {
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000467 if (unified_plan_ && stopped())
Harald Alvestrand6060df52020-08-11 09:54:02 +0200468 return webrtc::RtpTransceiverDirection::kStopped;
469
Steve Anton6e634bf2017-11-13 10:44:53 -0800470 return current_direction_;
471}
472
Steve Anton0f5400a2018-07-17 14:25:36 -0700473absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
474 const {
475 return fired_direction_;
476}
477
Harald Alvestrand6060df52020-08-11 09:54:02 +0200478void RtpTransceiver::StopSendingAndReceiving() {
479 // 1. Let sender be transceiver.[[Sender]].
480 // 2. Let receiver be transceiver.[[Receiver]].
481 //
482 // 3. Stop sending media with sender.
483 //
Tommi6589def2022-02-17 23:36:47 +0100484 RTC_DCHECK_RUN_ON(thread_);
485
Harald Alvestrand6060df52020-08-11 09:54:02 +0200486 // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
487 // specified in [RFC3550].
Harald Alvestrand6060df52020-08-11 09:54:02 +0200488 for (const auto& sender : senders_)
Steve Anton6e634bf2017-11-13 10:44:53 -0800489 sender->internal()->Stop();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200490
Tommi6589def2022-02-17 23:36:47 +0100491 // Signal to receiver sources that we're stopping.
Harald Alvestrand6060df52020-08-11 09:54:02 +0200492 for (const auto& receiver : receivers_)
Tommi6589def2022-02-17 23:36:47 +0100493 receiver->internal()->Stop();
494
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000495 context()->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Tommi6589def2022-02-17 23:36:47 +0100496 // 5 Stop receiving media with receiver.
497 for (const auto& receiver : receivers_)
498 receiver->internal()->SetMediaChannel(nullptr);
499 });
Harald Alvestrand6060df52020-08-11 09:54:02 +0200500
501 stopping_ = true;
502 direction_ = webrtc::RtpTransceiverDirection::kInactive;
503}
504
505RTCError RtpTransceiver::StopStandard() {
506 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000507 // If we're on Plan B, do what Stop() used to do there.
508 if (!unified_plan_) {
509 StopInternal();
510 return RTCError::OK();
511 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200512 // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
513 // invoked.
514 //
515 // 2. Let connection be the RTCPeerConnection object associated with
516 // transceiver.
517 //
518 // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
519 if (is_pc_closed_) {
520 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
521 "PeerConnection is closed.");
Harald Alvestranda88c9772020-08-10 18:06:09 +0000522 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200523
524 // 4. If transceiver.[[Stopping]] is true, abort these steps.
525 if (stopping_)
526 return RTCError::OK();
527
528 // 5. Stop sending and receiving given transceiver, and update the
529 // negotiation-needed flag for connection.
530 StopSendingAndReceiving();
Harald Alvestrand280054f2020-11-10 13:12:53 +0000531 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200532
533 return RTCError::OK();
534}
535
536void RtpTransceiver::StopInternal() {
Harald Alvestrand85466662021-04-19 21:21:36 +0000537 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000538 StopTransceiverProcedure();
539}
540
541void RtpTransceiver::StopTransceiverProcedure() {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200542 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000543 // As specified in the "Stop the RTCRtpTransceiver" procedure
Harald Alvestrand6060df52020-08-11 09:54:02 +0200544 // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
545 // transceiver.
546 if (!stopping_)
547 StopSendingAndReceiving();
548
549 // 2. Set transceiver.[[Stopped]] to true.
Steve Anton6e634bf2017-11-13 10:44:53 -0800550 stopped_ = true;
Harald Alvestrand6060df52020-08-11 09:54:02 +0200551
552 // Signal the updated change to the senders.
553 for (const auto& sender : senders_)
554 sender->internal()->SetTransceiverAsStopped();
555
556 // 3. Set transceiver.[[Receptive]] to false.
557 // 4. Set transceiver.[[CurrentDirection]] to null.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200558 current_direction_ = absl::nullopt;
Steve Anton6e634bf2017-11-13 10:44:53 -0800559}
560
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200561RTCError RtpTransceiver::SetCodecPreferences(
562 rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
563 RTC_DCHECK(unified_plan_);
Artem Titovc6c02ef2022-05-09 08:30:09 +0000564
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200565 // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
566 // to codecs and abort these steps.
567 if (codec_capabilities.empty()) {
568 codec_preferences_.clear();
569 return RTCError::OK();
570 }
571
572 // 4. Remove any duplicate values in codecs.
573 std::vector<RtpCodecCapability> codecs;
574 absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
575 [&codecs](const RtpCodecCapability& codec) {
576 return absl::c_linear_search(codecs, codec);
577 });
578
Johannes Kron3e983682020-03-29 22:17:00 +0200579 // 6. to 8.
580 RTCError result;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200581 if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200582 std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000583 send_codecs = media_engine()->voice().send_codecs();
584 recv_codecs = media_engine()->voice().recv_codecs();
Johannes Kron3e983682020-03-29 22:17:00 +0200585 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200586 } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
Johannes Kron3e983682020-03-29 22:17:00 +0200587 std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000588 send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
589 recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
Johannes Kron3e983682020-03-29 22:17:00 +0200590 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200591 }
592
Johannes Kron3e983682020-03-29 22:17:00 +0200593 if (result.ok()) {
594 codec_preferences_ = codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200595 }
596
Johannes Kron3e983682020-03-29 22:17:00 +0200597 return result;
Steve Anton6e634bf2017-11-13 10:44:53 -0800598}
599
Markus Handell0357b3e2020-03-16 13:40:51 +0100600std::vector<RtpHeaderExtensionCapability>
601RtpTransceiver::HeaderExtensionsToOffer() const {
Markus Handell755c65d2020-06-24 01:06:10 +0200602 return header_extensions_to_offer_;
603}
604
Markus Handell5932fe12020-12-17 22:19:40 +0100605std::vector<RtpHeaderExtensionCapability>
606RtpTransceiver::HeaderExtensionsNegotiated() const {
Tommicc7a3682021-05-04 14:59:38 +0200607 RTC_DCHECK_RUN_ON(thread_);
Markus Handell5932fe12020-12-17 22:19:40 +0100608 std::vector<RtpHeaderExtensionCapability> result;
Tommicc7a3682021-05-04 14:59:38 +0200609 for (const auto& ext : negotiated_header_extensions_) {
Markus Handell5932fe12020-12-17 22:19:40 +0100610 result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
611 }
612 return result;
613}
614
Markus Handell755c65d2020-06-24 01:06:10 +0200615RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
616 rtc::ArrayView<const RtpHeaderExtensionCapability>
617 header_extensions_to_offer) {
618 for (const auto& entry : header_extensions_to_offer) {
619 // Handle unsupported requests for mandatory extensions as per
620 // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
621 // Note:
622 // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
623 // this has to be checked on a higher level. We naturally error out
624 // in the handling of Step 2.2 if an unset URI is encountered.
625
626 // Step 2.2.
627 // Handle unknown extensions.
628 auto it = std::find_if(
629 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
630 [&entry](const auto& offered) { return entry.uri == offered.uri; });
631 if (it == header_extensions_to_offer_.end()) {
Markus Handellc17bca72021-01-14 17:08:01 +0100632 return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
Markus Handell755c65d2020-06-24 01:06:10 +0200633 "Attempted to modify an unoffered extension.");
634 }
635
636 // Step 2.4-2.5.
637 // - Use of the transceiver interface indicates unified plan is in effect,
638 // hence the MID extension needs to be enabled.
639 // - Also handle the mandatory video orientation extensions.
640 if ((entry.uri == RtpExtension::kMidUri ||
641 entry.uri == RtpExtension::kVideoRotationUri) &&
642 entry.direction != RtpTransceiverDirection::kSendRecv) {
643 return RTCError(RTCErrorType::INVALID_MODIFICATION,
644 "Attempted to stop a mandatory extension.");
645 }
646 }
647
648 // Apply mutation after error checking.
649 for (const auto& entry : header_extensions_to_offer) {
650 auto it = std::find_if(
651 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
652 [&entry](const auto& offered) { return entry.uri == offered.uri; });
653 it->direction = entry.direction;
654 }
655
656 return RTCError::OK();
Markus Handell0357b3e2020-03-16 13:40:51 +0100657}
658
Tommicc7a3682021-05-04 14:59:38 +0200659void RtpTransceiver::OnNegotiationUpdate(
660 SdpType sdp_type,
661 const cricket::MediaContentDescription* content) {
662 RTC_DCHECK_RUN_ON(thread_);
663 RTC_DCHECK(content);
664 if (sdp_type == SdpType::kAnswer)
665 negotiated_header_extensions_ = content->rtp_header_extensions();
666}
667
Harald Alvestrand6060df52020-08-11 09:54:02 +0200668void RtpTransceiver::SetPeerConnectionClosed() {
669 is_pc_closed_ = true;
670}
671
Steve Anton6e634bf2017-11-13 10:44:53 -0800672} // namespace webrtc