1 /*
2 * libjingle
3 * Copyright 2011, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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.
15 *
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.
26 */
27
28 #include <string>
29
30 #include "talk/app/webrtc/mediastreamproxy.h"
31 #include "talk/app/webrtc/mediastreamtrackproxy.h"
32 #include "talk/base/refcount.h"
33 #include "talk/base/scoped_ptr.h"
34 #include "talk/base/thread.h"
35 #include "talk/base/gunit.h"
36 #include "testing/base/public/gmock.h"
37
38 static const char kStreamLabel1[] = "local_stream_1";
39 static const char kVideoTrackLabel[] = "dummy_video_cam_1";
40 static const char kAudioTrackLabel[] = "dummy_microphone_1";
41
42 using talk_base::scoped_refptr;
43 using ::testing::Exactly;
44
45 namespace {
46
47 class ReadyStateMessageData : public talk_base::MessageData {
48 public:
ReadyStateMessageData(webrtc::MediaStreamInterface * stream,webrtc::MediaStreamInterface::ReadyState new_state)49 ReadyStateMessageData(
50 webrtc::MediaStreamInterface* stream,
51 webrtc::MediaStreamInterface::ReadyState new_state)
52 : stream_(stream),
53 ready_state_(new_state) {
54 }
55
56 scoped_refptr<webrtc::MediaStreamInterface> stream_;
57 webrtc::MediaStreamInterface::ReadyState ready_state_;
58 };
59
60 class TrackStateMessageData : public talk_base::MessageData {
61 public:
TrackStateMessageData(webrtc::MediaStreamTrackInterface * track,webrtc::MediaStreamTrackInterface::TrackState state)62 TrackStateMessageData(
63 webrtc::MediaStreamTrackInterface* track,
64 webrtc::MediaStreamTrackInterface::TrackState state)
65 : track_(track),
66 state_(state) {
67 }
68
69 scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
70 webrtc::MediaStreamTrackInterface::TrackState state_;
71 };
72
73 } // namespace anonymous
74
75 namespace webrtc {
76
77 // Helper class to test Observer.
78 class MockObserver : public ObserverInterface {
79 public:
MockObserver(talk_base::Thread * signaling_thread)80 explicit MockObserver(talk_base::Thread* signaling_thread)
81 : signaling_thread_(signaling_thread) {
82 }
83
84 MOCK_METHOD0(DoOnChanged, void());
OnChanged()85 virtual void OnChanged() {
86 ASSERT_TRUE(talk_base::Thread::Current() == signaling_thread_);
87 DoOnChanged();
88 }
89 private:
90 talk_base::Thread* signaling_thread_;
91 };
92
93 class MockMediaStream: public LocalMediaStreamInterface {
94 public:
MockMediaStream(const std::string & label,talk_base::Thread * signaling_thread)95 MockMediaStream(const std::string& label, talk_base::Thread* signaling_thread)
96 : stream_impl_(MediaStream::Create(label)),
97 signaling_thread_(signaling_thread) {
98 }
RegisterObserver(webrtc::ObserverInterface * observer)99 virtual void RegisterObserver(webrtc::ObserverInterface* observer) {
100 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
101 stream_impl_->RegisterObserver(observer);
102 }
UnregisterObserver(webrtc::ObserverInterface * observer)103 virtual void UnregisterObserver(webrtc::ObserverInterface* observer) {
104 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
105 stream_impl_->UnregisterObserver(observer);
106 }
label() const107 virtual std::string label() const {
108 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
109 return stream_impl_->label();
110 }
audio_tracks()111 virtual AudioTracks* audio_tracks() {
112 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
113 return stream_impl_->audio_tracks();
114 }
video_tracks()115 virtual VideoTracks* video_tracks() {
116 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
117 return stream_impl_->video_tracks();
118 }
ready_state() const119 virtual ReadyState ready_state() const {
120 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
121 return stream_impl_->ready_state();
122 }
set_ready_state(ReadyState state)123 virtual void set_ready_state(ReadyState state) {
124 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
125 return stream_impl_->set_ready_state(state);
126 }
AddTrack(AudioTrackInterface * audio_track)127 virtual bool AddTrack(AudioTrackInterface* audio_track) {
128 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
129 return stream_impl_->AddTrack(audio_track);
130 }
AddTrack(VideoTrackInterface * video_track)131 virtual bool AddTrack(VideoTrackInterface* video_track) {
132 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
133 return stream_impl_->AddTrack(video_track);
134 }
135
136 private:
137 scoped_refptr<MediaStream> stream_impl_;
138 talk_base::Thread* signaling_thread_;
139 };
140
141 template <class T>
142 class MockMediaStreamTrack: public T {
143 public:
MockMediaStreamTrack(T * implementation,talk_base::Thread * signaling_thread)144 MockMediaStreamTrack(T* implementation,
145 talk_base::Thread* signaling_thread)
146 : track_impl_(implementation),
147 signaling_thread_(signaling_thread) {
148 }
RegisterObserver(webrtc::ObserverInterface * observer)149 virtual void RegisterObserver(webrtc::ObserverInterface* observer) {
150 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
151 track_impl_->RegisterObserver(observer);
152 }
UnregisterObserver(webrtc::ObserverInterface * observer)153 virtual void UnregisterObserver(webrtc::ObserverInterface* observer) {
154 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
155 track_impl_->UnregisterObserver(observer);
156 }
kind() const157 virtual std::string kind() const {
158 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
159 return track_impl_->kind();
160 }
label() const161 virtual std::string label() const {
162 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
163 return track_impl_->label();
164 }
enabled() const165 virtual bool enabled() const {
166 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
167 return track_impl_->enabled();
168 }
state() const169 virtual MediaStreamTrackInterface::TrackState state() const {
170 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
171 return track_impl_->state();
172 }
set_enabled(bool enabled)173 virtual bool set_enabled(bool enabled) {
174 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
175 return track_impl_->set_enabled(enabled);
176 }
set_state(webrtc::MediaStreamTrackInterface::TrackState state)177 virtual bool set_state(webrtc::MediaStreamTrackInterface::TrackState state) {
178 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
179 return track_impl_->set_state(state);
180 }
181
182 protected:
183 scoped_refptr<T> track_impl_;
184 talk_base::Thread* signaling_thread_;
185 };
186
187 class MockLocalVideoTrack
188 : public MockMediaStreamTrack<LocalVideoTrackInterface> {
189 public:
MockLocalVideoTrack(LocalVideoTrackInterface * implementation,talk_base::Thread * signaling_thread)190 MockLocalVideoTrack(LocalVideoTrackInterface* implementation,
191 talk_base::Thread* signaling_thread)
192 : MockMediaStreamTrack<LocalVideoTrackInterface>(implementation,
193 signaling_thread) {
194 }
SetRenderer(webrtc::VideoRendererWrapperInterface * renderer)195 virtual void SetRenderer(webrtc::VideoRendererWrapperInterface* renderer) {
196 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
197 track_impl_->SetRenderer(renderer);
198 }
GetRenderer()199 virtual VideoRendererWrapperInterface* GetRenderer() {
200 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
201 return track_impl_->GetRenderer();
202 }
GetVideoCapture()203 virtual cricket::VideoCapturer* GetVideoCapture() {
204 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
205 return track_impl_->GetVideoCapture();
206 }
207 };
208
209 class MockLocalAudioTrack
210 : public MockMediaStreamTrack<LocalAudioTrackInterface> {
211 public:
MockLocalAudioTrack(LocalAudioTrackInterface * implementation,talk_base::Thread * signaling_thread)212 MockLocalAudioTrack(LocalAudioTrackInterface* implementation,
213 talk_base::Thread* signaling_thread)
214 : MockMediaStreamTrack<LocalAudioTrackInterface>(implementation,
215 signaling_thread) {
216 }
217
GetAudioDevice()218 virtual AudioDeviceModule* GetAudioDevice() {
219 EXPECT_EQ(talk_base::Thread::Current(), signaling_thread_);
220 return track_impl_->GetAudioDevice();
221 }
222 };
223
224 class MediaStreamTest: public testing::Test,
225 public talk_base::MessageHandler {
226 protected:
SetUp()227 virtual void SetUp() {
228 signaling_thread_ .reset(new talk_base::Thread());
229 ASSERT_TRUE(signaling_thread_->Start());
230
231 std::string label(kStreamLabel1);
232 // Create a stream proxy object that uses our mocked
233 // version of a LocalMediaStream.
234 scoped_refptr<MockMediaStream> mock_stream(
235 new talk_base::RefCountedObject<MockMediaStream>(label,
236 signaling_thread_.get()));
237 stream_ = MediaStreamProxy::Create(label, signaling_thread_.get(),
238 mock_stream);
239 ASSERT_TRUE(stream_.get() != NULL);
240 EXPECT_EQ(label, stream_->label());
241 EXPECT_EQ(MediaStreamInterface::kInitializing, stream_->ready_state());
242
243 // Create a video track proxy object that uses our mocked
244 // version of a LocalVideoTrack
245 scoped_refptr<VideoTrack> video_track_impl(
246 VideoTrack::CreateLocal(kVideoTrackLabel, NULL));
247 scoped_refptr<MockLocalVideoTrack> mock_videotrack(
248 new talk_base::RefCountedObject<MockLocalVideoTrack>(video_track_impl,
249 signaling_thread_.get()));
250 video_track_ = VideoTrackProxy::CreateLocal(mock_videotrack,
251 signaling_thread_.get());
252
253 ASSERT_TRUE(video_track_.get() != NULL);
254 EXPECT_EQ(MediaStreamTrackInterface::kInitializing, video_track_->state());
255
256 // Create an audio track proxy object that uses our mocked
257 // version of a LocalAudioTrack
258 scoped_refptr<AudioTrack> audio_track_impl(
259 AudioTrack::CreateLocal(kAudioTrackLabel, NULL));
260 scoped_refptr<MockLocalAudioTrack> mock_audiotrack(
261 new talk_base::RefCountedObject<MockLocalAudioTrack>(audio_track_impl,
262 signaling_thread_.get()));
263 audio_track_ = AudioTrackProxy::CreateLocal(mock_audiotrack,
264 signaling_thread_.get());
265
266 ASSERT_TRUE(audio_track_.get() != NULL);
267 EXPECT_EQ(MediaStreamTrackInterface::kInitializing, audio_track_->state());
268 }
269
270 enum {
271 MSG_SET_READYSTATE,
272 MSG_SET_TRACKSTATE,
273 };
274
275 // Set the ready state on the signaling thread.
276 // State can only be changed on the signaling thread.
SetReadyState(MediaStreamInterface * stream,MediaStreamInterface::ReadyState new_state)277 void SetReadyState(MediaStreamInterface* stream,
278 MediaStreamInterface::ReadyState new_state) {
279 ReadyStateMessageData state(stream, new_state);
280 signaling_thread_->Send(this, MSG_SET_READYSTATE, &state);
281 }
282
283 // Set the track state on the signaling thread.
284 // State can only be changed on the signaling thread.
SetTrackState(MediaStreamTrackInterface * track,MediaStreamTrackInterface::TrackState new_state)285 void SetTrackState(MediaStreamTrackInterface* track,
286 MediaStreamTrackInterface::TrackState new_state) {
287 TrackStateMessageData state(track, new_state);
288 signaling_thread_->Send(this, MSG_SET_TRACKSTATE, &state);
289 }
290
291 talk_base::scoped_ptr<talk_base::Thread> signaling_thread_;
292 scoped_refptr<LocalMediaStreamInterface> stream_;
293 scoped_refptr<LocalVideoTrackInterface> video_track_;
294 scoped_refptr<LocalAudioTrackInterface> audio_track_;
295
296 private:
297 // Implements talk_base::MessageHandler.
OnMessage(talk_base::Message * msg)298 virtual void OnMessage(talk_base::Message* msg) {
299 switch (msg->message_id) {
300 case MSG_SET_READYSTATE: {
301 ReadyStateMessageData* state =
302 static_cast<ReadyStateMessageData*>(msg->pdata);
303 state->stream_->set_ready_state(state->ready_state_);
304 break;
305 }
306 case MSG_SET_TRACKSTATE: {
307 TrackStateMessageData* state =
308 static_cast<TrackStateMessageData*>(msg->pdata);
309 state->track_->set_state(state->state_);
310 break;
311 }
312 default:
313 break;
314 }
315 }
316 };
317
TEST_F(MediaStreamTest,CreateLocalStream)318 TEST_F(MediaStreamTest, CreateLocalStream) {
319 EXPECT_TRUE(stream_->AddTrack(video_track_));
320 EXPECT_TRUE(stream_->AddTrack(audio_track_));
321
322 ASSERT_EQ(1u, stream_->video_tracks()->count());
323 ASSERT_EQ(1u, stream_->audio_tracks()->count());
324
325 // Verify the video track.
326 scoped_refptr<webrtc::MediaStreamTrackInterface> track(
327 stream_->video_tracks()->at(0));
328 EXPECT_EQ(0, track->label().compare(kVideoTrackLabel));
329 EXPECT_TRUE(track->enabled());
330
331 // Verify the audio track.
332 track = stream_->audio_tracks()->at(0);
333 EXPECT_EQ(0, track->label().compare(kAudioTrackLabel));
334 EXPECT_TRUE(track->enabled());
335 }
336
TEST_F(MediaStreamTest,ChangeStreamState)337 TEST_F(MediaStreamTest, ChangeStreamState) {
338 MockObserver observer(signaling_thread_.get());
339 stream_->RegisterObserver(&observer);
340
341 EXPECT_CALL(observer, DoOnChanged())
342 .Times(Exactly(1));
343 SetReadyState(stream_, MediaStreamInterface::kLive);
344
345 EXPECT_EQ(MediaStreamInterface::kLive, stream_->ready_state());
346 // It should not be possible to add
347 // streams when the state has changed to live.
348 EXPECT_FALSE(stream_->AddTrack(audio_track_));
349 EXPECT_EQ(0u, stream_->audio_tracks()->count());
350 }
351
TEST_F(MediaStreamTest,ChangeVideoTrack)352 TEST_F(MediaStreamTest, ChangeVideoTrack) {
353 MockObserver observer(signaling_thread_.get());
354 video_track_->RegisterObserver(&observer);
355
356 EXPECT_CALL(observer, DoOnChanged())
357 .Times(Exactly(1));
358 video_track_->set_enabled(false);
359 EXPECT_FALSE(video_track_->state());
360
361 EXPECT_CALL(observer, DoOnChanged())
362 .Times(Exactly(1));
363 SetTrackState(video_track_, MediaStreamTrackInterface::kLive);
364 EXPECT_EQ(MediaStreamTrackInterface::kLive, video_track_->state());
365
366 EXPECT_CALL(observer, DoOnChanged())
367 .Times(Exactly(1));
368 scoped_refptr<VideoRendererWrapperInterface> renderer(
369 CreateVideoRenderer(NULL));
370 video_track_->SetRenderer(renderer.get());
371 EXPECT_TRUE(renderer.get() == video_track_->GetRenderer());
372 }
373
TEST_F(MediaStreamTest,ChangeAudioTrack)374 TEST_F(MediaStreamTest, ChangeAudioTrack) {
375 MockObserver observer(signaling_thread_.get());
376 audio_track_->RegisterObserver(&observer);
377
378 EXPECT_CALL(observer, DoOnChanged())
379 .Times(Exactly(1));
380 audio_track_->set_enabled(false);
381 EXPECT_FALSE(audio_track_->enabled());
382
383 EXPECT_CALL(observer, DoOnChanged())
384 .Times(Exactly(1));
385 SetTrackState(audio_track_, MediaStreamTrackInterface::kLive);
386 EXPECT_EQ(MediaStreamTrackInterface::kLive, audio_track_->state());
387 }
388
389 } // namespace webrtc
390