blob: d7474185eb859c783f8557dac7047272e27b0cb6 [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"
Markus Handell0357b3e2020-03-16 13:40:51 +010020#include "api/rtp_parameters.h"
Artem Titovd15a5752021-02-10 14:31:24 +010021#include "api/sequence_checker.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000022#include "media/base/codec.h"
23#include "media/base/media_constants.h"
Florent Castelli2d9d82e2019-04-23 19:25:51 +020024#include "pc/channel_manager.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "pc/rtp_media_utils.h"
Markus Handell5932fe12020-12-17 22:19:40 +010026#include "pc/session_description.h"
Yves Gerey3e707812018-11-28 16:47:49 +010027#include "rtc_base/checks.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000028#include "rtc_base/location.h"
Yves Gerey3e707812018-11-28 16:47:49 +010029#include "rtc_base/logging.h"
Tommi99c8a802021-04-27 15:00:00 +020030#include "rtc_base/task_utils/to_queued_task.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000031#include "rtc_base/thread.h"
Steve Antondcc3c022017-12-22 16:02:54 -080032
Steve Anton6e634bf2017-11-13 10:44:53 -080033namespace webrtc {
Johannes Kron3e983682020-03-29 22:17:00 +020034namespace {
35template <class T>
36RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
37 const std::vector<T>& send_codecs,
38 const std::vector<T>& recv_codecs) {
39 // If the intersection between codecs and
40 // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
41 // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
42 // RED or FEC codecs or is an empty set, throw InvalidModificationError.
43 // This ensures that we always have something to offer, regardless of
44 // transceiver.direction.
45
46 if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
47 return codec.name != cricket::kRtxCodecName &&
48 codec.name != cricket::kRedCodecName &&
49 codec.name != cricket::kFlexfecCodecName &&
50 absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
51 return recv_codec.MatchesCapability(codec);
52 });
53 })) {
54 return RTCError(RTCErrorType::INVALID_MODIFICATION,
55 "Invalid codec preferences: Missing codec from recv "
56 "codec capabilities.");
57 }
58
59 if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
60 return codec.name != cricket::kRtxCodecName &&
61 codec.name != cricket::kRedCodecName &&
62 codec.name != cricket::kFlexfecCodecName &&
63 absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
64 return send_codec.MatchesCapability(codec);
65 });
66 })) {
67 return RTCError(RTCErrorType::INVALID_MODIFICATION,
68 "Invalid codec preferences: Missing codec from send "
69 "codec capabilities.");
70 }
71
72 // Let codecCapabilities be the union of
73 // RTCRtpSender.getCapabilities(kind).codecs and
74 // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
75 // codec is not in codecCapabilities, throw InvalidModificationError.
76 for (const auto& codec_preference : codecs) {
77 bool is_recv_codec =
78 absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
79 return codec.MatchesCapability(codec_preference);
80 });
81
82 bool is_send_codec =
83 absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
84 return codec.MatchesCapability(codec_preference);
85 });
86
87 if (!is_recv_codec && !is_send_codec) {
88 return RTCError(
89 RTCErrorType::INVALID_MODIFICATION,
90 std::string("Invalid codec preferences: invalid codec with name \"") +
91 codec_preference.name + "\".");
92 }
93 }
94
95 // Check we have a real codec (not just rtx, red or fec)
96 if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
97 return codec.name == cricket::kRtxCodecName ||
98 codec.name == cricket::kRedCodecName ||
99 codec.name == cricket::kUlpfecCodecName;
100 })) {
101 return RTCError(RTCErrorType::INVALID_MODIFICATION,
102 "Invalid codec preferences: codec list must have a non "
103 "RTX, RED or FEC entry.");
104 }
105
106 return RTCError::OK();
107}
108
Harald Alvestrand6060df52020-08-11 09:54:02 +0200109TaskQueueBase* GetCurrentTaskQueueOrThread() {
110 TaskQueueBase* current = TaskQueueBase::Current();
111 if (!current)
112 current = rtc::ThreadManager::Instance()->CurrentThread();
113 return current;
114}
115
Johannes Kron3e983682020-03-29 22:17:00 +0200116} // namespace
Steve Anton6e634bf2017-11-13 10:44:53 -0800117
Tommi99c8a802021-04-27 15:00:00 +0200118RtpTransceiver::RtpTransceiver(
119 cricket::MediaType media_type,
120 cricket::ChannelManager* channel_manager /* = nullptr*/)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200121 : thread_(GetCurrentTaskQueueOrThread()),
122 unified_plan_(false),
Tommi99c8a802021-04-27 15:00:00 +0200123 media_type_(media_type),
124 channel_manager_(channel_manager) {
Steve Anton6e634bf2017-11-13 10:44:53 -0800125 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
126 media_type == cricket::MEDIA_TYPE_VIDEO);
Tommi99c8a802021-04-27 15:00:00 +0200127 RTC_DCHECK(channel_manager_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800128}
129
Steve Anton79e79602017-11-20 10:25:56 -0800130RtpTransceiver::RtpTransceiver(
131 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
132 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200133 receiver,
Markus Handell0357b3e2020-03-16 13:40:51 +0100134 cricket::ChannelManager* channel_manager,
Harald Alvestrand280054f2020-11-10 13:12:53 +0000135 std::vector<RtpHeaderExtensionCapability> header_extensions_offered,
136 std::function<void()> on_negotiation_needed)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200137 : thread_(GetCurrentTaskQueueOrThread()),
138 unified_plan_(true),
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200139 media_type_(sender->media_type()),
Markus Handell0357b3e2020-03-16 13:40:51 +0100140 channel_manager_(channel_manager),
Harald Alvestrand280054f2020-11-10 13:12:53 +0000141 header_extensions_to_offer_(std::move(header_extensions_offered)),
142 on_negotiation_needed_(std::move(on_negotiation_needed)) {
Steve Anton79e79602017-11-20 10:25:56 -0800143 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
144 media_type_ == cricket::MEDIA_TYPE_VIDEO);
145 RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
Tommi99c8a802021-04-27 15:00:00 +0200146 RTC_DCHECK(channel_manager_);
Steve Anton79e79602017-11-20 10:25:56 -0800147 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
160 RTC_CHECK(!channel_) << "Missing call to SetChannel(nullptr)?";
Steve Anton6e634bf2017-11-13 10:44:53 -0800161}
162
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100163void RtpTransceiver::SetChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000164 std::unique_ptr<cricket::ChannelInterface> channel,
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100165 std::function<RtpTransportInternal*(const std::string&)> transport_lookup) {
Tommi99c8a802021-04-27 15:00:00 +0200166 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000167 RTC_DCHECK(channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000168 RTC_DCHECK(transport_lookup);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000169 RTC_DCHECK(!channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000170 // Cannot set a channel on a stopped transceiver.
Harald Alvestranddaee8702022-04-29 11:42:55 +0000171 if (stopped_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800172 return;
173 }
174
Tommife041642021-04-07 10:08:28 +0200175 RTC_LOG_THREAD_BLOCK_COUNT();
176
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000177 RTC_DCHECK_EQ(media_type(), channel->media_type());
178 signaling_thread_safety_ = PendingTaskSafetyFlag::Create();
Steve Anton60776752018-01-10 11:51:34 -0800179
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000180 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
181
Tommi99c8a802021-04-27 15:00:00 +0200182 // An alternative to this, could be to require SetChannel to be called
183 // on the network thread. The channel object operates for the most part
184 // on the network thread, as part of its initialization being on the network
185 // thread is required, so setting a channel object as part of the construction
186 // (without thread hopping) might be the more efficient thing to do than
187 // how SetChannel works today.
188 // Similarly, if the channel() accessor is limited to the network thread, that
189 // helps with keeping the channel implementation requirements being met and
190 // avoids synchronization for accessing the pointer or network related state.
191 channel_manager_->network_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000192 if (channel_) {
193 channel_->SetFirstPacketReceivedCallback(nullptr);
194 channel_->SetRtpTransport(nullptr);
195 channel_to_delete = std::move(channel_);
196 }
197
198 channel_ = std::move(channel);
Steve Anton60776752018-01-10 11:51:34 -0800199
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000200 channel_->SetRtpTransport(transport_lookup(channel_->mid()));
201 channel_->SetFirstPacketReceivedCallback(
202 [thread = thread_, flag = signaling_thread_safety_, this]() mutable {
203 thread->PostTask(ToQueuedTask(std::move(flag),
204 [this]() { OnFirstPacketReceived(); }));
205 });
Tommi99c8a802021-04-27 15:00:00 +0200206 });
Harald Alvestranddaee8702022-04-29 11:42:55 +0000207 PushNewMediaChannelAndDeleteChannel(nullptr);
Tommi6589def2022-02-17 23:36:47 +0100208
209 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
Steve Anton6e634bf2017-11-13 10:44:53 -0800210}
211
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000212void RtpTransceiver::ClearChannel() {
213 RTC_DCHECK_RUN_ON(thread_);
214
215 if (!channel_) {
216 return;
217 }
218
219 RTC_LOG_THREAD_BLOCK_COUNT();
220
221 if (channel_) {
222 signaling_thread_safety_->SetNotAlive();
223 signaling_thread_safety_ = nullptr;
224 }
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000225 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000226
227 channel_manager_->network_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
228 if (channel_) {
229 channel_->SetFirstPacketReceivedCallback(nullptr);
230 channel_->SetRtpTransport(nullptr);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000231 channel_to_delete = std::move(channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000232 }
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000233 });
234
235 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000236 PushNewMediaChannelAndDeleteChannel(std::move(channel_to_delete));
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000237
238 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
239}
240
Harald Alvestranddaee8702022-04-29 11:42:55 +0000241void RtpTransceiver::PushNewMediaChannelAndDeleteChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000242 std::unique_ptr<cricket::ChannelInterface> channel_to_delete) {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000243 // The clumsy combination of pushing down media channel and deleting
244 // the channel is due to the desire to do both things in one Invoke().
245 if (!channel_to_delete && senders_.empty() && receivers_.empty()) {
246 return;
247 }
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000248 channel_manager_->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000249 // Push down the new media_channel, if any, otherwise clear it.
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000250 auto* media_channel = channel_ ? channel_->media_channel() : nullptr;
251 for (const auto& sender : senders_) {
252 sender->internal()->SetMediaChannel(media_channel);
253 }
254
255 for (const auto& receiver : receivers_) {
256 receiver->internal()->SetMediaChannel(media_channel);
257 }
258
259 // Destroy the channel, if we had one, now _after_ updating the receivers
260 // who might have had references to the previous channel.
261 if (channel_to_delete) {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000262 channel_to_delete.reset(nullptr);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000263 }
264 });
265}
266
Steve Anton6e634bf2017-11-13 10:44:53 -0800267void RtpTransceiver::AddSender(
268 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
Tommi99c8a802021-04-27 15:00:00 +0200269 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800270 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800271 RTC_DCHECK(!unified_plan_);
272 RTC_DCHECK(sender);
Steve Anton69470252018-02-09 11:43:08 -0800273 RTC_DCHECK_EQ(media_type(), sender->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800274 RTC_DCHECK(!absl::c_linear_search(senders_, sender));
Steve Anton6e634bf2017-11-13 10:44:53 -0800275 senders_.push_back(sender);
276}
277
278bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
279 RTC_DCHECK(!unified_plan_);
280 if (sender) {
281 RTC_DCHECK_EQ(media_type(), sender->media_type());
282 }
Steve Anton64b626b2019-01-28 17:25:26 -0800283 auto it = absl::c_find(senders_, sender);
Steve Anton6e634bf2017-11-13 10:44:53 -0800284 if (it == senders_.end()) {
285 return false;
286 }
287 (*it)->internal()->Stop();
288 senders_.erase(it);
289 return true;
290}
291
292void RtpTransceiver::AddReceiver(
293 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
294 receiver) {
Tommi99c8a802021-04-27 15:00:00 +0200295 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800296 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800297 RTC_DCHECK(!unified_plan_);
298 RTC_DCHECK(receiver);
Steve Anton69470252018-02-09 11:43:08 -0800299 RTC_DCHECK_EQ(media_type(), receiver->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800300 RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
Steve Anton6e634bf2017-11-13 10:44:53 -0800301 receivers_.push_back(receiver);
302}
303
304bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
Tommi6589def2022-02-17 23:36:47 +0100305 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800306 RTC_DCHECK(!unified_plan_);
307 if (receiver) {
308 RTC_DCHECK_EQ(media_type(), receiver->media_type());
309 }
Steve Anton64b626b2019-01-28 17:25:26 -0800310 auto it = absl::c_find(receivers_, receiver);
Steve Anton6e634bf2017-11-13 10:44:53 -0800311 if (it == receivers_.end()) {
312 return false;
313 }
Tommi6589def2022-02-17 23:36:47 +0100314
Steve Anton6e634bf2017-11-13 10:44:53 -0800315 (*it)->internal()->Stop();
Tommi6589def2022-02-17 23:36:47 +0100316 channel_manager_->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
317 // `Stop()` will clear the receiver's pointer to the media channel.
318 (*it)->internal()->SetMediaChannel(nullptr);
319 });
320
Steve Anton6e634bf2017-11-13 10:44:53 -0800321 receivers_.erase(it);
322 return true;
323}
324
Steve Antonf9381f02017-12-14 10:23:57 -0800325rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
326 RTC_DCHECK(unified_plan_);
327 RTC_CHECK_EQ(1u, senders_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100328 return rtc::scoped_refptr<RtpSenderInternal>(senders_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800329}
330
331rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
332 const {
333 RTC_DCHECK(unified_plan_);
334 RTC_CHECK_EQ(1u, receivers_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100335 return rtc::scoped_refptr<RtpReceiverInternal>(receivers_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800336}
337
Steve Anton69470252018-02-09 11:43:08 -0800338cricket::MediaType RtpTransceiver::media_type() const {
339 return media_type_;
340}
341
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200342absl::optional<std::string> RtpTransceiver::mid() const {
Steve Anton6e634bf2017-11-13 10:44:53 -0800343 return mid_;
344}
345
Tommi99c8a802021-04-27 15:00:00 +0200346void RtpTransceiver::OnFirstPacketReceived() {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100347 for (const auto& receiver : receivers_) {
Steve Anton60776752018-01-10 11:51:34 -0800348 receiver->internal()->NotifyFirstPacketReceived();
349 }
350}
351
Steve Anton6e634bf2017-11-13 10:44:53 -0800352rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
353 RTC_DCHECK(unified_plan_);
354 RTC_CHECK_EQ(1u, senders_.size());
355 return senders_[0];
356}
357
358rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
359 RTC_DCHECK(unified_plan_);
360 RTC_CHECK_EQ(1u, receivers_.size());
361 return receivers_[0];
362}
363
Steve Antondcc3c022017-12-22 16:02:54 -0800364void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
Steve Anton3d954a62018-04-02 11:27:23 -0700365 RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
366 << ") current direction from "
367 << (current_direction_ ? RtpTransceiverDirectionToString(
368 *current_direction_)
369 : "<not set>")
370 << " to " << RtpTransceiverDirectionToString(direction)
371 << ".";
Steve Antondcc3c022017-12-22 16:02:54 -0800372 current_direction_ = direction;
373 if (RtpTransceiverDirectionHasSend(*current_direction_)) {
374 has_ever_been_used_to_send_ = true;
375 }
376}
377
Steve Anton0f5400a2018-07-17 14:25:36 -0700378void RtpTransceiver::set_fired_direction(RtpTransceiverDirection direction) {
379 fired_direction_ = direction;
380}
381
Steve Anton6e634bf2017-11-13 10:44:53 -0800382bool RtpTransceiver::stopped() const {
Tommi99c8a802021-04-27 15:00:00 +0200383 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800384 return stopped_;
385}
386
Harald Alvestrand6060df52020-08-11 09:54:02 +0200387bool RtpTransceiver::stopping() const {
388 RTC_DCHECK_RUN_ON(thread_);
389 return stopping_;
390}
391
Steve Anton6e634bf2017-11-13 10:44:53 -0800392RtpTransceiverDirection RtpTransceiver::direction() const {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200393 if (unified_plan_ && stopping())
394 return webrtc::RtpTransceiverDirection::kStopped;
395
Steve Anton6e634bf2017-11-13 10:44:53 -0800396 return direction_;
397}
398
Harald Alvestrand6060df52020-08-11 09:54:02 +0200399RTCError RtpTransceiver::SetDirectionWithError(
400 RtpTransceiverDirection new_direction) {
401 if (unified_plan_ && stopping()) {
402 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
403 "Cannot set direction on a stopping transceiver.");
Steve Anton52d86772018-02-20 15:48:12 -0800404 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200405 if (new_direction == direction_)
406 return RTCError::OK();
407
408 if (new_direction == RtpTransceiverDirection::kStopped) {
409 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
410 "The set direction 'stopped' is invalid.");
Steve Anton52d86772018-02-20 15:48:12 -0800411 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200412
Steve Anton52d86772018-02-20 15:48:12 -0800413 direction_ = new_direction;
Harald Alvestrand280054f2020-11-10 13:12:53 +0000414 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200415
416 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800417}
418
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200419absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
Steve Anton6e634bf2017-11-13 10:44:53 -0800420 const {
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000421 if (unified_plan_ && stopped())
Harald Alvestrand6060df52020-08-11 09:54:02 +0200422 return webrtc::RtpTransceiverDirection::kStopped;
423
Steve Anton6e634bf2017-11-13 10:44:53 -0800424 return current_direction_;
425}
426
Steve Anton0f5400a2018-07-17 14:25:36 -0700427absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
428 const {
429 return fired_direction_;
430}
431
Harald Alvestrand6060df52020-08-11 09:54:02 +0200432void RtpTransceiver::StopSendingAndReceiving() {
433 // 1. Let sender be transceiver.[[Sender]].
434 // 2. Let receiver be transceiver.[[Receiver]].
435 //
436 // 3. Stop sending media with sender.
437 //
Tommi6589def2022-02-17 23:36:47 +0100438 RTC_DCHECK_RUN_ON(thread_);
439
Harald Alvestrand6060df52020-08-11 09:54:02 +0200440 // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
441 // specified in [RFC3550].
Harald Alvestrand6060df52020-08-11 09:54:02 +0200442 for (const auto& sender : senders_)
Steve Anton6e634bf2017-11-13 10:44:53 -0800443 sender->internal()->Stop();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200444
Tommi6589def2022-02-17 23:36:47 +0100445 // Signal to receiver sources that we're stopping.
Harald Alvestrand6060df52020-08-11 09:54:02 +0200446 for (const auto& receiver : receivers_)
Tommi6589def2022-02-17 23:36:47 +0100447 receiver->internal()->Stop();
448
449 channel_manager_->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&]() {
450 // 5 Stop receiving media with receiver.
451 for (const auto& receiver : receivers_)
452 receiver->internal()->SetMediaChannel(nullptr);
453 });
Harald Alvestrand6060df52020-08-11 09:54:02 +0200454
455 stopping_ = true;
456 direction_ = webrtc::RtpTransceiverDirection::kInactive;
457}
458
459RTCError RtpTransceiver::StopStandard() {
460 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000461 // If we're on Plan B, do what Stop() used to do there.
462 if (!unified_plan_) {
463 StopInternal();
464 return RTCError::OK();
465 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200466 // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
467 // invoked.
468 //
469 // 2. Let connection be the RTCPeerConnection object associated with
470 // transceiver.
471 //
472 // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
473 if (is_pc_closed_) {
474 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
475 "PeerConnection is closed.");
Harald Alvestranda88c9772020-08-10 18:06:09 +0000476 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200477
478 // 4. If transceiver.[[Stopping]] is true, abort these steps.
479 if (stopping_)
480 return RTCError::OK();
481
482 // 5. Stop sending and receiving given transceiver, and update the
483 // negotiation-needed flag for connection.
484 StopSendingAndReceiving();
Harald Alvestrand280054f2020-11-10 13:12:53 +0000485 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200486
487 return RTCError::OK();
488}
489
490void RtpTransceiver::StopInternal() {
Harald Alvestrand85466662021-04-19 21:21:36 +0000491 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000492 StopTransceiverProcedure();
493}
494
495void RtpTransceiver::StopTransceiverProcedure() {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200496 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000497 // As specified in the "Stop the RTCRtpTransceiver" procedure
Harald Alvestrand6060df52020-08-11 09:54:02 +0200498 // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
499 // transceiver.
500 if (!stopping_)
501 StopSendingAndReceiving();
502
503 // 2. Set transceiver.[[Stopped]] to true.
Steve Anton6e634bf2017-11-13 10:44:53 -0800504 stopped_ = true;
Harald Alvestrand6060df52020-08-11 09:54:02 +0200505
506 // Signal the updated change to the senders.
507 for (const auto& sender : senders_)
508 sender->internal()->SetTransceiverAsStopped();
509
510 // 3. Set transceiver.[[Receptive]] to false.
511 // 4. Set transceiver.[[CurrentDirection]] to null.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200512 current_direction_ = absl::nullopt;
Steve Anton6e634bf2017-11-13 10:44:53 -0800513}
514
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200515RTCError RtpTransceiver::SetCodecPreferences(
516 rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
517 RTC_DCHECK(unified_plan_);
518
519 // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
520 // to codecs and abort these steps.
521 if (codec_capabilities.empty()) {
522 codec_preferences_.clear();
523 return RTCError::OK();
524 }
525
526 // 4. Remove any duplicate values in codecs.
527 std::vector<RtpCodecCapability> codecs;
528 absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
529 [&codecs](const RtpCodecCapability& codec) {
530 return absl::c_linear_search(codecs, codec);
531 });
532
Johannes Kron3e983682020-03-29 22:17:00 +0200533 // 6. to 8.
534 RTCError result;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200535 if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200536 std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
537 channel_manager_->GetSupportedAudioReceiveCodecs(&recv_codecs);
538 channel_manager_->GetSupportedAudioSendCodecs(&send_codecs);
539
Johannes Kron3e983682020-03-29 22:17:00 +0200540 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200541 } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
Johannes Kron3e983682020-03-29 22:17:00 +0200542 std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
543 channel_manager_->GetSupportedVideoReceiveCodecs(&recv_codecs);
544 channel_manager_->GetSupportedVideoSendCodecs(&send_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200545
Johannes Kron3e983682020-03-29 22:17:00 +0200546 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200547 }
548
Johannes Kron3e983682020-03-29 22:17:00 +0200549 if (result.ok()) {
550 codec_preferences_ = codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200551 }
552
Johannes Kron3e983682020-03-29 22:17:00 +0200553 return result;
Steve Anton6e634bf2017-11-13 10:44:53 -0800554}
555
Markus Handell0357b3e2020-03-16 13:40:51 +0100556std::vector<RtpHeaderExtensionCapability>
557RtpTransceiver::HeaderExtensionsToOffer() const {
Markus Handell755c65d2020-06-24 01:06:10 +0200558 return header_extensions_to_offer_;
559}
560
Markus Handell5932fe12020-12-17 22:19:40 +0100561std::vector<RtpHeaderExtensionCapability>
562RtpTransceiver::HeaderExtensionsNegotiated() const {
Tommicc7a3682021-05-04 14:59:38 +0200563 RTC_DCHECK_RUN_ON(thread_);
Markus Handell5932fe12020-12-17 22:19:40 +0100564 std::vector<RtpHeaderExtensionCapability> result;
Tommicc7a3682021-05-04 14:59:38 +0200565 for (const auto& ext : negotiated_header_extensions_) {
Markus Handell5932fe12020-12-17 22:19:40 +0100566 result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
567 }
568 return result;
569}
570
Markus Handell755c65d2020-06-24 01:06:10 +0200571RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
572 rtc::ArrayView<const RtpHeaderExtensionCapability>
573 header_extensions_to_offer) {
574 for (const auto& entry : header_extensions_to_offer) {
575 // Handle unsupported requests for mandatory extensions as per
576 // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
577 // Note:
578 // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
579 // this has to be checked on a higher level. We naturally error out
580 // in the handling of Step 2.2 if an unset URI is encountered.
581
582 // Step 2.2.
583 // Handle unknown extensions.
584 auto it = std::find_if(
585 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
586 [&entry](const auto& offered) { return entry.uri == offered.uri; });
587 if (it == header_extensions_to_offer_.end()) {
Markus Handellc17bca72021-01-14 17:08:01 +0100588 return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
Markus Handell755c65d2020-06-24 01:06:10 +0200589 "Attempted to modify an unoffered extension.");
590 }
591
592 // Step 2.4-2.5.
593 // - Use of the transceiver interface indicates unified plan is in effect,
594 // hence the MID extension needs to be enabled.
595 // - Also handle the mandatory video orientation extensions.
596 if ((entry.uri == RtpExtension::kMidUri ||
597 entry.uri == RtpExtension::kVideoRotationUri) &&
598 entry.direction != RtpTransceiverDirection::kSendRecv) {
599 return RTCError(RTCErrorType::INVALID_MODIFICATION,
600 "Attempted to stop a mandatory extension.");
601 }
602 }
603
604 // Apply mutation after error checking.
605 for (const auto& entry : header_extensions_to_offer) {
606 auto it = std::find_if(
607 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
608 [&entry](const auto& offered) { return entry.uri == offered.uri; });
609 it->direction = entry.direction;
610 }
611
612 return RTCError::OK();
Markus Handell0357b3e2020-03-16 13:40:51 +0100613}
614
Tommicc7a3682021-05-04 14:59:38 +0200615void RtpTransceiver::OnNegotiationUpdate(
616 SdpType sdp_type,
617 const cricket::MediaContentDescription* content) {
618 RTC_DCHECK_RUN_ON(thread_);
619 RTC_DCHECK(content);
620 if (sdp_type == SdpType::kAnswer)
621 negotiated_header_extensions_ = content->rtp_header_extensions();
622}
623
Harald Alvestrand6060df52020-08-11 09:54:02 +0200624void RtpTransceiver::SetPeerConnectionClosed() {
625 is_pc_closed_ = true;
626}
627
Steve Anton6e634bf2017-11-13 10:44:53 -0800628} // namespace webrtc