xref: /aosp_15_r20/external/webrtc/pc/rtp_transceiver.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "pc/rtp_transceiver.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <iterator>
15*d9f75844SAndroid Build Coastguard Worker #include <string>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker #include <vector>
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
20*d9f75844SAndroid Build Coastguard Worker #include "absl/memory/memory.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/peer_connection_interface.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/rtp_parameters.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/sequence_checker.h"
24*d9f75844SAndroid Build Coastguard Worker #include "media/base/codec.h"
25*d9f75844SAndroid Build Coastguard Worker #include "media/base/media_constants.h"
26*d9f75844SAndroid Build Coastguard Worker #include "media/base/media_engine.h"
27*d9f75844SAndroid Build Coastguard Worker #include "pc/channel.h"
28*d9f75844SAndroid Build Coastguard Worker #include "pc/rtp_media_utils.h"
29*d9f75844SAndroid Build Coastguard Worker #include "pc/session_description.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread.h"
33*d9f75844SAndroid Build Coastguard Worker 
34*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
35*d9f75844SAndroid Build Coastguard Worker namespace {
36*d9f75844SAndroid Build Coastguard Worker template <class T>
VerifyCodecPreferences(const std::vector<RtpCodecCapability> & codecs,const std::vector<T> & send_codecs,const std::vector<T> & recv_codecs)37*d9f75844SAndroid Build Coastguard Worker RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
38*d9f75844SAndroid Build Coastguard Worker                                 const std::vector<T>& send_codecs,
39*d9f75844SAndroid Build Coastguard Worker                                 const std::vector<T>& recv_codecs) {
40*d9f75844SAndroid Build Coastguard Worker   // If the intersection between codecs and
41*d9f75844SAndroid Build Coastguard Worker   // RTCRtpSender.getCapabilities(kind).codecs or the intersection between
42*d9f75844SAndroid Build Coastguard Worker   // codecs and RTCRtpReceiver.getCapabilities(kind).codecs only contains RTX,
43*d9f75844SAndroid Build Coastguard Worker   // RED or FEC codecs or is an empty set, throw InvalidModificationError.
44*d9f75844SAndroid Build Coastguard Worker   // This ensures that we always have something to offer, regardless of
45*d9f75844SAndroid Build Coastguard Worker   // transceiver.direction.
46*d9f75844SAndroid Build Coastguard Worker 
47*d9f75844SAndroid Build Coastguard Worker   if (!absl::c_any_of(codecs, [&recv_codecs](const RtpCodecCapability& codec) {
48*d9f75844SAndroid Build Coastguard Worker         return codec.name != cricket::kRtxCodecName &&
49*d9f75844SAndroid Build Coastguard Worker                codec.name != cricket::kRedCodecName &&
50*d9f75844SAndroid Build Coastguard Worker                codec.name != cricket::kFlexfecCodecName &&
51*d9f75844SAndroid Build Coastguard Worker                absl::c_any_of(recv_codecs, [&codec](const T& recv_codec) {
52*d9f75844SAndroid Build Coastguard Worker                  return recv_codec.MatchesCapability(codec);
53*d9f75844SAndroid Build Coastguard Worker                });
54*d9f75844SAndroid Build Coastguard Worker       })) {
55*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_MODIFICATION,
56*d9f75844SAndroid Build Coastguard Worker                     "Invalid codec preferences: Missing codec from recv "
57*d9f75844SAndroid Build Coastguard Worker                     "codec capabilities.");
58*d9f75844SAndroid Build Coastguard Worker   }
59*d9f75844SAndroid Build Coastguard Worker 
60*d9f75844SAndroid Build Coastguard Worker   if (!absl::c_any_of(codecs, [&send_codecs](const RtpCodecCapability& codec) {
61*d9f75844SAndroid Build Coastguard Worker         return codec.name != cricket::kRtxCodecName &&
62*d9f75844SAndroid Build Coastguard Worker                codec.name != cricket::kRedCodecName &&
63*d9f75844SAndroid Build Coastguard Worker                codec.name != cricket::kFlexfecCodecName &&
64*d9f75844SAndroid Build Coastguard Worker                absl::c_any_of(send_codecs, [&codec](const T& send_codec) {
65*d9f75844SAndroid Build Coastguard Worker                  return send_codec.MatchesCapability(codec);
66*d9f75844SAndroid Build Coastguard Worker                });
67*d9f75844SAndroid Build Coastguard Worker       })) {
68*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_MODIFICATION,
69*d9f75844SAndroid Build Coastguard Worker                     "Invalid codec preferences: Missing codec from send "
70*d9f75844SAndroid Build Coastguard Worker                     "codec capabilities.");
71*d9f75844SAndroid Build Coastguard Worker   }
72*d9f75844SAndroid Build Coastguard Worker 
73*d9f75844SAndroid Build Coastguard Worker   // Let codecCapabilities be the union of
74*d9f75844SAndroid Build Coastguard Worker   // RTCRtpSender.getCapabilities(kind).codecs and
75*d9f75844SAndroid Build Coastguard Worker   // RTCRtpReceiver.getCapabilities(kind).codecs. For each codec in codecs, If
76*d9f75844SAndroid Build Coastguard Worker   // codec is not in codecCapabilities, throw InvalidModificationError.
77*d9f75844SAndroid Build Coastguard Worker   for (const auto& codec_preference : codecs) {
78*d9f75844SAndroid Build Coastguard Worker     bool is_recv_codec =
79*d9f75844SAndroid Build Coastguard Worker         absl::c_any_of(recv_codecs, [&codec_preference](const T& codec) {
80*d9f75844SAndroid Build Coastguard Worker           return codec.MatchesCapability(codec_preference);
81*d9f75844SAndroid Build Coastguard Worker         });
82*d9f75844SAndroid Build Coastguard Worker 
83*d9f75844SAndroid Build Coastguard Worker     bool is_send_codec =
84*d9f75844SAndroid Build Coastguard Worker         absl::c_any_of(send_codecs, [&codec_preference](const T& codec) {
85*d9f75844SAndroid Build Coastguard Worker           return codec.MatchesCapability(codec_preference);
86*d9f75844SAndroid Build Coastguard Worker         });
87*d9f75844SAndroid Build Coastguard Worker 
88*d9f75844SAndroid Build Coastguard Worker     if (!is_recv_codec && !is_send_codec) {
89*d9f75844SAndroid Build Coastguard Worker       return RTCError(
90*d9f75844SAndroid Build Coastguard Worker           RTCErrorType::INVALID_MODIFICATION,
91*d9f75844SAndroid Build Coastguard Worker           std::string("Invalid codec preferences: invalid codec with name \"") +
92*d9f75844SAndroid Build Coastguard Worker               codec_preference.name + "\".");
93*d9f75844SAndroid Build Coastguard Worker     }
94*d9f75844SAndroid Build Coastguard Worker   }
95*d9f75844SAndroid Build Coastguard Worker 
96*d9f75844SAndroid Build Coastguard Worker   // Check we have a real codec (not just rtx, red or fec)
97*d9f75844SAndroid Build Coastguard Worker   if (absl::c_all_of(codecs, [](const RtpCodecCapability& codec) {
98*d9f75844SAndroid Build Coastguard Worker         return codec.name == cricket::kRtxCodecName ||
99*d9f75844SAndroid Build Coastguard Worker                codec.name == cricket::kRedCodecName ||
100*d9f75844SAndroid Build Coastguard Worker                codec.name == cricket::kUlpfecCodecName;
101*d9f75844SAndroid Build Coastguard Worker       })) {
102*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_MODIFICATION,
103*d9f75844SAndroid Build Coastguard Worker                     "Invalid codec preferences: codec list must have a non "
104*d9f75844SAndroid Build Coastguard Worker                     "RTX, RED or FEC entry.");
105*d9f75844SAndroid Build Coastguard Worker   }
106*d9f75844SAndroid Build Coastguard Worker 
107*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
108*d9f75844SAndroid Build Coastguard Worker }
109*d9f75844SAndroid Build Coastguard Worker 
110*d9f75844SAndroid Build Coastguard Worker // Matches the list of codecs as capabilities (potentially without SVC related
111*d9f75844SAndroid Build Coastguard Worker // information) to the list of send codecs and returns the list of codecs with
112*d9f75844SAndroid Build Coastguard Worker // all the SVC related information.
MatchCodecPreferences(const std::vector<RtpCodecCapability> & codecs,const std::vector<cricket::VideoCodec> & send_codecs)113*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::VideoCodec> MatchCodecPreferences(
114*d9f75844SAndroid Build Coastguard Worker     const std::vector<RtpCodecCapability>& codecs,
115*d9f75844SAndroid Build Coastguard Worker     const std::vector<cricket::VideoCodec>& send_codecs) {
116*d9f75844SAndroid Build Coastguard Worker   std::vector<cricket::VideoCodec> result;
117*d9f75844SAndroid Build Coastguard Worker 
118*d9f75844SAndroid Build Coastguard Worker   for (const auto& codec_preference : codecs) {
119*d9f75844SAndroid Build Coastguard Worker     for (const cricket::VideoCodec& send_codec : send_codecs) {
120*d9f75844SAndroid Build Coastguard Worker       if (send_codec.MatchesCapability(codec_preference)) {
121*d9f75844SAndroid Build Coastguard Worker         result.push_back(send_codec);
122*d9f75844SAndroid Build Coastguard Worker       }
123*d9f75844SAndroid Build Coastguard Worker     }
124*d9f75844SAndroid Build Coastguard Worker   }
125*d9f75844SAndroid Build Coastguard Worker 
126*d9f75844SAndroid Build Coastguard Worker   return result;
127*d9f75844SAndroid Build Coastguard Worker }
128*d9f75844SAndroid Build Coastguard Worker 
GetCurrentTaskQueueOrThread()129*d9f75844SAndroid Build Coastguard Worker TaskQueueBase* GetCurrentTaskQueueOrThread() {
130*d9f75844SAndroid Build Coastguard Worker   TaskQueueBase* current = TaskQueueBase::Current();
131*d9f75844SAndroid Build Coastguard Worker   if (!current)
132*d9f75844SAndroid Build Coastguard Worker     current = rtc::ThreadManager::Instance()->CurrentThread();
133*d9f75844SAndroid Build Coastguard Worker   return current;
134*d9f75844SAndroid Build Coastguard Worker }
135*d9f75844SAndroid Build Coastguard Worker 
136*d9f75844SAndroid Build Coastguard Worker }  // namespace
137*d9f75844SAndroid Build Coastguard Worker 
RtpTransceiver(cricket::MediaType media_type,ConnectionContext * context)138*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::RtpTransceiver(cricket::MediaType media_type,
139*d9f75844SAndroid Build Coastguard Worker                                ConnectionContext* context)
140*d9f75844SAndroid Build Coastguard Worker     : thread_(GetCurrentTaskQueueOrThread()),
141*d9f75844SAndroid Build Coastguard Worker       unified_plan_(false),
142*d9f75844SAndroid Build Coastguard Worker       media_type_(media_type),
143*d9f75844SAndroid Build Coastguard Worker       context_(context) {
144*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
145*d9f75844SAndroid Build Coastguard Worker              media_type == cricket::MEDIA_TYPE_VIDEO);
146*d9f75844SAndroid Build Coastguard Worker }
147*d9f75844SAndroid Build Coastguard Worker 
RtpTransceiver(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver,ConnectionContext * context,std::vector<RtpHeaderExtensionCapability> header_extensions_offered,std::function<void ()> on_negotiation_needed)148*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::RtpTransceiver(
149*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
150*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
151*d9f75844SAndroid Build Coastguard Worker         receiver,
152*d9f75844SAndroid Build Coastguard Worker     ConnectionContext* context,
153*d9f75844SAndroid Build Coastguard Worker     std::vector<RtpHeaderExtensionCapability> header_extensions_offered,
154*d9f75844SAndroid Build Coastguard Worker     std::function<void()> on_negotiation_needed)
155*d9f75844SAndroid Build Coastguard Worker     : thread_(GetCurrentTaskQueueOrThread()),
156*d9f75844SAndroid Build Coastguard Worker       unified_plan_(true),
157*d9f75844SAndroid Build Coastguard Worker       media_type_(sender->media_type()),
158*d9f75844SAndroid Build Coastguard Worker       context_(context),
159*d9f75844SAndroid Build Coastguard Worker       header_extensions_to_offer_(std::move(header_extensions_offered)),
160*d9f75844SAndroid Build Coastguard Worker       on_negotiation_needed_(std::move(on_negotiation_needed)) {
161*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
162*d9f75844SAndroid Build Coastguard Worker              media_type_ == cricket::MEDIA_TYPE_VIDEO);
163*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
164*d9f75844SAndroid Build Coastguard Worker   if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO)
165*d9f75844SAndroid Build Coastguard Worker     sender->internal()->SetVideoCodecPreferences(
166*d9f75844SAndroid Build Coastguard Worker         media_engine()->video().send_codecs(false));
167*d9f75844SAndroid Build Coastguard Worker   senders_.push_back(sender);
168*d9f75844SAndroid Build Coastguard Worker   receivers_.push_back(receiver);
169*d9f75844SAndroid Build Coastguard Worker }
170*d9f75844SAndroid Build Coastguard Worker 
~RtpTransceiver()171*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::~RtpTransceiver() {
172*d9f75844SAndroid Build Coastguard Worker   // TODO(tommi): On Android, when running PeerConnectionClientTest (e.g.
173*d9f75844SAndroid Build Coastguard Worker   // PeerConnectionClientTest#testCameraSwitch), the instance doesn't get
174*d9f75844SAndroid Build Coastguard Worker   // deleted on `thread_`. See if we can fix that.
175*d9f75844SAndroid Build Coastguard Worker   if (!stopped_) {
176*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(thread_);
177*d9f75844SAndroid Build Coastguard Worker     StopInternal();
178*d9f75844SAndroid Build Coastguard Worker   }
179*d9f75844SAndroid Build Coastguard Worker 
180*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(!channel_) << "Missing call to ClearChannel?";
181*d9f75844SAndroid Build Coastguard Worker }
182*d9f75844SAndroid Build Coastguard Worker 
CreateChannel(absl::string_view mid,Call * call_ptr,const cricket::MediaConfig & media_config,bool srtp_required,CryptoOptions crypto_options,const cricket::AudioOptions & audio_options,const cricket::VideoOptions & video_options,VideoBitrateAllocatorFactory * video_bitrate_allocator_factory,std::function<RtpTransportInternal * (absl::string_view)> transport_lookup)183*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::CreateChannel(
184*d9f75844SAndroid Build Coastguard Worker     absl::string_view mid,
185*d9f75844SAndroid Build Coastguard Worker     Call* call_ptr,
186*d9f75844SAndroid Build Coastguard Worker     const cricket::MediaConfig& media_config,
187*d9f75844SAndroid Build Coastguard Worker     bool srtp_required,
188*d9f75844SAndroid Build Coastguard Worker     CryptoOptions crypto_options,
189*d9f75844SAndroid Build Coastguard Worker     const cricket::AudioOptions& audio_options,
190*d9f75844SAndroid Build Coastguard Worker     const cricket::VideoOptions& video_options,
191*d9f75844SAndroid Build Coastguard Worker     VideoBitrateAllocatorFactory* video_bitrate_allocator_factory,
192*d9f75844SAndroid Build Coastguard Worker     std::function<RtpTransportInternal*(absl::string_view)> transport_lookup) {
193*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
194*d9f75844SAndroid Build Coastguard Worker   if (!media_engine()) {
195*d9f75844SAndroid Build Coastguard Worker     // TODO(hta): Must be a better way
196*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INTERNAL_ERROR,
197*d9f75844SAndroid Build Coastguard Worker                     "No media engine for mid=" + std::string(mid));
198*d9f75844SAndroid Build Coastguard Worker   }
199*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::ChannelInterface> new_channel;
200*d9f75844SAndroid Build Coastguard Worker   if (media_type() == cricket::MEDIA_TYPE_AUDIO) {
201*d9f75844SAndroid Build Coastguard Worker     // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
202*d9f75844SAndroid Build Coastguard Worker     // the worker thread. We shouldn't be using the `call_ptr_` hack here but
203*d9f75844SAndroid Build Coastguard Worker     // simply be on the worker thread and use `call_` (update upstream code).
204*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(call_ptr);
205*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(media_engine());
206*d9f75844SAndroid Build Coastguard Worker     // TODO(bugs.webrtc.org/11992): Remove this workaround after updates in
207*d9f75844SAndroid Build Coastguard Worker     // PeerConnection and add the expectation that we're already on the right
208*d9f75844SAndroid Build Coastguard Worker     // thread.
209*d9f75844SAndroid Build Coastguard Worker     context()->worker_thread()->BlockingCall([&] {
210*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_RUN_ON(context()->worker_thread());
211*d9f75844SAndroid Build Coastguard Worker 
212*d9f75844SAndroid Build Coastguard Worker       cricket::VoiceMediaChannel* media_channel =
213*d9f75844SAndroid Build Coastguard Worker           media_engine()->voice().CreateMediaChannel(
214*d9f75844SAndroid Build Coastguard Worker               call_ptr, media_config, audio_options, crypto_options);
215*d9f75844SAndroid Build Coastguard Worker       if (!media_channel) {
216*d9f75844SAndroid Build Coastguard Worker         return;
217*d9f75844SAndroid Build Coastguard Worker       }
218*d9f75844SAndroid Build Coastguard Worker 
219*d9f75844SAndroid Build Coastguard Worker       new_channel = std::make_unique<cricket::VoiceChannel>(
220*d9f75844SAndroid Build Coastguard Worker           context()->worker_thread(), context()->network_thread(),
221*d9f75844SAndroid Build Coastguard Worker           context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
222*d9f75844SAndroid Build Coastguard Worker           srtp_required, crypto_options, context()->ssrc_generator());
223*d9f75844SAndroid Build Coastguard Worker     });
224*d9f75844SAndroid Build Coastguard Worker   } else {
225*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, media_type());
226*d9f75844SAndroid Build Coastguard Worker 
227*d9f75844SAndroid Build Coastguard Worker     // TODO(bugs.webrtc.org/11992): CreateVideoChannel internally switches to
228*d9f75844SAndroid Build Coastguard Worker     // the worker thread. We shouldn't be using the `call_ptr_` hack here but
229*d9f75844SAndroid Build Coastguard Worker     // simply be on the worker thread and use `call_` (update upstream code).
230*d9f75844SAndroid Build Coastguard Worker     context()->worker_thread()->BlockingCall([&] {
231*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_RUN_ON(context()->worker_thread());
232*d9f75844SAndroid Build Coastguard Worker       cricket::VideoMediaChannel* media_channel =
233*d9f75844SAndroid Build Coastguard Worker           media_engine()->video().CreateMediaChannel(
234*d9f75844SAndroid Build Coastguard Worker               call_ptr, media_config, video_options, crypto_options,
235*d9f75844SAndroid Build Coastguard Worker               video_bitrate_allocator_factory);
236*d9f75844SAndroid Build Coastguard Worker       if (!media_channel) {
237*d9f75844SAndroid Build Coastguard Worker         return;
238*d9f75844SAndroid Build Coastguard Worker       }
239*d9f75844SAndroid Build Coastguard Worker 
240*d9f75844SAndroid Build Coastguard Worker       new_channel = std::make_unique<cricket::VideoChannel>(
241*d9f75844SAndroid Build Coastguard Worker           context()->worker_thread(), context()->network_thread(),
242*d9f75844SAndroid Build Coastguard Worker           context()->signaling_thread(), absl::WrapUnique(media_channel), mid,
243*d9f75844SAndroid Build Coastguard Worker           srtp_required, crypto_options, context()->ssrc_generator());
244*d9f75844SAndroid Build Coastguard Worker     });
245*d9f75844SAndroid Build Coastguard Worker   }
246*d9f75844SAndroid Build Coastguard Worker   if (!new_channel) {
247*d9f75844SAndroid Build Coastguard Worker     // TODO(hta): Must be a better way
248*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INTERNAL_ERROR,
249*d9f75844SAndroid Build Coastguard Worker                     "Failed to create channel for mid=" + std::string(mid));
250*d9f75844SAndroid Build Coastguard Worker   }
251*d9f75844SAndroid Build Coastguard Worker   SetChannel(std::move(new_channel), transport_lookup);
252*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
253*d9f75844SAndroid Build Coastguard Worker }
254*d9f75844SAndroid Build Coastguard Worker 
SetChannel(std::unique_ptr<cricket::ChannelInterface> channel,std::function<RtpTransportInternal * (const std::string &)> transport_lookup)255*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::SetChannel(
256*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<cricket::ChannelInterface> channel,
257*d9f75844SAndroid Build Coastguard Worker     std::function<RtpTransportInternal*(const std::string&)> transport_lookup) {
258*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
259*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(channel);
260*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(transport_lookup);
261*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!channel_);
262*d9f75844SAndroid Build Coastguard Worker   // Cannot set a channel on a stopped transceiver.
263*d9f75844SAndroid Build Coastguard Worker   if (stopped_) {
264*d9f75844SAndroid Build Coastguard Worker     return;
265*d9f75844SAndroid Build Coastguard Worker   }
266*d9f75844SAndroid Build Coastguard Worker 
267*d9f75844SAndroid Build Coastguard Worker   RTC_LOG_THREAD_BLOCK_COUNT();
268*d9f75844SAndroid Build Coastguard Worker 
269*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(media_type(), channel->media_type());
270*d9f75844SAndroid Build Coastguard Worker   signaling_thread_safety_ = PendingTaskSafetyFlag::Create();
271*d9f75844SAndroid Build Coastguard Worker 
272*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
273*d9f75844SAndroid Build Coastguard Worker 
274*d9f75844SAndroid Build Coastguard Worker   // An alternative to this, could be to require SetChannel to be called
275*d9f75844SAndroid Build Coastguard Worker   // on the network thread. The channel object operates for the most part
276*d9f75844SAndroid Build Coastguard Worker   // on the network thread, as part of its initialization being on the network
277*d9f75844SAndroid Build Coastguard Worker   // thread is required, so setting a channel object as part of the construction
278*d9f75844SAndroid Build Coastguard Worker   // (without thread hopping) might be the more efficient thing to do than
279*d9f75844SAndroid Build Coastguard Worker   // how SetChannel works today.
280*d9f75844SAndroid Build Coastguard Worker   // Similarly, if the channel() accessor is limited to the network thread, that
281*d9f75844SAndroid Build Coastguard Worker   // helps with keeping the channel implementation requirements being met and
282*d9f75844SAndroid Build Coastguard Worker   // avoids synchronization for accessing the pointer or network related state.
283*d9f75844SAndroid Build Coastguard Worker   context()->network_thread()->BlockingCall([&]() {
284*d9f75844SAndroid Build Coastguard Worker     if (channel_) {
285*d9f75844SAndroid Build Coastguard Worker       channel_->SetFirstPacketReceivedCallback(nullptr);
286*d9f75844SAndroid Build Coastguard Worker       channel_->SetRtpTransport(nullptr);
287*d9f75844SAndroid Build Coastguard Worker       channel_to_delete = std::move(channel_);
288*d9f75844SAndroid Build Coastguard Worker     }
289*d9f75844SAndroid Build Coastguard Worker 
290*d9f75844SAndroid Build Coastguard Worker     channel_ = std::move(channel);
291*d9f75844SAndroid Build Coastguard Worker 
292*d9f75844SAndroid Build Coastguard Worker     channel_->SetRtpTransport(transport_lookup(channel_->mid()));
293*d9f75844SAndroid Build Coastguard Worker     channel_->SetFirstPacketReceivedCallback(
294*d9f75844SAndroid Build Coastguard Worker         [thread = thread_, flag = signaling_thread_safety_, this]() mutable {
295*d9f75844SAndroid Build Coastguard Worker           thread->PostTask(
296*d9f75844SAndroid Build Coastguard Worker               SafeTask(std::move(flag), [this]() { OnFirstPacketReceived(); }));
297*d9f75844SAndroid Build Coastguard Worker         });
298*d9f75844SAndroid Build Coastguard Worker   });
299*d9f75844SAndroid Build Coastguard Worker   PushNewMediaChannelAndDeleteChannel(nullptr);
300*d9f75844SAndroid Build Coastguard Worker 
301*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
302*d9f75844SAndroid Build Coastguard Worker }
303*d9f75844SAndroid Build Coastguard Worker 
ClearChannel()304*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::ClearChannel() {
305*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
306*d9f75844SAndroid Build Coastguard Worker 
307*d9f75844SAndroid Build Coastguard Worker   if (!channel_) {
308*d9f75844SAndroid Build Coastguard Worker     return;
309*d9f75844SAndroid Build Coastguard Worker   }
310*d9f75844SAndroid Build Coastguard Worker 
311*d9f75844SAndroid Build Coastguard Worker   RTC_LOG_THREAD_BLOCK_COUNT();
312*d9f75844SAndroid Build Coastguard Worker 
313*d9f75844SAndroid Build Coastguard Worker   if (channel_) {
314*d9f75844SAndroid Build Coastguard Worker     signaling_thread_safety_->SetNotAlive();
315*d9f75844SAndroid Build Coastguard Worker     signaling_thread_safety_ = nullptr;
316*d9f75844SAndroid Build Coastguard Worker   }
317*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::ChannelInterface> channel_to_delete;
318*d9f75844SAndroid Build Coastguard Worker 
319*d9f75844SAndroid Build Coastguard Worker   context()->network_thread()->BlockingCall([&]() {
320*d9f75844SAndroid Build Coastguard Worker     if (channel_) {
321*d9f75844SAndroid Build Coastguard Worker       channel_->SetFirstPacketReceivedCallback(nullptr);
322*d9f75844SAndroid Build Coastguard Worker       channel_->SetRtpTransport(nullptr);
323*d9f75844SAndroid Build Coastguard Worker       channel_to_delete = std::move(channel_);
324*d9f75844SAndroid Build Coastguard Worker     }
325*d9f75844SAndroid Build Coastguard Worker   });
326*d9f75844SAndroid Build Coastguard Worker 
327*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(1);
328*d9f75844SAndroid Build Coastguard Worker   PushNewMediaChannelAndDeleteChannel(std::move(channel_to_delete));
329*d9f75844SAndroid Build Coastguard Worker 
330*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
331*d9f75844SAndroid Build Coastguard Worker }
332*d9f75844SAndroid Build Coastguard Worker 
PushNewMediaChannelAndDeleteChannel(std::unique_ptr<cricket::ChannelInterface> channel_to_delete)333*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::PushNewMediaChannelAndDeleteChannel(
334*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<cricket::ChannelInterface> channel_to_delete) {
335*d9f75844SAndroid Build Coastguard Worker   // The clumsy combination of pushing down media channel and deleting
336*d9f75844SAndroid Build Coastguard Worker   // the channel is due to the desire to do both things in one Invoke().
337*d9f75844SAndroid Build Coastguard Worker   if (!channel_to_delete && senders_.empty() && receivers_.empty()) {
338*d9f75844SAndroid Build Coastguard Worker     return;
339*d9f75844SAndroid Build Coastguard Worker   }
340*d9f75844SAndroid Build Coastguard Worker   context()->worker_thread()->BlockingCall([&]() {
341*d9f75844SAndroid Build Coastguard Worker     // Push down the new media_channel, if any, otherwise clear it.
342*d9f75844SAndroid Build Coastguard Worker     auto* media_channel = channel_ ? channel_->media_channel() : nullptr;
343*d9f75844SAndroid Build Coastguard Worker     for (const auto& sender : senders_) {
344*d9f75844SAndroid Build Coastguard Worker       sender->internal()->SetMediaChannel(media_channel);
345*d9f75844SAndroid Build Coastguard Worker     }
346*d9f75844SAndroid Build Coastguard Worker 
347*d9f75844SAndroid Build Coastguard Worker     for (const auto& receiver : receivers_) {
348*d9f75844SAndroid Build Coastguard Worker       receiver->internal()->SetMediaChannel(media_channel);
349*d9f75844SAndroid Build Coastguard Worker     }
350*d9f75844SAndroid Build Coastguard Worker 
351*d9f75844SAndroid Build Coastguard Worker     // Destroy the channel, if we had one, now _after_ updating the receivers
352*d9f75844SAndroid Build Coastguard Worker     // who might have had references to the previous channel.
353*d9f75844SAndroid Build Coastguard Worker     if (channel_to_delete) {
354*d9f75844SAndroid Build Coastguard Worker       channel_to_delete.reset(nullptr);
355*d9f75844SAndroid Build Coastguard Worker     }
356*d9f75844SAndroid Build Coastguard Worker   });
357*d9f75844SAndroid Build Coastguard Worker }
358*d9f75844SAndroid Build Coastguard Worker 
AddSender(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender)359*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::AddSender(
360*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) {
361*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
362*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!stopped_);
363*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!unified_plan_);
364*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(sender);
365*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(media_type(), sender->media_type());
366*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!absl::c_linear_search(senders_, sender));
367*d9f75844SAndroid Build Coastguard Worker   if (media_type() == cricket::MEDIA_TYPE_VIDEO) {
368*d9f75844SAndroid Build Coastguard Worker     std::vector<cricket::VideoCodec> send_codecs =
369*d9f75844SAndroid Build Coastguard Worker         media_engine()->video().send_codecs(false);
370*d9f75844SAndroid Build Coastguard Worker     sender->internal()->SetVideoCodecPreferences(
371*d9f75844SAndroid Build Coastguard Worker         codec_preferences_.empty()
372*d9f75844SAndroid Build Coastguard Worker             ? send_codecs
373*d9f75844SAndroid Build Coastguard Worker             : MatchCodecPreferences(codec_preferences_, send_codecs));
374*d9f75844SAndroid Build Coastguard Worker   }
375*d9f75844SAndroid Build Coastguard Worker   senders_.push_back(sender);
376*d9f75844SAndroid Build Coastguard Worker }
377*d9f75844SAndroid Build Coastguard Worker 
RemoveSender(RtpSenderInterface * sender)378*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) {
379*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!unified_plan_);
380*d9f75844SAndroid Build Coastguard Worker   if (sender) {
381*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(media_type(), sender->media_type());
382*d9f75844SAndroid Build Coastguard Worker   }
383*d9f75844SAndroid Build Coastguard Worker   auto it = absl::c_find(senders_, sender);
384*d9f75844SAndroid Build Coastguard Worker   if (it == senders_.end()) {
385*d9f75844SAndroid Build Coastguard Worker     return false;
386*d9f75844SAndroid Build Coastguard Worker   }
387*d9f75844SAndroid Build Coastguard Worker   (*it)->internal()->Stop();
388*d9f75844SAndroid Build Coastguard Worker   senders_.erase(it);
389*d9f75844SAndroid Build Coastguard Worker   return true;
390*d9f75844SAndroid Build Coastguard Worker }
391*d9f75844SAndroid Build Coastguard Worker 
AddReceiver(rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver)392*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::AddReceiver(
393*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
394*d9f75844SAndroid Build Coastguard Worker         receiver) {
395*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
396*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!stopped_);
397*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!unified_plan_);
398*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(receiver);
399*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(media_type(), receiver->media_type());
400*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!absl::c_linear_search(receivers_, receiver));
401*d9f75844SAndroid Build Coastguard Worker   receivers_.push_back(receiver);
402*d9f75844SAndroid Build Coastguard Worker }
403*d9f75844SAndroid Build Coastguard Worker 
RemoveReceiver(RtpReceiverInterface * receiver)404*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) {
405*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
406*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!unified_plan_);
407*d9f75844SAndroid Build Coastguard Worker   if (receiver) {
408*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(media_type(), receiver->media_type());
409*d9f75844SAndroid Build Coastguard Worker   }
410*d9f75844SAndroid Build Coastguard Worker   auto it = absl::c_find(receivers_, receiver);
411*d9f75844SAndroid Build Coastguard Worker   if (it == receivers_.end()) {
412*d9f75844SAndroid Build Coastguard Worker     return false;
413*d9f75844SAndroid Build Coastguard Worker   }
414*d9f75844SAndroid Build Coastguard Worker 
415*d9f75844SAndroid Build Coastguard Worker   (*it)->internal()->Stop();
416*d9f75844SAndroid Build Coastguard Worker   context()->worker_thread()->BlockingCall([&]() {
417*d9f75844SAndroid Build Coastguard Worker     // `Stop()` will clear the receiver's pointer to the media channel.
418*d9f75844SAndroid Build Coastguard Worker     (*it)->internal()->SetMediaChannel(nullptr);
419*d9f75844SAndroid Build Coastguard Worker   });
420*d9f75844SAndroid Build Coastguard Worker 
421*d9f75844SAndroid Build Coastguard Worker   receivers_.erase(it);
422*d9f75844SAndroid Build Coastguard Worker   return true;
423*d9f75844SAndroid Build Coastguard Worker }
424*d9f75844SAndroid Build Coastguard Worker 
sender_internal() const425*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const {
426*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(unified_plan_);
427*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_EQ(1u, senders_.size());
428*d9f75844SAndroid Build Coastguard Worker   return rtc::scoped_refptr<RtpSenderInternal>(senders_[0]->internal());
429*d9f75844SAndroid Build Coastguard Worker }
430*d9f75844SAndroid Build Coastguard Worker 
receiver_internal() const431*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal()
432*d9f75844SAndroid Build Coastguard Worker     const {
433*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(unified_plan_);
434*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_EQ(1u, receivers_.size());
435*d9f75844SAndroid Build Coastguard Worker   return rtc::scoped_refptr<RtpReceiverInternal>(receivers_[0]->internal());
436*d9f75844SAndroid Build Coastguard Worker }
437*d9f75844SAndroid Build Coastguard Worker 
media_type() const438*d9f75844SAndroid Build Coastguard Worker cricket::MediaType RtpTransceiver::media_type() const {
439*d9f75844SAndroid Build Coastguard Worker   return media_type_;
440*d9f75844SAndroid Build Coastguard Worker }
441*d9f75844SAndroid Build Coastguard Worker 
mid() const442*d9f75844SAndroid Build Coastguard Worker absl::optional<std::string> RtpTransceiver::mid() const {
443*d9f75844SAndroid Build Coastguard Worker   return mid_;
444*d9f75844SAndroid Build Coastguard Worker }
445*d9f75844SAndroid Build Coastguard Worker 
OnFirstPacketReceived()446*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::OnFirstPacketReceived() {
447*d9f75844SAndroid Build Coastguard Worker   for (const auto& receiver : receivers_) {
448*d9f75844SAndroid Build Coastguard Worker     receiver->internal()->NotifyFirstPacketReceived();
449*d9f75844SAndroid Build Coastguard Worker   }
450*d9f75844SAndroid Build Coastguard Worker }
451*d9f75844SAndroid Build Coastguard Worker 
sender() const452*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const {
453*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(unified_plan_);
454*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_EQ(1u, senders_.size());
455*d9f75844SAndroid Build Coastguard Worker   return senders_[0];
456*d9f75844SAndroid Build Coastguard Worker }
457*d9f75844SAndroid Build Coastguard Worker 
receiver() const458*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const {
459*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(unified_plan_);
460*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK_EQ(1u, receivers_.size());
461*d9f75844SAndroid Build Coastguard Worker   return receivers_[0];
462*d9f75844SAndroid Build Coastguard Worker }
463*d9f75844SAndroid Build Coastguard Worker 
set_current_direction(RtpTransceiverDirection direction)464*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) {
465*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>")
466*d9f75844SAndroid Build Coastguard Worker                    << ") current direction from "
467*d9f75844SAndroid Build Coastguard Worker                    << (current_direction_ ? RtpTransceiverDirectionToString(
468*d9f75844SAndroid Build Coastguard Worker                                                 *current_direction_)
469*d9f75844SAndroid Build Coastguard Worker                                           : "<not set>")
470*d9f75844SAndroid Build Coastguard Worker                    << " to " << RtpTransceiverDirectionToString(direction)
471*d9f75844SAndroid Build Coastguard Worker                    << ".";
472*d9f75844SAndroid Build Coastguard Worker   current_direction_ = direction;
473*d9f75844SAndroid Build Coastguard Worker   if (RtpTransceiverDirectionHasSend(*current_direction_)) {
474*d9f75844SAndroid Build Coastguard Worker     has_ever_been_used_to_send_ = true;
475*d9f75844SAndroid Build Coastguard Worker   }
476*d9f75844SAndroid Build Coastguard Worker }
477*d9f75844SAndroid Build Coastguard Worker 
set_fired_direction(absl::optional<RtpTransceiverDirection> direction)478*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::set_fired_direction(
479*d9f75844SAndroid Build Coastguard Worker     absl::optional<RtpTransceiverDirection> direction) {
480*d9f75844SAndroid Build Coastguard Worker   fired_direction_ = direction;
481*d9f75844SAndroid Build Coastguard Worker }
482*d9f75844SAndroid Build Coastguard Worker 
stopped() const483*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::stopped() const {
484*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
485*d9f75844SAndroid Build Coastguard Worker   return stopped_;
486*d9f75844SAndroid Build Coastguard Worker }
487*d9f75844SAndroid Build Coastguard Worker 
stopping() const488*d9f75844SAndroid Build Coastguard Worker bool RtpTransceiver::stopping() const {
489*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
490*d9f75844SAndroid Build Coastguard Worker   return stopping_;
491*d9f75844SAndroid Build Coastguard Worker }
492*d9f75844SAndroid Build Coastguard Worker 
direction() const493*d9f75844SAndroid Build Coastguard Worker RtpTransceiverDirection RtpTransceiver::direction() const {
494*d9f75844SAndroid Build Coastguard Worker   if (unified_plan_ && stopping())
495*d9f75844SAndroid Build Coastguard Worker     return webrtc::RtpTransceiverDirection::kStopped;
496*d9f75844SAndroid Build Coastguard Worker 
497*d9f75844SAndroid Build Coastguard Worker   return direction_;
498*d9f75844SAndroid Build Coastguard Worker }
499*d9f75844SAndroid Build Coastguard Worker 
SetDirectionWithError(RtpTransceiverDirection new_direction)500*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::SetDirectionWithError(
501*d9f75844SAndroid Build Coastguard Worker     RtpTransceiverDirection new_direction) {
502*d9f75844SAndroid Build Coastguard Worker   if (unified_plan_ && stopping()) {
503*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
504*d9f75844SAndroid Build Coastguard Worker                          "Cannot set direction on a stopping transceiver.");
505*d9f75844SAndroid Build Coastguard Worker   }
506*d9f75844SAndroid Build Coastguard Worker   if (new_direction == direction_)
507*d9f75844SAndroid Build Coastguard Worker     return RTCError::OK();
508*d9f75844SAndroid Build Coastguard Worker 
509*d9f75844SAndroid Build Coastguard Worker   if (new_direction == RtpTransceiverDirection::kStopped) {
510*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
511*d9f75844SAndroid Build Coastguard Worker                          "The set direction 'stopped' is invalid.");
512*d9f75844SAndroid Build Coastguard Worker   }
513*d9f75844SAndroid Build Coastguard Worker 
514*d9f75844SAndroid Build Coastguard Worker   direction_ = new_direction;
515*d9f75844SAndroid Build Coastguard Worker   on_negotiation_needed_();
516*d9f75844SAndroid Build Coastguard Worker 
517*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
518*d9f75844SAndroid Build Coastguard Worker }
519*d9f75844SAndroid Build Coastguard Worker 
current_direction() const520*d9f75844SAndroid Build Coastguard Worker absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction()
521*d9f75844SAndroid Build Coastguard Worker     const {
522*d9f75844SAndroid Build Coastguard Worker   if (unified_plan_ && stopped())
523*d9f75844SAndroid Build Coastguard Worker     return webrtc::RtpTransceiverDirection::kStopped;
524*d9f75844SAndroid Build Coastguard Worker 
525*d9f75844SAndroid Build Coastguard Worker   return current_direction_;
526*d9f75844SAndroid Build Coastguard Worker }
527*d9f75844SAndroid Build Coastguard Worker 
fired_direction() const528*d9f75844SAndroid Build Coastguard Worker absl::optional<RtpTransceiverDirection> RtpTransceiver::fired_direction()
529*d9f75844SAndroid Build Coastguard Worker     const {
530*d9f75844SAndroid Build Coastguard Worker   return fired_direction_;
531*d9f75844SAndroid Build Coastguard Worker }
532*d9f75844SAndroid Build Coastguard Worker 
StopSendingAndReceiving()533*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::StopSendingAndReceiving() {
534*d9f75844SAndroid Build Coastguard Worker   // 1. Let sender be transceiver.[[Sender]].
535*d9f75844SAndroid Build Coastguard Worker   // 2. Let receiver be transceiver.[[Receiver]].
536*d9f75844SAndroid Build Coastguard Worker   //
537*d9f75844SAndroid Build Coastguard Worker   // 3. Stop sending media with sender.
538*d9f75844SAndroid Build Coastguard Worker   //
539*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
540*d9f75844SAndroid Build Coastguard Worker 
541*d9f75844SAndroid Build Coastguard Worker   // 4. Send an RTCP BYE for each RTP stream that was being sent by sender, as
542*d9f75844SAndroid Build Coastguard Worker   // specified in [RFC3550].
543*d9f75844SAndroid Build Coastguard Worker   for (const auto& sender : senders_)
544*d9f75844SAndroid Build Coastguard Worker     sender->internal()->Stop();
545*d9f75844SAndroid Build Coastguard Worker 
546*d9f75844SAndroid Build Coastguard Worker   // Signal to receiver sources that we're stopping.
547*d9f75844SAndroid Build Coastguard Worker   for (const auto& receiver : receivers_)
548*d9f75844SAndroid Build Coastguard Worker     receiver->internal()->Stop();
549*d9f75844SAndroid Build Coastguard Worker 
550*d9f75844SAndroid Build Coastguard Worker   context()->worker_thread()->BlockingCall([&]() {
551*d9f75844SAndroid Build Coastguard Worker     // 5 Stop receiving media with receiver.
552*d9f75844SAndroid Build Coastguard Worker     for (const auto& receiver : receivers_)
553*d9f75844SAndroid Build Coastguard Worker       receiver->internal()->SetMediaChannel(nullptr);
554*d9f75844SAndroid Build Coastguard Worker   });
555*d9f75844SAndroid Build Coastguard Worker 
556*d9f75844SAndroid Build Coastguard Worker   stopping_ = true;
557*d9f75844SAndroid Build Coastguard Worker   direction_ = webrtc::RtpTransceiverDirection::kInactive;
558*d9f75844SAndroid Build Coastguard Worker }
559*d9f75844SAndroid Build Coastguard Worker 
StopStandard()560*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::StopStandard() {
561*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
562*d9f75844SAndroid Build Coastguard Worker   // If we're on Plan B, do what Stop() used to do there.
563*d9f75844SAndroid Build Coastguard Worker   if (!unified_plan_) {
564*d9f75844SAndroid Build Coastguard Worker     StopInternal();
565*d9f75844SAndroid Build Coastguard Worker     return RTCError::OK();
566*d9f75844SAndroid Build Coastguard Worker   }
567*d9f75844SAndroid Build Coastguard Worker   // 1. Let transceiver be the RTCRtpTransceiver object on which the method is
568*d9f75844SAndroid Build Coastguard Worker   // invoked.
569*d9f75844SAndroid Build Coastguard Worker   //
570*d9f75844SAndroid Build Coastguard Worker   // 2. Let connection be the RTCPeerConnection object associated with
571*d9f75844SAndroid Build Coastguard Worker   // transceiver.
572*d9f75844SAndroid Build Coastguard Worker   //
573*d9f75844SAndroid Build Coastguard Worker   // 3. If connection.[[IsClosed]] is true, throw an InvalidStateError.
574*d9f75844SAndroid Build Coastguard Worker   if (is_pc_closed_) {
575*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
576*d9f75844SAndroid Build Coastguard Worker                          "PeerConnection is closed.");
577*d9f75844SAndroid Build Coastguard Worker   }
578*d9f75844SAndroid Build Coastguard Worker 
579*d9f75844SAndroid Build Coastguard Worker   // 4. If transceiver.[[Stopping]] is true, abort these steps.
580*d9f75844SAndroid Build Coastguard Worker   if (stopping_)
581*d9f75844SAndroid Build Coastguard Worker     return RTCError::OK();
582*d9f75844SAndroid Build Coastguard Worker 
583*d9f75844SAndroid Build Coastguard Worker   // 5. Stop sending and receiving given transceiver, and update the
584*d9f75844SAndroid Build Coastguard Worker   // negotiation-needed flag for connection.
585*d9f75844SAndroid Build Coastguard Worker   StopSendingAndReceiving();
586*d9f75844SAndroid Build Coastguard Worker   on_negotiation_needed_();
587*d9f75844SAndroid Build Coastguard Worker 
588*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
589*d9f75844SAndroid Build Coastguard Worker }
590*d9f75844SAndroid Build Coastguard Worker 
StopInternal()591*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::StopInternal() {
592*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
593*d9f75844SAndroid Build Coastguard Worker   StopTransceiverProcedure();
594*d9f75844SAndroid Build Coastguard Worker }
595*d9f75844SAndroid Build Coastguard Worker 
StopTransceiverProcedure()596*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::StopTransceiverProcedure() {
597*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
598*d9f75844SAndroid Build Coastguard Worker   // As specified in the "Stop the RTCRtpTransceiver" procedure
599*d9f75844SAndroid Build Coastguard Worker   // 1. If transceiver.[[Stopping]] is false, stop sending and receiving given
600*d9f75844SAndroid Build Coastguard Worker   // transceiver.
601*d9f75844SAndroid Build Coastguard Worker   if (!stopping_)
602*d9f75844SAndroid Build Coastguard Worker     StopSendingAndReceiving();
603*d9f75844SAndroid Build Coastguard Worker 
604*d9f75844SAndroid Build Coastguard Worker   // 2. Set transceiver.[[Stopped]] to true.
605*d9f75844SAndroid Build Coastguard Worker   stopped_ = true;
606*d9f75844SAndroid Build Coastguard Worker 
607*d9f75844SAndroid Build Coastguard Worker   // Signal the updated change to the senders.
608*d9f75844SAndroid Build Coastguard Worker   for (const auto& sender : senders_)
609*d9f75844SAndroid Build Coastguard Worker     sender->internal()->SetTransceiverAsStopped();
610*d9f75844SAndroid Build Coastguard Worker 
611*d9f75844SAndroid Build Coastguard Worker   // 3. Set transceiver.[[Receptive]] to false.
612*d9f75844SAndroid Build Coastguard Worker   // 4. Set transceiver.[[CurrentDirection]] to null.
613*d9f75844SAndroid Build Coastguard Worker   current_direction_ = absl::nullopt;
614*d9f75844SAndroid Build Coastguard Worker }
615*d9f75844SAndroid Build Coastguard Worker 
SetCodecPreferences(rtc::ArrayView<RtpCodecCapability> codec_capabilities)616*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::SetCodecPreferences(
617*d9f75844SAndroid Build Coastguard Worker     rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
618*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(unified_plan_);
619*d9f75844SAndroid Build Coastguard Worker   // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
620*d9f75844SAndroid Build Coastguard Worker   // to codecs and abort these steps.
621*d9f75844SAndroid Build Coastguard Worker   if (codec_capabilities.empty()) {
622*d9f75844SAndroid Build Coastguard Worker     codec_preferences_.clear();
623*d9f75844SAndroid Build Coastguard Worker     if (media_type() == cricket::MEDIA_TYPE_VIDEO)
624*d9f75844SAndroid Build Coastguard Worker       senders_.front()->internal()->SetVideoCodecPreferences(
625*d9f75844SAndroid Build Coastguard Worker           media_engine()->video().send_codecs(false));
626*d9f75844SAndroid Build Coastguard Worker     return RTCError::OK();
627*d9f75844SAndroid Build Coastguard Worker   }
628*d9f75844SAndroid Build Coastguard Worker 
629*d9f75844SAndroid Build Coastguard Worker   // 4. Remove any duplicate values in codecs.
630*d9f75844SAndroid Build Coastguard Worker   std::vector<RtpCodecCapability> codecs;
631*d9f75844SAndroid Build Coastguard Worker   absl::c_remove_copy_if(codec_capabilities, std::back_inserter(codecs),
632*d9f75844SAndroid Build Coastguard Worker                          [&codecs](const RtpCodecCapability& codec) {
633*d9f75844SAndroid Build Coastguard Worker                            return absl::c_linear_search(codecs, codec);
634*d9f75844SAndroid Build Coastguard Worker                          });
635*d9f75844SAndroid Build Coastguard Worker 
636*d9f75844SAndroid Build Coastguard Worker   // 6. to 8.
637*d9f75844SAndroid Build Coastguard Worker   RTCError result;
638*d9f75844SAndroid Build Coastguard Worker   if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
639*d9f75844SAndroid Build Coastguard Worker     std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
640*d9f75844SAndroid Build Coastguard Worker     send_codecs = media_engine()->voice().send_codecs();
641*d9f75844SAndroid Build Coastguard Worker     recv_codecs = media_engine()->voice().recv_codecs();
642*d9f75844SAndroid Build Coastguard Worker     result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
643*d9f75844SAndroid Build Coastguard Worker   } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
644*d9f75844SAndroid Build Coastguard Worker     std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
645*d9f75844SAndroid Build Coastguard Worker     send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
646*d9f75844SAndroid Build Coastguard Worker     recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
647*d9f75844SAndroid Build Coastguard Worker     result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
648*d9f75844SAndroid Build Coastguard Worker 
649*d9f75844SAndroid Build Coastguard Worker     if (result.ok()) {
650*d9f75844SAndroid Build Coastguard Worker       senders_.front()->internal()->SetVideoCodecPreferences(
651*d9f75844SAndroid Build Coastguard Worker           MatchCodecPreferences(codecs, send_codecs));
652*d9f75844SAndroid Build Coastguard Worker     }
653*d9f75844SAndroid Build Coastguard Worker   }
654*d9f75844SAndroid Build Coastguard Worker 
655*d9f75844SAndroid Build Coastguard Worker   if (result.ok()) {
656*d9f75844SAndroid Build Coastguard Worker     codec_preferences_ = codecs;
657*d9f75844SAndroid Build Coastguard Worker   }
658*d9f75844SAndroid Build Coastguard Worker 
659*d9f75844SAndroid Build Coastguard Worker   return result;
660*d9f75844SAndroid Build Coastguard Worker }
661*d9f75844SAndroid Build Coastguard Worker 
662*d9f75844SAndroid Build Coastguard Worker std::vector<RtpHeaderExtensionCapability>
HeaderExtensionsToOffer() const663*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::HeaderExtensionsToOffer() const {
664*d9f75844SAndroid Build Coastguard Worker   return header_extensions_to_offer_;
665*d9f75844SAndroid Build Coastguard Worker }
666*d9f75844SAndroid Build Coastguard Worker 
667*d9f75844SAndroid Build Coastguard Worker std::vector<RtpHeaderExtensionCapability>
HeaderExtensionsNegotiated() const668*d9f75844SAndroid Build Coastguard Worker RtpTransceiver::HeaderExtensionsNegotiated() const {
669*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
670*d9f75844SAndroid Build Coastguard Worker   std::vector<RtpHeaderExtensionCapability> result;
671*d9f75844SAndroid Build Coastguard Worker   for (const auto& ext : negotiated_header_extensions_) {
672*d9f75844SAndroid Build Coastguard Worker     result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
673*d9f75844SAndroid Build Coastguard Worker   }
674*d9f75844SAndroid Build Coastguard Worker   return result;
675*d9f75844SAndroid Build Coastguard Worker }
676*d9f75844SAndroid Build Coastguard Worker 
SetOfferedRtpHeaderExtensions(rtc::ArrayView<const RtpHeaderExtensionCapability> header_extensions_to_offer)677*d9f75844SAndroid Build Coastguard Worker RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
678*d9f75844SAndroid Build Coastguard Worker     rtc::ArrayView<const RtpHeaderExtensionCapability>
679*d9f75844SAndroid Build Coastguard Worker         header_extensions_to_offer) {
680*d9f75844SAndroid Build Coastguard Worker   for (const auto& entry : header_extensions_to_offer) {
681*d9f75844SAndroid Build Coastguard Worker     // Handle unsupported requests for mandatory extensions as per
682*d9f75844SAndroid Build Coastguard Worker     // https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface.
683*d9f75844SAndroid Build Coastguard Worker     // Note:
684*d9f75844SAndroid Build Coastguard Worker     // - We do not handle setOfferedRtpHeaderExtensions algorithm step 2.1,
685*d9f75844SAndroid Build Coastguard Worker     //   this has to be checked on a higher level. We naturally error out
686*d9f75844SAndroid Build Coastguard Worker     //   in the handling of Step 2.2 if an unset URI is encountered.
687*d9f75844SAndroid Build Coastguard Worker 
688*d9f75844SAndroid Build Coastguard Worker     // Step 2.2.
689*d9f75844SAndroid Build Coastguard Worker     // Handle unknown extensions.
690*d9f75844SAndroid Build Coastguard Worker     auto it = std::find_if(
691*d9f75844SAndroid Build Coastguard Worker         header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
692*d9f75844SAndroid Build Coastguard Worker         [&entry](const auto& offered) { return entry.uri == offered.uri; });
693*d9f75844SAndroid Build Coastguard Worker     if (it == header_extensions_to_offer_.end()) {
694*d9f75844SAndroid Build Coastguard Worker       return RTCError(RTCErrorType::UNSUPPORTED_PARAMETER,
695*d9f75844SAndroid Build Coastguard Worker                       "Attempted to modify an unoffered extension.");
696*d9f75844SAndroid Build Coastguard Worker     }
697*d9f75844SAndroid Build Coastguard Worker 
698*d9f75844SAndroid Build Coastguard Worker     // Step 2.4-2.5.
699*d9f75844SAndroid Build Coastguard Worker     // - Use of the transceiver interface indicates unified plan is in effect,
700*d9f75844SAndroid Build Coastguard Worker     //   hence the MID extension needs to be enabled.
701*d9f75844SAndroid Build Coastguard Worker     // - Also handle the mandatory video orientation extensions.
702*d9f75844SAndroid Build Coastguard Worker     if ((entry.uri == RtpExtension::kMidUri ||
703*d9f75844SAndroid Build Coastguard Worker          entry.uri == RtpExtension::kVideoRotationUri) &&
704*d9f75844SAndroid Build Coastguard Worker         entry.direction != RtpTransceiverDirection::kSendRecv) {
705*d9f75844SAndroid Build Coastguard Worker       return RTCError(RTCErrorType::INVALID_MODIFICATION,
706*d9f75844SAndroid Build Coastguard Worker                       "Attempted to stop a mandatory extension.");
707*d9f75844SAndroid Build Coastguard Worker     }
708*d9f75844SAndroid Build Coastguard Worker   }
709*d9f75844SAndroid Build Coastguard Worker 
710*d9f75844SAndroid Build Coastguard Worker   // Apply mutation after error checking.
711*d9f75844SAndroid Build Coastguard Worker   for (const auto& entry : header_extensions_to_offer) {
712*d9f75844SAndroid Build Coastguard Worker     auto it = std::find_if(
713*d9f75844SAndroid Build Coastguard Worker         header_extensions_to_offer_.begin(), header_extensions_to_offer_.end(),
714*d9f75844SAndroid Build Coastguard Worker         [&entry](const auto& offered) { return entry.uri == offered.uri; });
715*d9f75844SAndroid Build Coastguard Worker     it->direction = entry.direction;
716*d9f75844SAndroid Build Coastguard Worker   }
717*d9f75844SAndroid Build Coastguard Worker 
718*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
719*d9f75844SAndroid Build Coastguard Worker }
720*d9f75844SAndroid Build Coastguard Worker 
OnNegotiationUpdate(SdpType sdp_type,const cricket::MediaContentDescription * content)721*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::OnNegotiationUpdate(
722*d9f75844SAndroid Build Coastguard Worker     SdpType sdp_type,
723*d9f75844SAndroid Build Coastguard Worker     const cricket::MediaContentDescription* content) {
724*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
725*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(content);
726*d9f75844SAndroid Build Coastguard Worker   if (sdp_type == SdpType::kAnswer)
727*d9f75844SAndroid Build Coastguard Worker     negotiated_header_extensions_ = content->rtp_header_extensions();
728*d9f75844SAndroid Build Coastguard Worker }
729*d9f75844SAndroid Build Coastguard Worker 
SetPeerConnectionClosed()730*d9f75844SAndroid Build Coastguard Worker void RtpTransceiver::SetPeerConnectionClosed() {
731*d9f75844SAndroid Build Coastguard Worker   is_pc_closed_ = true;
732*d9f75844SAndroid Build Coastguard Worker }
733*d9f75844SAndroid Build Coastguard Worker 
734*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
735