1 /*
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 
11 #include "pc/rtp_transceiver.h"
12 
13 #include <iterator>
14 #include <string>
15 #include <utility>
16 #include <vector>
17 
18 #include "absl/algorithm/container.h"
19 #include "api/rtp_parameters.h"
20 #include "api/sequence_checker.h"
21 #include "media/base/codec.h"
22 #include "media/base/media_constants.h"
23 #include "pc/channel_manager.h"
24 #include "pc/rtp_media_utils.h"
25 #include "pc/session_description.h"
26 #include "rtc_base/checks.h"
27 #include "rtc_base/logging.h"
28 #include "rtc_base/thread.h"
29 
30 namespace webrtc {
31 namespace {
32 template <class T>
VerifyCodecPreferences(const std::vector<RtpCodecCapability> & codecs,const std::vector<T> & send_codecs,const std::vector<T> & recv_codecs)33 RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
34                                 const std::vector<T>& send_codecs,
35                                 const std::vector<T>& recv_codecs) {
36   // If the intersection between codecs and
37   // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
38   // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
39   // RED or FEC codecs or is an empty set, throw InvalidModificationError.
40   // This ensures that we always have something to offer, regardless of
41   // transceiver.direction.
42 
43   if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
44         return codec.name != cricket::kRtxCodecName &&
45                codec.name != cricket::kRedCodecName &&
46                codec.name != cricket::kFlexfecCodecName &&
47                absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
48                  return recv_codec.MatchesCapability(codec);
49                });
50       })) {
51     return RTCError(RTCErrorType::INVALID_MODIFICATION,
52                     "Invalid codec preferences: Missing codec from recv "
53                     "codec capabilities.");
54   }
55 
56   if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
57         return codec.name != cricket::kRtxCodecName &&
58                codec.name != cricket::kRedCodecName &&
59                codec.name != cricket::kFlexfecCodecName &&
60                absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
61                  return send_codec.MatchesCapability(codec);
62                });
63       })) {
64     return RTCError(RTCErrorType::INVALID_MODIFICATION,
65                     "Invalid codec preferences: Missing codec from send "
66                     "codec capabilities.");
67   }
68 
69   // Let codecCapabilities be the union of
70   // RTCRtpSender.getCapabilities(kind).codecs and
71   // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
72   // codec is not in codecCapabilities, throw InvalidModificationError.
73   for (const auto& codec_preference : codecs) {
74     bool is_recv_codec =
75         absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
76           return codec.MatchesCapability(codec_preference);
77         });
78 
79     bool is_send_codec =
80         absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
81           return codec.MatchesCapability(codec_preference);
82         });
83 
84     if (!is_recv_codec && !is_send_codec) {
85       return RTCError(
86           RTCErrorType::INVALID_MODIFICATION,
87           std::string("Invalid codec preferences: invalid codec with name \"") +
88               codec_preference.name + "\".");
89     }
90   }
91 
92   // Check we have a real codec (not just rtx, red or fec)
93   if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
94         return codec.name == cricket::kRtxCodecName ||
95                codec.name == cricket::kRedCodecName ||
96                codec.name == cricket::kUlpfecCodecName;
97       })) {
98     return RTCError(RTCErrorType::INVALID_MODIFICATION,
99                     "Invalid codec preferences: codec list must have a non "
100                     "RTX, RED or FEC entry.");
101   }
102 
103   return RTCError::OK();
104 }
105 
GetCurrentTaskQueueOrThread()106 TaskQueueBase* GetCurrentTaskQueueOrThread() {
107   TaskQueueBase* current = TaskQueueBase::Current();
108   if (!current)
109     current = rtc::ThreadManager::Instance()->CurrentThread();
110   return current;
111 }
112 
113 }  // namespace
114 
RtpTransceiver(cricket::MediaType media_type)115 RtpTransceiver::RtpTransceiver(cricket::MediaType media_type)
116     : thread_(GetCurrentTaskQueueOrThread()),
117       unified_plan_(false),
118       media_type_(media_type) {
119   RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
120              media_type == cricket::MEDIA_TYPE_VIDEO);
121 }
122 
RtpTransceiver(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver,cricket::ChannelManager * channel_manager,std::vector<RtpHeaderExtensionCapability> header_extensions_offered,std::function<void ()> on_negotiation_needed)123 RtpTransceiver::RtpTransceiver(
124     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
125     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
126         receiver,
127     cricket::ChannelManager* channel_manager,
128     std::vector<RtpHeaderExtensionCapability> header_extensions_offered,
129     std::function<void()> on_negotiation_needed)
130     : thread_(GetCurrentTaskQueueOrThread()),
131       unified_plan_(true),
132       media_type_(sender->media_type()),
133       channel_manager_(channel_manager),
134       header_extensions_to_offer_(std::move(header_extensions_offered)),
135       on_negotiation_needed_(std::move(on_negotiation_needed)) {
136   RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
137              media_type_ == cricket::MEDIA_TYPE_VIDEO);
138   RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
139   senders_.push_back(sender);
140   receivers_.push_back(receiver);
141 }
142 
~RtpTransceiver()143 RtpTransceiver::~RtpTransceiver() {
144   StopInternal();
145 }
146 
SetChannel(cricket::ChannelInterface * channel)147 void RtpTransceiver::SetChannel(cricket::ChannelInterface* channel) {
148   // Cannot set a non-null channel on a stopped transceiver.
149   if (stopped_ && channel) {
150     return;
151   }
152 
153   RTC_LOG_THREAD_BLOCK_COUNT();
154 
155   if (channel) {
156     RTC_DCHECK_EQ(media_type(), channel->media_type());
157   }
158 
159   if (channel_) {
160     channel_->SignalFirstPacketReceived().disconnect(this);
161   }
162 
163   channel_ = channel;
164 
165   if (channel_) {
166     channel_->SignalFirstPacketReceived().connect(
167         this, &RtpTransceiver::OnFirstPacketReceived);
168   }
169 
170   for (const auto& sender : senders_) {
171     sender->internal()->SetMediaChannel(channel_ ? channel_->media_channel()
172                                                  : nullptr);
173   }
174 
175   RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(0);
176 
177   for (const auto& receiver : receivers_) {
178     if (!channel_) {
179       // TODO(tommi): This can internally block and hop to the worker thread.
180       // It's likely that SetMediaChannel also does that, so perhaps we should
181       // require SetMediaChannel(nullptr) to also Stop() and skip this call.
182       receiver->internal()->Stop();
183     }
184 
185     receiver->internal()->SetMediaChannel(channel_ ? channel_->media_channel()
186                                                    : nullptr);
187   }
188 
189   RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(receivers_.size() * 2);
190 }
191 
AddSender(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender)192 void RtpTransceiver::AddSender(
193     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
194   RTC_DCHECK(!stopped_);
195   RTC_DCHECK(!unified_plan_);
196   RTC_DCHECK(sender);
197   RTC_DCHECK_EQ(media_type(), sender->media_type());
198   RTC_DCHECK(!absl::c_linear_search(senders_, sender));
199   senders_.push_back(sender);
200 }
201 
RemoveSender(RtpSenderInterface * sender)202 bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
203   RTC_DCHECK(!unified_plan_);
204   if (sender) {
205     RTC_DCHECK_EQ(media_type(), sender->media_type());
206   }
207   auto it = absl::c_find(senders_, sender);
208   if (it == senders_.end()) {
209     return false;
210   }
211   (*it)->internal()->Stop();
212   senders_.erase(it);
213   return true;
214 }
215 
AddReceiver(rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver)216 void RtpTransceiver::AddReceiver(
217     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
218         receiver) {
219   RTC_DCHECK(!stopped_);
220   RTC_DCHECK(!unified_plan_);
221   RTC_DCHECK(receiver);
222   RTC_DCHECK_EQ(media_type(), receiver->media_type());
223   RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
224   receivers_.push_back(receiver);
225 }
226 
RemoveReceiver(RtpReceiverInterface * receiver)227 bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
228   RTC_DCHECK(!unified_plan_);
229   if (receiver) {
230     RTC_DCHECK_EQ(media_type(), receiver->media_type());
231   }
232   auto it = absl::c_find(receivers_, receiver);
233   if (it == receivers_.end()) {
234     return false;
235   }
236   (*it)->internal()->Stop();
237   // After the receiver has been removed, there's no guarantee that the
238   // contained media channel isn't deleted shortly after this. To make sure that
239   // the receiver doesn't spontaneously try to use it's (potentially stale)
240   // media channel reference, we clear it out.
241   (*it)->internal()->SetMediaChannel(nullptr);
242   receivers_.erase(it);
243   return true;
244 }
245 
sender_internal() const246 rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
247   RTC_DCHECK(unified_plan_);
248   RTC_CHECK_EQ(1u, senders_.size());
249   return senders_[0]->internal();
250 }
251 
receiver_internal() const252 rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
253     const {
254   RTC_DCHECK(unified_plan_);
255   RTC_CHECK_EQ(1u, receivers_.size());
256   return receivers_[0]->internal();
257 }
258 
media_type() const259 cricket::MediaType RtpTransceiver::media_type() const {
260   return media_type_;
261 }
262 
mid() const263 absl::optional<std::string> RtpTransceiver::mid() const {
264   return mid_;
265 }
266 
OnFirstPacketReceived(cricket::ChannelInterface *)267 void RtpTransceiver::OnFirstPacketReceived(cricket::ChannelInterface*) {
268   for (const auto& receiver : receivers_) {
269     receiver->internal()->NotifyFirstPacketReceived();
270   }
271 }
272 
sender() const273 rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
274   RTC_DCHECK(unified_plan_);
275   RTC_CHECK_EQ(1u, senders_.size());
276   return senders_[0];
277 }
278 
receiver() const279 rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
280   RTC_DCHECK(unified_plan_);
281   RTC_CHECK_EQ(1u, receivers_.size());
282   return receivers_[0];
283 }
284 
set_current_direction(RtpTransceiverDirection direction)285 void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
286   RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
287                    << ") current direction from "
288                    << (current_direction_ ? RtpTransceiverDirectionToString(
289                                                 *current_direction_)
290                                           : "<not set>")
291                    << " to " << RtpTransceiverDirectionToString(direction)
292                    << ".";
293   current_direction_ = direction;
294   if (RtpTransceiverDirectionHasSend(*current_direction_)) {
295     has_ever_been_used_to_send_ = true;
296   }
297 }
298 
set_fired_direction(RtpTransceiverDirection direction)299 void RtpTransceiver::set_fired_direction(RtpTransceiverDirection direction) {
300   fired_direction_ = direction;
301 }
302 
stopped() const303 bool RtpTransceiver::stopped() const {
304   return stopped_;
305 }
306 
stopping() const307 bool RtpTransceiver::stopping() const {
308   RTC_DCHECK_RUN_ON(thread_);
309   return stopping_;
310 }
311 
direction() const312 RtpTransceiverDirection RtpTransceiver::direction() const {
313   if (unified_plan_ && stopping())
314     return webrtc::RtpTransceiverDirection::kStopped;
315 
316   return direction_;
317 }
318 
SetDirectionWithError(RtpTransceiverDirection new_direction)319 RTCError RtpTransceiver::SetDirectionWithError(
320     RtpTransceiverDirection new_direction) {
321   if (unified_plan_ && stopping()) {
322     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
323                          "Cannot set direction on a stopping transceiver.");
324   }
325   if (new_direction == direction_)
326     return RTCError::OK();
327 
328   if (new_direction == RtpTransceiverDirection::kStopped) {
329     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
330                          "The set direction 'stopped' is invalid.");
331   }
332 
333   direction_ = new_direction;
334   on_negotiation_needed_();
335 
336   return RTCError::OK();
337 }
338 
current_direction() const339 absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
340     const {
341   if (unified_plan_ && stopped())
342     return webrtc::RtpTransceiverDirection::kStopped;
343 
344   return current_direction_;
345 }
346 
fired_direction() const347 absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
348     const {
349   return fired_direction_;
350 }
351 
StopSendingAndReceiving()352 void RtpTransceiver::StopSendingAndReceiving() {
353   // 1. Let sender be transceiver.[[Sender]].
354   // 2. Let receiver be transceiver.[[Receiver]].
355   //
356   // 3. Stop sending media with sender.
357   //
358   // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
359   // specified in [RFC3550].
360   RTC_DCHECK_RUN_ON(thread_);
361   for (const auto& sender : senders_)
362     sender->internal()->Stop();
363 
364   // 5. Stop receiving media with receiver.
365   for (const auto& receiver : receivers_)
366     receiver->internal()->StopAndEndTrack();
367 
368   stopping_ = true;
369   direction_ = webrtc::RtpTransceiverDirection::kInactive;
370 }
371 
StopStandard()372 RTCError RtpTransceiver::StopStandard() {
373   RTC_DCHECK_RUN_ON(thread_);
374   // If we're on Plan B, do what Stop() used to do there.
375   if (!unified_plan_) {
376     StopInternal();
377     return RTCError::OK();
378   }
379   // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
380   // invoked.
381   //
382   // 2. Let connection be the RTCPeerConnection object associated with
383   // transceiver.
384   //
385   // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
386   if (is_pc_closed_) {
387     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
388                          "PeerConnection is closed.");
389   }
390 
391   // 4. If transceiver.[[Stopping]] is true, abort these steps.
392   if (stopping_)
393     return RTCError::OK();
394 
395   // 5. Stop sending and receiving given transceiver, and update the
396   // negotiation-needed flag for connection.
397   StopSendingAndReceiving();
398   on_negotiation_needed_();
399 
400   return RTCError::OK();
401 }
402 
StopInternal()403 void RtpTransceiver::StopInternal() {
404   StopTransceiverProcedure();
405 }
406 
StopTransceiverProcedure()407 void RtpTransceiver::StopTransceiverProcedure() {
408   RTC_DCHECK_RUN_ON(thread_);
409   // As specified in the "Stop the RTCRtpTransceiver" procedure
410   // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
411   // transceiver.
412   if (!stopping_)
413     StopSendingAndReceiving();
414 
415   // 2. Set transceiver.[[Stopped]] to true.
416   stopped_ = true;
417 
418   // Signal the updated change to the senders.
419   for (const auto& sender : senders_)
420     sender->internal()->SetTransceiverAsStopped();
421 
422   // 3. Set transceiver.[[Receptive]] to false.
423   // 4. Set transceiver.[[CurrentDirection]] to null.
424   current_direction_ = absl::nullopt;
425 }
426 
SetCodecPreferences(rtc::ArrayView<RtpCodecCapability> codec_capabilities)427 RTCError RtpTransceiver::SetCodecPreferences(
428     rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
429   RTC_DCHECK(unified_plan_);
430 
431   // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
432   // to codecs and abort these steps.
433   if (codec_capabilities.empty()) {
434     codec_preferences_.clear();
435     return RTCError::OK();
436   }
437 
438   // 4. Remove any duplicate values in codecs.
439   std::vector<RtpCodecCapability> codecs;
440   absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
441                          [&codecs](const RtpCodecCapability& codec) {
442                            return absl::c_linear_search(codecs, codec);
443                          });
444 
445   // 6. to 8.
446   RTCError result;
447   if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
448     std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
449     channel_manager_->GetSupportedAudioReceiveCodecs(&recv_codecs);
450     channel_manager_->GetSupportedAudioSendCodecs(&send_codecs);
451 
452     result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
453   } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
454     std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
455     channel_manager_->GetSupportedVideoReceiveCodecs(&recv_codecs);
456     channel_manager_->GetSupportedVideoSendCodecs(&send_codecs);
457 
458     result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
459   }
460 
461   if (result.ok()) {
462     codec_preferences_ = codecs;
463   }
464 
465   return result;
466 }
467 
468 std::vector<RtpHeaderExtensionCapability>
HeaderExtensionsToOffer() const469 RtpTransceiver::HeaderExtensionsToOffer() const {
470   return header_extensions_to_offer_;
471 }
472 
473 std::vector<RtpHeaderExtensionCapability>
HeaderExtensionsNegotiated() const474 RtpTransceiver::HeaderExtensionsNegotiated() const {
475   if (!channel_)
476     return {};
477   std::vector<RtpHeaderExtensionCapability> result;
478   for (const auto& ext : channel_->GetNegotiatedRtpHeaderExtensions()) {
479     result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
480   }
481   return result;
482 }
483 
SetOfferedRtpHeaderExtensions(rtc::ArrayView<const RtpHeaderExtensionCapability> header_extensions_to_offer)484 RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
485     rtc::ArrayView<const RtpHeaderExtensionCapability>
486         header_extensions_to_offer) {
487   for (const auto& entry : header_extensions_to_offer) {
488     // Handle unsupported requests for mandatory extensions as per
489     // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
490     // Note:
491     // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
492     //   this has to be checked on a higher level. We naturally error out
493     //   in the handling of Step 2.2 if an unset URI is encountered.
494 
495     // Step 2.2.
496     // Handle unknown extensions.
497     auto it = std::find_if(
498         header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
499         [&entry](const auto& offered) { return entry.uri == offered.uri; });
500     if (it == header_extensions_to_offer_.end()) {
501       return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
502                       "Attempted to modify an unoffered extension.");
503     }
504 
505     // Step 2.4-2.5.
506     // - Use of the transceiver interface indicates unified plan is in effect,
507     //   hence the MID extension needs to be enabled.
508     // - Also handle the mandatory video orientation extensions.
509     if ((entry.uri == RtpExtension::kMidUri ||
510          entry.uri == RtpExtension::kVideoRotationUri) &&
511         entry.direction != RtpTransceiverDirection::kSendRecv) {
512       return RTCError(RTCErrorType::INVALID_MODIFICATION,
513                       "Attempted to stop a mandatory extension.");
514     }
515   }
516 
517   // Apply mutation after error checking.
518   for (const auto& entry : header_extensions_to_offer) {
519     auto it = std::find_if(
520         header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
521         [&entry](const auto& offered) { return entry.uri == offered.uri; });
522     it->direction = entry.direction;
523   }
524 
525   return RTCError::OK();
526 }
527 
SetPeerConnectionClosed()528 void RtpTransceiver::SetPeerConnectionClosed() {
529   is_pc_closed_ = true;
530 }
531 
532 }  // namespace webrtc
533