blob: 791eb8c6432e2ff3168e7745809e0197ea17a264 [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"
31#include "rtc_base/logging.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000032#include "rtc_base/thread.h"
Steve Antondcc3c022017-12-22 16:02:54 -080033
Steve Anton6e634bf2017-11-13 10:44:53 -080034namespace webrtc {
Johannes Kron3e983682020-03-29 22:17:00 +020035namespace {
36template <class T>
37RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
38 const std::vector<T>& send_codecs,
39 const std::vector<T>& recv_codecs) {
40 // If the intersection between codecs and
41 // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
42 // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
43 // RED or FEC codecs or is an empty set, throw InvalidModificationError.
44 // This ensures that we always have something to offer, regardless of
45 // transceiver.direction.
46
47 if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
48 return codec.name != cricket::kRtxCodecName &&
49 codec.name != cricket::kRedCodecName &&
50 codec.name != cricket::kFlexfecCodecName &&
51 absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
52 return recv_codec.MatchesCapability(codec);
53 });
54 })) {
55 return RTCError(RTCErrorType::INVALID_MODIFICATION,
56 "Invalid codec preferences: Missing codec from recv "
57 "codec capabilities.");
58 }
59
60 if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
61 return codec.name != cricket::kRtxCodecName &&
62 codec.name != cricket::kRedCodecName &&
63 codec.name != cricket::kFlexfecCodecName &&
64 absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
65 return send_codec.MatchesCapability(codec);
66 });
67 })) {
68 return RTCError(RTCErrorType::INVALID_MODIFICATION,
69 "Invalid codec preferences: Missing codec from send "
70 "codec capabilities.");
71 }
72
73 // Let codecCapabilities be the union of
74 // RTCRtpSender.getCapabilities(kind).codecs and
75 // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
76 // codec is not in codecCapabilities, throw InvalidModificationError.
77 for (const auto& codec_preference : codecs) {
78 bool is_recv_codec =
79 absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
80 return codec.MatchesCapability(codec_preference);
81 });
82
83 bool is_send_codec =
84 absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
85 return codec.MatchesCapability(codec_preference);
86 });
87
88 if (!is_recv_codec && !is_send_codec) {
89 return RTCError(
90 RTCErrorType::INVALID_MODIFICATION,
91 std::string("Invalid codec preferences: invalid codec with name \"") +
92 codec_preference.name + "\".");
93 }
94 }
95
96 // Check we have a real codec (not just rtx, red or fec)
97 if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
98 return codec.name == cricket::kRtxCodecName ||
99 codec.name == cricket::kRedCodecName ||
100 codec.name == cricket::kUlpfecCodecName;
101 })) {
102 return RTCError(RTCErrorType::INVALID_MODIFICATION,
103 "Invalid codec preferences: codec list must have a non "
104 "RTX, RED or FEC entry.");
105 }
106
107 return RTCError::OK();
108}
109
Florent Castelli725ee242022-10-18 17:05:58 +0200110// Matches the list of codecs as capabilities (potentially without SVC related
111// information) to the list of send codecs and returns the list of codecs with
112// all the SVC related information.
113std::vector<cricket::VideoCodec> MatchCodecPreferences(
114 const std::vector<RtpCodecCapability>& codecs,
115 const std::vector<cricket::VideoCodec>& send_codecs) {
116 std::vector<cricket::VideoCodec> result;
117
118 for (const auto& codec_preference : codecs) {
119 for (const cricket::VideoCodec& send_codec : send_codecs) {
120 if (send_codec.MatchesCapability(codec_preference)) {
121 result.push_back(send_codec);
122 }
123 }
124 }
125
126 return result;
127}
128
Harald Alvestrand6060df52020-08-11 09:54:02 +0200129TaskQueueBase* GetCurrentTaskQueueOrThread() {
130 TaskQueueBase* current = TaskQueueBase::Current();
131 if (!current)
132 current = rtc::ThreadManager::Instance()->CurrentThread();
133 return current;
134}
135
Johannes Kron3e983682020-03-29 22:17:00 +0200136} // namespace
Steve Anton6e634bf2017-11-13 10:44:53 -0800137
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000138RtpTransceiver::RtpTransceiver(cricket::MediaType media_type,
139 ConnectionContext* context)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200140 : thread_(GetCurrentTaskQueueOrThread()),
141 unified_plan_(false),
Tommi99c8a802021-04-27 15:00:00 +0200142 media_type_(media_type),
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000143 context_(context) {
Steve Anton6e634bf2017-11-13 10:44:53 -0800144 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
145 media_type == cricket::MEDIA_TYPE_VIDEO);
146}
147
Steve Anton79e79602017-11-20 10:25:56 -0800148RtpTransceiver::RtpTransceiver(
149 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
150 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200151 receiver,
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000152 ConnectionContext* context,
Harald Alvestrand280054f2020-11-10 13:12:53 +0000153 std::vector<RtpHeaderExtensionCapability> header_extensions_offered,
154 std::function<void()> on_negotiation_needed)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200155 : thread_(GetCurrentTaskQueueOrThread()),
156 unified_plan_(true),
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200157 media_type_(sender->media_type()),
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000158 context_(context),
Harald Alvestrand280054f2020-11-10 13:12:53 +0000159 header_extensions_to_offer_(std::move(header_extensions_offered)),
160 on_negotiation_needed_(std::move(on_negotiation_needed)) {
Steve Anton79e79602017-11-20 10:25:56 -0800161 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
162 media_type_ == cricket::MEDIA_TYPE_VIDEO);
163 RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
Florent Castelli725ee242022-10-18 17:05:58 +0200164 if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO)
165 sender->internal()->SetVideoCodecPreferences(
166 media_engine()->video().send_codecs(false));
Steve Anton79e79602017-11-20 10:25:56 -0800167 senders_.push_back(sender);
168 receivers_.push_back(receiver);
169}
170
Steve Anton6e634bf2017-11-13 10:44:53 -0800171RtpTransceiver::~RtpTransceiver() {
Tommi99c8a802021-04-27 15:00:00 +0200172 // TODO(tommi): On Android, when running PeerConnectionClientTest (e.g.
173 // PeerConnectionClientTest#testCameraSwitch), the instance doesn't get
174 // deleted on `thread_`. See if we can fix that.
Harald Alvestrand85466662021-04-19 21:21:36 +0000175 if (!stopped_) {
176 RTC_DCHECK_RUN_ON(thread_);
177 StopInternal();
178 }
Tomas Gunnarsson16de2162022-01-26 10:21:57 +0100179
Harald Alvestrand8f429922022-05-04 10:32:30 +0000180 RTC_CHECK(!channel_) << "Missing call to ClearChannel?";
181}
182
183RTCError RtpTransceiver::CreateChannel(
184 absl::string_view mid,
185 Call* call_ptr,
186 const cricket::MediaConfig& media_config,
187 bool srtp_required,
188 CryptoOptions crypto_options,
189 const cricket::AudioOptions& audio_options,
190 const cricket::VideoOptions& video_options,
191 VideoBitrateAllocatorFactory* video_bitrate_allocator_factory,
192 std::function<RtpTransportInternal*(absl::string_view)> transport_lookup) {
193 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000194 if (!media_engine()) {
Harald Alvestrand8f429922022-05-04 10:32:30 +0000195 // TODO(hta): Must be a better way
196 return RTCError(RTCErrorType::INTERNAL_ERROR,
197 "No media engine for mid=" + std::string(mid));
198 }
199 std::unique_ptr<cricket::ChannelInterface> new_channel;
200 if (media_type() == cricket::MEDIA_TYPE_AUDIO) {
201 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
202 // the worker thread. We shouldn't be using the `call_ptr_` hack here but
203 // simply be on the worker thread and use `call_` (update upstream code).
Harald Alvestrand485457f2022-05-23 08:46:57 +0000204 RTC_DCHECK(call_ptr);
205 RTC_DCHECK(media_engine());
206 // TODO(bugs.webrtc.org/11992): Remove this workaround after updates in
207 // PeerConnection and add the expectation that we're already on the right
208 // thread.
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200209 context()->worker_thread()->BlockingCall([&] {
210 RTC_DCHECK_RUN_ON(context()->worker_thread());
Harald Alvestrand8f429922022-05-04 10:32:30 +0000211
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200212 cricket::VoiceMediaChannel* media_channel =
213 media_engine()->voice().CreateMediaChannel(
Harald Alvestrand16579cc2023-02-09 13:01:24 +0000214 cricket::MediaChannel::Role::kBoth, call_ptr, media_config,
215 audio_options, crypto_options);
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200216 if (!media_channel) {
217 return;
218 }
Harald Alvestrand485457f2022-05-23 08:46:57 +0000219
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200220 new_channel = std::make_unique<cricket::VoiceChannel>(
221 context()->worker_thread(), context()->network_thread(),
222 context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
223 srtp_required, crypto_options, context()->ssrc_generator());
224 });
Harald Alvestrand8f429922022-05-04 10:32:30 +0000225 } else {
226 RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, media_type());
227
228 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
229 // the worker thread. We shouldn't be using the `call_ptr_` hack here but
230 // simply be on the worker thread and use `call_` (update upstream code).
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200231 context()->worker_thread()->BlockingCall([&] {
232 RTC_DCHECK_RUN_ON(context()->worker_thread());
233 cricket::VideoMediaChannel* media_channel =
234 media_engine()->video().CreateMediaChannel(
Harald Alvestrand16579cc2023-02-09 13:01:24 +0000235 cricket::MediaChannel::Role::kBoth, call_ptr, media_config,
236 video_options, crypto_options, video_bitrate_allocator_factory);
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200237 if (!media_channel) {
238 return;
239 }
Harald Alvestrand485457f2022-05-23 08:46:57 +0000240
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200241 new_channel = std::make_unique<cricket::VideoChannel>(
242 context()->worker_thread(), context()->network_thread(),
243 context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
244 srtp_required, crypto_options, context()->ssrc_generator());
245 });
Harald Alvestrand8f429922022-05-04 10:32:30 +0000246 }
247 if (!new_channel) {
248 // TODO(hta): Must be a better way
249 return RTCError(RTCErrorType::INTERNAL_ERROR,
250 "Failed to create channel for mid=" + std::string(mid));
251 }
252 SetChannel(std::move(new_channel), transport_lookup);
253 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800254}
255
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100256void RtpTransceiver::SetChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000257 std::unique_ptr<cricket::ChannelInterface> channel,
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100258 std::function<RtpTransportInternal*(const std::string&)> transport_lookup) {
Tommi99c8a802021-04-27 15:00:00 +0200259 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000260 RTC_DCHECK(channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000261 RTC_DCHECK(transport_lookup);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000262 RTC_DCHECK(!channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000263 // Cannot set a channel on a stopped transceiver.
Harald Alvestranddaee8702022-04-29 11:42:55 +0000264 if (stopped_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800265 return;
266 }
267
Tommife041642021-04-07 10:08:28 +0200268 RTC_LOG_THREAD_BLOCK_COUNT();
269
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000270 RTC_DCHECK_EQ(media_type(), channel->media_type());
271 signaling_thread_safety_ = PendingTaskSafetyFlag::Create();
Steve Anton60776752018-01-10 11:51:34 -0800272
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000273 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
274
Tommi99c8a802021-04-27 15:00:00 +0200275 // An alternative to this, could be to require SetChannel to be called
276 // on the network thread. The channel object operates for the most part
277 // on the network thread, as part of its initialization being on the network
278 // thread is required, so setting a channel object as part of the construction
279 // (without thread hopping) might be the more efficient thing to do than
280 // how SetChannel works today.
281 // Similarly, if the channel() accessor is limited to the network thread, that
282 // helps with keeping the channel implementation requirements being met and
283 // avoids synchronization for accessing the pointer or network related state.
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200284 context()->network_thread()->BlockingCall([&]() {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000285 if (channel_) {
286 channel_->SetFirstPacketReceivedCallback(nullptr);
287 channel_->SetRtpTransport(nullptr);
288 channel_to_delete = std::move(channel_);
289 }
290
291 channel_ = std::move(channel);
Steve Anton60776752018-01-10 11:51:34 -0800292
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000293 channel_->SetRtpTransport(transport_lookup(channel_->mid()));
294 channel_->SetFirstPacketReceivedCallback(
295 [thread = thread_, flag = signaling_thread_safety_, this]() mutable {
Danil Chapovalova30439b2022-07-07 10:08:49 +0200296 thread->PostTask(
297 SafeTask(std::move(flag), [this]() { OnFirstPacketReceived(); }));
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000298 });
Tommi99c8a802021-04-27 15:00:00 +0200299 });
Harald Alvestranddaee8702022-04-29 11:42:55 +0000300 PushNewMediaChannelAndDeleteChannel(nullptr);
Tommi6589def2022-02-17 23:36:47 +0100301
302 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
Steve Anton6e634bf2017-11-13 10:44:53 -0800303}
304
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000305void RtpTransceiver::ClearChannel() {
306 RTC_DCHECK_RUN_ON(thread_);
307
308 if (!channel_) {
309 return;
310 }
311
312 RTC_LOG_THREAD_BLOCK_COUNT();
313
314 if (channel_) {
315 signaling_thread_safety_->SetNotAlive();
316 signaling_thread_safety_ = nullptr;
317 }
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000318 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000319
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200320 context()->network_thread()->BlockingCall([&]() {
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000321 if (channel_) {
322 channel_->SetFirstPacketReceivedCallback(nullptr);
323 channel_->SetRtpTransport(nullptr);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000324 channel_to_delete = std::move(channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000325 }
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000326 });
327
328 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000329 PushNewMediaChannelAndDeleteChannel(std::move(channel_to_delete));
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000330
331 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
332}
333
Harald Alvestranddaee8702022-04-29 11:42:55 +0000334void RtpTransceiver::PushNewMediaChannelAndDeleteChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000335 std::unique_ptr<cricket::ChannelInterface> channel_to_delete) {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000336 // The clumsy combination of pushing down media channel and deleting
337 // the channel is due to the desire to do both things in one Invoke().
338 if (!channel_to_delete && senders_.empty() && receivers_.empty()) {
339 return;
340 }
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200341 context()->worker_thread()->BlockingCall([&]() {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000342 // Push down the new media_channel, if any, otherwise clear it.
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000343 auto* media_send_channel =
344 channel_ ? channel_->media_send_channel() : nullptr;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000345 for (const auto& sender : senders_) {
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000346 sender->internal()->SetMediaChannel(media_send_channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000347 }
348
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000349 auto* media_receive_channel =
350 channel_ ? channel_->media_receive_channel() : nullptr;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000351 for (const auto& receiver : receivers_) {
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000352 receiver->internal()->SetMediaChannel(media_receive_channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000353 }
354
355 // Destroy the channel, if we had one, now _after_ updating the receivers
356 // who might have had references to the previous channel.
357 if (channel_to_delete) {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000358 channel_to_delete.reset(nullptr);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000359 }
360 });
361}
362
Steve Anton6e634bf2017-11-13 10:44:53 -0800363void RtpTransceiver::AddSender(
364 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
Tommi99c8a802021-04-27 15:00:00 +0200365 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800366 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800367 RTC_DCHECK(!unified_plan_);
368 RTC_DCHECK(sender);
Steve Anton69470252018-02-09 11:43:08 -0800369 RTC_DCHECK_EQ(media_type(), sender->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800370 RTC_DCHECK(!absl::c_linear_search(senders_, sender));
Florent Castelli725ee242022-10-18 17:05:58 +0200371 if (media_type() == cricket::MEDIA_TYPE_VIDEO) {
372 std::vector<cricket::VideoCodec> send_codecs =
373 media_engine()->video().send_codecs(false);
374 sender->internal()->SetVideoCodecPreferences(
375 codec_preferences_.empty()
376 ? send_codecs
377 : MatchCodecPreferences(codec_preferences_, send_codecs));
378 }
Steve Anton6e634bf2017-11-13 10:44:53 -0800379 senders_.push_back(sender);
380}
381
382bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
383 RTC_DCHECK(!unified_plan_);
384 if (sender) {
385 RTC_DCHECK_EQ(media_type(), sender->media_type());
386 }
Steve Anton64b626b2019-01-28 17:25:26 -0800387 auto it = absl::c_find(senders_, sender);
Steve Anton6e634bf2017-11-13 10:44:53 -0800388 if (it == senders_.end()) {
389 return false;
390 }
391 (*it)->internal()->Stop();
392 senders_.erase(it);
393 return true;
394}
395
396void RtpTransceiver::AddReceiver(
397 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
398 receiver) {
Tommi99c8a802021-04-27 15:00:00 +0200399 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800400 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800401 RTC_DCHECK(!unified_plan_);
402 RTC_DCHECK(receiver);
Steve Anton69470252018-02-09 11:43:08 -0800403 RTC_DCHECK_EQ(media_type(), receiver->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800404 RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
Steve Anton6e634bf2017-11-13 10:44:53 -0800405 receivers_.push_back(receiver);
406}
407
408bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
Tommi6589def2022-02-17 23:36:47 +0100409 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800410 RTC_DCHECK(!unified_plan_);
411 if (receiver) {
412 RTC_DCHECK_EQ(media_type(), receiver->media_type());
413 }
Steve Anton64b626b2019-01-28 17:25:26 -0800414 auto it = absl::c_find(receivers_, receiver);
Steve Anton6e634bf2017-11-13 10:44:53 -0800415 if (it == receivers_.end()) {
416 return false;
417 }
Tommi6589def2022-02-17 23:36:47 +0100418
Steve Anton6e634bf2017-11-13 10:44:53 -0800419 (*it)->internal()->Stop();
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200420 context()->worker_thread()->BlockingCall([&]() {
Tommi6589def2022-02-17 23:36:47 +0100421 // `Stop()` will clear the receiver's pointer to the media channel.
422 (*it)->internal()->SetMediaChannel(nullptr);
423 });
424
Steve Anton6e634bf2017-11-13 10:44:53 -0800425 receivers_.erase(it);
426 return true;
427}
428
Steve Antonf9381f02017-12-14 10:23:57 -0800429rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
430 RTC_DCHECK(unified_plan_);
431 RTC_CHECK_EQ(1u, senders_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100432 return rtc::scoped_refptr<RtpSenderInternal>(senders_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800433}
434
435rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
436 const {
437 RTC_DCHECK(unified_plan_);
438 RTC_CHECK_EQ(1u, receivers_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100439 return rtc::scoped_refptr<RtpReceiverInternal>(receivers_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800440}
441
Steve Anton69470252018-02-09 11:43:08 -0800442cricket::MediaType RtpTransceiver::media_type() const {
443 return media_type_;
444}
445
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200446absl::optional<std::string> RtpTransceiver::mid() const {
Steve Anton6e634bf2017-11-13 10:44:53 -0800447 return mid_;
448}
449
Tommi99c8a802021-04-27 15:00:00 +0200450void RtpTransceiver::OnFirstPacketReceived() {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100451 for (const auto& receiver : receivers_) {
Steve Anton60776752018-01-10 11:51:34 -0800452 receiver->internal()->NotifyFirstPacketReceived();
453 }
454}
455
Steve Anton6e634bf2017-11-13 10:44:53 -0800456rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
457 RTC_DCHECK(unified_plan_);
458 RTC_CHECK_EQ(1u, senders_.size());
459 return senders_[0];
460}
461
462rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
463 RTC_DCHECK(unified_plan_);
464 RTC_CHECK_EQ(1u, receivers_.size());
465 return receivers_[0];
466}
467
Steve Antondcc3c022017-12-22 16:02:54 -0800468void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
Steve Anton3d954a62018-04-02 11:27:23 -0700469 RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
470 << ") current direction from "
471 << (current_direction_ ? RtpTransceiverDirectionToString(
472 *current_direction_)
473 : "<not set>")
474 << " to " << RtpTransceiverDirectionToString(direction)
475 << ".";
Steve Antondcc3c022017-12-22 16:02:54 -0800476 current_direction_ = direction;
477 if (RtpTransceiverDirectionHasSend(*current_direction_)) {
478 has_ever_been_used_to_send_ = true;
479 }
480}
481
Henrik Boström0a162762022-05-02 15:47:52 +0200482void RtpTransceiver::set_fired_direction(
483 absl::optional<RtpTransceiverDirection> direction) {
Steve Anton0f5400a2018-07-17 14:25:36 -0700484 fired_direction_ = direction;
485}
486
Steve Anton6e634bf2017-11-13 10:44:53 -0800487bool RtpTransceiver::stopped() const {
Tommi99c8a802021-04-27 15:00:00 +0200488 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800489 return stopped_;
490}
491
Harald Alvestrand6060df52020-08-11 09:54:02 +0200492bool RtpTransceiver::stopping() const {
493 RTC_DCHECK_RUN_ON(thread_);
494 return stopping_;
495}
496
Steve Anton6e634bf2017-11-13 10:44:53 -0800497RtpTransceiverDirection RtpTransceiver::direction() const {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200498 if (unified_plan_ && stopping())
499 return webrtc::RtpTransceiverDirection::kStopped;
500
Steve Anton6e634bf2017-11-13 10:44:53 -0800501 return direction_;
502}
503
Harald Alvestrand6060df52020-08-11 09:54:02 +0200504RTCError RtpTransceiver::SetDirectionWithError(
505 RtpTransceiverDirection new_direction) {
506 if (unified_plan_ && stopping()) {
507 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
508 "Cannot set direction on a stopping transceiver.");
Steve Anton52d86772018-02-20 15:48:12 -0800509 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200510 if (new_direction == direction_)
511 return RTCError::OK();
512
513 if (new_direction == RtpTransceiverDirection::kStopped) {
514 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
515 "The set direction 'stopped' is invalid.");
Steve Anton52d86772018-02-20 15:48:12 -0800516 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200517
Steve Anton52d86772018-02-20 15:48:12 -0800518 direction_ = new_direction;
Harald Alvestrand280054f2020-11-10 13:12:53 +0000519 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200520
521 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800522}
523
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200524absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
Steve Anton6e634bf2017-11-13 10:44:53 -0800525 const {
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000526 if (unified_plan_ && stopped())
Harald Alvestrand6060df52020-08-11 09:54:02 +0200527 return webrtc::RtpTransceiverDirection::kStopped;
528
Steve Anton6e634bf2017-11-13 10:44:53 -0800529 return current_direction_;
530}
531
Steve Anton0f5400a2018-07-17 14:25:36 -0700532absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
533 const {
534 return fired_direction_;
535}
536
Harald Alvestrand6060df52020-08-11 09:54:02 +0200537void RtpTransceiver::StopSendingAndReceiving() {
538 // 1. Let sender be transceiver.[[Sender]].
539 // 2. Let receiver be transceiver.[[Receiver]].
540 //
541 // 3. Stop sending media with sender.
542 //
Tommi6589def2022-02-17 23:36:47 +0100543 RTC_DCHECK_RUN_ON(thread_);
544
Harald Alvestrand6060df52020-08-11 09:54:02 +0200545 // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
546 // specified in [RFC3550].
Harald Alvestrand6060df52020-08-11 09:54:02 +0200547 for (const auto& sender : senders_)
Steve Anton6e634bf2017-11-13 10:44:53 -0800548 sender->internal()->Stop();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200549
Tommi6589def2022-02-17 23:36:47 +0100550 // Signal to receiver sources that we're stopping.
Harald Alvestrand6060df52020-08-11 09:54:02 +0200551 for (const auto& receiver : receivers_)
Tommi6589def2022-02-17 23:36:47 +0100552 receiver->internal()->Stop();
553
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200554 context()->worker_thread()->BlockingCall([&]() {
Tommi6589def2022-02-17 23:36:47 +0100555 // 5 Stop receiving media with receiver.
556 for (const auto& receiver : receivers_)
557 receiver->internal()->SetMediaChannel(nullptr);
558 });
Harald Alvestrand6060df52020-08-11 09:54:02 +0200559
560 stopping_ = true;
561 direction_ = webrtc::RtpTransceiverDirection::kInactive;
562}
563
564RTCError RtpTransceiver::StopStandard() {
565 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000566 // If we're on Plan B, do what Stop() used to do there.
567 if (!unified_plan_) {
568 StopInternal();
569 return RTCError::OK();
570 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200571 // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
572 // invoked.
573 //
574 // 2. Let connection be the RTCPeerConnection object associated with
575 // transceiver.
576 //
577 // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
578 if (is_pc_closed_) {
579 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
580 "PeerConnection is closed.");
Harald Alvestranda88c9772020-08-10 18:06:09 +0000581 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200582
583 // 4. If transceiver.[[Stopping]] is true, abort these steps.
584 if (stopping_)
585 return RTCError::OK();
586
587 // 5. Stop sending and receiving given transceiver, and update the
588 // negotiation-needed flag for connection.
589 StopSendingAndReceiving();
Harald Alvestrand280054f2020-11-10 13:12:53 +0000590 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200591
592 return RTCError::OK();
593}
594
595void RtpTransceiver::StopInternal() {
Harald Alvestrand85466662021-04-19 21:21:36 +0000596 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000597 StopTransceiverProcedure();
598}
599
600void RtpTransceiver::StopTransceiverProcedure() {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200601 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000602 // As specified in the "Stop the RTCRtpTransceiver" procedure
Harald Alvestrand6060df52020-08-11 09:54:02 +0200603 // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
604 // transceiver.
605 if (!stopping_)
606 StopSendingAndReceiving();
607
608 // 2. Set transceiver.[[Stopped]] to true.
Steve Anton6e634bf2017-11-13 10:44:53 -0800609 stopped_ = true;
Harald Alvestrand6060df52020-08-11 09:54:02 +0200610
611 // Signal the updated change to the senders.
612 for (const auto& sender : senders_)
613 sender->internal()->SetTransceiverAsStopped();
614
615 // 3. Set transceiver.[[Receptive]] to false.
616 // 4. Set transceiver.[[CurrentDirection]] to null.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200617 current_direction_ = absl::nullopt;
Steve Anton6e634bf2017-11-13 10:44:53 -0800618}
619
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200620RTCError RtpTransceiver::SetCodecPreferences(
621 rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
622 RTC_DCHECK(unified_plan_);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200623 // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
624 // to codecs and abort these steps.
625 if (codec_capabilities.empty()) {
626 codec_preferences_.clear();
Florent Castelli725ee242022-10-18 17:05:58 +0200627 if (media_type() == cricket::MEDIA_TYPE_VIDEO)
628 senders_.front()->internal()->SetVideoCodecPreferences(
629 media_engine()->video().send_codecs(false));
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200630 return RTCError::OK();
631 }
632
633 // 4. Remove any duplicate values in codecs.
634 std::vector<RtpCodecCapability> codecs;
635 absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
636 [&codecs](const RtpCodecCapability& codec) {
637 return absl::c_linear_search(codecs, codec);
638 });
639
Johannes Kron3e983682020-03-29 22:17:00 +0200640 // 6. to 8.
641 RTCError result;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200642 if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200643 std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000644 send_codecs = media_engine()->voice().send_codecs();
645 recv_codecs = media_engine()->voice().recv_codecs();
Johannes Kron3e983682020-03-29 22:17:00 +0200646 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200647 } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
Johannes Kron3e983682020-03-29 22:17:00 +0200648 std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000649 send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
650 recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
Johannes Kron3e983682020-03-29 22:17:00 +0200651 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli725ee242022-10-18 17:05:58 +0200652
653 if (result.ok()) {
654 senders_.front()->internal()->SetVideoCodecPreferences(
655 MatchCodecPreferences(codecs, send_codecs));
656 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200657 }
658
Johannes Kron3e983682020-03-29 22:17:00 +0200659 if (result.ok()) {
660 codec_preferences_ = codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200661 }
662
Johannes Kron3e983682020-03-29 22:17:00 +0200663 return result;
Steve Anton6e634bf2017-11-13 10:44:53 -0800664}
665
Markus Handell0357b3e2020-03-16 13:40:51 +0100666std::vector<RtpHeaderExtensionCapability>
667RtpTransceiver::HeaderExtensionsToOffer() const {
Markus Handell755c65d2020-06-24 01:06:10 +0200668 return header_extensions_to_offer_;
669}
670
Markus Handell5932fe12020-12-17 22:19:40 +0100671std::vector<RtpHeaderExtensionCapability>
672RtpTransceiver::HeaderExtensionsNegotiated() const {
Tommicc7a3682021-05-04 14:59:38 +0200673 RTC_DCHECK_RUN_ON(thread_);
Markus Handell5932fe12020-12-17 22:19:40 +0100674 std::vector<RtpHeaderExtensionCapability> result;
Tommicc7a3682021-05-04 14:59:38 +0200675 for (const auto& ext : negotiated_header_extensions_) {
Markus Handell5932fe12020-12-17 22:19:40 +0100676 result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
677 }
678 return result;
679}
680
Philipp Hancke51dbe822023-02-02 13:20:37 +0100681// Helper function to determine mandatory-to-negotiate extensions.
682// See https://www.rfc-editor.org/rfc/rfc8834#name-header-extensions
683// and https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
684// Since BUNDLE is offered by default, MID is mandatory and can not be turned
685// off via this API.
686bool IsMandatoryHeaderExtension(const std::string& uri) {
687 return uri == RtpExtension::kMidUri;
688}
689
Markus Handell755c65d2020-06-24 01:06:10 +0200690RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
691 rtc::ArrayView<const RtpHeaderExtensionCapability>
692 header_extensions_to_offer) {
693 for (const auto& entry : header_extensions_to_offer) {
694 // Handle unsupported requests for mandatory extensions as per
695 // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
696 // Note:
697 // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
698 // this has to be checked on a higher level. We naturally error out
699 // in the handling of Step 2.2 if an unset URI is encountered.
700
701 // Step 2.2.
702 // Handle unknown extensions.
703 auto it = std::find_if(
704 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
705 [&entry](const auto& offered) { return entry.uri == offered.uri; });
706 if (it == header_extensions_to_offer_.end()) {
Markus Handellc17bca72021-01-14 17:08:01 +0100707 return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
Markus Handell755c65d2020-06-24 01:06:10 +0200708 "Attempted to modify an unoffered extension.");
709 }
710
711 // Step 2.4-2.5.
Philipp Hancke51dbe822023-02-02 13:20:37 +0100712 if (IsMandatoryHeaderExtension(entry.uri) &&
Markus Handell755c65d2020-06-24 01:06:10 +0200713 entry.direction != RtpTransceiverDirection::kSendRecv) {
714 return RTCError(RTCErrorType::INVALID_MODIFICATION,
715 "Attempted to stop a mandatory extension.");
716 }
717 }
718
Philipp Hancke51dbe822023-02-02 13:20:37 +0100719 // Set all current extensions but the mandatory ones to stopped.
720 // This means that anything filtered from the input will not show up.
721 for (auto& entry : header_extensions_to_offer_) {
722 if (!IsMandatoryHeaderExtension(entry.uri)) {
723 entry.direction = RtpTransceiverDirection::kStopped;
724 }
725 }
Markus Handell755c65d2020-06-24 01:06:10 +0200726 // Apply mutation after error checking.
727 for (const auto& entry : header_extensions_to_offer) {
728 auto it = std::find_if(
729 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
730 [&entry](const auto& offered) { return entry.uri == offered.uri; });
731 it->direction = entry.direction;
732 }
733
734 return RTCError::OK();
Markus Handell0357b3e2020-03-16 13:40:51 +0100735}
736
Tommicc7a3682021-05-04 14:59:38 +0200737void RtpTransceiver::OnNegotiationUpdate(
738 SdpType sdp_type,
739 const cricket::MediaContentDescription* content) {
740 RTC_DCHECK_RUN_ON(thread_);
741 RTC_DCHECK(content);
742 if (sdp_type == SdpType::kAnswer)
743 negotiated_header_extensions_ = content->rtp_header_extensions();
744}
745
Harald Alvestrand6060df52020-08-11 09:54:02 +0200746void RtpTransceiver::SetPeerConnectionClosed() {
747 is_pc_closed_ = true;
748}
749
Steve Anton6e634bf2017-11-13 10:44:53 -0800750} // namespace webrtc