diff options
author | jiayl@webrtc.org <jiayl@webrtc.org> | 2014-09-04 17:12:25 +0000 |
---|---|---|
committer | jiayl@webrtc.org <jiayl@webrtc.org> | 2014-09-04 17:12:25 +0000 |
commit | 1e086db8395c034f1dc0c4e318ad929a244c76b1 (patch) | |
tree | d758eab60612e6a1439a8fe3ab29d3ba306ea03d /app | |
parent | 32b3ea41f034fa85fc38e7af3e8d408e35780641 (diff) | |
download | talk-1e086db8395c034f1dc0c4e318ad929a244c76b1.tar.gz |
Fixes two issues in how we handle OfferToReceiveX for CreateOffer:
1. the options set in the first CreateOffer call should not affect the result of a second CreateOffer call, if SetLocalDescription is not called after the first CreateOffer. So the member var options_ of MediaStreamSignaling is removed to make each CreateOffer independent.
Instead, MediaSession is responsible to make sure that an m-line in the current local description is never removed from the newly created offer.
2. OfferToReceiveAudio used to default to true, i.e. always having m=audio line even if no audio track. This is changed so that by default m=audio is only added if there are any audio tracks.
BUG=2108
R=pthatcher@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/16309004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/talk@7068 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'app')
-rw-r--r-- | app/webrtc/mediastreamsignaling.cc | 145 | ||||
-rw-r--r-- | app/webrtc/mediastreamsignaling.h | 8 | ||||
-rw-r--r-- | app/webrtc/mediastreamsignaling_unittest.cc | 6 | ||||
-rw-r--r-- | app/webrtc/peerconnection.cc | 4 | ||||
-rw-r--r-- | app/webrtc/webrtcsession_unittest.cc | 28 |
5 files changed, 93 insertions, 98 deletions
diff --git a/app/webrtc/mediastreamsignaling.cc b/app/webrtc/mediastreamsignaling.cc index c4a8281..9a22ad4 100644 --- a/app/webrtc/mediastreamsignaling.cc +++ b/app/webrtc/mediastreamsignaling.cc @@ -51,9 +51,9 @@ namespace webrtc { using rtc::scoped_ptr; using rtc::scoped_refptr; -static bool ParseConstraints( +static bool ParseConstraintsForAnswer( const MediaConstraintsInterface* constraints, - cricket::MediaSessionOptions* options, bool is_answer) { + cricket::MediaSessionOptions* options) { bool value; size_t mandatory_constraints_satisfied = 0; @@ -82,7 +82,7 @@ static bool ParseConstraints( // kOfferToReceiveVideo defaults to false according to spec. But // if it is an answer and video is offered, we should still accept video // per default. - options->has_video |= is_answer; + options->has_video = true; } if (FindConstraint(constraints, @@ -133,6 +133,55 @@ static bool IsValidOfferToReceiveMedia(int value) { (value <= Options::kMaxOfferToReceiveMedia); } +// Add the stream and RTP data channel info to |session_options|. +static void SetStreams( + cricket::MediaSessionOptions* session_options, + rtc::scoped_refptr<StreamCollection> streams, + const MediaStreamSignaling::RtpDataChannels& rtp_data_channels) { + session_options->streams.clear(); + if (streams != NULL) { + for (size_t i = 0; i < streams->count(); ++i) { + MediaStreamInterface* stream = streams->at(i); + + AudioTrackVector audio_tracks(stream->GetAudioTracks()); + + // For each audio track in the stream, add it to the MediaSessionOptions. + for (size_t j = 0; j < audio_tracks.size(); ++j) { + scoped_refptr<MediaStreamTrackInterface> track(audio_tracks[j]); + session_options->AddStream( + cricket::MEDIA_TYPE_AUDIO, track->id(), stream->label()); + } + + VideoTrackVector video_tracks(stream->GetVideoTracks()); + + // For each video track in the stream, add it to the MediaSessionOptions. + for (size_t j = 0; j < video_tracks.size(); ++j) { + scoped_refptr<MediaStreamTrackInterface> track(video_tracks[j]); + session_options->AddStream( + cricket::MEDIA_TYPE_VIDEO, track->id(), stream->label()); + } + } + } + + // Check for data channels. + MediaStreamSignaling::RtpDataChannels::const_iterator data_channel_it = + rtp_data_channels.begin(); + for (; data_channel_it != rtp_data_channels.end(); ++data_channel_it) { + const DataChannel* channel = data_channel_it->second; + if (channel->state() == DataChannel::kConnecting || + channel->state() == DataChannel::kOpen) { + // |streamid| and |sync_label| are both set to the DataChannel label + // here so they can be signaled the same way as MediaStreams and Tracks. + // For MediaStreams, the sync_label is the MediaStream label and the + // track label is the same as |streamid|. + const std::string& streamid = channel->label(); + const std::string& sync_label = channel->label(); + session_options->AddStream( + cricket::MEDIA_TYPE_DATA, streamid, sync_label); + } + } +} + // Factory class for creating remote MediaStreams and MediaStreamTracks. class RemoteMediaStreamFactory { public: @@ -192,8 +241,6 @@ MediaStreamSignaling::MediaStreamSignaling( channel_manager)), last_allocated_sctp_even_sid_(-2), last_allocated_sctp_odd_sid_(-1) { - options_.has_video = false; - options_.has_audio = false; } MediaStreamSignaling::~MediaStreamSignaling() { @@ -377,40 +424,38 @@ bool MediaStreamSignaling::GetOptionsForOffer( return false; } - UpdateSessionOptions(); + session_options->has_audio = false; + session_options->has_video = false; + SetStreams(session_options, local_streams_, rtp_data_channels_); - // |options.has_audio| and |options.has_video| can only change from false to - // true, but never change from true to false. This is to make sure - // CreateOffer / CreateAnswer doesn't remove a media content - // description that has been created. - if (rtc_options.offer_to_receive_audio > 0) { - options_.has_audio = true; + // If |offer_to_receive_[audio/video]| is undefined, respect the flags set + // from SetStreams. Otherwise, overwrite it based on |rtc_options|. + if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) { + session_options->has_audio = rtc_options.offer_to_receive_audio > 0; } - if (rtc_options.offer_to_receive_video > 0) { - options_.has_video = true; + if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) { + session_options->has_video = rtc_options.offer_to_receive_video > 0; } - options_.vad_enabled = rtc_options.voice_activity_detection; - options_.transport_options.ice_restart = rtc_options.ice_restart; - options_.bundle_enabled = rtc_options.use_rtp_mux; - options_.bundle_enabled = EvaluateNeedForBundle(options_); - *session_options = options_; + session_options->vad_enabled = rtc_options.voice_activity_detection; + session_options->transport_options.ice_restart = rtc_options.ice_restart; + session_options->bundle_enabled = rtc_options.use_rtp_mux; + + session_options->bundle_enabled = EvaluateNeedForBundle(*session_options); return true; } bool MediaStreamSignaling::GetOptionsForAnswer( const MediaConstraintsInterface* constraints, cricket::MediaSessionOptions* options) { - UpdateSessionOptions(); + options->has_audio = false; + options->has_video = false; + SetStreams(options, local_streams_, rtp_data_channels_); - // Copy the |options_| to not let the flag MediaSessionOptions::has_audio and - // MediaSessionOptions::has_video affect subsequent offers. - cricket::MediaSessionOptions current_options = options_; - if (!ParseConstraints(constraints, ¤t_options, true)) { + if (!ParseConstraintsForAnswer(constraints, options)) { return false; } - current_options.bundle_enabled = EvaluateNeedForBundle(current_options); - *options = current_options; + options->bundle_enabled = EvaluateNeedForBundle(*options); return true; } @@ -545,54 +590,6 @@ void MediaStreamSignaling::OnDataChannelClose() { } } -void MediaStreamSignaling::UpdateSessionOptions() { - options_.streams.clear(); - if (local_streams_ != NULL) { - for (size_t i = 0; i < local_streams_->count(); ++i) { - MediaStreamInterface* stream = local_streams_->at(i); - - AudioTrackVector audio_tracks(stream->GetAudioTracks()); - if (!audio_tracks.empty()) { - options_.has_audio = true; - } - - // For each audio track in the stream, add it to the MediaSessionOptions. - for (size_t j = 0; j < audio_tracks.size(); ++j) { - scoped_refptr<MediaStreamTrackInterface> track(audio_tracks[j]); - options_.AddStream(cricket::MEDIA_TYPE_AUDIO, track->id(), - stream->label()); - } - - VideoTrackVector video_tracks(stream->GetVideoTracks()); - if (!video_tracks.empty()) { - options_.has_video = true; - } - // For each video track in the stream, add it to the MediaSessionOptions. - for (size_t j = 0; j < video_tracks.size(); ++j) { - scoped_refptr<MediaStreamTrackInterface> track(video_tracks[j]); - options_.AddStream(cricket::MEDIA_TYPE_VIDEO, track->id(), - stream->label()); - } - } - } - - // Check for data channels. - RtpDataChannels::const_iterator data_channel_it = rtp_data_channels_.begin(); - for (; data_channel_it != rtp_data_channels_.end(); ++data_channel_it) { - const DataChannel* channel = data_channel_it->second; - if (channel->state() == DataChannel::kConnecting || - channel->state() == DataChannel::kOpen) { - // |streamid| and |sync_label| are both set to the DataChannel label - // here so they can be signaled the same way as MediaStreams and Tracks. - // For MediaStreams, the sync_label is the MediaStream label and the - // track label is the same as |streamid|. - const std::string& streamid = channel->label(); - const std::string& sync_label = channel->label(); - options_.AddStream(cricket::MEDIA_TYPE_DATA, streamid, sync_label); - } - } -} - void MediaStreamSignaling::UpdateRemoteStreamsList( const cricket::StreamParamsVec& streams, cricket::MediaType media_type, diff --git a/app/webrtc/mediastreamsignaling.h b/app/webrtc/mediastreamsignaling.h index 7f17971..d4b1be8 100644 --- a/app/webrtc/mediastreamsignaling.h +++ b/app/webrtc/mediastreamsignaling.h @@ -160,6 +160,9 @@ class MediaStreamSignalingObserver { class MediaStreamSignaling : public sigslot::has_slots<> { public: + typedef std::map<std::string, rtc::scoped_refptr<DataChannel> > + RtpDataChannels; + MediaStreamSignaling(rtc::Thread* signaling_thread, MediaStreamSignalingObserver* stream_observer, cricket::ChannelManager* channel_manager); @@ -289,8 +292,6 @@ class MediaStreamSignaling : public sigslot::has_slots<> { }; typedef std::vector<TrackInfo> TrackInfos; - void UpdateSessionOptions(); - // Makes sure a MediaStream Track is created for each StreamParam in // |streams|. |media_type| is the type of the |streams| and can be either // audio or video. @@ -378,7 +379,6 @@ class MediaStreamSignaling : public sigslot::has_slots<> { RemotePeerInfo remote_info_; rtc::Thread* signaling_thread_; DataChannelFactory* data_channel_factory_; - cricket::MediaSessionOptions options_; MediaStreamSignalingObserver* stream_observer_; rtc::scoped_refptr<StreamCollection> local_streams_; rtc::scoped_refptr<StreamCollection> remote_streams_; @@ -392,8 +392,6 @@ class MediaStreamSignaling : public sigslot::has_slots<> { int last_allocated_sctp_even_sid_; int last_allocated_sctp_odd_sid_; - typedef std::map<std::string, rtc::scoped_refptr<DataChannel> > - RtpDataChannels; typedef std::vector<rtc::scoped_refptr<DataChannel> > SctpDataChannels; RtpDataChannels rtp_data_channels_; diff --git a/app/webrtc/mediastreamsignaling_unittest.cc b/app/webrtc/mediastreamsignaling_unittest.cc index fa83646..2ccfd8d 100644 --- a/app/webrtc/mediastreamsignaling_unittest.cc +++ b/app/webrtc/mediastreamsignaling_unittest.cc @@ -775,8 +775,10 @@ TEST_F(MediaStreamSignalingTest, MediaConstraintsInAnswer) { RTCOfferAnswerOptions default_rtc_options; EXPECT_TRUE(signaling_->GetOptionsForOffer(default_rtc_options, &updated_offer_options)); - EXPECT_TRUE(updated_offer_options.has_audio); - EXPECT_TRUE(updated_offer_options.has_video); + // By default, |has_audio| or |has_video| are false if there is no media + // track. + EXPECT_FALSE(updated_offer_options.has_audio); + EXPECT_FALSE(updated_offer_options.has_video); } // This test verifies that the remote MediaStreams corresponding to a received diff --git a/app/webrtc/peerconnection.cc b/app/webrtc/peerconnection.cc index 201269a..9c2bf02 100644 --- a/app/webrtc/peerconnection.cc +++ b/app/webrtc/peerconnection.cc @@ -508,10 +508,6 @@ void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, return; } RTCOfferAnswerOptions options; - // Defaults to receiving audio and not receiving video. - options.offer_to_receive_audio = - RTCOfferAnswerOptions::kOfferToReceiveMediaTrue; - options.offer_to_receive_video = 0; bool value; size_t mandatory_constraints = 0; diff --git a/app/webrtc/webrtcsession_unittest.cc b/app/webrtc/webrtcsession_unittest.cc index 2f731a9..001156d 100644 --- a/app/webrtc/webrtcsession_unittest.cc +++ b/app/webrtc/webrtcsession_unittest.cc @@ -510,7 +510,7 @@ class WebRtcSessionTest : public testing::Test { } void VerifyAnswerFromNonCryptoOffer() { - // Create a SDP without Crypto. + // Create an SDP without Crypto. cricket::MediaSessionOptions options; options.has_video = true; JsepSessionDescription* offer( @@ -1211,14 +1211,13 @@ TEST_F(WebRtcSessionTest, TestCreateSdesOfferReceiveSdesAnswer) { rtc::FromString<uint64>(offer->session_version())); SetLocalDescriptionWithoutError(offer); + EXPECT_EQ(0u, video_channel_->send_streams().size()); + EXPECT_EQ(0u, voice_channel_->send_streams().size()); mediastream_signaling_.SendAudioVideoStream2(); answer = CreateRemoteAnswer(session_->local_description()); SetRemoteDescriptionWithoutError(answer); - EXPECT_EQ(0u, video_channel_->send_streams().size()); - EXPECT_EQ(0u, voice_channel_->send_streams().size()); - // Make sure the receive streams have not changed. ASSERT_EQ(1u, video_channel_->recv_streams().size()); EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); @@ -1992,13 +1991,21 @@ TEST_F(WebRtcSessionTest, CreateOfferWithConstraints) { const cricket::ContentInfo* content = cricket::GetFirstAudioContent(offer->description()); - EXPECT_TRUE(content != NULL); + content = cricket::GetFirstVideoContent(offer->description()); EXPECT_TRUE(content != NULL); - // TODO(perkj): Should the direction be set to SEND_ONLY if - // The constraints is set to not receive audio or video but a track is added? + // Sets constraints to false and verifies that audio/video contents are + // removed. + options.offer_to_receive_audio = 0; + options.offer_to_receive_video = 0; + offer.reset(CreateOffer(options)); + + content = cricket::GetFirstAudioContent(offer->description()); + EXPECT_TRUE(content == NULL); + content = cricket::GetFirstVideoContent(offer->description()); + EXPECT_TRUE(content == NULL); } // Test that an answer can not be created if the last remote description is not @@ -2037,8 +2044,7 @@ TEST_F(WebRtcSessionTest, CreateAudioAnswerWithoutConstraintsOrStreams) { Init(NULL); // Create a remote offer with audio only. cricket::MediaSessionOptions options; - options.has_audio = true; - options.has_video = false; + rtc::scoped_ptr<JsepSessionDescription> offer( CreateRemoteOffer(options)); ASSERT_TRUE(cricket::GetFirstVideoContent(offer->description()) == NULL); @@ -2174,7 +2180,6 @@ TEST_F(WebRtcSessionTest, TestAVOfferWithAudioOnlyAnswer) { SessionDescriptionInterface* offer = CreateOffer(); cricket::MediaSessionOptions options; - options.has_video = false; SessionDescriptionInterface* answer = CreateRemoteAnswer(offer, options); // SetLocalDescription and SetRemoteDescriptions takes ownership of offer @@ -2887,7 +2892,6 @@ TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) { TEST_F(WebRtcSessionTest, TestCreateAnswerWithNewUfragAndPassword) { Init(NULL); cricket::MediaSessionOptions options; - options.has_audio = true; options.has_video = true; rtc::scoped_ptr<JsepSessionDescription> offer( CreateRemoteOffer(options)); @@ -2919,7 +2923,6 @@ TEST_F(WebRtcSessionTest, TestCreateAnswerWithNewUfragAndPassword) { TEST_F(WebRtcSessionTest, TestCreateAnswerWithOldUfragAndPassword) { Init(NULL); cricket::MediaSessionOptions options; - options.has_audio = true; options.has_video = true; rtc::scoped_ptr<JsepSessionDescription> offer( CreateRemoteOffer(options)); @@ -2985,7 +2988,6 @@ TEST_F(WebRtcSessionTest, TestIceStatesBundle) { TEST_F(WebRtcSessionTest, SetSdpFailedOnSessionError) { Init(NULL); cricket::MediaSessionOptions options; - options.has_audio = true; options.has_video = true; cricket::BaseSession::Error error_code = cricket::BaseSession::ERROR_CONTENT; |