Separate RTP object handling (senders, receivers, transceivers)
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 <hbos@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32443}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 6e46301..821802f 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -195,8 +195,6 @@
"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 @@
":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_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 7123b7b..9f3f6ba 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -13,6 +13,10 @@
#include <limits.h>
#include <stddef.h>
#include <algorithm>
+#include <limits>
+#include <memory>
+#include <queue>
+#include <set>
#include <utility>
#include "absl/algorithm/container.h"
@@ -83,9 +87,6 @@
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 @@
// 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 @@
OnTransportControllerConnectionState(s);
});
- stats_.reset(new StatsCollector(this));
- stats_collector_ = RTCStatsCollector::Create(this);
-
configuration_ = configuration;
transport_controller_->SetIceConfig(ParseIceConfig(configuration));
+ stats_ = std::make_unique<StatsCollector>(this);
+ stats_collector_ = RTCStatsCollector::Create(this);
+
+ rtp_manager_ = std::make_unique<RtpTransmissionManager>(
+ 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 @@
// Add default audio/video transceivers for Plan B SDP.
if (!IsUnifiedPlan()) {
- transceivers_.Add(RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
- signaling_thread(), new RtpTransceiver(cricket::MEDIA_TYPE_AUDIO)));
- transceivers_.Add(RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
- signaling_thread(), new RtpTransceiver(cricket::MEDIA_TYPE_VIDEO)));
+ rtp_manager()->transceivers()->Add(
+ RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
+ signaling_thread(), new RtpTransceiver(cricket::MEDIA_TYPE_AUDIO)));
+ rtp_manager()->transceivers()->Add(
+ RtpTransceiverProxyWithInternal<RtpTransceiver>::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 @@
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 @@
return sender_or_error;
}
-RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
-PeerConnection::AddTrackPlanB(
- rtc::scoped_refptr<MediaStreamTrackInterface> track,
- const std::vector<std::string>& 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<std::string> 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<RtpSenderInterface>(new_sender);
-}
-
-RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
-PeerConnection::AddTrackUnifiedPlan(
- rtc::scoped_refptr<MediaStreamTrackInterface> track,
- const std::vector<std::string>& 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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
-PeerConnection::FindFirstTransceiverForAddedTrack(
- rtc::scoped_refptr<MediaStreamTrackInterface> 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 @@
} 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 @@
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
PeerConnection::FindTransceiverBySender(
rtc::scoped_refptr<RtpSenderInterface> sender) {
- return transceivers_.FindBySender(sender);
+ return rtp_manager()->transceivers()->FindBySender(sender);
}
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
@@ -987,13 +894,14 @@
<< " 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 @@
return rtc::scoped_refptr<RtpTransceiverInterface>(transceiver);
}
-rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
-PeerConnection::CreateSender(
- cricket::MediaType media_type,
- const std::string& id,
- rtc::scoped_refptr<MediaStreamTrackInterface> track,
- const std::vector<std::string>& stream_ids,
- const std::vector<RtpEncodingParameters>& send_encodings) {
- RTC_DCHECK_RUN_ON(signaling_thread());
- rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender;
- if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- RTC_DCHECK(!track ||
- (track->kind() == MediaStreamTrackInterface::kAudioKind));
- sender = RtpSenderProxyWithInternal<RtpSenderInternal>::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<RtpSenderInternal>::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<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
-PeerConnection::CreateReceiver(cricket::MediaType media_type,
- const std::string& receiver_id) {
- rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
- receiver;
- if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
- signaling_thread(), new AudioRtpReceiver(worker_thread(), receiver_id,
- std::vector<std::string>({})));
- NoteUsageEvent(UsageEvent::AUDIO_ADDED);
- } else {
- RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
- receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
- signaling_thread(), new VideoRtpReceiver(worker_thread(), receiver_id,
- std::vector<std::string>({})));
- NoteUsageEvent(UsageEvent::VIDEO_ADDED);
- }
- return receiver;
-}
-
-rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
-PeerConnection::CreateAndAddTransceiver(
- rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
- rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
- 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<RtpTransceiver>::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<RtpSenderProxyWithInternal<RtpSenderInternal>> 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<RtpSenderInternal>::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<RtpSenderInternal>::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 @@
const {
RTC_DCHECK_RUN_ON(signaling_thread());
std::vector<rtc::scoped_refptr<RtpSenderInterface>> ret;
- for (const auto& sender : GetSendersInternal()) {
+ for (const auto& sender : rtp_manager()->GetSendersInternal()) {
ret.push_back(sender);
}
return ret;
}
-std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
-PeerConnection::GetSendersInternal() const {
- RTC_DCHECK_RUN_ON(signaling_thread());
- std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
- 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<RtpReceiverInterface>>
PeerConnection::GetReceivers() const {
RTC_DCHECK_RUN_ON(signaling_thread());
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> ret;
- for (const auto& receiver : GetReceiversInternal()) {
+ for (const auto& receiver : rtp_manager()->GetReceiversInternal()) {
ret.push_back(receiver);
}
return ret;
}
-std::vector<
- rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
-PeerConnection::GetReceiversInternal() const {
- std::vector<
- rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
- 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<rtc::scoped_refptr<RtpTransceiverInterface>>
PeerConnection::GetTransceivers() const {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_CHECK(IsUnifiedPlan())
<< "GetTransceivers is only supported with Unified Plan SdpSemantics.";
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> 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 @@
RTC_DCHECK(stats_collector_);
rtc::scoped_refptr<RtpSenderInternal> 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 @@
RTC_DCHECK(stats_collector_);
rtc::scoped_refptr<RtpReceiverInternal> 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 @@
if (modified_config.allow_codec_switching.has_value()) {
std::vector<cricket::VideoMediaChannel*> 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 @@
std::unique_ptr<rtc::SSLCertChain>
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 @@
audio_transceiver->internal()->channel()->transport_name());
}
-rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
-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> resource) {
if (!worker_thread()->IsCurrent()) {
@@ -1807,7 +1600,7 @@
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 @@
// call the transport controller.
sdp_handler_.ResetSessionDescFactory();
transport_controller_.reset();
+ rtp_manager_->Close();
network_thread()->Invoke<void>(
RTC_FROM_HERE, rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool,
@@ -1848,176 +1642,6 @@
observer_ = nullptr;
}
-cricket::VoiceMediaChannel* PeerConnection::voice_media_channel() const {
- RTC_DCHECK(!IsUnifiedPlan());
- auto* voice_channel = static_cast<cricket::VoiceChannel*>(
- 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<cricket::VideoChannel*>(
- 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<rtc::scoped_refptr<MediaStreamInterface>> streams;
- streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(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<RtpReceiverInternal>::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<rtc::scoped_refptr<MediaStreamInterface>> streams;
- streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(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<RtpReceiverInternal>::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<RtpReceiverInterface> 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 @@
if (IsClosed()) {
return;
}
- AddAudioTrack(track, stream);
+ rtp_manager()->AddAudioTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@@ -2135,7 +1759,7 @@
if (IsClosed()) {
return;
}
- RemoveAudioTrack(track, stream);
+ rtp_manager()->RemoveAudioTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@@ -2144,7 +1768,7 @@
if (IsClosed()) {
return;
}
- AddVideoTrack(track, stream);
+ rtp_manager()->AddVideoTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@@ -2153,7 +1777,7 @@
if (IsClosed()) {
return;
}
- RemoveVideoTrack(track, stream);
+ rtp_manager()->RemoveVideoTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@@ -2172,104 +1796,6 @@
}
}
-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<RtpReceiverInterface> 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<AudioTrackInterface> 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<VideoTrackInterface> 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 @@
static_cast<SctpDataChannel*>(channel));
}
-rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
-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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
-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<RtpSenderProxyWithInternal<RtpSenderInternal>>
-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<RtpSenderProxyWithInternal<RtpSenderInternal>>
-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<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
-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::RtpSenderInfo>*
-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::RtpSenderInfo>* 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<PeerConnection::RtpSenderInfo>& 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 @@
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 @@
const {
RTC_DCHECK_RUN_ON(signaling_thread());
std::map<std::string, std::string> 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::ReportTransportStats() {
std::map<std::string, std::set<cricket::MediaType>>
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 @@
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 c2ea92f..582c76d 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 @@
// - Generating stats.
class PeerConnection : public PeerConnectionInternal,
public JsepTransportController::Observer,
- public RtpSenderBase::SetStreamsObserver,
public sigslot::has_slots<> {
public:
explicit PeerConnection(rtc::scoped_refptr<ConnectionContext> context,
@@ -291,7 +292,7 @@
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
GetTransceiversInternal() const override {
RTC_DCHECK_RUN_ON(signaling_thread());
- return transceivers_.List();
+ return rtp_manager()->transceivers()->List();
}
sigslot::signal1<RtpDataChannel*>& SignalRtpDataChannelCreated() override {
@@ -366,6 +367,11 @@
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 @@
// 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<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
- GetSendersInternal() const;
- std::vector<
- rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
- GetReceiversInternal() const RTC_RUN_ON(signaling_thread());
-
- rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
- GetAudioTransceiver() const;
- rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
- GetVideoTransceiver() const;
-
- rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
- 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<RtpReceiverInterface> 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<rtc::scoped_refptr<RtpSenderInterface>> AddTrackUnifiedPlan(
- rtc::scoped_refptr<MediaStreamTrackInterface> track,
- const std::vector<std::string>& stream_ids)
- RTC_RUN_ON(signaling_thread());
- // AddTrack implementation when Plan B is specified.
- RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrackPlanB(
- rtc::scoped_refptr<MediaStreamTrackInterface> track,
- const std::vector<std::string>& 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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
- FindFirstTransceiverForAddedTrack(
- rtc::scoped_refptr<MediaStreamTrackInterface> track)
- RTC_RUN_ON(signaling_thread());
-
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
FindTransceiverBySender(rtc::scoped_refptr<RtpSenderInterface> sender)
RTC_RUN_ON(signaling_thread());
@@ -470,24 +399,6 @@
const RtpTransceiverInit& init,
bool fire_callback = true);
- rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
- CreateSender(cricket::MediaType media_type,
- const std::string& id,
- rtc::scoped_refptr<MediaStreamTrackInterface> track,
- const std::vector<std::string>& stream_ids,
- const std::vector<RtpEncodingParameters>& send_encodings);
-
- rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
- 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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
- CreateAndAddTransceiver(
- rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
- rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
- receiver);
-
void SetIceConnectionState(IceConnectionState new_state);
void SetStandardizedIceConnectionState(
PeerConnectionInterface::IceConnectionState new_state)
@@ -539,36 +450,6 @@
// channels are configured this will return nullopt.
absl::optional<std::string> 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 @@
return configuration_.sdp_semantics == SdpSemantics::kUnifiedPlan;
}
- // Return the RtpSender with the given track attached.
- rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
- FindSenderForTrack(MediaStreamTrackInterface* track) const
- RTC_RUN_ON(signaling_thread());
-
- // Return the RtpSender with the given id, or null if none exists.
- rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
- 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<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
- FindReceiverById(const std::string& receiver_id) const
- RTC_RUN_ON(signaling_thread());
-
- std::vector<RtpSenderInfo>* GetRemoteSenderInfos(
- cricket::MediaType media_type);
- std::vector<RtpSenderInfo>* GetLocalSenderInfos(
- cricket::MediaType media_type);
- const RtpSenderInfo* FindSenderInfo(const std::vector<RtpSenderInfo>& 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 @@
rtc::scoped_refptr<DtlsTransport> 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 @@
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<RtpSenderInfo> remote_audio_sender_infos_
- RTC_GUARDED_BY(signaling_thread());
- std::vector<RtpSenderInfo> remote_video_sender_infos_
- RTC_GUARDED_BY(signaling_thread());
- std::vector<RtpSenderInfo> local_audio_sender_infos_
- RTC_GUARDED_BY(signaling_thread());
- std::vector<RtpSenderInfo> 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> call_ RTC_GUARDED_BY(worker_thread());
@@ -832,7 +677,6 @@
RTC_GUARDED_BY(signaling_thread()); // A pointer is passed to senders_
rtc::scoped_refptr<RTCStatsCollector> stats_collector_
RTC_GUARDED_BY(signaling_thread());
- TransceiverList transceivers_;
std::string session_id_ RTC_GUARDED_BY(signaling_thread());
@@ -882,6 +726,10 @@
// 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<RtpTransmissionManager> rtp_manager_;
};
} // namespace webrtc
diff --git a/pc/rtp_transmission_manager.cc b/pc/rtp_transmission_manager.cc
new file mode 100644
index 0000000..5c0e4d9
--- /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 <algorithm>
+
+#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<void()> 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<cricket::VoiceChannel*>(
+ 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<cricket::VideoChannel*>(
+ GetVideoTransceiver()->internal()->channel());
+ if (video_channel) {
+ return video_channel->media_channel();
+ } else {
+ return nullptr;
+ }
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
+RtpTransmissionManager::AddTrack(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& stream_ids) {
+ RTC_DCHECK_RUN_ON(signaling_thread());
+
+ return (IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids)
+ : AddTrackPlanB(track, stream_ids));
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
+RtpTransmissionManager::AddTrackPlanB(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& 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<std::string> 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<RtpSenderInterface>(new_sender);
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
+RtpTransmissionManager::AddTrackUnifiedPlan(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& 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<RtpSenderProxyWithInternal<RtpSenderInternal>>
+RtpTransmissionManager::CreateSender(
+ cricket::MediaType media_type,
+ const std::string& id,
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& stream_ids,
+ const std::vector<RtpEncodingParameters>& send_encodings) {
+ RTC_DCHECK_RUN_ON(signaling_thread());
+ rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender;
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ RTC_DCHECK(!track ||
+ (track->kind() == MediaStreamTrackInterface::kAudioKind));
+ sender = RtpSenderProxyWithInternal<RtpSenderInternal>::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<RtpSenderInternal>::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<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+RtpTransmissionManager::CreateReceiver(cricket::MediaType media_type,
+ const std::string& receiver_id) {
+ RTC_DCHECK_RUN_ON(signaling_thread());
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+ receiver;
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
+ signaling_thread(), new AudioRtpReceiver(worker_thread(), receiver_id,
+ std::vector<std::string>({})));
+ NoteUsageEvent(UsageEvent::AUDIO_ADDED);
+ } else {
+ RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
+ receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
+ signaling_thread(), new VideoRtpReceiver(worker_thread(), receiver_id,
+ std::vector<std::string>({})));
+ NoteUsageEvent(UsageEvent::VIDEO_ADDED);
+ }
+ return receiver;
+}
+
+rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+RtpTransmissionManager::CreateAndAddTransceiver(
+ rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+ 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<RtpTransceiver>::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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+RtpTransmissionManager::FindFirstTransceiverForAddedTrack(
+ rtc::scoped_refptr<MediaStreamTrackInterface> 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<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
+RtpTransmissionManager::GetSendersInternal() const {
+ RTC_DCHECK_RUN_ON(signaling_thread());
+ std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
+ 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<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
+RtpTransmissionManager::GetReceiversInternal() const {
+ RTC_DCHECK_RUN_ON(signaling_thread());
+ std::vector<
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
+ 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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+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<rtc::scoped_refptr<MediaStreamInterface>> streams;
+ streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(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<RtpReceiverInternal>::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<rtc::scoped_refptr<MediaStreamInterface>> streams;
+ streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(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<RtpReceiverInternal>::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<RtpReceiverInterface>
+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<RtpReceiverInterface> 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<AudioTrackInterface> 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<VideoTrackInterface> 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<RtpSenderInfo>* 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<RtpSenderInfo>* 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<RtpSenderInfo>& 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<RtpSenderProxyWithInternal<RtpSenderInternal>>
+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<RtpSenderProxyWithInternal<RtpSenderInternal>>
+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<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+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 0000000..7aa410c
--- /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 <stdint.h>
+#include <functional>
+#include <string>
+#include <vector>
+
+#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<void()> 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<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& stream_ids);
+
+ // Create a new RTP sender. Does not associate with a transceiver.
+ rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
+ CreateSender(cricket::MediaType media_type,
+ const std::string& id,
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& stream_ids,
+ const std::vector<RtpEncodingParameters>& send_encodings);
+
+ // Create a new RTP receiver. Does not associate with a transceiver.
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+ 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<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+ CreateAndAddTransceiver(
+ rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+ receiver);
+
+ // Returns the first RtpTransceiver suitable for a newly added track, if such
+ // transceiver is available.
+ rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+ FindFirstTransceiverForAddedTrack(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track);
+
+ // Returns the list of senders currently associated with some
+ // registered transceiver
+ std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
+ GetSendersInternal() const;
+
+ // Returns the list of receivers currently associated with a transceiver
+ std::vector<
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
+ GetReceiversInternal() const;
+
+ // Plan B: Get the transceiver containing all audio senders and receivers
+ rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+ GetAudioTransceiver() const;
+ // Plan B: Get the transceiver containing all video senders and receivers
+ rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+ GetVideoTransceiver() const;
+
+ // Gets the first audio transceiver.
+ rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+ 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<RtpSenderInfo>* GetRemoteSenderInfos(
+ cricket::MediaType media_type);
+ std::vector<RtpSenderInfo>* GetLocalSenderInfos(
+ cricket::MediaType media_type);
+ const RtpSenderInfo* FindSenderInfo(const std::vector<RtpSenderInfo>& infos,
+ const std::string& stream_id,
+ const std::string sender_id) const;
+
+ // Return the RtpSender with the given track attached.
+ rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
+ FindSenderForTrack(MediaStreamTrackInterface* track) const;
+
+ // Return the RtpSender with the given id, or null if none exists.
+ rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
+ FindSenderById(const std::string& sender_id) const;
+
+ // Return the RtpReceiver with the given id, or null if none exists.
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+ 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<rtc::scoped_refptr<RtpSenderInterface>> AddTrackUnifiedPlan(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& stream_ids);
+ // AddTrack implementation when Plan B is specified.
+ RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrackPlanB(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const std::vector<std::string>& 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<RtpReceiverInterface> 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<RtpSenderInfo> remote_audio_sender_infos_
+ RTC_GUARDED_BY(signaling_thread());
+ std::vector<RtpSenderInfo> remote_video_sender_infos_
+ RTC_GUARDED_BY(signaling_thread());
+ std::vector<RtpSenderInfo> local_audio_sender_infos_
+ RTC_GUARDED_BY(signaling_thread());
+ std::vector<RtpSenderInfo> 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<void()> 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 d7863d7..5197a69 100644
--- a/pc/sdp_offer_answer.cc
+++ b/pc/sdp_offer_answer.cc
@@ -947,11 +947,17 @@
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 @@
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 @@
}
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list;
std::vector<rtc::scoped_refptr<MediaStreamInterface>> removed_streams;
- for (const auto& transceiver : transceivers().List()) {
+ for (const auto& transceiver : transceivers()->List()) {
if (transceiver->stopped()) {
continue;
}
@@ -1300,7 +1312,7 @@
}
if (IsUnifiedPlan()) {
- for (const auto& transceiver : transceivers().List()) {
+ for (const auto& transceiver : transceivers()->List()) {
if (transceiver->stopped()) {
continue;
}
@@ -1577,7 +1589,7 @@
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list;
std::vector<rtc::scoped_refptr<MediaStreamInterface>> added_streams;
std::vector<rtc::scoped_refptr<MediaStreamInterface>> 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 @@
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 @@
} else {
RTC_DCHECK(type == SdpType::kAnswer);
ChangeSignalingState(PeerConnectionInterface::kStable);
- transceivers().DiscardStableStates();
+ transceivers()->DiscardStableStates();
have_pending_rtp_data_channel_ = false;
}
@@ -2492,10 +2504,10 @@
stream_observers_.push_back(std::unique_ptr<MediaStreamObserver>(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 @@
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 @@
std::vector<rtc::scoped_refptr<MediaStreamInterface>> all_removed_streams;
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
std::string sender_id = rtc::CreateRandomUuid();
std::vector<RtpEncodingParameters> 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 @@
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 @@
// 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 @@
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 @@
!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 @@
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 @@
// 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 @@
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 @@
!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 @@
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 @@
std::vector<
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
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 @@
const std::vector<cricket::StreamParams>& streams,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
- std::vector<PeerConnection::RtpSenderInfo>* current_senders =
- pc_->GetLocalSenderInfos(media_type);
+ std::vector<RtpSenderInfo>* 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 @@
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 @@
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(!IsUnifiedPlan());
- std::vector<PeerConnection::RtpSenderInfo>* current_senders =
- pc_->GetRemoteSenderInfos(media_type);
+ std::vector<RtpSenderInfo>* 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 @@
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 @@
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 @@
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 @@
}
// 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 @@
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 @@
<< " 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 @@
// 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 @@
// 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 @@
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::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 @@
// single Invoke; necessary due to thread guards.
std::vector<std::pair<RtpTransceiverDirection, cricket::ChannelInterface*>>
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 56f6175..da8b3a2 100644
--- a/pc/sdp_offer_answer.h
+++ b/pc/sdp_offer_answer.h
@@ -74,6 +74,7 @@
class PeerConnection;
class VideoRtpReceiver;
class RtcEventLog;
+class RtpTransmissionManager;
class TransceiverList;
// SdpOfferAnswerHandler is a component
@@ -525,13 +526,15 @@
// ==================================================================
// 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_;