Revert of Moving MediaStreamSignaling logic into PeerConnection. (patchset #10 id:180001 of https://codereview.webrtc.org/1393563002/ )
Reason for revert:
Broke browser_tests on Mac. Still need to investigate the cause.
Original issue's description:
> Moving MediaStreamSignaling logic into PeerConnection.
>
> This needs to happen because in the future, m-lines will be offered
> based on the set of RtpSenders/RtpReceivers, rather than the set of
> tracks that MediaStreamSignaling knows about.
>
> Besides that, MediaStreamSignaling was a "glue class" without
> a clearly defined role, so it going away is good for other
> reasons as well.
>
> Committed: https://crrev.com/97c392935411398b506861601c82e31d95c591f0
> Cr-Commit-Position: refs/heads/master@{#10268}
TBR=pthatcher@webrtc.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
Review URL: https://codereview.webrtc.org/1403633005
Cr-Commit-Position: refs/heads/master@{#10269}
diff --git a/talk/app/webrtc/datachannel.cc b/talk/app/webrtc/datachannel.cc
index 20cf743..2028dc9 100644
--- a/talk/app/webrtc/datachannel.cc
+++ b/talk/app/webrtc/datachannel.cc
@@ -31,7 +31,6 @@
#include "talk/app/webrtc/mediastreamprovider.h"
#include "talk/app/webrtc/sctputils.h"
-#include "talk/media/sctp/sctpdataengine.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/refcount.h"
@@ -44,42 +43,6 @@
MSG_CHANNELREADY,
};
-bool SctpSidAllocator::AllocateSid(rtc::SSLRole role, int* sid) {
- int potential_sid = (role == rtc::SSL_CLIENT) ? 0 : 1;
- while (!IsSidAvailable(potential_sid)) {
- potential_sid += 2;
- if (potential_sid > static_cast<int>(cricket::kMaxSctpSid)) {
- return false;
- }
- }
-
- *sid = potential_sid;
- used_sids_.insert(potential_sid);
- return true;
-}
-
-bool SctpSidAllocator::ReserveSid(int sid) {
- if (!IsSidAvailable(sid)) {
- return false;
- }
- used_sids_.insert(sid);
- return true;
-}
-
-void SctpSidAllocator::ReleaseSid(int sid) {
- auto it = used_sids_.find(sid);
- if (it != used_sids_.end()) {
- used_sids_.erase(it);
- }
-}
-
-bool SctpSidAllocator::IsSidAvailable(int sid) const {
- if (sid < 0 || sid > static_cast<int>(cricket::kMaxSctpSid)) {
- return false;
- }
- return used_sids_.find(sid) == used_sids_.end();
-}
-
DataChannel::PacketQueue::PacketQueue() : byte_count_(0) {}
DataChannel::PacketQueue::~PacketQueue() {
@@ -294,9 +257,8 @@
void DataChannel::SetSctpSid(int sid) {
ASSERT(config_.id < 0 && sid >= 0 && data_channel_type_ == cricket::DCT_SCTP);
- if (config_.id == sid) {
+ if (config_.id == sid)
return;
- }
config_.id = sid;
provider_->AddSctpDataStream(sid);
@@ -314,13 +276,6 @@
}
}
-// The underlying transport channel was destroyed.
-// This function makes sure the DataChannel is disconnected and changes state to
-// kClosed.
-void DataChannel::OnTransportChannelDestroyed() {
- DoClose();
-}
-
void DataChannel::SetSendSsrc(uint32_t send_ssrc) {
ASSERT(data_channel_type_ == cricket::DCT_RTP);
if (send_ssrc_set_) {
@@ -339,6 +294,13 @@
}
}
+// The underlaying data engine is closing.
+// This function makes sure the DataChannel is disconnected and changes state to
+// kClosed.
+void DataChannel::OnDataEngineClose() {
+ DoClose();
+}
+
void DataChannel::OnDataReceived(cricket::DataChannel* channel,
const cricket::ReceiveDataParams& params,
const rtc::Buffer& payload) {
@@ -399,12 +361,6 @@
}
}
-void DataChannel::OnStreamClosedRemotely(uint32_t sid) {
- if (data_channel_type_ == cricket::DCT_SCTP && sid == config_.id) {
- Close();
- }
-}
-
void DataChannel::OnChannelReady(bool writable) {
writable_ = writable;
if (!writable) {
@@ -480,17 +436,13 @@
}
void DataChannel::SetState(DataState state) {
- if (state_ == state) {
+ if (state_ == state)
return;
- }
state_ = state;
if (observer_) {
observer_->OnStateChange();
}
- if (state_ == kClosed) {
- SignalClosed(this);
- }
}
void DataChannel::DisconnectFromProvider() {
diff --git a/talk/app/webrtc/datachannel.h b/talk/app/webrtc/datachannel.h
index 2713ae3..4506f71 100644
--- a/talk/app/webrtc/datachannel.h
+++ b/talk/app/webrtc/datachannel.h
@@ -29,7 +29,6 @@
#define TALK_APP_WEBRTC_DATACHANNEL_H_
#include <deque>
-#include <set>
#include <string>
#include "talk/app/webrtc/datachannelinterface.h"
@@ -84,28 +83,6 @@
OpenHandshakeRole open_handshake_role;
};
-// Helper class to allocate unique IDs for SCTP DataChannels
-class SctpSidAllocator {
- public:
- // Gets the first unused odd/even id based on the DTLS role. If |role| is
- // SSL_CLIENT, the allocated id starts from 0 and takes even numbers;
- // otherwise, the id starts from 1 and takes odd numbers.
- // Returns false if no id can be allocated.
- bool AllocateSid(rtc::SSLRole role, int* sid);
-
- // Attempts to reserve a specific sid. Returns false if it's unavailable.
- bool ReserveSid(int sid);
-
- // Indicates that |sid| isn't in use any more, and is thus available again.
- void ReleaseSid(int sid);
-
- private:
- // Checks if |sid| is available to be assigned to a new SCTP data channel.
- bool IsSidAvailable(int sid) const;
-
- std::set<int> used_sids_;
-};
-
// DataChannel is a an implementation of the DataChannelInterface based on
// libjingle's data engine. It provides an implementation of unreliable or
// reliabledata channels. Currently this class is specifically designed to use
@@ -152,6 +129,9 @@
// rtc::MessageHandler override.
virtual void OnMessage(rtc::Message* msg);
+ // Called if the underlying data engine is closing.
+ void OnDataEngineClose();
+
// Called when the channel's ready to use. That can happen when the
// underlying DataMediaChannel becomes ready, or when this channel is a new
// stream on an existing DataMediaChannel, and we've finished negotiation.
@@ -161,7 +141,6 @@
void OnDataReceived(cricket::DataChannel* channel,
const cricket::ReceiveDataParams& params,
const rtc::Buffer& payload);
- void OnStreamClosedRemotely(uint32_t sid);
// The remote peer request that this channel should be closed.
void RemotePeerRequestClose();
@@ -172,10 +151,7 @@
// be called once.
void SetSctpSid(int sid);
// Called when the transport channel is created.
- // Only needs to be called for SCTP data channels.
void OnTransportChannelCreated();
- // Called when the transport channel is destroyed.
- void OnTransportChannelDestroyed();
// The following methods are for RTP only.
@@ -191,11 +167,6 @@
return data_channel_type_;
}
- // Emitted when state transitions to kClosed.
- // In the case of SCTP channels, this signal can be used to tell when the
- // channel's sid is free.
- sigslot::signal1<DataChannel*> SignalClosed;
-
protected:
DataChannel(DataChannelProviderInterface* client,
cricket::DataChannelType dct,
@@ -276,6 +247,16 @@
PacketQueue queued_send_data_;
};
+class DataChannelFactory {
+ public:
+ virtual rtc::scoped_refptr<DataChannel> CreateDataChannel(
+ const std::string& label,
+ const InternalDataChannelInit* config) = 0;
+
+ protected:
+ virtual ~DataChannelFactory() {}
+};
+
// Define proxy for DataChannelInterface.
BEGIN_PROXY_MAP(DataChannel)
PROXY_METHOD1(void, RegisterObserver, DataChannelObserver*)
diff --git a/talk/app/webrtc/datachannel_unittest.cc b/talk/app/webrtc/datachannel_unittest.cc
index ff79541..b4f611e 100644
--- a/talk/app/webrtc/datachannel_unittest.cc
+++ b/talk/app/webrtc/datachannel_unittest.cc
@@ -31,7 +31,6 @@
#include "webrtc/base/gunit.h"
using webrtc::DataChannel;
-using webrtc::SctpSidAllocator;
class FakeDataChannelObserver : public webrtc::DataChannelObserver {
public:
@@ -507,75 +506,3 @@
webrtc_data_channel_->OnTransportChannelCreated();
webrtc_data_channel_->Close();
}
-
-class SctpSidAllocatorTest : public testing::Test {
- protected:
- SctpSidAllocator allocator_;
-};
-
-// Verifies that an even SCTP id is allocated for SSL_CLIENT and an odd id for
-// SSL_SERVER.
-TEST_F(SctpSidAllocatorTest, SctpIdAllocationBasedOnRole) {
- int id;
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_SERVER, &id));
- EXPECT_EQ(1, id);
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_CLIENT, &id));
- EXPECT_EQ(0, id);
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_SERVER, &id));
- EXPECT_EQ(3, id);
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_CLIENT, &id));
- EXPECT_EQ(2, id);
-}
-
-// Verifies that SCTP ids of existing DataChannels are not reused.
-TEST_F(SctpSidAllocatorTest, SctpIdAllocationNoReuse) {
- int old_id = 1;
- EXPECT_TRUE(allocator_.ReserveSid(old_id));
-
- int new_id;
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_SERVER, &new_id));
- EXPECT_NE(old_id, new_id);
-
- old_id = 0;
- EXPECT_TRUE(allocator_.ReserveSid(old_id));
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_CLIENT, &new_id));
- EXPECT_NE(old_id, new_id);
-}
-
-// Verifies that SCTP ids of removed DataChannels can be reused.
-TEST_F(SctpSidAllocatorTest, SctpIdReusedForRemovedDataChannel) {
- int odd_id = 1;
- int even_id = 0;
- EXPECT_TRUE(allocator_.ReserveSid(odd_id));
- EXPECT_TRUE(allocator_.ReserveSid(even_id));
-
- int allocated_id = -1;
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_SERVER, &allocated_id));
- EXPECT_EQ(odd_id + 2, allocated_id);
-
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_CLIENT, &allocated_id));
- EXPECT_EQ(even_id + 2, allocated_id);
-
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_SERVER, &allocated_id));
- EXPECT_EQ(odd_id + 4, allocated_id);
-
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_CLIENT, &allocated_id));
- EXPECT_EQ(even_id + 4, allocated_id);
-
- allocator_.ReleaseSid(odd_id);
- allocator_.ReleaseSid(even_id);
-
- // Verifies that removed ids are reused.
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_SERVER, &allocated_id));
- EXPECT_EQ(odd_id, allocated_id);
-
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_CLIENT, &allocated_id));
- EXPECT_EQ(even_id, allocated_id);
-
- // Verifies that used higher ids are not reused.
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_SERVER, &allocated_id));
- EXPECT_EQ(odd_id + 6, allocated_id);
-
- EXPECT_TRUE(allocator_.AllocateSid(rtc::SSL_CLIENT, &allocated_id));
- EXPECT_EQ(even_id + 6, allocated_id);
-}
diff --git a/talk/app/webrtc/mediastreamsignaling.cc b/talk/app/webrtc/mediastreamsignaling.cc
index b405273..c12471c 100644
--- a/talk/app/webrtc/mediastreamsignaling.cc
+++ b/talk/app/webrtc/mediastreamsignaling.cc
@@ -27,4 +27,1000 @@
#include "talk/app/webrtc/mediastreamsignaling.h"
-// TODO(deadbeef): Remove this file once Chrome build files don't reference it.
+#include <vector>
+
+#include "talk/app/webrtc/audiotrack.h"
+#include "talk/app/webrtc/mediaconstraintsinterface.h"
+#include "talk/app/webrtc/mediastreamproxy.h"
+#include "talk/app/webrtc/mediastreamtrackproxy.h"
+#include "talk/app/webrtc/remoteaudiosource.h"
+#include "talk/app/webrtc/remotevideocapturer.h"
+#include "talk/app/webrtc/sctputils.h"
+#include "talk/app/webrtc/videosource.h"
+#include "talk/app/webrtc/videotrack.h"
+#include "talk/media/sctp/sctpdataengine.h"
+#include "webrtc/base/bytebuffer.h"
+#include "webrtc/base/stringutils.h"
+
+static const char kDefaultStreamLabel[] = "default";
+static const char kDefaultAudioTrackLabel[] = "defaulta0";
+static const char kDefaultVideoTrackLabel[] = "defaultv0";
+
+namespace webrtc {
+
+using rtc::scoped_ptr;
+using rtc::scoped_refptr;
+
+static bool ParseConstraintsForAnswer(
+ const MediaConstraintsInterface* constraints,
+ cricket::MediaSessionOptions* options) {
+ bool value = false;
+ size_t mandatory_constraints_satisfied = 0;
+
+ // kOfferToReceiveAudio defaults to true according to spec.
+ if (!FindConstraint(constraints,
+ MediaConstraintsInterface::kOfferToReceiveAudio,
+ &value, &mandatory_constraints_satisfied) || value) {
+ options->recv_audio = true;
+ }
+
+ // kOfferToReceiveVideo defaults to false according to spec. But
+ // if it is an answer and video is offered, we should still accept video
+ // per default.
+ value = false;
+ if (!FindConstraint(constraints,
+ MediaConstraintsInterface::kOfferToReceiveVideo,
+ &value, &mandatory_constraints_satisfied) || value) {
+ options->recv_video = true;
+ }
+
+ if (FindConstraint(constraints,
+ MediaConstraintsInterface::kVoiceActivityDetection,
+ &value, &mandatory_constraints_satisfied)) {
+ options->vad_enabled = value;
+ }
+
+ if (FindConstraint(constraints,
+ MediaConstraintsInterface::kUseRtpMux,
+ &value, &mandatory_constraints_satisfied)) {
+ options->bundle_enabled = value;
+ } else {
+ // kUseRtpMux defaults to true according to spec.
+ options->bundle_enabled = true;
+ }
+ if (FindConstraint(constraints,
+ MediaConstraintsInterface::kIceRestart,
+ &value, &mandatory_constraints_satisfied)) {
+ options->transport_options.ice_restart = value;
+ } else {
+ // kIceRestart defaults to false according to spec.
+ options->transport_options.ice_restart = false;
+ }
+
+ if (!constraints) {
+ return true;
+ }
+ return mandatory_constraints_satisfied == constraints->GetMandatory().size();
+}
+
+// Returns true if if at least one media content is present and
+// |options.bundle_enabled| is true.
+// Bundle will be enabled by default if at least one media content is present
+// and the constraint kUseRtpMux has not disabled bundle.
+static bool EvaluateNeedForBundle(const cricket::MediaSessionOptions& options) {
+ return options.bundle_enabled &&
+ (options.has_audio() || options.has_video() || options.has_data());
+}
+
+static bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
+ return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
+}
+
+static bool IsValidOfferToReceiveMedia(int value) {
+ typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
+ return (value >= Options::kUndefined) &&
+ (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->AddSendStream(
+ 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->AddSendStream(
+ 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->AddSendStream(
+ cricket::MEDIA_TYPE_DATA, streamid, sync_label);
+ }
+ }
+}
+
+// Factory class for creating remote MediaStreams and MediaStreamTracks.
+class RemoteMediaStreamFactory {
+ public:
+ explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
+ cricket::ChannelManager* channel_manager)
+ : signaling_thread_(signaling_thread),
+ channel_manager_(channel_manager) {
+ }
+
+ rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
+ const std::string& stream_label) {
+ return MediaStreamProxy::Create(
+ signaling_thread_, MediaStream::Create(stream_label));
+ }
+
+ AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
+ const std::string& track_id) {
+ return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
+ stream, track_id, RemoteAudioSource::Create().get());
+ }
+
+ VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
+ const std::string& track_id) {
+ return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
+ stream, track_id, VideoSource::Create(channel_manager_,
+ new RemoteVideoCapturer(),
+ NULL).get());
+ }
+
+ private:
+ template <typename TI, typename T, typename TP, typename S>
+ TI* AddTrack(MediaStreamInterface* stream, const std::string& track_id,
+ S* source) {
+ rtc::scoped_refptr<TI> track(
+ TP::Create(signaling_thread_, T::Create(track_id, source)));
+ track->set_state(webrtc::MediaStreamTrackInterface::kLive);
+ if (stream->AddTrack(track)) {
+ return track;
+ }
+ return NULL;
+ }
+
+ rtc::Thread* signaling_thread_;
+ cricket::ChannelManager* channel_manager_;
+};
+
+MediaStreamSignaling::MediaStreamSignaling(
+ rtc::Thread* signaling_thread,
+ MediaStreamSignalingObserver* stream_observer,
+ cricket::ChannelManager* channel_manager)
+ : signaling_thread_(signaling_thread),
+ data_channel_factory_(NULL),
+ stream_observer_(stream_observer),
+ local_streams_(StreamCollection::Create()),
+ remote_streams_(StreamCollection::Create()),
+ remote_stream_factory_(new RemoteMediaStreamFactory(signaling_thread,
+ channel_manager)),
+ last_allocated_sctp_even_sid_(-2),
+ last_allocated_sctp_odd_sid_(-1) {
+}
+
+MediaStreamSignaling::~MediaStreamSignaling() {
+}
+
+void MediaStreamSignaling::TearDown() {
+ OnAudioChannelClose();
+ OnVideoChannelClose();
+ OnDataChannelClose();
+}
+
+bool MediaStreamSignaling::IsSctpSidAvailable(int sid) const {
+ if (sid < 0 || sid > static_cast<int>(cricket::kMaxSctpSid))
+ return false;
+
+ return FindDataChannelBySid(sid) < 0;
+}
+
+// Gets the first unused odd/even id based on the DTLS role. If |role| is
+// SSL_CLIENT, the allocated id starts from 0 and takes even numbers; otherwise,
+// the id starts from 1 and takes odd numbers. Returns false if no id can be
+// allocated.
+bool MediaStreamSignaling::AllocateSctpSid(rtc::SSLRole role, int* sid) {
+ int& last_id = (role == rtc::SSL_CLIENT) ?
+ last_allocated_sctp_even_sid_ : last_allocated_sctp_odd_sid_;
+
+ do {
+ last_id += 2;
+ } while (last_id <= static_cast<int>(cricket::kMaxSctpSid) &&
+ !IsSctpSidAvailable(last_id));
+
+ if (last_id > static_cast<int>(cricket::kMaxSctpSid)) {
+ return false;
+ }
+
+ *sid = last_id;
+ return true;
+}
+
+bool MediaStreamSignaling::HasDataChannels() const {
+ return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
+}
+
+bool MediaStreamSignaling::AddDataChannel(DataChannel* data_channel) {
+ ASSERT(data_channel != NULL);
+ if (data_channel->data_channel_type() == cricket::DCT_RTP) {
+ if (rtp_data_channels_.find(data_channel->label()) !=
+ rtp_data_channels_.end()) {
+ LOG(LS_ERROR) << "DataChannel with label " << data_channel->label()
+ << " already exists.";
+ return false;
+ }
+ rtp_data_channels_[data_channel->label()] = data_channel;
+ } else {
+ ASSERT(data_channel->data_channel_type() == cricket::DCT_SCTP);
+ sctp_data_channels_.push_back(data_channel);
+ }
+ return true;
+}
+
+bool MediaStreamSignaling::AddDataChannelFromOpenMessage(
+ const cricket::ReceiveDataParams& params,
+ const rtc::Buffer& payload) {
+ if (!data_channel_factory_) {
+ LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
+ << "are not supported.";
+ return false;
+ }
+
+ std::string label;
+ InternalDataChannelInit config;
+ config.id = params.ssrc;
+ if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
+ LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
+ << params.ssrc;
+ return false;
+ }
+ config.open_handshake_role = InternalDataChannelInit::kAcker;
+
+ scoped_refptr<DataChannel> channel(
+ data_channel_factory_->CreateDataChannel(label, &config));
+ if (!channel.get()) {
+ LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
+ return false;
+ }
+
+ stream_observer_->OnAddDataChannel(channel);
+ return true;
+}
+
+void MediaStreamSignaling::RemoveSctpDataChannel(int sid) {
+ ASSERT(sid >= 0);
+ for (SctpDataChannels::iterator iter = sctp_data_channels_.begin();
+ iter != sctp_data_channels_.end();
+ ++iter) {
+ if ((*iter)->id() == sid) {
+ sctp_data_channels_.erase(iter);
+
+ if (rtc::IsEven(sid) && sid <= last_allocated_sctp_even_sid_) {
+ last_allocated_sctp_even_sid_ = sid - 2;
+ } else if (rtc::IsOdd(sid) && sid <= last_allocated_sctp_odd_sid_) {
+ last_allocated_sctp_odd_sid_ = sid - 2;
+ }
+ return;
+ }
+ }
+}
+
+bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
+ if (local_streams_->find(local_stream->label()) != NULL) {
+ LOG(LS_WARNING) << "MediaStream with label " << local_stream->label()
+ << "already exist.";
+ return false;
+ }
+ local_streams_->AddStream(local_stream);
+
+ // Find tracks that has already been configured in SDP. This can occur if a
+ // local session description that contains the MSID of these tracks is set
+ // before AddLocalStream is called. It can also occur if the local session
+ // description is not changed and RemoveLocalStream
+ // is called and later AddLocalStream is called again with the same stream.
+ AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
+ for (AudioTrackVector::const_iterator it = audio_tracks.begin();
+ it != audio_tracks.end(); ++it) {
+ const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
+ track_info->ssrc, cricket::MEDIA_TYPE_AUDIO);
+ }
+ }
+
+ VideoTrackVector video_tracks = local_stream->GetVideoTracks();
+ for (VideoTrackVector::const_iterator it = video_tracks.begin();
+ it != video_tracks.end(); ++it) {
+ const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
+ track_info->ssrc, cricket::MEDIA_TYPE_VIDEO);
+ }
+ }
+ return true;
+}
+
+void MediaStreamSignaling::RemoveLocalStream(
+ MediaStreamInterface* local_stream) {
+ AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
+ for (AudioTrackVector::const_iterator it = audio_tracks.begin();
+ it != audio_tracks.end(); ++it) {
+ const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ stream_observer_->OnRemoveLocalAudioTrack(local_stream, *it,
+ track_info->ssrc);
+ }
+ }
+ VideoTrackVector video_tracks = local_stream->GetVideoTracks();
+ for (VideoTrackVector::const_iterator it = video_tracks.begin();
+ it != video_tracks.end(); ++it) {
+ const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
+ local_stream->label(),
+ (*it)->id());
+ if (track_info) {
+ stream_observer_->OnRemoveLocalVideoTrack(local_stream, *it);
+ }
+ }
+
+ local_streams_->RemoveStream(local_stream);
+ stream_observer_->OnRemoveLocalStream(local_stream);
+}
+
+bool MediaStreamSignaling::GetOptionsForOffer(
+ const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
+ cricket::MediaSessionOptions* session_options) {
+ typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
+ if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
+ !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
+ return false;
+ }
+
+ SetStreams(session_options, local_streams_, rtp_data_channels_);
+
+ // According to the spec, offer to receive audio/video if the constraint is
+ // not set and there are send streams.
+ if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
+ session_options->recv_audio =
+ session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO);
+ } else {
+ session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
+ }
+ if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
+ session_options->recv_video =
+ session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO);
+ } else {
+ session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
+ }
+
+ 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) {
+ SetStreams(options, local_streams_, rtp_data_channels_);
+
+ options->recv_audio = false;
+ options->recv_video = false;
+ if (!ParseConstraintsForAnswer(constraints, options)) {
+ return false;
+ }
+ options->bundle_enabled = EvaluateNeedForBundle(*options);
+ return true;
+}
+
+// Updates or creates remote MediaStream objects given a
+// remote SessionDesription.
+// If the remote SessionDesription contains new remote MediaStreams
+// the observer OnAddStream method is called. If a remote MediaStream is missing
+// from the remote SessionDescription OnRemoveStream is called.
+void MediaStreamSignaling::OnRemoteDescriptionChanged(
+ const SessionDescriptionInterface* desc) {
+ const cricket::SessionDescription* remote_desc = desc->description();
+ rtc::scoped_refptr<StreamCollection> new_streams(
+ StreamCollection::Create());
+
+ // Find all audio rtp streams and create corresponding remote AudioTracks
+ // and MediaStreams.
+ const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
+ if (audio_content) {
+ const cricket::AudioContentDescription* desc =
+ static_cast<const cricket::AudioContentDescription*>(
+ audio_content->description);
+ UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
+ remote_info_.default_audio_track_needed =
+ MediaContentDirectionHasSend(desc->direction()) &&
+ desc->streams().empty();
+ }
+
+ // Find all video rtp streams and create corresponding remote VideoTracks
+ // and MediaStreams.
+ const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
+ if (video_content) {
+ const cricket::VideoContentDescription* desc =
+ static_cast<const cricket::VideoContentDescription*>(
+ video_content->description);
+ UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
+ remote_info_.default_video_track_needed =
+ MediaContentDirectionHasSend(desc->direction()) &&
+ desc->streams().empty();
+ }
+
+ // Update the DataChannels with the information from the remote peer.
+ const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc);
+ if (data_content) {
+ const cricket::DataContentDescription* data_desc =
+ static_cast<const cricket::DataContentDescription*>(
+ data_content->description);
+ if (rtc::starts_with(
+ data_desc->protocol().data(), cricket::kMediaProtocolRtpPrefix)) {
+ UpdateRemoteRtpDataChannels(data_desc->streams());
+ }
+ }
+
+ // Iterate new_streams and notify the observer about new MediaStreams.
+ for (size_t i = 0; i < new_streams->count(); ++i) {
+ MediaStreamInterface* new_stream = new_streams->at(i);
+ stream_observer_->OnAddRemoteStream(new_stream);
+ }
+
+ // Find removed MediaStreams.
+ if (remote_info_.IsDefaultMediaStreamNeeded() &&
+ remote_streams_->find(kDefaultStreamLabel) != NULL) {
+ // The default media stream already exists. No need to do anything.
+ } else {
+ UpdateEndedRemoteMediaStreams();
+ remote_info_.msid_supported |= remote_streams_->count() > 0;
+ }
+ MaybeCreateDefaultStream();
+}
+
+void MediaStreamSignaling::OnLocalDescriptionChanged(
+ const SessionDescriptionInterface* desc) {
+ const cricket::ContentInfo* audio_content =
+ GetFirstAudioContent(desc->description());
+ if (audio_content) {
+ if (audio_content->rejected) {
+ RejectRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
+ }
+ const cricket::AudioContentDescription* audio_desc =
+ static_cast<const cricket::AudioContentDescription*>(
+ audio_content->description);
+ UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
+ }
+
+ const cricket::ContentInfo* video_content =
+ GetFirstVideoContent(desc->description());
+ if (video_content) {
+ if (video_content->rejected) {
+ RejectRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
+ }
+ const cricket::VideoContentDescription* video_desc =
+ static_cast<const cricket::VideoContentDescription*>(
+ video_content->description);
+ UpdateLocalTracks(video_desc->streams(), video_desc->type());
+ }
+
+ const cricket::ContentInfo* data_content =
+ GetFirstDataContent(desc->description());
+ if (data_content) {
+ const cricket::DataContentDescription* data_desc =
+ static_cast<const cricket::DataContentDescription*>(
+ data_content->description);
+ if (rtc::starts_with(
+ data_desc->protocol().data(), cricket::kMediaProtocolRtpPrefix)) {
+ UpdateLocalRtpDataChannels(data_desc->streams());
+ }
+ }
+}
+
+void MediaStreamSignaling::OnAudioChannelClose() {
+ RejectRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
+}
+
+void MediaStreamSignaling::OnVideoChannelClose() {
+ RejectRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
+}
+
+void MediaStreamSignaling::OnDataChannelClose() {
+ // Use a temporary copy of the RTP/SCTP DataChannel list because the
+ // DataChannel may callback to us and try to modify the list.
+ RtpDataChannels temp_rtp_dcs;
+ temp_rtp_dcs.swap(rtp_data_channels_);
+ RtpDataChannels::iterator it1 = temp_rtp_dcs.begin();
+ for (; it1 != temp_rtp_dcs.end(); ++it1) {
+ it1->second->OnDataEngineClose();
+ }
+
+ SctpDataChannels temp_sctp_dcs;
+ temp_sctp_dcs.swap(sctp_data_channels_);
+ SctpDataChannels::iterator it2 = temp_sctp_dcs.begin();
+ for (; it2 != temp_sctp_dcs.end(); ++it2) {
+ (*it2)->OnDataEngineClose();
+ }
+}
+
+void MediaStreamSignaling::UpdateRemoteStreamsList(
+ const cricket::StreamParamsVec& streams,
+ cricket::MediaType media_type,
+ StreamCollection* new_streams) {
+ TrackInfos* current_tracks = GetRemoteTracks(media_type);
+
+ // Find removed tracks. Ie tracks where the track id or ssrc don't match the
+ // new StreamParam.
+ TrackInfos::iterator track_it = current_tracks->begin();
+ while (track_it != current_tracks->end()) {
+ const TrackInfo& info = *track_it;
+ const cricket::StreamParams* params =
+ cricket::GetStreamBySsrc(streams, info.ssrc);
+ if (!params || params->id != info.track_id) {
+ OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
+ track_it = current_tracks->erase(track_it);
+ } else {
+ ++track_it;
+ }
+ }
+
+ // Find new and active tracks.
+ for (cricket::StreamParamsVec::const_iterator it = streams.begin();
+ it != streams.end(); ++it) {
+ // The sync_label is the MediaStream label and the |stream.id| is the
+ // track id.
+ const std::string& stream_label = it->sync_label;
+ const std::string& track_id = it->id;
+ uint32_t ssrc = it->first_ssrc();
+
+ rtc::scoped_refptr<MediaStreamInterface> stream =
+ remote_streams_->find(stream_label);
+ if (!stream) {
+ // This is a new MediaStream. Create a new remote MediaStream.
+ stream = remote_stream_factory_->CreateMediaStream(stream_label);
+ remote_streams_->AddStream(stream);
+ new_streams->AddStream(stream);
+ }
+
+ const TrackInfo* track_info = FindTrackInfo(*current_tracks, stream_label,
+ track_id);
+ if (!track_info) {
+ current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
+ OnRemoteTrackSeen(stream_label, track_id, it->first_ssrc(), media_type);
+ }
+ }
+}
+
+void MediaStreamSignaling::OnRemoteTrackSeen(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc,
+ cricket::MediaType media_type) {
+ MediaStreamInterface* stream = remote_streams_->find(stream_label);
+
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ AudioTrackInterface* audio_track =
+ remote_stream_factory_->AddAudioTrack(stream, track_id);
+ stream_observer_->OnAddRemoteAudioTrack(stream, audio_track, ssrc);
+ } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
+ VideoTrackInterface* video_track =
+ remote_stream_factory_->AddVideoTrack(stream, track_id);
+ stream_observer_->OnAddRemoteVideoTrack(stream, video_track, ssrc);
+ } else {
+ ASSERT(false && "Invalid media type");
+ }
+}
+
+void MediaStreamSignaling::OnRemoteTrackRemoved(
+ const std::string& stream_label,
+ const std::string& track_id,
+ cricket::MediaType media_type) {
+ MediaStreamInterface* stream = remote_streams_->find(stream_label);
+
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ rtc::scoped_refptr<AudioTrackInterface> audio_track =
+ stream->FindAudioTrack(track_id);
+ if (audio_track) {
+ audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
+ stream->RemoveTrack(audio_track);
+ stream_observer_->OnRemoveRemoteAudioTrack(stream, audio_track);
+ }
+ } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
+ rtc::scoped_refptr<VideoTrackInterface> video_track =
+ stream->FindVideoTrack(track_id);
+ if (video_track) {
+ video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
+ stream->RemoveTrack(video_track);
+ stream_observer_->OnRemoveRemoteVideoTrack(stream, video_track);
+ }
+ } else {
+ ASSERT(false && "Invalid media type");
+ }
+}
+
+void MediaStreamSignaling::RejectRemoteTracks(cricket::MediaType media_type) {
+ TrackInfos* current_tracks = GetRemoteTracks(media_type);
+ for (TrackInfos::iterator track_it = current_tracks->begin();
+ track_it != current_tracks->end(); ++track_it) {
+ const TrackInfo& info = *track_it;
+ MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
+ // There's no guarantee the track is still available, e.g. the track may
+ // have been removed from the stream by javascript.
+ if (track) {
+ track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
+ }
+ }
+ if (media_type == cricket::MEDIA_TYPE_VIDEO) {
+ VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
+ // There's no guarantee the track is still available, e.g. the track may
+ // have been removed from the stream by javascript.
+ if (track) {
+ track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
+ }
+ }
+ }
+}
+
+void MediaStreamSignaling::UpdateEndedRemoteMediaStreams() {
+ std::vector<scoped_refptr<MediaStreamInterface> > streams_to_remove;
+ for (size_t i = 0; i < remote_streams_->count(); ++i) {
+ MediaStreamInterface*stream = remote_streams_->at(i);
+ if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
+ streams_to_remove.push_back(stream);
+ }
+ }
+
+ std::vector<scoped_refptr<MediaStreamInterface> >::const_iterator it;
+ for (it = streams_to_remove.begin(); it != streams_to_remove.end(); ++it) {
+ remote_streams_->RemoveStream(*it);
+ stream_observer_->OnRemoveRemoteStream(*it);
+ }
+}
+
+void MediaStreamSignaling::MaybeCreateDefaultStream() {
+ if (!remote_info_.IsDefaultMediaStreamNeeded())
+ return;
+
+ bool default_created = false;
+
+ scoped_refptr<MediaStreamInterface> default_remote_stream =
+ remote_streams_->find(kDefaultStreamLabel);
+ if (default_remote_stream == NULL) {
+ default_created = true;
+ default_remote_stream =
+ remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
+ remote_streams_->AddStream(default_remote_stream);
+ }
+ if (remote_info_.default_audio_track_needed &&
+ default_remote_stream->GetAudioTracks().size() == 0) {
+ remote_audio_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
+ kDefaultAudioTrackLabel, 0));
+
+ OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
+ cricket::MEDIA_TYPE_AUDIO);
+ }
+ if (remote_info_.default_video_track_needed &&
+ default_remote_stream->GetVideoTracks().size() == 0) {
+ remote_video_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
+ kDefaultVideoTrackLabel, 0));
+ OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
+ cricket::MEDIA_TYPE_VIDEO);
+ }
+ if (default_created) {
+ stream_observer_->OnAddRemoteStream(default_remote_stream);
+ }
+}
+
+MediaStreamSignaling::TrackInfos* MediaStreamSignaling::GetRemoteTracks(
+ cricket::MediaType type) {
+ if (type == cricket::MEDIA_TYPE_AUDIO)
+ return &remote_audio_tracks_;
+ else if (type == cricket::MEDIA_TYPE_VIDEO)
+ return &remote_video_tracks_;
+ ASSERT(false && "Unknown MediaType");
+ return NULL;
+}
+
+MediaStreamSignaling::TrackInfos* MediaStreamSignaling::GetLocalTracks(
+ cricket::MediaType media_type) {
+ ASSERT(media_type == cricket::MEDIA_TYPE_AUDIO ||
+ media_type == cricket::MEDIA_TYPE_VIDEO);
+
+ return (media_type == cricket::MEDIA_TYPE_AUDIO) ?
+ &local_audio_tracks_ : &local_video_tracks_;
+}
+
+void MediaStreamSignaling::UpdateLocalTracks(
+ const std::vector<cricket::StreamParams>& streams,
+ cricket::MediaType media_type) {
+ TrackInfos* current_tracks = GetLocalTracks(media_type);
+
+ // Find removed tracks. Ie tracks where the track id, stream label or ssrc
+ // don't match the new StreamParam.
+ TrackInfos::iterator track_it = current_tracks->begin();
+ while (track_it != current_tracks->end()) {
+ const TrackInfo& info = *track_it;
+ const cricket::StreamParams* params =
+ cricket::GetStreamBySsrc(streams, info.ssrc);
+ if (!params || params->id != info.track_id ||
+ params->sync_label != info.stream_label) {
+ OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
+ media_type);
+ track_it = current_tracks->erase(track_it);
+ } else {
+ ++track_it;
+ }
+ }
+
+ // Find new and active tracks.
+ for (cricket::StreamParamsVec::const_iterator it = streams.begin();
+ it != streams.end(); ++it) {
+ // The sync_label is the MediaStream label and the |stream.id| is the
+ // track id.
+ const std::string& stream_label = it->sync_label;
+ const std::string& track_id = it->id;
+ uint32_t ssrc = it->first_ssrc();
+ const TrackInfo* track_info = FindTrackInfo(*current_tracks,
+ stream_label,
+ track_id);
+ if (!track_info) {
+ current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
+ OnLocalTrackSeen(stream_label, track_id, it->first_ssrc(), media_type);
+ }
+ }
+}
+
+void MediaStreamSignaling::OnLocalTrackSeen(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc,
+ cricket::MediaType media_type) {
+ MediaStreamInterface* stream = local_streams_->find(stream_label);
+ if (!stream) {
+ LOG(LS_WARNING) << "An unknown local MediaStream with label "
+ << stream_label << " has been configured.";
+ return;
+ }
+
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
+ if (!audio_track) {
+ LOG(LS_WARNING) << "An unknown local AudioTrack with id , "
+ << track_id << " has been configured.";
+ return;
+ }
+ stream_observer_->OnAddLocalAudioTrack(stream, audio_track, ssrc);
+ } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
+ VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
+ if (!video_track) {
+ LOG(LS_WARNING) << "An unknown local VideoTrack with id , "
+ << track_id << " has been configured.";
+ return;
+ }
+ stream_observer_->OnAddLocalVideoTrack(stream, video_track, ssrc);
+ } else {
+ ASSERT(false && "Invalid media type");
+ }
+}
+
+void MediaStreamSignaling::OnLocalTrackRemoved(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc,
+ cricket::MediaType media_type) {
+ MediaStreamInterface* stream = local_streams_->find(stream_label);
+ if (!stream) {
+ // This is the normal case. Ie RemoveLocalStream has been called and the
+ // SessionDescriptions has been renegotiated.
+ return;
+ }
+ // A track has been removed from the SessionDescription but the MediaStream
+ // is still associated with MediaStreamSignaling. This only occurs if the SDP
+ // doesn't match with the calls to AddLocalStream and RemoveLocalStream.
+
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
+ if (!audio_track) {
+ return;
+ }
+ stream_observer_->OnRemoveLocalAudioTrack(stream, audio_track, ssrc);
+ } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
+ VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
+ if (!video_track) {
+ return;
+ }
+ stream_observer_->OnRemoveLocalVideoTrack(stream, video_track);
+ } else {
+ ASSERT(false && "Invalid media type.");
+ }
+}
+
+void MediaStreamSignaling::UpdateLocalRtpDataChannels(
+ const cricket::StreamParamsVec& streams) {
+ std::vector<std::string> existing_channels;
+
+ // Find new and active data channels.
+ for (cricket::StreamParamsVec::const_iterator it =streams.begin();
+ it != streams.end(); ++it) {
+ // |it->sync_label| is actually the data channel label. The reason is that
+ // we use the same naming of data channels as we do for
+ // MediaStreams and Tracks.
+ // For MediaStreams, the sync_label is the MediaStream label and the
+ // track label is the same as |streamid|.
+ const std::string& channel_label = it->sync_label;
+ RtpDataChannels::iterator data_channel_it =
+ rtp_data_channels_.find(channel_label);
+ if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
+ continue;
+ }
+ // Set the SSRC the data channel should use for sending.
+ data_channel_it->second->SetSendSsrc(it->first_ssrc());
+ existing_channels.push_back(data_channel_it->first);
+ }
+
+ UpdateClosingDataChannels(existing_channels, true);
+}
+
+void MediaStreamSignaling::UpdateRemoteRtpDataChannels(
+ const cricket::StreamParamsVec& streams) {
+ std::vector<std::string> existing_channels;
+
+ // Find new and active data channels.
+ for (cricket::StreamParamsVec::const_iterator it = streams.begin();
+ it != streams.end(); ++it) {
+ // The data channel label is either the mslabel or the SSRC if the mslabel
+ // does not exist. Ex a=ssrc:444330170 mslabel:test1.
+ std::string label = it->sync_label.empty() ?
+ rtc::ToString(it->first_ssrc()) : it->sync_label;
+ RtpDataChannels::iterator data_channel_it =
+ rtp_data_channels_.find(label);
+ if (data_channel_it == rtp_data_channels_.end()) {
+ // This is a new data channel.
+ CreateRemoteDataChannel(label, it->first_ssrc());
+ } else {
+ data_channel_it->second->SetReceiveSsrc(it->first_ssrc());
+ }
+ existing_channels.push_back(label);
+ }
+
+ UpdateClosingDataChannels(existing_channels, false);
+}
+
+void MediaStreamSignaling::UpdateClosingDataChannels(
+ const std::vector<std::string>& active_channels, bool is_local_update) {
+ RtpDataChannels::iterator it = rtp_data_channels_.begin();
+ while (it != rtp_data_channels_.end()) {
+ DataChannel* data_channel = it->second;
+ if (std::find(active_channels.begin(), active_channels.end(),
+ data_channel->label()) != active_channels.end()) {
+ ++it;
+ continue;
+ }
+
+ if (is_local_update)
+ data_channel->SetSendSsrc(0);
+ else
+ data_channel->RemotePeerRequestClose();
+
+ if (data_channel->state() == DataChannel::kClosed) {
+ rtp_data_channels_.erase(it);
+ it = rtp_data_channels_.begin();
+ } else {
+ ++it;
+ }
+ }
+}
+
+void MediaStreamSignaling::CreateRemoteDataChannel(const std::string& label,
+ uint32_t remote_ssrc) {
+ if (!data_channel_factory_) {
+ LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
+ << "are not supported.";
+ return;
+ }
+ scoped_refptr<DataChannel> channel(
+ data_channel_factory_->CreateDataChannel(label, NULL));
+ if (!channel.get()) {
+ LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
+ << "CreateDataChannel failed.";
+ return;
+ }
+ channel->SetReceiveSsrc(remote_ssrc);
+ stream_observer_->OnAddDataChannel(channel);
+}
+
+void MediaStreamSignaling::OnDataTransportCreatedForSctp() {
+ SctpDataChannels::iterator it = sctp_data_channels_.begin();
+ for (; it != sctp_data_channels_.end(); ++it) {
+ (*it)->OnTransportChannelCreated();
+ }
+}
+
+void MediaStreamSignaling::OnDtlsRoleReadyForSctp(rtc::SSLRole role) {
+ SctpDataChannels::iterator it = sctp_data_channels_.begin();
+ for (; it != sctp_data_channels_.end(); ++it) {
+ if ((*it)->id() < 0) {
+ int sid;
+ if (!AllocateSctpSid(role, &sid)) {
+ LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
+ continue;
+ }
+ (*it)->SetSctpSid(sid);
+ }
+ }
+}
+
+void MediaStreamSignaling::OnRemoteSctpDataChannelClosed(uint32_t sid) {
+ int index = FindDataChannelBySid(sid);
+ if (index < 0) {
+ LOG(LS_WARNING) << "Unexpected sid " << sid
+ << " of the remotely closed DataChannel.";
+ return;
+ }
+ sctp_data_channels_[index]->Close();
+}
+
+const MediaStreamSignaling::TrackInfo*
+MediaStreamSignaling::FindTrackInfo(
+ const MediaStreamSignaling::TrackInfos& infos,
+ const std::string& stream_label,
+ const std::string track_id) const {
+
+ for (TrackInfos::const_iterator it = infos.begin();
+ it != infos.end(); ++it) {
+ if (it->stream_label == stream_label && it->track_id == track_id)
+ return &*it;
+ }
+ return NULL;
+}
+
+int MediaStreamSignaling::FindDataChannelBySid(int sid) const {
+ for (size_t i = 0; i < sctp_data_channels_.size(); ++i) {
+ if (sctp_data_channels_[i]->id() == sid) {
+ return static_cast<int>(i);
+ }
+ }
+ return -1;
+}
+
+} // namespace webrtc
diff --git a/talk/app/webrtc/mediastreamsignaling.h b/talk/app/webrtc/mediastreamsignaling.h
index e8c5c11..b858b5b 100644
--- a/talk/app/webrtc/mediastreamsignaling.h
+++ b/talk/app/webrtc/mediastreamsignaling.h
@@ -25,4 +25,379 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-// TODO(deadbeef): Remove this file once Chrome build files don't reference it.
+#ifndef TALK_APP_WEBRTC_MEDIASTREAMSIGNALING_H_
+#define TALK_APP_WEBRTC_MEDIASTREAMSIGNALING_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "talk/app/webrtc/datachannel.h"
+#include "talk/app/webrtc/mediastream.h"
+#include "talk/app/webrtc/peerconnectioninterface.h"
+#include "talk/app/webrtc/streamcollection.h"
+#include "talk/session/media/mediasession.h"
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/base/sigslot.h"
+
+namespace rtc {
+class Thread;
+} // namespace rtc
+
+namespace webrtc {
+
+class RemoteMediaStreamFactory;
+
+// A MediaStreamSignalingObserver is notified when events happen to
+// MediaStreams, MediaStreamTracks or DataChannels associated with the observed
+// MediaStreamSignaling object. The notifications identify the stream, track or
+// channel.
+class MediaStreamSignalingObserver {
+ public:
+ // Triggered when the remote SessionDescription has a new stream.
+ virtual void OnAddRemoteStream(MediaStreamInterface* stream) = 0;
+
+ // Triggered when the remote SessionDescription removes a stream.
+ virtual void OnRemoveRemoteStream(MediaStreamInterface* stream) = 0;
+
+ // Triggered when the remote SessionDescription has a new data channel.
+ virtual void OnAddDataChannel(DataChannelInterface* data_channel) = 0;
+
+ // Triggered when the remote SessionDescription has a new audio track.
+ virtual void OnAddRemoteAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) = 0;
+
+ // Triggered when the remote SessionDescription has a new video track.
+ virtual void OnAddRemoteVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) = 0;
+
+ // Triggered when the remote SessionDescription has removed an audio track.
+ virtual void OnRemoveRemoteAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track) = 0;
+
+ // Triggered when the remote SessionDescription has removed a video track.
+ virtual void OnRemoveRemoteVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) = 0;
+
+ // Triggered when the local SessionDescription has a new audio track.
+ virtual void OnAddLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) = 0;
+
+ // Triggered when the local SessionDescription has a new video track.
+ virtual void OnAddLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) = 0;
+
+ // Triggered when the local SessionDescription has removed an audio track.
+ virtual void OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) = 0;
+
+ // Triggered when the local SessionDescription has removed a video track.
+ virtual void OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) = 0;
+
+ // Triggered when RemoveLocalStream is called. |stream| is no longer used
+ // when negotiating and all tracks in |stream| should stop providing data to
+ // this PeerConnection. This doesn't mean that the local session description
+ // has changed and OnRemoveLocalAudioTrack and OnRemoveLocalVideoTrack is not
+ // called for each individual track.
+ virtual void OnRemoveLocalStream(MediaStreamInterface* stream) = 0;
+
+ protected:
+ ~MediaStreamSignalingObserver() {}
+};
+
+// MediaStreamSignaling works as a glue between MediaStreams and a cricket
+// classes for SessionDescriptions.
+// It is used for creating cricket::MediaSessionOptions given the local
+// MediaStreams and data channels.
+//
+// It is responsible for creating remote MediaStreams given a remote
+// SessionDescription and creating cricket::MediaSessionOptions given
+// local MediaStreams.
+//
+// To signal that a DataChannel should be established:
+// 1. Call AddDataChannel with the new DataChannel. Next time
+// GetMediaSessionOptions will include the description of the DataChannel.
+// 2. When a local session description is set, call UpdateLocalStreams with the
+// session description. This will set the SSRC used for sending data on
+// this DataChannel.
+// 3. When remote session description is set, call UpdateRemoteStream with the
+// session description. If the DataChannel label and a SSRC is included in
+// the description, the DataChannel is updated with SSRC that will be used
+// for receiving data.
+// 4. When both the local and remote SSRC of a DataChannel is set the state of
+// the DataChannel change to kOpen.
+//
+// To setup a DataChannel initialized by the remote end.
+// 1. When remote session description is set, call UpdateRemoteStream with the
+// session description. If a label and a SSRC of a new DataChannel is found
+// MediaStreamSignalingObserver::OnAddDataChannel with the label and SSRC is
+// triggered.
+// 2. Create a DataChannel instance with the label and set the remote SSRC.
+// 3. Call AddDataChannel with this new DataChannel. GetMediaSessionOptions
+// will include the description of the DataChannel.
+// 4. Create a local session description and call UpdateLocalStreams. This will
+// set the local SSRC used by the DataChannel.
+// 5. When both the local and remote SSRC of a DataChannel is set the state of
+// the DataChannel change to kOpen.
+//
+// To close a DataChannel:
+// 1. Call DataChannel::Close. This will change the state of the DataChannel to
+// kClosing. GetMediaSessionOptions will not
+// include the description of the DataChannel.
+// 2. When a local session description is set, call UpdateLocalStreams with the
+// session description. The description will no longer contain the
+// DataChannel label or SSRC.
+// 3. When remote session description is set, call UpdateRemoteStream with the
+// session description. The description will no longer contain the
+// DataChannel label or SSRC. The DataChannel SSRC is updated with SSRC=0.
+// The DataChannel change state to kClosed.
+
+class MediaStreamSignaling : public sigslot::has_slots<> {
+ public:
+ typedef std::map<std::string, rtc::scoped_refptr<DataChannel> >
+ RtpDataChannels;
+ typedef std::vector<rtc::scoped_refptr<DataChannel>> SctpDataChannels;
+
+ MediaStreamSignaling(rtc::Thread* signaling_thread,
+ MediaStreamSignalingObserver* stream_observer,
+ cricket::ChannelManager* channel_manager);
+ virtual ~MediaStreamSignaling();
+
+ // Notify all referenced objects that MediaStreamSignaling will be teared
+ // down. This method must be called prior to the dtor.
+ void TearDown();
+
+ // Set a factory for creating data channels that are initiated by the remote
+ // peer.
+ void SetDataChannelFactory(DataChannelFactory* data_channel_factory) {
+ data_channel_factory_ = data_channel_factory;
+ }
+
+ // Checks if |id| is available to be assigned to a new SCTP data channel.
+ bool IsSctpSidAvailable(int sid) const;
+
+ // Gets the first available SCTP id that is not assigned to any existing
+ // data channels.
+ bool AllocateSctpSid(rtc::SSLRole role, int* sid);
+
+ // Adds |local_stream| to the collection of known MediaStreams that will be
+ // offered in a SessionDescription.
+ bool AddLocalStream(MediaStreamInterface* local_stream);
+
+ // Removes |local_stream| from the collection of known MediaStreams that will
+ // be offered in a SessionDescription.
+ void RemoveLocalStream(MediaStreamInterface* local_stream);
+
+ // Checks if any data channel has been added.
+ bool HasDataChannels() const;
+ // Adds |data_channel| to the collection of DataChannels that will be
+ // be offered in a SessionDescription.
+ bool AddDataChannel(DataChannel* data_channel);
+ // After we receive an OPEN message, create a data channel and add it.
+ bool AddDataChannelFromOpenMessage(const cricket::ReceiveDataParams& params,
+ const rtc::Buffer& payload);
+ void RemoveSctpDataChannel(int sid);
+
+ // Returns a MediaSessionOptions struct with options decided by |options|,
+ // the local MediaStreams and DataChannels.
+ virtual bool GetOptionsForOffer(
+ const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
+ cricket::MediaSessionOptions* session_options);
+
+ // Returns a MediaSessionOptions struct with options decided by
+ // |constraints|, the local MediaStreams and DataChannels.
+ virtual bool GetOptionsForAnswer(
+ const MediaConstraintsInterface* constraints,
+ cricket::MediaSessionOptions* options);
+
+ // Called when the remote session description has changed. The purpose is to
+ // update remote MediaStreams and DataChannels with the current
+ // session state.
+ // If the remote SessionDescription contain information about a new remote
+ // MediaStreams a new remote MediaStream is created and
+ // MediaStreamSignalingObserver::OnAddStream is called.
+ // If a remote MediaStream is missing from
+ // the remote SessionDescription MediaStreamSignalingObserver::OnRemoveStream
+ // is called.
+ // If the SessionDescription contains information about a new DataChannel,
+ // MediaStreamSignalingObserver::OnAddDataChannel is called with the
+ // DataChannel.
+ void OnRemoteDescriptionChanged(const SessionDescriptionInterface* desc);
+
+ // Called when the local session description has changed. The purpose is to
+ // update local and remote MediaStreams and DataChannels with the current
+ // session state.
+ // If |desc| indicates that the media type should be rejected, the method
+ // ends the remote MediaStreamTracks.
+ // It also updates local DataChannels with information about its local SSRC.
+ void OnLocalDescriptionChanged(const SessionDescriptionInterface* desc);
+
+ // Called when the audio channel closes.
+ void OnAudioChannelClose();
+ // Called when the video channel closes.
+ void OnVideoChannelClose();
+ // Called when the data channel closes.
+ void OnDataChannelClose();
+
+ // Returns all current known local MediaStreams.
+ StreamCollectionInterface* local_streams() const { return local_streams_;}
+
+ // Returns all current remote MediaStreams.
+ StreamCollectionInterface* remote_streams() const {
+ return remote_streams_.get();
+ }
+ void OnDataTransportCreatedForSctp();
+ void OnDtlsRoleReadyForSctp(rtc::SSLRole role);
+ void OnRemoteSctpDataChannelClosed(uint32_t sid);
+
+ const SctpDataChannels& sctp_data_channels() const {
+ return sctp_data_channels_;
+ }
+
+ private:
+ struct RemotePeerInfo {
+ RemotePeerInfo()
+ : msid_supported(false),
+ default_audio_track_needed(false),
+ default_video_track_needed(false) {
+ }
+ // True if it has been discovered that the remote peer support MSID.
+ bool msid_supported;
+ // The remote peer indicates in the session description that audio will be
+ // sent but no MSID is given.
+ bool default_audio_track_needed;
+ // The remote peer indicates in the session description that video will be
+ // sent but no MSID is given.
+ bool default_video_track_needed;
+
+ bool IsDefaultMediaStreamNeeded() {
+ return !msid_supported && (default_audio_track_needed ||
+ default_video_track_needed);
+ }
+ };
+
+ struct TrackInfo {
+ TrackInfo() : ssrc(0) {}
+ TrackInfo(const std::string& stream_label,
+ const std::string track_id,
+ uint32_t ssrc)
+ : stream_label(stream_label), track_id(track_id), ssrc(ssrc) {}
+ std::string stream_label;
+ std::string track_id;
+ uint32_t ssrc;
+ };
+ typedef std::vector<TrackInfo> TrackInfos;
+
+ // 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.
+ // If a new MediaStream is created it is added to |new_streams|.
+ void UpdateRemoteStreamsList(
+ const std::vector<cricket::StreamParams>& streams,
+ cricket::MediaType media_type,
+ StreamCollection* new_streams);
+
+ // Triggered when a remote track has been seen for the first time in a remote
+ // session description. It creates a remote MediaStreamTrackInterface
+ // implementation and triggers MediaStreamSignaling::OnAddRemoteAudioTrack or
+ // MediaStreamSignaling::OnAddRemoteVideoTrack.
+ void OnRemoteTrackSeen(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc,
+ cricket::MediaType media_type);
+
+ // Triggered when a remote track has been removed from a remote session
+ // description. It removes the remote track with id |track_id| from a remote
+ // MediaStream and triggers MediaStreamSignaling::OnRemoveRemoteAudioTrack or
+ // MediaStreamSignaling::OnRemoveRemoteVideoTrack.
+ void OnRemoteTrackRemoved(const std::string& stream_label,
+ const std::string& track_id,
+ cricket::MediaType media_type);
+
+ // Set the MediaStreamTrackInterface::TrackState to |kEnded| on all remote
+ // tracks of type |media_type|.
+ void RejectRemoteTracks(cricket::MediaType media_type);
+
+ // Finds remote MediaStreams without any tracks and removes them from
+ // |remote_streams_| and notifies the observer that the MediaStream no longer
+ // exist.
+ void UpdateEndedRemoteMediaStreams();
+ void MaybeCreateDefaultStream();
+ TrackInfos* GetRemoteTracks(cricket::MediaType type);
+
+ // Returns a map of currently negotiated LocalTrackInfo of type |type|.
+ TrackInfos* GetLocalTracks(cricket::MediaType type);
+ bool FindLocalTrack(const std::string& track_id, cricket::MediaType type);
+
+ // Loops through the vector of |streams| and finds added and removed
+ // StreamParams since last time this method was called.
+ // For each new or removed StreamParam NotifyLocalTrackAdded or
+ // NotifyLocalTrackRemoved in invoked.
+ void UpdateLocalTracks(const std::vector<cricket::StreamParams>& streams,
+ cricket::MediaType media_type);
+
+ // Triggered when a local track has been seen for the first time in a local
+ // session description.
+ // This method triggers MediaStreamSignaling::OnAddLocalAudioTrack or
+ // MediaStreamSignaling::OnAddLocalVideoTrack if the rtp streams in the local
+ // SessionDescription can be mapped to a MediaStreamTrack in a MediaStream in
+ // |local_streams_|
+ void OnLocalTrackSeen(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc,
+ cricket::MediaType media_type);
+
+ // Triggered when a local track has been removed from a local session
+ // description.
+ // This method triggers MediaStreamSignaling::OnRemoveLocalAudioTrack or
+ // MediaStreamSignaling::OnRemoveLocalVideoTrack 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 OnLocalTrackRemoved(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc,
+ cricket::MediaType media_type);
+
+ void UpdateLocalRtpDataChannels(const cricket::StreamParamsVec& streams);
+ void UpdateRemoteRtpDataChannels(const cricket::StreamParamsVec& streams);
+ void UpdateClosingDataChannels(
+ const std::vector<std::string>& active_channels, bool is_local_update);
+ void CreateRemoteDataChannel(const std::string& label, uint32_t remote_ssrc);
+
+ const TrackInfo* FindTrackInfo(const TrackInfos& infos,
+ const std::string& stream_label,
+ const std::string track_id) const;
+
+ // Returns the index of the specified SCTP DataChannel in sctp_data_channels_,
+ // or -1 if not found.
+ int FindDataChannelBySid(int sid) const;
+
+ RemotePeerInfo remote_info_;
+ rtc::Thread* signaling_thread_;
+ DataChannelFactory* data_channel_factory_;
+ MediaStreamSignalingObserver* stream_observer_;
+ rtc::scoped_refptr<StreamCollection> local_streams_;
+ rtc::scoped_refptr<StreamCollection> remote_streams_;
+ rtc::scoped_ptr<RemoteMediaStreamFactory> remote_stream_factory_;
+
+ TrackInfos remote_audio_tracks_;
+ TrackInfos remote_video_tracks_;
+ TrackInfos local_audio_tracks_;
+ TrackInfos local_video_tracks_;
+
+ int last_allocated_sctp_even_sid_;
+ int last_allocated_sctp_odd_sid_;
+
+ RtpDataChannels rtp_data_channels_;
+ SctpDataChannels sctp_data_channels_;
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_MEDIASTREAMSIGNALING_H_
diff --git a/talk/app/webrtc/mediastreamsignaling_unittest.cc b/talk/app/webrtc/mediastreamsignaling_unittest.cc
new file mode 100644
index 0000000..2333705
--- /dev/null
+++ b/talk/app/webrtc/mediastreamsignaling_unittest.cc
@@ -0,0 +1,1341 @@
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <vector>
+
+#include "talk/app/webrtc/audiotrack.h"
+#include "talk/app/webrtc/mediastream.h"
+#include "talk/app/webrtc/mediastreamsignaling.h"
+#include "talk/app/webrtc/sctputils.h"
+#include "talk/app/webrtc/streamcollection.h"
+#include "talk/app/webrtc/test/fakeconstraints.h"
+#include "talk/app/webrtc/test/fakedatachannelprovider.h"
+#include "talk/app/webrtc/videotrack.h"
+#include "talk/media/base/fakemediaengine.h"
+#include "webrtc/p2p/base/constants.h"
+#include "webrtc/p2p/base/sessiondescription.h"
+#include "talk/session/media/channelmanager.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/stringutils.h"
+#include "webrtc/base/thread.h"
+
+static const char kStreams[][8] = {"stream1", "stream2"};
+static const char kAudioTracks[][32] = {"audiotrack0", "audiotrack1"};
+static const char kVideoTracks[][32] = {"videotrack0", "videotrack1"};
+
+using webrtc::AudioTrack;
+using webrtc::AudioTrackInterface;
+using webrtc::AudioTrackVector;
+using webrtc::VideoTrack;
+using webrtc::VideoTrackInterface;
+using webrtc::VideoTrackVector;
+using webrtc::DataChannelInterface;
+using webrtc::FakeConstraints;
+using webrtc::IceCandidateInterface;
+using webrtc::MediaConstraintsInterface;
+using webrtc::MediaStreamInterface;
+using webrtc::MediaStreamTrackInterface;
+using webrtc::PeerConnectionInterface;
+using webrtc::SdpParseError;
+using webrtc::SessionDescriptionInterface;
+using webrtc::StreamCollection;
+using webrtc::StreamCollectionInterface;
+
+typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
+
+// Reference SDP with a MediaStream with label "stream1" and audio track with
+// id "audio_1" and a video track with id "video_1;
+static const char kSdpStringWithStream1[] =
+ "v=0\r\n"
+ "o=- 0 0 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=audio 1 RTP/AVPF 103\r\n"
+ "a=mid:audio\r\n"
+ "a=rtpmap:103 ISAC/16000\r\n"
+ "a=ssrc:1 cname:stream1\r\n"
+ "a=ssrc:1 mslabel:stream1\r\n"
+ "a=ssrc:1 label:audiotrack0\r\n"
+ "m=video 1 RTP/AVPF 120\r\n"
+ "a=mid:video\r\n"
+ "a=rtpmap:120 VP8/90000\r\n"
+ "a=ssrc:2 cname:stream1\r\n"
+ "a=ssrc:2 mslabel:stream1\r\n"
+ "a=ssrc:2 label:videotrack0\r\n";
+
+// Reference SDP with two MediaStreams with label "stream1" and "stream2. Each
+// MediaStreams have one audio track and one video track.
+// This uses MSID.
+static const char kSdpStringWith2Stream[] =
+ "v=0\r\n"
+ "o=- 0 0 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=msid-semantic: WMS stream1 stream2\r\n"
+ "m=audio 1 RTP/AVPF 103\r\n"
+ "a=mid:audio\r\n"
+ "a=rtpmap:103 ISAC/16000\r\n"
+ "a=ssrc:1 cname:stream1\r\n"
+ "a=ssrc:1 msid:stream1 audiotrack0\r\n"
+ "a=ssrc:3 cname:stream2\r\n"
+ "a=ssrc:3 msid:stream2 audiotrack1\r\n"
+ "m=video 1 RTP/AVPF 120\r\n"
+ "a=mid:video\r\n"
+ "a=rtpmap:120 VP8/0\r\n"
+ "a=ssrc:2 cname:stream1\r\n"
+ "a=ssrc:2 msid:stream1 videotrack0\r\n"
+ "a=ssrc:4 cname:stream2\r\n"
+ "a=ssrc:4 msid:stream2 videotrack1\r\n";
+
+// Reference SDP without MediaStreams. Msid is not supported.
+static const char kSdpStringWithoutStreams[] =
+ "v=0\r\n"
+ "o=- 0 0 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=audio 1 RTP/AVPF 103\r\n"
+ "a=mid:audio\r\n"
+ "a=rtpmap:103 ISAC/16000\r\n"
+ "m=video 1 RTP/AVPF 120\r\n"
+ "a=mid:video\r\n"
+ "a=rtpmap:120 VP8/90000\r\n";
+
+// Reference SDP without MediaStreams. Msid is supported.
+static const char kSdpStringWithMsidWithoutStreams[] =
+ "v=0\r\n"
+ "o=- 0 0 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=msid-semantic: WMS\r\n"
+ "m=audio 1 RTP/AVPF 103\r\n"
+ "a=mid:audio\r\n"
+ "a=rtpmap:103 ISAC/16000\r\n"
+ "m=video 1 RTP/AVPF 120\r\n"
+ "a=mid:video\r\n"
+ "a=rtpmap:120 VP8/90000\r\n";
+
+// Reference SDP without MediaStreams and audio only.
+static const char kSdpStringWithoutStreamsAudioOnly[] =
+ "v=0\r\n"
+ "o=- 0 0 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=audio 1 RTP/AVPF 103\r\n"
+ "a=mid:audio\r\n"
+ "a=rtpmap:103 ISAC/16000\r\n";
+
+// Reference SENDONLY SDP without MediaStreams. Msid is not supported.
+static const char kSdpStringSendOnlyWithWithoutStreams[] =
+ "v=0\r\n"
+ "o=- 0 0 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=audio 1 RTP/AVPF 103\r\n"
+ "a=mid:audio\r\n"
+ "a=sendonly"
+ "a=rtpmap:103 ISAC/16000\r\n"
+ "m=video 1 RTP/AVPF 120\r\n"
+ "a=mid:video\r\n"
+ "a=sendonly"
+ "a=rtpmap:120 VP8/90000\r\n";
+
+static const char kSdpStringInit[] =
+ "v=0\r\n"
+ "o=- 0 0 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=msid-semantic: WMS\r\n";
+
+static const char kSdpStringAudio[] =
+ "m=audio 1 RTP/AVPF 103\r\n"
+ "a=mid:audio\r\n"
+ "a=rtpmap:103 ISAC/16000\r\n";
+
+static const char kSdpStringVideo[] =
+ "m=video 1 RTP/AVPF 120\r\n"
+ "a=mid:video\r\n"
+ "a=rtpmap:120 VP8/90000\r\n";
+
+static const char kSdpStringMs1Audio0[] =
+ "a=ssrc:1 cname:stream1\r\n"
+ "a=ssrc:1 msid:stream1 audiotrack0\r\n";
+
+static const char kSdpStringMs1Video0[] =
+ "a=ssrc:2 cname:stream1\r\n"
+ "a=ssrc:2 msid:stream1 videotrack0\r\n";
+
+static const char kSdpStringMs1Audio1[] =
+ "a=ssrc:3 cname:stream1\r\n"
+ "a=ssrc:3 msid:stream1 audiotrack1\r\n";
+
+static const char kSdpStringMs1Video1[] =
+ "a=ssrc:4 cname:stream1\r\n"
+ "a=ssrc:4 msid:stream1 videotrack1\r\n";
+
+// Verifies that |options| contain all tracks in |collection| and that
+// the |options| has set the the has_audio and has_video flags correct.
+static void VerifyMediaOptions(StreamCollectionInterface* collection,
+ const cricket::MediaSessionOptions& options) {
+ if (!collection) {
+ return;
+ }
+
+ size_t stream_index = 0;
+ for (size_t i = 0; i < collection->count(); ++i) {
+ MediaStreamInterface* stream = collection->at(i);
+ AudioTrackVector audio_tracks = stream->GetAudioTracks();
+ ASSERT_GE(options.streams.size(), stream_index + audio_tracks.size());
+ for (size_t j = 0; j < audio_tracks.size(); ++j) {
+ webrtc::AudioTrackInterface* audio = audio_tracks[j];
+ EXPECT_EQ(options.streams[stream_index].sync_label, stream->label());
+ EXPECT_EQ(options.streams[stream_index++].id, audio->id());
+ EXPECT_TRUE(options.has_audio());
+ }
+ VideoTrackVector video_tracks = stream->GetVideoTracks();
+ ASSERT_GE(options.streams.size(), stream_index + video_tracks.size());
+ for (size_t j = 0; j < video_tracks.size(); ++j) {
+ webrtc::VideoTrackInterface* video = video_tracks[j];
+ EXPECT_EQ(options.streams[stream_index].sync_label, stream->label());
+ EXPECT_EQ(options.streams[stream_index++].id, video->id());
+ EXPECT_TRUE(options.has_video());
+ }
+ }
+}
+
+static bool CompareStreamCollections(StreamCollectionInterface* s1,
+ StreamCollectionInterface* s2) {
+ if (s1 == NULL || s2 == NULL || s1->count() != s2->count())
+ return false;
+
+ for (size_t i = 0; i != s1->count(); ++i) {
+ if (s1->at(i)->label() != s2->at(i)->label())
+ return false;
+ webrtc::AudioTrackVector audio_tracks1 = s1->at(i)->GetAudioTracks();
+ webrtc::AudioTrackVector audio_tracks2 = s2->at(i)->GetAudioTracks();
+ webrtc::VideoTrackVector video_tracks1 = s1->at(i)->GetVideoTracks();
+ webrtc::VideoTrackVector video_tracks2 = s2->at(i)->GetVideoTracks();
+
+ if (audio_tracks1.size() != audio_tracks2.size())
+ return false;
+ for (size_t j = 0; j != audio_tracks1.size(); ++j) {
+ if (audio_tracks1[j]->id() != audio_tracks2[j]->id())
+ return false;
+ }
+ if (video_tracks1.size() != video_tracks2.size())
+ return false;
+ for (size_t j = 0; j != video_tracks1.size(); ++j) {
+ if (video_tracks1[j]->id() != video_tracks2[j]->id())
+ return false;
+ }
+ }
+ return true;
+}
+
+class FakeDataChannelFactory : public webrtc::DataChannelFactory {
+ public:
+ FakeDataChannelFactory(FakeDataChannelProvider* provider,
+ cricket::DataChannelType dct,
+ webrtc::MediaStreamSignaling* media_stream_signaling)
+ : provider_(provider),
+ type_(dct),
+ media_stream_signaling_(media_stream_signaling) {}
+
+ virtual rtc::scoped_refptr<webrtc::DataChannel> CreateDataChannel(
+ const std::string& label,
+ const webrtc::InternalDataChannelInit* config) {
+ last_init_ = *config;
+ rtc::scoped_refptr<webrtc::DataChannel> data_channel =
+ webrtc::DataChannel::Create(provider_, type_, label, *config);
+ media_stream_signaling_->AddDataChannel(data_channel);
+ return data_channel;
+ }
+
+ const webrtc::InternalDataChannelInit& last_init() const {
+ return last_init_;
+ }
+
+ private:
+ FakeDataChannelProvider* provider_;
+ cricket::DataChannelType type_;
+ webrtc::MediaStreamSignaling* media_stream_signaling_;
+ webrtc::InternalDataChannelInit last_init_;
+};
+
+class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
+ public:
+ MockSignalingObserver()
+ : remote_media_streams_(StreamCollection::Create()) {
+ }
+
+ virtual ~MockSignalingObserver() {
+ }
+
+ // New remote stream have been discovered.
+ virtual void OnAddRemoteStream(MediaStreamInterface* remote_stream) {
+ remote_media_streams_->AddStream(remote_stream);
+ }
+
+ // Remote stream is no longer available.
+ virtual void OnRemoveRemoteStream(MediaStreamInterface* remote_stream) {
+ remote_media_streams_->RemoveStream(remote_stream);
+ }
+
+ virtual void OnAddDataChannel(DataChannelInterface* data_channel) {
+ }
+
+ virtual void OnAddLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) {
+ AddTrack(&local_audio_tracks_, stream, audio_track, ssrc);
+ }
+
+ virtual void OnAddLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) {
+ AddTrack(&local_video_tracks_, stream, video_track, ssrc);
+ }
+
+ virtual void OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) {
+ RemoveTrack(&local_audio_tracks_, stream, audio_track);
+ }
+
+ virtual void OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) {
+ RemoveTrack(&local_video_tracks_, stream, video_track);
+ }
+
+ virtual void OnAddRemoteAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) {
+ AddTrack(&remote_audio_tracks_, stream, audio_track, ssrc);
+ }
+
+ virtual void OnAddRemoteVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) {
+ AddTrack(&remote_video_tracks_, stream, video_track, ssrc);
+ }
+
+ virtual void OnRemoveRemoteAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track) {
+ RemoveTrack(&remote_audio_tracks_, stream, audio_track);
+ }
+
+ virtual void OnRemoveRemoteVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) {
+ RemoveTrack(&remote_video_tracks_, stream, video_track);
+ }
+
+ virtual void OnRemoveLocalStream(MediaStreamInterface* stream) {
+ }
+
+ MediaStreamInterface* RemoteStream(const std::string& label) {
+ return remote_media_streams_->find(label);
+ }
+
+ StreamCollectionInterface* remote_streams() const {
+ return remote_media_streams_;
+ }
+
+ size_t NumberOfRemoteAudioTracks() { return remote_audio_tracks_.size(); }
+
+ void VerifyRemoteAudioTrack(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc) {
+ VerifyTrack(remote_audio_tracks_, stream_label, track_id, ssrc);
+ }
+
+ size_t NumberOfRemoteVideoTracks() { return remote_video_tracks_.size(); }
+
+ void VerifyRemoteVideoTrack(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc) {
+ VerifyTrack(remote_video_tracks_, stream_label, track_id, ssrc);
+ }
+
+ size_t NumberOfLocalAudioTracks() { return local_audio_tracks_.size(); }
+ void VerifyLocalAudioTrack(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc) {
+ VerifyTrack(local_audio_tracks_, stream_label, track_id, ssrc);
+ }
+
+ size_t NumberOfLocalVideoTracks() { return local_video_tracks_.size(); }
+
+ void VerifyLocalVideoTrack(const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc) {
+ VerifyTrack(local_video_tracks_, stream_label, track_id, ssrc);
+ }
+
+ private:
+ struct TrackInfo {
+ TrackInfo() {}
+ TrackInfo(const std::string& stream_label,
+ const std::string track_id,
+ uint32_t ssrc)
+ : stream_label(stream_label), track_id(track_id), ssrc(ssrc) {}
+ std::string stream_label;
+ std::string track_id;
+ uint32_t ssrc;
+ };
+ typedef std::vector<TrackInfo> TrackInfos;
+
+ void AddTrack(TrackInfos* track_infos,
+ MediaStreamInterface* stream,
+ MediaStreamTrackInterface* track,
+ uint32_t ssrc) {
+ (*track_infos).push_back(TrackInfo(stream->label(), track->id(), ssrc));
+ }
+
+ void RemoveTrack(TrackInfos* track_infos, MediaStreamInterface* stream,
+ MediaStreamTrackInterface* track) {
+ for (TrackInfos::iterator it = track_infos->begin();
+ it != track_infos->end(); ++it) {
+ if (it->stream_label == stream->label() && it->track_id == track->id()) {
+ track_infos->erase(it);
+ return;
+ }
+ }
+ ADD_FAILURE();
+ }
+
+ const TrackInfo* FindTrackInfo(const TrackInfos& infos,
+ const std::string& stream_label,
+ const std::string track_id) const {
+ for (TrackInfos::const_iterator it = infos.begin();
+ it != infos.end(); ++it) {
+ if (it->stream_label == stream_label && it->track_id == track_id)
+ return &*it;
+ }
+ return NULL;
+ }
+
+ void VerifyTrack(const TrackInfos& track_infos,
+ const std::string& stream_label,
+ const std::string& track_id,
+ uint32_t ssrc) {
+ const TrackInfo* track_info = FindTrackInfo(track_infos,
+ stream_label,
+ track_id);
+ ASSERT_TRUE(track_info != NULL);
+ EXPECT_EQ(ssrc, track_info->ssrc);
+ }
+
+ TrackInfos remote_audio_tracks_;
+ TrackInfos remote_video_tracks_;
+ TrackInfos local_audio_tracks_;
+ TrackInfos local_video_tracks_;
+
+ rtc::scoped_refptr<StreamCollection> remote_media_streams_;
+};
+
+class MediaStreamSignalingForTest : public webrtc::MediaStreamSignaling {
+ public:
+ MediaStreamSignalingForTest(MockSignalingObserver* observer,
+ cricket::ChannelManager* channel_manager)
+ : webrtc::MediaStreamSignaling(rtc::Thread::Current(), observer,
+ channel_manager) {
+ };
+
+ using webrtc::MediaStreamSignaling::GetOptionsForOffer;
+ using webrtc::MediaStreamSignaling::GetOptionsForAnswer;
+ using webrtc::MediaStreamSignaling::OnRemoteDescriptionChanged;
+ using webrtc::MediaStreamSignaling::remote_streams;
+};
+
+class MediaStreamSignalingTest: public testing::Test {
+ protected:
+ virtual void SetUp() {
+ observer_.reset(new MockSignalingObserver());
+ channel_manager_.reset(
+ new cricket::ChannelManager(new cricket::FakeMediaEngine(),
+ rtc::Thread::Current()));
+ signaling_.reset(new MediaStreamSignalingForTest(observer_.get(),
+ channel_manager_.get()));
+ data_channel_provider_.reset(new FakeDataChannelProvider());
+ }
+
+ // Create a collection of streams.
+ // CreateStreamCollection(1) creates a collection that
+ // correspond to kSdpString1.
+ // CreateStreamCollection(2) correspond to kSdpString2.
+ rtc::scoped_refptr<StreamCollection>
+ CreateStreamCollection(int number_of_streams) {
+ rtc::scoped_refptr<StreamCollection> local_collection(
+ StreamCollection::Create());
+
+ for (int i = 0; i < number_of_streams; ++i) {
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream(
+ webrtc::MediaStream::Create(kStreams[i]));
+
+ // Add a local audio track.
+ rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ webrtc::AudioTrack::Create(kAudioTracks[i], NULL));
+ stream->AddTrack(audio_track);
+
+ // Add a local video track.
+ rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
+ webrtc::VideoTrack::Create(kVideoTracks[i], NULL));
+ stream->AddTrack(video_track);
+
+ local_collection->AddStream(stream);
+ }
+ return local_collection;
+ }
+
+ // This functions Creates a MediaStream with label kStreams[0] and
+ // |number_of_audio_tracks| and |number_of_video_tracks| tracks and the
+ // corresponding SessionDescriptionInterface. The SessionDescriptionInterface
+ // is returned in |desc| and the MediaStream is stored in
+ // |reference_collection_|
+ void CreateSessionDescriptionAndReference(
+ size_t number_of_audio_tracks,
+ size_t number_of_video_tracks,
+ SessionDescriptionInterface** desc) {
+ ASSERT_TRUE(desc != NULL);
+ ASSERT_LE(number_of_audio_tracks, 2u);
+ ASSERT_LE(number_of_video_tracks, 2u);
+
+ reference_collection_ = StreamCollection::Create();
+ std::string sdp_ms1 = std::string(kSdpStringInit);
+
+ std::string mediastream_label = kStreams[0];
+
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream(
+ webrtc::MediaStream::Create(mediastream_label));
+ reference_collection_->AddStream(stream);
+
+ if (number_of_audio_tracks > 0) {
+ sdp_ms1 += std::string(kSdpStringAudio);
+ sdp_ms1 += std::string(kSdpStringMs1Audio0);
+ AddAudioTrack(kAudioTracks[0], stream);
+ }
+ if (number_of_audio_tracks > 1) {
+ sdp_ms1 += kSdpStringMs1Audio1;
+ AddAudioTrack(kAudioTracks[1], stream);
+ }
+
+ if (number_of_video_tracks > 0) {
+ sdp_ms1 += std::string(kSdpStringVideo);
+ sdp_ms1 += std::string(kSdpStringMs1Video0);
+ AddVideoTrack(kVideoTracks[0], stream);
+ }
+ if (number_of_video_tracks > 1) {
+ sdp_ms1 += kSdpStringMs1Video1;
+ AddVideoTrack(kVideoTracks[1], stream);
+ }
+
+ *desc = webrtc::CreateSessionDescription(
+ SessionDescriptionInterface::kOffer, sdp_ms1, NULL);
+ }
+
+ void AddAudioTrack(const std::string& track_id,
+ MediaStreamInterface* stream) {
+ rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ webrtc::AudioTrack::Create(track_id, NULL));
+ ASSERT_TRUE(stream->AddTrack(audio_track));
+ }
+
+ void AddVideoTrack(const std::string& track_id,
+ MediaStreamInterface* stream) {
+ rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
+ webrtc::VideoTrack::Create(track_id, NULL));
+ ASSERT_TRUE(stream->AddTrack(video_track));
+ }
+
+ rtc::scoped_refptr<webrtc::DataChannel> AddDataChannel(
+ cricket::DataChannelType type, const std::string& label, int id) {
+ webrtc::InternalDataChannelInit config;
+ config.id = id;
+ rtc::scoped_refptr<webrtc::DataChannel> data_channel(
+ webrtc::DataChannel::Create(
+ data_channel_provider_.get(), type, label, config));
+ EXPECT_TRUE(data_channel.get() != NULL);
+ EXPECT_TRUE(signaling_->AddDataChannel(data_channel.get()));
+ return data_channel;
+ }
+
+ // ChannelManager is used by VideoSource, so it should be released after all
+ // the video tracks. Put it as the first private variable should ensure that.
+ rtc::scoped_ptr<cricket::ChannelManager> channel_manager_;
+ rtc::scoped_refptr<StreamCollection> reference_collection_;
+ rtc::scoped_ptr<MockSignalingObserver> observer_;
+ rtc::scoped_ptr<MediaStreamSignalingForTest> signaling_;
+ rtc::scoped_ptr<FakeDataChannelProvider> data_channel_provider_;
+};
+
+TEST_F(MediaStreamSignalingTest, GetOptionsForOfferWithInvalidAudioOption) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc_options.offer_to_receive_audio = RTCOfferAnswerOptions::kUndefined - 1;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_FALSE(signaling_->GetOptionsForOffer(rtc_options, &options));
+
+ rtc_options.offer_to_receive_audio =
+ RTCOfferAnswerOptions::kMaxOfferToReceiveMedia + 1;
+ EXPECT_FALSE(signaling_->GetOptionsForOffer(rtc_options, &options));
+}
+
+
+TEST_F(MediaStreamSignalingTest, GetOptionsForOfferWithInvalidVideoOption) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc_options.offer_to_receive_video =
+ RTCOfferAnswerOptions::kUndefined - 1;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_FALSE(signaling_->GetOptionsForOffer(rtc_options, &options));
+
+ rtc_options.offer_to_receive_video =
+ RTCOfferAnswerOptions::kMaxOfferToReceiveMedia + 1;
+ EXPECT_FALSE(signaling_->GetOptionsForOffer(rtc_options, &options));
+}
+
+// Test that a MediaSessionOptions is created for an offer if
+// OfferToReceiveAudio and OfferToReceiveVideo options are set but no
+// MediaStreams are sent.
+TEST_F(MediaStreamSignalingTest, GetMediaSessionOptionsForOfferWithAudioVideo) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc_options.offer_to_receive_audio = 1;
+ rtc_options.offer_to_receive_video = 1;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ EXPECT_TRUE(options.has_audio());
+ EXPECT_TRUE(options.has_video());
+ EXPECT_TRUE(options.bundle_enabled);
+}
+
+// Test that a correct MediaSessionOptions is created for an offer if
+// OfferToReceiveAudio is set but no MediaStreams are sent.
+TEST_F(MediaStreamSignalingTest, GetMediaSessionOptionsForOfferWithAudio) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc_options.offer_to_receive_audio = 1;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ EXPECT_TRUE(options.has_audio());
+ EXPECT_FALSE(options.has_video());
+ EXPECT_TRUE(options.bundle_enabled);
+}
+
+// Test that a correct MediaSessionOptions is created for an offer if
+// the default OfferOptons is used or MediaStreams are sent.
+TEST_F(MediaStreamSignalingTest, GetDefaultMediaSessionOptionsForOffer) {
+ RTCOfferAnswerOptions rtc_options;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ EXPECT_FALSE(options.has_audio());
+ EXPECT_FALSE(options.has_video());
+ EXPECT_FALSE(options.bundle_enabled);
+ EXPECT_TRUE(options.vad_enabled);
+ EXPECT_FALSE(options.transport_options.ice_restart);
+}
+
+// Test that a correct MediaSessionOptions is created for an offer if
+// OfferToReceiveVideo is set but no MediaStreams are sent.
+TEST_F(MediaStreamSignalingTest, GetMediaSessionOptionsForOfferWithVideo) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc_options.offer_to_receive_audio = 0;
+ rtc_options.offer_to_receive_video = 1;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ EXPECT_FALSE(options.has_audio());
+ EXPECT_TRUE(options.has_video());
+ EXPECT_TRUE(options.bundle_enabled);
+}
+
+// Test that a correct MediaSessionOptions is created for an offer if
+// UseRtpMux is set to false.
+TEST_F(MediaStreamSignalingTest,
+ GetMediaSessionOptionsForOfferWithBundleDisabled) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc_options.offer_to_receive_audio = 1;
+ rtc_options.offer_to_receive_video = 1;
+ rtc_options.use_rtp_mux = false;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ EXPECT_TRUE(options.has_audio());
+ EXPECT_TRUE(options.has_video());
+ EXPECT_FALSE(options.bundle_enabled);
+}
+
+// Test that a correct MediaSessionOptions is created to restart ice if
+// IceRestart is set. It also tests that subsequent MediaSessionOptions don't
+// have |transport_options.ice_restart| set.
+TEST_F(MediaStreamSignalingTest,
+ GetMediaSessionOptionsForOfferWithIceRestart) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc_options.ice_restart = true;
+
+ cricket::MediaSessionOptions options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ EXPECT_TRUE(options.transport_options.ice_restart);
+
+ rtc_options = RTCOfferAnswerOptions();
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ EXPECT_FALSE(options.transport_options.ice_restart);
+}
+
+// Test that a correct MediaSessionOptions are created for an offer if
+// a MediaStream is sent and later updated with a new track.
+// MediaConstraints are not used.
+TEST_F(MediaStreamSignalingTest, AddTrackToLocalMediaStream) {
+ RTCOfferAnswerOptions rtc_options;
+ rtc::scoped_refptr<StreamCollection> local_streams(
+ CreateStreamCollection(1));
+ MediaStreamInterface* local_stream = local_streams->at(0);
+ EXPECT_TRUE(signaling_->AddLocalStream(local_stream));
+ cricket::MediaSessionOptions options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ VerifyMediaOptions(local_streams, options);
+
+ cricket::MediaSessionOptions updated_options;
+ local_stream->AddTrack(AudioTrack::Create(kAudioTracks[1], NULL));
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(rtc_options, &options));
+ VerifyMediaOptions(local_streams, options);
+}
+
+// Test that the MediaConstraints in an answer don't affect if audio and video
+// is offered in an offer but that if kOfferToReceiveAudio or
+// kOfferToReceiveVideo constraints are true in an offer, the media type will be
+// included in subsequent answers.
+TEST_F(MediaStreamSignalingTest, MediaConstraintsInAnswer) {
+ FakeConstraints answer_c;
+ answer_c.SetMandatoryReceiveAudio(true);
+ answer_c.SetMandatoryReceiveVideo(true);
+
+ cricket::MediaSessionOptions answer_options;
+ EXPECT_TRUE(signaling_->GetOptionsForAnswer(&answer_c, &answer_options));
+ EXPECT_TRUE(answer_options.has_audio());
+ EXPECT_TRUE(answer_options.has_video());
+
+ RTCOfferAnswerOptions rtc_offer_optoins;
+
+ cricket::MediaSessionOptions offer_options;
+ EXPECT_TRUE(
+ signaling_->GetOptionsForOffer(rtc_offer_optoins, &offer_options));
+ EXPECT_FALSE(offer_options.has_audio());
+ EXPECT_FALSE(offer_options.has_video());
+
+ RTCOfferAnswerOptions updated_rtc_offer_optoins;
+ updated_rtc_offer_optoins.offer_to_receive_audio = 1;
+ updated_rtc_offer_optoins.offer_to_receive_video = 1;
+
+ cricket::MediaSessionOptions updated_offer_options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(updated_rtc_offer_optoins,
+ &updated_offer_options));
+ EXPECT_TRUE(updated_offer_options.has_audio());
+ EXPECT_TRUE(updated_offer_options.has_video());
+
+ // Since an offer has been created with both audio and video, subsequent
+ // offers and answers should contain both audio and video.
+ // Answers will only contain the media types that exist in the offer
+ // regardless of the value of |updated_answer_options.has_audio| and
+ // |updated_answer_options.has_video|.
+ FakeConstraints updated_answer_c;
+ answer_c.SetMandatoryReceiveAudio(false);
+ answer_c.SetMandatoryReceiveVideo(false);
+
+ cricket::MediaSessionOptions updated_answer_options;
+ EXPECT_TRUE(signaling_->GetOptionsForAnswer(&updated_answer_c,
+ &updated_answer_options));
+ EXPECT_TRUE(updated_answer_options.has_audio());
+ EXPECT_TRUE(updated_answer_options.has_video());
+
+ RTCOfferAnswerOptions default_rtc_options;
+ EXPECT_TRUE(signaling_->GetOptionsForOffer(default_rtc_options,
+ &updated_offer_options));
+ // 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
+// SDP string is created. In this test the two separate MediaStreams are
+// signaled.
+TEST_F(MediaStreamSignalingTest, UpdateRemoteStreams) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithStream1, NULL));
+ EXPECT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+
+ rtc::scoped_refptr<StreamCollection> reference(
+ CreateStreamCollection(1));
+ EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
+ reference.get()));
+ EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),
+ reference.get()));
+ EXPECT_EQ(1u, observer_->NumberOfRemoteAudioTracks());
+ observer_->VerifyRemoteAudioTrack(kStreams[0], kAudioTracks[0], 1);
+ EXPECT_EQ(1u, observer_->NumberOfRemoteVideoTracks());
+ observer_->VerifyRemoteVideoTrack(kStreams[0], kVideoTracks[0], 2);
+ ASSERT_EQ(1u, observer_->remote_streams()->count());
+ MediaStreamInterface* remote_stream = observer_->remote_streams()->at(0);
+ EXPECT_TRUE(remote_stream->GetVideoTracks()[0]->GetSource() != NULL);
+
+ // Create a session description based on another SDP with another
+ // MediaStream.
+ rtc::scoped_ptr<SessionDescriptionInterface> update_desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWith2Stream, NULL));
+ EXPECT_TRUE(update_desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(update_desc.get());
+
+ rtc::scoped_refptr<StreamCollection> reference2(
+ CreateStreamCollection(2));
+ EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
+ reference2.get()));
+ EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),
+ reference2.get()));
+
+ EXPECT_EQ(2u, observer_->NumberOfRemoteAudioTracks());
+ observer_->VerifyRemoteAudioTrack(kStreams[0], kAudioTracks[0], 1);
+ observer_->VerifyRemoteAudioTrack(kStreams[1], kAudioTracks[1], 3);
+ EXPECT_EQ(2u, observer_->NumberOfRemoteVideoTracks());
+ observer_->VerifyRemoteVideoTrack(kStreams[0], kVideoTracks[0], 2);
+ observer_->VerifyRemoteVideoTrack(kStreams[1], kVideoTracks[1], 4);
+}
+
+// This test verifies that the remote MediaStreams corresponding to a received
+// SDP string is created. In this test the same remote MediaStream is signaled
+// but MediaStream tracks are added and removed.
+TEST_F(MediaStreamSignalingTest, AddRemoveTrackFromExistingRemoteMediaStream) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_ms1;
+ CreateSessionDescriptionAndReference(1, 1, desc_ms1.use());
+ signaling_->OnRemoteDescriptionChanged(desc_ms1.get());
+ EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
+ reference_collection_));
+
+ // Add extra audio and video tracks to the same MediaStream.
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_ms1_two_tracks;
+ CreateSessionDescriptionAndReference(2, 2, desc_ms1_two_tracks.use());
+ signaling_->OnRemoteDescriptionChanged(desc_ms1_two_tracks.get());
+ EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
+ reference_collection_));
+ EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),
+ reference_collection_));
+
+ // Remove the extra audio and video tracks again.
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_ms2;
+ CreateSessionDescriptionAndReference(1, 1, desc_ms2.use());
+ signaling_->OnRemoteDescriptionChanged(desc_ms2.get());
+ EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
+ reference_collection_));
+ EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),
+ reference_collection_));
+}
+
+// This test that remote tracks are ended if a
+// local session description is set that rejects the media content type.
+TEST_F(MediaStreamSignalingTest, RejectMediaContent) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithStream1, NULL));
+ EXPECT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+
+ ASSERT_EQ(1u, observer_->remote_streams()->count());
+ MediaStreamInterface* remote_stream = observer_->remote_streams()->at(0);
+ ASSERT_EQ(1u, remote_stream->GetVideoTracks().size());
+ ASSERT_EQ(1u, remote_stream->GetAudioTracks().size());
+
+ rtc::scoped_refptr<webrtc::VideoTrackInterface> remote_video =
+ remote_stream->GetVideoTracks()[0];
+ EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, remote_video->state());
+ rtc::scoped_refptr<webrtc::AudioTrackInterface> remote_audio =
+ remote_stream->GetAudioTracks()[0];
+ EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, remote_audio->state());
+
+ cricket::ContentInfo* video_info =
+ desc->description()->GetContentByName("video");
+ ASSERT_TRUE(video_info != NULL);
+ video_info->rejected = true;
+ signaling_->OnLocalDescriptionChanged(desc.get());
+ EXPECT_EQ(webrtc::MediaStreamTrackInterface::kEnded, remote_video->state());
+ EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, remote_audio->state());
+
+ cricket::ContentInfo* audio_info =
+ desc->description()->GetContentByName("audio");
+ ASSERT_TRUE(audio_info != NULL);
+ audio_info->rejected = true;
+ signaling_->OnLocalDescriptionChanged(desc.get());
+ EXPECT_EQ(webrtc::MediaStreamTrackInterface::kEnded, remote_audio->state());
+}
+
+// This test that it won't crash if the remote track as been removed outside
+// of MediaStreamSignaling and then MediaStreamSignaling tries to reject
+// this track.
+TEST_F(MediaStreamSignalingTest, RemoveTrackThenRejectMediaContent) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithStream1, NULL));
+ EXPECT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+
+ MediaStreamInterface* remote_stream = observer_->remote_streams()->at(0);
+ remote_stream->RemoveTrack(remote_stream->GetVideoTracks()[0]);
+ remote_stream->RemoveTrack(remote_stream->GetAudioTracks()[0]);
+
+ cricket::ContentInfo* video_info =
+ desc->description()->GetContentByName("video");
+ video_info->rejected = true;
+ signaling_->OnLocalDescriptionChanged(desc.get());
+
+ cricket::ContentInfo* audio_info =
+ desc->description()->GetContentByName("audio");
+ audio_info->rejected = true;
+ signaling_->OnLocalDescriptionChanged(desc.get());
+
+ // No crash is a pass.
+}
+
+// This tests that a default MediaStream is created if a remote session
+// description doesn't contain any streams and no MSID support.
+// It also tests that the default stream is updated if a video m-line is added
+// in a subsequent session description.
+TEST_F(MediaStreamSignalingTest, SdpWithoutMsidCreatesDefaultStream) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_audio_only(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithoutStreamsAudioOnly,
+ NULL));
+ ASSERT_TRUE(desc_audio_only != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc_audio_only.get());
+
+ EXPECT_EQ(1u, signaling_->remote_streams()->count());
+ ASSERT_EQ(1u, observer_->remote_streams()->count());
+ MediaStreamInterface* remote_stream = observer_->remote_streams()->at(0);
+
+ EXPECT_EQ(1u, remote_stream->GetAudioTracks().size());
+ EXPECT_EQ(0u, remote_stream->GetVideoTracks().size());
+ EXPECT_EQ("default", remote_stream->label());
+
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithoutStreams, NULL));
+ ASSERT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+ EXPECT_EQ(1u, signaling_->remote_streams()->count());
+ ASSERT_EQ(1u, remote_stream->GetAudioTracks().size());
+ EXPECT_EQ("defaulta0", remote_stream->GetAudioTracks()[0]->id());
+ ASSERT_EQ(1u, remote_stream->GetVideoTracks().size());
+ EXPECT_EQ("defaultv0", remote_stream->GetVideoTracks()[0]->id());
+ observer_->VerifyRemoteAudioTrack("default", "defaulta0", 0);
+ observer_->VerifyRemoteVideoTrack("default", "defaultv0", 0);
+}
+
+// This tests that a default MediaStream is created if a remote session
+// description doesn't contain any streams and media direction is send only.
+TEST_F(MediaStreamSignalingTest, RecvOnlySdpWithoutMsidCreatesDefaultStream) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringSendOnlyWithWithoutStreams,
+ NULL));
+ ASSERT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+
+ EXPECT_EQ(1u, signaling_->remote_streams()->count());
+ ASSERT_EQ(1u, observer_->remote_streams()->count());
+ MediaStreamInterface* remote_stream = observer_->remote_streams()->at(0);
+
+ EXPECT_EQ(1u, remote_stream->GetAudioTracks().size());
+ EXPECT_EQ(1u, remote_stream->GetVideoTracks().size());
+ EXPECT_EQ("default", remote_stream->label());
+}
+
+// This tests that it won't crash when MediaStreamSignaling tries to remove
+// a remote track that as already been removed from the mediastream.
+TEST_F(MediaStreamSignalingTest, RemoveAlreadyGoneRemoteStream) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_audio_only(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithoutStreams,
+ NULL));
+ ASSERT_TRUE(desc_audio_only != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc_audio_only.get());
+ MediaStreamInterface* remote_stream = observer_->remote_streams()->at(0);
+ remote_stream->RemoveTrack(remote_stream->GetAudioTracks()[0]);
+ remote_stream->RemoveTrack(remote_stream->GetVideoTracks()[0]);
+
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithoutStreams, NULL));
+ ASSERT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+
+ // No crash is a pass.
+}
+
+// This tests that a default MediaStream is created if the remote session
+// description doesn't contain any streams and don't contain an indication if
+// MSID is supported.
+TEST_F(MediaStreamSignalingTest,
+ SdpWithoutMsidAndStreamsCreatesDefaultStream) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithoutStreams,
+ NULL));
+ ASSERT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+
+ ASSERT_EQ(1u, observer_->remote_streams()->count());
+ MediaStreamInterface* remote_stream = observer_->remote_streams()->at(0);
+ EXPECT_EQ(1u, remote_stream->GetAudioTracks().size());
+ EXPECT_EQ(1u, remote_stream->GetVideoTracks().size());
+}
+
+// This tests that a default MediaStream is not created if the remote session
+// description doesn't contain any streams but does support MSID.
+TEST_F(MediaStreamSignalingTest, SdpWitMsidDontCreatesDefaultStream) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_msid_without_streams(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithMsidWithoutStreams,
+ NULL));
+ signaling_->OnRemoteDescriptionChanged(desc_msid_without_streams.get());
+ EXPECT_EQ(0u, observer_->remote_streams()->count());
+}
+
+// This test that a default MediaStream is not created if a remote session
+// description is updated to not have any MediaStreams.
+TEST_F(MediaStreamSignalingTest, VerifyDefaultStreamIsNotCreated) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithStream1,
+ NULL));
+ ASSERT_TRUE(desc != NULL);
+ signaling_->OnRemoteDescriptionChanged(desc.get());
+ rtc::scoped_refptr<StreamCollection> reference(
+ CreateStreamCollection(1));
+ EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),
+ reference.get()));
+
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_without_streams(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ kSdpStringWithoutStreams,
+ NULL));
+ signaling_->OnRemoteDescriptionChanged(desc_without_streams.get());
+ EXPECT_EQ(0u, observer_->remote_streams()->count());
+}
+
+// This test that the correct MediaStreamSignalingObserver methods are called
+// when MediaStreamSignaling::OnLocalDescriptionChanged is called with an
+// updated local session description.
+TEST_F(MediaStreamSignalingTest, LocalDescriptionChanged) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_1;
+ CreateSessionDescriptionAndReference(2, 2, desc_1.use());
+
+ signaling_->AddLocalStream(reference_collection_->at(0));
+ signaling_->OnLocalDescriptionChanged(desc_1.get());
+ EXPECT_EQ(2u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(2u, observer_->NumberOfLocalVideoTracks());
+ observer_->VerifyLocalAudioTrack(kStreams[0], kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 2);
+ observer_->VerifyLocalAudioTrack(kStreams[0], kAudioTracks[1], 3);
+ observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[1], 4);
+
+ // Remove an audio and video track.
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_2;
+ CreateSessionDescriptionAndReference(1, 1, desc_2.use());
+ signaling_->OnLocalDescriptionChanged(desc_2.get());
+ EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
+ observer_->VerifyLocalAudioTrack(kStreams[0], kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 2);
+}
+
+// This test that the correct MediaStreamSignalingObserver methods are called
+// when MediaStreamSignaling::AddLocalStream is called after
+// MediaStreamSignaling::OnLocalDescriptionChanged is called.
+TEST_F(MediaStreamSignalingTest, AddLocalStreamAfterLocalDescriptionChanged) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_1;
+ CreateSessionDescriptionAndReference(2, 2, desc_1.use());
+
+ signaling_->OnLocalDescriptionChanged(desc_1.get());
+ EXPECT_EQ(0u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(0u, observer_->NumberOfLocalVideoTracks());
+
+ signaling_->AddLocalStream(reference_collection_->at(0));
+ EXPECT_EQ(2u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(2u, observer_->NumberOfLocalVideoTracks());
+ observer_->VerifyLocalAudioTrack(kStreams[0], kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 2);
+ observer_->VerifyLocalAudioTrack(kStreams[0], kAudioTracks[1], 3);
+ observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[1], 4);
+}
+
+// This test that the correct MediaStreamSignalingObserver methods are called
+// if the ssrc on a local track is changed when
+// MediaStreamSignaling::OnLocalDescriptionChanged is called.
+TEST_F(MediaStreamSignalingTest, ChangeSsrcOnTrackInLocalSessionDescription) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc;
+ CreateSessionDescriptionAndReference(1, 1, desc.use());
+
+ signaling_->AddLocalStream(reference_collection_->at(0));
+ signaling_->OnLocalDescriptionChanged(desc.get());
+ EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
+ observer_->VerifyLocalAudioTrack(kStreams[0], kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 2);
+
+ // Change the ssrc of the audio and video track.
+ std::string sdp;
+ desc->ToString(&sdp);
+ std::string ssrc_org = "a=ssrc:1";
+ std::string ssrc_to = "a=ssrc:97";
+ rtc::replace_substrs(ssrc_org.c_str(), ssrc_org.length(),
+ ssrc_to.c_str(), ssrc_to.length(),
+ &sdp);
+ ssrc_org = "a=ssrc:2";
+ ssrc_to = "a=ssrc:98";
+ rtc::replace_substrs(ssrc_org.c_str(), ssrc_org.length(),
+ ssrc_to.c_str(), ssrc_to.length(),
+ &sdp);
+ rtc::scoped_ptr<SessionDescriptionInterface> updated_desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ sdp, NULL));
+
+ signaling_->OnLocalDescriptionChanged(updated_desc.get());
+ EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
+ observer_->VerifyLocalAudioTrack(kStreams[0], kAudioTracks[0], 97);
+ observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 98);
+}
+
+// This test that the correct MediaStreamSignalingObserver methods are called
+// if a new session description is set with the same tracks but they are now
+// sent on a another MediaStream.
+TEST_F(MediaStreamSignalingTest, SignalSameTracksInSeparateMediaStream) {
+ rtc::scoped_ptr<SessionDescriptionInterface> desc;
+ CreateSessionDescriptionAndReference(1, 1, desc.use());
+
+ signaling_->AddLocalStream(reference_collection_->at(0));
+ signaling_->OnLocalDescriptionChanged(desc.get());
+ EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
+
+ std::string stream_label_0 = kStreams[0];
+ observer_->VerifyLocalAudioTrack(stream_label_0, kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(stream_label_0, kVideoTracks[0], 2);
+
+ // Add a new MediaStream but with the same tracks as in the first stream.
+ std::string stream_label_1 = kStreams[1];
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream_1(
+ webrtc::MediaStream::Create(kStreams[1]));
+ stream_1->AddTrack(reference_collection_->at(0)->GetVideoTracks()[0]);
+ stream_1->AddTrack(reference_collection_->at(0)->GetAudioTracks()[0]);
+ signaling_->AddLocalStream(stream_1);
+
+ // Replace msid in the original SDP.
+ std::string sdp;
+ desc->ToString(&sdp);
+ rtc::replace_substrs(
+ kStreams[0], strlen(kStreams[0]), kStreams[1], strlen(kStreams[1]), &sdp);
+
+ rtc::scoped_ptr<SessionDescriptionInterface> updated_desc(
+ webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
+ sdp, NULL));
+
+ signaling_->OnLocalDescriptionChanged(updated_desc.get());
+ observer_->VerifyLocalAudioTrack(kStreams[1], kAudioTracks[0], 1);
+ observer_->VerifyLocalVideoTrack(kStreams[1], kVideoTracks[0], 2);
+ EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
+ EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
+}
+
+// Verifies that an even SCTP id is allocated for SSL_CLIENT and an odd id for
+// SSL_SERVER.
+TEST_F(MediaStreamSignalingTest, SctpIdAllocationBasedOnRole) {
+ int id;
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_SERVER, &id));
+ EXPECT_EQ(1, id);
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_CLIENT, &id));
+ EXPECT_EQ(0, id);
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_SERVER, &id));
+ EXPECT_EQ(3, id);
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_CLIENT, &id));
+ EXPECT_EQ(2, id);
+}
+
+// Verifies that SCTP ids of existing DataChannels are not reused.
+TEST_F(MediaStreamSignalingTest, SctpIdAllocationNoReuse) {
+ int old_id = 1;
+ AddDataChannel(cricket::DCT_SCTP, "a", old_id);
+
+ int new_id;
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_SERVER, &new_id));
+ EXPECT_NE(old_id, new_id);
+
+ // Creates a DataChannel with id 0.
+ old_id = 0;
+ AddDataChannel(cricket::DCT_SCTP, "a", old_id);
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_CLIENT, &new_id));
+ EXPECT_NE(old_id, new_id);
+}
+
+// Verifies that SCTP ids of removed DataChannels can be reused.
+TEST_F(MediaStreamSignalingTest, SctpIdReusedForRemovedDataChannel) {
+ int odd_id = 1;
+ int even_id = 0;
+ AddDataChannel(cricket::DCT_SCTP, "a", odd_id);
+ AddDataChannel(cricket::DCT_SCTP, "a", even_id);
+
+ int allocated_id = -1;
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_SERVER,
+ &allocated_id));
+ EXPECT_EQ(odd_id + 2, allocated_id);
+ AddDataChannel(cricket::DCT_SCTP, "a", allocated_id);
+
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_CLIENT,
+ &allocated_id));
+ EXPECT_EQ(even_id + 2, allocated_id);
+ AddDataChannel(cricket::DCT_SCTP, "a", allocated_id);
+
+ signaling_->RemoveSctpDataChannel(odd_id);
+ signaling_->RemoveSctpDataChannel(even_id);
+
+ // Verifies that removed DataChannel ids are reused.
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_SERVER,
+ &allocated_id));
+ EXPECT_EQ(odd_id, allocated_id);
+
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_CLIENT,
+ &allocated_id));
+ EXPECT_EQ(even_id, allocated_id);
+
+ // Verifies that used higher DataChannel ids are not reused.
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_SERVER,
+ &allocated_id));
+ EXPECT_NE(odd_id + 2, allocated_id);
+
+ ASSERT_TRUE(signaling_->AllocateSctpSid(rtc::SSL_CLIENT,
+ &allocated_id));
+ EXPECT_NE(even_id + 2, allocated_id);
+
+}
+
+// Verifies that duplicated label is not allowed for RTP data channel.
+TEST_F(MediaStreamSignalingTest, RtpDuplicatedLabelNotAllowed) {
+ AddDataChannel(cricket::DCT_RTP, "a", -1);
+
+ webrtc::InternalDataChannelInit config;
+ rtc::scoped_refptr<webrtc::DataChannel> data_channel =
+ webrtc::DataChannel::Create(
+ data_channel_provider_.get(), cricket::DCT_RTP, "a", config);
+ ASSERT_TRUE(data_channel.get() != NULL);
+ EXPECT_FALSE(signaling_->AddDataChannel(data_channel.get()));
+}
+
+// Verifies that duplicated label is allowed for SCTP data channel.
+TEST_F(MediaStreamSignalingTest, SctpDuplicatedLabelAllowed) {
+ AddDataChannel(cricket::DCT_SCTP, "a", -1);
+ AddDataChannel(cricket::DCT_SCTP, "a", -1);
+}
+
+// Verifies the correct configuration is used to create DataChannel from an OPEN
+// message.
+TEST_F(MediaStreamSignalingTest, CreateDataChannelFromOpenMessage) {
+ FakeDataChannelFactory fake_factory(data_channel_provider_.get(),
+ cricket::DCT_SCTP,
+ signaling_.get());
+ signaling_->SetDataChannelFactory(&fake_factory);
+ webrtc::DataChannelInit config;
+ config.id = 1;
+ rtc::Buffer payload;
+ webrtc::WriteDataChannelOpenMessage("a", config, &payload);
+ cricket::ReceiveDataParams params;
+ params.ssrc = config.id;
+ EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage(params, payload));
+ EXPECT_EQ(config.id, fake_factory.last_init().id);
+ EXPECT_FALSE(fake_factory.last_init().negotiated);
+ EXPECT_EQ(webrtc::InternalDataChannelInit::kAcker,
+ fake_factory.last_init().open_handshake_role);
+}
+
+// Verifies that duplicated label from OPEN message is allowed.
+TEST_F(MediaStreamSignalingTest, DuplicatedLabelFromOpenMessageAllowed) {
+ AddDataChannel(cricket::DCT_SCTP, "a", -1);
+
+ FakeDataChannelFactory fake_factory(data_channel_provider_.get(),
+ cricket::DCT_SCTP,
+ signaling_.get());
+ signaling_->SetDataChannelFactory(&fake_factory);
+ webrtc::DataChannelInit config;
+ config.id = 0;
+ rtc::Buffer payload;
+ webrtc::WriteDataChannelOpenMessage("a", config, &payload);
+ cricket::ReceiveDataParams params;
+ params.ssrc = config.id;
+ EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage(params, payload));
+}
+
+// Verifies that a DataChannel closed remotely is closed locally.
+TEST_F(MediaStreamSignalingTest,
+ SctpDataChannelClosedLocallyWhenClosedRemotely) {
+ webrtc::InternalDataChannelInit config;
+ config.id = 0;
+
+ rtc::scoped_refptr<webrtc::DataChannel> data_channel =
+ webrtc::DataChannel::Create(
+ data_channel_provider_.get(), cricket::DCT_SCTP, "a", config);
+ ASSERT_TRUE(data_channel.get() != NULL);
+ EXPECT_EQ(webrtc::DataChannelInterface::kConnecting,
+ data_channel->state());
+
+ EXPECT_TRUE(signaling_->AddDataChannel(data_channel.get()));
+
+ signaling_->OnRemoteSctpDataChannelClosed(config.id);
+ EXPECT_EQ(webrtc::DataChannelInterface::kClosed, data_channel->state());
+}
+
+// Verifies that DataChannel added from OPEN message is added to
+// MediaStreamSignaling only once (webrtc issue 3778).
+TEST_F(MediaStreamSignalingTest, DataChannelFromOpenMessageAddedOnce) {
+ FakeDataChannelFactory fake_factory(data_channel_provider_.get(),
+ cricket::DCT_SCTP,
+ signaling_.get());
+ signaling_->SetDataChannelFactory(&fake_factory);
+ webrtc::DataChannelInit config;
+ config.id = 1;
+ rtc::Buffer payload;
+ webrtc::WriteDataChannelOpenMessage("a", config, &payload);
+ cricket::ReceiveDataParams params;
+ params.ssrc = config.id;
+ EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage(params, payload));
+ EXPECT_TRUE(signaling_->HasDataChannels());
+
+ // Removes the DataChannel and verifies that no DataChannel is left.
+ signaling_->RemoveSctpDataChannel(config.id);
+ EXPECT_FALSE(signaling_->HasDataChannels());
+}
diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc
index 44a231e..86902b0 100644
--- a/talk/app/webrtc/peerconnection.cc
+++ b/talk/app/webrtc/peerconnection.cc
@@ -30,36 +30,22 @@
#include <vector>
#include <cctype> // for isdigit
-#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/dtmfsender.h"
#include "talk/app/webrtc/jsepicecandidate.h"
#include "talk/app/webrtc/jsepsessiondescription.h"
#include "talk/app/webrtc/mediaconstraintsinterface.h"
-#include "talk/app/webrtc/mediastream.h"
-#include "talk/app/webrtc/mediastreamproxy.h"
-#include "talk/app/webrtc/mediastreamtrackproxy.h"
-#include "talk/app/webrtc/remoteaudiosource.h"
-#include "talk/app/webrtc/remotevideocapturer.h"
#include "talk/app/webrtc/rtpreceiver.h"
#include "talk/app/webrtc/rtpsender.h"
#include "talk/app/webrtc/streamcollection.h"
-#include "talk/app/webrtc/videosource.h"
-#include "talk/app/webrtc/videotrack.h"
-#include "talk/media/sctp/sctpdataengine.h"
#include "webrtc/p2p/client/basicportallocator.h"
#include "talk/session/media/channelmanager.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/stringencode.h"
-#include "webrtc/base/stringutils.h"
#include "webrtc/system_wrappers/interface/field_trial.h"
namespace {
-using webrtc::DataChannel;
-using webrtc::MediaConstraintsInterface;
-using webrtc::MediaStreamInterface;
using webrtc::PeerConnectionInterface;
-using webrtc::StreamCollection;
using webrtc::StunConfigurations;
using webrtc::TurnConfigurations;
typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
@@ -67,10 +53,6 @@
typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
TurnConfiguration;
-static const char kDefaultStreamLabel[] = "default";
-static const char kDefaultAudioTrackLabel[] = "defaulta0";
-static const char kDefaultVideoTrackLabel[] = "defaultv0";
-
// The min number of tokens must present in Turn host uri.
// e.g. user@turn.example.org
static const size_t kTurnHostTokensNum = 2;
@@ -102,7 +84,6 @@
enum {
MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
MSG_SET_SESSIONDESCRIPTION_FAILED,
- MSG_CREATE_SESSIONDESCRIPTION_FAILED,
MSG_GETSTATS,
};
@@ -116,15 +97,6 @@
std::string error;
};
-struct CreateSessionDescriptionMsg : public rtc::MessageData {
- explicit CreateSessionDescriptionMsg(
- webrtc::CreateSessionDescriptionObserver* observer)
- : observer(observer) {}
-
- rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
- std::string error;
-};
-
struct GetStatsMsg : public rtc::MessageData {
GetStatsMsg(webrtc::StatsObserver* observer,
webrtc::MediaStreamTrackInterface* track)
@@ -330,210 +302,10 @@
return true;
}
-// Check if we can send |new_stream| on a PeerConnection.
-bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
- webrtc::MediaStreamInterface* new_stream) {
- if (!new_stream || !current_streams) {
- return false;
- }
- if (current_streams->find(new_stream->label()) != nullptr) {
- LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
- << " is already added.";
- return false;
- }
- return true;
-}
-
-bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
- return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
-}
-
-bool IsValidOfferToReceiveMedia(int value) {
- typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
- return (value >= Options::kUndefined) &&
- (value <= Options::kMaxOfferToReceiveMedia);
-}
-
-// Add the stream and RTP data channel info to |session_options|.
-void SetStreams(cricket::MediaSessionOptions* session_options,
- rtc::scoped_refptr<StreamCollection> streams,
- const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
- rtp_data_channels) {
- session_options->streams.clear();
- if (streams != nullptr) {
- for (size_t i = 0; i < streams->count(); ++i) {
- MediaStreamInterface* stream = streams->at(i);
- // For each audio track in the stream, add it to the MediaSessionOptions.
- for (const auto& track : stream->GetAudioTracks()) {
- session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, track->id(),
- stream->label());
- }
- // For each video track in the stream, add it to the MediaSessionOptions.
- for (const auto& track : stream->GetVideoTracks()) {
- session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, track->id(),
- stream->label());
- }
- }
- }
-
- // Check for data channels.
- for (const auto& kv : rtp_data_channels) {
- const DataChannel* channel = kv.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->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
- sync_label);
- }
- }
-}
-
} // namespace
namespace webrtc {
-// Factory class for creating remote MediaStreams and MediaStreamTracks.
-class RemoteMediaStreamFactory {
- public:
- explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
- cricket::ChannelManager* channel_manager)
- : signaling_thread_(signaling_thread),
- channel_manager_(channel_manager) {}
-
- rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
- const std::string& stream_label) {
- return MediaStreamProxy::Create(signaling_thread_,
- MediaStream::Create(stream_label));
- }
-
- AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
- const std::string& track_id) {
- return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
- stream, track_id, RemoteAudioSource::Create().get());
- }
-
- VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
- const std::string& track_id) {
- return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
- stream, track_id,
- VideoSource::Create(channel_manager_, new RemoteVideoCapturer(),
- nullptr)
- .get());
- }
-
- private:
- template <typename TI, typename T, typename TP, typename S>
- TI* AddTrack(MediaStreamInterface* stream,
- const std::string& track_id,
- S* source) {
- rtc::scoped_refptr<TI> track(
- TP::Create(signaling_thread_, T::Create(track_id, source)));
- track->set_state(webrtc::MediaStreamTrackInterface::kLive);
- if (stream->AddTrack(track)) {
- return track;
- }
- return nullptr;
- }
-
- rtc::Thread* signaling_thread_;
- cricket::ChannelManager* channel_manager_;
-};
-
-bool ConvertRtcOptionsForOffer(
- const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
- cricket::MediaSessionOptions* session_options) {
- typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
- if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
- !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
- return false;
- }
-
- // According to the spec, offer to receive audio/video if the constraint is
- // not set and there are send streams.
- if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
- session_options->recv_audio =
- session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO);
- } else {
- session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
- }
- if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
- session_options->recv_video =
- session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO);
- } else {
- session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
- }
-
- 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->has_audio() || session_options->has_video() ||
- session_options->has_data());
-
- return true;
-}
-
-bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
- cricket::MediaSessionOptions* session_options) {
- bool value = false;
- size_t mandatory_constraints_satisfied = 0;
-
- // kOfferToReceiveAudio defaults to true according to spec.
- if (!FindConstraint(constraints,
- MediaConstraintsInterface::kOfferToReceiveAudio, &value,
- &mandatory_constraints_satisfied) ||
- value) {
- session_options->recv_audio = true;
- }
-
- // kOfferToReceiveVideo defaults to false according to spec. But
- // if it is an answer and video is offered, we should still accept video
- // per default.
- value = false;
- if (!FindConstraint(constraints,
- MediaConstraintsInterface::kOfferToReceiveVideo, &value,
- &mandatory_constraints_satisfied) ||
- value) {
- session_options->recv_video = true;
- }
-
- if (FindConstraint(constraints,
- MediaConstraintsInterface::kVoiceActivityDetection, &value,
- &mandatory_constraints_satisfied)) {
- session_options->vad_enabled = value;
- }
-
- if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
- &mandatory_constraints_satisfied)) {
- session_options->bundle_enabled = value;
- } else {
- // kUseRtpMux defaults to true according to spec.
- session_options->bundle_enabled = true;
- }
- session_options->bundle_enabled =
- session_options->bundle_enabled &&
- (session_options->has_audio() || session_options->has_video() ||
- session_options->has_data());
-
- if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
- &value, &mandatory_constraints_satisfied)) {
- session_options->transport_options.ice_restart = value;
- } else {
- // kIceRestart defaults to false according to spec.
- session_options->transport_options.ice_restart = false;
- }
-
- if (!constraints) {
- return true;
- }
- return mandatory_constraints_satisfied == constraints->GetMandatory().size();
-}
-
bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
StunConfigurations* stun_config,
TurnConfigurations* turn_config) {
@@ -561,6 +333,22 @@
return true;
}
+// Check if we can send |new_stream| on a PeerConnection.
+// Currently only one audio but multiple video track is supported per
+// PeerConnection.
+bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
+ webrtc::MediaStreamInterface* new_stream) {
+ if (!new_stream || !current_streams)
+ return false;
+ if (current_streams->find(new_stream->label()) != NULL) {
+ LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
+ << " is already added.";
+ return false;
+ }
+
+ return true;
+}
+
PeerConnection::PeerConnection(PeerConnectionFactory* factory)
: factory_(factory),
observer_(NULL),
@@ -568,12 +356,14 @@
signaling_state_(kStable),
ice_state_(kIceNew),
ice_connection_state_(kIceConnectionNew),
- ice_gathering_state_(kIceGatheringNew),
- local_streams_(StreamCollection::Create()),
- remote_streams_(StreamCollection::Create()) {}
+ ice_gathering_state_(kIceGatheringNew) {
+}
PeerConnection::~PeerConnection() {
RTC_DCHECK(signaling_thread()->IsCurrent());
+ if (mediastream_signaling_) {
+ mediastream_signaling_->TearDown();
+ }
// Need to detach RTP senders/receivers from WebRtcSession,
// since it's about to be destroyed.
for (const auto& sender : senders_) {
@@ -590,10 +380,9 @@
PortAllocatorFactoryInterface* allocator_factory,
rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
PeerConnectionObserver* observer) {
- RTC_DCHECK(observer != nullptr);
- if (!observer) {
+ RTC_DCHECK(observer != NULL);
+ if (!observer)
return false;
- }
observer_ = observer;
std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
@@ -611,8 +400,8 @@
cricket::PORTALLOCATOR_ENABLE_IPV6;
bool value;
// If IPv6 flag was specified, we'll not override it by experiment.
- if (FindConstraint(constraints, MediaConstraintsInterface::kEnableIPv6,
- &value, nullptr)) {
+ if (FindConstraint(
+ constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
if (!value) {
portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
}
@@ -630,45 +419,36 @@
// No step delay is used while allocating ports.
port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
- remote_stream_factory_.reset(new RemoteMediaStreamFactory(
- factory_->signaling_thread(), factory_->channel_manager()));
+ mediastream_signaling_.reset(new MediaStreamSignaling(
+ factory_->signaling_thread(), this, factory_->channel_manager()));
- session_.reset(new WebRtcSession(
- factory_->channel_manager(), factory_->signaling_thread(),
- factory_->worker_thread(), port_allocator_.get()));
- stats_.reset(new StatsCollector(this));
+ session_.reset(new WebRtcSession(factory_->channel_manager(),
+ factory_->signaling_thread(),
+ factory_->worker_thread(),
+ port_allocator_.get(),
+ mediastream_signaling_.get()));
+ stats_.reset(new StatsCollector(session_.get()));
// Initialize the WebRtcSession. It creates transport channels etc.
if (!session_->Initialize(factory_->options(), constraints,
- dtls_identity_store.Pass(), configuration)) {
+ dtls_identity_store.Pass(), configuration))
return false;
- }
// Register PeerConnection as receiver of local ice candidates.
// All the callbacks will be posted to the application from PeerConnection.
session_->RegisterIceObserver(this);
session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
- session_->SignalVoiceChannelDestroyed.connect(
- this, &PeerConnection::OnVoiceChannelDestroyed);
- session_->SignalVideoChannelDestroyed.connect(
- this, &PeerConnection::OnVideoChannelDestroyed);
- session_->SignalDataChannelCreated.connect(
- this, &PeerConnection::OnDataChannelCreated);
- session_->SignalDataChannelDestroyed.connect(
- this, &PeerConnection::OnDataChannelDestroyed);
- session_->SignalDataChannelOpenMessage.connect(
- this, &PeerConnection::OnDataChannelOpenMessage);
return true;
}
rtc::scoped_refptr<StreamCollectionInterface>
PeerConnection::local_streams() {
- return local_streams_;
+ return mediastream_signaling_->local_streams();
}
rtc::scoped_refptr<StreamCollectionInterface>
PeerConnection::remote_streams() {
- return remote_streams_;
+ return mediastream_signaling_->remote_streams();
}
// TODO(deadbeef): Create RtpSenders immediately here, even if local
@@ -677,57 +457,20 @@
if (IsClosed()) {
return false;
}
- if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
+ if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
+ local_stream))
+ return false;
+
+ if (!mediastream_signaling_->AddLocalStream(local_stream)) {
return false;
}
-
- local_streams_->AddStream(local_stream);
-
- // Find tracks that have already been configured in SDP. This can occur if a
- // local session description that contains the MSID of these tracks is set
- // before AddLocalStream is called. It can also occur if the local session
- // description is not changed and RemoveLocalStream is called and later
- // AddLocalStream is called again with the same stream.
- for (const auto& track : local_stream->GetAudioTracks()) {
- const TrackInfo* track_info =
- FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id());
- if (track_info) {
- CreateAudioSender(local_stream, track.get(), track_info->ssrc);
- }
- }
- for (const auto& track : local_stream->GetVideoTracks()) {
- const TrackInfo* track_info =
- FindTrackInfo(local_video_tracks_, local_stream->label(), track->id());
- if (track_info) {
- CreateVideoSender(local_stream, track.get(), track_info->ssrc);
- }
- }
-
stats_->AddStream(local_stream);
observer_->OnRenegotiationNeeded();
return true;
}
-// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
-// indefinitely.
void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
- for (const auto& track : local_stream->GetAudioTracks()) {
- const TrackInfo* track_info =
- FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id());
- if (track_info) {
- DestroyAudioSender(local_stream, track.get(), track_info->ssrc);
- }
- }
- for (const auto& track : local_stream->GetVideoTracks()) {
- const TrackInfo* track_info =
- FindTrackInfo(local_video_tracks_, local_stream->label(), track->id());
- if (track_info) {
- DestroyVideoSender(local_stream, track.get());
- }
- }
-
- local_streams_->RemoveStream(local_stream);
-
+ mediastream_signaling_->RemoveLocalStream(local_stream);
if (IsClosed()) {
return;
}
@@ -740,7 +483,7 @@
LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
return NULL;
}
- if (!local_streams_->FindAudioTrack(track->id())) {
+ if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
return NULL;
}
@@ -810,17 +553,16 @@
PeerConnection::CreateDataChannel(
const std::string& label,
const DataChannelInit* config) {
- bool first_datachannel = !HasDataChannels();
+ bool first_datachannel = !mediastream_signaling_->HasDataChannels();
rtc::scoped_ptr<InternalDataChannelInit> internal_config;
if (config) {
internal_config.reset(new InternalDataChannelInit(*config));
}
rtc::scoped_refptr<DataChannelInterface> channel(
- InternalCreateDataChannel(label, internal_config.get()));
- if (!channel.get()) {
- return nullptr;
- }
+ session_->CreateDataChannel(label, internal_config.get()));
+ if (!channel.get())
+ return NULL;
// Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
// the first SCTP DataChannel.
@@ -833,7 +575,7 @@
void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
const MediaConstraintsInterface* constraints) {
- if (!VERIFY(observer != nullptr)) {
+ if (!VERIFY(observer != NULL)) {
LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
return;
}
@@ -884,45 +626,27 @@
void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
const RTCOfferAnswerOptions& options) {
- if (!VERIFY(observer != nullptr)) {
+ if (!VERIFY(observer != NULL)) {
LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
return;
}
-
- cricket::MediaSessionOptions session_options;
- if (!GetOptionsForOffer(options, &session_options)) {
- std::string error = "CreateOffer called with invalid options.";
- LOG(LS_ERROR) << error;
- PostCreateSessionDescriptionFailure(observer, error);
- return;
- }
-
- session_->CreateOffer(observer, options, session_options);
+ session_->CreateOffer(observer, options);
}
void PeerConnection::CreateAnswer(
CreateSessionDescriptionObserver* observer,
const MediaConstraintsInterface* constraints) {
- if (!VERIFY(observer != nullptr)) {
+ if (!VERIFY(observer != NULL)) {
LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
return;
}
-
- cricket::MediaSessionOptions session_options;
- if (!GetOptionsForAnswer(constraints, &session_options)) {
- std::string error = "CreateAnswer called with invalid constraints.";
- LOG(LS_ERROR) << error;
- PostCreateSessionDescriptionFailure(observer, error);
- return;
- }
-
- session_->CreateAnswer(observer, constraints, session_options);
+ session_->CreateAnswer(observer, constraints);
}
void PeerConnection::SetLocalDescription(
SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc) {
- if (!VERIFY(observer != nullptr)) {
+ if (!VERIFY(observer != NULL)) {
LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
return;
}
@@ -938,50 +662,8 @@
PostSetSessionDescriptionFailure(observer, error);
return;
}
-
- // If setting the description decided our SSL role, allocate any necessary
- // SCTP sids.
- rtc::SSLRole role;
- if (session_->data_channel_type() == cricket::DCT_SCTP &&
- session_->GetSslRole(&role)) {
- AllocateSctpSids(role);
- }
-
- // Update state and SSRC of local MediaStreams and DataChannels based on the
- // local session description.
- const cricket::ContentInfo* audio_content =
- GetFirstAudioContent(desc->description());
- if (audio_content) {
- const cricket::AudioContentDescription* audio_desc =
- static_cast<const cricket::AudioContentDescription*>(
- audio_content->description);
- UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
- }
-
- const cricket::ContentInfo* video_content =
- GetFirstVideoContent(desc->description());
- if (video_content) {
- const cricket::VideoContentDescription* video_desc =
- static_cast<const cricket::VideoContentDescription*>(
- video_content->description);
- UpdateLocalTracks(video_desc->streams(), video_desc->type());
- }
-
- const cricket::ContentInfo* data_content =
- GetFirstDataContent(desc->description());
- if (data_content) {
- const cricket::DataContentDescription* data_desc =
- static_cast<const cricket::DataContentDescription*>(
- data_content->description);
- if (rtc::starts_with(data_desc->protocol().data(),
- cricket::kMediaProtocolRtpPrefix)) {
- UpdateLocalRtpDataChannels(data_desc->streams());
- }
- }
-
- SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
+ SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
-
// MaybeStartGathering needs to be called after posting
// MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
// before signaling that SetLocalDescription completed.
@@ -991,7 +673,7 @@
void PeerConnection::SetRemoteDescription(
SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc) {
- if (!VERIFY(observer != nullptr)) {
+ if (!VERIFY(observer != NULL)) {
LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
return;
}
@@ -1007,80 +689,18 @@
PostSetSessionDescriptionFailure(observer, error);
return;
}
-
- // If setting the description decided our SSL role, allocate any necessary
- // SCTP sids.
- rtc::SSLRole role;
- if (session_->data_channel_type() == cricket::DCT_SCTP &&
- session_->GetSslRole(&role)) {
- AllocateSctpSids(role);
- }
-
- const cricket::SessionDescription* remote_desc = desc->description();
-
- // We wait to signal new streams until we finish processing the description,
- // since only at that point will new streams have all their tracks.
- rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
-
- // Find all audio rtp streams and create corresponding remote AudioTracks
- // and MediaStreams.
- const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
- if (audio_content) {
- const cricket::AudioContentDescription* desc =
- static_cast<const cricket::AudioContentDescription*>(
- audio_content->description);
- UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
- remote_info_.default_audio_track_needed =
- MediaContentDirectionHasSend(desc->direction()) &&
- desc->streams().empty();
- }
-
- // Find all video rtp streams and create corresponding remote VideoTracks
- // and MediaStreams.
- const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
- if (video_content) {
- const cricket::VideoContentDescription* desc =
- static_cast<const cricket::VideoContentDescription*>(
- video_content->description);
- UpdateRemoteStreamsList(desc->streams(), desc->type(), new_streams);
- remote_info_.default_video_track_needed =
- MediaContentDirectionHasSend(desc->direction()) &&
- desc->streams().empty();
- }
-
- // Update the DataChannels with the information from the remote peer.
- const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc);
- if (data_content) {
- const cricket::DataContentDescription* data_desc =
- static_cast<const cricket::DataContentDescription*>(
- data_content->description);
- if (rtc::starts_with(data_desc->protocol().data(),
- cricket::kMediaProtocolRtpPrefix)) {
- UpdateRemoteRtpDataChannels(data_desc->streams());
- }
- }
-
- // Iterate new_streams and notify the observer about new MediaStreams.
- for (size_t i = 0; i < new_streams->count(); ++i) {
- MediaStreamInterface* new_stream = new_streams->at(i);
- stats_->AddStream(new_stream);
- observer_->OnAddStream(new_stream);
- }
-
- // Find removed MediaStreams.
- if (remote_info_.IsDefaultMediaStreamNeeded() &&
- remote_streams_->find(kDefaultStreamLabel) != nullptr) {
- // The default media stream already exists. No need to do anything.
- } else {
- UpdateEndedRemoteMediaStreams();
- remote_info_.msid_supported |= remote_streams_->count() > 0;
- }
- MaybeCreateDefaultStream();
-
- SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
+ SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
}
+void PeerConnection::PostSetSessionDescriptionFailure(
+ SetSessionDescriptionObserver* observer,
+ const std::string& error) {
+ SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
+ msg->error = error;
+ signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
+}
+
bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
if (port_allocator_) {
std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
@@ -1212,13 +832,6 @@
delete param;
break;
}
- case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
- CreateSessionDescriptionMsg* param =
- static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
- param->observer->OnFailure(param->error);
- delete param;
- break;
- }
case MSG_GETSTATS: {
GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
StatsReports reports;
@@ -1233,22 +846,37 @@
}
}
-void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track,
- uint32_t ssrc) {
+void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
+ stats_->AddStream(stream);
+ observer_->OnAddStream(stream);
+}
+
+void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
+ observer_->OnRemoveStream(stream);
+}
+
+void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
+ observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
+ data_channel));
+}
+
+void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) {
receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
}
-void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
- VideoTrackInterface* video_track,
- uint32_t ssrc) {
+void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) {
receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
}
// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
// description.
-void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track) {
+void PeerConnection::OnRemoveRemoteAudioTrack(
+ MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track) {
auto it = FindReceiverForTrack(audio_track);
if (it == receivers_.end()) {
LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
@@ -1259,8 +887,9 @@
}
}
-void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
- VideoTrackInterface* video_track) {
+void PeerConnection::OnRemoveRemoteVideoTrack(
+ MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) {
auto it = FindReceiverForTrack(video_track);
if (it == receivers_.end()) {
LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
@@ -1271,24 +900,24 @@
}
}
-void PeerConnection::CreateAudioSender(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track,
- uint32_t ssrc) {
+void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) {
senders_.push_back(new AudioRtpSender(audio_track, ssrc, session_.get()));
stats_->AddLocalAudioTrack(audio_track, ssrc);
}
-void PeerConnection::CreateVideoSender(MediaStreamInterface* stream,
- VideoTrackInterface* video_track,
- uint32_t ssrc) {
+void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) {
senders_.push_back(new VideoRtpSender(video_track, ssrc, session_.get()));
}
// TODO(deadbeef): Keep RtpSenders around even if track goes away in local
// description.
-void PeerConnection::DestroyAudioSender(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track,
- uint32_t ssrc) {
+void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) {
auto it = FindSenderForTrack(audio_track);
if (it == senders_.end()) {
LOG(LS_WARNING) << "RtpSender for track with id " << audio_track->id()
@@ -1301,8 +930,8 @@
stats_->RemoveLocalAudioTrack(audio_track, ssrc);
}
-void PeerConnection::DestroyVideoSender(MediaStreamInterface* stream,
- VideoTrackInterface* video_track) {
+void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) {
auto it = FindSenderForTrack(video_track);
if (it == senders_.end()) {
LOG(LS_WARNING) << "RtpSender for track with id " << video_track->id()
@@ -1314,12 +943,15 @@
}
}
+void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
+}
+
void PeerConnection::OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) {
RTC_DCHECK(signaling_thread()->IsCurrent());
// After transitioning to "closed", ignore any additional states from
// WebRtcSession (such as "disconnected").
- if (IsClosed()) {
+ if (ice_connection_state_ == kIceConnectionClosed) {
return;
}
ice_connection_state_ = new_state;
@@ -1366,540 +998,6 @@
observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
}
-void PeerConnection::PostSetSessionDescriptionFailure(
- SetSessionDescriptionObserver* observer,
- const std::string& error) {
- SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
- msg->error = error;
- signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
-}
-
-void PeerConnection::PostCreateSessionDescriptionFailure(
- CreateSessionDescriptionObserver* observer,
- const std::string& error) {
- CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
- msg->error = error;
- signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
-}
-
-bool PeerConnection::GetOptionsForOffer(
- const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
- cricket::MediaSessionOptions* session_options) {
- SetStreams(session_options, local_streams_, rtp_data_channels_);
-
- if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
- return false;
- }
-
- if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
- session_options->data_channel_type = cricket::DCT_SCTP;
- }
- return true;
-}
-
-bool PeerConnection::GetOptionsForAnswer(
- const MediaConstraintsInterface* constraints,
- cricket::MediaSessionOptions* session_options) {
- SetStreams(session_options, local_streams_, rtp_data_channels_);
- session_options->recv_audio = false;
- session_options->recv_video = false;
-
- if (!ParseConstraintsForAnswer(constraints, session_options)) {
- return false;
- }
-
- // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
- // are not signaled in the SDP so does not go through that path and must be
- // handled here.
- if (session_->data_channel_type() == cricket::DCT_SCTP) {
- session_options->data_channel_type = cricket::DCT_SCTP;
- }
- return true;
-}
-
-void PeerConnection::UpdateRemoteStreamsList(
- const cricket::StreamParamsVec& streams,
- cricket::MediaType media_type,
- StreamCollection* new_streams) {
- TrackInfos* current_tracks = GetRemoteTracks(media_type);
-
- // Find removed tracks. I.e., tracks where the track id or ssrc don't match
- // the
- // new StreamParam.
- auto track_it = current_tracks->begin();
- while (track_it != current_tracks->end()) {
- const TrackInfo& info = *track_it;
- const cricket::StreamParams* params =
- cricket::GetStreamBySsrc(streams, info.ssrc);
- if (!params || params->id != info.track_id) {
- OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
- track_it = current_tracks->erase(track_it);
- } else {
- ++track_it;
- }
- }
-
- // Find new and active tracks.
- for (const cricket::StreamParams& params : streams) {
- // The sync_label is the MediaStream label and the |stream.id| is the
- // track id.
- const std::string& stream_label = params.sync_label;
- const std::string& track_id = params.id;
- uint32_t ssrc = params.first_ssrc();
-
- rtc::scoped_refptr<MediaStreamInterface> stream =
- remote_streams_->find(stream_label);
- if (!stream) {
- // This is a new MediaStream. Create a new remote MediaStream.
- stream = remote_stream_factory_->CreateMediaStream(stream_label);
- remote_streams_->AddStream(stream);
- new_streams->AddStream(stream);
- }
-
- const TrackInfo* track_info =
- FindTrackInfo(*current_tracks, stream_label, track_id);
- if (!track_info) {
- current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
- OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
- }
- }
-}
-
-void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
- const std::string& track_id,
- uint32_t ssrc,
- cricket::MediaType media_type) {
- MediaStreamInterface* stream = remote_streams_->find(stream_label);
-
- if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- AudioTrackInterface* audio_track =
- remote_stream_factory_->AddAudioTrack(stream, track_id);
- CreateAudioReceiver(stream, audio_track, ssrc);
- } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
- VideoTrackInterface* video_track =
- remote_stream_factory_->AddVideoTrack(stream, track_id);
- CreateVideoReceiver(stream, video_track, ssrc);
- } else {
- RTC_DCHECK(false && "Invalid media type");
- }
-}
-
-void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
- const std::string& track_id,
- cricket::MediaType media_type) {
- MediaStreamInterface* stream = remote_streams_->find(stream_label);
-
- if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- rtc::scoped_refptr<AudioTrackInterface> audio_track =
- stream->FindAudioTrack(track_id);
- if (audio_track) {
- audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
- stream->RemoveTrack(audio_track);
- DestroyAudioReceiver(stream, audio_track);
- }
- } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
- rtc::scoped_refptr<VideoTrackInterface> video_track =
- stream->FindVideoTrack(track_id);
- if (video_track) {
- video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
- stream->RemoveTrack(video_track);
- DestroyVideoReceiver(stream, video_track);
- }
- } else {
- ASSERT(false && "Invalid media type");
- }
-}
-
-void PeerConnection::UpdateEndedRemoteMediaStreams() {
- std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
- for (size_t i = 0; i < remote_streams_->count(); ++i) {
- MediaStreamInterface* stream = remote_streams_->at(i);
- if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
- streams_to_remove.push_back(stream);
- }
- }
-
- for (const auto& stream : streams_to_remove) {
- remote_streams_->RemoveStream(stream);
- observer_->OnRemoveStream(stream);
- }
-}
-
-void PeerConnection::MaybeCreateDefaultStream() {
- if (!remote_info_.IsDefaultMediaStreamNeeded()) {
- return;
- }
-
- bool default_created = false;
-
- rtc::scoped_refptr<MediaStreamInterface> default_remote_stream =
- remote_streams_->find(kDefaultStreamLabel);
- if (default_remote_stream == nullptr) {
- default_created = true;
- default_remote_stream =
- remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
- remote_streams_->AddStream(default_remote_stream);
- }
- if (remote_info_.default_audio_track_needed &&
- default_remote_stream->GetAudioTracks().size() == 0) {
- remote_audio_tracks_.push_back(
- TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0));
- OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
- cricket::MEDIA_TYPE_AUDIO);
- }
- if (remote_info_.default_video_track_needed &&
- default_remote_stream->GetVideoTracks().size() == 0) {
- remote_video_tracks_.push_back(
- TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0));
- OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
- cricket::MEDIA_TYPE_VIDEO);
- }
- if (default_created) {
- stats_->AddStream(default_remote_stream);
- observer_->OnAddStream(default_remote_stream);
- }
-}
-
-void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
- TrackInfos* current_tracks = GetRemoteTracks(media_type);
- for (TrackInfos::iterator track_it = current_tracks->begin();
- track_it != current_tracks->end(); ++track_it) {
- const TrackInfo& info = *track_it;
- MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
- if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
- // There's no guarantee the track is still available, e.g. the track may
- // have been removed from the stream by javascript.
- if (track) {
- track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
- }
- }
- if (media_type == cricket::MEDIA_TYPE_VIDEO) {
- VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
- // There's no guarantee the track is still available, e.g. the track may
- // have been removed from the stream by javascript.
- if (track) {
- track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
- }
- }
- }
-}
-
-void PeerConnection::UpdateLocalTracks(
- const std::vector<cricket::StreamParams>& streams,
- cricket::MediaType media_type) {
- TrackInfos* current_tracks = GetLocalTracks(media_type);
-
- // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
- // don't match the new StreamParam.
- TrackInfos::iterator track_it = current_tracks->begin();
- while (track_it != current_tracks->end()) {
- const TrackInfo& info = *track_it;
- const cricket::StreamParams* params =
- cricket::GetStreamBySsrc(streams, info.ssrc);
- if (!params || params->id != info.track_id ||
- params->sync_label != info.stream_label) {
- OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
- media_type);
- track_it = current_tracks->erase(track_it);
- } else {
- ++track_it;
- }
- }
-
- // Find new and active tracks.
- for (const cricket::StreamParams& params : streams) {
- // The sync_label is the MediaStream label and the |stream.id| is the
- // track id.
- const std::string& stream_label = params.sync_label;
- const std::string& track_id = params.id;
- uint32_t ssrc = params.first_ssrc();
- const TrackInfo* track_info =
- FindTrackInfo(*current_tracks, stream_label, track_id);
- if (!track_info) {
- current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
- OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
- }
- }
-}
-
-void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
- const std::string& track_id,
- uint32_t ssrc,
- cricket::MediaType media_type) {
- MediaStreamInterface* stream = local_streams_->find(stream_label);
- if (!stream) {
- LOG(LS_WARNING) << "An unknown local MediaStream with label "
- << stream_label << " has been configured.";
- return;
- }
-
- if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
- if (!audio_track) {
- LOG(LS_WARNING) << "An unknown local AudioTrack with id , " << track_id
- << " has been configured.";
- return;
- }
- CreateAudioSender(stream, audio_track, ssrc);
- } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
- VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
- if (!video_track) {
- LOG(LS_WARNING) << "An unknown local VideoTrack with id , " << track_id
- << " has been configured.";
- return;
- }
- CreateVideoSender(stream, video_track, ssrc);
- } else {
- RTC_DCHECK(false && "Invalid media type");
- }
-}
-
-void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
- const std::string& track_id,
- uint32_t ssrc,
- cricket::MediaType media_type) {
- MediaStreamInterface* stream = local_streams_->find(stream_label);
- if (!stream) {
- // This is the normal case. I.e., RemoveLocalStream has been called and the
- // SessionDescriptions has been renegotiated.
- return;
- }
- // A track has been removed from the SessionDescription but the MediaStream
- // is still associated with PeerConnection. This only occurs if the SDP
- // doesn't match with the calls to AddLocalStream and RemoveLocalStream.
- if (media_type == cricket::MEDIA_TYPE_AUDIO) {
- AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
- if (!audio_track) {
- return;
- }
- DestroyAudioSender(stream, audio_track, ssrc);
- } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
- VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
- if (!video_track) {
- return;
- }
- DestroyVideoSender(stream, video_track);
- } else {
- RTC_DCHECK(false && "Invalid media type.");
- }
-}
-
-void PeerConnection::UpdateLocalRtpDataChannels(
- const cricket::StreamParamsVec& streams) {
- std::vector<std::string> existing_channels;
-
- // Find new and active data channels.
- for (const cricket::StreamParams& params : streams) {
- // |it->sync_label| is actually the data channel label. The reason is that
- // we use the same naming of data channels as we do for
- // MediaStreams and Tracks.
- // For MediaStreams, the sync_label is the MediaStream label and the
- // track label is the same as |streamid|.
- const std::string& channel_label = params.sync_label;
- auto data_channel_it = rtp_data_channels_.find(channel_label);
- if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
- continue;
- }
- // Set the SSRC the data channel should use for sending.
- data_channel_it->second->SetSendSsrc(params.first_ssrc());
- existing_channels.push_back(data_channel_it->first);
- }
-
- UpdateClosingRtpDataChannels(existing_channels, true);
-}
-
-void PeerConnection::UpdateRemoteRtpDataChannels(
- const cricket::StreamParamsVec& streams) {
- std::vector<std::string> existing_channels;
-
- // Find new and active data channels.
- for (const cricket::StreamParams& params : streams) {
- // The data channel label is either the mslabel or the SSRC if the mslabel
- // does not exist. Ex a=ssrc:444330170 mslabel:test1.
- std::string label = params.sync_label.empty()
- ? rtc::ToString(params.first_ssrc())
- : params.sync_label;
- auto data_channel_it = rtp_data_channels_.find(label);
- if (data_channel_it == rtp_data_channels_.end()) {
- // This is a new data channel.
- CreateRemoteRtpDataChannel(label, params.first_ssrc());
- } else {
- data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
- }
- existing_channels.push_back(label);
- }
-
- UpdateClosingRtpDataChannels(existing_channels, false);
-}
-
-void PeerConnection::UpdateClosingRtpDataChannels(
- const std::vector<std::string>& active_channels,
- bool is_local_update) {
- auto it = rtp_data_channels_.begin();
- while (it != rtp_data_channels_.end()) {
- DataChannel* data_channel = it->second;
- if (std::find(active_channels.begin(), active_channels.end(),
- data_channel->label()) != active_channels.end()) {
- ++it;
- continue;
- }
-
- if (is_local_update) {
- data_channel->SetSendSsrc(0);
- } else {
- data_channel->RemotePeerRequestClose();
- }
-
- if (data_channel->state() == DataChannel::kClosed) {
- rtp_data_channels_.erase(it);
- it = rtp_data_channels_.begin();
- } else {
- ++it;
- }
- }
-}
-
-void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
- uint32_t remote_ssrc) {
- rtc::scoped_refptr<DataChannel> channel(
- InternalCreateDataChannel(label, nullptr));
- if (!channel.get()) {
- LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
- << "CreateDataChannel failed.";
- return;
- }
- channel->SetReceiveSsrc(remote_ssrc);
- observer_->OnDataChannel(
- DataChannelProxy::Create(signaling_thread(), channel));
-}
-
-rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
- const std::string& label,
- const InternalDataChannelInit* config) {
- if (IsClosed()) {
- return nullptr;
- }
- if (session_->data_channel_type() == cricket::DCT_NONE) {
- LOG(LS_ERROR)
- << "InternalCreateDataChannel: Data is not supported in this call.";
- return nullptr;
- }
- InternalDataChannelInit new_config =
- config ? (*config) : InternalDataChannelInit();
- if (session_->data_channel_type() == cricket::DCT_SCTP) {
- if (new_config.id < 0) {
- rtc::SSLRole role;
- if (session_->GetSslRole(&role) &&
- !sid_allocator_.AllocateSid(role, &new_config.id)) {
- LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
- return nullptr;
- }
- } else if (!sid_allocator_.ReserveSid(new_config.id)) {
- LOG(LS_ERROR) << "Failed to create a SCTP data channel "
- << "because the id is already in use or out of range.";
- return nullptr;
- }
- }
-
- rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
- session_.get(), session_->data_channel_type(), label, new_config));
- if (!channel) {
- sid_allocator_.ReleaseSid(new_config.id);
- return nullptr;
- }
-
- if (channel->data_channel_type() == cricket::DCT_RTP) {
- if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
- LOG(LS_ERROR) << "DataChannel with label " << channel->label()
- << " already exists.";
- return nullptr;
- }
- rtp_data_channels_[channel->label()] = channel;
- } else {
- RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
- sctp_data_channels_.push_back(channel);
- channel->SignalClosed.connect(this,
- &PeerConnection::OnSctpDataChannelClosed);
- }
-
- return channel;
-}
-
-bool PeerConnection::HasDataChannels() const {
- return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
-}
-
-void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
- for (const auto& channel : sctp_data_channels_) {
- if (channel->id() < 0) {
- int sid;
- if (!sid_allocator_.AllocateSid(role, &sid)) {
- LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
- continue;
- }
- channel->SetSctpSid(sid);
- }
- }
-}
-
-void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
- for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
- ++it) {
- if (it->get() == channel) {
- int sid = channel->id();
- RTC_DCHECK(sid >= 0);
- sid_allocator_.ReleaseSid(sid);
- sctp_data_channels_.erase(it);
- return;
- }
- }
-}
-
-void PeerConnection::OnVoiceChannelDestroyed() {
- EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
-}
-
-void PeerConnection::OnVideoChannelDestroyed() {
- EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
-}
-
-void PeerConnection::OnDataChannelCreated() {
- for (const auto& channel : sctp_data_channels_) {
- channel->OnTransportChannelCreated();
- }
-}
-
-void PeerConnection::OnDataChannelDestroyed() {
- // Use a temporary copy of the RTP/SCTP DataChannel list because the
- // DataChannel may callback to us and try to modify the list.
- std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
- temp_rtp_dcs.swap(rtp_data_channels_);
- for (const auto& kv : temp_rtp_dcs) {
- kv.second->OnTransportChannelDestroyed();
- }
-
- std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
- temp_sctp_dcs.swap(sctp_data_channels_);
- for (const auto& channel : temp_sctp_dcs) {
- channel->OnTransportChannelDestroyed();
- }
-}
-
-void PeerConnection::OnDataChannelOpenMessage(
- const std::string& label,
- const InternalDataChannelInit& config) {
- rtc::scoped_refptr<DataChannel> channel(
- InternalCreateDataChannel(label, &config));
- if (!channel.get()) {
- LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
- return;
- }
-
- observer_->OnDataChannel(
- DataChannelProxy::Create(signaling_thread(), channel));
-}
-
std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
return std::find_if(
@@ -1918,42 +1016,4 @@
});
}
-PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
- 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_tracks_
- : &remote_video_tracks_;
-}
-
-PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
- 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_tracks_
- : &local_video_tracks_;
-}
-
-const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
- const PeerConnection::TrackInfos& infos,
- const std::string& stream_label,
- const std::string track_id) const {
- for (const TrackInfo& track_info : infos) {
- if (track_info.stream_label == stream_label &&
- track_info.track_id == track_id) {
- return &track_info;
- }
- }
- return nullptr;
-}
-
-DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
- for (const auto& channel : sctp_data_channels_) {
- if (channel->id() == sid) {
- return channel;
- }
- }
- return nullptr;
-}
-
} // namespace webrtc
diff --git a/talk/app/webrtc/peerconnection.h b/talk/app/webrtc/peerconnection.h
index 0c04898..3d6ce1b 100644
--- a/talk/app/webrtc/peerconnection.h
+++ b/talk/app/webrtc/peerconnection.h
@@ -31,6 +31,7 @@
#include <string>
#include "talk/app/webrtc/dtlsidentitystore.h"
+#include "talk/app/webrtc/mediastreamsignaling.h"
#include "talk/app/webrtc/peerconnectionfactory.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/app/webrtc/rtpreceiverinterface.h"
@@ -42,26 +43,11 @@
namespace webrtc {
-class RemoteMediaStreamFactory;
-
typedef std::vector<PortAllocatorFactoryInterface::StunConfiguration>
StunConfigurations;
typedef std::vector<PortAllocatorFactoryInterface::TurnConfiguration>
TurnConfigurations;
-// Populates |session_options| from |rtc_options|, and returns true if options
-// are valid.
-// Send streams should already be added to |session_options| before this method
-// is called, as this affects the values of recv_audio and recv_video.
-bool ConvertRtcOptionsForOffer(
- const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
- cricket::MediaSessionOptions* session_options);
-
-// Populates |session_options| from |constraints|, and returns true if all
-// mandatory constraints are satisfied.
-bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
- cricket::MediaSessionOptions* session_options);
-
// Parses the URLs for each server in |servers| to build |stun_config| and
// |turn_config|.
bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
@@ -69,8 +55,10 @@
TurnConfigurations* turn_config);
// PeerConnection implements the PeerConnectionInterface interface.
-// It uses WebRtcSession to implement the PeerConnection functionality.
+// It uses MediaStreamSignaling and WebRtcSession to implement
+// the PeerConnection functionality.
class PeerConnection : public PeerConnectionInterface,
+ public MediaStreamSignalingObserver,
public IceObserver,
public rtc::MessageHandler,
public sigslot::has_slots<> {
@@ -88,8 +76,6 @@
bool AddStream(MediaStreamInterface* local_stream) override;
void RemoveStream(MediaStreamInterface* local_stream) override;
- virtual WebRtcSession* session() { return session_.get(); }
-
rtc::scoped_refptr<DtmfSenderInterface> CreateDtmfSender(
AudioTrackInterface* track) override;
@@ -134,72 +120,39 @@
void Close() override;
- // Virtual for unit tests.
- virtual const std::vector<rtc::scoped_refptr<DataChannel>>&
- sctp_data_channels() const {
- return sctp_data_channels_;
- };
-
protected:
~PeerConnection() override;
private:
- struct TrackInfo {
- TrackInfo() : ssrc(0) {}
- TrackInfo(const std::string& stream_label,
- const std::string track_id,
- uint32_t ssrc)
- : stream_label(stream_label), track_id(track_id), ssrc(ssrc) {}
- std::string stream_label;
- std::string track_id;
- uint32_t ssrc;
- };
- typedef std::vector<TrackInfo> TrackInfos;
-
- struct RemotePeerInfo {
- RemotePeerInfo()
- : msid_supported(false),
- default_audio_track_needed(false),
- default_video_track_needed(false) {}
- // True if it has been discovered that the remote peer support MSID.
- bool msid_supported;
- // The remote peer indicates in the session description that audio will be
- // sent but no MSID is given.
- bool default_audio_track_needed;
- // The remote peer indicates in the session description that video will be
- // sent but no MSID is given.
- bool default_video_track_needed;
-
- bool IsDefaultMediaStreamNeeded() {
- return !msid_supported &&
- (default_audio_track_needed || default_video_track_needed);
- }
- };
-
// Implements MessageHandler.
void OnMessage(rtc::Message* msg) override;
- void CreateAudioReceiver(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track,
- uint32_t ssrc);
- void CreateVideoReceiver(MediaStreamInterface* stream,
- VideoTrackInterface* video_track,
- uint32_t ssrc);
- void DestroyAudioReceiver(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track);
- void DestroyVideoReceiver(MediaStreamInterface* stream,
- VideoTrackInterface* video_track);
- void CreateAudioSender(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track,
- uint32_t ssrc);
- void CreateVideoSender(MediaStreamInterface* stream,
- VideoTrackInterface* video_track,
- uint32_t ssrc);
- void DestroyAudioSender(MediaStreamInterface* stream,
- AudioTrackInterface* audio_track,
- uint32_t ssrc);
- void DestroyVideoSender(MediaStreamInterface* stream,
- VideoTrackInterface* video_track);
+ // Implements MediaStreamSignalingObserver.
+ void OnAddRemoteStream(MediaStreamInterface* stream) override;
+ void OnRemoveRemoteStream(MediaStreamInterface* stream) override;
+ void OnAddDataChannel(DataChannelInterface* data_channel) override;
+ void OnAddRemoteAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) override;
+ void OnAddRemoteVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) override;
+ void OnRemoveRemoteAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track) override;
+ void OnRemoveRemoteVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) override;
+ void OnAddLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) override;
+ void OnAddLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track,
+ uint32_t ssrc) override;
+ void OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
+ AudioTrackInterface* audio_track,
+ uint32_t ssrc) override;
+ void OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
+ VideoTrackInterface* video_track) override;
+ void OnRemoveLocalStream(MediaStreamInterface* stream) override;
// Implements IceObserver
void OnIceConnectionChange(IceConnectionState new_state) override;
@@ -219,138 +172,21 @@
void PostSetSessionDescriptionFailure(SetSessionDescriptionObserver* observer,
const std::string& error);
- void PostCreateSessionDescriptionFailure(
- CreateSessionDescriptionObserver* observer,
- const std::string& error);
bool IsClosed() const {
return signaling_state_ == PeerConnectionInterface::kClosed;
}
- // Returns a MediaSessionOptions struct with options decided by |options|,
- // the local MediaStreams and DataChannels.
- virtual bool GetOptionsForOffer(
- const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
- cricket::MediaSessionOptions* session_options);
-
- // Returns a MediaSessionOptions struct with options decided by
- // |constraints|, the local MediaStreams and DataChannels.
- virtual bool GetOptionsForAnswer(
- const MediaConstraintsInterface* constraints,
- cricket::MediaSessionOptions* session_options);
-
- // 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.
- // If a new MediaStream is created it is added to |new_streams|.
- void UpdateRemoteStreamsList(
- const std::vector<cricket::StreamParams>& streams,
- cricket::MediaType media_type,
- StreamCollection* new_streams);
-
- // Triggered when a remote track has been seen for the first time in a remote
- // session description. It creates a remote MediaStreamTrackInterface
- // implementation and triggers CreateAudioReceiver or CreateVideoReceiver.
- void OnRemoteTrackSeen(const std::string& stream_label,
- const std::string& track_id,
- uint32_t ssrc,
- cricket::MediaType media_type);
-
- // Triggered when a remote track has been removed from a remote session
- // description. It removes the remote track with id |track_id| from a remote
- // MediaStream and triggers DestroyAudioReceiver or DestroyVideoReceiver.
- void OnRemoteTrackRemoved(const std::string& stream_label,
- const std::string& track_id,
- cricket::MediaType media_type);
-
- // Finds remote MediaStreams without any tracks and removes them from
- // |remote_streams_| and notifies the observer that the MediaStreams no longer
- // exist.
- void UpdateEndedRemoteMediaStreams();
-
- void MaybeCreateDefaultStream();
-
- // Set the MediaStreamTrackInterface::TrackState to |kEnded| on all remote
- // tracks of type |media_type|.
- void EndRemoteTracks(cricket::MediaType media_type);
-
- // Loops through the vector of |streams| and finds added and removed
- // StreamParams since last time this method was called.
- // For each new or removed StreamParam, OnLocalTrackSeen or
- // OnLocalTrackRemoved is invoked.
- void UpdateLocalTracks(const std::vector<cricket::StreamParams>& streams,
- cricket::MediaType media_type);
-
- // Triggered when a local track 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 OnLocalTrackSeen(const std::string& stream_label,
- const std::string& track_id,
- uint32_t ssrc,
- cricket::MediaType media_type);
-
- // Triggered when a local track 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 OnLocalTrackRemoved(const std::string& stream_label,
- const std::string& track_id,
- uint32_t ssrc,
- cricket::MediaType media_type);
-
- void UpdateLocalRtpDataChannels(const cricket::StreamParamsVec& streams);
- void UpdateRemoteRtpDataChannels(const cricket::StreamParamsVec& streams);
- void UpdateClosingRtpDataChannels(
- const std::vector<std::string>& active_channels,
- bool is_local_update);
- void CreateRemoteRtpDataChannel(const std::string& label,
- uint32_t remote_ssrc);
-
- // Creates channel and adds it to the collection of DataChannels that will
- // be offered in a SessionDescription.
- rtc::scoped_refptr<DataChannel> InternalCreateDataChannel(
- const std::string& label,
- const InternalDataChannelInit* config);
-
- // Checks if any data channel has been added.
- bool HasDataChannels() const;
-
- void AllocateSctpSids(rtc::SSLRole role);
- void OnSctpDataChannelClosed(DataChannel* channel);
-
- // Notifications from WebRtcSession relating to BaseChannels.
- void OnVoiceChannelDestroyed();
- void OnVideoChannelDestroyed();
- void OnDataChannelCreated();
- void OnDataChannelDestroyed();
- // Called when the cricket::DataChannel receives a message indicating that a
- // webrtc::DataChannel should be opened.
- void OnDataChannelOpenMessage(const std::string& label,
- const InternalDataChannelInit& config);
-
std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
FindSenderForTrack(MediaStreamTrackInterface* track);
std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
FindReceiverForTrack(MediaStreamTrackInterface* track);
- TrackInfos* GetRemoteTracks(cricket::MediaType media_type);
- TrackInfos* GetLocalTracks(cricket::MediaType media_type);
- const TrackInfo* FindTrackInfo(const TrackInfos& infos,
- const std::string& stream_label,
- const std::string track_id) const;
-
- // Returns the specified SCTP DataChannel in sctp_data_channels_,
- // or nullptr if not found.
- DataChannel* FindDataChannelBySid(int sid) const;
-
// Storing the factory as a scoped reference pointer ensures that the memory
// in the PeerConnectionFactoryImpl remains available as long as the
// PeerConnection is running. It is passed to PeerConnection as a raw pointer.
// However, since the reference counting is done in the
- // PeerConnectionFactoryInterface all instances created using the raw pointer
+ // PeerConnectionFactoryInteface all instances created using the raw pointer
// will refer to the same reference count.
rtc::scoped_refptr<PeerConnectionFactory> factory_;
PeerConnectionObserver* observer_;
@@ -362,35 +198,12 @@
IceGatheringState ice_gathering_state_;
rtc::scoped_ptr<cricket::PortAllocator> port_allocator_;
-
- // Streams added via AddStream.
- rtc::scoped_refptr<StreamCollection> local_streams_;
- // Streams created as a result of SetRemoteDescription.
- rtc::scoped_refptr<StreamCollection> remote_streams_;
-
- // These lists store track info seen in local/remote descriptions.
- TrackInfos remote_audio_tracks_;
- TrackInfos remote_video_tracks_;
- TrackInfos local_audio_tracks_;
- TrackInfos local_video_tracks_;
-
- SctpSidAllocator sid_allocator_;
- // label -> DataChannel
- std::map<std::string, rtc::scoped_refptr<DataChannel>> rtp_data_channels_;
- std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_;
-
- RemotePeerInfo remote_info_;
- rtc::scoped_ptr<RemoteMediaStreamFactory> remote_stream_factory_;
+ rtc::scoped_ptr<WebRtcSession> session_;
+ rtc::scoped_ptr<MediaStreamSignaling> mediastream_signaling_;
+ rtc::scoped_ptr<StatsCollector> stats_;
std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders_;
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers_;
-
- // The session_ scoped_ptr is declared at the bottom of PeerConnection
- // because its destruction fires signals (such as VoiceChannelDestroyed)
- // which will trigger some final actions in PeerConnection...
- rtc::scoped_ptr<WebRtcSession> session_;
- // ... But stats_ depends on session_ so it should be destroyed even earlier.
- rtc::scoped_ptr<StatsCollector> stats_;
};
} // namespace webrtc
diff --git a/talk/app/webrtc/peerconnectionendtoend_unittest.cc b/talk/app/webrtc/peerconnectionendtoend_unittest.cc
index eacedd4..ceabf04 100644
--- a/talk/app/webrtc/peerconnectionendtoend_unittest.cc
+++ b/talk/app/webrtc/peerconnectionendtoend_unittest.cc
@@ -364,35 +364,3 @@
EXPECT_EQ(1U, dc_1_observer->received_message_count());
EXPECT_EQ(1U, dc_2_observer->received_message_count());
}
-
-// Verifies that a DataChannel added from an OPEN message functions after
-// a channel has been previously closed (webrtc issue 3778).
-// This previously failed because the new channel re-uses the ID of the closed
-// channel, and the closed channel was incorrectly still assigned to the id.
-// TODO(deadbeef): This is disabled because there's currently a race condition
-// caused by the fact that a data channel signals that it's closed before it
-// really is. Re-enable this test once that's fixed.
-TEST_F(PeerConnectionEndToEndTest,
- DISABLED_DataChannelFromOpenWorksAfterClose) {
- MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
-
- CreatePcs();
-
- webrtc::DataChannelInit init;
- rtc::scoped_refptr<DataChannelInterface> caller_dc(
- caller_->CreateDataChannel("data", init));
-
- Negotiate();
- WaitForConnection();
-
- WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 0);
- CloseDataChannels(caller_dc, callee_signaled_data_channels_, 0);
-
- // Create a new channel and ensure it works after closing the previous one.
- caller_dc = caller_->CreateDataChannel("data2", init);
-
- WaitForDataChannelsToOpen(caller_dc, callee_signaled_data_channels_, 1);
- TestDataChannelSendAndReceive(caller_dc, callee_signaled_data_channels_[1]);
-
- CloseDataChannels(caller_dc, callee_signaled_data_channels_, 1);
-}
diff --git a/talk/app/webrtc/peerconnectionfactory.cc b/talk/app/webrtc/peerconnectionfactory.cc
index 0887754..c329446 100644
--- a/talk/app/webrtc/peerconnectionfactory.cc
+++ b/talk/app/webrtc/peerconnectionfactory.cc
@@ -29,7 +29,6 @@
#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/localaudiosource.h"
-#include "talk/app/webrtc/mediastream.h"
#include "talk/app/webrtc/mediastreamproxy.h"
#include "talk/app/webrtc/mediastreamtrackproxy.h"
#include "talk/app/webrtc/peerconnection.h"
diff --git a/talk/app/webrtc/peerconnectioninterface_unittest.cc b/talk/app/webrtc/peerconnectioninterface_unittest.cc
index 5e88658..8b7c9cf 100644
--- a/talk/app/webrtc/peerconnectioninterface_unittest.cc
+++ b/talk/app/webrtc/peerconnectioninterface_unittest.cc
@@ -27,22 +27,15 @@
#include <string>
-#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/fakeportallocatorfactory.h"
#include "talk/app/webrtc/jsepsessiondescription.h"
-#include "talk/app/webrtc/mediastream.h"
#include "talk/app/webrtc/mediastreaminterface.h"
-#include "talk/app/webrtc/peerconnection.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
-#include "talk/app/webrtc/rtpreceiverinterface.h"
-#include "talk/app/webrtc/rtpsenderinterface.h"
-#include "talk/app/webrtc/streamcollection.h"
#include "talk/app/webrtc/test/fakeconstraints.h"
#include "talk/app/webrtc/test/fakedtlsidentitystore.h"
#include "talk/app/webrtc/test/mockpeerconnectionobservers.h"
#include "talk/app/webrtc/test/testsdpstrings.h"
#include "talk/app/webrtc/videosource.h"
-#include "talk/app/webrtc/videotrack.h"
#include "talk/media/base/fakevideocapturer.h"
#include "talk/media/sctp/sctpdataengine.h"
#include "talk/session/media/mediasession.h"
@@ -67,167 +60,6 @@
static const char kTurnHostname[] = "turn.example.org";
static const uint32_t kTimeout = 10000U;
-static const char kStreams[][8] = {"stream1", "stream2"};
-static const char kAudioTracks[][32] = {"audiotrack0", "audiotrack1"};
-static const char kVideoTracks[][32] = {"videotrack0", "videotrack1"};
-
-// Reference SDP with a MediaStream with label "stream1" and audio track with
-// id "audio_1" and a video track with id "video_1;
-static const char kSdpStringWithStream1[] =
- "v=0\r\n"
- "o=- 0 0 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=ice-ufrag:e5785931\r\n"
- "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
- "a=fingerprint:sha-256 58:AB:6E:F5:F1:E4:57:B7:E9:46:F4:86:04:28:F9:A7:ED:"
- "BD:AB:AE:40:EF:CE:9A:51:2C:2A:B1:9B:8B:78:84\r\n"
- "m=audio 1 RTP/AVPF 103\r\n"
- "a=mid:audio\r\n"
- "a=rtpmap:103 ISAC/16000\r\n"
- "a=ssrc:1 cname:stream1\r\n"
- "a=ssrc:1 mslabel:stream1\r\n"
- "a=ssrc:1 label:audiotrack0\r\n"
- "m=video 1 RTP/AVPF 120\r\n"
- "a=mid:video\r\n"
- "a=rtpmap:120 VP8/90000\r\n"
- "a=ssrc:2 cname:stream1\r\n"
- "a=ssrc:2 mslabel:stream1\r\n"
- "a=ssrc:2 label:videotrack0\r\n";
-
-// Reference SDP with two MediaStreams with label "stream1" and "stream2. Each
-// MediaStreams have one audio track and one video track.
-// This uses MSID.
-static const char kSdpStringWithStream1And2[] =
- "v=0\r\n"
- "o=- 0 0 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=ice-ufrag:e5785931\r\n"
- "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
- "a=fingerprint:sha-256 58:AB:6E:F5:F1:E4:57:B7:E9:46:F4:86:04:28:F9:A7:ED:"
- "BD:AB:AE:40:EF:CE:9A:51:2C:2A:B1:9B:8B:78:84\r\n"
- "a=msid-semantic: WMS stream1 stream2\r\n"
- "m=audio 1 RTP/AVPF 103\r\n"
- "a=mid:audio\r\n"
- "a=rtpmap:103 ISAC/16000\r\n"
- "a=ssrc:1 cname:stream1\r\n"
- "a=ssrc:1 msid:stream1 audiotrack0\r\n"
- "a=ssrc:3 cname:stream2\r\n"
- "a=ssrc:3 msid:stream2 audiotrack1\r\n"
- "m=video 1 RTP/AVPF 120\r\n"
- "a=mid:video\r\n"
- "a=rtpmap:120 VP8/0\r\n"
- "a=ssrc:2 cname:stream1\r\n"
- "a=ssrc:2 msid:stream1 videotrack0\r\n"
- "a=ssrc:4 cname:stream2\r\n"
- "a=ssrc:4 msid:stream2 videotrack1\r\n";
-
-// Reference SDP without MediaStreams. Msid is not supported.
-static const char kSdpStringWithoutStreams[] =
- "v=0\r\n"
- "o=- 0 0 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=ice-ufrag:e5785931\r\n"
- "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
- "a=fingerprint:sha-256 58:AB:6E:F5:F1:E4:57:B7:E9:46:F4:86:04:28:F9:A7:ED:"
- "BD:AB:AE:40:EF:CE:9A:51:2C:2A:B1:9B:8B:78:84\r\n"
- "m=audio 1 RTP/AVPF 103\r\n"
- "a=mid:audio\r\n"
- "a=rtpmap:103 ISAC/16000\r\n"
- "m=video 1 RTP/AVPF 120\r\n"
- "a=mid:video\r\n"
- "a=rtpmap:120 VP8/90000\r\n";
-
-// Reference SDP without MediaStreams. Msid is supported.
-static const char kSdpStringWithMsidWithoutStreams[] =
- "v=0\r\n"
- "o=- 0 0 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=ice-ufrag:e5785931\r\n"
- "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
- "a=fingerprint:sha-256 58:AB:6E:F5:F1:E4:57:B7:E9:46:F4:86:04:28:F9:A7:ED:"
- "BD:AB:AE:40:EF:CE:9A:51:2C:2A:B1:9B:8B:78:84\r\n"
- "a=msid-semantic: WMS\r\n"
- "m=audio 1 RTP/AVPF 103\r\n"
- "a=mid:audio\r\n"
- "a=rtpmap:103 ISAC/16000\r\n"
- "m=video 1 RTP/AVPF 120\r\n"
- "a=mid:video\r\n"
- "a=rtpmap:120 VP8/90000\r\n";
-
-// Reference SDP without MediaStreams and audio only.
-static const char kSdpStringWithoutStreamsAudioOnly[] =
- "v=0\r\n"
- "o=- 0 0 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=ice-ufrag:e5785931\r\n"
- "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
- "a=fingerprint:sha-256 58:AB:6E:F5:F1:E4:57:B7:E9:46:F4:86:04:28:F9:A7:ED:"
- "BD:AB:AE:40:EF:CE:9A:51:2C:2A:B1:9B:8B:78:84\r\n"
- "m=audio 1 RTP/AVPF 103\r\n"
- "a=mid:audio\r\n"
- "a=rtpmap:103 ISAC/16000\r\n";
-
-// Reference SENDONLY SDP without MediaStreams. Msid is not supported.
-static const char kSdpStringSendOnlyWithoutStreams[] =
- "v=0\r\n"
- "o=- 0 0 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=ice-ufrag:e5785931\r\n"
- "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
- "a=fingerprint:sha-256 58:AB:6E:F5:F1:E4:57:B7:E9:46:F4:86:04:28:F9:A7:ED:"
- "BD:AB:AE:40:EF:CE:9A:51:2C:2A:B1:9B:8B:78:84\r\n"
- "m=audio 1 RTP/AVPF 103\r\n"
- "a=mid:audio\r\n"
- "a=sendonly\r\n"
- "a=rtpmap:103 ISAC/16000\r\n"
- "m=video 1 RTP/AVPF 120\r\n"
- "a=mid:video\r\n"
- "a=sendonly\r\n"
- "a=rtpmap:120 VP8/90000\r\n";
-
-static const char kSdpStringInit[] =
- "v=0\r\n"
- "o=- 0 0 IN IP4 127.0.0.1\r\n"
- "s=-\r\n"
- "t=0 0\r\n"
- "a=ice-ufrag:e5785931\r\n"
- "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
- "a=fingerprint:sha-256 58:AB:6E:F5:F1:E4:57:B7:E9:46:F4:86:04:28:F9:A7:ED:"
- "BD:AB:AE:40:EF:CE:9A:51:2C:2A:B1:9B:8B:78:84\r\n"
- "a=msid-semantic: WMS\r\n";
-
-static const char kSdpStringAudio[] =
- "m=audio 1 RTP/AVPF 103\r\n"
- "a=mid:audio\r\n"
- "a=rtpmap:103 ISAC/16000\r\n";
-
-static const char kSdpStringVideo[] =
- "m=video 1 RTP/AVPF 120\r\n"
- "a=mid:video\r\n"
- "a=rtpmap:120 VP8/90000\r\n";
-
-static const char kSdpStringMs1Audio0[] =
- "a=ssrc:1 cname:stream1\r\n"
- "a=ssrc:1 msid:stream1 audiotrack0\r\n";
-
-static const char kSdpStringMs1Video0[] =
- "a=ssrc:2 cname:stream1\r\n"
- "a=ssrc:2 msid:stream1 videotrack0\r\n";
-
-static const char kSdpStringMs1Audio1[] =
- "a=ssrc:3 cname:stream1\r\n"
- "a=ssrc:3 msid:stream1 audiotrack1\r\n";
-
-static const char kSdpStringMs1Video1[] =
- "a=ssrc:4 cname:stream1\r\n"
- "a=ssrc:4 msid:stream1 videotrack1\r\n";
-
#define MAYBE_SKIP_TEST(feature) \
if (!(feature())) { \
LOG(LS_INFO) << "Feature disabled... skipping"; \
@@ -237,14 +69,12 @@
using rtc::scoped_ptr;
using rtc::scoped_refptr;
using webrtc::AudioSourceInterface;
-using webrtc::AudioTrack;
using webrtc::AudioTrackInterface;
using webrtc::DataBuffer;
using webrtc::DataChannelInterface;
using webrtc::FakeConstraints;
using webrtc::FakePortAllocatorFactory;
using webrtc::IceCandidateInterface;
-using webrtc::MediaStream;
using webrtc::MediaStreamInterface;
using webrtc::MediaStreamTrackInterface;
using webrtc::MockCreateSessionDescriptionObserver;
@@ -254,18 +84,11 @@
using webrtc::PeerConnectionInterface;
using webrtc::PeerConnectionObserver;
using webrtc::PortAllocatorFactoryInterface;
-using webrtc::RtpReceiverInterface;
-using webrtc::RtpSenderInterface;
using webrtc::SdpParseError;
using webrtc::SessionDescriptionInterface;
-using webrtc::StreamCollection;
-using webrtc::StreamCollectionInterface;
using webrtc::VideoSourceInterface;
-using webrtc::VideoTrack;
using webrtc::VideoTrackInterface;
-typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
-
namespace {
// Gets the first ssrc of given content type from the ContentInfo.
@@ -295,97 +118,12 @@
}
}
-// Check if |streams| contains the specified track.
-bool ContainsTrack(const std::vector<cricket::StreamParams>& streams,
- const std::string& stream_label,
- const std::string& track_id) {
- for (const cricket::StreamParams& params : streams) {
- if (params.sync_label == stream_label && params.id == track_id) {
- return true;
- }
- }
- return false;
-}
-
-// Check if |senders| contains the specified sender, by id.
-bool ContainsSender(
- const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
- const std::string& id) {
- for (const auto& sender : senders) {
- if (sender->id() == id) {
- return true;
- }
- }
- return false;
-}
-
-// Create a collection of streams.
-// CreateStreamCollection(1) creates a collection that
-// correspond to kSdpStringWithStream1.
-// CreateStreamCollection(2) correspond to kSdpStringWithStream1And2.
-rtc::scoped_refptr<StreamCollection> CreateStreamCollection(
- int number_of_streams) {
- rtc::scoped_refptr<StreamCollection> local_collection(
- StreamCollection::Create());
-
- for (int i = 0; i < number_of_streams; ++i) {
- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream(
- webrtc::MediaStream::Create(kStreams[i]));
-
- // Add a local audio track.
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
- webrtc::AudioTrack::Create(kAudioTracks[i], nullptr));
- stream->AddTrack(audio_track);
-
- // Add a local video track.
- rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
- webrtc::VideoTrack::Create(kVideoTracks[i], nullptr));
- stream->AddTrack(video_track);
-
- local_collection->AddStream(stream);
- }
- return local_collection;
-}
-
-// Check equality of StreamCollections.
-bool CompareStreamCollections(StreamCollectionInterface* s1,
- StreamCollectionInterface* s2) {
- if (s1 == nullptr || s2 == nullptr || s1->count() != s2->count()) {
- return false;
- }
-
- for (size_t i = 0; i != s1->count(); ++i) {
- if (s1->at(i)->label() != s2->at(i)->label()) {
- return false;
- }
- webrtc::AudioTrackVector audio_tracks1 = s1->at(i)->GetAudioTracks();
- webrtc::AudioTrackVector audio_tracks2 = s2->at(i)->GetAudioTracks();
- webrtc::VideoTrackVector video_tracks1 = s1->at(i)->GetVideoTracks();
- webrtc::VideoTrackVector video_tracks2 = s2->at(i)->GetVideoTracks();
-
- if (audio_tracks1.size() != audio_tracks2.size()) {
- return false;
- }
- for (size_t j = 0; j != audio_tracks1.size(); ++j) {
- if (audio_tracks1[j]->id() != audio_tracks2[j]->id()) {
- return false;
- }
- }
- if (video_tracks1.size() != video_tracks2.size()) {
- return false;
- }
- for (size_t j = 0; j != video_tracks1.size(); ++j) {
- if (video_tracks1[j]->id() != video_tracks2[j]->id()) {
- return false;
- }
- }
- }
- return true;
-}
-
class MockPeerConnectionObserver : public PeerConnectionObserver {
public:
- MockPeerConnectionObserver() : remote_streams_(StreamCollection::Create()) {}
+ MockPeerConnectionObserver()
+ : renegotiation_needed_(false),
+ ice_complete_(false) {
+ }
~MockPeerConnectionObserver() {
}
void SetPeerConnectionInterface(PeerConnectionInterface* pc) {
@@ -419,18 +157,11 @@
break;
}
}
-
- MediaStreamInterface* RemoteStream(const std::string& label) {
- return remote_streams_->find(label);
- }
- StreamCollectionInterface* remote_streams() const { return remote_streams_; }
virtual void OnAddStream(MediaStreamInterface* stream) {
last_added_stream_ = stream;
- remote_streams_->AddStream(stream);
}
virtual void OnRemoveStream(MediaStreamInterface* stream) {
last_removed_stream_ = stream;
- remote_streams_->RemoveStream(stream);
}
virtual void OnRenegotiationNeeded() {
renegotiation_needed_ = true;
@@ -485,9 +216,8 @@
PeerConnectionInterface::SignalingState state_;
scoped_ptr<IceCandidateInterface> last_candidate_;
scoped_refptr<DataChannelInterface> last_datachannel_;
- rtc::scoped_refptr<StreamCollection> remote_streams_;
- bool renegotiation_needed_ = false;
- bool ice_complete_ = false;
+ bool renegotiation_needed_;
+ bool ice_complete_;
private:
scoped_refptr<MediaStreamInterface> last_added_stream_;
@@ -495,7 +225,6 @@
};
} // namespace
-
class PeerConnectionInterfaceTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -598,7 +327,7 @@
observer_.SetPeerConnectionInterface(NULL);
}
- void AddVideoStream(const std::string& label) {
+ void AddStream(const std::string& label) {
// Create a local stream.
scoped_refptr<MediaStreamInterface> stream(
pc_factory_->CreateLocalMediaStream(label));
@@ -731,14 +460,6 @@
EXPECT_EQ(PeerConnectionInterface::kHaveRemoteOffer, observer_.state_);
}
- void CreateAndSetRemoteOffer(const std::string& sdp) {
- SessionDescriptionInterface* remote_offer =
- webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
- sdp, nullptr);
- EXPECT_TRUE(DoSetRemoteDescription(remote_offer));
- EXPECT_EQ(PeerConnectionInterface::kHaveRemoteOffer, observer_.state_);
- }
-
void CreateAnswerAsLocalDescription() {
scoped_ptr<SessionDescriptionInterface> answer;
ASSERT_TRUE(DoCreateAnswer(answer.use()));
@@ -802,25 +523,25 @@
EXPECT_TRUE_WAIT(observer_.ice_complete_, kTimeout);
}
- void CreateAnswerAsRemoteDescription(const std::string& sdp) {
+ void CreateAnswerAsRemoteDescription(const std::string& offer) {
webrtc::JsepSessionDescription* answer = new webrtc::JsepSessionDescription(
SessionDescriptionInterface::kAnswer);
- EXPECT_TRUE(answer->Initialize(sdp, NULL));
+ EXPECT_TRUE(answer->Initialize(offer, NULL));
EXPECT_TRUE(DoSetRemoteDescription(answer));
EXPECT_EQ(PeerConnectionInterface::kStable, observer_.state_);
}
- void CreatePrAnswerAndAnswerAsRemoteDescription(const std::string& sdp) {
+ void CreatePrAnswerAndAnswerAsRemoteDescription(const std::string& offer) {
webrtc::JsepSessionDescription* pr_answer =
new webrtc::JsepSessionDescription(
SessionDescriptionInterface::kPrAnswer);
- EXPECT_TRUE(pr_answer->Initialize(sdp, NULL));
+ EXPECT_TRUE(pr_answer->Initialize(offer, NULL));
EXPECT_TRUE(DoSetRemoteDescription(pr_answer));
EXPECT_EQ(PeerConnectionInterface::kHaveRemotePrAnswer, observer_.state_);
webrtc::JsepSessionDescription* answer =
new webrtc::JsepSessionDescription(
SessionDescriptionInterface::kAnswer);
- EXPECT_TRUE(answer->Initialize(sdp, NULL));
+ EXPECT_TRUE(answer->Initialize(offer, NULL));
EXPECT_TRUE(DoSetRemoteDescription(answer));
EXPECT_EQ(PeerConnectionInterface::kStable, observer_.state_);
}
@@ -845,71 +566,10 @@
CreateAnswerAsRemoteDescription(sdp);
}
- // This function creates a MediaStream with label kStreams[0] and
- // |number_of_audio_tracks| and |number_of_video_tracks| tracks and the
- // corresponding SessionDescriptionInterface. The SessionDescriptionInterface
- // is returned in |desc| and the MediaStream is stored in
- // |reference_collection_|
- void CreateSessionDescriptionAndReference(
- size_t number_of_audio_tracks,
- size_t number_of_video_tracks,
- SessionDescriptionInterface** desc) {
- ASSERT_TRUE(desc != nullptr);
- ASSERT_LE(number_of_audio_tracks, 2u);
- ASSERT_LE(number_of_video_tracks, 2u);
-
- reference_collection_ = StreamCollection::Create();
- std::string sdp_ms1 = std::string(kSdpStringInit);
-
- std::string mediastream_label = kStreams[0];
-
- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream(
- webrtc::MediaStream::Create(mediastream_label));
- reference_collection_->AddStream(stream);
-
- if (number_of_audio_tracks > 0) {
- sdp_ms1 += std::string(kSdpStringAudio);
- sdp_ms1 += std::string(kSdpStringMs1Audio0);
- AddAudioTrack(kAudioTracks[0], stream);
- }
- if (number_of_audio_tracks > 1) {
- sdp_ms1 += kSdpStringMs1Audio1;
- AddAudioTrack(kAudioTracks[1], stream);
- }
-
- if (number_of_video_tracks > 0) {
- sdp_ms1 += std::string(kSdpStringVideo);
- sdp_ms1 += std::string(kSdpStringMs1Video0);
- AddVideoTrack(kVideoTracks[0], stream);
- }
- if (number_of_video_tracks > 1) {
- sdp_ms1 += kSdpStringMs1Video1;
- AddVideoTrack(kVideoTracks[1], stream);
- }
-
- *desc = webrtc::CreateSessionDescription(
- SessionDescriptionInterface::kOffer, sdp_ms1, nullptr);
- }
-
- void AddAudioTrack(const std::string& track_id,
- MediaStreamInterface* stream) {
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
- webrtc::AudioTrack::Create(track_id, nullptr));
- ASSERT_TRUE(stream->AddTrack(audio_track));
- }
-
- void AddVideoTrack(const std::string& track_id,
- MediaStreamInterface* stream) {
- rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
- webrtc::VideoTrack::Create(track_id, nullptr));
- ASSERT_TRUE(stream->AddTrack(video_track));
- }
-
scoped_refptr<FakePortAllocatorFactory> port_allocator_factory_;
scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_;
scoped_refptr<PeerConnectionInterface> pc_;
MockPeerConnectionObserver observer_;
- rtc::scoped_refptr<StreamCollection> reference_collection_;
};
TEST_F(PeerConnectionInterfaceTest,
@@ -919,7 +579,7 @@
TEST_F(PeerConnectionInterfaceTest, AddStreams) {
CreatePeerConnection();
- AddVideoStream(kStreamLabel1);
+ AddStream(kStreamLabel1);
AddVoiceStream(kStreamLabel2);
ASSERT_EQ(2u, pc_->local_streams()->count());
@@ -946,54 +606,9 @@
EXPECT_EQ(0u, pc_->local_streams()->count());
}
-// Test that the created offer includes streams we added.
-TEST_F(PeerConnectionInterfaceTest, AddedStreamsPresentInOffer) {
- CreatePeerConnection();
- AddAudioVideoStream(kStreamLabel1, "audio_track", "video_track");
- scoped_ptr<SessionDescriptionInterface> offer;
- ASSERT_TRUE(DoCreateOffer(offer.accept()));
-
- const cricket::ContentInfo* audio_content =
- cricket::GetFirstAudioContent(offer->description());
- const cricket::AudioContentDescription* audio_desc =
- static_cast<const cricket::AudioContentDescription*>(
- audio_content->description);
- EXPECT_TRUE(
- ContainsTrack(audio_desc->streams(), kStreamLabel1, "audio_track"));
-
- const cricket::ContentInfo* video_content =
- cricket::GetFirstVideoContent(offer->description());
- const cricket::VideoContentDescription* video_desc =
- static_cast<const cricket::VideoContentDescription*>(
- video_content->description);
- EXPECT_TRUE(
- ContainsTrack(video_desc->streams(), kStreamLabel1, "video_track"));
-
- // Add another stream and ensure the offer includes both the old and new
- // streams.
- AddAudioVideoStream(kStreamLabel2, "audio_track2", "video_track2");
- ASSERT_TRUE(DoCreateOffer(offer.accept()));
-
- audio_content = cricket::GetFirstAudioContent(offer->description());
- audio_desc = static_cast<const cricket::AudioContentDescription*>(
- audio_content->description);
- EXPECT_TRUE(
- ContainsTrack(audio_desc->streams(), kStreamLabel1, "audio_track"));
- EXPECT_TRUE(
- ContainsTrack(audio_desc->streams(), kStreamLabel2, "audio_track2"));
-
- video_content = cricket::GetFirstVideoContent(offer->description());
- video_desc = static_cast<const cricket::VideoContentDescription*>(
- video_content->description);
- EXPECT_TRUE(
- ContainsTrack(video_desc->streams(), kStreamLabel1, "video_track"));
- EXPECT_TRUE(
- ContainsTrack(video_desc->streams(), kStreamLabel2, "video_track2"));
-}
-
TEST_F(PeerConnectionInterfaceTest, RemoveStream) {
CreatePeerConnection();
- AddVideoStream(kStreamLabel1);
+ AddStream(kStreamLabel1);
ASSERT_EQ(1u, pc_->local_streams()->count());
pc_->RemoveStream(pc_->local_streams()->at(0));
EXPECT_EQ(0u, pc_->local_streams()->count());
@@ -1007,7 +622,7 @@
TEST_F(PeerConnectionInterfaceTest, CreateOfferReceivePrAnswerAndAnswer) {
CreatePeerConnection();
- AddVideoStream(kStreamLabel1);
+ AddStream(kStreamLabel1);
CreateOfferAsLocalDescription();
std::string offer;
EXPECT_TRUE(pc_->local_description()->ToString(&offer));
@@ -1017,7 +632,7 @@
TEST_F(PeerConnectionInterfaceTest, ReceiveOfferCreateAnswer) {
CreatePeerConnection();
- AddVideoStream(kStreamLabel1);
+ AddStream(kStreamLabel1);
CreateOfferAsRemoteDescription();
CreateAnswerAsLocalDescription();
@@ -1027,7 +642,7 @@
TEST_F(PeerConnectionInterfaceTest, ReceiveOfferCreatePrAnswerAndAnswer) {
CreatePeerConnection();
- AddVideoStream(kStreamLabel1);
+ AddStream(kStreamLabel1);
CreateOfferAsRemoteDescription();
CreatePrAnswerAsLocalDescription();
@@ -1042,7 +657,7 @@
pc_->RemoveStream(pc_->local_streams()->at(0));
CreateOfferReceiveAnswer();
EXPECT_EQ(0u, pc_->remote_streams()->count());
- AddVideoStream(kStreamLabel1);
+ AddStream(kStreamLabel1);
CreateOfferReceiveAnswer();
}
@@ -1067,7 +682,7 @@
EXPECT_FALSE(pc_->AddIceCandidate(observer_.last_candidate_.get()));
// SetRemoteDescription takes ownership of offer.
SessionDescriptionInterface* offer = NULL;
- AddVideoStream(kStreamLabel1);
+ AddStream(kStreamLabel1);
EXPECT_TRUE(DoCreateOffer(&offer));
EXPECT_TRUE(DoSetRemoteDescription(offer));
@@ -1082,7 +697,7 @@
EXPECT_TRUE(pc_->AddIceCandidate(observer_.last_candidate_.get()));
}
-// Test that CreateOffer and CreateAnswer will fail if the track labels are
+// Test that the CreateOffer and CreatAnswer will fail if the track labels are
// not unique.
TEST_F(PeerConnectionInterfaceTest, CreateOfferAnswerWithInvalidStream) {
CreatePeerConnection();
@@ -1332,22 +947,6 @@
EXPECT_TRUE(channel == NULL);
}
-// Verifies that duplicated label is not allowed for RTP data channel.
-TEST_F(PeerConnectionInterfaceTest, RtpDuplicatedLabelNotAllowed) {
- FakeConstraints constraints;
- constraints.SetAllowRtpDataChannels();
- CreatePeerConnection(&constraints);
-
- std::string label = "test";
- scoped_refptr<DataChannelInterface> channel =
- pc_->CreateDataChannel(label, nullptr);
- EXPECT_NE(channel, nullptr);
-
- scoped_refptr<DataChannelInterface> dup_channel =
- pc_->CreateDataChannel(label, nullptr);
- EXPECT_EQ(dup_channel, nullptr);
-}
-
// This tests that a SCTP data channel is returned using different
// DataChannelInit configurations.
TEST_F(PeerConnectionInterfaceTest, CreateSctpDataChannel) {
@@ -1432,23 +1031,6 @@
EXPECT_TRUE(channel == NULL);
}
-// Verifies that duplicated label is allowed for SCTP data channel.
-TEST_F(PeerConnectionInterfaceTest, SctpDuplicatedLabelAllowed) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
-
- std::string label = "test";
- scoped_refptr<DataChannelInterface> channel =
- pc_->CreateDataChannel(label, nullptr);
- EXPECT_NE(channel, nullptr);
-
- scoped_refptr<DataChannelInterface> dup_channel =
- pc_->CreateDataChannel(label, nullptr);
- EXPECT_NE(dup_channel, nullptr);
-}
-
// This test verifies that OnRenegotiationNeeded is fired for every new RTP
// DataChannel.
TEST_F(PeerConnectionInterfaceTest, RenegotiationNeededForNewRtpDataChannel) {
@@ -1652,567 +1234,3 @@
pc_->Close();
DoGetStats(NULL);
}
-
-// NOTE: The series of tests below come from what used to be
-// mediastreamsignaling_unittest.cc, and are mostly aimed at testing that
-// setting a remote or local description has the expected effects.
-
-// This test verifies that the remote MediaStreams corresponding to a received
-// SDP string is created. In this test the two separate MediaStreams are
-// signaled.
-TEST_F(PeerConnectionInterfaceTest, UpdateRemoteStreams) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringWithStream1);
-
- rtc::scoped_refptr<StreamCollection> reference(CreateStreamCollection(1));
- EXPECT_TRUE(
- CompareStreamCollections(observer_.remote_streams(), reference.get()));
- MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
- EXPECT_TRUE(remote_stream->GetVideoTracks()[0]->GetSource() != nullptr);
-
- // Create a session description based on another SDP with another
- // MediaStream.
- CreateAndSetRemoteOffer(kSdpStringWithStream1And2);
-
- rtc::scoped_refptr<StreamCollection> reference2(CreateStreamCollection(2));
- EXPECT_TRUE(
- CompareStreamCollections(observer_.remote_streams(), reference2.get()));
-}
-
-// This test verifies that when remote tracks are added/removed from SDP, the
-// created remote streams are updated appropriately.
-TEST_F(PeerConnectionInterfaceTest,
- AddRemoveTrackFromExistingRemoteMediaStream) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- rtc::scoped_ptr<SessionDescriptionInterface> desc_ms1;
- CreateSessionDescriptionAndReference(1, 1, desc_ms1.accept());
- EXPECT_TRUE(DoSetRemoteDescription(desc_ms1.release()));
- EXPECT_TRUE(CompareStreamCollections(observer_.remote_streams(),
- reference_collection_));
-
- // Add extra audio and video tracks to the same MediaStream.
- rtc::scoped_ptr<SessionDescriptionInterface> desc_ms1_two_tracks;
- CreateSessionDescriptionAndReference(2, 2, desc_ms1_two_tracks.accept());
- EXPECT_TRUE(DoSetRemoteDescription(desc_ms1_two_tracks.release()));
- EXPECT_TRUE(CompareStreamCollections(observer_.remote_streams(),
- reference_collection_));
-
- // Remove the extra audio and video tracks.
- rtc::scoped_ptr<SessionDescriptionInterface> desc_ms2;
- CreateSessionDescriptionAndReference(1, 1, desc_ms2.accept());
- EXPECT_TRUE(DoSetRemoteDescription(desc_ms2.release()));
- EXPECT_TRUE(CompareStreamCollections(observer_.remote_streams(),
- reference_collection_));
-}
-
-// This tests that remote tracks are ended if a local session description is set
-// that rejects the media content type.
-TEST_F(PeerConnectionInterfaceTest, RejectMediaContent) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- // First create and set a remote offer, then reject its video content in our
- // answer.
- CreateAndSetRemoteOffer(kSdpStringWithStream1);
- ASSERT_EQ(1u, observer_.remote_streams()->count());
- MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
- ASSERT_EQ(1u, remote_stream->GetVideoTracks().size());
- ASSERT_EQ(1u, remote_stream->GetAudioTracks().size());
-
- rtc::scoped_refptr<webrtc::VideoTrackInterface> remote_video =
- remote_stream->GetVideoTracks()[0];
- EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, remote_video->state());
- rtc::scoped_refptr<webrtc::AudioTrackInterface> remote_audio =
- remote_stream->GetAudioTracks()[0];
- EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, remote_audio->state());
-
- rtc::scoped_ptr<SessionDescriptionInterface> local_answer;
- EXPECT_TRUE(DoCreateAnswer(local_answer.accept()));
- cricket::ContentInfo* video_info =
- local_answer->description()->GetContentByName("video");
- video_info->rejected = true;
- EXPECT_TRUE(DoSetLocalDescription(local_answer.release()));
- EXPECT_EQ(webrtc::MediaStreamTrackInterface::kEnded, remote_video->state());
- EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, remote_audio->state());
-
- // Now create an offer where we reject both video and audio.
- rtc::scoped_ptr<SessionDescriptionInterface> local_offer;
- EXPECT_TRUE(DoCreateOffer(local_offer.accept()));
- video_info = local_offer->description()->GetContentByName("video");
- ASSERT_TRUE(video_info != nullptr);
- video_info->rejected = true;
- cricket::ContentInfo* audio_info =
- local_offer->description()->GetContentByName("audio");
- ASSERT_TRUE(audio_info != nullptr);
- audio_info->rejected = true;
- EXPECT_TRUE(DoSetLocalDescription(local_offer.release()));
- EXPECT_EQ(webrtc::MediaStreamTrackInterface::kEnded, remote_video->state());
- EXPECT_EQ(webrtc::MediaStreamTrackInterface::kEnded, remote_audio->state());
-}
-
-// This tests that we won't crash if the remote track has been removed outside
-// of PeerConnection and then PeerConnection tries to reject the track.
-TEST_F(PeerConnectionInterfaceTest, RemoveTrackThenRejectMediaContent) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringWithStream1);
- MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
- remote_stream->RemoveTrack(remote_stream->GetVideoTracks()[0]);
- remote_stream->RemoveTrack(remote_stream->GetAudioTracks()[0]);
-
- rtc::scoped_ptr<SessionDescriptionInterface> local_answer(
- webrtc::CreateSessionDescription(SessionDescriptionInterface::kAnswer,
- kSdpStringWithStream1, nullptr));
- cricket::ContentInfo* video_info =
- local_answer->description()->GetContentByName("video");
- video_info->rejected = true;
- cricket::ContentInfo* audio_info =
- local_answer->description()->GetContentByName("audio");
- audio_info->rejected = true;
- EXPECT_TRUE(DoSetLocalDescription(local_answer.release()));
-
- // No crash is a pass.
-}
-
-// This tests that a default MediaStream is created if a remote session
-// description doesn't contain any streams and no MSID support.
-// It also tests that the default stream is updated if a video m-line is added
-// in a subsequent session description.
-TEST_F(PeerConnectionInterfaceTest, SdpWithoutMsidCreatesDefaultStream) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringWithoutStreamsAudioOnly);
-
- ASSERT_EQ(1u, observer_.remote_streams()->count());
- MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
-
- EXPECT_EQ(1u, remote_stream->GetAudioTracks().size());
- EXPECT_EQ(0u, remote_stream->GetVideoTracks().size());
- EXPECT_EQ("default", remote_stream->label());
-
- CreateAndSetRemoteOffer(kSdpStringWithoutStreams);
- ASSERT_EQ(1u, observer_.remote_streams()->count());
- ASSERT_EQ(1u, remote_stream->GetAudioTracks().size());
- EXPECT_EQ("defaulta0", remote_stream->GetAudioTracks()[0]->id());
- ASSERT_EQ(1u, remote_stream->GetVideoTracks().size());
- EXPECT_EQ("defaultv0", remote_stream->GetVideoTracks()[0]->id());
-}
-
-// This tests that a default MediaStream is created if a remote session
-// description doesn't contain any streams and media direction is send only.
-TEST_F(PeerConnectionInterfaceTest,
- SendOnlySdpWithoutMsidCreatesDefaultStream) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringSendOnlyWithoutStreams);
-
- ASSERT_EQ(1u, observer_.remote_streams()->count());
- MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
-
- EXPECT_EQ(1u, remote_stream->GetAudioTracks().size());
- EXPECT_EQ(1u, remote_stream->GetVideoTracks().size());
- EXPECT_EQ("default", remote_stream->label());
-}
-
-// This tests that it won't crash when PeerConnection tries to remove
-// a remote track that as already been removed from the MediaStream.
-TEST_F(PeerConnectionInterfaceTest, RemoveAlreadyGoneRemoteStream) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringWithStream1);
- MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
- remote_stream->RemoveTrack(remote_stream->GetAudioTracks()[0]);
- remote_stream->RemoveTrack(remote_stream->GetVideoTracks()[0]);
-
- CreateAndSetRemoteOffer(kSdpStringWithoutStreams);
-
- // No crash is a pass.
-}
-
-// This tests that a default MediaStream is created if the remote session
-// description doesn't contain any streams and don't contain an indication if
-// MSID is supported.
-TEST_F(PeerConnectionInterfaceTest,
- SdpWithoutMsidAndStreamsCreatesDefaultStream) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringWithoutStreams);
-
- ASSERT_EQ(1u, observer_.remote_streams()->count());
- MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
- EXPECT_EQ(1u, remote_stream->GetAudioTracks().size());
- EXPECT_EQ(1u, remote_stream->GetVideoTracks().size());
-}
-
-// This tests that a default MediaStream is not created if the remote session
-// description doesn't contain any streams but does support MSID.
-TEST_F(PeerConnectionInterfaceTest, SdpWithMsidDontCreatesDefaultStream) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringWithMsidWithoutStreams);
- EXPECT_EQ(0u, observer_.remote_streams()->count());
-}
-
-// This tests that a default MediaStream is not created if a remote session
-// description is updated to not have any MediaStreams.
-TEST_F(PeerConnectionInterfaceTest, VerifyDefaultStreamIsNotCreated) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- CreateAndSetRemoteOffer(kSdpStringWithStream1);
- rtc::scoped_refptr<StreamCollection> reference(CreateStreamCollection(1));
- EXPECT_TRUE(
- CompareStreamCollections(observer_.remote_streams(), reference.get()));
-
- CreateAndSetRemoteOffer(kSdpStringWithoutStreams);
- EXPECT_EQ(0u, observer_.remote_streams()->count());
-}
-
-// This tests that an RtpSender is created when the local description is set
-// after adding a local stream.
-// TODO(deadbeef): This test and the one below it need to be updated when
-// an RtpSender's lifetime isn't determined by when a local description is set.
-TEST_F(PeerConnectionInterfaceTest, LocalDescriptionChanged) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- // Create an offer just to ensure we have an identity before we manually
- // call SetLocalDescription.
- rtc::scoped_ptr<SessionDescriptionInterface> throwaway;
- ASSERT_TRUE(DoCreateOffer(throwaway.accept()));
-
- rtc::scoped_ptr<SessionDescriptionInterface> desc_1;
- CreateSessionDescriptionAndReference(2, 2, desc_1.accept());
-
- pc_->AddStream(reference_collection_->at(0));
- EXPECT_TRUE(DoSetLocalDescription(desc_1.release()));
- auto senders = pc_->GetSenders();
- EXPECT_EQ(4u, senders.size());
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[1]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[1]));
-
- // Remove an audio and video track.
- rtc::scoped_ptr<SessionDescriptionInterface> desc_2;
- CreateSessionDescriptionAndReference(1, 1, desc_2.accept());
- EXPECT_TRUE(DoSetLocalDescription(desc_2.release()));
- senders = pc_->GetSenders();
- EXPECT_EQ(2u, senders.size());
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
- EXPECT_FALSE(ContainsSender(senders, kAudioTracks[1]));
- EXPECT_FALSE(ContainsSender(senders, kVideoTracks[1]));
-}
-
-// This tests that an RtpSender is created when the local description is set
-// before adding a local stream.
-TEST_F(PeerConnectionInterfaceTest,
- AddLocalStreamAfterLocalDescriptionChanged) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- // Create an offer just to ensure we have an identity before we manually
- // call SetLocalDescription.
- rtc::scoped_ptr<SessionDescriptionInterface> throwaway;
- ASSERT_TRUE(DoCreateOffer(throwaway.accept()));
-
- rtc::scoped_ptr<SessionDescriptionInterface> desc_1;
- CreateSessionDescriptionAndReference(2, 2, desc_1.accept());
-
- EXPECT_TRUE(DoSetLocalDescription(desc_1.release()));
- auto senders = pc_->GetSenders();
- EXPECT_EQ(0u, senders.size());
-
- pc_->AddStream(reference_collection_->at(0));
- senders = pc_->GetSenders();
- EXPECT_EQ(4u, senders.size());
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[1]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[1]));
-}
-
-// This tests that the expected behavior occurs if the SSRC on a local track is
-// changed when SetLocalDescription is called.
-TEST_F(PeerConnectionInterfaceTest,
- ChangeSsrcOnTrackInLocalSessionDescription) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- // Create an offer just to ensure we have an identity before we manually
- // call SetLocalDescription.
- rtc::scoped_ptr<SessionDescriptionInterface> throwaway;
- ASSERT_TRUE(DoCreateOffer(throwaway.accept()));
-
- rtc::scoped_ptr<SessionDescriptionInterface> desc;
- CreateSessionDescriptionAndReference(1, 1, desc.accept());
- std::string sdp;
- desc->ToString(&sdp);
-
- pc_->AddStream(reference_collection_->at(0));
- EXPECT_TRUE(DoSetLocalDescription(desc.release()));
- auto senders = pc_->GetSenders();
- EXPECT_EQ(2u, senders.size());
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
-
- // Change the ssrc of the audio and video track.
- std::string ssrc_org = "a=ssrc:1";
- std::string ssrc_to = "a=ssrc:97";
- rtc::replace_substrs(ssrc_org.c_str(), ssrc_org.length(), ssrc_to.c_str(),
- ssrc_to.length(), &sdp);
- ssrc_org = "a=ssrc:2";
- ssrc_to = "a=ssrc:98";
- rtc::replace_substrs(ssrc_org.c_str(), ssrc_org.length(), ssrc_to.c_str(),
- ssrc_to.length(), &sdp);
- rtc::scoped_ptr<SessionDescriptionInterface> updated_desc(
- webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer, sdp,
- nullptr));
-
- EXPECT_TRUE(DoSetLocalDescription(updated_desc.release()));
- senders = pc_->GetSenders();
- EXPECT_EQ(2u, senders.size());
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
- // TODO(deadbeef): Once RtpSenders expose parameters, check that the SSRC
- // changed.
-}
-
-// This tests that the expected behavior occurs if a new session description is
-// set with the same tracks, but on a different MediaStream.
-TEST_F(PeerConnectionInterfaceTest, SignalSameTracksInSeparateMediaStream) {
- FakeConstraints constraints;
- constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- CreatePeerConnection(&constraints);
- // Create an offer just to ensure we have an identity before we manually
- // call SetLocalDescription.
- rtc::scoped_ptr<SessionDescriptionInterface> throwaway;
- ASSERT_TRUE(DoCreateOffer(throwaway.accept()));
-
- rtc::scoped_ptr<SessionDescriptionInterface> desc;
- CreateSessionDescriptionAndReference(1, 1, desc.accept());
- std::string sdp;
- desc->ToString(&sdp);
-
- pc_->AddStream(reference_collection_->at(0));
- EXPECT_TRUE(DoSetLocalDescription(desc.release()));
- auto senders = pc_->GetSenders();
- EXPECT_EQ(2u, senders.size());
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
-
- // Add a new MediaStream but with the same tracks as in the first stream.
- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream_1(
- webrtc::MediaStream::Create(kStreams[1]));
- stream_1->AddTrack(reference_collection_->at(0)->GetVideoTracks()[0]);
- stream_1->AddTrack(reference_collection_->at(0)->GetAudioTracks()[0]);
- pc_->AddStream(stream_1);
-
- // Replace msid in the original SDP.
- rtc::replace_substrs(kStreams[0], strlen(kStreams[0]), kStreams[1],
- strlen(kStreams[1]), &sdp);
-
- rtc::scoped_ptr<SessionDescriptionInterface> updated_desc(
- webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer, sdp,
- nullptr));
-
- EXPECT_TRUE(DoSetLocalDescription(updated_desc.release()));
- senders = pc_->GetSenders();
- EXPECT_EQ(2u, senders.size());
- EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
- EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
-}
-
-// The following tests verify that session options are created correctly.
-
-TEST(CreateSessionOptionsTest, GetOptionsForOfferWithInvalidAudioOption) {
- RTCOfferAnswerOptions rtc_options;
- rtc_options.offer_to_receive_audio = RTCOfferAnswerOptions::kUndefined - 1;
-
- cricket::MediaSessionOptions options;
- EXPECT_FALSE(ConvertRtcOptionsForOffer(rtc_options, &options));
-
- rtc_options.offer_to_receive_audio =
- RTCOfferAnswerOptions::kMaxOfferToReceiveMedia + 1;
- EXPECT_FALSE(ConvertRtcOptionsForOffer(rtc_options, &options));
-}
-
-TEST(CreateSessionOptionsTest, GetOptionsForOfferWithInvalidVideoOption) {
- RTCOfferAnswerOptions rtc_options;
- rtc_options.offer_to_receive_video = RTCOfferAnswerOptions::kUndefined - 1;
-
- cricket::MediaSessionOptions options;
- EXPECT_FALSE(ConvertRtcOptionsForOffer(rtc_options, &options));
-
- rtc_options.offer_to_receive_video =
- RTCOfferAnswerOptions::kMaxOfferToReceiveMedia + 1;
- EXPECT_FALSE(ConvertRtcOptionsForOffer(rtc_options, &options));
-}
-
-// Test that a MediaSessionOptions is created for an offer if
-// OfferToReceiveAudio and OfferToReceiveVideo options are set but no
-// MediaStreams are sent.
-TEST(CreateSessionOptionsTest, GetMediaSessionOptionsForOfferWithAudioVideo) {
- RTCOfferAnswerOptions rtc_options;
- rtc_options.offer_to_receive_audio = 1;
- rtc_options.offer_to_receive_video = 1;
-
- cricket::MediaSessionOptions options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options));
- EXPECT_TRUE(options.has_audio());
- EXPECT_TRUE(options.has_video());
- EXPECT_TRUE(options.bundle_enabled);
-}
-
-// Test that a correct MediaSessionOptions is created for an offer if
-// OfferToReceiveAudio is set but no MediaStreams are sent.
-TEST(CreateSessionOptionsTest, GetMediaSessionOptionsForOfferWithAudio) {
- RTCOfferAnswerOptions rtc_options;
- rtc_options.offer_to_receive_audio = 1;
-
- cricket::MediaSessionOptions options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options));
- EXPECT_TRUE(options.has_audio());
- EXPECT_FALSE(options.has_video());
- EXPECT_TRUE(options.bundle_enabled);
-}
-
-// Test that a correct MediaSessionOptions is created for an offer if
-// the default OfferOptons is used or MediaStreams are sent.
-TEST(CreateSessionOptionsTest, GetDefaultMediaSessionOptionsForOffer) {
- RTCOfferAnswerOptions rtc_options;
-
- cricket::MediaSessionOptions options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options));
- EXPECT_FALSE(options.has_audio());
- EXPECT_FALSE(options.has_video());
- EXPECT_FALSE(options.bundle_enabled);
- EXPECT_TRUE(options.vad_enabled);
- EXPECT_FALSE(options.transport_options.ice_restart);
-}
-
-// Test that a correct MediaSessionOptions is created for an offer if
-// OfferToReceiveVideo is set but no MediaStreams are sent.
-TEST(CreateSessionOptionsTest, GetMediaSessionOptionsForOfferWithVideo) {
- RTCOfferAnswerOptions rtc_options;
- rtc_options.offer_to_receive_audio = 0;
- rtc_options.offer_to_receive_video = 1;
-
- cricket::MediaSessionOptions options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options));
- EXPECT_FALSE(options.has_audio());
- EXPECT_TRUE(options.has_video());
- EXPECT_TRUE(options.bundle_enabled);
-}
-
-// Test that a correct MediaSessionOptions is created for an offer if
-// UseRtpMux is set to false.
-TEST(CreateSessionOptionsTest,
- GetMediaSessionOptionsForOfferWithBundleDisabled) {
- RTCOfferAnswerOptions rtc_options;
- rtc_options.offer_to_receive_audio = 1;
- rtc_options.offer_to_receive_video = 1;
- rtc_options.use_rtp_mux = false;
-
- cricket::MediaSessionOptions options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options));
- EXPECT_TRUE(options.has_audio());
- EXPECT_TRUE(options.has_video());
- EXPECT_FALSE(options.bundle_enabled);
-}
-
-// Test that a correct MediaSessionOptions is created to restart ice if
-// IceRestart is set. It also tests that subsequent MediaSessionOptions don't
-// have |transport_options.ice_restart| set.
-TEST(CreateSessionOptionsTest, GetMediaSessionOptionsForOfferWithIceRestart) {
- RTCOfferAnswerOptions rtc_options;
- rtc_options.ice_restart = true;
-
- cricket::MediaSessionOptions options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options));
- EXPECT_TRUE(options.transport_options.ice_restart);
-
- rtc_options = RTCOfferAnswerOptions();
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_options, &options));
- EXPECT_FALSE(options.transport_options.ice_restart);
-}
-
-// Test that the MediaConstraints in an answer don't affect if audio and video
-// is offered in an offer but that if kOfferToReceiveAudio or
-// kOfferToReceiveVideo constraints are true in an offer, the media type will be
-// included in subsequent answers.
-TEST(CreateSessionOptionsTest, MediaConstraintsInAnswer) {
- FakeConstraints answer_c;
- answer_c.SetMandatoryReceiveAudio(true);
- answer_c.SetMandatoryReceiveVideo(true);
-
- cricket::MediaSessionOptions answer_options;
- EXPECT_TRUE(ParseConstraintsForAnswer(&answer_c, &answer_options));
- EXPECT_TRUE(answer_options.has_audio());
- EXPECT_TRUE(answer_options.has_video());
-
- RTCOfferAnswerOptions rtc_offer_optoins;
-
- cricket::MediaSessionOptions offer_options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(rtc_offer_optoins, &offer_options));
- EXPECT_FALSE(offer_options.has_audio());
- EXPECT_FALSE(offer_options.has_video());
-
- RTCOfferAnswerOptions updated_rtc_offer_optoins;
- updated_rtc_offer_optoins.offer_to_receive_audio = 1;
- updated_rtc_offer_optoins.offer_to_receive_video = 1;
-
- cricket::MediaSessionOptions updated_offer_options;
- EXPECT_TRUE(ConvertRtcOptionsForOffer(updated_rtc_offer_optoins,
- &updated_offer_options));
- EXPECT_TRUE(updated_offer_options.has_audio());
- EXPECT_TRUE(updated_offer_options.has_video());
-
- // Since an offer has been created with both audio and video, subsequent
- // offers and answers should contain both audio and video.
- // Answers will only contain the media types that exist in the offer
- // regardless of the value of |updated_answer_options.has_audio| and
- // |updated_answer_options.has_video|.
- FakeConstraints updated_answer_c;
- answer_c.SetMandatoryReceiveAudio(false);
- answer_c.SetMandatoryReceiveVideo(false);
-
- cricket::MediaSessionOptions updated_answer_options;
- EXPECT_TRUE(
- ParseConstraintsForAnswer(&updated_answer_c, &updated_answer_options));
- EXPECT_TRUE(updated_answer_options.has_audio());
- EXPECT_TRUE(updated_answer_options.has_video());
-
- RTCOfferAnswerOptions default_rtc_options;
- EXPECT_TRUE(
- ConvertRtcOptionsForOffer(default_rtc_options, &updated_offer_options));
- // 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());
-}
diff --git a/talk/app/webrtc/sctputils.cc b/talk/app/webrtc/sctputils.cc
index 2239599..a643837 100644
--- a/talk/app/webrtc/sctputils.cc
+++ b/talk/app/webrtc/sctputils.cc
@@ -48,19 +48,6 @@
DCOMCT_UNORDERED_PARTIAL_TIME = 0x82,
};
-bool IsOpenMessage(const rtc::Buffer& payload) {
- // Format defined at
- // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
-
- rtc::ByteBuffer buffer(payload);
- uint8_t message_type;
- if (!buffer.ReadUInt8(&message_type)) {
- LOG(LS_WARNING) << "Could not read OPEN message type.";
- return false;
- }
- return message_type == DATA_CHANNEL_OPEN_MESSAGE_TYPE;
-}
-
bool ParseDataChannelOpenMessage(const rtc::Buffer& payload,
std::string* label,
DataChannelInit* config) {
diff --git a/talk/app/webrtc/sctputils.h b/talk/app/webrtc/sctputils.h
index f16873c..ab1818b 100644
--- a/talk/app/webrtc/sctputils.h
+++ b/talk/app/webrtc/sctputils.h
@@ -39,9 +39,6 @@
namespace webrtc {
struct DataChannelInit;
-// Read the message type and return true if it's an OPEN message.
-bool IsOpenMessage(const rtc::Buffer& payload);
-
bool ParseDataChannelOpenMessage(const rtc::Buffer& payload,
std::string* label,
DataChannelInit* config);
diff --git a/talk/app/webrtc/sctputils_unittest.cc b/talk/app/webrtc/sctputils_unittest.cc
index e0e203f..e5f323a 100644
--- a/talk/app/webrtc/sctputils_unittest.cc
+++ b/talk/app/webrtc/sctputils_unittest.cc
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2013 Google Inc.
+ * Copyright 2013 Google Inc
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -159,20 +159,3 @@
EXPECT_TRUE(webrtc::ParseDataChannelOpenAckMessage(packet));
}
-
-TEST_F(SctpUtilsTest, TestIsOpenMessage) {
- rtc::ByteBuffer open;
- open.WriteUInt8(0x03);
- EXPECT_TRUE(webrtc::IsOpenMessage(open));
-
- rtc::ByteBuffer openAck;
- openAck.WriteUInt8(0x02);
- EXPECT_FALSE(webrtc::IsOpenMessage(open));
-
- rtc::ByteBuffer invalid;
- openAck.WriteUInt8(0x01);
- EXPECT_FALSE(webrtc::IsOpenMessage(invalid));
-
- rtc::ByteBuffer empty;
- EXPECT_FALSE(webrtc::IsOpenMessage(empty));
-}
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc
index 9ba7da8..5b527ec 100644
--- a/talk/app/webrtc/statscollector.cc
+++ b/talk/app/webrtc/statscollector.cc
@@ -30,7 +30,6 @@
#include <utility>
#include <vector>
-#include "talk/app/webrtc/peerconnection.h"
#include "talk/session/media/channel.h"
#include "webrtc/base/base64.h"
#include "webrtc/base/checks.h"
@@ -357,13 +356,14 @@
}
}
-StatsCollector::StatsCollector(PeerConnection* pc)
- : pc_(pc), stats_gathering_started_(0) {
- RTC_DCHECK(pc_);
+StatsCollector::StatsCollector(WebRtcSession* session)
+ : session_(session),
+ stats_gathering_started_(0) {
+ RTC_DCHECK(session_);
}
StatsCollector::~StatsCollector() {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
}
double StatsCollector::GetTimeNow() {
@@ -373,7 +373,7 @@
// Adds a MediaStream with tracks that can be used as a |selector| in a call
// to GetStats.
void StatsCollector::AddStream(MediaStreamInterface* stream) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
RTC_DCHECK(stream != NULL);
CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
@@ -384,7 +384,7 @@
void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
uint32_t ssrc) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
RTC_DCHECK(audio_track != NULL);
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
for (const auto& track : local_audio_tracks_)
@@ -416,7 +416,7 @@
void StatsCollector::GetStats(MediaStreamTrackInterface* track,
StatsReports* reports) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
RTC_DCHECK(reports != NULL);
RTC_DCHECK(reports->empty());
@@ -430,7 +430,7 @@
}
StatsReport* report = reports_.Find(StatsReport::NewTypedId(
- StatsReport::kStatsReportTypeSession, pc_->session()->id()));
+ StatsReport::kStatsReportTypeSession, session_->id()));
if (report)
reports->push_back(report);
@@ -456,7 +456,7 @@
void
StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
double time_now = GetTimeNow();
// Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
// ms apart will be ignored.
@@ -467,7 +467,7 @@
}
stats_gathering_started_ = time_now;
- if (pc_->session()) {
+ if (session_) {
// TODO(tommi): All of these hop over to the worker thread to fetch
// information. We could use an AsyncInvoker to run all of these and post
// the information back to the signaling thread where we can create and
@@ -482,12 +482,11 @@
}
}
-StatsReport* StatsCollector::PrepareReport(
- bool local,
- uint32_t ssrc,
- const StatsReport::Id& transport_id,
- StatsReport::Direction direction) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+StatsReport* StatsCollector::PrepareReport(bool local,
+ uint32_t ssrc,
+ const StatsReport::Id& transport_id,
+ StatsReport::Direction direction) {
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
StatsReport::Id id(StatsReport::NewIdWithDirection(
local ? StatsReport::kStatsReportTypeSsrc
: StatsReport::kStatsReportTypeRemoteSsrc,
@@ -526,7 +525,7 @@
StatsReport* StatsCollector::AddOneCertificateReport(
const rtc::SSLCertificate* cert, const StatsReport* issuer) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
// TODO(bemasc): Move this computation to a helper class that caches these
// values to reduce CPU use in GetStats. This will require adding a fast
@@ -569,7 +568,7 @@
StatsReport* StatsCollector::AddCertificateReports(
const rtc::SSLCertificate* cert) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
// Produces a chain of StatsReports representing this certificate and the rest
// of its chain, and adds those reports to |reports_|. The return value is
// the id of the leaf report. The provided cert must be non-null, so at least
@@ -669,18 +668,18 @@
}
void StatsCollector::ExtractSessionInfo() {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
// Extract information from the base session.
StatsReport::Id id(StatsReport::NewTypedId(
- StatsReport::kStatsReportTypeSession, pc_->session()->id()));
+ StatsReport::kStatsReportTypeSession, session_->id()));
StatsReport* report = reports_.ReplaceOrAddNew(id);
report->set_timestamp(stats_gathering_started_);
report->AddBoolean(StatsReport::kStatsValueNameInitiator,
- pc_->session()->initiator());
+ session_->initiator());
cricket::SessionStats stats;
- if (!pc_->session()->GetTransportStats(&stats)) {
+ if (!session_->GetTransportStats(&stats)) {
return;
}
@@ -699,16 +698,16 @@
//
StatsReport::Id local_cert_report_id, remote_cert_report_id;
rtc::scoped_refptr<rtc::RTCCertificate> certificate;
- if (pc_->session()->GetLocalCertificate(
- transport_iter.second.transport_name, &certificate)) {
+ if (session_->GetLocalCertificate(transport_iter.second.transport_name,
+ &certificate)) {
StatsReport* r = AddCertificateReports(&(certificate->ssl_certificate()));
if (r)
local_cert_report_id = r->id();
}
rtc::scoped_ptr<rtc::SSLCertificate> cert;
- if (pc_->session()->GetRemoteSSLCertificate(
- transport_iter.second.transport_name, cert.accept())) {
+ if (session_->GetRemoteSSLCertificate(transport_iter.second.transport_name,
+ cert.accept())) {
StatsReport* r = AddCertificateReports(cert.get());
if (r)
remote_cert_report_id = r->id();
@@ -759,13 +758,13 @@
}
void StatsCollector::ExtractVoiceInfo() {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
- if (!pc_->session()->voice_channel()) {
+ if (!session_->voice_channel()) {
return;
}
cricket::VoiceMediaInfo voice_info;
- if (!pc_->session()->voice_channel()->GetStats(&voice_info)) {
+ if (!session_->voice_channel()->GetStats(&voice_info)) {
LOG(LS_ERROR) << "Failed to get voice channel stats.";
return;
}
@@ -774,11 +773,11 @@
// results back to the signaling thread, where we can add data to the reports.
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
- StatsReport::Id transport_id(GetTransportIdFromProxy(
- proxy_to_transport_, pc_->session()->voice_channel()->content_name()));
+ StatsReport::Id transport_id(GetTransportIdFromProxy(proxy_to_transport_,
+ session_->voice_channel()->content_name()));
if (!transport_id.get()) {
LOG(LS_ERROR) << "Failed to get transport name for proxy "
- << pc_->session()->voice_channel()->content_name();
+ << session_->voice_channel()->content_name();
return;
}
@@ -792,13 +791,13 @@
void StatsCollector::ExtractVideoInfo(
PeerConnectionInterface::StatsOutputLevel level) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
- if (!pc_->session()->video_channel())
+ if (!session_->video_channel())
return;
cricket::VideoMediaInfo video_info;
- if (!pc_->session()->video_channel()->GetStats(&video_info)) {
+ if (!session_->video_channel()->GetStats(&video_info)) {
LOG(LS_ERROR) << "Failed to get video channel stats.";
return;
}
@@ -807,11 +806,11 @@
// results back to the signaling thread, where we can add data to the reports.
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
- StatsReport::Id transport_id(GetTransportIdFromProxy(
- proxy_to_transport_, pc_->session()->video_channel()->content_name()));
+ StatsReport::Id transport_id(GetTransportIdFromProxy(proxy_to_transport_,
+ session_->video_channel()->content_name()));
if (!transport_id.get()) {
LOG(LS_ERROR) << "Failed to get transport name for proxy "
- << pc_->session()->video_channel()->content_name();
+ << session_->video_channel()->content_name();
return;
}
ExtractStatsFromList(video_info.receivers, transport_id, this,
@@ -829,11 +828,12 @@
}
void StatsCollector::ExtractDataInfo() {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
- for (const auto& dc : pc_->sctp_data_channels()) {
+ for (const auto& dc :
+ session_->mediastream_signaling()->sctp_data_channels()) {
StatsReport::Id id(StatsReport::NewTypedIntId(
StatsReport::kStatsReportTypeDataChannel, dc->id()));
StatsReport* report = reports_.ReplaceOrAddNew(id);
@@ -849,14 +849,14 @@
StatsReport* StatsCollector::GetReport(const StatsReport::StatsType& type,
const std::string& id,
StatsReport::Direction direction) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
RTC_DCHECK(type == StatsReport::kStatsReportTypeSsrc ||
type == StatsReport::kStatsReportTypeRemoteSsrc);
return reports_.Find(StatsReport::NewIdWithDirection(type, id, direction));
}
void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
// Loop through the existing local audio tracks.
for (const auto& it : local_audio_tracks_) {
AudioTrackInterface* track = it.first;
@@ -884,7 +884,7 @@
void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
StatsReport* report) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
RTC_DCHECK(track != NULL);
int signal_level = 0;
@@ -907,16 +907,16 @@
bool StatsCollector::GetTrackIdBySsrc(uint32_t ssrc,
std::string* track_id,
StatsReport::Direction direction) {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
if (direction == StatsReport::kSend) {
- if (!pc_->session()->GetLocalTrackIdBySsrc(ssrc, track_id)) {
+ if (!session_->GetLocalTrackIdBySsrc(ssrc, track_id)) {
LOG(LS_WARNING) << "The SSRC " << ssrc
<< " is not associated with a sending track";
return false;
}
} else {
RTC_DCHECK(direction == StatsReport::kReceive);
- if (!pc_->session()->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
+ if (!session_->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
LOG(LS_WARNING) << "The SSRC " << ssrc
<< " is not associated with a receiving track";
return false;
@@ -927,7 +927,7 @@
}
void StatsCollector::UpdateTrackReports() {
- RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
+ RTC_DCHECK(session_->signaling_thread()->IsCurrent());
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
diff --git a/talk/app/webrtc/statscollector.h b/talk/app/webrtc/statscollector.h
index 714f15a..add26c6 100644
--- a/talk/app/webrtc/statscollector.h
+++ b/talk/app/webrtc/statscollector.h
@@ -43,8 +43,6 @@
namespace webrtc {
-class PeerConnection;
-
// Conversion function to convert candidate type string to the corresponding one
// from enum RTCStatsIceCandidateType.
const char* IceCandidateTypeToStatsType(const std::string& candidate_type);
@@ -59,9 +57,9 @@
class StatsCollector {
public:
- // The caller is responsible for ensuring that the pc outlives the
+ // The caller is responsible for ensuring that the session outlives the
// StatsCollector instance.
- explicit StatsCollector(PeerConnection* pc);
+ explicit StatsCollector(WebRtcSession* session);
virtual ~StatsCollector();
// Adds a MediaStream with tracks that can be used as a |selector| in a call
@@ -153,8 +151,8 @@
// A collection for all of our stats reports.
StatsCollection reports_;
TrackIdMap track_ids_;
- // Raw pointer to the peer connection the statistics are gathered from.
- PeerConnection* const pc_;
+ // Raw pointer to the session the statistics are gathered from.
+ WebRtcSession* const session_;
double stats_gathering_started_;
cricket::ProxyTransportMap proxy_to_transport_;
diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc
index 49b992c..21f9df8 100644
--- a/talk/app/webrtc/statscollector_unittest.cc
+++ b/talk/app/webrtc/statscollector_unittest.cc
@@ -31,13 +31,12 @@
#include "talk/app/webrtc/statscollector.h"
-#include "talk/app/webrtc/peerconnection.h"
-#include "talk/app/webrtc/peerconnectionfactory.h"
#include "talk/app/webrtc/mediastream.h"
#include "talk/app/webrtc/mediastreaminterface.h"
#include "talk/app/webrtc/mediastreamsignaling.h"
#include "talk/app/webrtc/mediastreamtrack.h"
#include "talk/app/webrtc/test/fakedatachannelprovider.h"
+#include "talk/app/webrtc/test/fakemediastreamsignaling.h"
#include "talk/app/webrtc/videotrack.h"
#include "talk/media/base/fakemediaengine.h"
#include "talk/session/media/channelmanager.h"
@@ -55,7 +54,6 @@
using testing::Field;
using testing::Return;
using testing::ReturnNull;
-using testing::ReturnRef;
using testing::SetArgPointee;
using webrtc::PeerConnectionInterface;
using webrtc::StatsReport;
@@ -85,12 +83,12 @@
class MockWebRtcSession : public webrtc::WebRtcSession {
public:
explicit MockWebRtcSession(cricket::ChannelManager* channel_manager)
- : WebRtcSession(channel_manager,
- rtc::Thread::Current(),
- rtc::Thread::Current(),
- nullptr) {}
+ : WebRtcSession(channel_manager, rtc::Thread::Current(),
+ rtc::Thread::Current(), NULL, NULL) {
+ }
MOCK_METHOD0(voice_channel, cricket::VoiceChannel*());
MOCK_METHOD0(video_channel, cricket::VideoChannel*());
+ MOCK_CONST_METHOD0(mediastream_signaling, const MediaStreamSignaling*());
// Libjingle uses "local" for a outgoing track, and "remote" for a incoming
// track.
MOCK_METHOD2(GetLocalTrackIdBySsrc, bool(uint32_t, std::string*));
@@ -104,21 +102,6 @@
rtc::SSLCertificate** cert));
};
-// The factory isn't really used; it just satisfies the base PeerConnection.
-class FakePeerConnectionFactory
- : public rtc::RefCountedObject<PeerConnectionFactory> {};
-
-class MockPeerConnection
- : public rtc::RefCountedObject<webrtc::PeerConnection> {
- public:
- MockPeerConnection()
- : rtc::RefCountedObject<webrtc::PeerConnection>(
- new FakePeerConnectionFactory()) {}
- MOCK_METHOD0(session, WebRtcSession*());
- MOCK_CONST_METHOD0(sctp_data_channels,
- const std::vector<rtc::scoped_refptr<DataChannel>>&());
-};
-
class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
public:
MockVideoMediaChannel() :
@@ -489,8 +472,9 @@
class StatsCollectorForTest : public webrtc::StatsCollector {
public:
- explicit StatsCollectorForTest(PeerConnection* pc)
- : StatsCollector(pc), time_now_(19477) {}
+ explicit StatsCollectorForTest(WebRtcSession* session) :
+ StatsCollector(session), time_now_(19477) {
+ }
double GetTimeNow() override {
return time_now_;
@@ -503,18 +487,15 @@
class StatsCollectorTest : public testing::Test {
protected:
StatsCollectorTest()
- : media_engine_(new cricket::FakeMediaEngine()),
- channel_manager_(
- new cricket::ChannelManager(media_engine_, rtc::Thread::Current())),
- session_(channel_manager_.get()) {
+ : media_engine_(new cricket::FakeMediaEngine()),
+ channel_manager_(
+ new cricket::ChannelManager(media_engine_, rtc::Thread::Current())),
+ session_(channel_manager_.get()),
+ signaling_(channel_manager_.get()) {
// By default, we ignore session GetStats calls.
EXPECT_CALL(session_, GetTransportStats(_)).WillRepeatedly(Return(false));
- // Add default returns for mock classes.
- EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
- EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
- EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_));
- EXPECT_CALL(pc_, sctp_data_channels())
- .WillRepeatedly(ReturnRef(data_channels_));
+ EXPECT_CALL(session_, mediastream_signaling()).WillRepeatedly(
+ Return(&signaling_));
}
~StatsCollectorTest() {}
@@ -576,16 +557,6 @@
.WillOnce(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true)));
}
- void AddDataChannel(cricket::DataChannelType type,
- const std::string& label,
- int id) {
- InternalDataChannelInit config;
- config.id = id;
-
- data_channels_.push_back(DataChannel::Create(
- &data_channel_provider_, cricket::DCT_SCTP, label, config));
- }
-
StatsReport* AddCandidateReport(StatsCollector* collector,
const cricket::Candidate& candidate,
bool local) {
@@ -673,7 +644,7 @@
const std::vector<std::string>& local_ders,
const rtc::FakeSSLCertificate& remote_cert,
const std::vector<std::string>& remote_ders) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
StatsReports reports; // returned values.
@@ -708,6 +679,8 @@
EXPECT_CALL(session_, GetTransportStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
@@ -761,13 +734,12 @@
cricket::FakeMediaEngine* media_engine_;
rtc::scoped_ptr<cricket::ChannelManager> channel_manager_;
MockWebRtcSession session_;
- MockPeerConnection pc_;
+ FakeMediaStreamSignaling signaling_;
FakeDataChannelProvider data_channel_provider_;
cricket::SessionStats session_stats_;
rtc::scoped_refptr<webrtc::MediaStream> stream_;
rtc::scoped_refptr<webrtc::VideoTrack> track_;
rtc::scoped_refptr<FakeAudioTrack> audio_track_;
- std::vector<rtc::scoped_refptr<DataChannel>> data_channels_;
};
// Verify that ExtractDataInfo populates reports.
@@ -777,8 +749,14 @@
const std::string state = DataChannelInterface::DataStateString(
DataChannelInterface::DataState::kConnecting);
- AddDataChannel(cricket::DCT_SCTP, label, id);
- StatsCollectorForTest stats(&pc_);
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+
+ InternalDataChannelInit config;
+ config.id = id;
+ signaling_.AddDataChannel(DataChannel::Create(
+ &data_channel_provider_, cricket::DCT_SCTP, label, config));
+ StatsCollectorForTest stats(&session_);
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
@@ -810,7 +788,7 @@
// This test verifies that 64-bit counters are passed successfully.
TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -856,7 +834,7 @@
// Test that BWE information is reported via stats.
TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -913,9 +891,11 @@
// This test verifies that an object of type "googSession" always
// exists in the returned stats.
TEST_F(StatsCollectorTest, SessionObjectExists) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
StatsReports reports; // returned values.
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const StatsReport* session_report = FindNthReportByType(
@@ -926,9 +906,11 @@
// This test verifies that only one object of type "googSession" exists
// in the returned stats.
TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
StatsReports reports; // returned values.
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
@@ -943,7 +925,7 @@
// This test verifies that the empty track report exists in the returned stats
// without calling StatsCollector::UpdateStats.
TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(rtc::Thread::Current(),
@@ -968,7 +950,7 @@
// This test verifies that the empty track report exists in the returned stats
// when StatsCollector::UpdateStats is called with ssrc stats.
TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1036,7 +1018,7 @@
// This test verifies that an SSRC object has the identifier of a Transport
// stats object, and that this transport stats object exists in stats.
TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1099,7 +1081,7 @@
// This test verifies that a remote stats object will not be created for
// an outgoing SSRC where remote stats are not returned.
TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
// The transport_name known by the video channel.
@@ -1109,6 +1091,9 @@
AddOutgoingVideoTrackStats();
stats.AddStream(stream_);
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
StatsReports reports;
stats.GetStats(NULL, &reports);
@@ -1120,7 +1105,7 @@
// This test verifies that a remote stats object will be created for
// an outgoing SSRC where stats are returned.
TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1171,7 +1156,7 @@
// This test verifies that the empty track report exists in the returned stats
// when StatsCollector::UpdateStats is called with ssrc stats.
TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1229,7 +1214,7 @@
// This test verifies the Ice Candidate report should contain the correct
// information from local/remote candidates.
TEST_F(StatsCollectorTest, IceCandidateReport) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
StatsReports reports; // returned values.
@@ -1359,7 +1344,7 @@
// This test verifies that the stats are generated correctly when no
// transport is present.
TEST_F(StatsCollectorTest, NoTransport) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1385,6 +1370,9 @@
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
@@ -1418,7 +1406,7 @@
// This test verifies that the stats are generated correctly when the transport
// does not have any certificates.
TEST_F(StatsCollectorTest, NoCertificates) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1447,6 +1435,9 @@
EXPECT_CALL(session_, GetTransportStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
+ EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
+ EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
+
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
@@ -1484,7 +1475,7 @@
// This test verifies that a local stats object can get statistics via
// AudioTrackInterface::GetStats() method.
TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1519,7 +1510,7 @@
// This test verifies that audio receive streams populate stats reports
// correctly.
TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1548,7 +1539,7 @@
// This test verifies that a local stats object won't update its statistics
// after a RemoveLocalAudioTrack() call.
TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1609,7 +1600,7 @@
// This test verifies that when ongoing and incoming audio tracks are using
// the same ssrc, they populate stats reports correctly.
TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
@@ -1696,7 +1687,7 @@
// TODO(xians): Figure out if it is possible to encapsulate the setup and
// avoid duplication of code in test cases.
TEST_F(StatsCollectorTest, TwoLocalTracksWithSameSsrc) {
- StatsCollectorForTest stats(&pc_);
+ StatsCollectorForTest stats(&session_);
EXPECT_CALL(session_, GetLocalCertificate(_, _))
.WillRepeatedly(Return(false));
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index 1a5751a..bdc4784 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -38,7 +38,6 @@
#include "talk/app/webrtc/mediaconstraintsinterface.h"
#include "talk/app/webrtc/mediastreamsignaling.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
-#include "talk/app/webrtc/sctputils.h"
#include "talk/app/webrtc/webrtcsessiondescriptionfactory.h"
#include "talk/media/base/constants.h"
#include "talk/media/base/videocapturer.h"
@@ -537,10 +536,12 @@
bool ice_restart_;
};
-WebRtcSession::WebRtcSession(cricket::ChannelManager* channel_manager,
- rtc::Thread* signaling_thread,
- rtc::Thread* worker_thread,
- cricket::PortAllocator* port_allocator)
+WebRtcSession::WebRtcSession(
+ cricket::ChannelManager* channel_manager,
+ rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ cricket::PortAllocator* port_allocator,
+ MediaStreamSignaling* mediastream_signaling)
: cricket::BaseSession(signaling_thread,
worker_thread,
port_allocator,
@@ -550,6 +551,7 @@
// o line MUST be representable with a "64 bit signed integer".
// Due to this constraint session id |sid_| is max limited to LLONG_MAX.
channel_manager_(channel_manager),
+ mediastream_signaling_(mediastream_signaling),
ice_observer_(NULL),
ice_connection_state_(PeerConnectionInterface::kIceConnectionNew),
ice_connection_receiving_(true),
@@ -641,6 +643,9 @@
data_channel_type_ = cricket::DCT_SCTP;
}
}
+ if (data_channel_type_ != cricket::DCT_NONE) {
+ mediastream_signaling_->SetDataChannelFactory(this);
+ }
// Find DSCP constraint.
if (FindConstraint(
@@ -738,19 +743,21 @@
if (!dtls_enabled_) {
// Construct with DTLS disabled.
webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
- signaling_thread(), channel_manager_, this, id()));
+ signaling_thread(), channel_manager_, mediastream_signaling_, this,
+ id(), data_channel_type_));
} else {
// Construct with DTLS enabled.
if (!certificate) {
// Use the |dtls_identity_store| to generate a certificate.
RTC_DCHECK(dtls_identity_store);
webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
- signaling_thread(), channel_manager_, dtls_identity_store.Pass(),
- this, id()));
+ signaling_thread(), channel_manager_, mediastream_signaling_,
+ dtls_identity_store.Pass(), this, id(), data_channel_type_));
} else {
// Use the already generated certificate.
webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
- signaling_thread(), channel_manager_, certificate, this, id()));
+ signaling_thread(), channel_manager_, mediastream_signaling_,
+ certificate, this, id(), data_channel_type_));
}
}
@@ -812,17 +819,13 @@
void WebRtcSession::CreateOffer(
CreateSessionDescriptionObserver* observer,
- const PeerConnectionInterface::RTCOfferAnswerOptions& options,
- const cricket::MediaSessionOptions& session_options) {
- webrtc_session_desc_factory_->CreateOffer(observer, options, session_options);
+ const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
+ webrtc_session_desc_factory_->CreateOffer(observer, options);
}
-void WebRtcSession::CreateAnswer(
- CreateSessionDescriptionObserver* observer,
- const MediaConstraintsInterface* constraints,
- const cricket::MediaSessionOptions& session_options) {
- webrtc_session_desc_factory_->CreateAnswer(observer, constraints,
- session_options);
+void WebRtcSession::CreateAnswer(CreateSessionDescriptionObserver* observer,
+ const MediaConstraintsInterface* constraints) {
+ webrtc_session_desc_factory_->CreateAnswer(observer, constraints);
}
bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
@@ -880,6 +883,14 @@
UseCandidatesInSessionDescription(remote_desc_.get());
}
+ // Update state and SSRC of local MediaStreams and DataChannels based on the
+ // local session description.
+ mediastream_signaling_->OnLocalDescriptionChanged(local_desc_.get());
+
+ rtc::SSLRole role;
+ if (data_channel_type_ == cricket::DCT_SCTP && GetSslRole(&role)) {
+ mediastream_signaling_->OnDtlsRoleReadyForSctp(role);
+ }
if (error() != cricket::BaseSession::ERROR_NONE) {
return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc);
}
@@ -916,6 +927,8 @@
return false;
}
+ // Update remote MediaStreams.
+ mediastream_signaling_->OnRemoteDescriptionChanged(desc);
if (local_description() && !UseCandidatesInSessionDescription(desc)) {
return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc);
}
@@ -937,6 +950,11 @@
remote_desc_.reset(desc_temp.release());
+ rtc::SSLRole role;
+ if (data_channel_type_ == cricket::DCT_SCTP && GetSslRole(&role)) {
+ mediastream_signaling_->OnDtlsRoleReadyForSctp(role);
+ }
+
if (error() != cricket::BaseSession::ERROR_NONE) {
return BadRemoteSdp(desc->type(), GetSessionErrorMsg(), err_desc);
}
@@ -1369,8 +1387,6 @@
&DataChannel::OnChannelReady);
data_channel_->SignalDataReceived.connect(webrtc_data_channel,
&DataChannel::OnDataReceived);
- data_channel_->SignalStreamClosedRemotely.connect(
- webrtc_data_channel, &DataChannel::OnStreamClosedRemotely);
return true;
}
@@ -1381,7 +1397,6 @@
}
data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel);
data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
- data_channel_->SignalStreamClosedRemotely.disconnect(webrtc_data_channel);
}
void WebRtcSession::AddSctpDataStream(int sid) {
@@ -1394,6 +1409,8 @@
}
void WebRtcSession::RemoveSctpDataStream(int sid) {
+ mediastream_signaling_->RemoveSctpDataChannel(sid);
+
if (!data_channel_) {
LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is "
<< "NULL.";
@@ -1407,6 +1424,41 @@
return data_channel_ && data_channel_->ready_to_send_data();
}
+rtc::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel(
+ const std::string& label,
+ const InternalDataChannelInit* config) {
+ if (state() == STATE_RECEIVEDTERMINATE) {
+ return NULL;
+ }
+ if (data_channel_type_ == cricket::DCT_NONE) {
+ LOG(LS_ERROR) << "CreateDataChannel: Data is not supported in this call.";
+ return NULL;
+ }
+ InternalDataChannelInit new_config =
+ config ? (*config) : InternalDataChannelInit();
+ if (data_channel_type_ == cricket::DCT_SCTP) {
+ if (new_config.id < 0) {
+ rtc::SSLRole role;
+ if (GetSslRole(&role) &&
+ !mediastream_signaling_->AllocateSctpSid(role, &new_config.id)) {
+ LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
+ return NULL;
+ }
+ } else if (!mediastream_signaling_->IsSctpSidAvailable(new_config.id)) {
+ LOG(LS_ERROR) << "Failed to create a SCTP data channel "
+ << "because the id is already in use or out of range.";
+ return NULL;
+ }
+ }
+
+ rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
+ this, data_channel_type_, label, new_config));
+ if (channel && !mediastream_signaling_->AddDataChannel(channel))
+ return NULL;
+
+ return channel;
+}
+
cricket::DataChannelType WebRtcSession::data_channel_type() const {
return data_channel_type_;
}
@@ -1675,6 +1727,7 @@
const cricket::ContentInfo* video_info =
cricket::GetFirstVideoContent(desc);
if ((!video_info || video_info->rejected) && video_channel_) {
+ mediastream_signaling_->OnVideoChannelClose();
SignalVideoChannelDestroyed();
const std::string content_name = video_channel_->content_name();
channel_manager_->DestroyVideoChannel(video_channel_.release());
@@ -1683,6 +1736,7 @@
const cricket::ContentInfo* voice_info =
cricket::GetFirstAudioContent(desc);
if ((!voice_info || voice_info->rejected) && voice_channel_) {
+ mediastream_signaling_->OnAudioChannelClose();
SignalVoiceChannelDestroyed();
const std::string content_name = voice_channel_->content_name();
channel_manager_->DestroyVoiceChannel(voice_channel_.release());
@@ -1691,6 +1745,7 @@
const cricket::ContentInfo* data_info =
cricket::GetFirstDataContent(desc);
if ((!data_info || data_info->rejected) && data_channel_) {
+ mediastream_signaling_->OnDataChannelClose();
SignalDataChannelDestroyed();
const std::string content_name = data_channel_->content_name();
channel_manager_->DestroyDataChannel(data_channel_.release());
@@ -1765,8 +1820,6 @@
voice_channel_->SignalDtlsSetupFailure.connect(
this, &WebRtcSession::OnDtlsSetupFailure);
-
- SignalVoiceChannelCreated();
return true;
}
@@ -1780,8 +1833,6 @@
video_channel_->SignalDtlsSetupFailure.connect(
this, &WebRtcSession::OnDtlsSetupFailure);
-
- SignalVideoChannelCreated();
return true;
}
@@ -1794,14 +1845,16 @@
}
if (sctp) {
+ mediastream_signaling_->OnDataTransportCreatedForSctp();
data_channel_->SignalDataReceived.connect(
this, &WebRtcSession::OnDataChannelMessageReceived);
+ data_channel_->SignalStreamClosedRemotely.connect(
+ mediastream_signaling_,
+ &MediaStreamSignaling::OnRemoteSctpDataChannelClosed);
}
data_channel_->SignalDtlsSetupFailure.connect(
this, &WebRtcSession::OnDtlsSetupFailure);
-
- SignalDataChannelCreated();
return true;
}
@@ -1827,22 +1880,13 @@
cricket::DataChannel* channel,
const cricket::ReceiveDataParams& params,
const rtc::Buffer& payload) {
- RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
- if (params.type == cricket::DMT_CONTROL && IsOpenMessage(payload)) {
- // Received OPEN message; parse and signal that a new data channel should
- // be created.
- std::string label;
- InternalDataChannelInit config;
- config.id = params.ssrc;
- if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
- LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
- << params.ssrc;
- return;
- }
- config.open_handshake_role = InternalDataChannelInit::kAcker;
- SignalDataChannelOpenMessage(label, config);
+ ASSERT(data_channel_type_ == cricket::DCT_SCTP);
+ if (params.type == cricket::DMT_CONTROL &&
+ mediastream_signaling_->IsSctpSidAvailable(params.ssrc)) {
+ // Received CONTROL on unused sid, process as an OPEN message.
+ mediastream_signaling_->AddDataChannelFromOpenMessage(params, payload);
}
- // Otherwise ignore the message.
+ // otherwise ignore the message.
}
// Returns false if bundle is enabled and rtcp_mux is disabled.
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index 8dcc85f..b214eb6 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -114,6 +114,7 @@
class WebRtcSession : public cricket::BaseSession,
public AudioProviderInterface,
+ public DataChannelFactory,
public VideoProviderInterface,
public DtmfProviderInterface,
public DataChannelProviderInterface {
@@ -121,7 +122,8 @@
WebRtcSession(cricket::ChannelManager* channel_manager,
rtc::Thread* signaling_thread,
rtc::Thread* worker_thread,
- cricket::PortAllocator* port_allocator);
+ cricket::PortAllocator* port_allocator,
+ MediaStreamSignaling* mediastream_signaling);
virtual ~WebRtcSession();
bool Initialize(
@@ -147,6 +149,10 @@
return data_channel_.get();
}
+ virtual const MediaStreamSignaling* mediastream_signaling() const {
+ return mediastream_signaling_;
+ }
+
void SetSdesPolicy(cricket::SecurePolicy secure_policy);
cricket::SecurePolicy SdesPolicy() const;
@@ -159,11 +165,9 @@
void CreateOffer(
CreateSessionDescriptionObserver* observer,
- const PeerConnectionInterface::RTCOfferAnswerOptions& options,
- const cricket::MediaSessionOptions& session_options);
+ const PeerConnectionInterface::RTCOfferAnswerOptions& options);
void CreateAnswer(CreateSessionDescriptionObserver* observer,
- const MediaConstraintsInterface* constraints,
- const cricket::MediaSessionOptions& session_options);
+ const MediaConstraintsInterface* constraints);
// The ownership of |desc| will be transferred after this call.
bool SetLocalDescription(SessionDescriptionInterface* desc,
std::string* err_desc);
@@ -247,6 +251,11 @@
virtual bool GetRemoteSSLCertificate(const std::string& transport_name,
rtc::SSLCertificate** cert);
+ // Implements DataChannelFactory.
+ rtc::scoped_refptr<DataChannel> CreateDataChannel(
+ const std::string& label,
+ const InternalDataChannelInit* config) override;
+
cricket::DataChannelType data_channel_type() const;
bool IceRestartPending() const;
@@ -268,20 +277,6 @@
metrics_observer_ = metrics_observer;
}
- // Called when voice_channel_, video_channel_ and data_channel_ are created
- // and destroyed. As a result of, for example, setting a new description.
- sigslot::signal0<> SignalVoiceChannelCreated;
- sigslot::signal0<> SignalVoiceChannelDestroyed;
- sigslot::signal0<> SignalVideoChannelCreated;
- sigslot::signal0<> SignalVideoChannelDestroyed;
- sigslot::signal0<> SignalDataChannelCreated;
- sigslot::signal0<> SignalDataChannelDestroyed;
-
- // Called when a valid data channel OPEN message is received.
- // std::string represents the data channel label.
- sigslot::signal2<const std::string&, const InternalDataChannelInit&>
- SignalDataChannelOpenMessage;
-
private:
// Indicates the type of SessionDescription in a call to SetLocalDescription
// and SetRemoteDescription.
@@ -391,6 +386,7 @@
rtc::scoped_ptr<cricket::VideoChannel> video_channel_;
rtc::scoped_ptr<cricket::DataChannel> data_channel_;
cricket::ChannelManager* channel_manager_;
+ MediaStreamSignaling* mediastream_signaling_;
IceObserver* ice_observer_;
PeerConnectionInterface::IceConnectionState ice_connection_state_;
bool ice_connection_receiving_;
@@ -414,6 +410,10 @@
rtc::scoped_ptr<WebRtcSessionDescriptionFactory>
webrtc_session_desc_factory_;
+ sigslot::signal0<> SignalVoiceChannelDestroyed;
+ sigslot::signal0<> SignalVideoChannelDestroyed;
+ sigslot::signal0<> SignalDataChannelDestroyed;
+
// Member variables for caching global options.
cricket::AudioOptions audio_options_;
cricket::VideoOptions video_options_;
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc
index f0558ee..a463ba9 100644
--- a/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -31,13 +31,11 @@
#include "talk/app/webrtc/fakemetricsobserver.h"
#include "talk/app/webrtc/jsepicecandidate.h"
#include "talk/app/webrtc/jsepsessiondescription.h"
-#include "talk/app/webrtc/peerconnection.h"
#include "talk/app/webrtc/mediastreamsignaling.h"
-#include "talk/app/webrtc/sctputils.h"
-#include "talk/app/webrtc/streamcollection.h"
#include "talk/app/webrtc/streamcollection.h"
#include "talk/app/webrtc/test/fakeconstraints.h"
#include "talk/app/webrtc/test/fakedtlsidentitystore.h"
+#include "talk/app/webrtc/test/fakemediastreamsignaling.h"
#include "talk/app/webrtc/videotrack.h"
#include "talk/app/webrtc/webrtcsession.h"
#include "talk/app/webrtc/webrtcsessiondescriptionfactory.h"
@@ -81,12 +79,10 @@
using webrtc::CreateSessionDescription;
using webrtc::CreateSessionDescriptionObserver;
using webrtc::CreateSessionDescriptionRequest;
-using webrtc::DataChannel;
using webrtc::DtlsIdentityStoreInterface;
using webrtc::FakeConstraints;
using webrtc::FakeMetricsObserver;
using webrtc::IceCandidateCollection;
-using webrtc::InternalDataChannelInit;
using webrtc::JsepIceCandidate;
using webrtc::JsepSessionDescription;
using webrtc::PeerConnectionFactoryInterface;
@@ -161,14 +157,6 @@
"a=rtpmap:96 rtx/90000\r\n"
"a=fmtp:96 apt=0\r\n";
-static const char kStream1[] = "stream1";
-static const char kVideoTrack1[] = "video1";
-static const char kAudioTrack1[] = "audio1";
-
-static const char kStream2[] = "stream2";
-static const char kVideoTrack2[] = "video2";
-static const char kAudioTrack2[] = "audio2";
-
enum RTCCertificateGenerationMethod { ALREADY_GENERATED, DTLS_IDENTITY_STORE };
// Add some extra |newlines| to the |message| after |line|.
@@ -249,8 +237,10 @@
rtc::Thread* signaling_thread,
rtc::Thread* worker_thread,
cricket::PortAllocator* port_allocator,
- webrtc::IceObserver* ice_observer)
- : WebRtcSession(cmgr, signaling_thread, worker_thread, port_allocator) {
+ webrtc::IceObserver* ice_observer,
+ webrtc::MediaStreamSignaling* mediastream_signaling)
+ : WebRtcSession(cmgr, signaling_thread, worker_thread, port_allocator,
+ mediastream_signaling) {
RegisterIceObserver(ice_observer);
}
virtual ~WebRtcSessionForTest() {}
@@ -354,8 +344,7 @@
};
class WebRtcSessionTest
- : public testing::TestWithParam<RTCCertificateGenerationMethod>,
- public sigslot::has_slots<> {
+ : public testing::TestWithParam<RTCCertificateGenerationMethod> {
protected:
// TODO Investigate why ChannelManager crashes, if it's created
// after stun_server.
@@ -377,6 +366,7 @@
stun_server_(cricket::TestStunServer::Create(Thread::Current(),
stun_socket_addr_)),
turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr),
+ mediastream_signaling_(channel_manager_.get()),
metrics_observer_(new rtc::RefCountedObject<FakeMetricsObserver>()) {
cricket::ServerAddresses stun_servers;
stun_servers.insert(stun_socket_addr_);
@@ -405,10 +395,10 @@
const PeerConnectionInterface::RTCConfiguration& rtc_configuration) {
ASSERT_TRUE(session_.get() == NULL);
session_.reset(new WebRtcSessionForTest(
- channel_manager_.get(), rtc::Thread::Current(), rtc::Thread::Current(),
- allocator_.get(), &observer_));
- session_->SignalDataChannelOpenMessage.connect(
- this, &WebRtcSessionTest::OnDataChannelOpenMessage);
+ channel_manager_.get(), rtc::Thread::Current(),
+ rtc::Thread::Current(), allocator_.get(),
+ &observer_,
+ &mediastream_signaling_));
EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
observer_.ice_connection_state_);
@@ -421,12 +411,6 @@
session_->set_metrics_observer(metrics_observer_);
}
- void OnDataChannelOpenMessage(const std::string& label,
- const InternalDataChannelInit& config) {
- last_data_channel_label_ = label;
- last_data_channel_config_ = config;
- }
-
void Init() {
PeerConnectionInterface::RTCConfiguration configuration;
Init(nullptr, configuration);
@@ -490,97 +474,8 @@
Init();
}
- void SendAudioVideoStream1() {
- send_stream_1_ = true;
- send_stream_2_ = false;
- send_audio_ = true;
- send_video_ = true;
- }
-
- void SendAudioVideoStream2() {
- send_stream_1_ = false;
- send_stream_2_ = true;
- send_audio_ = true;
- send_video_ = true;
- }
-
- void SendAudioVideoStream1And2() {
- send_stream_1_ = true;
- send_stream_2_ = true;
- send_audio_ = true;
- send_video_ = true;
- }
-
- void SendNothing() {
- send_stream_1_ = false;
- send_stream_2_ = false;
- send_audio_ = false;
- send_video_ = false;
- }
-
- void SendAudioOnlyStream2() {
- send_stream_1_ = false;
- send_stream_2_ = true;
- send_audio_ = true;
- send_video_ = false;
- }
-
- void SendVideoOnlyStream2() {
- send_stream_1_ = false;
- send_stream_2_ = true;
- send_audio_ = false;
- send_video_ = true;
- }
-
- void AddStreamsToOptions(cricket::MediaSessionOptions* session_options) {
- if (send_stream_1_ && send_audio_) {
- session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack1,
- kStream1);
- }
- if (send_stream_1_ && send_video_) {
- session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack1,
- kStream1);
- }
- if (send_stream_2_ && send_audio_) {
- session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack2,
- kStream2);
- }
- if (send_stream_2_ && send_video_) {
- session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack2,
- kStream2);
- }
- if (data_channel_ && session_->data_channel_type() == cricket::DCT_RTP) {
- session_options->AddSendStream(cricket::MEDIA_TYPE_DATA,
- data_channel_->label(),
- data_channel_->label());
- }
- }
-
- void GetOptionsForOffer(
- const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
- cricket::MediaSessionOptions* session_options) {
- AddStreamsToOptions(session_options);
- ASSERT_TRUE(ConvertRtcOptionsForOffer(rtc_options, session_options));
-
- if (session_->data_channel_type() == cricket::DCT_SCTP && data_channel_) {
- session_options->data_channel_type = cricket::DCT_SCTP;
- }
- }
-
- void GetOptionsForAnswer(const webrtc::MediaConstraintsInterface* constraints,
- cricket::MediaSessionOptions* session_options) {
- AddStreamsToOptions(session_options);
- session_options->recv_audio = false;
- session_options->recv_video = false;
- ASSERT_TRUE(ParseConstraintsForAnswer(constraints, session_options));
-
- if (session_->data_channel_type() == cricket::DCT_SCTP) {
- session_options->data_channel_type = cricket::DCT_SCTP;
- }
- }
-
- // Creates a local offer and applies it. Starts ICE.
- // Call SendAudioVideoStreamX() before this function
+ // Creates a local offer and applies it. Starts ice.
+ // Call mediastream_signaling_.UseOptionsWithStreamX() before this function
// to decide which streams to create.
void InitiateCall() {
SessionDescriptionInterface* offer = CreateOffer();
@@ -602,9 +497,7 @@
const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest>
observer = new WebRtcSessionCreateSDPObserverForTest();
- cricket::MediaSessionOptions session_options;
- GetOptionsForOffer(options, &session_options);
- session_->CreateOffer(observer, options, session_options);
+ session_->CreateOffer(observer, options);
EXPECT_TRUE_WAIT(
observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit,
2000);
@@ -615,9 +508,7 @@
const webrtc::MediaConstraintsInterface* constraints) {
rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> observer
= new WebRtcSessionCreateSDPObserverForTest();
- cricket::MediaSessionOptions session_options;
- GetOptionsForAnswer(constraints, &session_options);
- session_->CreateAnswer(observer, constraints, session_options);
+ session_->CreateAnswer(observer, constraints);
EXPECT_TRUE_WAIT(
observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit,
2000);
@@ -747,7 +638,7 @@
value_set);
session_.reset();
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
@@ -844,7 +735,7 @@
// Creates a remote offer and and applies it as a remote description,
// creates a local answer and applies is as a local description.
- // Call SendAudioVideoStreamX() before this function
+ // Call mediastream_signaling_.UseOptionsWithStreamX() before this function
// to decide which local and remote streams to create.
void CreateAndSetRemoteOfferAndLocalAnswer() {
SessionDescriptionInterface* offer = CreateRemoteOffer();
@@ -1020,11 +911,11 @@
return offer;
}
- // Create a remote offer. Call SendAudioVideoStreamX()
+ // Create a remote offer. Call mediastream_signaling_.UseOptionsWithStreamX()
// before this function to decide which streams to create.
JsepSessionDescription* CreateRemoteOffer() {
cricket::MediaSessionOptions options;
- GetOptionsForAnswer(NULL, &options);
+ mediastream_signaling_.GetOptionsForAnswer(NULL, &options);
return CreateRemoteOffer(options, session_->remote_description());
}
@@ -1052,20 +943,21 @@
return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED);
}
- // Creates an answer session description.
- // Call SendAudioVideoStreamX() before this function
+ // Creates an answer session description with streams based on
+ // |mediastream_signaling_|. Call
+ // mediastream_signaling_.UseOptionsWithStreamX() before this function
// to decide which streams to create.
JsepSessionDescription* CreateRemoteAnswer(
const SessionDescriptionInterface* offer) {
cricket::MediaSessionOptions options;
- GetOptionsForAnswer(NULL, &options);
+ mediastream_signaling_.GetOptionsForAnswer(NULL, &options);
return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED);
}
void TestSessionCandidatesWithBundleRtcpMux(bool bundle, bool rtcp_mux) {
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = bundle;
@@ -1113,7 +1005,7 @@
} else {
Init();
}
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
EXPECT_FALSE(session_->CanInsertDtmf(""));
EXPECT_EQ(can, session_->CanInsertDtmf(kAudioTrack1));
@@ -1229,7 +1121,7 @@
void TestLoopbackCall(const LoopbackNetworkConfiguration& config) {
LoopbackNetworkManager loopback_network_manager(this, config);
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
@@ -1326,15 +1218,10 @@
return true;
}
- void CreateDataChannel() {
- webrtc::InternalDataChannelInit dci;
- dci.reliable = session_->data_channel_type() == cricket::DCT_SCTP;
- data_channel_ = DataChannel::Create(
- session_.get(), session_->data_channel_type(), "datachannel", dci);
- }
-
void SetLocalDescriptionWithDataChannel() {
- CreateDataChannel();
+ webrtc::InternalDataChannelInit dci;
+ dci.reliable = false;
+ session_->CreateDataChannel("datachannel", &dci);
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
}
@@ -1365,16 +1252,15 @@
}
PeerConnectionInterface::RTCOfferAnswerOptions options;
- cricket::MediaSessionOptions session_options;
const int kNumber = 3;
rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest>
observers[kNumber];
for (int i = 0; i < kNumber; ++i) {
observers[i] = new WebRtcSessionCreateSDPObserverForTest();
if (type == CreateSessionDescriptionRequest::kOffer) {
- session_->CreateOffer(observers[i], options, session_options);
+ session_->CreateOffer(observers[i], options);
} else {
- session_->CreateAnswer(observers[i], nullptr, session_options);
+ session_->CreateAnswer(observers[i], NULL);
}
}
@@ -1419,20 +1305,12 @@
rtc::scoped_ptr<cricket::BasicPortAllocator> allocator_;
PeerConnectionFactoryInterface::Options options_;
rtc::scoped_ptr<FakeConstraints> constraints_;
+ FakeMediaStreamSignaling mediastream_signaling_;
rtc::scoped_ptr<WebRtcSessionForTest> session_;
MockIceObserver observer_;
cricket::FakeVideoMediaChannel* video_channel_;
cricket::FakeVoiceMediaChannel* voice_channel_;
rtc::scoped_refptr<FakeMetricsObserver> metrics_observer_;
- // The following flags affect options created for CreateOffer/CreateAnswer.
- bool send_stream_1_ = false;
- bool send_stream_2_ = false;
- bool send_audio_ = false;
- bool send_video_ = false;
- rtc::scoped_refptr<DataChannel> data_channel_;
- // Last values received from data channel creation signal.
- std::string last_data_channel_label_;
- InternalDataChannelInit last_data_channel_config_;
};
TEST_P(WebRtcSessionTest, TestInitializeWithDtls) {
@@ -1465,7 +1343,7 @@
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
AddInterface(rtc::SocketAddress(kClientAddrHost2, kClientAddrPort));
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
InitiateCall();
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
EXPECT_EQ(8u, observer_.mline_0_candidates_.size());
@@ -1480,7 +1358,7 @@
rtc::FD_ANY,
rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
InitiateCall();
// Since kClientAddrHost1 is blocked, not expecting stun candidates for it.
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
@@ -1492,7 +1370,7 @@
TEST_F(WebRtcSessionTest, TestIceTransportsNone) {
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
InitWithIceTransport(PeerConnectionInterface::kNone);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
InitiateCall();
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
EXPECT_EQ(0u, observer_.mline_0_candidates_.size());
@@ -1505,7 +1383,7 @@
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
ConfigureAllocatorWithTurn();
InitWithIceTransport(PeerConnectionInterface::kRelay);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
InitiateCall();
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
EXPECT_EQ(2u, observer_.mline_0_candidates_.size());
@@ -1524,7 +1402,7 @@
TEST_F(WebRtcSessionTest, TestIceTransportsAll) {
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
InitWithIceTransport(PeerConnectionInterface::kAll);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
InitiateCall();
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
// Host + STUN. By default allocator is disabled to gather relay candidates.
@@ -1545,13 +1423,13 @@
// media engine creates the expected send and receive streams.
TEST_F(WebRtcSessionTest, TestCreateSdesOfferReceiveSdesAnswer) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
const std::string session_id_orig = offer->session_id();
const std::string session_version_orig = offer->session_version();
SetLocalDescriptionWithoutError(offer);
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -1571,7 +1449,7 @@
EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id);
// Create new offer without send streams.
- SendNothing();
+ mediastream_signaling_.SendNothing();
offer = CreateOffer();
// Verify the session id is the same and the session version is
@@ -1584,7 +1462,7 @@
EXPECT_EQ(0u, video_channel_->send_streams().size());
EXPECT_EQ(0u, voice_channel_->send_streams().size());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
answer = CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -1599,12 +1477,12 @@
// media engine creates the expected send and receive streams.
TEST_F(WebRtcSessionTest, TestReceiveSdesOfferCreateSdesAnswer) {
Init();
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* offer = CreateOffer();
VerifyCryptoParams(offer->description());
SetRemoteDescriptionWithoutError(offer);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* answer = CreateAnswer(NULL);
VerifyCryptoParams(answer->description());
SetLocalDescriptionWithoutError(answer);
@@ -1626,12 +1504,12 @@
ASSERT_EQ(1u, voice_channel_->send_streams().size());
EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id);
- SendAudioVideoStream1And2();
+ mediastream_signaling_.SendAudioVideoStream1And2();
offer = CreateOffer();
SetRemoteDescriptionWithoutError(offer);
// Answer by turning off all send streams.
- SendNothing();
+ mediastream_signaling_.SendNothing();
answer = CreateAnswer(NULL);
// Verify the session id is the same and the session version is
@@ -1745,7 +1623,7 @@
// and that we return an answer with a DTLS fingerprint.
TEST_P(WebRtcSessionTest, TestReceiveDtlsOfferCreateDtlsAnswer) {
MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
InitWithDtls(GetParam());
SetFactoryDtlsSrtp();
cricket::MediaSessionOptions options;
@@ -1774,7 +1652,7 @@
// and then we accept a remote answer with a DTLS fingerprint successfully.
TEST_P(WebRtcSessionTest, TestCreateDtlsOfferReceiveDtlsAnswer) {
MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
InitWithDtls(GetParam());
SetFactoryDtlsSrtp();
@@ -1863,7 +1741,7 @@
// Test that we create a local offer without SDES or DTLS and accept a remote
// answer without SDES or DTLS when encryption is disabled.
TEST_P(WebRtcSessionTest, TestCreateOfferReceiveAnswerWithoutEncryption) {
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
options_.disable_encryption = true;
InitWithDtls(GetParam());
@@ -1919,7 +1797,7 @@
TEST_F(WebRtcSessionTest, TestSetLocalOfferTwice) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
// SetLocalDescription take ownership of offer.
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
@@ -1931,7 +1809,7 @@
TEST_F(WebRtcSessionTest, TestSetRemoteOfferTwice) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
// SetLocalDescription take ownership of offer.
SessionDescriptionInterface* offer = CreateOffer();
SetRemoteDescriptionWithoutError(offer);
@@ -1942,7 +1820,7 @@
TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteOffer) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
offer = CreateOffer();
@@ -1952,7 +1830,7 @@
TEST_F(WebRtcSessionTest, TestSetRemoteAndLocalOffer) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
SessionDescriptionInterface* offer = CreateOffer();
SetRemoteDescriptionWithoutError(offer);
offer = CreateOffer();
@@ -1962,7 +1840,7 @@
TEST_F(WebRtcSessionTest, TestSetLocalPrAnswer) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
SessionDescriptionInterface* offer = CreateRemoteOffer();
SetRemoteDescriptionExpectState(offer, BaseSession::STATE_RECEIVEDINITIATE);
@@ -1971,21 +1849,21 @@
pranswer->set_type(SessionDescriptionInterface::kPrAnswer);
SetLocalDescriptionExpectState(pranswer, BaseSession::STATE_SENTPRACCEPT);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
JsepSessionDescription* pranswer2 = static_cast<JsepSessionDescription*>(
CreateAnswer(NULL));
pranswer2->set_type(SessionDescriptionInterface::kPrAnswer);
SetLocalDescriptionExpectState(pranswer2, BaseSession::STATE_SENTPRACCEPT);
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer = CreateAnswer(NULL);
SetLocalDescriptionExpectState(answer, BaseSession::STATE_SENTACCEPT);
}
TEST_F(WebRtcSessionTest, TestSetRemotePrAnswer) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionExpectState(offer, BaseSession::STATE_SENTINITIATE);
@@ -1996,7 +1874,7 @@
SetRemoteDescriptionExpectState(pranswer,
BaseSession::STATE_RECEIVEDPRACCEPT);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
JsepSessionDescription* pranswer2 =
CreateRemoteAnswer(session_->local_description());
pranswer2->set_type(SessionDescriptionInterface::kPrAnswer);
@@ -2004,7 +1882,7 @@
SetRemoteDescriptionExpectState(pranswer2,
BaseSession::STATE_RECEIVEDPRACCEPT);
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionExpectState(answer, BaseSession::STATE_RECEIVEDACCEPT);
@@ -2012,7 +1890,7 @@
TEST_F(WebRtcSessionTest, TestSetLocalAnswerWithoutOffer) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
SessionDescriptionInterface* answer =
@@ -2023,7 +1901,7 @@
TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithoutOffer) {
Init();
- SendNothing();
+ mediastream_signaling_.SendNothing();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
SessionDescriptionInterface* answer =
@@ -2034,7 +1912,7 @@
TEST_F(WebRtcSessionTest, TestAddRemoteCandidate) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
cricket::Candidate candidate;
candidate.set_component(1);
@@ -2087,7 +1965,7 @@
candidate1.set_component(1);
JsepIceCandidate ice_candidate1(kMediaContentName0, kMediaContentIndex0,
candidate1);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1));
@@ -2136,7 +2014,7 @@
TEST_F(WebRtcSessionTest, TestLocalCandidatesAddedToSessionDescription) {
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
const SessionDescriptionInterface* local_desc = session_->local_description();
@@ -2156,7 +2034,7 @@
EXPECT_EQ(0u, candidates->count());
// Update the session descriptions.
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
local_desc = session_->local_description();
@@ -2176,7 +2054,7 @@
candidate1.set_component(1);
JsepIceCandidate ice_candidate(kMediaContentName0, kMediaContentIndex0,
candidate1);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
EXPECT_TRUE(offer->AddCandidate(&ice_candidate));
@@ -2200,7 +2078,7 @@
TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteDescriptionWithCandidates) {
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
// Ice is started but candidates are not provided until SetLocalDescription
// is called.
EXPECT_EQ(0u, observer_.mline_0_candidates_.size());
@@ -2227,7 +2105,7 @@
// present in the SessionDescription.
TEST_F(WebRtcSessionTest, TestChannelCreationsWithContentNames) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
// CreateOffer creates session description with the content names "audio" and
@@ -2292,7 +2170,7 @@
TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraints) {
Init();
// Test Audio only offer.
- SendAudioOnlyStream2();
+ mediastream_signaling_.UseOptionsAudioOnly();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
const cricket::ContentInfo* content =
@@ -2302,7 +2180,7 @@
EXPECT_TRUE(content == NULL);
// Test Audio / Video offer.
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
offer.reset(CreateOffer());
content = cricket::GetFirstAudioContent(offer->description());
EXPECT_TRUE(content != NULL);
@@ -2441,7 +2319,7 @@
rtc::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
SetRemoteDescriptionWithoutError(offer.release());
// Test with a stream with tracks.
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> answer(
CreateAnswer(NULL));
const cricket::ContentInfo* content =
@@ -2491,7 +2369,7 @@
constraints_no_receive.SetMandatoryReceiveVideo(false);
// Test with a stream with tracks.
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> answer(
CreateAnswer(&constraints_no_receive));
@@ -2548,7 +2426,7 @@
EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL);
EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
cricket::MediaSessionOptions options;
@@ -2569,7 +2447,7 @@
EXPECT_EQ(kAudioTrack1, voice_channel_->send_streams()[0].id);
// Let the remote end update the session descriptions, with Audio and Video.
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
CreateAndSetRemoteOfferAndLocalAnswer();
video_channel_ = media_engine_->GetVideoChannel(0);
@@ -2588,7 +2466,7 @@
EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
// Change session back to audio only.
- SendAudioOnlyStream2();
+ mediastream_signaling_.UseOptionsAudioOnly();
CreateAndSetRemoteOfferAndLocalAnswer();
EXPECT_EQ(0u, video_channel_->recv_streams().size());
@@ -2604,7 +2482,7 @@
Init();
EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL);
EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
cricket::MediaSessionOptions options;
@@ -2629,7 +2507,7 @@
EXPECT_EQ(kVideoTrack1, video_channel_->send_streams()[0].id);
// Update the session descriptions, with Audio and Video.
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
CreateAndSetRemoteOfferAndLocalAnswer();
voice_channel_ = media_engine_->GetVoiceChannel(0);
@@ -2641,7 +2519,7 @@
EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
// Change session back to video only.
- SendVideoOnlyStream2();
+ mediastream_signaling_.UseOptionsVideoOnly();
CreateAndSetRemoteOfferAndLocalAnswer();
video_channel_ = media_engine_->GetVideoChannel(0);
@@ -2655,7 +2533,7 @@
TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDP) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
VerifyCryptoParams(offer->description());
SetRemoteDescriptionWithoutError(offer.release());
@@ -2666,7 +2544,7 @@
TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) {
options_.disable_encryption = true;
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
VerifyNoCryptoParams(offer->description(), false);
}
@@ -2685,7 +2563,7 @@
// no a=ice-ufrag and a=ice-pwd lines are present in the SDP.
TEST_F(WebRtcSessionTest, TestSetLocalDescriptionWithoutIce) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
std::string sdp;
@@ -2711,7 +2589,7 @@
// too short ice ufrag and pwd strings.
TEST_F(WebRtcSessionTest, TestSetLocalDescriptionInvalidIceCredentials) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
std::string sdp;
@@ -2817,7 +2695,7 @@
AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -2900,7 +2778,7 @@
// kBundlePolicyBalanced BUNDLE policy and answer contains BUNDLE.
TEST_F(WebRtcSessionTest, TestBalancedBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -2911,7 +2789,7 @@
EXPECT_NE(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -2923,7 +2801,7 @@
// kBundlePolicyBalanced BUNDLE policy but no BUNDLE in the answer.
TEST_F(WebRtcSessionTest, TestBalancedNoBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -2934,7 +2812,7 @@
EXPECT_NE(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
// Remove BUNDLE from the answer.
rtc::scoped_ptr<SessionDescriptionInterface> answer(
@@ -2953,7 +2831,7 @@
// kBundlePolicyMaxBundle policy with BUNDLE in the answer.
TEST_F(WebRtcSessionTest, TestMaxBundleBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -2964,7 +2842,7 @@
EXPECT_EQ(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -2977,7 +2855,7 @@
// audio content in the answer.
TEST_F(WebRtcSessionTest, TestMaxBundleRejectAudio) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -2988,7 +2866,7 @@
EXPECT_EQ(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
cricket::MediaSessionOptions recv_options;
recv_options.recv_audio = false;
recv_options.recv_video = true;
@@ -3009,7 +2887,7 @@
// kBundlePolicyMaxBundle policy but no BUNDLE in the answer.
TEST_F(WebRtcSessionTest, TestMaxBundleNoBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -3020,7 +2898,7 @@
EXPECT_EQ(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
// Remove BUNDLE from the answer.
rtc::scoped_ptr<SessionDescriptionInterface> answer(
@@ -3039,7 +2917,7 @@
// kBundlePolicyMaxBundle policy with BUNDLE in the remote offer.
TEST_F(WebRtcSessionTest, TestMaxBundleBundleInRemoteOffer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateRemoteOffer();
SetRemoteDescriptionWithoutError(offer);
@@ -3047,7 +2925,7 @@
EXPECT_EQ(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer = CreateAnswer(nullptr);
SetLocalDescriptionWithoutError(answer);
@@ -3058,7 +2936,7 @@
// kBundlePolicyMaxBundle policy but no BUNDLE in the remote offer.
TEST_F(WebRtcSessionTest, TestMaxBundleNoBundleInRemoteOffer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
// Remove BUNDLE from the offer.
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer());
@@ -3076,7 +2954,7 @@
// kBundlePolicyMaxCompat bundle policy and answer contains BUNDLE.
TEST_F(WebRtcSessionTest, TestMaxCompatBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxCompat);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -3087,7 +2965,7 @@
EXPECT_NE(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -3101,7 +2979,7 @@
// kBundlePolicyMaxCompat BUNDLE policy but no BUNDLE in the answer.
TEST_F(WebRtcSessionTest, TestMaxCompatNoBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxCompat);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -3111,7 +2989,7 @@
EXPECT_NE(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
// Remove BUNDLE from the answer.
rtc::scoped_ptr<SessionDescriptionInterface> answer(
@@ -3130,7 +3008,7 @@
// kBundlePolicyMaxbundle and then we call SetRemoteDescription first.
TEST_F(WebRtcSessionTest, TestMaxBundleWithSetRemoteDescriptionFirst) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -3144,7 +3022,7 @@
TEST_F(WebRtcSessionTest, TestRequireRtcpMux) {
InitWithRtcpMuxPolicy(PeerConnectionInterface::kRtcpMuxPolicyRequire);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
SessionDescriptionInterface* offer = CreateOffer(options);
@@ -3153,7 +3031,7 @@
EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL);
EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL);
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -3164,7 +3042,7 @@
TEST_F(WebRtcSessionTest, TestNegotiateRtcpMux) {
InitWithRtcpMuxPolicy(PeerConnectionInterface::kRtcpMuxPolicyNegotiate);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
SessionDescriptionInterface* offer = CreateOffer(options);
@@ -3173,7 +3051,7 @@
EXPECT_TRUE(session_->voice_rtcp_transport_channel() != NULL);
EXPECT_TRUE(session_->video_rtcp_transport_channel() != NULL);
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -3186,7 +3064,7 @@
// if BUNDLE is enabled but rtcp-mux is disabled in m-lines.
TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -3214,7 +3092,7 @@
TEST_F(WebRtcSessionTest, SetAudioPlayout) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
ASSERT_TRUE(channel != NULL);
@@ -3233,7 +3111,7 @@
TEST_F(WebRtcSessionTest, SetAudioSend) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
ASSERT_TRUE(channel != NULL);
@@ -3261,7 +3139,7 @@
TEST_F(WebRtcSessionTest, AudioRendererForLocalStream) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
ASSERT_TRUE(channel != NULL);
@@ -3284,7 +3162,7 @@
TEST_F(WebRtcSessionTest, SetVideoPlayout) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0);
ASSERT_TRUE(channel != NULL);
@@ -3301,7 +3179,7 @@
TEST_F(WebRtcSessionTest, SetVideoSend) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0);
ASSERT_TRUE(channel != NULL);
@@ -3326,7 +3204,7 @@
TEST_F(WebRtcSessionTest, InsertDtmf) {
// Setup
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
CreateAndSetRemoteOfferAndLocalAnswer();
FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0);
EXPECT_EQ(0U, channel->dtmf_info_queue().size());
@@ -3377,7 +3255,7 @@
// Verifing local offer and remote answer have matching m-lines as per RFC 3264.
TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
rtc::scoped_ptr<SessionDescriptionInterface> answer(
@@ -3425,7 +3303,7 @@
// RFC 3264.
TEST_F(WebRtcSessionTest, TestIncorrectMLinesInLocalAnswer) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateRemoteOffer();
SetRemoteDescriptionWithoutError(offer);
SessionDescriptionInterface* answer = CreateAnswer(NULL);
@@ -3446,7 +3324,7 @@
// before SetLocalDescription is called.
TEST_F(WebRtcSessionTest, TestIceStartAfterSetLocalDescriptionOnly) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateRemoteOffer();
cricket::Candidate candidate;
candidate.set_component(1);
@@ -3476,7 +3354,7 @@
// description as per security policy set in MediaSessionDescriptionFactory.
TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescription) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
// Making sure SetLocalDescription correctly sets crypto value in
@@ -3495,7 +3373,7 @@
TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) {
options_.disable_encryption = true;
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
// Making sure SetLocalDescription correctly sets crypto value in
@@ -3520,7 +3398,7 @@
CreateRemoteOffer(options));
SetRemoteDescriptionWithoutError(offer.release());
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> answer(
CreateAnswer(NULL));
SetLocalDescriptionWithoutError(answer.release());
@@ -3551,7 +3429,7 @@
CreateRemoteOffer(options));
SetRemoteDescriptionWithoutError(offer.release());
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> answer(
CreateAnswer(NULL));
SetLocalDescriptionWithoutError(answer.release());
@@ -3574,7 +3452,7 @@
TEST_F(WebRtcSessionTest, TestSessionContentError) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
const std::string session_id_orig = offer->session_id();
const std::string session_version_orig = offer->session_version();
@@ -3583,7 +3461,7 @@
video_channel_ = media_engine_->GetVideoChannel(0);
video_channel_->set_fail_set_send_codecs(true);
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionAnswerExpectError("ERROR_CONTENT", answer);
@@ -3751,8 +3629,11 @@
// TEST PLAN: Set the port number to something new, set it in the SDP,
// and pass it all the way down.
+ webrtc::InternalDataChannelInit dci;
+ dci.reliable = true;
EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
- CreateDataChannel();
+ rtc::scoped_refptr<webrtc::DataChannel> dc =
+ session_->CreateDataChannel("datachannel", &dci);
cricket::FakeDataMediaChannel* ch = data_engine_->GetChannel(0);
int portnum = -1;
@@ -3774,36 +3655,7 @@
EXPECT_EQ(new_recv_port, portnum);
}
-// Verifies that when a session's DataChannel receives an OPEN message,
-// WebRtcSession signals the DataChannel creation request with the expected
-// config.
-TEST_P(WebRtcSessionTest, TestSctpDataChannelOpenMessage) {
- MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
-
- InitWithDtls(GetParam());
-
- SetLocalDescriptionWithDataChannel();
- EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
-
- webrtc::DataChannelInit config;
- config.id = 1;
- rtc::Buffer payload;
- webrtc::WriteDataChannelOpenMessage("a", config, &payload);
- cricket::ReceiveDataParams params;
- params.ssrc = config.id;
- params.type = cricket::DMT_CONTROL;
-
- cricket::DataChannel* data_channel = session_->data_channel();
- data_channel->SignalDataReceived(data_channel, params, payload);
-
- EXPECT_EQ("a", last_data_channel_label_);
- EXPECT_EQ(config.id, last_data_channel_config_.id);
- EXPECT_FALSE(last_data_channel_config_.negotiated);
- EXPECT_EQ(webrtc::InternalDataChannelInit::kAcker,
- last_data_channel_config_.open_handshake_role);
-}
-
-TEST_P(WebRtcSessionTest, TestUsesProvidedCertificate) {
+TEST_F(WebRtcSessionTest, TestUsesProvidedCertificate) {
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
FakeDtlsIdentityStore::GenerateCertificate();
@@ -3823,7 +3675,7 @@
InitWithDtls(GetParam());
EXPECT_TRUE(session_->waiting_for_certificate_for_testing());
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer());
EXPECT_TRUE(offer != NULL);
@@ -3940,7 +3792,7 @@
constraints_->AddOptional(
webrtc::MediaConstraintsInterface::kEnableDscp, true);
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
@@ -3964,7 +3816,7 @@
webrtc::MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate,
true);
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
@@ -3992,7 +3844,7 @@
webrtc::MediaConstraintsInterface::kCombinedAudioVideoBwe,
true);
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
@@ -4012,7 +3864,7 @@
InitWithDtls(GetParam());
SetFactoryDtlsSrtp();
- SendAudioOnlyStream2();
+ mediastream_signaling_.UseOptionsAudioOnly();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
@@ -4042,7 +3894,7 @@
InitWithDtls(GetParam());
SetFactoryDtlsSrtp();
- SendAudioOnlyStream2();
+ mediastream_signaling_.UseOptionsAudioOnly();
SessionDescriptionInterface* offer = CreateOffer();
SetLocalDescriptionWithoutError(offer);
@@ -4068,7 +3920,7 @@
// by local side.
TEST_F(WebRtcSessionTest, TestRtxRemovedByCreateAnswer) {
Init();
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
std::string offer_sdp(kSdpWithRtx);
SessionDescriptionInterface* offer =
@@ -4091,7 +3943,7 @@
// and voice channels.
TEST_F(WebRtcSessionTest, TestSetSocketOptionBeforeBundle) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
- SendAudioVideoStream1();
+ mediastream_signaling_.SendAudioVideoStream1();
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.use_rtp_mux = true;
@@ -4121,7 +3973,7 @@
EXPECT_NE(session_->voice_rtp_transport_channel(),
session_->video_rtp_transport_channel());
- SendAudioVideoStream2();
+ mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
@@ -4145,12 +3997,10 @@
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.offer_to_receive_audio =
RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
- cricket::MediaSessionOptions session_options;
- session_options.recv_audio = true;
for (auto& o : observers) {
o = new WebRtcSessionCreateSDPObserverForTest();
- session_->CreateOffer(o, options, session_options);
+ session_->CreateOffer(o, options);
}
session_.reset();
diff --git a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
index d391020..8769315 100644
--- a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
+++ b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
@@ -31,6 +31,7 @@
#include "talk/app/webrtc/jsep.h"
#include "talk/app/webrtc/jsepsessiondescription.h"
#include "talk/app/webrtc/mediaconstraintsinterface.h"
+#include "talk/app/webrtc/mediastreamsignaling.h"
#include "talk/app/webrtc/webrtcsession.h"
#include "webrtc/base/sslidentity.h"
@@ -130,13 +131,16 @@
WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
const rtc::scoped_refptr<WebRtcIdentityRequestObserver>&
identity_request_observer,
WebRtcSession* session,
const std::string& session_id,
+ cricket::DataChannelType dct,
bool dtls_enabled)
: signaling_thread_(signaling_thread),
+ mediastream_signaling_(mediastream_signaling),
session_desc_factory_(channel_manager, &transport_desc_factory_),
// RFC 4566 suggested a Network Time Protocol (NTP) format timestamp
// as the session id and session version. To simplify, it should be fine
@@ -147,6 +151,7 @@
identity_request_observer_(identity_request_observer),
session_(session),
session_id_(session_id),
+ data_channel_type_(dct),
certificate_request_state_(CERTIFICATE_NOT_NEEDED) {
session_desc_factory_.set_add_legacy_streams(false);
// SRTP-SDES is disabled if DTLS is on.
@@ -156,14 +161,18 @@
WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
WebRtcSession* session,
- const std::string& session_id)
+ const std::string& session_id,
+ cricket::DataChannelType dct)
: WebRtcSessionDescriptionFactory(signaling_thread,
channel_manager,
+ mediastream_signaling,
nullptr,
nullptr,
session,
session_id,
+ dct,
false) {
LOG(LS_VERBOSE) << "DTLS-SRTP disabled.";
}
@@ -171,17 +180,21 @@
WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
WebRtcSession* session,
- const std::string& session_id)
+ const std::string& session_id,
+ cricket::DataChannelType dct)
: WebRtcSessionDescriptionFactory(
- signaling_thread,
- channel_manager,
- dtls_identity_store.Pass(),
- new rtc::RefCountedObject<WebRtcIdentityRequestObserver>(),
- session,
- session_id,
- true) {
+ signaling_thread,
+ channel_manager,
+ mediastream_signaling,
+ dtls_identity_store.Pass(),
+ new rtc::RefCountedObject<WebRtcIdentityRequestObserver>(),
+ session,
+ session_id,
+ dct,
+ true) {
RTC_DCHECK(dtls_identity_store_);
certificate_request_state_ = CERTIFICATE_WAITING;
@@ -203,16 +216,14 @@
WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
WebRtcSession* session,
- const std::string& session_id)
- : WebRtcSessionDescriptionFactory(signaling_thread,
- channel_manager,
- nullptr,
- nullptr,
- session,
- session_id,
- true) {
+ const std::string& session_id,
+ cricket::DataChannelType dct)
+ : WebRtcSessionDescriptionFactory(
+ signaling_thread, channel_manager, mediastream_signaling, nullptr,
+ nullptr, session, session_id, dct, true) {
RTC_DCHECK(certificate);
certificate_request_state_ = CERTIFICATE_WAITING;
@@ -253,8 +264,9 @@
void WebRtcSessionDescriptionFactory::CreateOffer(
CreateSessionDescriptionObserver* observer,
- const PeerConnectionInterface::RTCOfferAnswerOptions& options,
- const cricket::MediaSessionOptions& session_options) {
+ const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
+ cricket::MediaSessionOptions session_options;
+
std::string error = "CreateOffer";
if (certificate_request_state_ == CERTIFICATE_FAILED) {
error += kFailedDueToIdentityFailed;
@@ -263,6 +275,14 @@
return;
}
+ if (!mediastream_signaling_->GetOptionsForOffer(options,
+ &session_options)) {
+ error += " called with invalid options.";
+ LOG(LS_ERROR) << error;
+ PostCreateSessionDescriptionFailed(observer, error);
+ return;
+ }
+
if (!ValidStreams(session_options.streams)) {
error += " called with invalid media streams.";
LOG(LS_ERROR) << error;
@@ -270,6 +290,11 @@
return;
}
+ if (data_channel_type_ == cricket::DCT_SCTP &&
+ mediastream_signaling_->HasDataChannels()) {
+ session_options.data_channel_type = cricket::DCT_SCTP;
+ }
+
CreateSessionDescriptionRequest request(
CreateSessionDescriptionRequest::kOffer, observer, session_options);
if (certificate_request_state_ == CERTIFICATE_WAITING) {
@@ -283,8 +308,7 @@
void WebRtcSessionDescriptionFactory::CreateAnswer(
CreateSessionDescriptionObserver* observer,
- const MediaConstraintsInterface* constraints,
- const cricket::MediaSessionOptions& session_options) {
+ const MediaConstraintsInterface* constraints) {
std::string error = "CreateAnswer";
if (certificate_request_state_ == CERTIFICATE_FAILED) {
error += kFailedDueToIdentityFailed;
@@ -306,15 +330,28 @@
return;
}
- if (!ValidStreams(session_options.streams)) {
+ cricket::MediaSessionOptions options;
+ if (!mediastream_signaling_->GetOptionsForAnswer(constraints, &options)) {
+ error += " called with invalid constraints.";
+ LOG(LS_ERROR) << error;
+ PostCreateSessionDescriptionFailed(observer, error);
+ return;
+ }
+ if (!ValidStreams(options.streams)) {
error += " called with invalid media streams.";
LOG(LS_ERROR) << error;
PostCreateSessionDescriptionFailed(observer, error);
return;
}
+ // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
+ // are not signaled in the SDP so does not go through that path and must be
+ // handled here.
+ if (data_channel_type_ == cricket::DCT_SCTP) {
+ options.data_channel_type = cricket::DCT_SCTP;
+ }
CreateSessionDescriptionRequest request(
- CreateSessionDescriptionRequest::kAnswer, observer, session_options);
+ CreateSessionDescriptionRequest::kAnswer, observer, options);
if (certificate_request_state_ == CERTIFICATE_WAITING) {
create_session_description_requests_.push(request);
} else {
diff --git a/talk/app/webrtc/webrtcsessiondescriptionfactory.h b/talk/app/webrtc/webrtcsessiondescriptionfactory.h
index 91adc66..95fab63 100644
--- a/talk/app/webrtc/webrtcsessiondescriptionfactory.h
+++ b/talk/app/webrtc/webrtcsessiondescriptionfactory.h
@@ -43,6 +43,7 @@
namespace webrtc {
class CreateSessionDescriptionObserver;
class MediaConstraintsInterface;
+class MediaStreamSignaling;
class SessionDescriptionInterface;
class WebRtcSession;
@@ -91,26 +92,32 @@
// Construct with DTLS disabled.
WebRtcSessionDescriptionFactory(rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
WebRtcSession* session,
- const std::string& session_id);
+ const std::string& session_id,
+ cricket::DataChannelType dct);
// Construct with DTLS enabled using the specified |dtls_identity_store| to
// generate a certificate.
WebRtcSessionDescriptionFactory(
rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
WebRtcSession* session,
- const std::string& session_id);
+ const std::string& session_id,
+ cricket::DataChannelType dct);
// Construct with DTLS enabled using the specified (already generated)
// |certificate|.
WebRtcSessionDescriptionFactory(
rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
WebRtcSession* session,
- const std::string& session_id);
+ const std::string& session_id,
+ cricket::DataChannelType dct);
virtual ~WebRtcSessionDescriptionFactory();
static void CopyCandidatesFromSessionDescription(
@@ -119,11 +126,10 @@
void CreateOffer(
CreateSessionDescriptionObserver* observer,
- const PeerConnectionInterface::RTCOfferAnswerOptions& options,
- const cricket::MediaSessionOptions& session_options);
- void CreateAnswer(CreateSessionDescriptionObserver* observer,
- const MediaConstraintsInterface* constraints,
- const cricket::MediaSessionOptions& session_options);
+ const PeerConnectionInterface::RTCOfferAnswerOptions& options);
+ void CreateAnswer(
+ CreateSessionDescriptionObserver* observer,
+ const MediaConstraintsInterface* constraints);
void SetSdesPolicy(cricket::SecurePolicy secure_policy);
cricket::SecurePolicy SdesPolicy() const;
@@ -147,11 +153,13 @@
WebRtcSessionDescriptionFactory(
rtc::Thread* signaling_thread,
cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
const rtc::scoped_refptr<WebRtcIdentityRequestObserver>&
identity_request_observer,
WebRtcSession* session,
const std::string& session_id,
+ cricket::DataChannelType dct,
bool dtls_enabled);
// MessageHandler implementation.
@@ -175,6 +183,7 @@
std::queue<CreateSessionDescriptionRequest>
create_session_description_requests_;
rtc::Thread* const signaling_thread_;
+ MediaStreamSignaling* const mediastream_signaling_;
cricket::TransportDescriptionFactory transport_desc_factory_;
cricket::MediaSessionDescriptionFactory session_desc_factory_;
uint64_t session_version_;
@@ -184,6 +193,7 @@
// TODO(jiayl): remove the dependency on session once bug 2264 is fixed.
WebRtcSession* const session_;
const std::string session_id_;
+ const cricket::DataChannelType data_channel_type_;
CertificateRequestState certificate_request_state_;
RTC_DISALLOW_COPY_AND_ASSIGN(WebRtcSessionDescriptionFactory);
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index 2e42047..366267c 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -200,6 +200,7 @@
'app/webrtc/jsepsessiondescription_unittest.cc',
'app/webrtc/localaudiosource_unittest.cc',
'app/webrtc/mediastream_unittest.cc',
+ 'app/webrtc/mediastreamsignaling_unittest.cc',
'app/webrtc/peerconnection_unittest.cc',
'app/webrtc/peerconnectionendtoend_unittest.cc',
'app/webrtc/peerconnectionfactory_unittest.cc',