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(RunClosure(quit_closure
));
53 const scoped_refptr
<media::VideoFrame
> frame
=
54 media::VideoFrame::CreateColorFrame(
55 gfx::Size(MediaStreamVideoSource::kDefaultWidth
,
56 MediaStreamVideoSource::kDefaultHeight
),
57 kColorValue
, kColorValue
, kColorValue
, base::TimeDelta());
58 mock_source()->DeliverVideoFrame(frame
);
63 base::MessageLoop
* io_message_loop() const {
64 return child_process_
->io_message_loop();
67 // Create a track that's associated with |mock_source_|.
68 blink::WebMediaStreamTrack
CreateTrack() {
69 blink::WebMediaConstraints constraints
;
70 constraints
.initialize();
71 const bool enabled
= true;
72 blink::WebMediaStreamTrack track
=
73 MediaStreamVideoTrack::CreateVideoTrack(
74 mock_source_
, constraints
,
75 MediaStreamSource::ConstraintsCallback(), enabled
);
76 if (!source_started_
) {
77 mock_source_
->StartMockedSource();
78 source_started_
= true;
83 MockMediaStreamVideoSource
* mock_source() { return mock_source_
; }
84 const blink::WebMediaStreamSource
& blink_source() const {
89 const base::MessageLoopForUI message_loop_
;
90 const scoped_ptr
<ChildProcess
> child_process_
;
91 blink::WebMediaStreamSource blink_source_
;
92 // |mock_source_| is owned by |webkit_source_|.
93 MockMediaStreamVideoSource
* mock_source_
;
97 TEST_F(MediaStreamVideoTrackTest
, AddAndRemoveSink
) {
98 MockMediaStreamVideoSink sink
;
99 blink::WebMediaStreamTrack track
= CreateTrack();
100 MediaStreamVideoSink::AddToVideoTrack(&sink
, sink
.GetDeliverFrameCB(), track
);
102 DeliverVideoFrameAndWaitForRenderer(&sink
);
103 EXPECT_EQ(1, sink
.number_of_frames());
105 DeliverVideoFrameAndWaitForRenderer(&sink
);
107 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
109 scoped_refptr
<media::VideoFrame
> frame
=
110 media::VideoFrame::CreateBlackFrame(
111 gfx::Size(MediaStreamVideoSource::kDefaultWidth
,
112 MediaStreamVideoSource::kDefaultHeight
));
113 mock_source()->DeliverVideoFrame(frame
);
114 // Wait for the IO thread to complete delivering frames.
115 io_message_loop()->RunUntilIdle();
116 EXPECT_EQ(2, sink
.number_of_frames());
119 class CheckThreadHelper
{
121 CheckThreadHelper(base::Closure callback
, bool* correct
)
122 : callback_(callback
),
126 ~CheckThreadHelper() {
127 *correct_
= thread_checker_
.CalledOnValidThread();
132 base::Closure callback_
;
134 base::ThreadCheckerImpl thread_checker_
;
137 void CheckThreadVideoFrameReceiver(
138 CheckThreadHelper
* helper
,
139 const scoped_refptr
<media::VideoFrame
>& frame
,
140 base::TimeTicks estimated_capture_time
) {
144 // Checks that the callback given to the track is reset on the right thread.
145 TEST_F(MediaStreamVideoTrackTest
, ResetCallbackOnThread
) {
146 MockMediaStreamVideoSink sink
;
147 blink::WebMediaStreamTrack track
= CreateTrack();
149 base::RunLoop run_loop
;
150 bool correct
= false;
151 MediaStreamVideoSink::AddToVideoTrack(
154 &CheckThreadVideoFrameReceiver
,
155 base::Owned(new CheckThreadHelper(run_loop
.QuitClosure(), &correct
))),
157 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
159 EXPECT_TRUE(correct
) << "Not called on correct thread.";
162 TEST_F(MediaStreamVideoTrackTest
, SetEnabled
) {
163 MockMediaStreamVideoSink sink
;
164 blink::WebMediaStreamTrack track
= CreateTrack();
165 MediaStreamVideoSink::AddToVideoTrack(&sink
, sink
.GetDeliverFrameCB(), track
);
167 MediaStreamVideoTrack
* video_track
=
168 MediaStreamVideoTrack::GetVideoTrack(track
);
170 DeliverVideoFrameAndWaitForRenderer(&sink
);
171 EXPECT_EQ(1, sink
.number_of_frames());
172 EXPECT_EQ(kColorValue
, *sink
.last_frame()->data(media::VideoFrame::kYPlane
));
174 video_track
->SetEnabled(false);
175 EXPECT_FALSE(sink
.enabled());
177 DeliverVideoFrameAndWaitForRenderer(&sink
);
178 EXPECT_EQ(2, sink
.number_of_frames());
179 EXPECT_EQ(kBlackValue
, *sink
.last_frame()->data(media::VideoFrame::kYPlane
));
181 video_track
->SetEnabled(true);
182 EXPECT_TRUE(sink
.enabled());
183 DeliverVideoFrameAndWaitForRenderer(&sink
);
184 EXPECT_EQ(3, sink
.number_of_frames());
185 EXPECT_EQ(kColorValue
, *sink
.last_frame()->data(media::VideoFrame::kYPlane
));
186 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
189 TEST_F(MediaStreamVideoTrackTest
, SourceStopped
) {
190 MockMediaStreamVideoSink sink
;
191 blink::WebMediaStreamTrack track
= CreateTrack();
192 MediaStreamVideoSink::AddToVideoTrack(&sink
, sink
.GetDeliverFrameCB(), track
);
193 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
, sink
.state());
195 mock_source()->StopSource();
196 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
, sink
.state());
197 MediaStreamVideoSink::RemoveFromVideoTrack(&sink
, track
);
200 TEST_F(MediaStreamVideoTrackTest
, StopLastTrack
) {
201 MockMediaStreamVideoSink sink1
;
202 blink::WebMediaStreamTrack track1
= CreateTrack();
203 MediaStreamVideoSink::AddToVideoTrack(
204 &sink1
, sink1
.GetDeliverFrameCB(), track1
);
205 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
, sink1
.state());
207 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
,
208 blink_source().readyState());
210 MockMediaStreamVideoSink sink2
;
211 blink::WebMediaStreamTrack track2
= CreateTrack();
212 MediaStreamVideoSink::AddToVideoTrack(
213 &sink2
, sink2
.GetDeliverFrameCB(), track2
);
214 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
, sink2
.state());
216 MediaStreamVideoTrack
* const native_track1
=
217 MediaStreamVideoTrack::GetVideoTrack(track1
);
218 native_track1
->Stop();
219 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
, sink1
.state());
220 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
,
221 blink_source().readyState());
222 MediaStreamVideoSink::RemoveFromVideoTrack(&sink1
, track1
);
224 MediaStreamVideoTrack
* const native_track2
=
225 MediaStreamVideoTrack::GetVideoTrack(track2
);
226 native_track2
->Stop();
227 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
, sink2
.state());
228 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
,
229 blink_source().readyState());
230 MediaStreamVideoSink::RemoveFromVideoTrack(&sink2
, track2
);
233 } // namespace content