From ed10bd95492f09da792ccf541f1d139aa7736504 Mon Sep 17 00:00:00 2001 From: Steve Anton Date: Tue, 5 Dec 2017 10:52:59 -0800 Subject: [PATCH] Modify SetLocalDescription helpers to work with RtpTransceivers This change allows EnableBundle and PushdownMediaDescription to work with RtpTransceivers, which means they can be reused in the Unified Plan version of SetLocalDescription. Bug: webrtc:8587 Change-Id: I4d862556879c14cea06fdf9d5c7c29cc32e1057a Reviewed-on: https://webrtc-review.googlesource.com/27762 Commit-Queue: Steve Anton Reviewed-by: Zhi Huang Reviewed-by: Peter Thatcher Cr-Commit-Position: refs/heads/master@{#21092} --- pc/peerconnection.cc | 108 ++++++++++++++++++++++++++++++------------- pc/peerconnection.h | 13 +++++- 2 files changed, 89 insertions(+), 32 deletions(-) diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc index 5c0da40679..acde8d12e8 100644 --- a/pc/peerconnection.cc +++ b/pc/peerconnection.cc @@ -1873,6 +1873,27 @@ RTCError PeerConnection::ApplyRemoteDescription( return RTCError::OK(); } +const cricket::ContentInfo* PeerConnection::FindMediaSectionForTransceiver( + rtc::scoped_refptr> + transceiver, + const SessionDescriptionInterface* sdesc) const { + RTC_DCHECK(transceiver); + RTC_DCHECK(sdesc); + if (IsUnifiedPlan()) { + if (!transceiver->internal()->mid()) { + // This transceiver is not associated with a media section yet. + return nullptr; + } + return sdesc->description()->GetContentByName( + *transceiver->internal()->mid()); + } else { + // Plan B only allows at most one audio and one video section, so use the + // first media section of that type. + return cricket::GetFirstMediaContent(sdesc->description()->contents(), + transceiver->internal()->media_type()); + } +} + PeerConnectionInterface::RTCConfiguration PeerConnection::GetConfiguration() { return configuration_; } @@ -3531,7 +3552,7 @@ RTCError PeerConnection::UpdateSessionState(cricket::ContentAction action, // If this is answer-ish we're ready to let media flow. if (action == cricket::CA_ANSWER || action == cricket::CA_PRANSWER) { - EnableChannels(); + EnableSending(); } // Update the signaling state according to the specified state machine (see @@ -3565,30 +3586,57 @@ RTCError PeerConnection::UpdateSessionState(cricket::ContentAction action, RTCError PeerConnection::PushdownMediaDescription( cricket::ContentAction action, cricket::ContentSource source) { - const SessionDescription* sdesc = - (source == cricket::CS_LOCAL ? local_description() : remote_description()) - ->description(); + const SessionDescriptionInterface* sdesc = + (source == cricket::CS_LOCAL ? local_description() + : remote_description()); RTC_DCHECK(sdesc); - for (auto* channel : Channels()) { - // TODO(steveanton): Add support for multiple channels of the same type. + + // Push down the new SDP media section for each audio/video transceiver. + for (auto transceiver : transceivers_) { const ContentInfo* content_info = - cricket::GetFirstMediaContent(sdesc->contents(), channel->media_type()); - if (!content_info) { + FindMediaSectionForTransceiver(transceiver, sdesc); + cricket::BaseChannel* channel = transceiver->internal()->channel(); + if (!channel || !content_info || content_info->rejected) { continue; } const MediaContentDescription* content_desc = static_cast(content_info->description); - if (content_desc && !content_info->rejected) { - std::string error; - bool success = - (source == cricket::CS_LOCAL) - ? channel->SetLocalContent(content_desc, action, &error) - : channel->SetRemoteContent(content_desc, action, &error); - if (!success) { - LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, std::move(error)); + if (!content_desc) { + continue; + } + std::string error; + bool success = + (source == cricket::CS_LOCAL) + ? channel->SetLocalContent(content_desc, action, &error) + : channel->SetRemoteContent(content_desc, action, &error); + if (!success) { + LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, std::move(error)); + } + } + + // If using the RtpDataChannel, push down the new SDP section for it too. + if (rtp_data_channel_) { + const ContentInfo* data_content = + cricket::GetFirstDataContent(sdesc->description()); + if (data_content && !data_content->rejected) { + const MediaContentDescription* data_desc = + static_cast( + data_content->description); + if (data_desc) { + std::string error; + bool success = + (source == cricket::CS_LOCAL) + ? rtp_data_channel_->SetLocalContent(data_desc, action, &error) + : rtp_data_channel_->SetRemoteContent(data_desc, action, + &error); + if (!success) { + LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, + std::move(error)); + } } } } + // Need complete offer/answer with an SCTP m= section before starting SCTP, // according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19 if (sctp_transport_ && local_description() && remote_description() && @@ -3602,6 +3650,7 @@ RTCError PeerConnection::PushdownMediaDescription( "Failed to push down SCTP parameters."); } } + return RTCError::OK(); } @@ -3673,14 +3722,14 @@ bool PeerConnection::EnableBundle(const cricket::ContentGroup& bundle) { auto maybe_set_transport = [this, bundle, transport_name](cricket::BaseChannel* ch) { if (!ch || !bundle.HasContentName(ch->content_name())) { - return true; + return; } std::string old_transport_name = ch->transport_name(); if (old_transport_name == transport_name) { RTC_LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name() << " on " << transport_name << "."; - return true; + return; } cricket::DtlsTransportInternal* rtp_dtls_transport = @@ -3704,14 +3753,13 @@ bool PeerConnection::EnableBundle(const cricket::ContentGroup& bundle) { transport_controller_->DestroyDtlsTransport( old_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); } - return true; }; - if (!maybe_set_transport(voice_channel()) || - !maybe_set_transport(video_channel()) || - !maybe_set_transport(rtp_data_channel())) { - return false; + for (auto transceiver : transceivers_) { + maybe_set_transport(transceiver->internal()->channel()); } + maybe_set_transport(rtp_data_channel_); + // For SCTP, transport creation/deletion happens here instead of in the // object itself. if (sctp_transport_) { @@ -4027,14 +4075,12 @@ void PeerConnection::OnTransportControllerDtlsHandshakeError( } } -// Enabling voice and video (and RTP data) channels. -void PeerConnection::EnableChannels() { - if (voice_channel() && !voice_channel()->enabled()) { - voice_channel()->Enable(true); - } - - if (video_channel() && !video_channel()->enabled()) { - video_channel()->Enable(true); +void PeerConnection::EnableSending() { + for (auto transceiver : transceivers_) { + cricket::BaseChannel* channel = transceiver->internal()->channel(); + if (channel && !channel->enabled()) { + channel->Enable(true); + } } if (rtp_data_channel_ && !rtp_data_channel_->enabled()) { diff --git a/pc/peerconnection.h b/pc/peerconnection.h index 58f7646a5a..4c8983bc47 100644 --- a/pc/peerconnection.h +++ b/pc/peerconnection.h @@ -376,6 +376,15 @@ class PeerConnection : public PeerConnectionInterface, RTCError ApplyRemoteDescription( std::unique_ptr desc); + // Returns the media section in the given session description that is + // associated with the RtpTransceiver. Returns null if none found or this + // RtpTransceiver is not associated. Logic varies depending on the + // SdpSemantics specified in the configuration. + const cricket::ContentInfo* FindMediaSectionForTransceiver( + rtc::scoped_refptr> + transceiver, + const SessionDescriptionInterface* sdesc) const; + bool IsClosed() const { return signaling_state_ == PeerConnectionInterface::kClosed; } @@ -638,7 +647,9 @@ class PeerConnection : public PeerConnectionInterface, bool EnableBundle(const cricket::ContentGroup& bundle); // Enables media channels to allow sending of media. - void EnableChannels(); + // This enables media to flow on all configured audio/video channels and the + // RtpDataChannel. + void EnableSending(); // Returns the media index for a local ice candidate given the content name. // Returns false if the local session description does not have a media // content called |content_name|.