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