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
) {}
29 void(const media::VideoCaptureParams
& params
,
30 const VideoCaptureDeliverFrameCB
& new_frame_callback
,
31 scoped_refptr
<base::SingleThreadTaskRunner
>
32 frame_callback_task_runner
,
33 const RunningCallback
& running_callback
));
34 MOCK_METHOD0(StopCapture
, void());
37 class MediaStreamVideoCapturerSourceTest
: public testing::Test
{
39 MediaStreamVideoCapturerSourceTest()
40 : child_process_(new ChildProcess()),
43 source_stopped_(false) {
46 void TearDown() override
{
47 webkit_source_
.reset();
48 blink::WebHeap::collectAllGarbageForTesting();
51 void InitWithDeviceInfo(const StreamDeviceInfo
& device_info
) {
52 scoped_ptr
<MockVideoCapturerDelegate
> delegate(
53 new MockVideoCapturerDelegate(device_info
));
54 delegate_
= delegate
.get();
55 source_
= new MediaStreamVideoCapturerSource(
56 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped
,
57 base::Unretained(this)),
59 source_
->SetDeviceInfo(device_info
);
61 webkit_source_
.initialize(base::UTF8ToUTF16("dummy_source_id"),
62 blink::WebMediaStreamSource::TypeVideo
,
63 base::UTF8ToUTF16("dummy_source_name"),
64 false /* remote */ , true /* readonly */);
65 webkit_source_
.setExtraData(source_
);
66 webkit_source_id_
= webkit_source_
.id();
69 blink::WebMediaStreamTrack
StartSource() {
70 MockMediaConstraintFactory factory
;
72 // CreateVideoTrack will trigger OnConstraintsApplied.
73 return MediaStreamVideoTrack::CreateVideoTrack(
74 source_
, factory
.CreateWebMediaConstraints(),
76 &MediaStreamVideoCapturerSourceTest::OnConstraintsApplied
,
77 base::Unretained(this)),
81 MockVideoCapturerDelegate
& mock_delegate() {
85 void OnSourceStopped(const blink::WebMediaStreamSource
& source
) {
86 source_stopped_
= true;
87 EXPECT_EQ(source
.id(), webkit_source_id_
);
91 void OnConstraintsApplied(MediaStreamSource
* source
,
92 MediaStreamRequestResult result
,
93 const blink::WebString
& result_name
) {
96 base::MessageLoopForUI message_loop_
;
97 scoped_ptr
<ChildProcess
> child_process_
;
98 blink::WebMediaStreamSource webkit_source_
;
99 MediaStreamVideoCapturerSource
* source_
; // owned by |webkit_source_|.
100 MockVideoCapturerDelegate
* delegate_
; // owned by |source|.
101 blink::WebString webkit_source_id_
;
102 bool source_stopped_
;
105 TEST_F(MediaStreamVideoCapturerSourceTest
, TabCaptureAllowResolutionChange
) {
106 StreamDeviceInfo device_info
;
107 device_info
.device
.type
= MEDIA_TAB_VIDEO_CAPTURE
;
108 InitWithDeviceInfo(device_info
);
110 EXPECT_CALL(mock_delegate(), StartCapture(
111 testing::Field(&media::VideoCaptureParams::resolution_change_policy
,
112 media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT
),
115 testing::_
)).Times(1);
116 blink::WebMediaStreamTrack track
= StartSource();
117 // When the track goes out of scope, the source will be stopped.
118 EXPECT_CALL(mock_delegate(), StopCapture());
121 TEST_F(MediaStreamVideoCapturerSourceTest
,
122 DesktopCaptureAllowResolutionChange
) {
123 StreamDeviceInfo device_info
;
124 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
125 InitWithDeviceInfo(device_info
);
127 EXPECT_CALL(mock_delegate(), StartCapture(
128 testing::Field(&media::VideoCaptureParams::resolution_change_policy
,
129 media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT
),
132 testing::_
)).Times(1);
133 blink::WebMediaStreamTrack track
= StartSource();
134 // When the track goes out of scope, the source will be stopped.
135 EXPECT_CALL(mock_delegate(), StopCapture());
138 TEST_F(MediaStreamVideoCapturerSourceTest
, Ended
) {
139 StreamDeviceInfo device_info
;
140 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
141 scoped_ptr
<VideoCapturerDelegate
> delegate(
142 new VideoCapturerDelegate(device_info
));
143 VideoCapturerDelegate
* delegate_ptr
= delegate
.get();
144 source_
= new MediaStreamVideoCapturerSource(
145 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped
,
146 base::Unretained(this)),
148 source_
->SetDeviceInfo(device_info
);
149 webkit_source_
.initialize(base::UTF8ToUTF16("dummy_source_id"),
150 blink::WebMediaStreamSource::TypeVideo
,
151 base::UTF8ToUTF16("dummy_source_name"),
152 false /* remote */ , true /* readonly */);
153 webkit_source_
.setExtraData(source_
);
154 webkit_source_id_
= webkit_source_
.id();
155 blink::WebMediaStreamTrack track
= StartSource();
156 message_loop_
.RunUntilIdle();
158 delegate_ptr
->OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED
);
159 message_loop_
.RunUntilIdle();
160 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
,
161 webkit_source_
.readyState());
163 EXPECT_FALSE(source_stopped_
);
164 delegate_ptr
->OnStateUpdate(VIDEO_CAPTURE_STATE_ERROR
);
165 message_loop_
.RunUntilIdle();
166 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
,
167 webkit_source_
.readyState());
168 // Verify that MediaStreamSource::SourceStoppedCallback has been triggered.
169 EXPECT_TRUE(source_stopped_
);
172 class FakeMediaStreamVideoSink
: public MediaStreamVideoSink
{
174 FakeMediaStreamVideoSink(base::TimeTicks
* capture_time
,
175 media::VideoFrameMetadata
* metadata
,
176 base::Closure got_frame_cb
)
177 : capture_time_(capture_time
),
179 got_frame_cb_(got_frame_cb
) {
182 void OnVideoFrame(const scoped_refptr
<media::VideoFrame
>& frame
,
183 const base::TimeTicks
& capture_time
) {
184 *capture_time_
= capture_time
;
186 base::DictionaryValue tmp
;
187 frame
->metadata()->MergeInternalValuesInto(&tmp
);
188 metadata_
->MergeInternalValuesFrom(tmp
);
189 base::ResetAndReturn(&got_frame_cb_
).Run();
193 base::TimeTicks
* const capture_time_
;
194 media::VideoFrameMetadata
* const metadata_
;
195 base::Closure got_frame_cb_
;
198 TEST_F(MediaStreamVideoCapturerSourceTest
, CaptureTimeAndMetadataPlumbing
) {
199 StreamDeviceInfo device_info
;
200 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
201 InitWithDeviceInfo(device_info
);
203 VideoCaptureDeliverFrameCB deliver_frame_cb
;
204 VideoCapturerDelegate::RunningCallback running_cb
;
206 EXPECT_CALL(mock_delegate(), StartCapture(
212 .WillOnce(testing::DoAll(testing::SaveArg
<1>(&deliver_frame_cb
),
213 testing::SaveArg
<3>(&running_cb
)));
214 EXPECT_CALL(mock_delegate(), StopCapture());
215 blink::WebMediaStreamTrack track
= StartSource();
216 running_cb
.Run(true);
218 base::RunLoop run_loop
;
219 base::TimeTicks reference_capture_time
=
220 base::TimeTicks::FromInternalValue(60013);
221 base::TimeTicks capture_time
;
222 media::VideoFrameMetadata metadata
;
223 FakeMediaStreamVideoSink
fake_sink(
226 media::BindToCurrentLoop(run_loop
.QuitClosure()));
227 FakeMediaStreamVideoSink::AddToVideoTrack(
229 base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame
,
230 base::Unretained(&fake_sink
)),
232 const scoped_refptr
<media::VideoFrame
> frame
=
233 media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2));
234 frame
->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE
, 30.0);
235 child_process_
->io_message_loop()->PostTask(
236 FROM_HERE
, base::Bind(deliver_frame_cb
, frame
, reference_capture_time
));
238 FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink
, track
);
239 EXPECT_EQ(reference_capture_time
, capture_time
);
240 double metadata_value
;
241 EXPECT_TRUE(metadata
.GetDouble(media::VideoFrameMetadata::FRAME_RATE
,
243 EXPECT_EQ(30.0, metadata_value
);
246 } // namespace content