1 /*
2 * Copyright 2020 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_transmission_manager.h"
12
13 #include <type_traits>
14 #include <utility>
15
16 #include "absl/types/optional.h"
17 #include "api/peer_connection_interface.h"
18 #include "api/rtp_transceiver_direction.h"
19 #include "pc/audio_rtp_receiver.h"
20 #include "pc/channel_interface.h"
21 #include "pc/legacy_stats_collector_interface.h"
22 #include "pc/video_rtp_receiver.h"
23 #include "rtc_base/checks.h"
24 #include "rtc_base/helpers.h"
25 #include "rtc_base/logging.h"
26
27 namespace webrtc {
28
29 namespace {
30
31 static const char kDefaultAudioSenderId[] = "defaulta0";
32 static const char kDefaultVideoSenderId[] = "defaultv0";
33
34 } // namespace
35
RtpTransmissionManager(bool is_unified_plan,ConnectionContext * context,UsagePattern * usage_pattern,PeerConnectionObserver * observer,LegacyStatsCollectorInterface * legacy_stats,std::function<void ()> on_negotiation_needed)36 RtpTransmissionManager::RtpTransmissionManager(
37 bool is_unified_plan,
38 ConnectionContext* context,
39 UsagePattern* usage_pattern,
40 PeerConnectionObserver* observer,
41 LegacyStatsCollectorInterface* legacy_stats,
42 std::function<void()> on_negotiation_needed)
43 : is_unified_plan_(is_unified_plan),
44 context_(context),
45 usage_pattern_(usage_pattern),
46 observer_(observer),
47 legacy_stats_(legacy_stats),
48 on_negotiation_needed_(on_negotiation_needed),
49 weak_ptr_factory_(this) {}
50
Close()51 void RtpTransmissionManager::Close() {
52 closed_ = true;
53 observer_ = nullptr;
54 }
55
56 // Implementation of SetStreamsObserver
OnSetStreams()57 void RtpTransmissionManager::OnSetStreams() {
58 RTC_DCHECK_RUN_ON(signaling_thread());
59 if (IsUnifiedPlan())
60 OnNegotiationNeeded();
61 }
62
63 // Function to call back to the PeerConnection when negotiation is needed
OnNegotiationNeeded()64 void RtpTransmissionManager::OnNegotiationNeeded() {
65 on_negotiation_needed_();
66 }
67
68 // Function that returns the currently valid observer
Observer() const69 PeerConnectionObserver* RtpTransmissionManager::Observer() const {
70 RTC_DCHECK(!closed_);
71 RTC_DCHECK(observer_);
72 return observer_;
73 }
74
voice_media_channel() const75 cricket::VoiceMediaChannel* RtpTransmissionManager::voice_media_channel()
76 const {
77 RTC_DCHECK_RUN_ON(signaling_thread());
78 RTC_DCHECK(!IsUnifiedPlan());
79 auto* voice_channel = GetAudioTransceiver()->internal()->channel();
80 if (voice_channel) {
81 return voice_channel->voice_media_channel();
82 } else {
83 return nullptr;
84 }
85 }
86
video_media_channel() const87 cricket::VideoMediaChannel* RtpTransmissionManager::video_media_channel()
88 const {
89 RTC_DCHECK_RUN_ON(signaling_thread());
90 RTC_DCHECK(!IsUnifiedPlan());
91 auto* video_channel = GetVideoTransceiver()->internal()->channel();
92 if (video_channel) {
93 return video_channel->video_media_channel();
94 } else {
95 return nullptr;
96 }
97 }
98
99 RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
AddTrack(rtc::scoped_refptr<MediaStreamTrackInterface> track,const std::vector<std::string> & stream_ids,const std::vector<RtpEncodingParameters> * init_send_encodings)100 RtpTransmissionManager::AddTrack(
101 rtc::scoped_refptr<MediaStreamTrackInterface> track,
102 const std::vector<std::string>& stream_ids,
103 const std::vector<RtpEncodingParameters>* init_send_encodings) {
104 RTC_DCHECK_RUN_ON(signaling_thread());
105
106 return (IsUnifiedPlan()
107 ? AddTrackUnifiedPlan(track, stream_ids, init_send_encodings)
108 : AddTrackPlanB(track, stream_ids, init_send_encodings));
109 }
110
111 RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
AddTrackPlanB(rtc::scoped_refptr<MediaStreamTrackInterface> track,const std::vector<std::string> & stream_ids,const std::vector<RtpEncodingParameters> * init_send_encodings)112 RtpTransmissionManager::AddTrackPlanB(
113 rtc::scoped_refptr<MediaStreamTrackInterface> track,
114 const std::vector<std::string>& stream_ids,
115 const std::vector<RtpEncodingParameters>* init_send_encodings) {
116 RTC_DCHECK_RUN_ON(signaling_thread());
117 if (stream_ids.size() > 1u) {
118 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
119 "AddTrack with more than one stream is not "
120 "supported with Plan B semantics.");
121 }
122 std::vector<std::string> adjusted_stream_ids = stream_ids;
123 if (adjusted_stream_ids.empty()) {
124 adjusted_stream_ids.push_back(rtc::CreateRandomUuid());
125 }
126 cricket::MediaType media_type =
127 (track->kind() == MediaStreamTrackInterface::kAudioKind
128 ? cricket::MEDIA_TYPE_AUDIO
129 : cricket::MEDIA_TYPE_VIDEO);
130 auto new_sender =
131 CreateSender(media_type, track->id(), track, adjusted_stream_ids,
132 init_send_encodings ? *init_send_encodings
133 : std::vector<RtpEncodingParameters>());
134 if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
135 new_sender->internal()->SetMediaChannel(voice_media_channel());
136 GetAudioTransceiver()->internal()->AddSender(new_sender);
137 const RtpSenderInfo* sender_info =
138 FindSenderInfo(local_audio_sender_infos_,
139 new_sender->internal()->stream_ids()[0], track->id());
140 if (sender_info) {
141 new_sender->internal()->SetSsrc(sender_info->first_ssrc);
142 }
143 } else {
144 RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
145 new_sender->internal()->SetMediaChannel(video_media_channel());
146 GetVideoTransceiver()->internal()->AddSender(new_sender);
147 const RtpSenderInfo* sender_info =
148 FindSenderInfo(local_video_sender_infos_,
149 new_sender->internal()->stream_ids()[0], track->id());
150 if (sender_info) {
151 new_sender->internal()->SetSsrc(sender_info->first_ssrc);
152 }
153 }
154 return rtc::scoped_refptr<RtpSenderInterface>(new_sender);
155 }
156
157 RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
AddTrackUnifiedPlan(rtc::scoped_refptr<MediaStreamTrackInterface> track,const std::vector<std::string> & stream_ids,const std::vector<RtpEncodingParameters> * init_send_encodings)158 RtpTransmissionManager::AddTrackUnifiedPlan(
159 rtc::scoped_refptr<MediaStreamTrackInterface> track,
160 const std::vector<std::string>& stream_ids,
161 const std::vector<RtpEncodingParameters>* init_send_encodings) {
162 auto transceiver =
163 FindFirstTransceiverForAddedTrack(track, init_send_encodings);
164 if (transceiver) {
165 RTC_LOG(LS_INFO) << "Reusing an existing "
166 << cricket::MediaTypeToString(transceiver->media_type())
167 << " transceiver for AddTrack.";
168 if (transceiver->stopping()) {
169 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
170 "The existing transceiver is stopping.");
171 }
172
173 if (transceiver->direction() == RtpTransceiverDirection::kRecvOnly) {
174 transceiver->internal()->set_direction(
175 RtpTransceiverDirection::kSendRecv);
176 } else if (transceiver->direction() == RtpTransceiverDirection::kInactive) {
177 transceiver->internal()->set_direction(
178 RtpTransceiverDirection::kSendOnly);
179 }
180 transceiver->sender()->SetTrack(track.get());
181 transceiver->internal()->sender_internal()->set_stream_ids(stream_ids);
182 transceiver->internal()->set_reused_for_addtrack(true);
183 } else {
184 cricket::MediaType media_type =
185 (track->kind() == MediaStreamTrackInterface::kAudioKind
186 ? cricket::MEDIA_TYPE_AUDIO
187 : cricket::MEDIA_TYPE_VIDEO);
188 RTC_LOG(LS_INFO) << "Adding " << cricket::MediaTypeToString(media_type)
189 << " transceiver in response to a call to AddTrack.";
190 std::string sender_id = track->id();
191 // Avoid creating a sender with an existing ID by generating a random ID.
192 // This can happen if this is the second time AddTrack has created a sender
193 // for this track.
194 if (FindSenderById(sender_id)) {
195 sender_id = rtc::CreateRandomUuid();
196 }
197 auto sender = CreateSender(media_type, sender_id, track, stream_ids,
198 init_send_encodings
199 ? *init_send_encodings
200 : std::vector<RtpEncodingParameters>());
201 auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid());
202 transceiver = CreateAndAddTransceiver(sender, receiver);
203 transceiver->internal()->set_created_by_addtrack(true);
204 transceiver->internal()->set_direction(RtpTransceiverDirection::kSendRecv);
205 }
206 return transceiver->sender();
207 }
208
209 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
CreateSender(cricket::MediaType media_type,const std::string & id,rtc::scoped_refptr<MediaStreamTrackInterface> track,const std::vector<std::string> & stream_ids,const std::vector<RtpEncodingParameters> & send_encodings)210 RtpTransmissionManager::CreateSender(
211 cricket::MediaType media_type,
212 const std::string& id,
213 rtc::scoped_refptr<MediaStreamTrackInterface> track,
214 const std::vector<std::string>& stream_ids,
215 const std::vector<RtpEncodingParameters>& send_encodings) {
216 RTC_DCHECK_RUN_ON(signaling_thread());
217 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender;
218 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
219 RTC_DCHECK(!track ||
220 (track->kind() == MediaStreamTrackInterface::kAudioKind));
221 sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
222 signaling_thread(),
223 AudioRtpSender::Create(worker_thread(), id, legacy_stats_, this));
224 NoteUsageEvent(UsageEvent::AUDIO_ADDED);
225 } else {
226 RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
227 RTC_DCHECK(!track ||
228 (track->kind() == MediaStreamTrackInterface::kVideoKind));
229 sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
230 signaling_thread(), VideoRtpSender::Create(worker_thread(), id, this));
231 NoteUsageEvent(UsageEvent::VIDEO_ADDED);
232 }
233 bool set_track_succeeded = sender->SetTrack(track.get());
234 RTC_DCHECK(set_track_succeeded);
235 sender->internal()->set_stream_ids(stream_ids);
236 sender->internal()->set_init_send_encodings(send_encodings);
237 return sender;
238 }
239
240 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
CreateReceiver(cricket::MediaType media_type,const std::string & receiver_id)241 RtpTransmissionManager::CreateReceiver(cricket::MediaType media_type,
242 const std::string& receiver_id) {
243 RTC_DCHECK_RUN_ON(signaling_thread());
244 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
245 receiver;
246 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
247 receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
248 signaling_thread(), worker_thread(),
249 rtc::make_ref_counted<AudioRtpReceiver>(worker_thread(), receiver_id,
250 std::vector<std::string>({}),
251 IsUnifiedPlan()));
252 NoteUsageEvent(UsageEvent::AUDIO_ADDED);
253 } else {
254 RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
255 receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
256 signaling_thread(), worker_thread(),
257 rtc::make_ref_counted<VideoRtpReceiver>(worker_thread(), receiver_id,
258 std::vector<std::string>({})));
259 NoteUsageEvent(UsageEvent::VIDEO_ADDED);
260 }
261 return receiver;
262 }
263
264 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
CreateAndAddTransceiver(rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> receiver)265 RtpTransmissionManager::CreateAndAddTransceiver(
266 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
267 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
268 receiver) {
269 RTC_DCHECK_RUN_ON(signaling_thread());
270 // Ensure that the new sender does not have an ID that is already in use by
271 // another sender.
272 // Allow receiver IDs to conflict since those come from remote SDP (which
273 // could be invalid, but should not cause a crash).
274 RTC_DCHECK(!FindSenderById(sender->id()));
275 auto transceiver = RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
276 signaling_thread(),
277 rtc::make_ref_counted<RtpTransceiver>(
278 sender, receiver, context_,
279 sender->media_type() == cricket::MEDIA_TYPE_AUDIO
280 ? media_engine()->voice().GetRtpHeaderExtensions()
281 : media_engine()->video().GetRtpHeaderExtensions(),
282 [this_weak_ptr = weak_ptr_factory_.GetWeakPtr()]() {
283 if (this_weak_ptr) {
284 this_weak_ptr->OnNegotiationNeeded();
285 }
286 }));
287 transceivers()->Add(transceiver);
288 return transceiver;
289 }
290
291 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
FindFirstTransceiverForAddedTrack(rtc::scoped_refptr<MediaStreamTrackInterface> track,const std::vector<RtpEncodingParameters> * init_send_encodings)292 RtpTransmissionManager::FindFirstTransceiverForAddedTrack(
293 rtc::scoped_refptr<MediaStreamTrackInterface> track,
294 const std::vector<RtpEncodingParameters>* init_send_encodings) {
295 RTC_DCHECK_RUN_ON(signaling_thread());
296 RTC_DCHECK(track);
297 if (init_send_encodings != nullptr) {
298 return nullptr;
299 }
300 for (auto transceiver : transceivers()->List()) {
301 if (!transceiver->sender()->track() &&
302 cricket::MediaTypeToString(transceiver->media_type()) ==
303 track->kind() &&
304 !transceiver->internal()->has_ever_been_used_to_send() &&
305 !transceiver->stopped()) {
306 return transceiver;
307 }
308 }
309 return nullptr;
310 }
311
312 std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
GetSendersInternal() const313 RtpTransmissionManager::GetSendersInternal() const {
314 RTC_DCHECK_RUN_ON(signaling_thread());
315 std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
316 all_senders;
317 for (const auto& transceiver : transceivers_.List()) {
318 if (IsUnifiedPlan() && transceiver->internal()->stopped())
319 continue;
320
321 auto senders = transceiver->internal()->senders();
322 all_senders.insert(all_senders.end(), senders.begin(), senders.end());
323 }
324 return all_senders;
325 }
326
327 std::vector<
328 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
GetReceiversInternal() const329 RtpTransmissionManager::GetReceiversInternal() const {
330 RTC_DCHECK_RUN_ON(signaling_thread());
331 std::vector<
332 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
333 all_receivers;
334 for (const auto& transceiver : transceivers_.List()) {
335 if (IsUnifiedPlan() && transceiver->internal()->stopped())
336 continue;
337
338 auto receivers = transceiver->internal()->receivers();
339 all_receivers.insert(all_receivers.end(), receivers.begin(),
340 receivers.end());
341 }
342 return all_receivers;
343 }
344
345 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
GetAudioTransceiver() const346 RtpTransmissionManager::GetAudioTransceiver() const {
347 RTC_DCHECK_RUN_ON(signaling_thread());
348 // This method only works with Plan B SDP, where there is a single
349 // audio/video transceiver.
350 RTC_DCHECK(!IsUnifiedPlan());
351 for (auto transceiver : transceivers_.List()) {
352 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
353 return transceiver;
354 }
355 }
356 RTC_DCHECK_NOTREACHED();
357 return nullptr;
358 }
359
360 rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
GetVideoTransceiver() const361 RtpTransmissionManager::GetVideoTransceiver() const {
362 RTC_DCHECK_RUN_ON(signaling_thread());
363 // This method only works with Plan B SDP, where there is a single
364 // audio/video transceiver.
365 RTC_DCHECK(!IsUnifiedPlan());
366 for (auto transceiver : transceivers_.List()) {
367 if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
368 return transceiver;
369 }
370 }
371 RTC_DCHECK_NOTREACHED();
372 return nullptr;
373 }
374
AddAudioTrack(AudioTrackInterface * track,MediaStreamInterface * stream)375 void RtpTransmissionManager::AddAudioTrack(AudioTrackInterface* track,
376 MediaStreamInterface* stream) {
377 RTC_DCHECK_RUN_ON(signaling_thread());
378 RTC_DCHECK(track);
379 RTC_DCHECK(stream);
380 auto sender = FindSenderForTrack(track);
381 if (sender) {
382 // We already have a sender for this track, so just change the stream_id
383 // so that it's correct in the next call to CreateOffer.
384 sender->internal()->set_stream_ids({stream->id()});
385 return;
386 }
387
388 // Normal case; we've never seen this track before.
389 auto new_sender = CreateSender(cricket::MEDIA_TYPE_AUDIO, track->id(),
390 rtc::scoped_refptr<AudioTrackInterface>(track),
391 {stream->id()}, {});
392 new_sender->internal()->SetMediaChannel(voice_media_channel());
393 GetAudioTransceiver()->internal()->AddSender(new_sender);
394 // If the sender has already been configured in SDP, we call SetSsrc,
395 // which will connect the sender to the underlying transport. This can
396 // occur if a local session description that contains the ID of the sender
397 // is set before AddStream is called. It can also occur if the local
398 // session description is not changed and RemoveStream is called, and
399 // later AddStream is called again with the same stream.
400 const RtpSenderInfo* sender_info =
401 FindSenderInfo(local_audio_sender_infos_, stream->id(), track->id());
402 if (sender_info) {
403 new_sender->internal()->SetSsrc(sender_info->first_ssrc);
404 }
405 }
406
407 // TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
408 // indefinitely, when we have unified plan SDP.
RemoveAudioTrack(AudioTrackInterface * track,MediaStreamInterface * stream)409 void RtpTransmissionManager::RemoveAudioTrack(AudioTrackInterface* track,
410 MediaStreamInterface* stream) {
411 RTC_DCHECK_RUN_ON(signaling_thread());
412 RTC_DCHECK(!IsUnifiedPlan());
413 auto sender = FindSenderForTrack(track);
414 if (!sender) {
415 RTC_LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
416 << " doesn't exist.";
417 return;
418 }
419 GetAudioTransceiver()->internal()->RemoveSender(sender.get());
420 }
421
AddVideoTrack(VideoTrackInterface * track,MediaStreamInterface * stream)422 void RtpTransmissionManager::AddVideoTrack(VideoTrackInterface* track,
423 MediaStreamInterface* stream) {
424 RTC_DCHECK_RUN_ON(signaling_thread());
425 RTC_DCHECK(track);
426 RTC_DCHECK(stream);
427 auto sender = FindSenderForTrack(track);
428 if (sender) {
429 // We already have a sender for this track, so just change the stream_id
430 // so that it's correct in the next call to CreateOffer.
431 sender->internal()->set_stream_ids({stream->id()});
432 return;
433 }
434
435 // Normal case; we've never seen this track before.
436 auto new_sender = CreateSender(cricket::MEDIA_TYPE_VIDEO, track->id(),
437 rtc::scoped_refptr<VideoTrackInterface>(track),
438 {stream->id()}, {});
439 new_sender->internal()->SetMediaChannel(video_media_channel());
440 GetVideoTransceiver()->internal()->AddSender(new_sender);
441 const RtpSenderInfo* sender_info =
442 FindSenderInfo(local_video_sender_infos_, stream->id(), track->id());
443 if (sender_info) {
444 new_sender->internal()->SetSsrc(sender_info->first_ssrc);
445 }
446 }
447
RemoveVideoTrack(VideoTrackInterface * track,MediaStreamInterface * stream)448 void RtpTransmissionManager::RemoveVideoTrack(VideoTrackInterface* track,
449 MediaStreamInterface* stream) {
450 RTC_DCHECK_RUN_ON(signaling_thread());
451 RTC_DCHECK(!IsUnifiedPlan());
452 auto sender = FindSenderForTrack(track);
453 if (!sender) {
454 RTC_LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
455 << " doesn't exist.";
456 return;
457 }
458 GetVideoTransceiver()->internal()->RemoveSender(sender.get());
459 }
460
CreateAudioReceiver(MediaStreamInterface * stream,const RtpSenderInfo & remote_sender_info)461 void RtpTransmissionManager::CreateAudioReceiver(
462 MediaStreamInterface* stream,
463 const RtpSenderInfo& remote_sender_info) {
464 RTC_DCHECK(!closed_);
465 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams;
466 streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(stream));
467 // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use
468 // the constructor taking stream IDs instead.
469 auto audio_receiver = rtc::make_ref_counted<AudioRtpReceiver>(
470 worker_thread(), remote_sender_info.sender_id, streams, IsUnifiedPlan(),
471 voice_media_channel());
472 if (remote_sender_info.sender_id == kDefaultAudioSenderId) {
473 audio_receiver->SetupUnsignaledMediaChannel();
474 } else {
475 audio_receiver->SetupMediaChannel(remote_sender_info.first_ssrc);
476 }
477
478 auto receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
479 signaling_thread(), worker_thread(), std::move(audio_receiver));
480 GetAudioTransceiver()->internal()->AddReceiver(receiver);
481 Observer()->OnAddTrack(receiver, streams);
482 NoteUsageEvent(UsageEvent::AUDIO_ADDED);
483 }
484
CreateVideoReceiver(MediaStreamInterface * stream,const RtpSenderInfo & remote_sender_info)485 void RtpTransmissionManager::CreateVideoReceiver(
486 MediaStreamInterface* stream,
487 const RtpSenderInfo& remote_sender_info) {
488 RTC_DCHECK(!closed_);
489 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams;
490 streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(stream));
491 // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use
492 // the constructor taking stream IDs instead.
493 auto video_receiver = rtc::make_ref_counted<VideoRtpReceiver>(
494 worker_thread(), remote_sender_info.sender_id, streams);
495
496 video_receiver->SetupMediaChannel(
497 remote_sender_info.sender_id == kDefaultVideoSenderId
498 ? absl::nullopt
499 : absl::optional<uint32_t>(remote_sender_info.first_ssrc),
500 video_media_channel());
501
502 auto receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
503 signaling_thread(), worker_thread(), std::move(video_receiver));
504 GetVideoTransceiver()->internal()->AddReceiver(receiver);
505 Observer()->OnAddTrack(receiver, streams);
506 NoteUsageEvent(UsageEvent::VIDEO_ADDED);
507 }
508
509 // TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
510 // description.
511 rtc::scoped_refptr<RtpReceiverInterface>
RemoveAndStopReceiver(const RtpSenderInfo & remote_sender_info)512 RtpTransmissionManager::RemoveAndStopReceiver(
513 const RtpSenderInfo& remote_sender_info) {
514 auto receiver = FindReceiverById(remote_sender_info.sender_id);
515 if (!receiver) {
516 RTC_LOG(LS_WARNING) << "RtpReceiver for track with id "
517 << remote_sender_info.sender_id << " doesn't exist.";
518 return nullptr;
519 }
520 if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
521 GetAudioTransceiver()->internal()->RemoveReceiver(receiver.get());
522 } else {
523 GetVideoTransceiver()->internal()->RemoveReceiver(receiver.get());
524 }
525 return receiver;
526 }
527
OnRemoteSenderAdded(const RtpSenderInfo & sender_info,MediaStreamInterface * stream,cricket::MediaType media_type)528 void RtpTransmissionManager::OnRemoteSenderAdded(
529 const RtpSenderInfo& sender_info,
530 MediaStreamInterface* stream,
531 cricket::MediaType media_type) {
532 RTC_DCHECK_RUN_ON(signaling_thread());
533 RTC_LOG(LS_INFO) << "Creating " << cricket::MediaTypeToString(media_type)
534 << " receiver for track_id=" << sender_info.sender_id
535 << " and stream_id=" << sender_info.stream_id;
536
537 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
538 CreateAudioReceiver(stream, sender_info);
539 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
540 CreateVideoReceiver(stream, sender_info);
541 } else {
542 RTC_DCHECK_NOTREACHED() << "Invalid media type";
543 }
544 }
545
OnRemoteSenderRemoved(const RtpSenderInfo & sender_info,MediaStreamInterface * stream,cricket::MediaType media_type)546 void RtpTransmissionManager::OnRemoteSenderRemoved(
547 const RtpSenderInfo& sender_info,
548 MediaStreamInterface* stream,
549 cricket::MediaType media_type) {
550 RTC_DCHECK_RUN_ON(signaling_thread());
551 RTC_LOG(LS_INFO) << "Removing " << cricket::MediaTypeToString(media_type)
552 << " receiver for track_id=" << sender_info.sender_id
553 << " and stream_id=" << sender_info.stream_id;
554
555 rtc::scoped_refptr<RtpReceiverInterface> receiver;
556 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
557 // When the MediaEngine audio channel is destroyed, the RemoteAudioSource
558 // will be notified which will end the AudioRtpReceiver::track().
559 receiver = RemoveAndStopReceiver(sender_info);
560 rtc::scoped_refptr<AudioTrackInterface> audio_track =
561 stream->FindAudioTrack(sender_info.sender_id);
562 if (audio_track) {
563 stream->RemoveTrack(audio_track);
564 }
565 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
566 // Stopping or destroying a VideoRtpReceiver will end the
567 // VideoRtpReceiver::track().
568 receiver = RemoveAndStopReceiver(sender_info);
569 rtc::scoped_refptr<VideoTrackInterface> video_track =
570 stream->FindVideoTrack(sender_info.sender_id);
571 if (video_track) {
572 // There's no guarantee the track is still available, e.g. the track may
573 // have been removed from the stream by an application.
574 stream->RemoveTrack(video_track);
575 }
576 } else {
577 RTC_DCHECK_NOTREACHED() << "Invalid media type";
578 }
579 if (receiver) {
580 RTC_DCHECK(!closed_);
581 Observer()->OnRemoveTrack(receiver);
582 }
583 }
584
OnLocalSenderAdded(const RtpSenderInfo & sender_info,cricket::MediaType media_type)585 void RtpTransmissionManager::OnLocalSenderAdded(
586 const RtpSenderInfo& sender_info,
587 cricket::MediaType media_type) {
588 RTC_DCHECK_RUN_ON(signaling_thread());
589 RTC_DCHECK(!IsUnifiedPlan());
590 auto sender = FindSenderById(sender_info.sender_id);
591 if (!sender) {
592 RTC_LOG(LS_WARNING) << "An unknown RtpSender with id "
593 << sender_info.sender_id
594 << " has been configured in the local description.";
595 return;
596 }
597
598 if (sender->media_type() != media_type) {
599 RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local"
600 " description with an unexpected media type.";
601 return;
602 }
603
604 sender->internal()->set_stream_ids({sender_info.stream_id});
605 sender->internal()->SetSsrc(sender_info.first_ssrc);
606 }
607
OnLocalSenderRemoved(const RtpSenderInfo & sender_info,cricket::MediaType media_type)608 void RtpTransmissionManager::OnLocalSenderRemoved(
609 const RtpSenderInfo& sender_info,
610 cricket::MediaType media_type) {
611 RTC_DCHECK_RUN_ON(signaling_thread());
612 auto sender = FindSenderById(sender_info.sender_id);
613 if (!sender) {
614 // This is the normal case. I.e., RemoveStream has been called and the
615 // SessionDescriptions has been renegotiated.
616 return;
617 }
618
619 // A sender has been removed from the SessionDescription but it's still
620 // associated with the PeerConnection. This only occurs if the SDP doesn't
621 // match with the calls to CreateSender, AddStream and RemoveStream.
622 if (sender->media_type() != media_type) {
623 RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local"
624 " description with an unexpected media type.";
625 return;
626 }
627
628 sender->internal()->SetSsrc(0);
629 }
630
GetRemoteSenderInfos(cricket::MediaType media_type)631 std::vector<RtpSenderInfo>* RtpTransmissionManager::GetRemoteSenderInfos(
632 cricket::MediaType media_type) {
633 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
634 media_type == cricket::MEDIA_TYPE_VIDEO);
635 return (media_type == cricket::MEDIA_TYPE_AUDIO)
636 ? &remote_audio_sender_infos_
637 : &remote_video_sender_infos_;
638 }
639
GetLocalSenderInfos(cricket::MediaType media_type)640 std::vector<RtpSenderInfo>* RtpTransmissionManager::GetLocalSenderInfos(
641 cricket::MediaType media_type) {
642 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
643 media_type == cricket::MEDIA_TYPE_VIDEO);
644 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_sender_infos_
645 : &local_video_sender_infos_;
646 }
647
FindSenderInfo(const std::vector<RtpSenderInfo> & infos,const std::string & stream_id,const std::string & sender_id) const648 const RtpSenderInfo* RtpTransmissionManager::FindSenderInfo(
649 const std::vector<RtpSenderInfo>& infos,
650 const std::string& stream_id,
651 const std::string& sender_id) const {
652 for (const RtpSenderInfo& sender_info : infos) {
653 if (sender_info.stream_id == stream_id &&
654 sender_info.sender_id == sender_id) {
655 return &sender_info;
656 }
657 }
658 return nullptr;
659 }
660
661 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
FindSenderForTrack(MediaStreamTrackInterface * track) const662 RtpTransmissionManager::FindSenderForTrack(
663 MediaStreamTrackInterface* track) const {
664 RTC_DCHECK_RUN_ON(signaling_thread());
665 for (const auto& transceiver : transceivers_.List()) {
666 for (auto sender : transceiver->internal()->senders()) {
667 if (sender->track() == track) {
668 return sender;
669 }
670 }
671 }
672 return nullptr;
673 }
674
675 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
FindSenderById(const std::string & sender_id) const676 RtpTransmissionManager::FindSenderById(const std::string& sender_id) const {
677 RTC_DCHECK_RUN_ON(signaling_thread());
678 for (const auto& transceiver : transceivers_.List()) {
679 for (auto sender : transceiver->internal()->senders()) {
680 if (sender->id() == sender_id) {
681 return sender;
682 }
683 }
684 }
685 return nullptr;
686 }
687
688 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
FindReceiverById(const std::string & receiver_id) const689 RtpTransmissionManager::FindReceiverById(const std::string& receiver_id) const {
690 RTC_DCHECK_RUN_ON(signaling_thread());
691 for (const auto& transceiver : transceivers_.List()) {
692 for (auto receiver : transceiver->internal()->receivers()) {
693 if (receiver->id() == receiver_id) {
694 return receiver;
695 }
696 }
697 }
698 return nullptr;
699 }
700
media_engine() const701 cricket::MediaEngineInterface* RtpTransmissionManager::media_engine() const {
702 return context_->media_engine();
703 }
704
705 } // namespace webrtc
706