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}
This commit is contained in:
Harald Alvestrand 2020-10-19 13:28:05 +00:00 committed by Commit Bot
parent 82031310f5
commit e15fb15035
7 changed files with 1182 additions and 886 deletions

View File

@ -195,8 +195,6 @@ rtc_library("peerconnection") {
"stream_collection.h",
"track_media_info_map.cc",
"track_media_info_map.h",
"transceiver_list.cc",
"transceiver_list.h",
"webrtc_sdp.cc",
"webrtc_sdp.h",
"webrtc_session_description_factory.cc",
@ -220,7 +218,9 @@ rtc_library("peerconnection") {
":rtp_receiver",
":rtp_sender",
":rtp_transceiver",
":rtp_transmission_manager",
":stats_collector_interface",
":transceiver_list",
":usage_pattern",
":video_rtp_receiver",
":video_track",
@ -365,6 +365,47 @@ rtc_library("rtp_transceiver") {
]
}
rtc_library("rtp_transmission_manager") {
sources = [
"rtp_transmission_manager.cc",
"rtp_transmission_manager.h",
]
deps = [
":audio_rtp_receiver",
":rtc_pc_base",
":rtp_receiver",
":rtp_sender",
":rtp_transceiver",
":stats_collector_interface",
":transceiver_list",
":usage_pattern",
":video_rtp_receiver",
"../api:libjingle_peerconnection_api",
"../api:media_stream_interface",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_transceiver_direction",
"../api:scoped_refptr",
"../media:rtc_media_base",
"../rtc_base",
"../rtc_base:checks",
"../rtc_base/third_party/sigslot",
]
absl_deps = [
"//third_party/abseil-cpp/absl/algorithm:container",
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
}
rtc_library("transceiver_list") {
sources = [
"transceiver_list.cc",
"transceiver_list.h",
]
deps = [ ":rtp_transceiver" ]
}
rtc_library("rtp_receiver") {
sources = [
"rtp_receiver.cc",

View File

@ -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 @@ namespace {
const char kSimulcastNumberOfEncodings[] =
"WebRTC.PeerConnection.Simulcast.NumberOfSendEncodings";
static const char kDefaultAudioSenderId[] = "defaulta0";
static const char kDefaultVideoSenderId[] = "defaultv0";
static const int REPORT_USAGE_PATTERN_DELAY_MS = 60000;
@ -351,8 +352,10 @@ PeerConnection::~PeerConnection() {
// Need to stop transceivers before destroying the stats collector because
// AudioRtpSender has a reference to the StatsCollector it will update when
// stopping.
for (const auto& transceiver : transceivers_.List()) {
transceiver->StopInternal();
if (rtp_manager()) {
for (const auto& transceiver : rtp_manager()->transceivers()->List()) {
transceiver->StopInternal();
}
}
stats_.reset(nullptr);
@ -547,13 +550,20 @@ bool PeerConnection::Initialize(
OnTransportControllerConnectionState(s);
});
stats_.reset(new StatsCollector(this));
stats_collector_ = RTCStatsCollector::Create(this);
configuration_ = configuration;
transport_controller_->SetIceConfig(ParseIceConfig(configuration));
stats_ = std::make_unique<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 @@ bool PeerConnection::Initialize(
// 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 @@ RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
"PeerConnection is closed.");
}
if (FindSenderForTrack(track)) {
if (rtp_manager()->FindSenderForTrack(track)) {
LOG_AND_RETURN_ERROR(
RTCErrorType::INVALID_PARAMETER,
"Sender already exists for track " + track->id() + ".");
}
auto sender_or_error =
(IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids)
: AddTrackPlanB(track, stream_ids));
auto sender_or_error = rtp_manager()->AddTrack(track, stream_ids);
if (sender_or_error.ok()) {
sdp_handler_.UpdateNegotiationNeeded();
stats_->AddTrack(track);
@ -697,111 +707,6 @@ RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
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 @@ RTCError PeerConnection::RemoveTrackNew(
} else {
bool removed;
if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
removed = GetAudioTransceiver()->internal()->RemoveSender(sender);
removed = rtp_manager()->GetAudioTransceiver()->internal()->RemoveSender(
sender);
} else {
RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, sender->media_type());
removed = GetVideoTransceiver()->internal()->RemoveSender(sender);
removed = rtp_manager()->GetVideoTransceiver()->internal()->RemoveSender(
sender);
}
if (!removed) {
LOG_AND_RETURN_ERROR(
@ -851,7 +758,7 @@ RTCError PeerConnection::RemoveTrackNew(
rtc::scoped_refptr<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 @@ PeerConnection::AddTransceiver(
<< " transceiver in response to a call to AddTransceiver.";
// Set the sender ID equal to the track ID if the track is specified unless
// that sender ID is already in use.
std::string sender_id =
(track && !FindSenderById(track->id()) ? track->id()
: rtc::CreateRandomUuid());
auto sender = CreateSender(media_type, sender_id, track, init.stream_ids,
parameters.encodings);
auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid());
auto transceiver = CreateAndAddTransceiver(sender, receiver);
std::string sender_id = (track && !rtp_manager()->FindSenderById(track->id())
? track->id()
: rtc::CreateRandomUuid());
auto sender = rtp_manager()->CreateSender(
media_type, sender_id, track, init.stream_ids, parameters.encodings);
auto receiver =
rtp_manager()->CreateReceiver(media_type, rtc::CreateRandomUuid());
auto transceiver = rtp_manager()->CreateAndAddTransceiver(sender, receiver);
transceiver->internal()->set_direction(init.direction);
if (update_negotiation_needed) {
@ -1003,81 +911,6 @@ PeerConnection::AddTransceiver(
return rtc::scoped_refptr<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<RtpSenderInterface> PeerConnection::CreateSender(
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 @@ std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
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 @@ void PeerConnection::GetStats(
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 @@ void PeerConnection::GetStats(
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 @@ RTCError PeerConnection::SetConfiguration(
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 @@ PeerConnection::GetRemoteAudioSSLCertificate() {
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 @@ PeerConnection::GetRemoteAudioSSLCertChain() {
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 @@ void PeerConnection::Close() {
NoteUsageEvent(UsageEvent::CLOSE_CALLED);
for (const auto& transceiver : transceivers_.List()) {
for (const auto& transceiver : rtp_manager()->transceivers()->List()) {
transceiver->internal()->SetPeerConnectionClosed();
if (!transceiver->stopped())
transceiver->StopInternal();
@ -1830,6 +1623,7 @@ void PeerConnection::Close() {
// call the transport controller.
sdp_handler_.ResetSessionDescFactory();
transport_controller_.reset();
rtp_manager_->Close();
network_thread()->Invoke<void>(
RTC_FROM_HERE, rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool,
@ -1848,176 +1642,6 @@ void PeerConnection::Close() {
observer_ = nullptr;
}
cricket::VoiceMediaChannel* PeerConnection::voice_media_channel() const {
RTC_DCHECK(!IsUnifiedPlan());
auto* voice_channel = static_cast<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 @@ void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
if (IsClosed()) {
return;
}
AddAudioTrack(track, stream);
rtp_manager()->AddAudioTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@ -2135,7 +1759,7 @@ void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
if (IsClosed()) {
return;
}
RemoveAudioTrack(track, stream);
rtp_manager()->RemoveAudioTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@ -2144,7 +1768,7 @@ void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
if (IsClosed()) {
return;
}
AddVideoTrack(track, stream);
rtp_manager()->AddVideoTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@ -2153,7 +1777,7 @@ void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
if (IsClosed()) {
return;
}
RemoveVideoTrack(track, stream);
rtp_manager()->RemoveVideoTrack(track, stream);
sdp_handler_.UpdateNegotiationNeeded();
}
@ -2172,104 +1796,6 @@ absl::optional<std::string> PeerConnection::GetDataMid() const {
}
}
void PeerConnection::OnRemoteSenderAdded(const RtpSenderInfo& sender_info,
MediaStreamInterface* stream,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_LOG(LS_INFO) << "Creating " << cricket::MediaTypeToString(media_type)
<< " receiver for track_id=" << sender_info.sender_id
<< " and stream_id=" << sender_info.stream_id;
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
CreateAudioReceiver(stream, sender_info);
} else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
CreateVideoReceiver(stream, sender_info);
} else {
RTC_NOTREACHED() << "Invalid media type";
}
}
void PeerConnection::OnRemoteSenderRemoved(const RtpSenderInfo& sender_info,
MediaStreamInterface* stream,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_LOG(LS_INFO) << "Removing " << cricket::MediaTypeToString(media_type)
<< " receiver for track_id=" << sender_info.sender_id
<< " and stream_id=" << sender_info.stream_id;
rtc::scoped_refptr<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 @@ void PeerConnection::OnSctpDataChannelClosed(DataChannelInterface* channel) {
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 @@ void PeerConnection::StopRtcEventLog_w() {
cricket::ChannelInterface* PeerConnection::GetChannel(
const std::string& content_name) {
for (const auto& transceiver : transceivers_.List()) {
for (const auto& transceiver : rtp_manager()->transceivers()->List()) {
cricket::ChannelInterface* channel = transceiver->internal()->channel();
if (channel && channel->content_name() == content_name) {
return channel;
@ -2641,7 +2071,7 @@ std::map<std::string, std::string> PeerConnection::GetTransportNamesByMid()
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::OnTransportControllerGatheringState(
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 @@ bool PeerConnection::OnTransportChanged(
return ret;
}
void PeerConnection::OnSetStreams() {
RTC_DCHECK_RUN_ON(signaling_thread());
if (IsUnifiedPlan())
sdp_handler_.UpdateNegotiationNeeded();
}
PeerConnectionObserver* PeerConnection::Observer() const {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(observer_);

View File

@ -73,8 +73,10 @@
#include "pc/rtp_receiver.h"
#include "pc/rtp_sender.h"
#include "pc/rtp_transceiver.h"
#include "pc/rtp_transmission_manager.h"
#include "pc/rtp_transport_internal.h"
#include "pc/sctp_data_channel.h"
#include "pc/sctp_transport.h"
#include "pc/sdp_offer_answer.h"
#include "pc/session_description.h"
#include "pc/stats_collector.h"
@ -114,7 +116,6 @@ namespace webrtc {
// - Generating stats.
class PeerConnection : public PeerConnectionInternal,
public JsepTransportController::Observer,
public RtpSenderBase::SetStreamsObserver,
public sigslot::has_slots<> {
public:
explicit PeerConnection(rtc::scoped_refptr<ConnectionContext> context,
@ -291,7 +292,7 @@ class PeerConnection : public PeerConnectionInternal,
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 @@ class PeerConnection : public PeerConnectionInternal,
return &message_handler_;
}
RtpTransmissionManager* rtp_manager() { return rtp_manager_.get(); }
const RtpTransmissionManager* rtp_manager() const {
return rtp_manager_.get();
}
// Functions made public for testing.
void ReturnHistogramVeryQuicklyForTesting() {
RTC_DCHECK_RUN_ON(signaling_thread());
@ -381,83 +387,6 @@ class PeerConnection : public PeerConnectionInternal,
// TOOD(https://bugs.webrtc.org/11995): Remove friendship.
friend class SdpOfferAnswerHandler;
struct RtpSenderInfo {
RtpSenderInfo() : first_ssrc(0) {}
RtpSenderInfo(const std::string& stream_id,
const std::string sender_id,
uint32_t ssrc)
: stream_id(stream_id), sender_id(sender_id), first_ssrc(ssrc) {}
bool operator==(const RtpSenderInfo& other) {
return this->stream_id == other.stream_id &&
this->sender_id == other.sender_id &&
this->first_ssrc == other.first_ssrc;
}
std::string stream_id;
std::string sender_id;
// An RtpSender can have many SSRCs. The first one is used as a sort of ID
// for communicating with the lower layers.
uint32_t first_ssrc;
};
// Plan B helpers for getting the voice/video media channels for the single
// audio/video transceiver, if it exists.
cricket::VoiceMediaChannel* voice_media_channel() const
RTC_RUN_ON(signaling_thread());
cricket::VideoMediaChannel* video_media_channel() const
RTC_RUN_ON(signaling_thread());
std::vector<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 @@ class PeerConnection : public PeerConnectionInternal,
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 @@ class PeerConnection : public PeerConnectionInternal,
// 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 @@ class PeerConnection : public PeerConnectionInternal,
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 @@ class PeerConnection : public PeerConnectionInternal,
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 @@ class PeerConnection : public PeerConnectionInternal,
tls_cert_verifier_; // TODO(bugs.webrtc.org/9987): Accessed on both
// signaling and network thread.
// These lists store sender info seen in local/remote descriptions.
std::vector<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 @@ class PeerConnection : public PeerConnectionInternal,
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 @@ class PeerConnection : public PeerConnectionInternal,
// Machinery for handling messages posted to oneself
PeerConnectionMessageHandler message_handler_;
// Administration of senders, receivers and transceivers
// Accessed on both signaling and network thread. Const after Initialize().
std::unique_ptr<RtpTransmissionManager> rtp_manager_;
};
} // namespace webrtc

View File

@ -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

View File

@ -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_

View File

@ -947,11 +947,17 @@ SdpOfferAnswerHandler::~SdpOfferAnswerHandler() {}
cricket::ChannelManager* SdpOfferAnswerHandler::channel_manager() const {
return pc_->channel_manager();
}
TransceiverList& SdpOfferAnswerHandler::transceivers() {
return pc_->transceivers_;
TransceiverList* SdpOfferAnswerHandler::transceivers() {
if (!pc_->rtp_manager()) {
return nullptr;
}
return pc_->rtp_manager()->transceivers();
}
const TransceiverList& SdpOfferAnswerHandler::transceivers() const {
return pc_->transceivers_;
const TransceiverList* SdpOfferAnswerHandler::transceivers() const {
if (!pc_->rtp_manager()) {
return nullptr;
}
return pc_->rtp_manager()->transceivers();
}
JsepTransportController* SdpOfferAnswerHandler::transport_controller() {
return pc_->transport_controller_.get();
@ -969,6 +975,12 @@ cricket::PortAllocator* SdpOfferAnswerHandler::port_allocator() {
const cricket::PortAllocator* SdpOfferAnswerHandler::port_allocator() const {
return pc_->port_allocator_.get();
}
RtpTransmissionManager* SdpOfferAnswerHandler::rtp_manager() {
return pc_->rtp_manager();
}
const RtpTransmissionManager* SdpOfferAnswerHandler::rtp_manager() const {
return pc_->rtp_manager();
}
// ===================================================================
@ -1211,7 +1223,7 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
}
std::vector<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 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
}
if (IsUnifiedPlan()) {
for (const auto& transceiver : transceivers().List()) {
for (const auto& transceiver : transceivers()->List()) {
if (transceiver->stopped()) {
continue;
}
@ -1577,7 +1589,7 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
std::vector<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 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
stream_ids = media_desc->streams()[0].stream_ids();
}
transceivers()
.StableState(transceiver)
->StableState(transceiver)
->SetRemoteStreamIdsIfUnset(transceiver->receiver()->stream_ids());
RTC_LOG(LS_INFO) << "Processing the MSIDs for MID=" << content->name
@ -2401,7 +2413,7 @@ RTCError SdpOfferAnswerHandler::UpdateSessionState(
} else {
RTC_DCHECK(type == SdpType::kAnswer);
ChangeSignalingState(PeerConnectionInterface::kStable);
transceivers().DiscardStableStates();
transceivers()->DiscardStableStates();
have_pending_rtp_data_channel_ = false;
}
@ -2492,10 +2504,10 @@ bool SdpOfferAnswerHandler::AddStream(MediaStreamInterface* local_stream) {
stream_observers_.push_back(std::unique_ptr<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 @@ void SdpOfferAnswerHandler::RemoveStream(MediaStreamInterface* local_stream) {
TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
if (!pc_->IsClosed()) {
for (const auto& track : local_stream->GetAudioTracks()) {
pc_->RemoveAudioTrack(track.get(), local_stream);
rtp_manager()->RemoveAudioTrack(track.get(), local_stream);
}
for (const auto& track : local_stream->GetVideoTracks()) {
pc_->RemoveVideoTrack(track.get(), local_stream);
rtp_manager()->RemoveVideoTrack(track.get(), local_stream);
}
}
local_streams_->RemoveStream(local_stream);
@ -2546,7 +2558,7 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) {
std::vector<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 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) {
if (transceiver->internal()->reused_for_addtrack()) {
transceiver->internal()->set_created_by_addtrack(true);
} else {
transceivers().Remove(transceiver);
transceivers()->Remove(transceiver);
}
}
transceiver->internal()->sender_internal()->set_transport(nullptr);
@ -2590,7 +2602,7 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) {
DestroyDataChannelTransport();
have_pending_rtp_data_channel_ = false;
}
transceivers().DiscardStableStates();
transceivers()->DiscardStableStates();
pending_local_description_.reset();
pending_remote_description_.reset();
ChangeSignalingState(PeerConnectionInterface::kStable);
@ -2742,7 +2754,7 @@ bool SdpOfferAnswerHandler::CheckIfNegotiationIsNeeded() {
// 5. For each transceiver in connection's set of transceivers, perform the
// following checks:
for (const auto& transceiver : transceivers().List()) {
for (const auto& transceiver : transceivers()->List()) {
const ContentInfo* current_local_msection =
FindTransceiverMSection(transceiver.get(), description);
@ -3060,27 +3072,27 @@ SdpOfferAnswerHandler::AssociateTransceiver(
// If this is an offer then the m= section might be recycled. If the m=
// section is being recycled (defined as: rejected in the current local or
// remote description and not rejected in new description), the transceiver
// should have been removed by RemoveStoppedTransceivers().
// should have been removed by RemoveStoppedtransceivers()->
if (IsMediaSectionBeingRecycled(type, content, old_local_content,
old_remote_content)) {
const std::string& old_mid =
(old_local_content && old_local_content->rejected)
? old_local_content->name
: old_remote_content->name;
auto old_transceiver = transceivers().FindByMid(old_mid);
auto old_transceiver = transceivers()->FindByMid(old_mid);
// The transceiver should be disassociated in RemoveStoppedTransceivers()
RTC_DCHECK(!old_transceiver);
}
#endif
const MediaContentDescription* media_desc = content.media_description();
auto transceiver = transceivers().FindByMid(content.name);
auto transceiver = transceivers()->FindByMid(content.name);
if (source == cricket::CS_LOCAL) {
// Find the RtpTransceiver that corresponds to this m= section, using the
// mapping between transceivers and m= section indices established when
// creating the offer.
if (!transceiver) {
transceiver = transceivers().FindByMLineIndex(mline_index);
transceiver = transceivers()->FindByMLineIndex(mline_index);
}
if (!transceiver) {
// This may happen normally when media sections are rejected.
@ -3109,20 +3121,21 @@ SdpOfferAnswerHandler::AssociateTransceiver(
std::string sender_id = rtc::CreateRandomUuid();
std::vector<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 @@ SdpOfferAnswerHandler::AssociateTransceiver(
transceiver->internal()->mline_index() != mline_index;
if (state_changes) {
transceivers()
.StableState(transceiver)
->StableState(transceiver)
->SetMSectionIfUnset(transceiver->internal()->mid(),
transceiver->internal()->mline_index());
}
@ -3337,7 +3350,7 @@ SdpOfferAnswerHandler::FindAvailableTransceiverToReceive(
// the same type that were added to the PeerConnection by addTrack and are not
// associated with any m= section and are not stopped, find the first such
// RtpTransceiver.
for (auto transceiver : transceivers().List()) {
for (auto transceiver : transceivers()->List()) {
if (transceiver->media_type() == media_type &&
transceiver->internal()->created_by_addtrack() && !transceiver->mid() &&
!transceiver->stopped()) {
@ -3421,8 +3434,10 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBOffer(
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
cricket::MediaSessionOptions* session_options) {
// Figure out transceiver directional preferences.
bool send_audio = !pc_->GetAudioTransceiver()->internal()->senders().empty();
bool send_video = !pc_->GetVideoTransceiver()->internal()->senders().empty();
bool send_audio =
!rtp_manager()->GetAudioTransceiver()->internal()->senders().empty();
bool send_video =
!rtp_manager()->GetVideoTransceiver()->internal()->senders().empty();
// By default, generate sendrecv/recvonly m= sections.
bool recv_audio = true;
@ -3496,7 +3511,7 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBOffer(
!video_index ? nullptr
: &session_options->media_description_options[*video_index];
AddPlanBRtpSenderOptions(pc_->GetSendersInternal(),
AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(),
audio_media_description_options,
video_media_description_options,
offer_answer_options.num_simulcast_layers);
@ -3545,7 +3560,7 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer(
media_type == cricket::MEDIA_TYPE_VIDEO) {
// A media section is considered eligible for recycling if it is marked as
// rejected in either the current local or current remote description.
auto transceiver = transceivers().FindByMid(mid);
auto transceiver = transceivers()->FindByMid(mid);
if (!transceiver) {
// No associated transceiver. The media section has been stopped.
recycleable_mline_indices.push(i);
@ -3599,7 +3614,7 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer(
// and not associated). Reuse media sections marked as recyclable first,
// otherwise append to the end of the offer. New media sections should be
// added in the order they were added to the PeerConnection.
for (const auto& transceiver : transceivers().List()) {
for (const auto& transceiver : transceivers()->List()) {
if (transceiver->mid() || transceiver->stopping()) {
continue;
}
@ -3670,8 +3685,10 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer(
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
cricket::MediaSessionOptions* session_options) {
// Figure out transceiver directional preferences.
bool send_audio = !pc_->GetAudioTransceiver()->internal()->senders().empty();
bool send_video = !pc_->GetVideoTransceiver()->internal()->senders().empty();
bool send_audio =
!rtp_manager()->GetAudioTransceiver()->internal()->senders().empty();
bool send_video =
!rtp_manager()->GetVideoTransceiver()->internal()->senders().empty();
// By default, generate sendrecv/recvonly m= sections. The direction is also
// restricted by the direction in the offer.
@ -3708,7 +3725,7 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer(
!video_index ? nullptr
: &session_options->media_description_options[*video_index];
AddPlanBRtpSenderOptions(pc_->GetSendersInternal(),
AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(),
audio_media_description_options,
video_media_description_options,
offer_answer_options.num_simulcast_layers);
@ -3726,7 +3743,7 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanAnswer(
cricket::MediaType media_type = content.media_description()->type();
if (media_type == cricket::MEDIA_TYPE_AUDIO ||
media_type == cricket::MEDIA_TYPE_VIDEO) {
auto transceiver = transceivers().FindByMid(content.name);
auto transceiver = transceivers()->FindByMid(content.name);
if (transceiver) {
session_options->media_description_options.push_back(
GetMediaDescriptionOptionsForTransceiver(
@ -3855,7 +3872,7 @@ SdpOfferAnswerHandler::GetReceivingTransceiversOfType(
std::vector<
rtc::scoped_refptr<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 @@ void SdpOfferAnswerHandler::UpdateLocalSenders(
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 @@ void SdpOfferAnswerHandler::UpdateLocalSenders(
const std::string& stream_id = params.first_stream_id();
const std::string& sender_id = params.id;
uint32_t ssrc = params.first_ssrc();
const PeerConnection::RtpSenderInfo* sender_info =
pc_->FindSenderInfo(*current_senders, stream_id, sender_id);
const RtpSenderInfo* sender_info =
rtp_manager()->FindSenderInfo(*current_senders, stream_id, sender_id);
if (!sender_info) {
current_senders->push_back(
PeerConnection::RtpSenderInfo(stream_id, sender_id, ssrc));
pc_->OnLocalSenderAdded(current_senders->back(), media_type);
current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc));
rtp_manager()->OnLocalSenderAdded(current_senders->back(), media_type);
}
}
}
@ -3952,15 +3968,15 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList(
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(!IsUnifiedPlan());
std::vector<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 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList(
sender_exists) {
++sender_it;
} else {
pc_->OnRemoteSenderRemoved(info, remote_streams_->find(info.stream_id),
media_type);
rtp_manager()->OnRemoteSenderRemoved(
info, remote_streams_->find(info.stream_id), media_type);
sender_it = current_senders->erase(sender_it);
}
}
@ -4013,12 +4029,12 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList(
new_streams->AddStream(stream);
}
const PeerConnection::RtpSenderInfo* sender_info =
pc_->FindSenderInfo(*current_senders, stream_id, sender_id);
const RtpSenderInfo* sender_info =
rtp_manager()->FindSenderInfo(*current_senders, stream_id, sender_id);
if (!sender_info) {
current_senders->push_back(
PeerConnection::RtpSenderInfo(stream_id, sender_id, ssrc));
pc_->OnRemoteSenderAdded(current_senders->back(), stream, media_type);
current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc));
rtp_manager()->OnRemoteSenderAdded(current_senders->back(), stream,
media_type);
}
}
@ -4036,21 +4052,20 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList(
std::string default_sender_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
? kDefaultAudioSenderId
: kDefaultVideoSenderId;
const PeerConnection::RtpSenderInfo* default_sender_info =
pc_->FindSenderInfo(*current_senders, kDefaultStreamId,
default_sender_id);
const RtpSenderInfo* default_sender_info = rtp_manager()->FindSenderInfo(
*current_senders, kDefaultStreamId, default_sender_id);
if (!default_sender_info) {
current_senders->push_back(PeerConnection::RtpSenderInfo(
kDefaultStreamId, default_sender_id, /*ssrc=*/0));
pc_->OnRemoteSenderAdded(current_senders->back(), default_stream,
media_type);
current_senders->push_back(
RtpSenderInfo(kDefaultStreamId, default_sender_id, /*ssrc=*/0));
rtp_manager()->OnRemoteSenderAdded(current_senders->back(),
default_stream, media_type);
}
}
}
void SdpOfferAnswerHandler::EnableSending() {
RTC_DCHECK_RUN_ON(signaling_thread());
for (const auto& transceiver : transceivers().List()) {
for (const auto& transceiver : transceivers()->List()) {
cricket::ChannelInterface* channel = transceiver->internal()->channel();
if (channel && !channel->enabled()) {
channel->Enable(true);
@ -4081,7 +4096,7 @@ RTCError SdpOfferAnswerHandler::PushdownMediaDescription(
}
// Push down the new SDP media section for each audio/video transceiver.
for (const auto& transceiver : transceivers().List()) {
for (const auto& transceiver : transceivers()->List()) {
const ContentInfo* content_info =
FindMediaSectionForTransceiver(transceiver, sdesc);
cricket::ChannelInterface* channel = transceiver->internal()->channel();
@ -4178,7 +4193,7 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() {
if (!IsUnifiedPlan())
return;
// Traverse a copy of the transceiver list.
auto transceiver_list = transceivers().List();
auto transceiver_list = transceivers()->List();
for (auto transceiver : transceiver_list) {
// 3.2.10.1.1: If transceiver is stopped, associated with an m= section
// and the associated m= section is rejected in
@ -4198,7 +4213,7 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() {
<< " since the media section is being recycled.";
transceiver->internal()->set_mid(absl::nullopt);
transceiver->internal()->set_mline_index(absl::nullopt);
transceivers().Remove(transceiver);
transceivers()->Remove(transceiver);
continue;
}
if (!local_content && !remote_content) {
@ -4206,7 +4221,7 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() {
// See https://github.com/w3c/webrtc-pc/issues/2576
RTC_LOG(LS_INFO)
<< "Dropping stopped transceiver that was never associated";
transceivers().Remove(transceiver);
transceivers()->Remove(transceiver);
continue;
}
}
@ -4219,12 +4234,12 @@ void SdpOfferAnswerHandler::RemoveUnusedChannels(
// voice channel.
const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc);
if (!video_info || video_info->rejected) {
DestroyTransceiverChannel(pc_->GetVideoTransceiver());
DestroyTransceiverChannel(rtp_manager()->GetVideoTransceiver());
}
const cricket::ContentInfo* audio_info = cricket::GetFirstAudioContent(desc);
if (!audio_info || audio_info->rejected) {
DestroyTransceiverChannel(pc_->GetAudioTransceiver());
DestroyTransceiverChannel(rtp_manager()->GetAudioTransceiver());
}
const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc);
@ -4432,24 +4447,24 @@ RTCError SdpOfferAnswerHandler::CreateChannels(const SessionDescription& desc) {
RTC_DCHECK_RUN_ON(signaling_thread());
const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(&desc);
if (voice && !voice->rejected &&
!pc_->GetAudioTransceiver()->internal()->channel()) {
!rtp_manager()->GetAudioTransceiver()->internal()->channel()) {
cricket::VoiceChannel* voice_channel = CreateVoiceChannel(voice->name);
if (!voice_channel) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to create voice channel.");
}
pc_->GetAudioTransceiver()->internal()->SetChannel(voice_channel);
rtp_manager()->GetAudioTransceiver()->internal()->SetChannel(voice_channel);
}
const cricket::ContentInfo* video = cricket::GetFirstVideoContent(&desc);
if (video && !video->rejected &&
!pc_->GetVideoTransceiver()->internal()->channel()) {
!rtp_manager()->GetVideoTransceiver()->internal()->channel()) {
cricket::VideoChannel* video_channel = CreateVideoChannel(video->name);
if (!video_channel) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
"Failed to create video channel.");
}
pc_->GetVideoTransceiver()->internal()->SetChannel(video_channel);
rtp_manager()->GetVideoTransceiver()->internal()->SetChannel(video_channel);
}
const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc);
@ -4627,14 +4642,17 @@ void SdpOfferAnswerHandler::DestroyChannelInterface(
void SdpOfferAnswerHandler::DestroyAllChannels() {
RTC_DCHECK_RUN_ON(signaling_thread());
if (!transceivers()) {
return;
}
// Destroy video channels first since they may have a pointer to a voice
// channel.
for (const auto& transceiver : transceivers().List()) {
for (const auto& transceiver : transceivers()->List()) {
if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
DestroyTransceiverChannel(transceiver);
}
}
for (const auto& transceiver : transceivers().List()) {
for (const auto& transceiver : transceivers()->List()) {
if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
DestroyTransceiverChannel(transceiver);
}
@ -4819,7 +4837,7 @@ bool SdpOfferAnswerHandler::UpdatePayloadTypeDemuxingState(
// single Invoke; necessary due to thread guards.
std::vector<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);

View File

@ -74,6 +74,7 @@ class MediaStreamObserver;
class PeerConnection;
class VideoRtpReceiver;
class RtcEventLog;
class RtpTransmissionManager;
class TransceiverList;
// SdpOfferAnswerHandler is a component
@ -525,13 +526,15 @@ class SdpOfferAnswerHandler {
// ==================================================================
// Access to pc_ variables
cricket::ChannelManager* channel_manager() const;
TransceiverList& transceivers();
const TransceiverList& transceivers() const;
TransceiverList* transceivers();
const TransceiverList* transceivers() const;
JsepTransportController* transport_controller();
DataChannelController* data_channel_controller();
const DataChannelController* data_channel_controller() const;
cricket::PortAllocator* port_allocator();
const cricket::PortAllocator* port_allocator() const;
RtpTransmissionManager* rtp_manager();
const RtpTransmissionManager* rtp_manager() const;
// ===================================================================
PeerConnection* const pc_;