Home | History | Annotate | Download | only in media
      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.
      4 
      5 #include "base/bind.h"
      6 #include "base/bind_helpers.h"
      7 #include "base/callback.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/run_loop.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/threading/thread_checker_impl.h"
     12 #include "content/child/child_process.h"
     13 #include "content/renderer/media/media_stream_video_track.h"
     14 #include "content/renderer/media/mock_media_stream_video_sink.h"
     15 #include "content/renderer/media/mock_media_stream_video_source.h"
     16 #include "media/base/video_frame.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 #include "third_party/WebKit/public/web/WebHeap.h"
     19 
     20 namespace content {
     21 
     22 const uint8 kBlackValue = 0x00;
     23 const uint8 kColorValue = 0xAB;
     24 
     25 ACTION_P(RunClosure, closure) {
     26   closure.Run();
     27 }
     28 
     29 class MediaStreamVideoTrackTest : public ::testing::Test {
     30  public:
     31   MediaStreamVideoTrackTest()
     32       : child_process_(new ChildProcess()),
     33         mock_source_(new MockMediaStreamVideoSource(false)),
     34         source_started_(false) {
     35     blink_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
     36                               blink::WebMediaStreamSource::TypeVideo,
     37                               base::UTF8ToUTF16("dummy_source_name"));
     38     blink_source_.setExtraData(mock_source_);
     39   }
     40 
     41   virtual ~MediaStreamVideoTrackTest() {
     42   }
     43 
     44   virtual void TearDown() OVERRIDE {
     45     blink_source_.reset();
     46     blink::WebHeap::collectAllGarbageForTesting();
     47   }
     48 
     49   void DeliverVideoFrameAndWaitForRenderer(MockMediaStreamVideoSink* sink) {
     50     base::RunLoop run_loop;
     51     base::Closure quit_closure = run_loop.QuitClosure();
     52     EXPECT_CALL(*sink, OnVideoFrame()).WillOnce(
     53         RunClosure(quit_closure));
     54     scoped_refptr<media::VideoFrame> frame =
     55         media::VideoFrame::CreateColorFrame(
     56             gfx::Size(MediaStreamVideoSource::kDefaultWidth,
     57                       MediaStreamVideoSource::kDefaultHeight),
     58             kColorValue, kColorValue, kColorValue, base::TimeDelta());
     59     mock_source()->DeliverVideoFrame(frame);
     60     run_loop.Run();
     61   }
     62 
     63  protected:
     64   base::MessageLoop* io_message_loop() const {
     65     return child_process_->io_message_loop();
     66   }
     67 
     68   // Create a track that's associated with |mock_source_|.
     69   blink::WebMediaStreamTrack CreateTrack() {
     70     blink::WebMediaConstraints constraints;
     71     constraints.initialize();
     72     bool enabled = true;
     73     blink::WebMediaStreamTrack track =
     74         MediaStreamVideoTrack::CreateVideoTrack(
     75             mock_source_, constraints,
     76             MediaStreamSource::ConstraintsCallback(), enabled);
     77     if (!source_started_) {
     78       mock_source_->StartMockedSource();
     79       source_started_ = true;
     80     }
     81     return track;
     82   }
     83 
     84   MockMediaStreamVideoSource* mock_source() { return mock_source_; }
     85   const blink::WebMediaStreamSource& blink_source() const {
     86     return blink_source_;
     87   }
     88 
     89  private:
     90   base::MessageLoopForUI message_loop_;
     91   scoped_ptr<ChildProcess> child_process_;
     92   blink::WebMediaStreamSource blink_source_;
     93   // |mock_source_| is owned by |webkit_source_|.
     94   MockMediaStreamVideoSource* mock_source_;
     95   bool source_started_;
     96 };
     97 
     98 TEST_F(MediaStreamVideoTrackTest, AddAndRemoveSink) {
     99   MockMediaStreamVideoSink sink;
    100   blink::WebMediaStreamTrack track = CreateTrack();
    101   MediaStreamVideoSink::AddToVideoTrack(
    102       &sink, sink.GetDeliverFrameCB(), track);
    103 
    104   DeliverVideoFrameAndWaitForRenderer(&sink);
    105   EXPECT_EQ(1, sink.number_of_frames());
    106 
    107   DeliverVideoFrameAndWaitForRenderer(&sink);
    108 
    109   MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
    110 
    111   scoped_refptr<media::VideoFrame> frame =
    112       media::VideoFrame::CreateBlackFrame(
    113           gfx::Size(MediaStreamVideoSource::kDefaultWidth,
    114                     MediaStreamVideoSource::kDefaultHeight));
    115   mock_source()->DeliverVideoFrame(frame);
    116   // Wait for the IO thread to complete delivering frames.
    117   io_message_loop()->RunUntilIdle();
    118   EXPECT_EQ(2, sink.number_of_frames());
    119 }
    120 
    121 class CheckThreadHelper {
    122  public:
    123   CheckThreadHelper(base::Closure callback, bool* correct)
    124       : callback_(callback),
    125         correct_(correct) {
    126   }
    127 
    128   ~CheckThreadHelper() {
    129     *correct_ = thread_checker_.CalledOnValidThread();
    130     callback_.Run();
    131   }
    132 
    133  private:
    134   base::Closure callback_;
    135   bool* correct_;
    136   base::ThreadCheckerImpl thread_checker_;
    137 };
    138 
    139 void CheckThreadVideoFrameReceiver(
    140     CheckThreadHelper* helper,
    141     const scoped_refptr<media::VideoFrame>& frame,
    142     const media::VideoCaptureFormat& format,
    143     const base::TimeTicks& estimated_capture_time) {
    144   // Do nothing.
    145 }
    146 
    147 // Checks that the callback given to the track is reset on the right thread.
    148 TEST_F(MediaStreamVideoTrackTest, ResetCallbackOnThread) {
    149   MockMediaStreamVideoSink sink;
    150   blink::WebMediaStreamTrack track = CreateTrack();
    151 
    152   base::RunLoop run_loop;
    153   bool correct = false;
    154   MediaStreamVideoSink::AddToVideoTrack(
    155       &sink,
    156       base::Bind(
    157           &CheckThreadVideoFrameReceiver,
    158           base::Owned(new CheckThreadHelper(run_loop.QuitClosure(), &correct))),
    159       track);
    160   MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
    161   run_loop.Run();
    162   EXPECT_TRUE(correct) << "Not called on correct thread.";
    163 }
    164 
    165 TEST_F(MediaStreamVideoTrackTest, SetEnabled) {
    166   MockMediaStreamVideoSink sink;
    167   blink::WebMediaStreamTrack track = CreateTrack();
    168   MediaStreamVideoSink::AddToVideoTrack(
    169       &sink, sink.GetDeliverFrameCB(), track);
    170 
    171   MediaStreamVideoTrack* video_track =
    172       MediaStreamVideoTrack::GetVideoTrack(track);
    173 
    174   DeliverVideoFrameAndWaitForRenderer(&sink);
    175   EXPECT_EQ(1, sink.number_of_frames());
    176   EXPECT_EQ(kColorValue, *sink.last_frame()->data(media::VideoFrame::kYPlane));
    177 
    178   video_track->SetEnabled(false);
    179   EXPECT_FALSE(sink.enabled());
    180 
    181   DeliverVideoFrameAndWaitForRenderer(&sink);
    182   EXPECT_EQ(2, sink.number_of_frames());
    183   EXPECT_EQ(kBlackValue, *sink.last_frame()->data(media::VideoFrame::kYPlane));
    184 
    185   video_track->SetEnabled(true);
    186   EXPECT_TRUE(sink.enabled());
    187   DeliverVideoFrameAndWaitForRenderer(&sink);
    188   EXPECT_EQ(3, sink.number_of_frames());
    189   EXPECT_EQ(kColorValue, *sink.last_frame()->data(media::VideoFrame::kYPlane));
    190   MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
    191 }
    192 
    193 TEST_F(MediaStreamVideoTrackTest, SourceStopped) {
    194   MockMediaStreamVideoSink sink;
    195   blink::WebMediaStreamTrack track = CreateTrack();
    196   MediaStreamVideoSink::AddToVideoTrack(
    197       &sink, sink.GetDeliverFrameCB(), track);
    198   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, sink.state());
    199 
    200   mock_source()->StopSource();
    201   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, sink.state());
    202   MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
    203 }
    204 
    205 TEST_F(MediaStreamVideoTrackTest, StopLastTrack) {
    206   MockMediaStreamVideoSink sink1;
    207   blink::WebMediaStreamTrack track1 = CreateTrack();
    208   MediaStreamVideoSink::AddToVideoTrack(
    209       &sink1, sink1.GetDeliverFrameCB(), track1);
    210   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, sink1.state());
    211 
    212   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive,
    213             blink_source().readyState());
    214 
    215   MockMediaStreamVideoSink sink2;
    216   blink::WebMediaStreamTrack track2 = CreateTrack();
    217   MediaStreamVideoSink::AddToVideoTrack(
    218       &sink2, sink2.GetDeliverFrameCB(), track2);
    219   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, sink2.state());
    220 
    221   MediaStreamVideoTrack* native_track1 =
    222       MediaStreamVideoTrack::GetVideoTrack(track1);
    223   native_track1->Stop();
    224   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, sink1.state());
    225   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive,
    226               blink_source().readyState());
    227   MediaStreamVideoSink::RemoveFromVideoTrack(&sink1, track1);
    228 
    229   MediaStreamVideoTrack* native_track2 =
    230         MediaStreamVideoTrack::GetVideoTrack(track2);
    231   native_track2->Stop();
    232   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, sink2.state());
    233   EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded,
    234             blink_source().readyState());
    235   MediaStreamVideoSink::RemoveFromVideoTrack(&sink2, track2);
    236 }
    237 
    238 }  // namespace content
    239