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/callback_helpers.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/child/child_process.h"
11 #include "content/public/renderer/media_stream_video_sink.h"
12 #include "content/renderer/media/media_stream_video_capturer_source.h"
13 #include "content/renderer/media/media_stream_video_track.h"
14 #include "content/renderer/media/mock_media_constraint_factory.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/WebKit/public/web/WebHeap.h"
22 class MockVideoCapturerDelegate
: public VideoCapturerDelegate
{
24 explicit MockVideoCapturerDelegate(const StreamDeviceInfo
& device_info
)
25 : VideoCapturerDelegate(device_info
) {}
27 MOCK_METHOD3(StartCapture
,
28 void(const media::VideoCaptureParams
& params
,
29 const VideoCaptureDeliverFrameCB
& new_frame_callback
,
30 const RunningCallback
& running_callback
));
31 MOCK_METHOD0(StopCapture
, void());
33 virtual ~MockVideoCapturerDelegate() {}
36 class MediaStreamVideoCapturerSourceTest
: public testing::Test
{
38 MediaStreamVideoCapturerSourceTest()
39 : child_process_(new ChildProcess()),
42 source_stopped_(false) {
45 void TearDown() override
{
46 webkit_source_
.reset();
47 blink::WebHeap::collectAllGarbageForTesting();
50 void InitWithDeviceInfo(const StreamDeviceInfo
& device_info
) {
51 scoped_ptr
<MockVideoCapturerDelegate
> delegate(
52 new MockVideoCapturerDelegate(device_info
));
53 delegate_
= delegate
.get();
54 source_
= new MediaStreamVideoCapturerSource(
56 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped
,
57 base::Unretained(this)),
60 webkit_source_
.initialize(base::UTF8ToUTF16("dummy_source_id"),
61 blink::WebMediaStreamSource::TypeVideo
,
62 base::UTF8ToUTF16("dummy_source_name"),
63 false /* remote */ , true /* readonly */);
64 webkit_source_
.setExtraData(source_
);
65 webkit_source_id_
= webkit_source_
.id();
68 blink::WebMediaStreamTrack
StartSource() {
69 MockMediaConstraintFactory factory
;
71 // CreateVideoTrack will trigger OnConstraintsApplied.
72 return MediaStreamVideoTrack::CreateVideoTrack(
73 source_
, factory
.CreateWebMediaConstraints(),
75 &MediaStreamVideoCapturerSourceTest::OnConstraintsApplied
,
76 base::Unretained(this)),
80 MockVideoCapturerDelegate
& mock_delegate() {
84 void OnSourceStopped(const blink::WebMediaStreamSource
& source
) {
85 source_stopped_
= true;
86 EXPECT_EQ(source
.id(), webkit_source_id_
);
90 void OnConstraintsApplied(MediaStreamSource
* source
,
91 MediaStreamRequestResult result
,
92 const blink::WebString
& result_name
) {
95 base::MessageLoopForUI message_loop_
;
96 scoped_ptr
<ChildProcess
> child_process_
;
97 blink::WebMediaStreamSource webkit_source_
;
98 MediaStreamVideoCapturerSource
* source_
; // owned by |webkit_source_|.
99 MockVideoCapturerDelegate
* delegate_
; // owned by |source|.
100 blink::WebString webkit_source_id_
;
101 bool source_stopped_
;
104 TEST_F(MediaStreamVideoCapturerSourceTest
, TabCaptureAllowResolutionChange
) {
105 StreamDeviceInfo device_info
;
106 device_info
.device
.type
= MEDIA_TAB_VIDEO_CAPTURE
;
107 InitWithDeviceInfo(device_info
);
109 EXPECT_CALL(mock_delegate(), StartCapture(
110 testing::Field(&media::VideoCaptureParams::resolution_change_policy
,
111 media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT
),
113 testing::_
)).Times(1);
114 blink::WebMediaStreamTrack track
= StartSource();
115 // When the track goes out of scope, the source will be stopped.
116 EXPECT_CALL(mock_delegate(), StopCapture());
119 TEST_F(MediaStreamVideoCapturerSourceTest
,
120 DesktopCaptureAllowResolutionChange
) {
121 StreamDeviceInfo device_info
;
122 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
123 InitWithDeviceInfo(device_info
);
125 EXPECT_CALL(mock_delegate(), StartCapture(
126 testing::Field(&media::VideoCaptureParams::resolution_change_policy
,
127 media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT
),
129 testing::_
)).Times(1);
130 blink::WebMediaStreamTrack track
= StartSource();
131 // When the track goes out of scope, the source will be stopped.
132 EXPECT_CALL(mock_delegate(), StopCapture());
135 TEST_F(MediaStreamVideoCapturerSourceTest
, Ended
) {
136 StreamDeviceInfo device_info
;
137 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
138 scoped_ptr
<VideoCapturerDelegate
> delegate(
139 new VideoCapturerDelegate(device_info
));
140 VideoCapturerDelegate
* delegate_ptr
= delegate
.get();
141 source_
= new MediaStreamVideoCapturerSource(
143 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped
,
144 base::Unretained(this)),
146 webkit_source_
.initialize(base::UTF8ToUTF16("dummy_source_id"),
147 blink::WebMediaStreamSource::TypeVideo
,
148 base::UTF8ToUTF16("dummy_source_name"),
149 false /* remote */ , true /* readonly */);
150 webkit_source_
.setExtraData(source_
);
151 webkit_source_id_
= webkit_source_
.id();
152 blink::WebMediaStreamTrack track
= StartSource();
153 message_loop_
.RunUntilIdle();
155 delegate_ptr
->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_STARTED
);
156 message_loop_
.RunUntilIdle();
157 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
,
158 webkit_source_
.readyState());
160 EXPECT_FALSE(source_stopped_
);
161 delegate_ptr
->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_ERROR
);
162 message_loop_
.RunUntilIdle();
163 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
,
164 webkit_source_
.readyState());
165 // Verify that MediaStreamSource::SourceStoppedCallback has been triggered.
166 EXPECT_TRUE(source_stopped_
);
169 class FakeMediaStreamVideoSink
: public MediaStreamVideoSink
{
171 FakeMediaStreamVideoSink(base::TimeTicks
* capture_time
,
172 base::Closure got_frame_cb
)
173 : capture_time_(capture_time
),
174 got_frame_cb_(got_frame_cb
) {
177 void OnVideoFrame(const scoped_refptr
<media::VideoFrame
>& frame
,
178 const media::VideoCaptureFormat
& format
,
179 const base::TimeTicks
& capture_time
) {
180 *capture_time_
= capture_time
;
181 base::ResetAndReturn(&got_frame_cb_
).Run();
185 base::TimeTicks
* capture_time_
;
186 base::Closure got_frame_cb_
;
189 TEST_F(MediaStreamVideoCapturerSourceTest
, CaptureTime
) {
190 StreamDeviceInfo device_info
;
191 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
192 InitWithDeviceInfo(device_info
);
194 VideoCaptureDeliverFrameCB deliver_frame_cb
;
195 VideoCapturerDelegate::RunningCallback running_cb
;
197 EXPECT_CALL(mock_delegate(), StartCapture(
202 .WillOnce(testing::DoAll(testing::SaveArg
<1>(&deliver_frame_cb
),
203 testing::SaveArg
<2>(&running_cb
)));
204 EXPECT_CALL(mock_delegate(), StopCapture());
205 blink::WebMediaStreamTrack track
= StartSource();
206 running_cb
.Run(MEDIA_DEVICE_OK
);
208 base::RunLoop run_loop
;
209 base::TimeTicks reference_capture_time
=
210 base::TimeTicks::FromInternalValue(60013);
211 base::TimeTicks capture_time
;
212 FakeMediaStreamVideoSink
fake_sink(
214 media::BindToCurrentLoop(run_loop
.QuitClosure()));
215 FakeMediaStreamVideoSink::AddToVideoTrack(
217 base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame
,
218 base::Unretained(&fake_sink
)),
220 child_process_
->io_message_loop()->PostTask(
222 base::Bind(deliver_frame_cb
,
223 media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)),
224 media::VideoCaptureFormat(),
225 reference_capture_time
));
227 FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink
, track
);
228 EXPECT_EQ(reference_capture_time
, capture_time
);
231 } // namespace content