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"
21 class MockVideoCapturerDelegate
: public VideoCapturerDelegate
{
23 explicit MockVideoCapturerDelegate(const StreamDeviceInfo
& device_info
)
24 : VideoCapturerDelegate(device_info
) {}
26 MOCK_METHOD3(StartCapture
,
27 void(const media::VideoCaptureParams
& params
,
28 const VideoCaptureDeliverFrameCB
& new_frame_callback
,
29 const RunningCallback
& running_callback
));
30 MOCK_METHOD0(StopCapture
, void());
33 virtual ~MockVideoCapturerDelegate() {}
36 class MediaStreamVideoCapturerSourceTest
: public testing::Test
{
38 MediaStreamVideoCapturerSourceTest()
39 : child_process_(new ChildProcess()),
41 source_stopped_(false) {
44 void InitWithDeviceInfo(const StreamDeviceInfo
& device_info
) {
45 delegate_
= new MockVideoCapturerDelegate(device_info
);
46 source_
= new MediaStreamVideoCapturerSource(
48 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped
,
49 base::Unretained(this)),
52 webkit_source_
.initialize(base::UTF8ToUTF16("dummy_source_id"),
53 blink::WebMediaStreamSource::TypeVideo
,
54 base::UTF8ToUTF16("dummy_source_name"));
55 webkit_source_
.setExtraData(source_
);
58 blink::WebMediaStreamTrack
StartSource() {
59 MockMediaConstraintFactory factory
;
61 // CreateVideoTrack will trigger OnConstraintsApplied.
62 return MediaStreamVideoTrack::CreateVideoTrack(
63 source_
, factory
.CreateWebMediaConstraints(),
65 &MediaStreamVideoCapturerSourceTest::OnConstraintsApplied
,
66 base::Unretained(this)),
70 MockVideoCapturerDelegate
& mock_delegate() {
71 return *static_cast<MockVideoCapturerDelegate
*>(delegate_
.get());
74 void OnSourceStopped(const blink::WebMediaStreamSource
& source
) {
75 source_stopped_
= true;
76 EXPECT_EQ(source
.id(), webkit_source_
.id());
80 void OnConstraintsApplied(MediaStreamSource
* source
,
81 MediaStreamRequestResult result
,
82 const blink::WebString
& result_name
) {
85 base::MessageLoopForUI message_loop_
;
86 scoped_ptr
<ChildProcess
> child_process_
;
87 blink::WebMediaStreamSource webkit_source_
;
88 MediaStreamVideoCapturerSource
* source_
; // owned by webkit_source.
89 scoped_refptr
<VideoCapturerDelegate
> delegate_
;
93 TEST_F(MediaStreamVideoCapturerSourceTest
, TabCaptureAllowResolutionChange
) {
94 StreamDeviceInfo device_info
;
95 device_info
.device
.type
= MEDIA_TAB_VIDEO_CAPTURE
;
96 InitWithDeviceInfo(device_info
);
98 EXPECT_CALL(mock_delegate(), StartCapture(
99 testing::Field(&media::VideoCaptureParams::allow_resolution_change
, true),
101 testing::_
)).Times(1);
102 blink::WebMediaStreamTrack track
= StartSource();
103 // When the track goes out of scope, the source will be stopped.
104 EXPECT_CALL(mock_delegate(), StopCapture());
107 TEST_F(MediaStreamVideoCapturerSourceTest
,
108 DesktopCaptureAllowResolutionChange
) {
109 StreamDeviceInfo device_info
;
110 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
111 InitWithDeviceInfo(device_info
);
113 EXPECT_CALL(mock_delegate(), StartCapture(
114 testing::Field(&media::VideoCaptureParams::allow_resolution_change
, true),
116 testing::_
)).Times(1);
117 blink::WebMediaStreamTrack track
= StartSource();
118 // When the track goes out of scope, the source will be stopped.
119 EXPECT_CALL(mock_delegate(), StopCapture());
122 TEST_F(MediaStreamVideoCapturerSourceTest
, Ended
) {
123 StreamDeviceInfo device_info
;
124 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
125 delegate_
= new VideoCapturerDelegate(device_info
);
126 source_
= new MediaStreamVideoCapturerSource(
128 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped
,
129 base::Unretained(this)),
131 webkit_source_
.initialize(base::UTF8ToUTF16("dummy_source_id"),
132 blink::WebMediaStreamSource::TypeVideo
,
133 base::UTF8ToUTF16("dummy_source_name"));
134 webkit_source_
.setExtraData(source_
);
135 blink::WebMediaStreamTrack track
= StartSource();
136 message_loop_
.RunUntilIdle();
138 delegate_
->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_STARTED
);
139 message_loop_
.RunUntilIdle();
140 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive
,
141 webkit_source_
.readyState());
143 EXPECT_FALSE(source_stopped_
);
144 delegate_
->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_ERROR
);
145 message_loop_
.RunUntilIdle();
146 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded
,
147 webkit_source_
.readyState());
148 // Verify that MediaStreamSource::SourceStoppedCallback has been triggered.
149 EXPECT_TRUE(source_stopped_
);
152 class FakeMediaStreamVideoSink
: public MediaStreamVideoSink
{
154 FakeMediaStreamVideoSink(base::TimeTicks
* capture_time
,
155 base::Closure got_frame_cb
)
156 : capture_time_(capture_time
),
157 got_frame_cb_(got_frame_cb
) {
160 void OnVideoFrame(const scoped_refptr
<media::VideoFrame
>& frame
,
161 const media::VideoCaptureFormat
& format
,
162 const base::TimeTicks
& capture_time
) {
163 *capture_time_
= capture_time
;
164 base::ResetAndReturn(&got_frame_cb_
).Run();
168 base::TimeTicks
* capture_time_
;
169 base::Closure got_frame_cb_
;
172 TEST_F(MediaStreamVideoCapturerSourceTest
, CaptureTime
) {
173 StreamDeviceInfo device_info
;
174 device_info
.device
.type
= MEDIA_DESKTOP_VIDEO_CAPTURE
;
175 InitWithDeviceInfo(device_info
);
177 VideoCaptureDeliverFrameCB deliver_frame_cb
;
178 VideoCapturerDelegate::RunningCallback running_cb
;
180 EXPECT_CALL(mock_delegate(), StartCapture(
185 .WillOnce(testing::DoAll(testing::SaveArg
<1>(&deliver_frame_cb
),
186 testing::SaveArg
<2>(&running_cb
)));
187 EXPECT_CALL(mock_delegate(), StopCapture());
188 blink::WebMediaStreamTrack track
= StartSource();
189 running_cb
.Run(MEDIA_DEVICE_OK
);
191 base::RunLoop run_loop
;
192 base::TimeTicks reference_capture_time
=
193 base::TimeTicks::FromInternalValue(60013);
194 base::TimeTicks capture_time
;
195 FakeMediaStreamVideoSink
fake_sink(
197 media::BindToCurrentLoop(run_loop
.QuitClosure()));
198 FakeMediaStreamVideoSink::AddToVideoTrack(
200 base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame
,
201 base::Unretained(&fake_sink
)),
203 child_process_
->io_message_loop()->PostTask(
205 base::Bind(deliver_frame_cb
,
206 media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)),
207 media::VideoCaptureFormat(),
208 reference_capture_time
));
210 FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink
, track
);
211 EXPECT_EQ(reference_capture_time
, capture_time
);
214 } // namespace content