• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
14 #include <utility>
15 
16 #include "absl/algorithm/container.h"
17 #include "api/rtp_parameters.h"
18 #include "pc/channel_manager.h"
19 #include "pc/rtp_media_utils.h"
20 #include "pc/rtp_parameters_conversion.h"
21 #include "rtc_base/checks.h"
22 #include "rtc_base/logging.h"
23 
24 namespace webrtc {
25 namespace {
26 template <class T>
VerifyCodecPreferences(const std::vector<RtpCodecCapability> & codecs,const std::vector<T> & send_codecs,const std::vector<T> & recv_codecs)27 RTCError 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 
100 }  // namespace
101 
RtpTransceiver(cricket::MediaType media_type)102 RtpTransceiver::RtpTransceiver(cricket::MediaType media_type)
103     : unified_plan_(false), media_type_(media_type) {
104   RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
105              media_type == cricket::MEDIA_TYPE_VIDEO);
106 }
107 
RtpTransceiver(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver,cricket::ChannelManager * channel_manager,std::vector<RtpHeaderExtensionCapability> header_extensions_offered)108 RtpTransceiver::RtpTransceiver(
109     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
110     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
111         receiver,
112     cricket::ChannelManager* channel_manager,
113     std::vector<RtpHeaderExtensionCapability> header_extensions_offered)
114     : unified_plan_(true),
115       media_type_(sender->media_type()),
116       channel_manager_(channel_manager),
117       header_extensions_to_offer_(std::move(header_extensions_offered)) {
118   RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
119              media_type_ == cricket::MEDIA_TYPE_VIDEO);
120   RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
121   senders_.push_back(sender);
122   receivers_.push_back(receiver);
123 }
124 
~RtpTransceiver()125 RtpTransceiver::~RtpTransceiver() {
126   Stop();
127 }
128 
SetChannel(cricket::ChannelInterface * channel)129 void RtpTransceiver::SetChannel(cricket::ChannelInterface* channel) {
130   // Cannot set a non-null channel on a stopped transceiver.
131   if (stopped_ && channel) {
132     return;
133   }
134 
135   if (channel) {
136     RTC_DCHECK_EQ(media_type(), channel->media_type());
137   }
138 
139   if (channel_) {
140     channel_->SignalFirstPacketReceived().disconnect(this);
141   }
142 
143   channel_ = channel;
144 
145   if (channel_) {
146     channel_->SignalFirstPacketReceived().connect(
147         this, &RtpTransceiver::OnFirstPacketReceived);
148   }
149 
150   for (const auto& sender : senders_) {
151     sender->internal()->SetMediaChannel(channel_ ? channel_->media_channel()
152                                                  : nullptr);
153   }
154 
155   for (const auto& receiver : receivers_) {
156     if (!channel_) {
157       receiver->internal()->Stop();
158     }
159 
160     receiver->internal()->SetMediaChannel(channel_ ? channel_->media_channel()
161                                                    : nullptr);
162   }
163 }
164 
AddSender(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender)165 void RtpTransceiver::AddSender(
166     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
167   RTC_DCHECK(!stopped_);
168   RTC_DCHECK(!unified_plan_);
169   RTC_DCHECK(sender);
170   RTC_DCHECK_EQ(media_type(), sender->media_type());
171   RTC_DCHECK(!absl::c_linear_search(senders_, sender));
172   senders_.push_back(sender);
173 }
174 
RemoveSender(RtpSenderInterface * sender)175 bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
176   RTC_DCHECK(!unified_plan_);
177   if (sender) {
178     RTC_DCHECK_EQ(media_type(), sender->media_type());
179   }
180   auto it = absl::c_find(senders_, sender);
181   if (it == senders_.end()) {
182     return false;
183   }
184   (*it)->internal()->Stop();
185   senders_.erase(it);
186   return true;
187 }
188 
AddReceiver(rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver)189 void RtpTransceiver::AddReceiver(
190     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
191         receiver) {
192   RTC_DCHECK(!stopped_);
193   RTC_DCHECK(!unified_plan_);
194   RTC_DCHECK(receiver);
195   RTC_DCHECK_EQ(media_type(), receiver->media_type());
196   RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
197   receivers_.push_back(receiver);
198 }
199 
RemoveReceiver(RtpReceiverInterface * receiver)200 bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
201   RTC_DCHECK(!unified_plan_);
202   if (receiver) {
203     RTC_DCHECK_EQ(media_type(), receiver->media_type());
204   }
205   auto it = absl::c_find(receivers_, receiver);
206   if (it == receivers_.end()) {
207     return false;
208   }
209   (*it)->internal()->Stop();
210   // After the receiver has been removed, there's no guarantee that the
211   // contained media channel isn't deleted shortly after this. To make sure that
212   // the receiver doesn't spontaneously try to use it's (potentially stale)
213   // media channel reference, we clear it out.
214   (*it)->internal()->SetMediaChannel(nullptr);
215   receivers_.erase(it);
216   return true;
217 }
218 
sender_internal() const219 rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
220   RTC_DCHECK(unified_plan_);
221   RTC_CHECK_EQ(1u, senders_.size());
222   return senders_[0]->internal();
223 }
224 
receiver_internal() const225 rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
226     const {
227   RTC_DCHECK(unified_plan_);
228   RTC_CHECK_EQ(1u, receivers_.size());
229   return receivers_[0]->internal();
230 }
231 
media_type() const232 cricket::MediaType RtpTransceiver::media_type() const {
233   return media_type_;
234 }
235 
mid() const236 absl::optional<std::string> RtpTransceiver::mid() const {
237   return mid_;
238 }
239 
OnFirstPacketReceived(cricket::ChannelInterface *)240 void RtpTransceiver::OnFirstPacketReceived(cricket::ChannelInterface*) {
241   for (const auto& receiver : receivers_) {
242     receiver->internal()->NotifyFirstPacketReceived();
243   }
244 }
245 
sender() const246 rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
247   RTC_DCHECK(unified_plan_);
248   RTC_CHECK_EQ(1u, senders_.size());
249   return senders_[0];
250 }
251 
receiver() const252 rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
253   RTC_DCHECK(unified_plan_);
254   RTC_CHECK_EQ(1u, receivers_.size());
255   return receivers_[0];
256 }
257 
set_current_direction(RtpTransceiverDirection direction)258 void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
259   RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
260                    << ") current direction from "
261                    << (current_direction_ ? RtpTransceiverDirectionToString(
262                                                 *current_direction_)
263                                           : "<not set>")
264                    << " to " << RtpTransceiverDirectionToString(direction)
265                    << ".";
266   current_direction_ = direction;
267   if (RtpTransceiverDirectionHasSend(*current_direction_)) {
268     has_ever_been_used_to_send_ = true;
269   }
270 }
271 
set_fired_direction(RtpTransceiverDirection direction)272 void RtpTransceiver::set_fired_direction(RtpTransceiverDirection direction) {
273   fired_direction_ = direction;
274 }
275 
stopped() const276 bool RtpTransceiver::stopped() const {
277   return stopped_;
278 }
279 
direction() const280 RtpTransceiverDirection RtpTransceiver::direction() const {
281   return direction_;
282 }
283 
SetDirection(RtpTransceiverDirection new_direction)284 void RtpTransceiver::SetDirection(RtpTransceiverDirection new_direction) {
285   if (stopped()) {
286     return;
287   }
288   if (new_direction == direction_) {
289     return;
290   }
291   direction_ = new_direction;
292   SignalNegotiationNeeded();
293 }
294 
current_direction() const295 absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
296     const {
297   return current_direction_;
298 }
299 
fired_direction() const300 absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
301     const {
302   return fired_direction_;
303 }
304 
Stop()305 void RtpTransceiver::Stop() {
306   for (const auto& sender : senders_) {
307     sender->internal()->Stop();
308   }
309   for (const auto& receiver : receivers_) {
310     receiver->internal()->Stop();
311   }
312   stopped_ = true;
313   current_direction_ = absl::nullopt;
314 }
315 
SetCodecPreferences(rtc::ArrayView<RtpCodecCapability> codec_capabilities)316 RTCError RtpTransceiver::SetCodecPreferences(
317     rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
318   RTC_DCHECK(unified_plan_);
319 
320   // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
321   // to codecs and abort these steps.
322   if (codec_capabilities.empty()) {
323     codec_preferences_.clear();
324     return RTCError::OK();
325   }
326 
327   // 4. Remove any duplicate values in codecs.
328   std::vector<RtpCodecCapability> codecs;
329   absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
330                          [&codecs](const RtpCodecCapability& codec) {
331                            return absl::c_linear_search(codecs, codec);
332                          });
333 
334   // 6. to 8.
335   RTCError result;
336   if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
337     std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
338     channel_manager_->GetSupportedAudioReceiveCodecs(&recv_codecs);
339     channel_manager_->GetSupportedAudioSendCodecs(&send_codecs);
340 
341     result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
342   } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
343     std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
344     channel_manager_->GetSupportedVideoReceiveCodecs(&recv_codecs);
345     channel_manager_->GetSupportedVideoSendCodecs(&send_codecs);
346 
347     result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
348   }
349 
350   if (result.ok()) {
351     codec_preferences_ = codecs;
352   }
353 
354   return result;
355 }
356 
357 std::vector<RtpHeaderExtensionCapability>
HeaderExtensionsToOffer() const358 RtpTransceiver::HeaderExtensionsToOffer() const {
359   return header_extensions_to_offer_;
360 }
361 
SetOfferedRtpHeaderExtensions(rtc::ArrayView<const RtpHeaderExtensionCapability> header_extensions_to_offer)362 RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
363     rtc::ArrayView<const RtpHeaderExtensionCapability>
364         header_extensions_to_offer) {
365   for (const auto& entry : header_extensions_to_offer) {
366     // Handle unsupported requests for mandatory extensions as per
367     // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
368     // Note:
369     // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
370     //   this has to be checked on a higher level. We naturally error out
371     //   in the handling of Step 2.2 if an unset URI is encountered.
372 
373     // Step 2.2.
374     // Handle unknown extensions.
375     auto it = std::find_if(
376         header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
377         [&entry](const auto& offered) { return entry.uri == offered.uri; });
378     if (it == header_extensions_to_offer_.end()) {
379       return RTCError(RTCErrorType::INVALID_PARAMETER,
380                       "Attempted to modify an unoffered extension.");
381     }
382 
383     // Step 2.4-2.5.
384     // - Use of the transceiver interface indicates unified plan is in effect,
385     //   hence the MID extension needs to be enabled.
386     // - Also handle the mandatory video orientation extensions.
387     if ((entry.uri == RtpExtension::kMidUri ||
388          entry.uri == RtpExtension::kVideoRotationUri) &&
389         entry.direction != RtpTransceiverDirection::kSendRecv) {
390       return RTCError(RTCErrorType::INVALID_MODIFICATION,
391                       "Attempted to stop a mandatory extension.");
392     }
393   }
394 
395   // Apply mutation after error checking.
396   for (const auto& entry : header_extensions_to_offer) {
397     auto it = std::find_if(
398         header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
399         [&entry](const auto& offered) { return entry.uri == offered.uri; });
400     it->direction = entry.direction;
401   }
402 
403   return RTCError::OK();
404 }
405 
406 }  // namespace webrtc
407