blob: 5f9e876b4cf354c11f59d79f1b3ebbf0567598fb [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(
214 call_ptr, media_config, audio_options, crypto_options);
215 if (!media_channel) {
216 return;
217 }
Harald Alvestrand485457f2022-05-23 08:46:57 +0000218
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200219 new_channel = std::make_unique<cricket::VoiceChannel>(
220 context()->worker_thread(), context()->network_thread(),
221 context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
222 srtp_required, crypto_options, context()->ssrc_generator());
223 });
Harald Alvestrand8f429922022-05-04 10:32:30 +0000224 } else {
225 RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, media_type());
226
227 // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
228 // the worker thread. We shouldn't be using the `call_ptr_` hack here but
229 // simply be on the worker thread and use `call_` (update upstream code).
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200230 context()->worker_thread()->BlockingCall([&] {
231 RTC_DCHECK_RUN_ON(context()->worker_thread());
232 cricket::VideoMediaChannel* media_channel =
233 media_engine()->video().CreateMediaChannel(
234 call_ptr, media_config, video_options, crypto_options,
235 video_bitrate_allocator_factory);
236 if (!media_channel) {
237 return;
238 }
Harald Alvestrand485457f2022-05-23 08:46:57 +0000239
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200240 new_channel = std::make_unique<cricket::VideoChannel>(
241 context()->worker_thread(), context()->network_thread(),
242 context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
243 srtp_required, crypto_options, context()->ssrc_generator());
244 });
Harald Alvestrand8f429922022-05-04 10:32:30 +0000245 }
246 if (!new_channel) {
247 // TODO(hta): Must be a better way
248 return RTCError(RTCErrorType::INTERNAL_ERROR,
249 "Failed to create channel for mid=" + std::string(mid));
250 }
251 SetChannel(std::move(new_channel), transport_lookup);
252 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800253}
254
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100255void RtpTransceiver::SetChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000256 std::unique_ptr<cricket::ChannelInterface> channel,
Tomas Gunnarsson4f8a58c2022-01-19 11:36:23 +0100257 std::function<RtpTransportInternal*(const std::string&)> transport_lookup) {
Tommi99c8a802021-04-27 15:00:00 +0200258 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000259 RTC_DCHECK(channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000260 RTC_DCHECK(transport_lookup);
Harald Alvestranddaee8702022-04-29 11:42:55 +0000261 RTC_DCHECK(!channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000262 // Cannot set a channel on a stopped transceiver.
Harald Alvestranddaee8702022-04-29 11:42:55 +0000263 if (stopped_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800264 return;
265 }
266
Tommife041642021-04-07 10:08:28 +0200267 RTC_LOG_THREAD_BLOCK_COUNT();
268
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000269 RTC_DCHECK_EQ(media_type(), channel->media_type());
270 signaling_thread_safety_ = PendingTaskSafetyFlag::Create();
Steve Anton60776752018-01-10 11:51:34 -0800271
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000272 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
273
Tommi99c8a802021-04-27 15:00:00 +0200274 // An alternative to this, could be to require SetChannel to be called
275 // on the network thread. The channel object operates for the most part
276 // on the network thread, as part of its initialization being on the network
277 // thread is required, so setting a channel object as part of the construction
278 // (without thread hopping) might be the more efficient thing to do than
279 // how SetChannel works today.
280 // Similarly, if the channel() accessor is limited to the network thread, that
281 // helps with keeping the channel implementation requirements being met and
282 // avoids synchronization for accessing the pointer or network related state.
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200283 context()->network_thread()->BlockingCall([&]() {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000284 if (channel_) {
285 channel_->SetFirstPacketReceivedCallback(nullptr);
286 channel_->SetRtpTransport(nullptr);
287 channel_to_delete = std::move(channel_);
288 }
289
290 channel_ = std::move(channel);
Steve Anton60776752018-01-10 11:51:34 -0800291
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000292 channel_->SetRtpTransport(transport_lookup(channel_->mid()));
293 channel_->SetFirstPacketReceivedCallback(
294 [thread = thread_, flag = signaling_thread_safety_, this]() mutable {
Danil Chapovalova30439b2022-07-07 10:08:49 +0200295 thread->PostTask(
296 SafeTask(std::move(flag), [this]() { OnFirstPacketReceived(); }));
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000297 });
Tommi99c8a802021-04-27 15:00:00 +0200298 });
Harald Alvestranddaee8702022-04-29 11:42:55 +0000299 PushNewMediaChannelAndDeleteChannel(nullptr);
Tommi6589def2022-02-17 23:36:47 +0100300
301 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
Steve Anton6e634bf2017-11-13 10:44:53 -0800302}
303
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000304void RtpTransceiver::ClearChannel() {
305 RTC_DCHECK_RUN_ON(thread_);
306
307 if (!channel_) {
308 return;
309 }
310
311 RTC_LOG_THREAD_BLOCK_COUNT();
312
313 if (channel_) {
314 signaling_thread_safety_->SetNotAlive();
315 signaling_thread_safety_ = nullptr;
316 }
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000317 std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000318
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200319 context()->network_thread()->BlockingCall([&]() {
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000320 if (channel_) {
321 channel_->SetFirstPacketReceivedCallback(nullptr);
322 channel_->SetRtpTransport(nullptr);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000323 channel_to_delete = std::move(channel_);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000324 }
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000325 });
326
327 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000328 PushNewMediaChannelAndDeleteChannel(std::move(channel_to_delete));
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000329
330 RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
331}
332
Harald Alvestranddaee8702022-04-29 11:42:55 +0000333void RtpTransceiver::PushNewMediaChannelAndDeleteChannel(
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000334 std::unique_ptr<cricket::ChannelInterface> channel_to_delete) {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000335 // The clumsy combination of pushing down media channel and deleting
336 // the channel is due to the desire to do both things in one Invoke().
337 if (!channel_to_delete && senders_.empty() && receivers_.empty()) {
338 return;
339 }
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200340 context()->worker_thread()->BlockingCall([&]() {
Harald Alvestranddaee8702022-04-29 11:42:55 +0000341 // Push down the new media_channel, if any, otherwise clear it.
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000342 auto* media_send_channel =
343 channel_ ? channel_->media_send_channel() : nullptr;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000344 for (const auto& sender : senders_) {
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000345 sender->internal()->SetMediaChannel(media_send_channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000346 }
347
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000348 auto* media_receive_channel =
349 channel_ ? channel_->media_receive_channel() : nullptr;
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000350 for (const auto& receiver : receivers_) {
Harald Alvestrand36fafc82022-12-08 08:47:42 +0000351 receiver->internal()->SetMediaChannel(media_receive_channel);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000352 }
353
354 // Destroy the channel, if we had one, now _after_ updating the receivers
355 // who might have had references to the previous channel.
356 if (channel_to_delete) {
Harald Alvestrand3af79d12022-04-29 15:04:58 +0000357 channel_to_delete.reset(nullptr);
Harald Alvestrand19ebabc2022-04-28 13:31:17 +0000358 }
359 });
360}
361
Steve Anton6e634bf2017-11-13 10:44:53 -0800362void RtpTransceiver::AddSender(
363 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
Tommi99c8a802021-04-27 15:00:00 +0200364 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800365 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800366 RTC_DCHECK(!unified_plan_);
367 RTC_DCHECK(sender);
Steve Anton69470252018-02-09 11:43:08 -0800368 RTC_DCHECK_EQ(media_type(), sender->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800369 RTC_DCHECK(!absl::c_linear_search(senders_, sender));
Florent Castelli725ee242022-10-18 17:05:58 +0200370 if (media_type() == cricket::MEDIA_TYPE_VIDEO) {
371 std::vector<cricket::VideoCodec> send_codecs =
372 media_engine()->video().send_codecs(false);
373 sender->internal()->SetVideoCodecPreferences(
374 codec_preferences_.empty()
375 ? send_codecs
376 : MatchCodecPreferences(codec_preferences_, send_codecs));
377 }
Steve Anton6e634bf2017-11-13 10:44:53 -0800378 senders_.push_back(sender);
379}
380
381bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
382 RTC_DCHECK(!unified_plan_);
383 if (sender) {
384 RTC_DCHECK_EQ(media_type(), sender->media_type());
385 }
Steve Anton64b626b2019-01-28 17:25:26 -0800386 auto it = absl::c_find(senders_, sender);
Steve Anton6e634bf2017-11-13 10:44:53 -0800387 if (it == senders_.end()) {
388 return false;
389 }
390 (*it)->internal()->Stop();
391 senders_.erase(it);
392 return true;
393}
394
395void RtpTransceiver::AddReceiver(
396 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
397 receiver) {
Tommi99c8a802021-04-27 15:00:00 +0200398 RTC_DCHECK_RUN_ON(thread_);
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800399 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800400 RTC_DCHECK(!unified_plan_);
401 RTC_DCHECK(receiver);
Steve Anton69470252018-02-09 11:43:08 -0800402 RTC_DCHECK_EQ(media_type(), receiver->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800403 RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
Steve Anton6e634bf2017-11-13 10:44:53 -0800404 receivers_.push_back(receiver);
405}
406
407bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
Tommi6589def2022-02-17 23:36:47 +0100408 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800409 RTC_DCHECK(!unified_plan_);
410 if (receiver) {
411 RTC_DCHECK_EQ(media_type(), receiver->media_type());
412 }
Steve Anton64b626b2019-01-28 17:25:26 -0800413 auto it = absl::c_find(receivers_, receiver);
Steve Anton6e634bf2017-11-13 10:44:53 -0800414 if (it == receivers_.end()) {
415 return false;
416 }
Tommi6589def2022-02-17 23:36:47 +0100417
Steve Anton6e634bf2017-11-13 10:44:53 -0800418 (*it)->internal()->Stop();
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200419 context()->worker_thread()->BlockingCall([&]() {
Tommi6589def2022-02-17 23:36:47 +0100420 // `Stop()` will clear the receiver's pointer to the media channel.
421 (*it)->internal()->SetMediaChannel(nullptr);
422 });
423
Steve Anton6e634bf2017-11-13 10:44:53 -0800424 receivers_.erase(it);
425 return true;
426}
427
Steve Antonf9381f02017-12-14 10:23:57 -0800428rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
429 RTC_DCHECK(unified_plan_);
430 RTC_CHECK_EQ(1u, senders_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100431 return rtc::scoped_refptr<RtpSenderInternal>(senders_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800432}
433
434rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
435 const {
436 RTC_DCHECK(unified_plan_);
437 RTC_CHECK_EQ(1u, receivers_.size());
Niels Möllere7cc8832022-01-04 15:20:03 +0100438 return rtc::scoped_refptr<RtpReceiverInternal>(receivers_[0]->internal());
Steve Antonf9381f02017-12-14 10:23:57 -0800439}
440
Steve Anton69470252018-02-09 11:43:08 -0800441cricket::MediaType RtpTransceiver::media_type() const {
442 return media_type_;
443}
444
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200445absl::optional<std::string> RtpTransceiver::mid() const {
Steve Anton6e634bf2017-11-13 10:44:53 -0800446 return mid_;
447}
448
Tommi99c8a802021-04-27 15:00:00 +0200449void RtpTransceiver::OnFirstPacketReceived() {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100450 for (const auto& receiver : receivers_) {
Steve Anton60776752018-01-10 11:51:34 -0800451 receiver->internal()->NotifyFirstPacketReceived();
452 }
453}
454
Steve Anton6e634bf2017-11-13 10:44:53 -0800455rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
456 RTC_DCHECK(unified_plan_);
457 RTC_CHECK_EQ(1u, senders_.size());
458 return senders_[0];
459}
460
461rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
462 RTC_DCHECK(unified_plan_);
463 RTC_CHECK_EQ(1u, receivers_.size());
464 return receivers_[0];
465}
466
Steve Antondcc3c022017-12-22 16:02:54 -0800467void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
Steve Anton3d954a62018-04-02 11:27:23 -0700468 RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
469 << ") current direction from "
470 << (current_direction_ ? RtpTransceiverDirectionToString(
471 *current_direction_)
472 : "<not set>")
473 << " to " << RtpTransceiverDirectionToString(direction)
474 << ".";
Steve Antondcc3c022017-12-22 16:02:54 -0800475 current_direction_ = direction;
476 if (RtpTransceiverDirectionHasSend(*current_direction_)) {
477 has_ever_been_used_to_send_ = true;
478 }
479}
480
Henrik Boström0a162762022-05-02 15:47:52 +0200481void RtpTransceiver::set_fired_direction(
482 absl::optional<RtpTransceiverDirection> direction) {
Steve Anton0f5400a2018-07-17 14:25:36 -0700483 fired_direction_ = direction;
484}
485
Steve Anton6e634bf2017-11-13 10:44:53 -0800486bool RtpTransceiver::stopped() const {
Tommi99c8a802021-04-27 15:00:00 +0200487 RTC_DCHECK_RUN_ON(thread_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800488 return stopped_;
489}
490
Harald Alvestrand6060df52020-08-11 09:54:02 +0200491bool RtpTransceiver::stopping() const {
492 RTC_DCHECK_RUN_ON(thread_);
493 return stopping_;
494}
495
Steve Anton6e634bf2017-11-13 10:44:53 -0800496RtpTransceiverDirection RtpTransceiver::direction() const {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200497 if (unified_plan_ && stopping())
498 return webrtc::RtpTransceiverDirection::kStopped;
499
Steve Anton6e634bf2017-11-13 10:44:53 -0800500 return direction_;
501}
502
Harald Alvestrand6060df52020-08-11 09:54:02 +0200503RTCError RtpTransceiver::SetDirectionWithError(
504 RtpTransceiverDirection new_direction) {
505 if (unified_plan_ && stopping()) {
506 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
507 "Cannot set direction on a stopping transceiver.");
Steve Anton52d86772018-02-20 15:48:12 -0800508 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200509 if (new_direction == direction_)
510 return RTCError::OK();
511
512 if (new_direction == RtpTransceiverDirection::kStopped) {
513 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
514 "The set direction 'stopped' is invalid.");
Steve Anton52d86772018-02-20 15:48:12 -0800515 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200516
Steve Anton52d86772018-02-20 15:48:12 -0800517 direction_ = new_direction;
Harald Alvestrand280054f2020-11-10 13:12:53 +0000518 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200519
520 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800521}
522
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200523absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
Steve Anton6e634bf2017-11-13 10:44:53 -0800524 const {
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000525 if (unified_plan_ && stopped())
Harald Alvestrand6060df52020-08-11 09:54:02 +0200526 return webrtc::RtpTransceiverDirection::kStopped;
527
Steve Anton6e634bf2017-11-13 10:44:53 -0800528 return current_direction_;
529}
530
Steve Anton0f5400a2018-07-17 14:25:36 -0700531absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
532 const {
533 return fired_direction_;
534}
535
Harald Alvestrand6060df52020-08-11 09:54:02 +0200536void RtpTransceiver::StopSendingAndReceiving() {
537 // 1. Let sender be transceiver.[[Sender]].
538 // 2. Let receiver be transceiver.[[Receiver]].
539 //
540 // 3. Stop sending media with sender.
541 //
Tommi6589def2022-02-17 23:36:47 +0100542 RTC_DCHECK_RUN_ON(thread_);
543
Harald Alvestrand6060df52020-08-11 09:54:02 +0200544 // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
545 // specified in [RFC3550].
Harald Alvestrand6060df52020-08-11 09:54:02 +0200546 for (const auto& sender : senders_)
Steve Anton6e634bf2017-11-13 10:44:53 -0800547 sender->internal()->Stop();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200548
Tommi6589def2022-02-17 23:36:47 +0100549 // Signal to receiver sources that we're stopping.
Harald Alvestrand6060df52020-08-11 09:54:02 +0200550 for (const auto& receiver : receivers_)
Tommi6589def2022-02-17 23:36:47 +0100551 receiver->internal()->Stop();
552
Danil Chapovalov9e09a1f2022-09-08 18:38:10 +0200553 context()->worker_thread()->BlockingCall([&]() {
Tommi6589def2022-02-17 23:36:47 +0100554 // 5 Stop receiving media with receiver.
555 for (const auto& receiver : receivers_)
556 receiver->internal()->SetMediaChannel(nullptr);
557 });
Harald Alvestrand6060df52020-08-11 09:54:02 +0200558
559 stopping_ = true;
560 direction_ = webrtc::RtpTransceiverDirection::kInactive;
561}
562
563RTCError RtpTransceiver::StopStandard() {
564 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000565 // If we're on Plan B, do what Stop() used to do there.
566 if (!unified_plan_) {
567 StopInternal();
568 return RTCError::OK();
569 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200570 // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
571 // invoked.
572 //
573 // 2. Let connection be the RTCPeerConnection object associated with
574 // transceiver.
575 //
576 // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
577 if (is_pc_closed_) {
578 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
579 "PeerConnection is closed.");
Harald Alvestranda88c9772020-08-10 18:06:09 +0000580 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200581
582 // 4. If transceiver.[[Stopping]] is true, abort these steps.
583 if (stopping_)
584 return RTCError::OK();
585
586 // 5. Stop sending and receiving given transceiver, and update the
587 // negotiation-needed flag for connection.
588 StopSendingAndReceiving();
Harald Alvestrand280054f2020-11-10 13:12:53 +0000589 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200590
591 return RTCError::OK();
592}
593
594void RtpTransceiver::StopInternal() {
Harald Alvestrand85466662021-04-19 21:21:36 +0000595 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000596 StopTransceiverProcedure();
597}
598
599void RtpTransceiver::StopTransceiverProcedure() {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200600 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000601 // As specified in the "Stop the RTCRtpTransceiver" procedure
Harald Alvestrand6060df52020-08-11 09:54:02 +0200602 // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
603 // transceiver.
604 if (!stopping_)
605 StopSendingAndReceiving();
606
607 // 2. Set transceiver.[[Stopped]] to true.
Steve Anton6e634bf2017-11-13 10:44:53 -0800608 stopped_ = true;
Harald Alvestrand6060df52020-08-11 09:54:02 +0200609
610 // Signal the updated change to the senders.
611 for (const auto& sender : senders_)
612 sender->internal()->SetTransceiverAsStopped();
613
614 // 3. Set transceiver.[[Receptive]] to false.
615 // 4. Set transceiver.[[CurrentDirection]] to null.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200616 current_direction_ = absl::nullopt;
Steve Anton6e634bf2017-11-13 10:44:53 -0800617}
618
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200619RTCError RtpTransceiver::SetCodecPreferences(
620 rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
621 RTC_DCHECK(unified_plan_);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200622 // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
623 // to codecs and abort these steps.
624 if (codec_capabilities.empty()) {
625 codec_preferences_.clear();
Florent Castelli725ee242022-10-18 17:05:58 +0200626 if (media_type() == cricket::MEDIA_TYPE_VIDEO)
627 senders_.front()->internal()->SetVideoCodecPreferences(
628 media_engine()->video().send_codecs(false));
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200629 return RTCError::OK();
630 }
631
632 // 4. Remove any duplicate values in codecs.
633 std::vector<RtpCodecCapability> codecs;
634 absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
635 [&codecs](const RtpCodecCapability& codec) {
636 return absl::c_linear_search(codecs, codec);
637 });
638
Johannes Kron3e983682020-03-29 22:17:00 +0200639 // 6. to 8.
640 RTCError result;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200641 if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200642 std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000643 send_codecs = media_engine()->voice().send_codecs();
644 recv_codecs = media_engine()->voice().recv_codecs();
Johannes Kron3e983682020-03-29 22:17:00 +0200645 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200646 } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
Johannes Kron3e983682020-03-29 22:17:00 +0200647 std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
Harald Alvestrandc3fa7c32022-05-22 10:57:01 +0000648 send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
649 recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
Johannes Kron3e983682020-03-29 22:17:00 +0200650 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli725ee242022-10-18 17:05:58 +0200651
652 if (result.ok()) {
653 senders_.front()->internal()->SetVideoCodecPreferences(
654 MatchCodecPreferences(codecs, send_codecs));
655 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200656 }
657
Johannes Kron3e983682020-03-29 22:17:00 +0200658 if (result.ok()) {
659 codec_preferences_ = codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200660 }
661
Johannes Kron3e983682020-03-29 22:17:00 +0200662 return result;
Steve Anton6e634bf2017-11-13 10:44:53 -0800663}
664
Markus Handell0357b3e2020-03-16 13:40:51 +0100665std::vector<RtpHeaderExtensionCapability>
666RtpTransceiver::HeaderExtensionsToOffer() const {
Markus Handell755c65d2020-06-24 01:06:10 +0200667 return header_extensions_to_offer_;
668}
669
Markus Handell5932fe12020-12-17 22:19:40 +0100670std::vector<RtpHeaderExtensionCapability>
671RtpTransceiver::HeaderExtensionsNegotiated() const {
Tommicc7a3682021-05-04 14:59:38 +0200672 RTC_DCHECK_RUN_ON(thread_);
Markus Handell5932fe12020-12-17 22:19:40 +0100673 std::vector<RtpHeaderExtensionCapability> result;
Tommicc7a3682021-05-04 14:59:38 +0200674 for (const auto& ext : negotiated_header_extensions_) {
Markus Handell5932fe12020-12-17 22:19:40 +0100675 result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
676 }
677 return result;
678}
679
Markus Handell755c65d2020-06-24 01:06:10 +0200680RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
681 rtc::ArrayView<const RtpHeaderExtensionCapability>
682 header_extensions_to_offer) {
683 for (const auto& entry : header_extensions_to_offer) {
684 // Handle unsupported requests for mandatory extensions as per
685 // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
686 // Note:
687 // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
688 // this has to be checked on a higher level. We naturally error out
689 // in the handling of Step 2.2 if an unset URI is encountered.
690
691 // Step 2.2.
692 // Handle unknown extensions.
693 auto it = std::find_if(
694 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
695 [&entry](const auto& offered) { return entry.uri == offered.uri; });
696 if (it == header_extensions_to_offer_.end()) {
Markus Handellc17bca72021-01-14 17:08:01 +0100697 return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
Markus Handell755c65d2020-06-24 01:06:10 +0200698 "Attempted to modify an unoffered extension.");
699 }
700
701 // Step 2.4-2.5.
702 // - Use of the transceiver interface indicates unified plan is in effect,
703 // hence the MID extension needs to be enabled.
704 // - Also handle the mandatory video orientation extensions.
705 if ((entry.uri == RtpExtension::kMidUri ||
706 entry.uri == RtpExtension::kVideoRotationUri) &&
707 entry.direction != RtpTransceiverDirection::kSendRecv) {
708 return RTCError(RTCErrorType::INVALID_MODIFICATION,
709 "Attempted to stop a mandatory extension.");
710 }
711 }
712
713 // Apply mutation after error checking.
714 for (const auto& entry : header_extensions_to_offer) {
715 auto it = std::find_if(
716 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
717 [&entry](const auto& offered) { return entry.uri == offered.uri; });
718 it->direction = entry.direction;
719 }
720
721 return RTCError::OK();
Markus Handell0357b3e2020-03-16 13:40:51 +0100722}
723
Tommicc7a3682021-05-04 14:59:38 +0200724void RtpTransceiver::OnNegotiationUpdate(
725 SdpType sdp_type,
726 const cricket::MediaContentDescription* content) {
727 RTC_DCHECK_RUN_ON(thread_);
728 RTC_DCHECK(content);
729 if (sdp_type == SdpType::kAnswer)
730 negotiated_header_extensions_ = content->rtp_header_extensions();
731}
732
Harald Alvestrand6060df52020-08-11 09:54:02 +0200733void RtpTransceiver::SetPeerConnectionClosed() {
734 is_pc_closed_ = true;
735}
736
Steve Anton6e634bf2017-11-13 10:44:53 -0800737} // namespace webrtc