123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// found in the LICENSE file.
423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/bind.h"
646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/callback_helpers.h"
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/message_loop/message_loop.h"
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/run_loop.h"
923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/child/child_process.h"
1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "content/public/renderer/media_stream_video_sink.h"
1223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/renderer/media/media_stream_video_capturer_source.h"
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/renderer/media/media_stream_video_track.h"
1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/renderer/media/mock_media_constraint_factory.h"
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "media/base/bind_to_current_loop.h"
1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace content {
2023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)class MockVideoCapturerDelegate : public VideoCapturerDelegate {
2223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) public:
2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  explicit MockVideoCapturerDelegate(const StreamDeviceInfo& device_info)
2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      : VideoCapturerDelegate(device_info) {}
2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  MOCK_METHOD3(StartCapture,
2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)               void(const media::VideoCaptureParams& params,
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                    const VideoCaptureDeliverFrameCB& new_frame_callback,
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                    const RunningCallback& running_callback));
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  MOCK_METHOD0(StopCapture, void());
3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private:
3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual ~MockVideoCapturerDelegate() {}
3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)};
3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)class MediaStreamVideoCapturerSourceTest : public testing::Test {
3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) public:
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  MediaStreamVideoCapturerSourceTest()
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)     : child_process_(new ChildProcess()),
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       source_(NULL) {
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  void InitWithDeviceInfo(const StreamDeviceInfo& device_info) {
4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    delegate_ = new MockVideoCapturerDelegate(device_info);
4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    source_ = new MediaStreamVideoCapturerSource(
4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        device_info,
4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        MediaStreamSource::SourceStoppedCallback(),
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        delegate_);
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                              blink::WebMediaStreamSource::TypeVideo,
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                              base::UTF8ToUTF16("dummy_source_name"));
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    webkit_source_.setExtraData(source_);
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  blink::WebMediaStreamTrack StartSource() {
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    MockMediaConstraintFactory factory;
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool enabled = true;
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // CreateVideoTrack will trigger OnConstraintsApplied.
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return MediaStreamVideoTrack::CreateVideoTrack(
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        source_, factory.CreateWebMediaConstraints(),
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        base::Bind(
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            &MediaStreamVideoCapturerSourceTest::OnConstraintsApplied,
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            base::Unretained(this)),
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            enabled);
6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  MockVideoCapturerDelegate& mock_delegate() {
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return *static_cast<MockVideoCapturerDelegate*>(delegate_.get());
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) protected:
7323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  void OnConstraintsApplied(MediaStreamSource* source, bool success) {
7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoopForUI message_loop_;
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_ptr<ChildProcess> child_process_;
7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  blink::WebMediaStreamSource webkit_source_;
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  MediaStreamVideoCapturerSource* source_;  // owned by webkit_source.
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<VideoCapturerDelegate> delegate_;
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)};
8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) {
8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  StreamDeviceInfo device_info;
8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  InitWithDeviceInfo(device_info);
8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_CALL(mock_delegate(), StartCapture(
8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      testing::Field(&media::VideoCaptureParams::allow_resolution_change, true),
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      testing::_,
9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      testing::_)).Times(1);
920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  blink::WebMediaStreamTrack track = StartSource();
930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // When the track goes out of scope, the source will be stopped.
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_CALL(mock_delegate(), StopCapture());
9523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest,
9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)       DesktopCaptureAllowResolutionChange) {
9923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  StreamDeviceInfo device_info;
10023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
10123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  InitWithDeviceInfo(device_info);
10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_CALL(mock_delegate(), StartCapture(
10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      testing::Field(&media::VideoCaptureParams::allow_resolution_change, true),
10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      testing::_,
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      testing::_)).Times(1);
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  blink::WebMediaStreamTrack track = StartSource();
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // When the track goes out of scope, the source will be stopped.
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_CALL(mock_delegate(), StopCapture());
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest, Ended) {
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  StreamDeviceInfo device_info;
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  delegate_ = new VideoCapturerDelegate(device_info);
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  source_ = new MediaStreamVideoCapturerSource(
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      device_info,
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      MediaStreamSource::SourceStoppedCallback(),
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      delegate_);
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            blink::WebMediaStreamSource::TypeVideo,
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            base::UTF8ToUTF16("dummy_source_name"));
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  webkit_source_.setExtraData(source_);
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  blink::WebMediaStreamTrack track = StartSource();
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message_loop_.RunUntilIdle();
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_STARTED);
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message_loop_.RunUntilIdle();
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive,
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            webkit_source_.readyState());
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_ERROR);
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message_loop_.RunUntilIdle();
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded,
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            webkit_source_.readyState());
13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public:
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  FakeMediaStreamVideoSink(base::TimeTicks* capture_time,
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                           base::Closure got_frame_cb)
14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      : capture_time_(capture_time),
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        got_frame_cb_(got_frame_cb) {
14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                    const media::VideoCaptureFormat& format,
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                    const base::TimeTicks& capture_time) {
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    *capture_time_ = capture_time;
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    base::ResetAndReturn(&got_frame_cb_).Run();
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) private:
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TimeTicks* capture_time_;
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::Closure got_frame_cb_;
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTime) {
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  StreamDeviceInfo device_info;
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  InitWithDeviceInfo(device_info);
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  VideoCaptureDeliverFrameCB deliver_frame_cb;
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  VideoCapturerDelegate::RunningCallback running_cb;
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_CALL(mock_delegate(), StartCapture(
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      testing::_,
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      testing::_,
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      testing::_))
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      .Times(1)
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      .WillOnce(testing::DoAll(testing::SaveArg<1>(&deliver_frame_cb),
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                               testing::SaveArg<2>(&running_cb)));
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_CALL(mock_delegate(), StopCapture());
17446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  blink::WebMediaStreamTrack track = StartSource();
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  running_cb.Run(true);
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::RunLoop run_loop;
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TimeTicks reference_capture_time =
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::TimeTicks::FromInternalValue(60013);
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::TimeTicks capture_time;
18146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  FakeMediaStreamVideoSink fake_sink(
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      &capture_time,
18346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      media::BindToCurrentLoop(run_loop.QuitClosure()));
18446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  FakeMediaStreamVideoSink::AddToVideoTrack(
18546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      &fake_sink,
18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame,
18746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 base::Unretained(&fake_sink)),
18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      track);
18946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  child_process_->io_message_loop()->PostTask(
19046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      FROM_HERE,
19146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(deliver_frame_cb,
19246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)),
19346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 media::VideoCaptureFormat(),
19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 reference_capture_time));
19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  run_loop.Run();
19646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink, track);
19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(reference_capture_time, capture_time);
19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
20023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}  // namespace content
201