From e15fb15035fe5391a95a32a3d26cd611302ed688 Mon Sep 17 00:00:00 2001 From: Harald Alvestrand Date: Mon, 19 Oct 2020 13:28:05 +0000 Subject: [PATCH] Separate RTP object handling (senders, receivers, transceivers) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is part of the PeerConnection disassembly project. Bug: webrtc:11995 Change-Id: I4f207c8af39e267c4b5752c0828b84e221e1f080 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/188624 Reviewed-by: Henrik Boström Reviewed-by: Niels Moller Commit-Queue: Harald Alvestrand Cr-Commit-Position: refs/heads/master@{#32443} --- pc/BUILD.gn | 45 ++- pc/peer_connection.cc | 704 +++------------------------------ pc/peer_connection.h | 176 +-------- pc/rtp_transmission_manager.cc | 692 ++++++++++++++++++++++++++++++++ pc/rtp_transmission_manager.h | 270 +++++++++++++ pc/sdp_offer_answer.cc | 174 ++++---- pc/sdp_offer_answer.h | 7 +- 7 files changed, 1182 insertions(+), 886 deletions(-) create mode 100644 pc/rtp_transmission_manager.cc create mode 100644 pc/rtp_transmission_manager.h diff --git a/pc/BUILD.gn b/pc/BUILD.gn index 6e46301624..821802f00d 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -195,8 +195,6 @@ rtc_library("peerconnection") { "stream_collection.h", "track_media_info_map.cc", "track_media_info_map.h", - "transceiver_list.cc", - "transceiver_list.h", "webrtc_sdp.cc", "webrtc_sdp.h", "webrtc_session_description_factory.cc", @@ -220,7 +218,9 @@ rtc_library("peerconnection") { ":rtp_receiver", ":rtp_sender", ":rtp_transceiver", + ":rtp_transmission_manager", ":stats_collector_interface", + ":transceiver_list", ":usage_pattern", ":video_rtp_receiver", ":video_track", @@ -365,6 +365,47 @@ rtc_library("rtp_transceiver") { ] } +rtc_library("rtp_transmission_manager") { + sources = [ + "rtp_transmission_manager.cc", + "rtp_transmission_manager.h", + ] + deps = [ + ":audio_rtp_receiver", + ":rtc_pc_base", + ":rtp_receiver", + ":rtp_sender", + ":rtp_transceiver", + ":stats_collector_interface", + ":transceiver_list", + ":usage_pattern", + ":video_rtp_receiver", + "../api:libjingle_peerconnection_api", + "../api:media_stream_interface", + "../api:rtc_error", + "../api:rtp_parameters", + "../api:rtp_transceiver_direction", + "../api:scoped_refptr", + "../media:rtc_media_base", + "../rtc_base", + "../rtc_base:checks", + "../rtc_base/third_party/sigslot", + ] + absl_deps = [ + "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/strings", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + +rtc_library("transceiver_list") { + sources = [ + "transceiver_list.cc", + "transceiver_list.h", + ] + deps = [ ":rtp_transceiver" ] +} + rtc_library("rtp_receiver") { sources = [ "rtp_receiver.cc", diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index 7123b7b7fd..9f3f6ba65b 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -13,6 +13,10 @@ #include #include #include +#include +#include +#include +#include #include #include "absl/algorithm/container.h" @@ -83,9 +87,6 @@ namespace { const char kSimulcastNumberOfEncodings[] = "WebRTC.PeerConnection.Simulcast.NumberOfSendEncodings"; -static const char kDefaultAudioSenderId[] = "defaulta0"; -static const char kDefaultVideoSenderId[] = "defaultv0"; - static const int REPORT_USAGE_PATTERN_DELAY_MS = 60000; @@ -351,8 +352,10 @@ PeerConnection::~PeerConnection() { // Need to stop transceivers before destroying the stats collector because // AudioRtpSender has a reference to the StatsCollector it will update when // stopping. - for (const auto& transceiver : transceivers_.List()) { - transceiver->StopInternal(); + if (rtp_manager()) { + for (const auto& transceiver : rtp_manager()->transceivers()->List()) { + transceiver->StopInternal(); + } } stats_.reset(nullptr); @@ -547,13 +550,20 @@ bool PeerConnection::Initialize( OnTransportControllerConnectionState(s); }); - stats_.reset(new StatsCollector(this)); - stats_collector_ = RTCStatsCollector::Create(this); - configuration_ = configuration; transport_controller_->SetIceConfig(ParseIceConfig(configuration)); + stats_ = std::make_unique(this); + stats_collector_ = RTCStatsCollector::Create(this); + + rtp_manager_ = std::make_unique( + IsUnifiedPlan(), signaling_thread(), worker_thread(), channel_manager(), + &usage_pattern_, observer_, stats_.get(), [this]() { + RTC_DCHECK_RUN_ON(signaling_thread()); + sdp_handler_.UpdateNegotiationNeeded(); + }); + video_options_.screencast_min_bitrate_kbps = configuration.screencast_min_bitrate; audio_options_.combined_audio_video_bwe = @@ -601,10 +611,12 @@ bool PeerConnection::Initialize( // Add default audio/video transceivers for Plan B SDP. if (!IsUnifiedPlan()) { - transceivers_.Add(RtpTransceiverProxyWithInternal::Create( - signaling_thread(), new RtpTransceiver(cricket::MEDIA_TYPE_AUDIO))); - transceivers_.Add(RtpTransceiverProxyWithInternal::Create( - signaling_thread(), new RtpTransceiver(cricket::MEDIA_TYPE_VIDEO))); + rtp_manager()->transceivers()->Add( + RtpTransceiverProxyWithInternal::Create( + signaling_thread(), new RtpTransceiver(cricket::MEDIA_TYPE_AUDIO))); + rtp_manager()->transceivers()->Add( + RtpTransceiverProxyWithInternal::Create( + signaling_thread(), new RtpTransceiver(cricket::MEDIA_TYPE_VIDEO))); } int delay_ms = return_histogram_very_quickly_ ? 0 : REPORT_USAGE_PATTERN_DELAY_MS; @@ -682,14 +694,12 @@ RTCErrorOr> PeerConnection::AddTrack( LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE, "PeerConnection is closed."); } - if (FindSenderForTrack(track)) { + if (rtp_manager()->FindSenderForTrack(track)) { LOG_AND_RETURN_ERROR( RTCErrorType::INVALID_PARAMETER, "Sender already exists for track " + track->id() + "."); } - auto sender_or_error = - (IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids) - : AddTrackPlanB(track, stream_ids)); + auto sender_or_error = rtp_manager()->AddTrack(track, stream_ids); if (sender_or_error.ok()) { sdp_handler_.UpdateNegotiationNeeded(); stats_->AddTrack(track); @@ -697,111 +707,6 @@ RTCErrorOr> PeerConnection::AddTrack( return sender_or_error; } -RTCErrorOr> -PeerConnection::AddTrackPlanB( - rtc::scoped_refptr track, - const std::vector& stream_ids) { - if (stream_ids.size() > 1u) { - LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, - "AddTrack with more than one stream is not " - "supported with Plan B semantics."); - } - std::vector adjusted_stream_ids = stream_ids; - if (adjusted_stream_ids.empty()) { - adjusted_stream_ids.push_back(rtc::CreateRandomUuid()); - } - cricket::MediaType media_type = - (track->kind() == MediaStreamTrackInterface::kAudioKind - ? cricket::MEDIA_TYPE_AUDIO - : cricket::MEDIA_TYPE_VIDEO); - auto new_sender = - CreateSender(media_type, track->id(), track, adjusted_stream_ids, {}); - if (track->kind() == MediaStreamTrackInterface::kAudioKind) { - new_sender->internal()->SetMediaChannel(voice_media_channel()); - GetAudioTransceiver()->internal()->AddSender(new_sender); - const RtpSenderInfo* sender_info = - FindSenderInfo(local_audio_sender_infos_, - new_sender->internal()->stream_ids()[0], track->id()); - if (sender_info) { - new_sender->internal()->SetSsrc(sender_info->first_ssrc); - } - } else { - RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind()); - new_sender->internal()->SetMediaChannel(video_media_channel()); - GetVideoTransceiver()->internal()->AddSender(new_sender); - const RtpSenderInfo* sender_info = - FindSenderInfo(local_video_sender_infos_, - new_sender->internal()->stream_ids()[0], track->id()); - if (sender_info) { - new_sender->internal()->SetSsrc(sender_info->first_ssrc); - } - } - return rtc::scoped_refptr(new_sender); -} - -RTCErrorOr> -PeerConnection::AddTrackUnifiedPlan( - rtc::scoped_refptr track, - const std::vector& stream_ids) { - auto transceiver = FindFirstTransceiverForAddedTrack(track); - if (transceiver) { - RTC_LOG(LS_INFO) << "Reusing an existing " - << cricket::MediaTypeToString(transceiver->media_type()) - << " transceiver for AddTrack."; - if (transceiver->stopping()) { - LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, - "The existing transceiver is stopping."); - } - - if (transceiver->direction() == RtpTransceiverDirection::kRecvOnly) { - transceiver->internal()->set_direction( - RtpTransceiverDirection::kSendRecv); - } else if (transceiver->direction() == RtpTransceiverDirection::kInactive) { - transceiver->internal()->set_direction( - RtpTransceiverDirection::kSendOnly); - } - transceiver->sender()->SetTrack(track); - transceiver->internal()->sender_internal()->set_stream_ids(stream_ids); - transceiver->internal()->set_reused_for_addtrack(true); - } else { - cricket::MediaType media_type = - (track->kind() == MediaStreamTrackInterface::kAudioKind - ? cricket::MEDIA_TYPE_AUDIO - : cricket::MEDIA_TYPE_VIDEO); - RTC_LOG(LS_INFO) << "Adding " << cricket::MediaTypeToString(media_type) - << " transceiver in response to a call to AddTrack."; - std::string sender_id = track->id(); - // Avoid creating a sender with an existing ID by generating a random ID. - // This can happen if this is the second time AddTrack has created a sender - // for this track. - if (FindSenderById(sender_id)) { - sender_id = rtc::CreateRandomUuid(); - } - auto sender = CreateSender(media_type, sender_id, track, stream_ids, {}); - auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid()); - transceiver = CreateAndAddTransceiver(sender, receiver); - transceiver->internal()->set_created_by_addtrack(true); - transceiver->internal()->set_direction(RtpTransceiverDirection::kSendRecv); - } - return transceiver->sender(); -} - -rtc::scoped_refptr> -PeerConnection::FindFirstTransceiverForAddedTrack( - rtc::scoped_refptr track) { - RTC_DCHECK(track); - for (auto transceiver : transceivers_.List()) { - if (!transceiver->sender()->track() && - cricket::MediaTypeToString(transceiver->media_type()) == - track->kind() && - !transceiver->internal()->has_ever_been_used_to_send() && - !transceiver->stopped()) { - return transceiver; - } - } - return nullptr; -} - bool PeerConnection::RemoveTrack(RtpSenderInterface* sender) { TRACE_EVENT0("webrtc", "PeerConnection::RemoveTrack"); return RemoveTrackNew(sender).ok(); @@ -833,10 +738,12 @@ RTCError PeerConnection::RemoveTrackNew( } else { bool removed; if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) { - removed = GetAudioTransceiver()->internal()->RemoveSender(sender); + removed = rtp_manager()->GetAudioTransceiver()->internal()->RemoveSender( + sender); } else { RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, sender->media_type()); - removed = GetVideoTransceiver()->internal()->RemoveSender(sender); + removed = rtp_manager()->GetVideoTransceiver()->internal()->RemoveSender( + sender); } if (!removed) { LOG_AND_RETURN_ERROR( @@ -851,7 +758,7 @@ RTCError PeerConnection::RemoveTrackNew( rtc::scoped_refptr> PeerConnection::FindTransceiverBySender( rtc::scoped_refptr sender) { - return transceivers_.FindBySender(sender); + return rtp_manager()->transceivers()->FindBySender(sender); } RTCErrorOr> @@ -987,13 +894,14 @@ PeerConnection::AddTransceiver( << " transceiver in response to a call to AddTransceiver."; // Set the sender ID equal to the track ID if the track is specified unless // that sender ID is already in use. - std::string sender_id = - (track && !FindSenderById(track->id()) ? track->id() - : rtc::CreateRandomUuid()); - auto sender = CreateSender(media_type, sender_id, track, init.stream_ids, - parameters.encodings); - auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid()); - auto transceiver = CreateAndAddTransceiver(sender, receiver); + std::string sender_id = (track && !rtp_manager()->FindSenderById(track->id()) + ? track->id() + : rtc::CreateRandomUuid()); + auto sender = rtp_manager()->CreateSender( + media_type, sender_id, track, init.stream_ids, parameters.encodings); + auto receiver = + rtp_manager()->CreateReceiver(media_type, rtc::CreateRandomUuid()); + auto transceiver = rtp_manager()->CreateAndAddTransceiver(sender, receiver); transceiver->internal()->set_direction(init.direction); if (update_negotiation_needed) { @@ -1003,81 +911,6 @@ PeerConnection::AddTransceiver( return rtc::scoped_refptr(transceiver); } -rtc::scoped_refptr> -PeerConnection::CreateSender( - cricket::MediaType media_type, - const std::string& id, - rtc::scoped_refptr track, - const std::vector& stream_ids, - const std::vector& send_encodings) { - RTC_DCHECK_RUN_ON(signaling_thread()); - rtc::scoped_refptr> sender; - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - RTC_DCHECK(!track || - (track->kind() == MediaStreamTrackInterface::kAudioKind)); - sender = RtpSenderProxyWithInternal::Create( - signaling_thread(), - AudioRtpSender::Create(worker_thread(), id, stats_.get(), this)); - NoteUsageEvent(UsageEvent::AUDIO_ADDED); - } else { - RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO); - RTC_DCHECK(!track || - (track->kind() == MediaStreamTrackInterface::kVideoKind)); - sender = RtpSenderProxyWithInternal::Create( - signaling_thread(), VideoRtpSender::Create(worker_thread(), id, this)); - NoteUsageEvent(UsageEvent::VIDEO_ADDED); - } - bool set_track_succeeded = sender->SetTrack(track); - RTC_DCHECK(set_track_succeeded); - sender->internal()->set_stream_ids(stream_ids); - sender->internal()->set_init_send_encodings(send_encodings); - return sender; -} - -rtc::scoped_refptr> -PeerConnection::CreateReceiver(cricket::MediaType media_type, - const std::string& receiver_id) { - rtc::scoped_refptr> - receiver; - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - receiver = RtpReceiverProxyWithInternal::Create( - signaling_thread(), new AudioRtpReceiver(worker_thread(), receiver_id, - std::vector({}))); - NoteUsageEvent(UsageEvent::AUDIO_ADDED); - } else { - RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO); - receiver = RtpReceiverProxyWithInternal::Create( - signaling_thread(), new VideoRtpReceiver(worker_thread(), receiver_id, - std::vector({}))); - NoteUsageEvent(UsageEvent::VIDEO_ADDED); - } - return receiver; -} - -rtc::scoped_refptr> -PeerConnection::CreateAndAddTransceiver( - rtc::scoped_refptr> sender, - rtc::scoped_refptr> - receiver) { - RTC_DCHECK_RUN_ON(signaling_thread()); - // Ensure that the new sender does not have an ID that is already in use by - // another sender. - // Allow receiver IDs to conflict since those come from remote SDP (which - // could be invalid, but should not cause a crash). - RTC_DCHECK(!FindSenderById(sender->id())); - auto transceiver = RtpTransceiverProxyWithInternal::Create( - signaling_thread(), - new RtpTransceiver( - sender, receiver, channel_manager(), - sender->media_type() == cricket::MEDIA_TYPE_AUDIO - ? channel_manager()->GetSupportedAudioRtpHeaderExtensions() - : channel_manager()->GetSupportedVideoRtpHeaderExtensions())); - transceivers_.Add(transceiver); - transceiver->internal()->SignalNegotiationNeeded.connect( - this, &PeerConnection::OnNegotiationNeeded); - return transceiver; -} - void PeerConnection::OnNegotiationNeeded() { RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK(!IsClosed()); @@ -1112,18 +945,18 @@ rtc::scoped_refptr PeerConnection::CreateSender( rtc::scoped_refptr> new_sender; if (kind == MediaStreamTrackInterface::kAudioKind) { auto audio_sender = AudioRtpSender::Create( - worker_thread(), rtc::CreateRandomUuid(), stats_.get(), this); - audio_sender->SetMediaChannel(voice_media_channel()); + worker_thread(), rtc::CreateRandomUuid(), stats_.get(), rtp_manager()); + audio_sender->SetMediaChannel(rtp_manager()->voice_media_channel()); new_sender = RtpSenderProxyWithInternal::Create( signaling_thread(), audio_sender); - GetAudioTransceiver()->internal()->AddSender(new_sender); + rtp_manager()->GetAudioTransceiver()->internal()->AddSender(new_sender); } else if (kind == MediaStreamTrackInterface::kVideoKind) { - auto video_sender = - VideoRtpSender::Create(worker_thread(), rtc::CreateRandomUuid(), this); - video_sender->SetMediaChannel(video_media_channel()); + auto video_sender = VideoRtpSender::Create( + worker_thread(), rtc::CreateRandomUuid(), rtp_manager()); + video_sender->SetMediaChannel(rtp_manager()->video_media_channel()); new_sender = RtpSenderProxyWithInternal::Create( signaling_thread(), video_sender); - GetVideoTransceiver()->internal()->AddSender(new_sender); + rtp_manager()->GetVideoTransceiver()->internal()->AddSender(new_sender); } else { RTC_LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind; return nullptr; @@ -1137,61 +970,29 @@ std::vector> PeerConnection::GetSenders() const { RTC_DCHECK_RUN_ON(signaling_thread()); std::vector> ret; - for (const auto& sender : GetSendersInternal()) { + for (const auto& sender : rtp_manager()->GetSendersInternal()) { ret.push_back(sender); } return ret; } -std::vector>> -PeerConnection::GetSendersInternal() const { - RTC_DCHECK_RUN_ON(signaling_thread()); - std::vector>> - all_senders; - for (const auto& transceiver : transceivers_.List()) { - if (IsUnifiedPlan() && transceiver->internal()->stopped()) - continue; - - auto senders = transceiver->internal()->senders(); - all_senders.insert(all_senders.end(), senders.begin(), senders.end()); - } - return all_senders; -} - std::vector> PeerConnection::GetReceivers() const { RTC_DCHECK_RUN_ON(signaling_thread()); std::vector> ret; - for (const auto& receiver : GetReceiversInternal()) { + for (const auto& receiver : rtp_manager()->GetReceiversInternal()) { ret.push_back(receiver); } return ret; } -std::vector< - rtc::scoped_refptr>> -PeerConnection::GetReceiversInternal() const { - std::vector< - rtc::scoped_refptr>> - all_receivers; - for (const auto& transceiver : transceivers_.List()) { - if (IsUnifiedPlan() && transceiver->internal()->stopped()) - continue; - - auto receivers = transceiver->internal()->receivers(); - all_receivers.insert(all_receivers.end(), receivers.begin(), - receivers.end()); - } - return all_receivers; -} - std::vector> PeerConnection::GetTransceivers() const { RTC_DCHECK_RUN_ON(signaling_thread()); RTC_CHECK(IsUnifiedPlan()) << "GetTransceivers is only supported with Unified Plan SdpSemantics."; std::vector> all_transceivers; - for (const auto& transceiver : transceivers_.List()) { + for (const auto& transceiver : rtp_manager()->transceivers()->List()) { all_transceivers.push_back(transceiver); } return all_transceivers; @@ -1236,7 +1037,8 @@ void PeerConnection::GetStats( RTC_DCHECK(stats_collector_); rtc::scoped_refptr internal_sender; if (selector) { - for (const auto& proxy_transceiver : transceivers_.List()) { + for (const auto& proxy_transceiver : + rtp_manager()->transceivers()->List()) { for (const auto& proxy_sender : proxy_transceiver->internal()->senders()) { if (proxy_sender == selector) { @@ -1265,7 +1067,8 @@ void PeerConnection::GetStats( RTC_DCHECK(stats_collector_); rtc::scoped_refptr internal_receiver; if (selector) { - for (const auto& proxy_transceiver : transceivers_.List()) { + for (const auto& proxy_transceiver : + rtp_manager()->transceivers()->List()) { for (const auto& proxy_receiver : proxy_transceiver->internal()->receivers()) { if (proxy_receiver == selector) { @@ -1552,7 +1355,7 @@ RTCError PeerConnection::SetConfiguration( if (modified_config.allow_codec_switching.has_value()) { std::vector channels; - for (const auto& transceiver : transceivers_.List()) { + for (const auto& transceiver : rtp_manager()->transceivers()->List()) { if (transceiver->media_type() != cricket::MEDIA_TYPE_VIDEO) continue; @@ -1673,7 +1476,7 @@ PeerConnection::GetRemoteAudioSSLCertificate() { std::unique_ptr PeerConnection::GetRemoteAudioSSLCertChain() { RTC_DCHECK_RUN_ON(signaling_thread()); - auto audio_transceiver = GetFirstAudioTransceiver(); + auto audio_transceiver = rtp_manager()->GetFirstAudioTransceiver(); if (!audio_transceiver || !audio_transceiver->internal()->channel()) { return nullptr; } @@ -1681,16 +1484,6 @@ PeerConnection::GetRemoteAudioSSLCertChain() { audio_transceiver->internal()->channel()->transport_name()); } -rtc::scoped_refptr> -PeerConnection::GetFirstAudioTransceiver() const { - for (auto transceiver : transceivers_.List()) { - if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { - return transceiver; - } - } - return nullptr; -} - void PeerConnection::AddAdaptationResource( rtc::scoped_refptr resource) { if (!worker_thread()->IsCurrent()) { @@ -1807,7 +1600,7 @@ void PeerConnection::Close() { NoteUsageEvent(UsageEvent::CLOSE_CALLED); - for (const auto& transceiver : transceivers_.List()) { + for (const auto& transceiver : rtp_manager()->transceivers()->List()) { transceiver->internal()->SetPeerConnectionClosed(); if (!transceiver->stopped()) transceiver->StopInternal(); @@ -1830,6 +1623,7 @@ void PeerConnection::Close() { // call the transport controller. sdp_handler_.ResetSessionDescFactory(); transport_controller_.reset(); + rtp_manager_->Close(); network_thread()->Invoke( RTC_FROM_HERE, rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool, @@ -1848,176 +1642,6 @@ void PeerConnection::Close() { observer_ = nullptr; } -cricket::VoiceMediaChannel* PeerConnection::voice_media_channel() const { - RTC_DCHECK(!IsUnifiedPlan()); - auto* voice_channel = static_cast( - GetAudioTransceiver()->internal()->channel()); - if (voice_channel) { - return voice_channel->media_channel(); - } else { - return nullptr; - } -} - -cricket::VideoMediaChannel* PeerConnection::video_media_channel() const { - RTC_DCHECK(!IsUnifiedPlan()); - auto* video_channel = static_cast( - GetVideoTransceiver()->internal()->channel()); - if (video_channel) { - return video_channel->media_channel(); - } else { - return nullptr; - } -} - -void PeerConnection::CreateAudioReceiver( - MediaStreamInterface* stream, - const RtpSenderInfo& remote_sender_info) { - std::vector> streams; - streams.push_back(rtc::scoped_refptr(stream)); - // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use - // the constructor taking stream IDs instead. - auto* audio_receiver = new AudioRtpReceiver( - worker_thread(), remote_sender_info.sender_id, streams); - audio_receiver->SetMediaChannel(voice_media_channel()); - if (remote_sender_info.sender_id == kDefaultAudioSenderId) { - audio_receiver->SetupUnsignaledMediaChannel(); - } else { - audio_receiver->SetupMediaChannel(remote_sender_info.first_ssrc); - } - auto receiver = RtpReceiverProxyWithInternal::Create( - signaling_thread(), audio_receiver); - GetAudioTransceiver()->internal()->AddReceiver(receiver); - Observer()->OnAddTrack(receiver, streams); - NoteUsageEvent(UsageEvent::AUDIO_ADDED); -} - -void PeerConnection::CreateVideoReceiver( - MediaStreamInterface* stream, - const RtpSenderInfo& remote_sender_info) { - std::vector> streams; - streams.push_back(rtc::scoped_refptr(stream)); - // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use - // the constructor taking stream IDs instead. - auto* video_receiver = new VideoRtpReceiver( - worker_thread(), remote_sender_info.sender_id, streams); - video_receiver->SetMediaChannel(video_media_channel()); - if (remote_sender_info.sender_id == kDefaultVideoSenderId) { - video_receiver->SetupUnsignaledMediaChannel(); - } else { - video_receiver->SetupMediaChannel(remote_sender_info.first_ssrc); - } - auto receiver = RtpReceiverProxyWithInternal::Create( - signaling_thread(), video_receiver); - GetVideoTransceiver()->internal()->AddReceiver(receiver); - Observer()->OnAddTrack(receiver, streams); - NoteUsageEvent(UsageEvent::VIDEO_ADDED); -} - -// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote -// description. -rtc::scoped_refptr PeerConnection::RemoveAndStopReceiver( - const RtpSenderInfo& remote_sender_info) { - auto receiver = FindReceiverById(remote_sender_info.sender_id); - if (!receiver) { - RTC_LOG(LS_WARNING) << "RtpReceiver for track with id " - << remote_sender_info.sender_id << " doesn't exist."; - return nullptr; - } - if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { - GetAudioTransceiver()->internal()->RemoveReceiver(receiver); - } else { - GetVideoTransceiver()->internal()->RemoveReceiver(receiver); - } - return receiver; -} - -void PeerConnection::AddAudioTrack(AudioTrackInterface* track, - MediaStreamInterface* stream) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_DCHECK(!IsClosed()); - RTC_DCHECK(track); - RTC_DCHECK(stream); - auto sender = FindSenderForTrack(track); - if (sender) { - // We already have a sender for this track, so just change the stream_id - // so that it's correct in the next call to CreateOffer. - sender->internal()->set_stream_ids({stream->id()}); - return; - } - - // Normal case; we've never seen this track before. - auto new_sender = CreateSender(cricket::MEDIA_TYPE_AUDIO, track->id(), track, - {stream->id()}, {}); - new_sender->internal()->SetMediaChannel(voice_media_channel()); - GetAudioTransceiver()->internal()->AddSender(new_sender); - // If the sender has already been configured in SDP, we call SetSsrc, - // which will connect the sender to the underlying transport. This can - // occur if a local session description that contains the ID of the sender - // is set before AddStream is called. It can also occur if the local - // session description is not changed and RemoveStream is called, and - // later AddStream is called again with the same stream. - const RtpSenderInfo* sender_info = - FindSenderInfo(local_audio_sender_infos_, stream->id(), track->id()); - if (sender_info) { - new_sender->internal()->SetSsrc(sender_info->first_ssrc); - } -} - -// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around -// indefinitely, when we have unified plan SDP. -void PeerConnection::RemoveAudioTrack(AudioTrackInterface* track, - MediaStreamInterface* stream) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_DCHECK(!IsClosed()); - auto sender = FindSenderForTrack(track); - if (!sender) { - RTC_LOG(LS_WARNING) << "RtpSender for track with id " << track->id() - << " doesn't exist."; - return; - } - GetAudioTransceiver()->internal()->RemoveSender(sender); -} - -void PeerConnection::AddVideoTrack(VideoTrackInterface* track, - MediaStreamInterface* stream) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_DCHECK(!IsClosed()); - RTC_DCHECK(track); - RTC_DCHECK(stream); - auto sender = FindSenderForTrack(track); - if (sender) { - // We already have a sender for this track, so just change the stream_id - // so that it's correct in the next call to CreateOffer. - sender->internal()->set_stream_ids({stream->id()}); - return; - } - - // Normal case; we've never seen this track before. - auto new_sender = CreateSender(cricket::MEDIA_TYPE_VIDEO, track->id(), track, - {stream->id()}, {}); - new_sender->internal()->SetMediaChannel(video_media_channel()); - GetVideoTransceiver()->internal()->AddSender(new_sender); - const RtpSenderInfo* sender_info = - FindSenderInfo(local_video_sender_infos_, stream->id(), track->id()); - if (sender_info) { - new_sender->internal()->SetSsrc(sender_info->first_ssrc); - } -} - -void PeerConnection::RemoveVideoTrack(VideoTrackInterface* track, - MediaStreamInterface* stream) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_DCHECK(!IsClosed()); - auto sender = FindSenderForTrack(track); - if (!sender) { - RTC_LOG(LS_WARNING) << "RtpSender for track with id " << track->id() - << " doesn't exist."; - return; - } - GetVideoTransceiver()->internal()->RemoveSender(sender); -} - void PeerConnection::SetIceConnectionState(IceConnectionState new_state) { RTC_DCHECK_RUN_ON(signaling_thread()); if (ice_connection_state_ == new_state) { @@ -2126,7 +1750,7 @@ void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track, if (IsClosed()) { return; } - AddAudioTrack(track, stream); + rtp_manager()->AddAudioTrack(track, stream); sdp_handler_.UpdateNegotiationNeeded(); } @@ -2135,7 +1759,7 @@ void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track, if (IsClosed()) { return; } - RemoveAudioTrack(track, stream); + rtp_manager()->RemoveAudioTrack(track, stream); sdp_handler_.UpdateNegotiationNeeded(); } @@ -2144,7 +1768,7 @@ void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track, if (IsClosed()) { return; } - AddVideoTrack(track, stream); + rtp_manager()->AddVideoTrack(track, stream); sdp_handler_.UpdateNegotiationNeeded(); } @@ -2153,7 +1777,7 @@ void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track, if (IsClosed()) { return; } - RemoveVideoTrack(track, stream); + rtp_manager()->RemoveVideoTrack(track, stream); sdp_handler_.UpdateNegotiationNeeded(); } @@ -2172,104 +1796,6 @@ absl::optional PeerConnection::GetDataMid() const { } } -void PeerConnection::OnRemoteSenderAdded(const RtpSenderInfo& sender_info, - MediaStreamInterface* stream, - cricket::MediaType media_type) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_LOG(LS_INFO) << "Creating " << cricket::MediaTypeToString(media_type) - << " receiver for track_id=" << sender_info.sender_id - << " and stream_id=" << sender_info.stream_id; - - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - CreateAudioReceiver(stream, sender_info); - } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { - CreateVideoReceiver(stream, sender_info); - } else { - RTC_NOTREACHED() << "Invalid media type"; - } -} - -void PeerConnection::OnRemoteSenderRemoved(const RtpSenderInfo& sender_info, - MediaStreamInterface* stream, - cricket::MediaType media_type) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_LOG(LS_INFO) << "Removing " << cricket::MediaTypeToString(media_type) - << " receiver for track_id=" << sender_info.sender_id - << " and stream_id=" << sender_info.stream_id; - - rtc::scoped_refptr receiver; - if (media_type == cricket::MEDIA_TYPE_AUDIO) { - // When the MediaEngine audio channel is destroyed, the RemoteAudioSource - // will be notified which will end the AudioRtpReceiver::track(). - receiver = RemoveAndStopReceiver(sender_info); - rtc::scoped_refptr audio_track = - stream->FindAudioTrack(sender_info.sender_id); - if (audio_track) { - stream->RemoveTrack(audio_track); - } - } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { - // Stopping or destroying a VideoRtpReceiver will end the - // VideoRtpReceiver::track(). - receiver = RemoveAndStopReceiver(sender_info); - rtc::scoped_refptr video_track = - stream->FindVideoTrack(sender_info.sender_id); - if (video_track) { - // There's no guarantee the track is still available, e.g. the track may - // have been removed from the stream by an application. - stream->RemoveTrack(video_track); - } - } else { - RTC_NOTREACHED() << "Invalid media type"; - } - if (receiver) { - Observer()->OnRemoveTrack(receiver); - } -} - -void PeerConnection::OnLocalSenderAdded(const RtpSenderInfo& sender_info, - cricket::MediaType media_type) { - RTC_DCHECK_RUN_ON(signaling_thread()); - RTC_DCHECK(!IsUnifiedPlan()); - auto sender = FindSenderById(sender_info.sender_id); - if (!sender) { - RTC_LOG(LS_WARNING) << "An unknown RtpSender with id " - << sender_info.sender_id - << " has been configured in the local description."; - return; - } - - if (sender->media_type() != media_type) { - RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local" - " description with an unexpected media type."; - return; - } - - sender->internal()->set_stream_ids({sender_info.stream_id}); - sender->internal()->SetSsrc(sender_info.first_ssrc); -} - -void PeerConnection::OnLocalSenderRemoved(const RtpSenderInfo& sender_info, - cricket::MediaType media_type) { - RTC_DCHECK_RUN_ON(signaling_thread()); - auto sender = FindSenderById(sender_info.sender_id); - if (!sender) { - // This is the normal case. I.e., RemoveStream has been called and the - // SessionDescriptions has been renegotiated. - return; - } - - // A sender has been removed from the SessionDescription but it's still - // associated with the PeerConnection. This only occurs if the SDP doesn't - // match with the calls to CreateSender, AddStream and RemoveStream. - if (sender->media_type() != media_type) { - RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local" - " description with an unexpected media type."; - return; - } - - sender->internal()->SetSsrc(0); -} - void PeerConnection::OnSctpDataChannelClosed(DataChannelInterface* channel) { // Since data_channel_controller doesn't do signals, this // signal is relayed here. @@ -2277,102 +1803,6 @@ void PeerConnection::OnSctpDataChannelClosed(DataChannelInterface* channel) { static_cast(channel)); } -rtc::scoped_refptr> -PeerConnection::GetAudioTransceiver() const { - RTC_DCHECK_RUN_ON(signaling_thread()); - // This method only works with Plan B SDP, where there is a single - // audio/video transceiver. - RTC_DCHECK(!IsUnifiedPlan()); - for (auto transceiver : transceivers_.List()) { - if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { - return transceiver; - } - } - RTC_NOTREACHED(); - return nullptr; -} - -rtc::scoped_refptr> -PeerConnection::GetVideoTransceiver() const { - RTC_DCHECK_RUN_ON(signaling_thread()); - // This method only works with Plan B SDP, where there is a single - // audio/video transceiver. - RTC_DCHECK(!IsUnifiedPlan()); - for (auto transceiver : transceivers_.List()) { - if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) { - return transceiver; - } - } - RTC_NOTREACHED(); - return nullptr; -} - -rtc::scoped_refptr> -PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) const { - for (const auto& transceiver : transceivers_.List()) { - for (auto sender : transceiver->internal()->senders()) { - if (sender->track() == track) { - return sender; - } - } - } - return nullptr; -} - -rtc::scoped_refptr> -PeerConnection::FindSenderById(const std::string& sender_id) const { - for (const auto& transceiver : transceivers_.List()) { - for (auto sender : transceiver->internal()->senders()) { - if (sender->id() == sender_id) { - return sender; - } - } - } - return nullptr; -} - -rtc::scoped_refptr> -PeerConnection::FindReceiverById(const std::string& receiver_id) const { - for (const auto& transceiver : transceivers_.List()) { - for (auto receiver : transceiver->internal()->receivers()) { - if (receiver->id() == receiver_id) { - return receiver; - } - } - } - return nullptr; -} - -std::vector* -PeerConnection::GetRemoteSenderInfos(cricket::MediaType media_type) { - RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO || - media_type == cricket::MEDIA_TYPE_VIDEO); - return (media_type == cricket::MEDIA_TYPE_AUDIO) - ? &remote_audio_sender_infos_ - : &remote_video_sender_infos_; -} - -std::vector* PeerConnection::GetLocalSenderInfos( - cricket::MediaType media_type) { - RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO || - media_type == cricket::MEDIA_TYPE_VIDEO); - return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_sender_infos_ - : &local_video_sender_infos_; -} - -const PeerConnection::RtpSenderInfo* PeerConnection::FindSenderInfo( - const std::vector& infos, - const std::string& stream_id, - const std::string sender_id) const { - for (const RtpSenderInfo& sender_info : infos) { - if (sender_info.stream_id == stream_id && - sender_info.sender_id == sender_id) { - return &sender_info; - } - } - return nullptr; -} - SctpDataChannel* PeerConnection::FindDataChannelBySid(int sid) const { return data_channel_controller_.FindDataChannelBySid(sid); } @@ -2497,7 +1927,7 @@ void PeerConnection::StopRtcEventLog_w() { cricket::ChannelInterface* PeerConnection::GetChannel( const std::string& content_name) { - for (const auto& transceiver : transceivers_.List()) { + for (const auto& transceiver : rtp_manager()->transceivers()->List()) { cricket::ChannelInterface* channel = transceiver->internal()->channel(); if (channel && channel->content_name() == content_name) { return channel; @@ -2641,7 +2071,7 @@ std::map PeerConnection::GetTransportNamesByMid() const { RTC_DCHECK_RUN_ON(signaling_thread()); std::map transport_names_by_mid; - for (const auto& transceiver : transceivers_.List()) { + for (const auto& transceiver : rtp_manager()->transceivers()->List()) { cricket::ChannelInterface* channel = transceiver->internal()->channel(); if (channel) { transport_names_by_mid[channel->content_name()] = @@ -3007,7 +2437,7 @@ void PeerConnection::OnTransportControllerGatheringState( void PeerConnection::ReportTransportStats() { std::map> media_types_by_transport_name; - for (const auto& transceiver : transceivers_.List()) { + for (const auto& transceiver : rtp_manager()->transceivers()->List()) { if (transceiver->internal()->channel()) { const std::string& transport_name = transceiver->internal()->channel()->transport_name(); @@ -3173,12 +2603,6 @@ bool PeerConnection::OnTransportChanged( return ret; } -void PeerConnection::OnSetStreams() { - RTC_DCHECK_RUN_ON(signaling_thread()); - if (IsUnifiedPlan()) - sdp_handler_.UpdateNegotiationNeeded(); -} - PeerConnectionObserver* PeerConnection::Observer() const { RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK(observer_); diff --git a/pc/peer_connection.h b/pc/peer_connection.h index c2ea92f055..582c76d29f 100644 --- a/pc/peer_connection.h +++ b/pc/peer_connection.h @@ -73,8 +73,10 @@ #include "pc/rtp_receiver.h" #include "pc/rtp_sender.h" #include "pc/rtp_transceiver.h" +#include "pc/rtp_transmission_manager.h" #include "pc/rtp_transport_internal.h" #include "pc/sctp_data_channel.h" +#include "pc/sctp_transport.h" #include "pc/sdp_offer_answer.h" #include "pc/session_description.h" #include "pc/stats_collector.h" @@ -114,7 +116,6 @@ namespace webrtc { // - Generating stats. class PeerConnection : public PeerConnectionInternal, public JsepTransportController::Observer, - public RtpSenderBase::SetStreamsObserver, public sigslot::has_slots<> { public: explicit PeerConnection(rtc::scoped_refptr context, @@ -291,7 +292,7 @@ class PeerConnection : public PeerConnectionInternal, rtc::scoped_refptr>> GetTransceiversInternal() const override { RTC_DCHECK_RUN_ON(signaling_thread()); - return transceivers_.List(); + return rtp_manager()->transceivers()->List(); } sigslot::signal1& SignalRtpDataChannelCreated() override { @@ -366,6 +367,11 @@ class PeerConnection : public PeerConnectionInternal, return &message_handler_; } + RtpTransmissionManager* rtp_manager() { return rtp_manager_.get(); } + const RtpTransmissionManager* rtp_manager() const { + return rtp_manager_.get(); + } + // Functions made public for testing. void ReturnHistogramVeryQuicklyForTesting() { RTC_DCHECK_RUN_ON(signaling_thread()); @@ -381,83 +387,6 @@ class PeerConnection : public PeerConnectionInternal, // TOOD(https://bugs.webrtc.org/11995): Remove friendship. friend class SdpOfferAnswerHandler; - struct RtpSenderInfo { - RtpSenderInfo() : first_ssrc(0) {} - RtpSenderInfo(const std::string& stream_id, - const std::string sender_id, - uint32_t ssrc) - : stream_id(stream_id), sender_id(sender_id), first_ssrc(ssrc) {} - bool operator==(const RtpSenderInfo& other) { - return this->stream_id == other.stream_id && - this->sender_id == other.sender_id && - this->first_ssrc == other.first_ssrc; - } - std::string stream_id; - std::string sender_id; - // An RtpSender can have many SSRCs. The first one is used as a sort of ID - // for communicating with the lower layers. - uint32_t first_ssrc; - }; - - // Plan B helpers for getting the voice/video media channels for the single - // audio/video transceiver, if it exists. - cricket::VoiceMediaChannel* voice_media_channel() const - RTC_RUN_ON(signaling_thread()); - cricket::VideoMediaChannel* video_media_channel() const - RTC_RUN_ON(signaling_thread()); - - std::vector>> - GetSendersInternal() const; - std::vector< - rtc::scoped_refptr>> - GetReceiversInternal() const RTC_RUN_ON(signaling_thread()); - - rtc::scoped_refptr> - GetAudioTransceiver() const; - rtc::scoped_refptr> - GetVideoTransceiver() const; - - rtc::scoped_refptr> - GetFirstAudioTransceiver() const RTC_RUN_ON(signaling_thread()); - - - void CreateAudioReceiver(MediaStreamInterface* stream, - const RtpSenderInfo& remote_sender_info) - RTC_RUN_ON(signaling_thread()); - - void CreateVideoReceiver(MediaStreamInterface* stream, - const RtpSenderInfo& remote_sender_info) - RTC_RUN_ON(signaling_thread()); - rtc::scoped_refptr RemoveAndStopReceiver( - const RtpSenderInfo& remote_sender_info) RTC_RUN_ON(signaling_thread()); - - // May be called either by AddStream/RemoveStream, or when a track is - // added/removed from a stream previously added via AddStream. - void AddAudioTrack(AudioTrackInterface* track, MediaStreamInterface* stream); - void RemoveAudioTrack(AudioTrackInterface* track, - MediaStreamInterface* stream); - void AddVideoTrack(VideoTrackInterface* track, MediaStreamInterface* stream); - void RemoveVideoTrack(VideoTrackInterface* track, - MediaStreamInterface* stream); - - // AddTrack implementation when Unified Plan is specified. - RTCErrorOr> AddTrackUnifiedPlan( - rtc::scoped_refptr track, - const std::vector& stream_ids) - RTC_RUN_ON(signaling_thread()); - // AddTrack implementation when Plan B is specified. - RTCErrorOr> AddTrackPlanB( - rtc::scoped_refptr track, - const std::vector& stream_ids) - RTC_RUN_ON(signaling_thread()); - - // Returns the first RtpTransceiver suitable for a newly added track, if such - // transceiver is available. - rtc::scoped_refptr> - FindFirstTransceiverForAddedTrack( - rtc::scoped_refptr track) - RTC_RUN_ON(signaling_thread()); - rtc::scoped_refptr> FindTransceiverBySender(rtc::scoped_refptr sender) RTC_RUN_ON(signaling_thread()); @@ -470,24 +399,6 @@ class PeerConnection : public PeerConnectionInternal, const RtpTransceiverInit& init, bool fire_callback = true); - rtc::scoped_refptr> - CreateSender(cricket::MediaType media_type, - const std::string& id, - rtc::scoped_refptr track, - const std::vector& stream_ids, - const std::vector& send_encodings); - - rtc::scoped_refptr> - CreateReceiver(cricket::MediaType media_type, const std::string& receiver_id); - - // Create a new RtpTransceiver of the given type and add it to the list of - // transceivers. - rtc::scoped_refptr> - CreateAndAddTransceiver( - rtc::scoped_refptr> sender, - rtc::scoped_refptr> - receiver); - void SetIceConnectionState(IceConnectionState new_state); void SetStandardizedIceConnectionState( PeerConnectionInterface::IceConnectionState new_state) @@ -539,36 +450,6 @@ class PeerConnection : public PeerConnectionInternal, // channels are configured this will return nullopt. absl::optional GetDataMid() const; - // Triggered when a remote sender has been seen for the first time in a remote - // session description. It creates a remote MediaStreamTrackInterface - // implementation and triggers CreateAudioReceiver or CreateVideoReceiver. - void OnRemoteSenderAdded(const RtpSenderInfo& sender_info, - MediaStreamInterface* stream, - cricket::MediaType media_type); - - // Triggered when a remote sender has been removed from a remote session - // description. It removes the remote sender with id |sender_id| from a remote - // MediaStream and triggers DestroyAudioReceiver or DestroyVideoReceiver. - void OnRemoteSenderRemoved(const RtpSenderInfo& sender_info, - MediaStreamInterface* stream, - cricket::MediaType media_type); - - // Triggered when a local sender has been seen for the first time in a local - // session description. - // This method triggers CreateAudioSender or CreateVideoSender if the rtp - // streams in the local SessionDescription can be mapped to a MediaStreamTrack - // in a MediaStream in |local_streams_| - void OnLocalSenderAdded(const RtpSenderInfo& sender_info, - cricket::MediaType media_type); - - // Triggered when a local sender has been removed from a local session - // description. - // This method triggers DestroyAudioSender or DestroyVideoSender if a stream - // has been removed from the local SessionDescription and the stream can be - // mapped to a MediaStreamTrack in a MediaStream in |local_streams_|. - void OnLocalSenderRemoved(const RtpSenderInfo& sender_info, - cricket::MediaType media_type); - // Returns true if the PeerConnection is configured to use Unified Plan // semantics for creating offers/answers and setting local/remote // descriptions. If this is true the RtpTransceiver API will also be available @@ -580,29 +461,6 @@ class PeerConnection : public PeerConnectionInternal, return configuration_.sdp_semantics == SdpSemantics::kUnifiedPlan; } - // Return the RtpSender with the given track attached. - rtc::scoped_refptr> - FindSenderForTrack(MediaStreamTrackInterface* track) const - RTC_RUN_ON(signaling_thread()); - - // Return the RtpSender with the given id, or null if none exists. - rtc::scoped_refptr> - FindSenderById(const std::string& sender_id) const - RTC_RUN_ON(signaling_thread()); - - // Return the RtpReceiver with the given id, or null if none exists. - rtc::scoped_refptr> - FindReceiverById(const std::string& receiver_id) const - RTC_RUN_ON(signaling_thread()); - - std::vector* GetRemoteSenderInfos( - cricket::MediaType media_type); - std::vector* GetLocalSenderInfos( - cricket::MediaType media_type); - const RtpSenderInfo* FindSenderInfo(const std::vector& infos, - const std::string& stream_id, - const std::string sender_id) const; - // Returns the specified SCTP DataChannel in sctp_data_channels_, // or nullptr if not found. SctpDataChannel* FindDataChannelBySid(int sid) const @@ -739,9 +597,6 @@ class PeerConnection : public PeerConnectionInternal, rtc::scoped_refptr dtls_transport, DataChannelTransportInterface* data_channel_transport) override; - // RtpSenderBase::SetStreamsObserver override. - void OnSetStreams() override; - // Returns the CryptoOptions for this PeerConnection. This will always // return the RTCConfiguration.crypto_options if set and will only default // back to the PeerConnectionFactory settings if nothing was set. @@ -806,16 +661,6 @@ class PeerConnection : public PeerConnectionInternal, tls_cert_verifier_; // TODO(bugs.webrtc.org/9987): Accessed on both // signaling and network thread. - // These lists store sender info seen in local/remote descriptions. - std::vector remote_audio_sender_infos_ - RTC_GUARDED_BY(signaling_thread()); - std::vector remote_video_sender_infos_ - RTC_GUARDED_BY(signaling_thread()); - std::vector local_audio_sender_infos_ - RTC_GUARDED_BY(signaling_thread()); - std::vector local_video_sender_infos_ - RTC_GUARDED_BY(signaling_thread()); - // The unique_ptr belongs to the worker thread, but the Call object manages // its own thread safety. std::unique_ptr call_ RTC_GUARDED_BY(worker_thread()); @@ -832,7 +677,6 @@ class PeerConnection : public PeerConnectionInternal, RTC_GUARDED_BY(signaling_thread()); // A pointer is passed to senders_ rtc::scoped_refptr stats_collector_ RTC_GUARDED_BY(signaling_thread()); - TransceiverList transceivers_; std::string session_id_ RTC_GUARDED_BY(signaling_thread()); @@ -882,6 +726,10 @@ class PeerConnection : public PeerConnectionInternal, // Machinery for handling messages posted to oneself PeerConnectionMessageHandler message_handler_; + + // Administration of senders, receivers and transceivers + // Accessed on both signaling and network thread. Const after Initialize(). + std::unique_ptr rtp_manager_; }; } // namespace webrtc diff --git a/pc/rtp_transmission_manager.cc b/pc/rtp_transmission_manager.cc new file mode 100644 index 0000000000..5c0e4d9c31 --- /dev/null +++ b/pc/rtp_transmission_manager.cc @@ -0,0 +1,692 @@ +/* + * Copyright 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "pc/rtp_transmission_manager.h" + +#include + +#include "absl/types/optional.h" +#include "api/peer_connection_interface.h" +#include "api/rtp_transceiver_direction.h" +#include "pc/audio_rtp_receiver.h" +#include "pc/channel.h" +#include "pc/stats_collector_interface.h" +#include "pc/video_rtp_receiver.h" +#include "rtc_base/checks.h" +#include "rtc_base/helpers.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +namespace { + +static const char kDefaultAudioSenderId[] = "defaulta0"; +static const char kDefaultVideoSenderId[] = "defaultv0"; + +} // namespace + +RtpTransmissionManager::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 on_negotiation_needed) + : is_unified_plan_(is_unified_plan), + signaling_thread_(signaling_thread), + worker_thread_(worker_thread), + channel_manager_(channel_manager), + usage_pattern_(usage_pattern), + observer_(observer), + stats_(stats), + on_negotiation_needed_(on_negotiation_needed) {} + +void RtpTransmissionManager::Close() { + closed_ = true; + observer_ = nullptr; +} + +// Implementation of SetStreamsObserver +void RtpTransmissionManager::OnSetStreams() { + RTC_DCHECK_RUN_ON(signaling_thread()); + if (IsUnifiedPlan()) + OnNegotiationNeeded(); +} + +// Function to call back to the PeerConnection when negotiation is needed +void RtpTransmissionManager::OnNegotiationNeeded() { + on_negotiation_needed_(); +} + +// Function that returns the currently valid observer +PeerConnectionObserver* RtpTransmissionManager::Observer() const { + RTC_DCHECK(!closed_); + RTC_DCHECK(observer_); + return observer_; +} + +cricket::VoiceMediaChannel* RtpTransmissionManager::voice_media_channel() + const { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(!IsUnifiedPlan()); + auto* voice_channel = static_cast( + GetAudioTransceiver()->internal()->channel()); + if (voice_channel) { + return voice_channel->media_channel(); + } else { + return nullptr; + } +} + +cricket::VideoMediaChannel* RtpTransmissionManager::video_media_channel() + const { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(!IsUnifiedPlan()); + auto* video_channel = static_cast( + GetVideoTransceiver()->internal()->channel()); + if (video_channel) { + return video_channel->media_channel(); + } else { + return nullptr; + } +} + +RTCErrorOr> +RtpTransmissionManager::AddTrack( + rtc::scoped_refptr track, + const std::vector& stream_ids) { + RTC_DCHECK_RUN_ON(signaling_thread()); + + return (IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids) + : AddTrackPlanB(track, stream_ids)); +} + +RTCErrorOr> +RtpTransmissionManager::AddTrackPlanB( + rtc::scoped_refptr track, + const std::vector& stream_ids) { + RTC_DCHECK_RUN_ON(signaling_thread()); + if (stream_ids.size() > 1u) { + LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, + "AddTrack with more than one stream is not " + "supported with Plan B semantics."); + } + std::vector adjusted_stream_ids = stream_ids; + if (adjusted_stream_ids.empty()) { + adjusted_stream_ids.push_back(rtc::CreateRandomUuid()); + } + cricket::MediaType media_type = + (track->kind() == MediaStreamTrackInterface::kAudioKind + ? cricket::MEDIA_TYPE_AUDIO + : cricket::MEDIA_TYPE_VIDEO); + auto new_sender = + CreateSender(media_type, track->id(), track, adjusted_stream_ids, {}); + if (track->kind() == MediaStreamTrackInterface::kAudioKind) { + new_sender->internal()->SetMediaChannel(voice_media_channel()); + GetAudioTransceiver()->internal()->AddSender(new_sender); + const RtpSenderInfo* sender_info = + FindSenderInfo(local_audio_sender_infos_, + new_sender->internal()->stream_ids()[0], track->id()); + if (sender_info) { + new_sender->internal()->SetSsrc(sender_info->first_ssrc); + } + } else { + RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind()); + new_sender->internal()->SetMediaChannel(video_media_channel()); + GetVideoTransceiver()->internal()->AddSender(new_sender); + const RtpSenderInfo* sender_info = + FindSenderInfo(local_video_sender_infos_, + new_sender->internal()->stream_ids()[0], track->id()); + if (sender_info) { + new_sender->internal()->SetSsrc(sender_info->first_ssrc); + } + } + return rtc::scoped_refptr(new_sender); +} + +RTCErrorOr> +RtpTransmissionManager::AddTrackUnifiedPlan( + rtc::scoped_refptr track, + const std::vector& stream_ids) { + auto transceiver = FindFirstTransceiverForAddedTrack(track); + if (transceiver) { + RTC_LOG(LS_INFO) << "Reusing an existing " + << cricket::MediaTypeToString(transceiver->media_type()) + << " transceiver for AddTrack."; + if (transceiver->stopping()) { + LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, + "The existing transceiver is stopping."); + } + + if (transceiver->direction() == RtpTransceiverDirection::kRecvOnly) { + transceiver->internal()->set_direction( + RtpTransceiverDirection::kSendRecv); + } else if (transceiver->direction() == RtpTransceiverDirection::kInactive) { + transceiver->internal()->set_direction( + RtpTransceiverDirection::kSendOnly); + } + transceiver->sender()->SetTrack(track); + transceiver->internal()->sender_internal()->set_stream_ids(stream_ids); + transceiver->internal()->set_reused_for_addtrack(true); + } else { + cricket::MediaType media_type = + (track->kind() == MediaStreamTrackInterface::kAudioKind + ? cricket::MEDIA_TYPE_AUDIO + : cricket::MEDIA_TYPE_VIDEO); + RTC_LOG(LS_INFO) << "Adding " << cricket::MediaTypeToString(media_type) + << " transceiver in response to a call to AddTrack."; + std::string sender_id = track->id(); + // Avoid creating a sender with an existing ID by generating a random ID. + // This can happen if this is the second time AddTrack has created a sender + // for this track. + if (FindSenderById(sender_id)) { + sender_id = rtc::CreateRandomUuid(); + } + auto sender = CreateSender(media_type, sender_id, track, stream_ids, {}); + auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid()); + transceiver = CreateAndAddTransceiver(sender, receiver); + transceiver->internal()->set_created_by_addtrack(true); + transceiver->internal()->set_direction(RtpTransceiverDirection::kSendRecv); + } + return transceiver->sender(); +} + +rtc::scoped_refptr> +RtpTransmissionManager::CreateSender( + cricket::MediaType media_type, + const std::string& id, + rtc::scoped_refptr track, + const std::vector& stream_ids, + const std::vector& send_encodings) { + RTC_DCHECK_RUN_ON(signaling_thread()); + rtc::scoped_refptr> sender; + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + RTC_DCHECK(!track || + (track->kind() == MediaStreamTrackInterface::kAudioKind)); + sender = RtpSenderProxyWithInternal::Create( + signaling_thread(), + AudioRtpSender::Create(worker_thread(), id, stats_, this)); + NoteUsageEvent(UsageEvent::AUDIO_ADDED); + } else { + RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO); + RTC_DCHECK(!track || + (track->kind() == MediaStreamTrackInterface::kVideoKind)); + sender = RtpSenderProxyWithInternal::Create( + signaling_thread(), VideoRtpSender::Create(worker_thread(), id, this)); + NoteUsageEvent(UsageEvent::VIDEO_ADDED); + } + bool set_track_succeeded = sender->SetTrack(track); + RTC_DCHECK(set_track_succeeded); + sender->internal()->set_stream_ids(stream_ids); + sender->internal()->set_init_send_encodings(send_encodings); + return sender; +} + +rtc::scoped_refptr> +RtpTransmissionManager::CreateReceiver(cricket::MediaType media_type, + const std::string& receiver_id) { + RTC_DCHECK_RUN_ON(signaling_thread()); + rtc::scoped_refptr> + receiver; + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + receiver = RtpReceiverProxyWithInternal::Create( + signaling_thread(), new AudioRtpReceiver(worker_thread(), receiver_id, + std::vector({}))); + NoteUsageEvent(UsageEvent::AUDIO_ADDED); + } else { + RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO); + receiver = RtpReceiverProxyWithInternal::Create( + signaling_thread(), new VideoRtpReceiver(worker_thread(), receiver_id, + std::vector({}))); + NoteUsageEvent(UsageEvent::VIDEO_ADDED); + } + return receiver; +} + +rtc::scoped_refptr> +RtpTransmissionManager::CreateAndAddTransceiver( + rtc::scoped_refptr> sender, + rtc::scoped_refptr> + receiver) { + RTC_DCHECK_RUN_ON(signaling_thread()); + // Ensure that the new sender does not have an ID that is already in use by + // another sender. + // Allow receiver IDs to conflict since those come from remote SDP (which + // could be invalid, but should not cause a crash). + RTC_DCHECK(!FindSenderById(sender->id())); + auto transceiver = RtpTransceiverProxyWithInternal::Create( + signaling_thread(), + new RtpTransceiver( + sender, receiver, channel_manager(), + sender->media_type() == cricket::MEDIA_TYPE_AUDIO + ? channel_manager()->GetSupportedAudioRtpHeaderExtensions() + : channel_manager()->GetSupportedVideoRtpHeaderExtensions())); + transceivers()->Add(transceiver); + transceiver->internal()->SignalNegotiationNeeded.connect( + this, &RtpTransmissionManager::OnNegotiationNeeded); + return transceiver; +} + +rtc::scoped_refptr> +RtpTransmissionManager::FindFirstTransceiverForAddedTrack( + rtc::scoped_refptr track) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(track); + for (auto transceiver : transceivers()->List()) { + if (!transceiver->sender()->track() && + cricket::MediaTypeToString(transceiver->media_type()) == + track->kind() && + !transceiver->internal()->has_ever_been_used_to_send() && + !transceiver->stopped()) { + return transceiver; + } + } + return nullptr; +} + +std::vector>> +RtpTransmissionManager::GetSendersInternal() const { + RTC_DCHECK_RUN_ON(signaling_thread()); + std::vector>> + all_senders; + for (const auto& transceiver : transceivers_.List()) { + if (IsUnifiedPlan() && transceiver->internal()->stopped()) + continue; + + auto senders = transceiver->internal()->senders(); + all_senders.insert(all_senders.end(), senders.begin(), senders.end()); + } + return all_senders; +} + +std::vector< + rtc::scoped_refptr>> +RtpTransmissionManager::GetReceiversInternal() const { + RTC_DCHECK_RUN_ON(signaling_thread()); + std::vector< + rtc::scoped_refptr>> + all_receivers; + for (const auto& transceiver : transceivers_.List()) { + if (IsUnifiedPlan() && transceiver->internal()->stopped()) + continue; + + auto receivers = transceiver->internal()->receivers(); + all_receivers.insert(all_receivers.end(), receivers.begin(), + receivers.end()); + } + return all_receivers; +} + +rtc::scoped_refptr> +RtpTransmissionManager::GetAudioTransceiver() const { + RTC_DCHECK_RUN_ON(signaling_thread()); + // This method only works with Plan B SDP, where there is a single + // audio/video transceiver. + RTC_DCHECK(!IsUnifiedPlan()); + for (auto transceiver : transceivers_.List()) { + if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { + return transceiver; + } + } + RTC_NOTREACHED(); + return nullptr; +} + +rtc::scoped_refptr> +RtpTransmissionManager::GetVideoTransceiver() const { + RTC_DCHECK_RUN_ON(signaling_thread()); + // This method only works with Plan B SDP, where there is a single + // audio/video transceiver. + RTC_DCHECK(!IsUnifiedPlan()); + for (auto transceiver : transceivers_.List()) { + if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) { + return transceiver; + } + } + RTC_NOTREACHED(); + return nullptr; +} + +void RtpTransmissionManager::AddAudioTrack(AudioTrackInterface* track, + MediaStreamInterface* stream) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(track); + RTC_DCHECK(stream); + auto sender = FindSenderForTrack(track); + if (sender) { + // We already have a sender for this track, so just change the stream_id + // so that it's correct in the next call to CreateOffer. + sender->internal()->set_stream_ids({stream->id()}); + return; + } + + // Normal case; we've never seen this track before. + auto new_sender = CreateSender(cricket::MEDIA_TYPE_AUDIO, track->id(), track, + {stream->id()}, {}); + new_sender->internal()->SetMediaChannel(voice_media_channel()); + GetAudioTransceiver()->internal()->AddSender(new_sender); + // If the sender has already been configured in SDP, we call SetSsrc, + // which will connect the sender to the underlying transport. This can + // occur if a local session description that contains the ID of the sender + // is set before AddStream is called. It can also occur if the local + // session description is not changed and RemoveStream is called, and + // later AddStream is called again with the same stream. + const RtpSenderInfo* sender_info = + FindSenderInfo(local_audio_sender_infos_, stream->id(), track->id()); + if (sender_info) { + new_sender->internal()->SetSsrc(sender_info->first_ssrc); + } +} + +// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around +// indefinitely, when we have unified plan SDP. +void RtpTransmissionManager::RemoveAudioTrack(AudioTrackInterface* track, + MediaStreamInterface* stream) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(!IsUnifiedPlan()); + auto sender = FindSenderForTrack(track); + if (!sender) { + RTC_LOG(LS_WARNING) << "RtpSender for track with id " << track->id() + << " doesn't exist."; + return; + } + GetAudioTransceiver()->internal()->RemoveSender(sender); +} + +void RtpTransmissionManager::AddVideoTrack(VideoTrackInterface* track, + MediaStreamInterface* stream) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(track); + RTC_DCHECK(stream); + auto sender = FindSenderForTrack(track); + if (sender) { + // We already have a sender for this track, so just change the stream_id + // so that it's correct in the next call to CreateOffer. + sender->internal()->set_stream_ids({stream->id()}); + return; + } + + // Normal case; we've never seen this track before. + auto new_sender = CreateSender(cricket::MEDIA_TYPE_VIDEO, track->id(), track, + {stream->id()}, {}); + new_sender->internal()->SetMediaChannel(video_media_channel()); + GetVideoTransceiver()->internal()->AddSender(new_sender); + const RtpSenderInfo* sender_info = + FindSenderInfo(local_video_sender_infos_, stream->id(), track->id()); + if (sender_info) { + new_sender->internal()->SetSsrc(sender_info->first_ssrc); + } +} + +void RtpTransmissionManager::RemoveVideoTrack(VideoTrackInterface* track, + MediaStreamInterface* stream) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(!IsUnifiedPlan()); + auto sender = FindSenderForTrack(track); + if (!sender) { + RTC_LOG(LS_WARNING) << "RtpSender for track with id " << track->id() + << " doesn't exist."; + return; + } + GetVideoTransceiver()->internal()->RemoveSender(sender); +} + +rtc::scoped_refptr> +RtpTransmissionManager::GetFirstAudioTransceiver() const { + RTC_DCHECK_RUN_ON(signaling_thread()); + for (auto transceiver : transceivers_.List()) { + if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { + return transceiver; + } + } + return nullptr; +} + +void RtpTransmissionManager::CreateAudioReceiver( + MediaStreamInterface* stream, + const RtpSenderInfo& remote_sender_info) { + RTC_DCHECK(!closed_); + std::vector> streams; + streams.push_back(rtc::scoped_refptr(stream)); + // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use + // the constructor taking stream IDs instead. + auto* audio_receiver = new AudioRtpReceiver( + worker_thread(), remote_sender_info.sender_id, streams); + audio_receiver->SetMediaChannel(voice_media_channel()); + if (remote_sender_info.sender_id == kDefaultAudioSenderId) { + audio_receiver->SetupUnsignaledMediaChannel(); + } else { + audio_receiver->SetupMediaChannel(remote_sender_info.first_ssrc); + } + auto receiver = RtpReceiverProxyWithInternal::Create( + signaling_thread(), audio_receiver); + GetAudioTransceiver()->internal()->AddReceiver(receiver); + Observer()->OnAddTrack(receiver, streams); + NoteUsageEvent(UsageEvent::AUDIO_ADDED); +} + +void RtpTransmissionManager::CreateVideoReceiver( + MediaStreamInterface* stream, + const RtpSenderInfo& remote_sender_info) { + RTC_DCHECK(!closed_); + std::vector> streams; + streams.push_back(rtc::scoped_refptr(stream)); + // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use + // the constructor taking stream IDs instead. + auto* video_receiver = new VideoRtpReceiver( + worker_thread(), remote_sender_info.sender_id, streams); + video_receiver->SetMediaChannel(video_media_channel()); + if (remote_sender_info.sender_id == kDefaultVideoSenderId) { + video_receiver->SetupUnsignaledMediaChannel(); + } else { + video_receiver->SetupMediaChannel(remote_sender_info.first_ssrc); + } + auto receiver = RtpReceiverProxyWithInternal::Create( + signaling_thread(), video_receiver); + GetVideoTransceiver()->internal()->AddReceiver(receiver); + Observer()->OnAddTrack(receiver, streams); + NoteUsageEvent(UsageEvent::VIDEO_ADDED); +} + +// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote +// description. +rtc::scoped_refptr +RtpTransmissionManager::RemoveAndStopReceiver( + const RtpSenderInfo& remote_sender_info) { + auto receiver = FindReceiverById(remote_sender_info.sender_id); + if (!receiver) { + RTC_LOG(LS_WARNING) << "RtpReceiver for track with id " + << remote_sender_info.sender_id << " doesn't exist."; + return nullptr; + } + if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { + GetAudioTransceiver()->internal()->RemoveReceiver(receiver); + } else { + GetVideoTransceiver()->internal()->RemoveReceiver(receiver); + } + return receiver; +} + +void RtpTransmissionManager::OnRemoteSenderAdded( + const RtpSenderInfo& sender_info, + MediaStreamInterface* stream, + cricket::MediaType media_type) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_LOG(LS_INFO) << "Creating " << cricket::MediaTypeToString(media_type) + << " receiver for track_id=" << sender_info.sender_id + << " and stream_id=" << sender_info.stream_id; + + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + CreateAudioReceiver(stream, sender_info); + } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { + CreateVideoReceiver(stream, sender_info); + } else { + RTC_NOTREACHED() << "Invalid media type"; + } +} + +void RtpTransmissionManager::OnRemoteSenderRemoved( + const RtpSenderInfo& sender_info, + MediaStreamInterface* stream, + cricket::MediaType media_type) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_LOG(LS_INFO) << "Removing " << cricket::MediaTypeToString(media_type) + << " receiver for track_id=" << sender_info.sender_id + << " and stream_id=" << sender_info.stream_id; + + rtc::scoped_refptr receiver; + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + // When the MediaEngine audio channel is destroyed, the RemoteAudioSource + // will be notified which will end the AudioRtpReceiver::track(). + receiver = RemoveAndStopReceiver(sender_info); + rtc::scoped_refptr audio_track = + stream->FindAudioTrack(sender_info.sender_id); + if (audio_track) { + stream->RemoveTrack(audio_track); + } + } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { + // Stopping or destroying a VideoRtpReceiver will end the + // VideoRtpReceiver::track(). + receiver = RemoveAndStopReceiver(sender_info); + rtc::scoped_refptr video_track = + stream->FindVideoTrack(sender_info.sender_id); + if (video_track) { + // There's no guarantee the track is still available, e.g. the track may + // have been removed from the stream by an application. + stream->RemoveTrack(video_track); + } + } else { + RTC_NOTREACHED() << "Invalid media type"; + } + if (receiver) { + RTC_DCHECK(!closed_); + Observer()->OnRemoveTrack(receiver); + } +} + +void RtpTransmissionManager::OnLocalSenderAdded( + const RtpSenderInfo& sender_info, + cricket::MediaType media_type) { + RTC_DCHECK_RUN_ON(signaling_thread()); + RTC_DCHECK(!IsUnifiedPlan()); + auto sender = FindSenderById(sender_info.sender_id); + if (!sender) { + RTC_LOG(LS_WARNING) << "An unknown RtpSender with id " + << sender_info.sender_id + << " has been configured in the local description."; + return; + } + + if (sender->media_type() != media_type) { + RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local" + " description with an unexpected media type."; + return; + } + + sender->internal()->set_stream_ids({sender_info.stream_id}); + sender->internal()->SetSsrc(sender_info.first_ssrc); +} + +void RtpTransmissionManager::OnLocalSenderRemoved( + const RtpSenderInfo& sender_info, + cricket::MediaType media_type) { + RTC_DCHECK_RUN_ON(signaling_thread()); + auto sender = FindSenderById(sender_info.sender_id); + if (!sender) { + // This is the normal case. I.e., RemoveStream has been called and the + // SessionDescriptions has been renegotiated. + return; + } + + // A sender has been removed from the SessionDescription but it's still + // associated with the PeerConnection. This only occurs if the SDP doesn't + // match with the calls to CreateSender, AddStream and RemoveStream. + if (sender->media_type() != media_type) { + RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local" + " description with an unexpected media type."; + return; + } + + sender->internal()->SetSsrc(0); +} + +std::vector* RtpTransmissionManager::GetRemoteSenderInfos( + cricket::MediaType media_type) { + RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO || + media_type == cricket::MEDIA_TYPE_VIDEO); + return (media_type == cricket::MEDIA_TYPE_AUDIO) + ? &remote_audio_sender_infos_ + : &remote_video_sender_infos_; +} + +std::vector* RtpTransmissionManager::GetLocalSenderInfos( + cricket::MediaType media_type) { + RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO || + media_type == cricket::MEDIA_TYPE_VIDEO); + return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_sender_infos_ + : &local_video_sender_infos_; +} + +const RtpSenderInfo* RtpTransmissionManager::FindSenderInfo( + const std::vector& infos, + const std::string& stream_id, + const std::string sender_id) const { + for (const RtpSenderInfo& sender_info : infos) { + if (sender_info.stream_id == stream_id && + sender_info.sender_id == sender_id) { + return &sender_info; + } + } + return nullptr; +} + +rtc::scoped_refptr> +RtpTransmissionManager::FindSenderForTrack( + MediaStreamTrackInterface* track) const { + RTC_DCHECK_RUN_ON(signaling_thread()); + for (const auto& transceiver : transceivers_.List()) { + for (auto sender : transceiver->internal()->senders()) { + if (sender->track() == track) { + return sender; + } + } + } + return nullptr; +} + +rtc::scoped_refptr> +RtpTransmissionManager::FindSenderById(const std::string& sender_id) const { + RTC_DCHECK_RUN_ON(signaling_thread()); + for (const auto& transceiver : transceivers_.List()) { + for (auto sender : transceiver->internal()->senders()) { + if (sender->id() == sender_id) { + return sender; + } + } + } + return nullptr; +} + +rtc::scoped_refptr> +RtpTransmissionManager::FindReceiverById(const std::string& receiver_id) const { + RTC_DCHECK_RUN_ON(signaling_thread()); + for (const auto& transceiver : transceivers_.List()) { + for (auto receiver : transceiver->internal()->receivers()) { + if (receiver->id() == receiver_id) { + return receiver; + } + } + } + return nullptr; +} + +} // namespace webrtc diff --git a/pc/rtp_transmission_manager.h b/pc/rtp_transmission_manager.h new file mode 100644 index 0000000000..7aa410c51b --- /dev/null +++ b/pc/rtp_transmission_manager.h @@ -0,0 +1,270 @@ +/* + * Copyright 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef PC_RTP_TRANSMISSION_MANAGER_H_ +#define PC_RTP_TRANSMISSION_MANAGER_H_ + +#include +#include +#include +#include + +#include "api/media_stream_interface.h" +#include "api/media_types.h" +#include "api/peer_connection_interface.h" +#include "api/rtc_error.h" +#include "api/rtp_parameters.h" +#include "api/rtp_receiver_interface.h" +#include "api/rtp_sender_interface.h" +#include "api/scoped_refptr.h" +#include "media/base/media_channel.h" +#include "pc/channel_manager.h" +#include "pc/rtp_receiver.h" +#include "pc/rtp_sender.h" +#include "pc/rtp_transceiver.h" +#include "pc/stats_collector_interface.h" +#include "pc/transceiver_list.h" +#include "pc/usage_pattern.h" +#include "rtc_base/synchronization/sequence_checker.h" +#include "rtc_base/third_party/sigslot/sigslot.h" +#include "rtc_base/thread.h" +#include "rtc_base/thread_annotations.h" + +namespace rtc { +class Thread; +} + +namespace webrtc { + +// This class contains information about +// an RTPSender, used for things like looking it up by SSRC. +struct RtpSenderInfo { + RtpSenderInfo() : first_ssrc(0) {} + RtpSenderInfo(const std::string& stream_id, + const std::string sender_id, + uint32_t ssrc) + : stream_id(stream_id), sender_id(sender_id), first_ssrc(ssrc) {} + bool operator==(const RtpSenderInfo& other) { + return this->stream_id == other.stream_id && + this->sender_id == other.sender_id && + this->first_ssrc == other.first_ssrc; + } + std::string stream_id; + std::string sender_id; + // An RtpSender can have many SSRCs. The first one is used as a sort of ID + // for communicating with the lower layers. + uint32_t first_ssrc; +}; + +// The RtpTransmissionManager class is responsible for managing the lifetime +// and relationships between objects of type RtpSender, RtpReceiver and +// RtpTransceiver. +class RtpTransmissionManager : public RtpSenderBase::SetStreamsObserver, + public sigslot::has_slots<> { + public: + 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 on_negotiation_needed); + + // No move or copy permitted. + RtpTransmissionManager(const RtpTransmissionManager&) = delete; + RtpTransmissionManager& operator=(const RtpTransmissionManager&) = delete; + + // Stop activity. In particular, don't call observer_ any more. + void Close(); + + // RtpSenderBase::SetStreamsObserver override. + void OnSetStreams() override; + + // Add a new track, creating transceiver if required. + RTCErrorOr> AddTrack( + rtc::scoped_refptr track, + const std::vector& stream_ids); + + // Create a new RTP sender. Does not associate with a transceiver. + rtc::scoped_refptr> + CreateSender(cricket::MediaType media_type, + const std::string& id, + rtc::scoped_refptr track, + const std::vector& stream_ids, + const std::vector& send_encodings); + + // Create a new RTP receiver. Does not associate with a transceiver. + rtc::scoped_refptr> + CreateReceiver(cricket::MediaType media_type, const std::string& receiver_id); + + // Create a new RtpTransceiver of the given type and add it to the list of + // registered transceivers. + rtc::scoped_refptr> + CreateAndAddTransceiver( + rtc::scoped_refptr> sender, + rtc::scoped_refptr> + receiver); + + // Returns the first RtpTransceiver suitable for a newly added track, if such + // transceiver is available. + rtc::scoped_refptr> + FindFirstTransceiverForAddedTrack( + rtc::scoped_refptr track); + + // Returns the list of senders currently associated with some + // registered transceiver + std::vector>> + GetSendersInternal() const; + + // Returns the list of receivers currently associated with a transceiver + std::vector< + rtc::scoped_refptr>> + GetReceiversInternal() const; + + // Plan B: Get the transceiver containing all audio senders and receivers + rtc::scoped_refptr> + GetAudioTransceiver() const; + // Plan B: Get the transceiver containing all video senders and receivers + rtc::scoped_refptr> + GetVideoTransceiver() const; + + // Gets the first audio transceiver. + rtc::scoped_refptr> + GetFirstAudioTransceiver() const; + + // Add an audio track, reusing or creating the sender. + void AddAudioTrack(AudioTrackInterface* track, MediaStreamInterface* stream); + // Plan B: Remove an audio track, removing the sender. + void RemoveAudioTrack(AudioTrackInterface* track, + MediaStreamInterface* stream); + // Add a video track, reusing or creating the sender. + void AddVideoTrack(VideoTrackInterface* track, MediaStreamInterface* stream); + // Plan B: Remove a video track, removing the sender. + void RemoveVideoTrack(VideoTrackInterface* track, + MediaStreamInterface* stream); + + // Triggered when a remote sender has been seen for the first time in a remote + // session description. It creates a remote MediaStreamTrackInterface + // implementation and triggers CreateAudioReceiver or CreateVideoReceiver. + void OnRemoteSenderAdded(const RtpSenderInfo& sender_info, + MediaStreamInterface* stream, + cricket::MediaType media_type); + + // Triggered when a remote sender has been removed from a remote session + // description. It removes the remote sender with id |sender_id| from a remote + // MediaStream and triggers DestroyAudioReceiver or DestroyVideoReceiver. + void OnRemoteSenderRemoved(const RtpSenderInfo& sender_info, + MediaStreamInterface* stream, + cricket::MediaType media_type); + + // Triggered when a local sender has been seen for the first time in a local + // session description. + // This method triggers CreateAudioSender or CreateVideoSender if the rtp + // streams in the local SessionDescription can be mapped to a MediaStreamTrack + // in a MediaStream in |local_streams_| + void OnLocalSenderAdded(const RtpSenderInfo& sender_info, + cricket::MediaType media_type); + + // Triggered when a local sender has been removed from a local session + // description. + // This method triggers DestroyAudioSender or DestroyVideoSender if a stream + // has been removed from the local SessionDescription and the stream can be + // mapped to a MediaStreamTrack in a MediaStream in |local_streams_|. + void OnLocalSenderRemoved(const RtpSenderInfo& sender_info, + cricket::MediaType media_type); + + std::vector* GetRemoteSenderInfos( + cricket::MediaType media_type); + std::vector* GetLocalSenderInfos( + cricket::MediaType media_type); + const RtpSenderInfo* FindSenderInfo(const std::vector& infos, + const std::string& stream_id, + const std::string sender_id) const; + + // Return the RtpSender with the given track attached. + rtc::scoped_refptr> + FindSenderForTrack(MediaStreamTrackInterface* track) const; + + // Return the RtpSender with the given id, or null if none exists. + rtc::scoped_refptr> + FindSenderById(const std::string& sender_id) const; + + // Return the RtpReceiver with the given id, or null if none exists. + rtc::scoped_refptr> + FindReceiverById(const std::string& receiver_id) const; + + TransceiverList* transceivers() { return &transceivers_; } + const TransceiverList* transceivers() const { return &transceivers_; } + + // Plan B helpers for getting the voice/video media channels for the single + // audio/video transceiver, if it exists. + cricket::VoiceMediaChannel* voice_media_channel() const; + cricket::VideoMediaChannel* video_media_channel() const; + + private: + rtc::Thread* signaling_thread() const { return signaling_thread_; } + rtc::Thread* worker_thread() const { return worker_thread_; } + cricket::ChannelManager* channel_manager() const { return channel_manager_; } + bool IsUnifiedPlan() const { return is_unified_plan_; } + void NoteUsageEvent(UsageEvent event) { + usage_pattern_->NoteUsageEvent(event); + } + + // AddTrack implementation when Unified Plan is specified. + RTCErrorOr> AddTrackUnifiedPlan( + rtc::scoped_refptr track, + const std::vector& stream_ids); + // AddTrack implementation when Plan B is specified. + RTCErrorOr> AddTrackPlanB( + rtc::scoped_refptr track, + const std::vector& stream_ids); + + // Create an RtpReceiver that sources an audio track. + void CreateAudioReceiver(MediaStreamInterface* stream, + const RtpSenderInfo& remote_sender_info) + RTC_RUN_ON(signaling_thread()); + + // Create an RtpReceiver that sources a video track. + void CreateVideoReceiver(MediaStreamInterface* stream, + const RtpSenderInfo& remote_sender_info) + RTC_RUN_ON(signaling_thread()); + rtc::scoped_refptr RemoveAndStopReceiver( + const RtpSenderInfo& remote_sender_info) RTC_RUN_ON(signaling_thread()); + + PeerConnectionObserver* Observer() const; + void OnNegotiationNeeded(); + + TransceiverList transceivers_; + + // These lists store sender info seen in local/remote descriptions. + std::vector remote_audio_sender_infos_ + RTC_GUARDED_BY(signaling_thread()); + std::vector remote_video_sender_infos_ + RTC_GUARDED_BY(signaling_thread()); + std::vector local_audio_sender_infos_ + RTC_GUARDED_BY(signaling_thread()); + std::vector local_video_sender_infos_ + RTC_GUARDED_BY(signaling_thread()); + + bool closed_ = false; + bool const is_unified_plan_; + rtc::Thread* signaling_thread_; + rtc::Thread* worker_thread_; + cricket::ChannelManager* channel_manager_; + UsagePattern* usage_pattern_; + PeerConnectionObserver* observer_; + StatsCollectorInterface* const stats_; + std::function on_negotiation_needed_; +}; + +} // namespace webrtc + +#endif // PC_RTP_TRANSMISSION_MANAGER_H_ diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc index d7863d7424..5197a69025 100644 --- a/pc/sdp_offer_answer.cc +++ b/pc/sdp_offer_answer.cc @@ -947,11 +947,17 @@ SdpOfferAnswerHandler::~SdpOfferAnswerHandler() {} cricket::ChannelManager* SdpOfferAnswerHandler::channel_manager() const { return pc_->channel_manager(); } -TransceiverList& SdpOfferAnswerHandler::transceivers() { - return pc_->transceivers_; +TransceiverList* SdpOfferAnswerHandler::transceivers() { + if (!pc_->rtp_manager()) { + return nullptr; + } + return pc_->rtp_manager()->transceivers(); } -const TransceiverList& SdpOfferAnswerHandler::transceivers() const { - return pc_->transceivers_; +const TransceiverList* SdpOfferAnswerHandler::transceivers() const { + if (!pc_->rtp_manager()) { + return nullptr; + } + return pc_->rtp_manager()->transceivers(); } JsepTransportController* SdpOfferAnswerHandler::transport_controller() { return pc_->transport_controller_.get(); @@ -969,6 +975,12 @@ cricket::PortAllocator* SdpOfferAnswerHandler::port_allocator() { const cricket::PortAllocator* SdpOfferAnswerHandler::port_allocator() const { return pc_->port_allocator_.get(); } +RtpTransmissionManager* SdpOfferAnswerHandler::rtp_manager() { + return pc_->rtp_manager(); +} +const RtpTransmissionManager* SdpOfferAnswerHandler::rtp_manager() const { + return pc_->rtp_manager(); +} // =================================================================== @@ -1211,7 +1223,7 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription( } std::vector> remove_list; std::vector> removed_streams; - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { if (transceiver->stopped()) { continue; } @@ -1300,7 +1312,7 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription( } if (IsUnifiedPlan()) { - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { if (transceiver->stopped()) { continue; } @@ -1577,7 +1589,7 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription( std::vector> remove_list; std::vector> added_streams; std::vector> removed_streams; - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { const ContentInfo* content = FindMediaSectionForTransceiver(transceiver, remote_description()); if (!content) { @@ -1597,7 +1609,7 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription( stream_ids = media_desc->streams()[0].stream_ids(); } transceivers() - .StableState(transceiver) + ->StableState(transceiver) ->SetRemoteStreamIdsIfUnset(transceiver->receiver()->stream_ids()); RTC_LOG(LS_INFO) << "Processing the MSIDs for MID=" << content->name @@ -2401,7 +2413,7 @@ RTCError SdpOfferAnswerHandler::UpdateSessionState( } else { RTC_DCHECK(type == SdpType::kAnswer); ChangeSignalingState(PeerConnectionInterface::kStable); - transceivers().DiscardStableStates(); + transceivers()->DiscardStableStates(); have_pending_rtp_data_channel_ = false; } @@ -2492,10 +2504,10 @@ bool SdpOfferAnswerHandler::AddStream(MediaStreamInterface* local_stream) { stream_observers_.push_back(std::unique_ptr(observer)); for (const auto& track : local_stream->GetAudioTracks()) { - pc_->AddAudioTrack(track.get(), local_stream); + rtp_manager()->AddAudioTrack(track.get(), local_stream); } for (const auto& track : local_stream->GetVideoTracks()) { - pc_->AddVideoTrack(track.get(), local_stream); + rtp_manager()->AddVideoTrack(track.get(), local_stream); } pc_->stats()->AddStream(local_stream); @@ -2511,10 +2523,10 @@ void SdpOfferAnswerHandler::RemoveStream(MediaStreamInterface* local_stream) { TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream"); if (!pc_->IsClosed()) { for (const auto& track : local_stream->GetAudioTracks()) { - pc_->RemoveAudioTrack(track.get(), local_stream); + rtp_manager()->RemoveAudioTrack(track.get(), local_stream); } for (const auto& track : local_stream->GetVideoTracks()) { - pc_->RemoveVideoTrack(track.get(), local_stream); + rtp_manager()->RemoveVideoTrack(track.get(), local_stream); } } local_streams_->RemoveStream(local_stream); @@ -2546,7 +2558,7 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) { std::vector> all_removed_streams; std::vector> removed_receivers; - for (auto&& transceivers_stable_state_pair : transceivers().StableStates()) { + for (auto&& transceivers_stable_state_pair : transceivers()->StableStates()) { auto transceiver = transceivers_stable_state_pair.first; auto state = transceivers_stable_state_pair.second; @@ -2577,7 +2589,7 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) { if (transceiver->internal()->reused_for_addtrack()) { transceiver->internal()->set_created_by_addtrack(true); } else { - transceivers().Remove(transceiver); + transceivers()->Remove(transceiver); } } transceiver->internal()->sender_internal()->set_transport(nullptr); @@ -2590,7 +2602,7 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) { DestroyDataChannelTransport(); have_pending_rtp_data_channel_ = false; } - transceivers().DiscardStableStates(); + transceivers()->DiscardStableStates(); pending_local_description_.reset(); pending_remote_description_.reset(); ChangeSignalingState(PeerConnectionInterface::kStable); @@ -2742,7 +2754,7 @@ bool SdpOfferAnswerHandler::CheckIfNegotiationIsNeeded() { // 5. For each transceiver in connection's set of transceivers, perform the // following checks: - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { const ContentInfo* current_local_msection = FindTransceiverMSection(transceiver.get(), description); @@ -3060,27 +3072,27 @@ SdpOfferAnswerHandler::AssociateTransceiver( // If this is an offer then the m= section might be recycled. If the m= // section is being recycled (defined as: rejected in the current local or // remote description and not rejected in new description), the transceiver - // should have been removed by RemoveStoppedTransceivers(). + // should have been removed by RemoveStoppedtransceivers()-> if (IsMediaSectionBeingRecycled(type, content, old_local_content, old_remote_content)) { const std::string& old_mid = (old_local_content && old_local_content->rejected) ? old_local_content->name : old_remote_content->name; - auto old_transceiver = transceivers().FindByMid(old_mid); + auto old_transceiver = transceivers()->FindByMid(old_mid); // The transceiver should be disassociated in RemoveStoppedTransceivers() RTC_DCHECK(!old_transceiver); } #endif const MediaContentDescription* media_desc = content.media_description(); - auto transceiver = transceivers().FindByMid(content.name); + auto transceiver = transceivers()->FindByMid(content.name); if (source == cricket::CS_LOCAL) { // Find the RtpTransceiver that corresponds to this m= section, using the // mapping between transceivers and m= section indices established when // creating the offer. if (!transceiver) { - transceiver = transceivers().FindByMLineIndex(mline_index); + transceiver = transceivers()->FindByMLineIndex(mline_index); } if (!transceiver) { // This may happen normally when media sections are rejected. @@ -3109,20 +3121,21 @@ SdpOfferAnswerHandler::AssociateTransceiver( std::string sender_id = rtc::CreateRandomUuid(); std::vector send_encodings = GetSendEncodingsFromRemoteDescription(*media_desc); - auto sender = pc_->CreateSender(media_desc->type(), sender_id, nullptr, - {}, send_encodings); + auto sender = rtp_manager()->CreateSender(media_desc->type(), sender_id, + nullptr, {}, send_encodings); std::string receiver_id; if (!media_desc->streams().empty()) { receiver_id = media_desc->streams()[0].id; } else { receiver_id = rtc::CreateRandomUuid(); } - auto receiver = pc_->CreateReceiver(media_desc->type(), receiver_id); - transceiver = pc_->CreateAndAddTransceiver(sender, receiver); + auto receiver = + rtp_manager()->CreateReceiver(media_desc->type(), receiver_id); + transceiver = rtp_manager()->CreateAndAddTransceiver(sender, receiver); transceiver->internal()->set_direction( RtpTransceiverDirection::kRecvOnly); if (type == SdpType::kOffer) { - transceivers().StableState(transceiver)->set_newly_created(); + transceivers()->StableState(transceiver)->set_newly_created(); } } @@ -3166,7 +3179,7 @@ SdpOfferAnswerHandler::AssociateTransceiver( transceiver->internal()->mline_index() != mline_index; if (state_changes) { transceivers() - .StableState(transceiver) + ->StableState(transceiver) ->SetMSectionIfUnset(transceiver->internal()->mid(), transceiver->internal()->mline_index()); } @@ -3337,7 +3350,7 @@ SdpOfferAnswerHandler::FindAvailableTransceiverToReceive( // the same type that were added to the PeerConnection by addTrack and are not // associated with any m= section and are not stopped, find the first such // RtpTransceiver. - for (auto transceiver : transceivers().List()) { + for (auto transceiver : transceivers()->List()) { if (transceiver->media_type() == media_type && transceiver->internal()->created_by_addtrack() && !transceiver->mid() && !transceiver->stopped()) { @@ -3421,8 +3434,10 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBOffer( const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options, cricket::MediaSessionOptions* session_options) { // Figure out transceiver directional preferences. - bool send_audio = !pc_->GetAudioTransceiver()->internal()->senders().empty(); - bool send_video = !pc_->GetVideoTransceiver()->internal()->senders().empty(); + bool send_audio = + !rtp_manager()->GetAudioTransceiver()->internal()->senders().empty(); + bool send_video = + !rtp_manager()->GetVideoTransceiver()->internal()->senders().empty(); // By default, generate sendrecv/recvonly m= sections. bool recv_audio = true; @@ -3496,7 +3511,7 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBOffer( !video_index ? nullptr : &session_options->media_description_options[*video_index]; - AddPlanBRtpSenderOptions(pc_->GetSendersInternal(), + AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(), audio_media_description_options, video_media_description_options, offer_answer_options.num_simulcast_layers); @@ -3545,7 +3560,7 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer( media_type == cricket::MEDIA_TYPE_VIDEO) { // A media section is considered eligible for recycling if it is marked as // rejected in either the current local or current remote description. - auto transceiver = transceivers().FindByMid(mid); + auto transceiver = transceivers()->FindByMid(mid); if (!transceiver) { // No associated transceiver. The media section has been stopped. recycleable_mline_indices.push(i); @@ -3599,7 +3614,7 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer( // and not associated). Reuse media sections marked as recyclable first, // otherwise append to the end of the offer. New media sections should be // added in the order they were added to the PeerConnection. - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { if (transceiver->mid() || transceiver->stopping()) { continue; } @@ -3670,8 +3685,10 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer( const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options, cricket::MediaSessionOptions* session_options) { // Figure out transceiver directional preferences. - bool send_audio = !pc_->GetAudioTransceiver()->internal()->senders().empty(); - bool send_video = !pc_->GetVideoTransceiver()->internal()->senders().empty(); + bool send_audio = + !rtp_manager()->GetAudioTransceiver()->internal()->senders().empty(); + bool send_video = + !rtp_manager()->GetVideoTransceiver()->internal()->senders().empty(); // By default, generate sendrecv/recvonly m= sections. The direction is also // restricted by the direction in the offer. @@ -3708,7 +3725,7 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer( !video_index ? nullptr : &session_options->media_description_options[*video_index]; - AddPlanBRtpSenderOptions(pc_->GetSendersInternal(), + AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(), audio_media_description_options, video_media_description_options, offer_answer_options.num_simulcast_layers); @@ -3726,7 +3743,7 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanAnswer( cricket::MediaType media_type = content.media_description()->type(); if (media_type == cricket::MEDIA_TYPE_AUDIO || media_type == cricket::MEDIA_TYPE_VIDEO) { - auto transceiver = transceivers().FindByMid(content.name); + auto transceiver = transceivers()->FindByMid(content.name); if (transceiver) { session_options->media_description_options.push_back( GetMediaDescriptionOptionsForTransceiver( @@ -3855,7 +3872,7 @@ SdpOfferAnswerHandler::GetReceivingTransceiversOfType( std::vector< rtc::scoped_refptr>> receiving_transceivers; - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { if (!transceiver->stopped() && transceiver->media_type() == media_type && RtpTransceiverDirectionHasRecv(transceiver->direction())) { receiving_transceivers.push_back(transceiver); @@ -3907,20 +3924,20 @@ void SdpOfferAnswerHandler::UpdateLocalSenders( const std::vector& streams, cricket::MediaType media_type) { RTC_DCHECK_RUN_ON(signaling_thread()); - std::vector* current_senders = - pc_->GetLocalSenderInfos(media_type); + std::vector* current_senders = + rtp_manager()->GetLocalSenderInfos(media_type); // Find removed tracks. I.e., tracks where the track id, stream id or ssrc // don't match the new StreamParam. for (auto sender_it = current_senders->begin(); sender_it != current_senders->end(); /* incremented manually */) { - const PeerConnection::RtpSenderInfo& info = *sender_it; + const RtpSenderInfo& info = *sender_it; const cricket::StreamParams* params = cricket::GetStreamBySsrc(streams, info.first_ssrc); if (!params || params->id != info.sender_id || params->first_stream_id() != info.stream_id) { - pc_->OnLocalSenderRemoved(info, media_type); + rtp_manager()->OnLocalSenderRemoved(info, media_type); sender_it = current_senders->erase(sender_it); } else { ++sender_it; @@ -3934,12 +3951,11 @@ void SdpOfferAnswerHandler::UpdateLocalSenders( const std::string& stream_id = params.first_stream_id(); const std::string& sender_id = params.id; uint32_t ssrc = params.first_ssrc(); - const PeerConnection::RtpSenderInfo* sender_info = - pc_->FindSenderInfo(*current_senders, stream_id, sender_id); + const RtpSenderInfo* sender_info = + rtp_manager()->FindSenderInfo(*current_senders, stream_id, sender_id); if (!sender_info) { - current_senders->push_back( - PeerConnection::RtpSenderInfo(stream_id, sender_id, ssrc)); - pc_->OnLocalSenderAdded(current_senders->back(), media_type); + current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc)); + rtp_manager()->OnLocalSenderAdded(current_senders->back(), media_type); } } } @@ -3952,15 +3968,15 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList( RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK(!IsUnifiedPlan()); - std::vector* current_senders = - pc_->GetRemoteSenderInfos(media_type); + std::vector* current_senders = + rtp_manager()->GetRemoteSenderInfos(media_type); // Find removed senders. I.e., senders where the sender id or ssrc don't match // the new StreamParam. for (auto sender_it = current_senders->begin(); sender_it != current_senders->end(); /* incremented manually */) { - const PeerConnection::RtpSenderInfo& info = *sender_it; + const RtpSenderInfo& info = *sender_it; const cricket::StreamParams* params = cricket::GetStreamBySsrc(streams, info.first_ssrc); std::string params_stream_id; @@ -3976,8 +3992,8 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList( sender_exists) { ++sender_it; } else { - pc_->OnRemoteSenderRemoved(info, remote_streams_->find(info.stream_id), - media_type); + rtp_manager()->OnRemoteSenderRemoved( + info, remote_streams_->find(info.stream_id), media_type); sender_it = current_senders->erase(sender_it); } } @@ -4013,12 +4029,12 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList( new_streams->AddStream(stream); } - const PeerConnection::RtpSenderInfo* sender_info = - pc_->FindSenderInfo(*current_senders, stream_id, sender_id); + const RtpSenderInfo* sender_info = + rtp_manager()->FindSenderInfo(*current_senders, stream_id, sender_id); if (!sender_info) { - current_senders->push_back( - PeerConnection::RtpSenderInfo(stream_id, sender_id, ssrc)); - pc_->OnRemoteSenderAdded(current_senders->back(), stream, media_type); + current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc)); + rtp_manager()->OnRemoteSenderAdded(current_senders->back(), stream, + media_type); } } @@ -4036,21 +4052,20 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList( std::string default_sender_id = (media_type == cricket::MEDIA_TYPE_AUDIO) ? kDefaultAudioSenderId : kDefaultVideoSenderId; - const PeerConnection::RtpSenderInfo* default_sender_info = - pc_->FindSenderInfo(*current_senders, kDefaultStreamId, - default_sender_id); + const RtpSenderInfo* default_sender_info = rtp_manager()->FindSenderInfo( + *current_senders, kDefaultStreamId, default_sender_id); if (!default_sender_info) { - current_senders->push_back(PeerConnection::RtpSenderInfo( - kDefaultStreamId, default_sender_id, /*ssrc=*/0)); - pc_->OnRemoteSenderAdded(current_senders->back(), default_stream, - media_type); + current_senders->push_back( + RtpSenderInfo(kDefaultStreamId, default_sender_id, /*ssrc=*/0)); + rtp_manager()->OnRemoteSenderAdded(current_senders->back(), + default_stream, media_type); } } } void SdpOfferAnswerHandler::EnableSending() { RTC_DCHECK_RUN_ON(signaling_thread()); - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { cricket::ChannelInterface* channel = transceiver->internal()->channel(); if (channel && !channel->enabled()) { channel->Enable(true); @@ -4081,7 +4096,7 @@ RTCError SdpOfferAnswerHandler::PushdownMediaDescription( } // Push down the new SDP media section for each audio/video transceiver. - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { const ContentInfo* content_info = FindMediaSectionForTransceiver(transceiver, sdesc); cricket::ChannelInterface* channel = transceiver->internal()->channel(); @@ -4178,7 +4193,7 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() { if (!IsUnifiedPlan()) return; // Traverse a copy of the transceiver list. - auto transceiver_list = transceivers().List(); + auto transceiver_list = transceivers()->List(); for (auto transceiver : transceiver_list) { // 3.2.10.1.1: If transceiver is stopped, associated with an m= section // and the associated m= section is rejected in @@ -4198,7 +4213,7 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() { << " since the media section is being recycled."; transceiver->internal()->set_mid(absl::nullopt); transceiver->internal()->set_mline_index(absl::nullopt); - transceivers().Remove(transceiver); + transceivers()->Remove(transceiver); continue; } if (!local_content && !remote_content) { @@ -4206,7 +4221,7 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() { // See https://github.com/w3c/webrtc-pc/issues/2576 RTC_LOG(LS_INFO) << "Dropping stopped transceiver that was never associated"; - transceivers().Remove(transceiver); + transceivers()->Remove(transceiver); continue; } } @@ -4219,12 +4234,12 @@ void SdpOfferAnswerHandler::RemoveUnusedChannels( // voice channel. const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc); if (!video_info || video_info->rejected) { - DestroyTransceiverChannel(pc_->GetVideoTransceiver()); + DestroyTransceiverChannel(rtp_manager()->GetVideoTransceiver()); } const cricket::ContentInfo* audio_info = cricket::GetFirstAudioContent(desc); if (!audio_info || audio_info->rejected) { - DestroyTransceiverChannel(pc_->GetAudioTransceiver()); + DestroyTransceiverChannel(rtp_manager()->GetAudioTransceiver()); } const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc); @@ -4432,24 +4447,24 @@ RTCError SdpOfferAnswerHandler::CreateChannels(const SessionDescription& desc) { RTC_DCHECK_RUN_ON(signaling_thread()); const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(&desc); if (voice && !voice->rejected && - !pc_->GetAudioTransceiver()->internal()->channel()) { + !rtp_manager()->GetAudioTransceiver()->internal()->channel()) { cricket::VoiceChannel* voice_channel = CreateVoiceChannel(voice->name); if (!voice_channel) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create voice channel."); } - pc_->GetAudioTransceiver()->internal()->SetChannel(voice_channel); + rtp_manager()->GetAudioTransceiver()->internal()->SetChannel(voice_channel); } const cricket::ContentInfo* video = cricket::GetFirstVideoContent(&desc); if (video && !video->rejected && - !pc_->GetVideoTransceiver()->internal()->channel()) { + !rtp_manager()->GetVideoTransceiver()->internal()->channel()) { cricket::VideoChannel* video_channel = CreateVideoChannel(video->name); if (!video_channel) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create video channel."); } - pc_->GetVideoTransceiver()->internal()->SetChannel(video_channel); + rtp_manager()->GetVideoTransceiver()->internal()->SetChannel(video_channel); } const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc); @@ -4627,14 +4642,17 @@ void SdpOfferAnswerHandler::DestroyChannelInterface( void SdpOfferAnswerHandler::DestroyAllChannels() { RTC_DCHECK_RUN_ON(signaling_thread()); + if (!transceivers()) { + return; + } // Destroy video channels first since they may have a pointer to a voice // channel. - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) { DestroyTransceiverChannel(transceiver); } } - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { DestroyTransceiverChannel(transceiver); } @@ -4819,7 +4837,7 @@ bool SdpOfferAnswerHandler::UpdatePayloadTypeDemuxingState( // single Invoke; necessary due to thread guards. std::vector> channels_to_update; - for (const auto& transceiver : transceivers().List()) { + for (const auto& transceiver : transceivers()->List()) { cricket::ChannelInterface* channel = transceiver->internal()->channel(); const ContentInfo* content = FindMediaSectionForTransceiver(transceiver, sdesc); diff --git a/pc/sdp_offer_answer.h b/pc/sdp_offer_answer.h index 56f617505c..da8b3a2b3a 100644 --- a/pc/sdp_offer_answer.h +++ b/pc/sdp_offer_answer.h @@ -74,6 +74,7 @@ class MediaStreamObserver; class PeerConnection; class VideoRtpReceiver; class RtcEventLog; +class RtpTransmissionManager; class TransceiverList; // SdpOfferAnswerHandler is a component @@ -525,13 +526,15 @@ class SdpOfferAnswerHandler { // ================================================================== // Access to pc_ variables cricket::ChannelManager* channel_manager() const; - TransceiverList& transceivers(); - const TransceiverList& transceivers() const; + TransceiverList* transceivers(); + const TransceiverList* transceivers() const; JsepTransportController* transport_controller(); DataChannelController* data_channel_controller(); const DataChannelController* data_channel_controller() const; cricket::PortAllocator* port_allocator(); const cricket::PortAllocator* port_allocator() const; + RtpTransmissionManager* rtp_manager(); + const RtpTransmissionManager* rtp_manager() const; // =================================================================== PeerConnection* const pc_;