Change WebRtcSession to have a vector of channels
This is the first step towards supporting multiple audio/video
channels in PeerConnection/WebRtcSession. For now, there can only
be 0 or 1 channels in the vector. This adds the framework so that
all the other code that assumes a single audio/video channel can
be transitioned one-by-one to multiple channels.
Bug: webrtc:8183
Change-Id: I6456af32d6e3adf7eb83e281e43253ea973c4eb9
Reviewed-on: https://chromium-review.googlesource.com/644222
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Original-Commit-Position: refs/heads/master@{#19615}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 169629aca3140803731af3d586932ffc176bed46
diff --git a/pc/webrtcsession.cc b/pc/webrtcsession.cc
index 4c71fd4..b423663 100644
--- a/pc/webrtcsession.cc
+++ b/pc/webrtcsession.cc
@@ -507,13 +507,13 @@
WebRtcSession::~WebRtcSession() {
RTC_DCHECK(signaling_thread()->IsCurrent());
- // Destroy video_channel_ first since it may have a pointer to the
- // voice_channel_.
- if (video_channel_) {
- DestroyVideoChannel();
+ // Destroy video channels first since they may have a pointer to a voice
+ // channel.
+ for (auto* channel : video_channels_) {
+ DestroyVideoChannel(channel);
}
- if (voice_channel_) {
- DestroyVoiceChannel();
+ for (auto* channel : voice_channels_) {
+ DestroyVoiceChannel(channel);
}
if (rtp_data_channel_) {
DestroyDataChannel();
@@ -634,8 +634,8 @@
SetState(STATE_CLOSED);
RemoveUnusedChannels(nullptr);
call_ = nullptr;
- RTC_DCHECK(!voice_channel_);
- RTC_DCHECK(!video_channel_);
+ RTC_DCHECK(voice_channels_.empty());
+ RTC_DCHECK(video_channels_.empty());
RTC_DCHECK(!rtp_data_channel_);
RTC_DCHECK(!sctp_transport_);
}
@@ -1552,13 +1552,19 @@
}
}
-// Enabling voice and video (and RTP data) channel.
+// Enabling voice and video (and RTP data) channels.
void WebRtcSession::EnableChannels() {
- if (voice_channel_ && !voice_channel_->enabled())
- voice_channel_->Enable(true);
+ for (cricket::VoiceChannel* voice_channel : voice_channels_) {
+ if (!voice_channel->enabled()) {
+ voice_channel->Enable(true);
+ }
+ }
- if (video_channel_ && !video_channel_->enabled())
- video_channel_->Enable(true);
+ for (cricket::VideoChannel* video_channel : video_channels_) {
+ if (!video_channel->enabled()) {
+ video_channel->Enable(true);
+ }
+ }
if (rtp_data_channel_ && !rtp_data_channel_->enabled())
rtp_data_channel_->Enable(true);
@@ -1652,18 +1658,17 @@
}
void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) {
- // Destroy video_channel_ first since it may have a pointer to the
- // voice_channel_.
- const cricket::ContentInfo* video_info =
- cricket::GetFirstVideoContent(desc);
- if ((!video_info || video_info->rejected) && video_channel_) {
- DestroyVideoChannel();
+ // TODO(steveanton): Add support for multiple audio/video channels.
+ // Destroy video channel first since it may have a pointer to the
+ // voice channel.
+ const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc);
+ if ((!video_info || video_info->rejected) && video_channel()) {
+ RemoveAndDestroyVideoChannel(video_channel());
}
- const cricket::ContentInfo* voice_info =
- cricket::GetFirstAudioContent(desc);
- if ((!voice_info || voice_info->rejected) && voice_channel_) {
- DestroyVoiceChannel();
+ const cricket::ContentInfo* voice_info = cricket::GetFirstAudioContent(desc);
+ if ((!voice_info || voice_info->rejected) && voice_channel()) {
+ RemoveAndDestroyVoiceChannel(voice_channel());
}
const cricket::ContentInfo* data_info =
@@ -1709,6 +1714,7 @@
}
bool WebRtcSession::CreateChannels(const SessionDescription* desc) {
+ // TODO(steveanton): Add support for multiple audio/video channels.
const cricket::ContentGroup* bundle_group = nullptr;
if (bundle_policy_ == PeerConnectionInterface::kBundlePolicyMaxBundle) {
bundle_group = desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
@@ -1719,7 +1725,7 @@
}
// Creating the media channels and transport proxies.
const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(desc);
- if (voice && !voice->rejected && !voice_channel_) {
+ if (voice && !voice->rejected && !voice_channel()) {
if (!CreateVoiceChannel(voice,
GetBundleTransportName(voice, bundle_group))) {
LOG(LS_ERROR) << "Failed to create voice channel.";
@@ -1728,7 +1734,7 @@
}
const cricket::ContentInfo* video = cricket::GetFirstVideoContent(desc);
- if (video && !video->rejected && !video_channel_) {
+ if (video && !video->rejected && !video_channel()) {
if (!CreateVideoChannel(video,
GetBundleTransportName(video, bundle_group))) {
LOG(LS_ERROR) << "Failed to create video channel.";
@@ -1750,6 +1756,10 @@
bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content,
const std::string* bundle_transport) {
+ // TODO(steveanton): Check to see if it's safe to create multiple voice
+ // channels.
+ RTC_DCHECK(voice_channels_.empty());
+
bool require_rtcp_mux =
rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
@@ -1765,11 +1775,11 @@
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
}
- voice_channel_.reset(channel_manager_->CreateVoiceChannel(
+ cricket::VoiceChannel* voice_channel = channel_manager_->CreateVoiceChannel(
call_, media_config_, rtp_dtls_transport, rtcp_dtls_transport,
transport_controller_->signaling_thread(), content->name, SrtpRequired(),
- audio_options_));
- if (!voice_channel_) {
+ audio_options_);
+ if (!voice_channel) {
transport_controller_->DestroyDtlsTransport(
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
if (rtcp_dtls_transport) {
@@ -1779,19 +1789,26 @@
return false;
}
- voice_channel_->SignalRtcpMuxFullyActive.connect(
+ voice_channels_.push_back(voice_channel);
+
+ voice_channel->SignalRtcpMuxFullyActive.connect(
this, &WebRtcSession::DestroyRtcpTransport_n);
- voice_channel_->SignalDtlsSrtpSetupFailure.connect(
+ voice_channel->SignalDtlsSrtpSetupFailure.connect(
this, &WebRtcSession::OnDtlsSrtpSetupFailure);
+ // TODO(steveanton): This should signal which voice channel was created since
+ // we can have multiple.
SignalVoiceChannelCreated();
- voice_channel_->SignalSentPacket.connect(this,
- &WebRtcSession::OnSentPacket_w);
+ voice_channel->SignalSentPacket.connect(this, &WebRtcSession::OnSentPacket_w);
return true;
}
bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content,
const std::string* bundle_transport) {
+ // TODO(steveanton): Check to see if it's safe to create multiple video
+ // channels.
+ RTC_DCHECK(video_channels_.empty());
+
bool require_rtcp_mux =
rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
@@ -1807,12 +1824,12 @@
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
}
- video_channel_.reset(channel_manager_->CreateVideoChannel(
+ cricket::VideoChannel* video_channel = channel_manager_->CreateVideoChannel(
call_, media_config_, rtp_dtls_transport, rtcp_dtls_transport,
transport_controller_->signaling_thread(), content->name, SrtpRequired(),
- video_options_));
+ video_options_);
- if (!video_channel_) {
+ if (!video_channel) {
transport_controller_->DestroyDtlsTransport(
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
if (rtcp_dtls_transport) {
@@ -1822,14 +1839,17 @@
return false;
}
- video_channel_->SignalRtcpMuxFullyActive.connect(
+ video_channels_.push_back(video_channel);
+
+ video_channel->SignalRtcpMuxFullyActive.connect(
this, &WebRtcSession::DestroyRtcpTransport_n);
- video_channel_->SignalDtlsSrtpSetupFailure.connect(
+ video_channel->SignalDtlsSrtpSetupFailure.connect(
this, &WebRtcSession::OnDtlsSrtpSetupFailure);
+ // TODO(steveanton): This should signal which video channel was created since
+ // we can have multiple.
SignalVideoChannelCreated();
- video_channel_->SignalSentPacket.connect(this,
- &WebRtcSession::OnSentPacket_w);
+ video_channel->SignalSentPacket.connect(this, &WebRtcSession::OnSentPacket_w);
return true;
}
@@ -2365,13 +2385,30 @@
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
}
-void WebRtcSession::DestroyVideoChannel() {
+void WebRtcSession::RemoveAndDestroyVideoChannel(
+ cricket::VideoChannel* video_channel) {
+ auto it =
+ std::find(video_channels_.begin(), video_channels_.end(), video_channel);
+ RTC_DCHECK(it != video_channels_.end());
+ if (it == video_channels_.end()) {
+ return;
+ }
+ video_channels_.erase(it);
+ DestroyVideoChannel(video_channel);
+}
+
+void WebRtcSession::DestroyVideoChannel(cricket::VideoChannel* video_channel) {
+ // TODO(steveanton): This should take an identifier for the video channel
+ // since we now support more than one.
SignalVideoChannelDestroyed();
- RTC_DCHECK(video_channel_->rtp_dtls_transport());
- std::string transport_name;
- transport_name = video_channel_->rtp_dtls_transport()->transport_name();
- bool need_to_delete_rtcp = (video_channel_->rtcp_dtls_transport() != nullptr);
- channel_manager_->DestroyVideoChannel(video_channel_.release());
+ RTC_DCHECK(video_channel->rtp_dtls_transport());
+ const std::string transport_name =
+ video_channel->rtp_dtls_transport()->transport_name();
+ const bool need_to_delete_rtcp =
+ (video_channel->rtcp_dtls_transport() != nullptr);
+ // The above need to be cached before destroying the video channel so that we
+ // do not access uninitialized memory.
+ channel_manager_->DestroyVideoChannel(video_channel);
transport_controller_->DestroyDtlsTransport(
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
if (need_to_delete_rtcp) {
@@ -2380,13 +2417,30 @@
}
}
-void WebRtcSession::DestroyVoiceChannel() {
+void WebRtcSession::RemoveAndDestroyVoiceChannel(
+ cricket::VoiceChannel* voice_channel) {
+ auto it =
+ std::find(voice_channels_.begin(), voice_channels_.end(), voice_channel);
+ RTC_DCHECK(it != voice_channels_.end());
+ if (it == voice_channels_.end()) {
+ return;
+ }
+ voice_channels_.erase(it);
+ DestroyVoiceChannel(voice_channel);
+}
+
+void WebRtcSession::DestroyVoiceChannel(cricket::VoiceChannel* voice_channel) {
+ // TODO(steveanton): This should take an identifier for the voice channel
+ // since we now support more than one.
SignalVoiceChannelDestroyed();
- RTC_DCHECK(voice_channel_->rtp_dtls_transport());
- std::string transport_name;
- transport_name = voice_channel_->rtp_dtls_transport()->transport_name();
- bool need_to_delete_rtcp = (voice_channel_->rtcp_dtls_transport() != nullptr);
- channel_manager_->DestroyVoiceChannel(voice_channel_.release());
+ RTC_DCHECK(voice_channel->rtp_dtls_transport());
+ const std::string transport_name =
+ voice_channel->rtp_dtls_transport()->transport_name();
+ const bool need_to_delete_rtcp =
+ (voice_channel->rtcp_dtls_transport() != nullptr);
+ // The above need to be cached before destroying the video channel so that we
+ // do not access uninitialized memory.
+ channel_manager_->DestroyVoiceChannel(voice_channel);
transport_controller_->DestroyDtlsTransport(
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
if (need_to_delete_rtcp) {
diff --git a/pc/webrtcsession.h b/pc/webrtcsession.h
index 9b62c97..0f4d321 100644
--- a/pc/webrtcsession.h
+++ b/pc/webrtcsession.h
@@ -204,12 +204,29 @@
}
// Exposed for stats collecting.
+ // TODO(steveanton): Switch callers to use the plural form and remove these.
virtual cricket::VoiceChannel* voice_channel() {
- return voice_channel_.get();
+ if (voice_channels_.empty()) {
+ return nullptr;
+ } else {
+ return voice_channels_[0];
+ }
}
virtual cricket::VideoChannel* video_channel() {
- return video_channel_.get();
+ if (video_channels_.empty()) {
+ return nullptr;
+ } else {
+ return video_channels_[0];
+ }
}
+
+ virtual std::vector<cricket::VoiceChannel*> voice_channels() const {
+ return voice_channels_;
+ }
+ virtual std::vector<cricket::VideoChannel*> video_channels() const {
+ return video_channels_;
+ }
+
// Only valid when using deprecated RTP data channels.
virtual cricket::RtpDataChannel* rtp_data_channel() {
return rtp_data_channel_.get();
@@ -547,8 +564,10 @@
const std::string GetTransportName(const std::string& content_name);
void DestroyRtcpTransport_n(const std::string& transport_name);
- void DestroyVideoChannel();
- void DestroyVoiceChannel();
+ void RemoveAndDestroyVideoChannel(cricket::VideoChannel* video_channel);
+ void DestroyVideoChannel(cricket::VideoChannel* video_channel);
+ void RemoveAndDestroyVoiceChannel(cricket::VoiceChannel* voice_channel);
+ void DestroyVoiceChannel(cricket::VoiceChannel* voice_channel);
void DestroyDataChannel();
rtc::Thread* const network_thread_;
@@ -567,10 +586,18 @@
const cricket::MediaConfig media_config_;
RtcEventLog* event_log_;
Call* call_;
- std::unique_ptr<cricket::VoiceChannel> voice_channel_;
- std::unique_ptr<cricket::VideoChannel> video_channel_;
+ // TODO(steveanton): voice_channels_ and video_channels_ used to be a single
+ // VoiceChannel/VideoChannel respectively but are being changed to support
+ // multiple m= lines in unified plan. But until more work is done, these can
+ // only have 0 or 1 channel each.
+ // These channels are owned by ChannelManager.
+ std::vector<cricket::VoiceChannel*> voice_channels_;
+ std::vector<cricket::VideoChannel*> video_channels_;
// |rtp_data_channel_| is used if in RTP data channel mode, |sctp_transport_|
// when using SCTP.
+ // TODO(steveanton): This should be changed to a bare pointer because
+ // WebRtcSession doesn't actually own the RtpDataChannel
+ // (ChannelManager does).
std::unique_ptr<cricket::RtpDataChannel> rtp_data_channel_;
std::unique_ptr<cricket::SctpTransportInternal> sctp_transport_;