1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/bind_helpers.h"
7 #include "base/callback.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/threading/thread_checker_impl.h"
12 #include "content/child/child_process.h"
13 #include "content/renderer/media/media_stream_video_track.h"
14 #include "content/renderer/media/mock_media_stream_video_sink.h"
15 #include "content/renderer/media/mock_media_stream_video_source.h"
16 #include "media/base/video_frame.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/WebKit/public/web/WebHeap.h"
22 const uint8 kBlackValue
= 0x00;
23 const uint8 kColorValue
= 0xAB;
25 ACTION_P(RunClosure
, closure
) {
29 class MediaStreamVideoTrackTest
: public ::testing::Test
{
31 MediaStreamVideoTrackTest()
32 : child_process_(new ChildProcess()),
33 mock_source_(new MockMediaStreamVideoSource(false)),
34 source_started_(false) {
35 blink_source_
.initialize(base::UTF8ToUTF16("dummy_source_id"),
36 blink::WebMediaStreamSource::TypeVideo
,
37 base::UTF8ToUTF16("dummy_source_name"),
38 false /* remote */, true /* readonly */);
39 blink_source_
.setExtraData(mock_source_
);
42 ~MediaStreamVideoTrackTest() override
{}
44 void TearDown() override
{
45 blink_source_
.reset();
46 blink::WebHeap::collectAllGarbageForTesting();
49 void DeliverVideoFrameAndWaitForRenderer(MockMediaStreamVideoSink
* sink
) {
50 base::RunLoop run_loop
;
51 base::Closure quit_closure
= run_loop
.QuitClosure();
52 EXPECT_CALL(*sink
, OnVideoFrame()).WillOnce(
53 RunClosure(quit_closure
));
54 scoped_refptr
<media::VideoFrame
> frame
=
55 media::VideoFrame::CreateColorFrame(
56 gfx::Size(MediaStreamVideoSource::kDefaultWidth
,
57 MediaStreamVideoSource::kDefaultHeight
),
58 kColorValue
, kColorValue
, kColorValue
, base::TimeDelta());
59 mock_source()->DeliverVideoFrame(frame
);
64 base::MessageLoop
* io_message_loop() const {
65 return child_process_
->io_message_loop();
68 // Create a track that's associated with |mock_source_|.
69 blink::WebMediaStreamTrack
CreateTrack() {
70 blink::WebMediaConstraints constraints
;
71 constraints
.initialize();
73 blink::WebMediaStreamTrack track
=
74 MediaStreamVideoTrack::CreateVideoTrack(
75 mock_source_
, constraints
,
76 MediaStreamSource::ConstraintsCallback(), enabled
);
77 if (!source_started_
) {
78 mock_source_
->StartMockedSource();
79 source_started_
= true;
84 MockMediaStreamVideoSource
* mock_source() { return mock_source_
; }
85 const blink::WebMediaStreamSource
& blink_source() const {
90 base::MessageLoopForUI message_loop_
;
91 scoped_ptr
<ChildProcess
> child_process_
;
92 blink::WebMediaStreamSource blink_source_
;
93 // |mock_source_| is owned by |webkit_source_|.
94 MockMediaStreamVideoSource
* mock_source_
;
98 TEST_F(MediaStreamVideoTrackTest
, AddAndRemoveSink
) {
99 MockMediaStreamVideoSink sink
;
100 blink::WebMediaStreamTrack track
= CreateTrack();
101 MediaStreamVideoSink::AddToVideoTrack(
102 &sink
, sink
.GetDeliverFrameCB(), track
);
104 DeliverVideoFrameAndWaitForRenderer(&sink
);
105 EXPECT_EQ(1, sink
.number_of_frames());
107 DeliverVideoFrameAndWaitForRenderer(&sink
);
109 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
111 scoped_refptr
<media::VideoFrame
> frame
=
112 media::VideoFrame::CreateBlackFrame(
113 gfx::Size(MediaStreamVideoSource::kDefaultWidth
,
114 MediaStreamVideoSource::kDefaultHeight
));
115 mock_source()->DeliverVideoFrame(frame
);
116 // Wait for the IO thread to complete delivering frames.
117 io_message_loop()->RunUntilIdle();
118 EXPECT_EQ(2, sink
.number_of_frames());
121 class CheckThreadHelper
{
123 CheckThreadHelper(base::Closure callback
, bool* correct
)
124 : callback_(callback
),
128 ~CheckThreadHelper() {
129 *correct_
= thread_checker_
.CalledOnValidThread();
134 base::Closure callback_
;
136 base::ThreadCheckerImpl thread_checker_
;
139 void CheckThreadVideoFrameReceiver(
140 CheckThreadHelper
* helper
,
141 const scoped_refptr
<media::VideoFrame
>& frame
,
142 const base::TimeTicks
& estimated_capture_time
) {
146 // Checks that the callback given to the track is reset on the right thread.
147 TEST_F(MediaStreamVideoTrackTest
, ResetCallbackOnThread
) {
148 MockMediaStreamVideoSink sink
;
149 blink::WebMediaStreamTrack track
= CreateTrack();
151 base::RunLoop run_loop
;
152 bool correct
= false;
153 MediaStreamVideoSink::AddToVideoTrack(
156 &CheckThreadVideoFrameReceiver
,
157 base::Owned(new CheckThreadHelper(run_loop
.QuitClosure(), &correct
))),
159 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
161 EXPECT_TRUE(correct
) << "Not called on correct thread.";
164 TEST_F(MediaStreamVideoTrackTest
, SetEnabled
) {
165 MockMediaStreamVideoSink sink
;
166 blink::WebMediaStreamTrack track
= CreateTrack();
167 MediaStreamVideoSink::AddToVideoTrack(
168 &sink
, sink
.GetDeliverFrameCB(), track
);
170 MediaStreamVideoTrack
* video_track
=
171 MediaStreamVideoTrack::GetVideoTrack(track
);
173 DeliverVideoFrameAndWaitForRenderer(&sink
);
174 EXPECT_EQ(1, sink
.number_of_frames());
175 EXPECT_EQ(kColorValue
, *sink
.last_frame()->data(media::VideoFrame::kYPlane
));
177 video_track
->SetEnabled(false);
178 EXPECT_FALSE(sink
.enabled());
180 DeliverVideoFrameAndWaitForRenderer(&sink
);
181 EXPECT_EQ(2, sink
.number_of_frames());
182 EXPECT_EQ(kBlackValue
, *sink
.last_frame()->data(media::VideoFrame::kYPlane
));
184 video_track
->SetEnabled(true);
185 EXPECT_TRUE(sink
.enabled());
186 DeliverVideoFrameAndWaitForRenderer(&sink
);
187 EXPECT_EQ(3, sink
.number_of_frames());
188 EXPECT_EQ(kColorValue
, *sink
.last_frame()->data(media::VideoFrame::kYPlane
));
189 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
192 TEST_F(MediaStreamVideoTrackTest
, SourceStopped
) {
193 MockMediaStreamVideoSink sink
;
194 blink::WebMediaStreamTrack track
= CreateTrack();
195 MediaStreamVideoSink::AddToVideoTrack(
196 &sink
, sink
.GetDeliverFrameCB(), track
);
197 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
, sink
.state());
199 mock_source()->StopSource();
200 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
, sink
.state());
201 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
204 TEST_F(MediaStreamVideoTrackTest
, StopLastTrack
) {
205 MockMediaStreamVideoSink sink1
;
206 blink::WebMediaStreamTrack track1
= CreateTrack();
207 MediaStreamVideoSink::AddToVideoTrack(
208 &sink1
, sink1
.GetDeliverFrameCB(), track1
);
209 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
, sink1
.state());
211 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
,
212 blink_source().readyState());
214 MockMediaStreamVideoSink sink2
;
215 blink::WebMediaStreamTrack track2
= CreateTrack();
216 MediaStreamVideoSink::AddToVideoTrack(
217 &sink2
, sink2
.GetDeliverFrameCB(), track2
);
218 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
, sink2
.state());
220 MediaStreamVideoTrack
* native_track1
=
221 MediaStreamVideoTrack::GetVideoTrack(track1
);
222 native_track1
->Stop();
223 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
, sink1
.state());
224 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
,
225 blink_source().readyState());
226 MediaStreamVideoSink::RemoveFromVideoTrack(&sink1
, track1
);
228 MediaStreamVideoTrack
* native_track2
=
229 MediaStreamVideoTrack::GetVideoTrack(track2
);
230 native_track2
->Stop();
231 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
, sink2
.state());
232 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
,
233 blink_source().readyState());
234 MediaStreamVideoSink::RemoveFromVideoTrack(&sink2
, track2
);
237 } // namespace content