3
* Copyright 2012, Google Inc.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
8
* 1. Redistributions of source code must retain the above copyright notice,
9
* this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
13
* 3. The name of the author may not be used to endorse or promote products
14
* derived from this software without specific prior written permission.
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
#include "talk/app/webrtc/audiotrack.h"
32
#include "talk/app/webrtc/mediastream.h"
33
#include "talk/app/webrtc/mediastreamsignaling.h"
34
#include "talk/app/webrtc/streamcollectionimpl.h"
35
#include "talk/app/webrtc/videotrack.h"
36
#include "talk/base/gunit.h"
37
#include "talk/base/scoped_ptr.h"
38
#include "talk/base/thread.h"
39
#include "talk/p2p/base/constants.h"
40
#include "talk/p2p/base/sessiondescription.h"
42
static const char kStreams[][8] = {"stream1", "stream2"};
43
static const char kAudioTracks[][8] = {"audio_1", "audio_2"};
44
static const char kVideoTracks[][8] = {"video_1", "video_2"};
46
using webrtc::IceCandidateInterface;
47
using webrtc::MediaStreamInterface;
48
using webrtc::SessionDescriptionInterface;
50
using webrtc::StreamCollection;
51
using webrtc::StreamCollectionInterface;
53
// Reference SDP with a MediaStream with label "stream1" and audio track with
54
// label "audio_1" and a video track with label "video_1;
55
static const char kSdpString1[] =
57
"o=- 0 0 IN IP4 127.0.0.1\r\n"
60
"m=audio 1 RTP/AVPF 103\r\n"
62
"a=rtpmap:103 ISAC/16000\r\n"
63
"a=ssrc:1 cname:stream1\r\n"
64
"a=ssrc:1 mslabel:stream1\r\n"
65
"a=ssrc:1 label:audio_1\r\n"
66
"m=video 1 RTP/AVPF 120\r\n"
68
"a=rtpmap:120 VP8/90000\r\n"
69
"a=ssrc:2 cname:stream1\r\n"
70
"a=ssrc:2 mslabel:stream1\r\n"
71
"a=ssrc:2 label:video_1\r\n";
73
// Reference SDP with two MediaStreams with label "stream1" and "stream2. Each
74
// MediaStreams have one audio track and one video track.
75
static const char kSdpString2[] =
77
"o=- 0 0 IN IP4 127.0.0.1\r\n"
80
"m=audio 1 RTP/AVPF 103\r\n"
82
"a=rtpmap:103 ISAC/16000\r\n"
83
"a=ssrc:1 cname:stream1\r\n"
84
"a=ssrc:1 mslabel:stream1\r\n"
85
"a=ssrc:1 label:audio_1\r\n"
86
"a=ssrc:3 cname:stream2\r\n"
87
"a=ssrc:3 mslabel:stream2\r\n"
88
"a=ssrc:3 label:audio_2\r\n"
89
"m=video 1 RTP/AVPF 120\r\n"
91
"a=rtpmap:120 VP8/0\r\n"
92
"a=ssrc:2 cname:stream1\r\n"
93
"a=ssrc:2 mslabel:stream1\r\n"
94
"a=ssrc:2 label:video_1\r\n"
95
"a=ssrc:4 cname:stream2\r\n"
96
"a=ssrc:4 mslabel:stream2\r\n"
97
"a=ssrc:4 label:video_2\r\n";
99
// Create a collection of streams.
100
// CreateStreamCollection(1) creates a collection that
101
// correspond to kSdpString1.
102
// CreateStreamCollection(2) correspond to kSdpString2.
103
static talk_base::scoped_refptr<StreamCollection>
104
CreateStreamCollection(int number_of_streams) {
105
talk_base::scoped_refptr<StreamCollection> local_collection(
106
StreamCollection::Create());
108
for (int i = 0; i < number_of_streams; ++i) {
109
talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> stream(
110
webrtc::MediaStream::Create(kStreams[i]));
112
// Add a local audio track.
113
talk_base::scoped_refptr<webrtc::LocalAudioTrackInterface>
114
audio_track(webrtc::AudioTrack::CreateLocal(kAudioTracks[i], NULL));
115
stream->AddTrack(audio_track);
117
// Add a local video track.
118
talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface>
119
video_track(webrtc::VideoTrack::CreateLocal(kVideoTracks[i], NULL));
120
stream->AddTrack(video_track);
122
local_collection->AddStream(stream);
124
return local_collection;
127
// Verifies that |options| contain all tracks in |collection| if |hints| allow
129
static void VerifyMediaOptions(StreamCollectionInterface* collection,
130
const webrtc::MediaHints hints,
131
const cricket::MediaSessionOptions& options) {
132
EXPECT_EQ(hints.has_audio(), options.has_audio);
133
EXPECT_EQ(hints.has_video(), options.has_video);
138
size_t stream_index = 0;
139
for (size_t i = 0; i < collection->count(); ++i) {
140
MediaStreamInterface* stream = collection->at(i);
141
ASSERT_GE(options.streams.size(), stream->audio_tracks()->count());
142
for (size_t j = 0; j < stream->audio_tracks()->count(); ++j) {
143
webrtc::AudioTrackInterface* audio = stream->audio_tracks()->at(j);
144
EXPECT_EQ(options.streams[stream_index].sync_label, stream->label());
145
EXPECT_EQ(options.streams[stream_index++].name, audio->label());
147
ASSERT_GE(options.streams.size(), stream->audio_tracks()->count());
148
for (size_t j = 0; j < stream->video_tracks()->count(); ++j) {
149
webrtc::VideoTrackInterface* video = stream->video_tracks()->at(j);
150
EXPECT_EQ(options.streams[stream_index].sync_label, stream->label());
151
EXPECT_EQ(options.streams[stream_index++].name, video->label());
156
static bool CompareStreamCollections(StreamCollectionInterface* s1,
157
StreamCollectionInterface* s2) {
158
if (s1 == NULL || s2 == NULL || s1->count() != s2->count())
161
for (size_t i = 0; i != s1->count(); ++i) {
162
if (s1->at(i)->label() != s2->at(i)->label())
164
webrtc::AudioTracks* audio_tracks1 = s1->at(i)->audio_tracks();
165
webrtc::AudioTracks* audio_tracks2 = s2->at(i)->audio_tracks();
166
webrtc::VideoTracks* video_tracks1 = s1->at(i)->video_tracks();
167
webrtc::VideoTracks* video_tracks2 = s2->at(i)->video_tracks();
169
if (audio_tracks1->count() != audio_tracks2->count())
171
for (size_t j = 0; j != audio_tracks1->count(); ++j) {
172
if (audio_tracks1->at(j)->label() != audio_tracks2->at(j)->label())
175
if (video_tracks1->count() != video_tracks2->count())
177
for (size_t j = 0; j != video_tracks1->count(); ++j) {
178
if (video_tracks1->at(j)->label() != video_tracks2->at(j)->label())
185
// MockRemoteStreamObserver implements functions for listening to
186
// callbacks about added and removed remote MediaStreams.
187
class MockRemoteStreamObserver : public webrtc::RemoteMediaStreamObserver {
189
MockRemoteStreamObserver()
190
: remote_media_streams_(StreamCollection::Create()) {
193
virtual ~MockRemoteStreamObserver() {
196
// New remote stream have been discovered.
197
virtual void OnAddStream(MediaStreamInterface* remote_stream) {
198
EXPECT_EQ(MediaStreamInterface::kLive, remote_stream->ready_state());
199
remote_media_streams_->AddStream(remote_stream);
202
// Remote stream is no longer available.
203
virtual void OnRemoveStream(MediaStreamInterface* remote_stream) {
204
EXPECT_EQ(MediaStreamInterface::kEnded, remote_stream->ready_state());
205
remote_media_streams_->RemoveStream(remote_stream);
208
MediaStreamInterface* RemoteStream(const std::string& label) {
209
return remote_media_streams_->find(label);
212
StreamCollectionInterface* remote_streams() const {
213
return remote_media_streams_;
217
talk_base::scoped_refptr<StreamCollection> remote_media_streams_;
220
class MediaStreamSignalingForTest : public webrtc::MediaStreamSignaling {
222
explicit MediaStreamSignalingForTest(MockRemoteStreamObserver* observer)
223
: webrtc::MediaStreamSignaling(talk_base::Thread::Current(), observer) {
225
using webrtc::MediaStreamSignaling::SetLocalStreams;
226
using webrtc::MediaStreamSignaling::GetMediaSessionOptions;
227
using webrtc::MediaStreamSignaling::UpdateRemoteStreams;
228
using webrtc::MediaStreamSignaling::remote_streams;
231
class MediaStreamSignalingTest: public testing::Test {
233
virtual void SetUp() {
234
observer_.reset(new MockRemoteStreamObserver());
235
signaling_.reset(new MediaStreamSignalingForTest(observer_.get()));
238
talk_base::scoped_ptr<MockRemoteStreamObserver> observer_;
239
talk_base::scoped_ptr<MediaStreamSignalingForTest> signaling_;
241
void TestGetMediaSessionOptions(const webrtc::MediaHints& hints,
242
StreamCollectionInterface* streams) {
243
signaling_->SetLocalStreams(streams);
244
cricket::MediaSessionOptions options =
245
signaling_->GetMediaSessionOptions(hints);
246
VerifyMediaOptions(streams, hints, options);
250
TEST_F(MediaStreamSignalingTest, AudioVideoHints) {
251
webrtc::MediaHints hints;
252
talk_base::scoped_refptr<StreamCollection> local_streams(
253
CreateStreamCollection(1));
254
TestGetMediaSessionOptions(hints, local_streams.get());
257
TEST_F(MediaStreamSignalingTest, AudioHints) {
258
webrtc::MediaHints hints(true, false);
259
// Don't use all MediaStreams so we only create offer based on hints without
261
TestGetMediaSessionOptions(hints, NULL);
264
TEST_F(MediaStreamSignalingTest, VideoHints) {
265
webrtc::MediaHints hints(false, true);
266
// Don't use all MediaStreams so we only create offer based on hints without
268
TestGetMediaSessionOptions(hints, NULL);
271
TEST_F(MediaStreamSignalingTest, UpdateRemoteStreams) {
272
SessionDescriptionInterface* desc = webrtc::CreateSessionDescription(
274
EXPECT_TRUE(desc != NULL);
275
signaling_->UpdateRemoteStreams(desc);
277
talk_base::scoped_refptr<StreamCollection> reference(
278
CreateStreamCollection(1));
279
EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
281
EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),
284
// Update the remote streams.
285
SessionDescriptionInterface* update_desc =
286
webrtc::CreateSessionDescription(kSdpString2);
287
EXPECT_TRUE(update_desc != NULL);
288
signaling_->UpdateRemoteStreams(update_desc);
290
talk_base::scoped_refptr<StreamCollection> reference2(
291
CreateStreamCollection(2));
292
EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
294
EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),