1 // Copyright 2020 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.
4 
5 #include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
6 
7 #include "base/run_loop.h"
8 #include "media/base/bind_to_current_loop.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
11 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
12 #include "third_party/blink/public/web/web_heap.h"
13 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
14 #include "third_party/blink/renderer/modules/mediastream/video_track_adapter_settings.h"
15 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
16 #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
17 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
18 
19 namespace blink {
20 
21 namespace {
22 
23 class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
24  public:
FakeMediaStreamVideoSink(base::TimeTicks * capture_time,media::VideoFrameMetadata * metadata,gfx::Size * natural_size,base::OnceClosure got_frame_cb)25   FakeMediaStreamVideoSink(base::TimeTicks* capture_time,
26                            media::VideoFrameMetadata* metadata,
27                            gfx::Size* natural_size,
28                            base::OnceClosure got_frame_cb)
29       : capture_time_(capture_time),
30         metadata_(metadata),
31         natural_size_(natural_size),
32         got_frame_cb_(std::move(got_frame_cb)) {}
33 
ConnectToTrack(const WebMediaStreamTrack & track)34   void ConnectToTrack(const WebMediaStreamTrack& track) {
35     MediaStreamVideoSink::ConnectToTrack(
36         track,
37         ConvertToBaseRepeatingCallback(
38             CrossThreadBindRepeating(&FakeMediaStreamVideoSink::OnVideoFrame,
39                                      WTF::CrossThreadUnretained(this))),
40         true);
41   }
42 
DisconnectFromTrack()43   void DisconnectFromTrack() { MediaStreamVideoSink::DisconnectFromTrack(); }
44 
OnVideoFrame(scoped_refptr<media::VideoFrame> frame,base::TimeTicks capture_time)45   void OnVideoFrame(scoped_refptr<media::VideoFrame> frame,
46                     base::TimeTicks capture_time) {
47     *capture_time_ = capture_time;
48     *metadata_ = *frame->metadata();
49     *natural_size_ = frame->natural_size();
50     std::move(got_frame_cb_).Run();
51   }
52 
53  private:
54   base::TimeTicks* const capture_time_;
55   media::VideoFrameMetadata* const metadata_;
56   gfx::Size* const natural_size_;
57   base::OnceClosure got_frame_cb_;
58 };
59 
60 }  // namespace
61 
62 class PushableMediaStreamVideoSourceTest : public testing::Test {
63  public:
PushableMediaStreamVideoSourceTest()64   PushableMediaStreamVideoSourceTest() {
65     pushable_video_source_ = new PushableMediaStreamVideoSource();
66     stream_source_ = MakeGarbageCollected<MediaStreamSource>(
67         "dummy_source_id", MediaStreamSource::kTypeVideo, "dummy_source_name",
68         false /* remote */);
69     stream_source_->SetPlatformSource(base::WrapUnique(pushable_video_source_));
70   }
71 
TearDown()72   void TearDown() override {
73     stream_source_ = nullptr;
74     WebHeap::CollectAllGarbageForTesting();
75   }
76 
StartSource()77   WebMediaStreamTrack StartSource() {
78     return MediaStreamVideoTrack::CreateVideoTrack(
79         pushable_video_source_,
80         MediaStreamVideoSource::ConstraintsOnceCallback(),
81         /*enabled=*/true);
82   }
83 
84  protected:
85   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
86 
87   Persistent<MediaStreamSource> stream_source_;
88   PushableMediaStreamVideoSource* pushable_video_source_;
89 };
90 
TEST_F(PushableMediaStreamVideoSourceTest,StartAndStop)91 TEST_F(PushableMediaStreamVideoSourceTest, StartAndStop) {
92   EXPECT_EQ(MediaStreamSource::kReadyStateLive,
93             stream_source_->GetReadyState());
94   EXPECT_FALSE(pushable_video_source_->running());
95 
96   WebMediaStreamTrack track = StartSource();
97   EXPECT_EQ(MediaStreamSource::kReadyStateLive,
98             stream_source_->GetReadyState());
99   EXPECT_TRUE(pushable_video_source_->running());
100 
101   // If the pushable source stops, the MediaStreamSource should stop.
102   pushable_video_source_->StopSource();
103   EXPECT_EQ(MediaStreamSource::kReadyStateEnded,
104             stream_source_->GetReadyState());
105   EXPECT_FALSE(pushable_video_source_->running());
106 }
107 
TEST_F(PushableMediaStreamVideoSourceTest,FramesPropagateToSink)108 TEST_F(PushableMediaStreamVideoSourceTest, FramesPropagateToSink) {
109   WebMediaStreamTrack track = StartSource();
110   base::RunLoop run_loop;
111   base::TimeTicks reference_capture_time = base::TimeTicks::Now();
112   base::TimeTicks capture_time;
113   media::VideoFrameMetadata metadata;
114   gfx::Size natural_size;
115   FakeMediaStreamVideoSink fake_sink(
116       &capture_time, &metadata, &natural_size,
117       media::BindToCurrentLoop(run_loop.QuitClosure()));
118   fake_sink.ConnectToTrack(track);
119   const scoped_refptr<media::VideoFrame> frame =
120       media::VideoFrame::CreateBlackFrame(gfx::Size(100, 50));
121   frame->metadata()->frame_rate = 30.0;
122 
123   pushable_video_source_->PushFrame(frame, reference_capture_time);
124   run_loop.Run();
125 
126   fake_sink.DisconnectFromTrack();
127   EXPECT_EQ(reference_capture_time, capture_time);
128   EXPECT_EQ(30.0, *metadata.frame_rate);
129   EXPECT_EQ(natural_size.width(), 100);
130   EXPECT_EQ(natural_size.height(), 50);
131 }
132 
133 }  // namespace blink
134