blob: 6b3032e27fdd08c2a1d8806d7d7290b0b4aeacec [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
13#include <string>
Markus Handell0357b3e2020-03-16 13:40:51 +010014#include <utility>
Steve Anton6e634bf2017-11-13 10:44:53 -080015
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Markus Handell0357b3e2020-03-16 13:40:51 +010017#include "api/rtp_parameters.h"
Florent Castelli2d9d82e2019-04-23 19:25:51 +020018#include "pc/channel_manager.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "pc/rtp_media_utils.h"
Florent Castelli2d9d82e2019-04-23 19:25:51 +020020#include "pc/rtp_parameters_conversion.h"
Yves Gerey3e707812018-11-28 16:47:49 +010021#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
Steve Antondcc3c022017-12-22 16:02:54 -080023
Steve Anton6e634bf2017-11-13 10:44:53 -080024namespace webrtc {
Johannes Kron3e983682020-03-29 22:17:00 +020025namespace {
26template <class T>
27RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
28 const std::vector<T>& send_codecs,
29 const std::vector<T>& recv_codecs) {
30 // If the intersection between codecs and
31 // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
32 // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
33 // RED or FEC codecs or is an empty set, throw InvalidModificationError.
34 // This ensures that we always have something to offer, regardless of
35 // transceiver.direction.
36
37 if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
38 return codec.name != cricket::kRtxCodecName &&
39 codec.name != cricket::kRedCodecName &&
40 codec.name != cricket::kFlexfecCodecName &&
41 absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
42 return recv_codec.MatchesCapability(codec);
43 });
44 })) {
45 return RTCError(RTCErrorType::INVALID_MODIFICATION,
46 "Invalid codec preferences: Missing codec from recv "
47 "codec capabilities.");
48 }
49
50 if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
51 return codec.name != cricket::kRtxCodecName &&
52 codec.name != cricket::kRedCodecName &&
53 codec.name != cricket::kFlexfecCodecName &&
54 absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
55 return send_codec.MatchesCapability(codec);
56 });
57 })) {
58 return RTCError(RTCErrorType::INVALID_MODIFICATION,
59 "Invalid codec preferences: Missing codec from send "
60 "codec capabilities.");
61 }
62
63 // Let codecCapabilities be the union of
64 // RTCRtpSender.getCapabilities(kind).codecs and
65 // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
66 // codec is not in codecCapabilities, throw InvalidModificationError.
67 for (const auto& codec_preference : codecs) {
68 bool is_recv_codec =
69 absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
70 return codec.MatchesCapability(codec_preference);
71 });
72
73 bool is_send_codec =
74 absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
75 return codec.MatchesCapability(codec_preference);
76 });
77
78 if (!is_recv_codec && !is_send_codec) {
79 return RTCError(
80 RTCErrorType::INVALID_MODIFICATION,
81 std::string("Invalid codec preferences: invalid codec with name \"") +
82 codec_preference.name + "\".");
83 }
84 }
85
86 // Check we have a real codec (not just rtx, red or fec)
87 if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
88 return codec.name == cricket::kRtxCodecName ||
89 codec.name == cricket::kRedCodecName ||
90 codec.name == cricket::kUlpfecCodecName;
91 })) {
92 return RTCError(RTCErrorType::INVALID_MODIFICATION,
93 "Invalid codec preferences: codec list must have a non "
94 "RTX, RED or FEC entry.");
95 }
96
97 return RTCError::OK();
98}
99
Harald Alvestrand6060df52020-08-11 09:54:02 +0200100TaskQueueBase* GetCurrentTaskQueueOrThread() {
101 TaskQueueBase* current = TaskQueueBase::Current();
102 if (!current)
103 current = rtc::ThreadManager::Instance()->CurrentThread();
104 return current;
105}
106
Johannes Kron3e983682020-03-29 22:17:00 +0200107} // namespace
Steve Anton6e634bf2017-11-13 10:44:53 -0800108
109RtpTransceiver::RtpTransceiver(cricket::MediaType media_type)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200110 : thread_(GetCurrentTaskQueueOrThread()),
111 unified_plan_(false),
112 media_type_(media_type) {
Steve Anton6e634bf2017-11-13 10:44:53 -0800113 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
114 media_type == cricket::MEDIA_TYPE_VIDEO);
115}
116
Steve Anton79e79602017-11-20 10:25:56 -0800117RtpTransceiver::RtpTransceiver(
118 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
119 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200120 receiver,
Markus Handell0357b3e2020-03-16 13:40:51 +0100121 cricket::ChannelManager* channel_manager,
Harald Alvestrand280054f2020-11-10 13:12:53 +0000122 std::vector<RtpHeaderExtensionCapability> header_extensions_offered,
123 std::function<void()> on_negotiation_needed)
Harald Alvestrand6060df52020-08-11 09:54:02 +0200124 : thread_(GetCurrentTaskQueueOrThread()),
125 unified_plan_(true),
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200126 media_type_(sender->media_type()),
Markus Handell0357b3e2020-03-16 13:40:51 +0100127 channel_manager_(channel_manager),
Harald Alvestrand280054f2020-11-10 13:12:53 +0000128 header_extensions_to_offer_(std::move(header_extensions_offered)),
129 on_negotiation_needed_(std::move(on_negotiation_needed)) {
Steve Anton79e79602017-11-20 10:25:56 -0800130 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
131 media_type_ == cricket::MEDIA_TYPE_VIDEO);
132 RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
133 senders_.push_back(sender);
134 receivers_.push_back(receiver);
135}
136
Steve Anton6e634bf2017-11-13 10:44:53 -0800137RtpTransceiver::~RtpTransceiver() {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200138 StopInternal();
Steve Anton6e634bf2017-11-13 10:44:53 -0800139}
140
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800141void RtpTransceiver::SetChannel(cricket::ChannelInterface* channel) {
142 // Cannot set a non-null channel on a stopped transceiver.
143 if (stopped_ && channel) {
144 return;
145 }
146
Steve Anton6e634bf2017-11-13 10:44:53 -0800147 if (channel) {
148 RTC_DCHECK_EQ(media_type(), channel->media_type());
149 }
Steve Anton60776752018-01-10 11:51:34 -0800150
151 if (channel_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800152 channel_->SignalFirstPacketReceived().disconnect(this);
Steve Anton60776752018-01-10 11:51:34 -0800153 }
154
Steve Anton6e634bf2017-11-13 10:44:53 -0800155 channel_ = channel;
Steve Anton60776752018-01-10 11:51:34 -0800156
157 if (channel_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800158 channel_->SignalFirstPacketReceived().connect(
Steve Anton60776752018-01-10 11:51:34 -0800159 this, &RtpTransceiver::OnFirstPacketReceived);
160 }
161
Mirko Bonadei739baf02019-01-27 17:29:42 +0100162 for (const auto& sender : senders_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800163 sender->internal()->SetMediaChannel(channel_ ? channel_->media_channel()
164 : nullptr);
Steve Anton6e634bf2017-11-13 10:44:53 -0800165 }
Steve Anton60776752018-01-10 11:51:34 -0800166
Mirko Bonadei739baf02019-01-27 17:29:42 +0100167 for (const auto& receiver : receivers_) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800168 if (!channel_) {
Steve Anton6e634bf2017-11-13 10:44:53 -0800169 receiver->internal()->Stop();
170 }
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800171
172 receiver->internal()->SetMediaChannel(channel_ ? channel_->media_channel()
173 : nullptr);
Steve Anton6e634bf2017-11-13 10:44:53 -0800174 }
175}
176
177void RtpTransceiver::AddSender(
178 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800179 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800180 RTC_DCHECK(!unified_plan_);
181 RTC_DCHECK(sender);
Steve Anton69470252018-02-09 11:43:08 -0800182 RTC_DCHECK_EQ(media_type(), sender->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800183 RTC_DCHECK(!absl::c_linear_search(senders_, sender));
Steve Anton6e634bf2017-11-13 10:44:53 -0800184 senders_.push_back(sender);
185}
186
187bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
188 RTC_DCHECK(!unified_plan_);
189 if (sender) {
190 RTC_DCHECK_EQ(media_type(), sender->media_type());
191 }
Steve Anton64b626b2019-01-28 17:25:26 -0800192 auto it = absl::c_find(senders_, sender);
Steve Anton6e634bf2017-11-13 10:44:53 -0800193 if (it == senders_.end()) {
194 return false;
195 }
196 (*it)->internal()->Stop();
197 senders_.erase(it);
198 return true;
199}
200
201void RtpTransceiver::AddReceiver(
202 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
203 receiver) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800204 RTC_DCHECK(!stopped_);
Steve Anton6e634bf2017-11-13 10:44:53 -0800205 RTC_DCHECK(!unified_plan_);
206 RTC_DCHECK(receiver);
Steve Anton69470252018-02-09 11:43:08 -0800207 RTC_DCHECK_EQ(media_type(), receiver->media_type());
Steve Anton64b626b2019-01-28 17:25:26 -0800208 RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
Steve Anton6e634bf2017-11-13 10:44:53 -0800209 receivers_.push_back(receiver);
210}
211
212bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
213 RTC_DCHECK(!unified_plan_);
214 if (receiver) {
215 RTC_DCHECK_EQ(media_type(), receiver->media_type());
216 }
Steve Anton64b626b2019-01-28 17:25:26 -0800217 auto it = absl::c_find(receivers_, receiver);
Steve Anton6e634bf2017-11-13 10:44:53 -0800218 if (it == receivers_.end()) {
219 return false;
220 }
221 (*it)->internal()->Stop();
Markus Handell43e62fc2020-01-07 19:46:15 +0100222 // After the receiver has been removed, there's no guarantee that the
223 // contained media channel isn't deleted shortly after this. To make sure that
224 // the receiver doesn't spontaneously try to use it's (potentially stale)
225 // media channel reference, we clear it out.
226 (*it)->internal()->SetMediaChannel(nullptr);
Steve Anton6e634bf2017-11-13 10:44:53 -0800227 receivers_.erase(it);
228 return true;
229}
230
Steve Antonf9381f02017-12-14 10:23:57 -0800231rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
232 RTC_DCHECK(unified_plan_);
233 RTC_CHECK_EQ(1u, senders_.size());
234 return senders_[0]->internal();
235}
236
237rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
238 const {
239 RTC_DCHECK(unified_plan_);
240 RTC_CHECK_EQ(1u, receivers_.size());
241 return receivers_[0]->internal();
242}
243
Steve Anton69470252018-02-09 11:43:08 -0800244cricket::MediaType RtpTransceiver::media_type() const {
245 return media_type_;
246}
247
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200248absl::optional<std::string> RtpTransceiver::mid() const {
Steve Anton6e634bf2017-11-13 10:44:53 -0800249 return mid_;
250}
251
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800252void RtpTransceiver::OnFirstPacketReceived(cricket::ChannelInterface*) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100253 for (const auto& receiver : receivers_) {
Steve Anton60776752018-01-10 11:51:34 -0800254 receiver->internal()->NotifyFirstPacketReceived();
255 }
256}
257
Steve Anton6e634bf2017-11-13 10:44:53 -0800258rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
259 RTC_DCHECK(unified_plan_);
260 RTC_CHECK_EQ(1u, senders_.size());
261 return senders_[0];
262}
263
264rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
265 RTC_DCHECK(unified_plan_);
266 RTC_CHECK_EQ(1u, receivers_.size());
267 return receivers_[0];
268}
269
Steve Antondcc3c022017-12-22 16:02:54 -0800270void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
Steve Anton3d954a62018-04-02 11:27:23 -0700271 RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
272 << ") current direction from "
273 << (current_direction_ ? RtpTransceiverDirectionToString(
274 *current_direction_)
275 : "<not set>")
276 << " to " << RtpTransceiverDirectionToString(direction)
277 << ".";
Steve Antondcc3c022017-12-22 16:02:54 -0800278 current_direction_ = direction;
279 if (RtpTransceiverDirectionHasSend(*current_direction_)) {
280 has_ever_been_used_to_send_ = true;
281 }
282}
283
Steve Anton0f5400a2018-07-17 14:25:36 -0700284void RtpTransceiver::set_fired_direction(RtpTransceiverDirection direction) {
285 fired_direction_ = direction;
286}
287
Steve Anton6e634bf2017-11-13 10:44:53 -0800288bool RtpTransceiver::stopped() const {
289 return stopped_;
290}
291
Harald Alvestrand6060df52020-08-11 09:54:02 +0200292bool RtpTransceiver::stopping() const {
293 RTC_DCHECK_RUN_ON(thread_);
294 return stopping_;
295}
296
Steve Anton6e634bf2017-11-13 10:44:53 -0800297RtpTransceiverDirection RtpTransceiver::direction() const {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200298 if (unified_plan_ && stopping())
299 return webrtc::RtpTransceiverDirection::kStopped;
300
Steve Anton6e634bf2017-11-13 10:44:53 -0800301 return direction_;
302}
303
Harald Alvestrand6060df52020-08-11 09:54:02 +0200304RTCError RtpTransceiver::SetDirectionWithError(
305 RtpTransceiverDirection new_direction) {
306 if (unified_plan_ && stopping()) {
307 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
308 "Cannot set direction on a stopping transceiver.");
Steve Anton52d86772018-02-20 15:48:12 -0800309 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200310 if (new_direction == direction_)
311 return RTCError::OK();
312
313 if (new_direction == RtpTransceiverDirection::kStopped) {
314 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
315 "The set direction 'stopped' is invalid.");
Steve Anton52d86772018-02-20 15:48:12 -0800316 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200317
Steve Anton52d86772018-02-20 15:48:12 -0800318 direction_ = new_direction;
Harald Alvestrand280054f2020-11-10 13:12:53 +0000319 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200320
321 return RTCError::OK();
Steve Anton6e634bf2017-11-13 10:44:53 -0800322}
323
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200324absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
Steve Anton6e634bf2017-11-13 10:44:53 -0800325 const {
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000326 if (unified_plan_ && stopped())
Harald Alvestrand6060df52020-08-11 09:54:02 +0200327 return webrtc::RtpTransceiverDirection::kStopped;
328
Steve Anton6e634bf2017-11-13 10:44:53 -0800329 return current_direction_;
330}
331
Steve Anton0f5400a2018-07-17 14:25:36 -0700332absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
333 const {
334 return fired_direction_;
335}
336
Harald Alvestrand6060df52020-08-11 09:54:02 +0200337void RtpTransceiver::StopSendingAndReceiving() {
338 // 1. Let sender be transceiver.[[Sender]].
339 // 2. Let receiver be transceiver.[[Receiver]].
340 //
341 // 3. Stop sending media with sender.
342 //
343 // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
344 // specified in [RFC3550].
345 RTC_DCHECK_RUN_ON(thread_);
346 for (const auto& sender : senders_)
Steve Anton6e634bf2017-11-13 10:44:53 -0800347 sender->internal()->Stop();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200348
349 // 5. Stop receiving media with receiver.
350 for (const auto& receiver : receivers_)
Harald Alvestrand1ee33252020-09-24 13:31:15 +0000351 receiver->internal()->StopAndEndTrack();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200352
353 stopping_ = true;
354 direction_ = webrtc::RtpTransceiverDirection::kInactive;
355}
356
357RTCError RtpTransceiver::StopStandard() {
358 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000359 // If we're on Plan B, do what Stop() used to do there.
360 if (!unified_plan_) {
361 StopInternal();
362 return RTCError::OK();
363 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200364 // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
365 // invoked.
366 //
367 // 2. Let connection be the RTCPeerConnection object associated with
368 // transceiver.
369 //
370 // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
371 if (is_pc_closed_) {
372 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
373 "PeerConnection is closed.");
Harald Alvestranda88c9772020-08-10 18:06:09 +0000374 }
Harald Alvestrand6060df52020-08-11 09:54:02 +0200375
376 // 4. If transceiver.[[Stopping]] is true, abort these steps.
377 if (stopping_)
378 return RTCError::OK();
379
380 // 5. Stop sending and receiving given transceiver, and update the
381 // negotiation-needed flag for connection.
382 StopSendingAndReceiving();
Harald Alvestrand280054f2020-11-10 13:12:53 +0000383 on_negotiation_needed_();
Harald Alvestrand6060df52020-08-11 09:54:02 +0200384
385 return RTCError::OK();
386}
387
388void RtpTransceiver::StopInternal() {
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000389 StopTransceiverProcedure();
390}
391
392void RtpTransceiver::StopTransceiverProcedure() {
Harald Alvestrand6060df52020-08-11 09:54:02 +0200393 RTC_DCHECK_RUN_ON(thread_);
Harald Alvestrandc75c4282020-08-26 12:17:54 +0000394 // As specified in the "Stop the RTCRtpTransceiver" procedure
Harald Alvestrand6060df52020-08-11 09:54:02 +0200395 // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
396 // transceiver.
397 if (!stopping_)
398 StopSendingAndReceiving();
399
400 // 2. Set transceiver.[[Stopped]] to true.
Steve Anton6e634bf2017-11-13 10:44:53 -0800401 stopped_ = true;
Harald Alvestrand6060df52020-08-11 09:54:02 +0200402
403 // Signal the updated change to the senders.
404 for (const auto& sender : senders_)
405 sender->internal()->SetTransceiverAsStopped();
406
407 // 3. Set transceiver.[[Receptive]] to false.
408 // 4. Set transceiver.[[CurrentDirection]] to null.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200409 current_direction_ = absl::nullopt;
Steve Anton6e634bf2017-11-13 10:44:53 -0800410}
411
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200412RTCError RtpTransceiver::SetCodecPreferences(
413 rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
414 RTC_DCHECK(unified_plan_);
415
416 // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
417 // to codecs and abort these steps.
418 if (codec_capabilities.empty()) {
419 codec_preferences_.clear();
420 return RTCError::OK();
421 }
422
423 // 4. Remove any duplicate values in codecs.
424 std::vector<RtpCodecCapability> codecs;
425 absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
426 [&codecs](const RtpCodecCapability& codec) {
427 return absl::c_linear_search(codecs, codec);
428 });
429
Johannes Kron3e983682020-03-29 22:17:00 +0200430 // 6. to 8.
431 RTCError result;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200432 if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200433 std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
434 channel_manager_->GetSupportedAudioReceiveCodecs(&recv_codecs);
435 channel_manager_->GetSupportedAudioSendCodecs(&send_codecs);
436
Johannes Kron3e983682020-03-29 22:17:00 +0200437 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200438 } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
Johannes Kron3e983682020-03-29 22:17:00 +0200439 std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
440 channel_manager_->GetSupportedVideoReceiveCodecs(&recv_codecs);
441 channel_manager_->GetSupportedVideoSendCodecs(&send_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200442
Johannes Kron3e983682020-03-29 22:17:00 +0200443 result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200444 }
445
Johannes Kron3e983682020-03-29 22:17:00 +0200446 if (result.ok()) {
447 codec_preferences_ = codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200448 }
449
Johannes Kron3e983682020-03-29 22:17:00 +0200450 return result;
Steve Anton6e634bf2017-11-13 10:44:53 -0800451}
452
Markus Handell0357b3e2020-03-16 13:40:51 +0100453std::vector<RtpHeaderExtensionCapability>
454RtpTransceiver::HeaderExtensionsToOffer() const {
Markus Handell755c65d2020-06-24 01:06:10 +0200455 return header_extensions_to_offer_;
456}
457
458RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
459 rtc::ArrayView<const RtpHeaderExtensionCapability>
460 header_extensions_to_offer) {
461 for (const auto& entry : header_extensions_to_offer) {
462 // Handle unsupported requests for mandatory extensions as per
463 // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
464 // Note:
465 // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
466 // this has to be checked on a higher level. We naturally error out
467 // in the handling of Step 2.2 if an unset URI is encountered.
468
469 // Step 2.2.
470 // Handle unknown extensions.
471 auto it = std::find_if(
472 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
473 [&entry](const auto& offered) { return entry.uri == offered.uri; });
474 if (it == header_extensions_to_offer_.end()) {
475 return RTCError(RTCErrorType::INVALID_PARAMETER,
476 "Attempted to modify an unoffered extension.");
477 }
478
479 // Step 2.4-2.5.
480 // - Use of the transceiver interface indicates unified plan is in effect,
481 // hence the MID extension needs to be enabled.
482 // - Also handle the mandatory video orientation extensions.
483 if ((entry.uri == RtpExtension::kMidUri ||
484 entry.uri == RtpExtension::kVideoRotationUri) &&
485 entry.direction != RtpTransceiverDirection::kSendRecv) {
486 return RTCError(RTCErrorType::INVALID_MODIFICATION,
487 "Attempted to stop a mandatory extension.");
488 }
489 }
490
491 // Apply mutation after error checking.
492 for (const auto& entry : header_extensions_to_offer) {
493 auto it = std::find_if(
494 header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
495 [&entry](const auto& offered) { return entry.uri == offered.uri; });
496 it->direction = entry.direction;
497 }
498
499 return RTCError::OK();
Markus Handell0357b3e2020-03-16 13:40:51 +0100500}
501
Harald Alvestrand6060df52020-08-11 09:54:02 +0200502void RtpTransceiver::SetPeerConnectionClosed() {
503 is_pc_closed_ = true;
504}
505
Steve Anton6e634bf2017-11-13 10:44:53 -0800506} // namespace webrtc