Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2012 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 <string>
      6 
      7 #include "base/bind.h"
      8 #include "base/callback_helpers.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/run_loop.h"
     11 #include "content/browser/browser_thread_impl.h"
     12 #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
     13 #include "content/browser/renderer_host/media/media_stream_manager.h"
     14 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
     15 #include "content/browser/renderer_host/media/video_capture_manager.h"
     16 #include "content/common/media/media_stream_messages.h"
     17 #include "content/common/media/media_stream_options.h"
     18 #include "content/public/test/mock_resource_context.h"
     19 #include "content/public/test/test_browser_thread_bundle.h"
     20 #include "content/test/test_content_browser_client.h"
     21 #include "content/test/test_content_client.h"
     22 #include "ipc/ipc_message_macros.h"
     23 #include "media/audio/audio_manager.h"
     24 #include "media/video/capture/fake_video_capture_device.h"
     25 #include "net/url_request/url_request_context.h"
     26 #include "testing/gmock/include/gmock/gmock.h"
     27 #include "testing/gtest/include/gtest/gtest.h"
     28 
     29 using ::testing::_;
     30 using ::testing::DeleteArg;
     31 using ::testing::DoAll;
     32 using ::testing::Return;
     33 using ::testing::SaveArg;
     34 
     35 const int kProcessId = 5;
     36 const int kRenderId = 6;
     37 const int kPageRequestId = 7;
     38 
     39 namespace content {
     40 
     41 class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
     42                                       public TestContentBrowserClient {
     43  public:
     44   MockMediaStreamDispatcherHost(
     45       const scoped_refptr<base::MessageLoopProxy>& message_loop,
     46       MediaStreamManager* manager)
     47       : MediaStreamDispatcherHost(kProcessId, manager),
     48         message_loop_(message_loop) {}
     49 
     50   // A list of mock methods.
     51   MOCK_METHOD4(OnStreamGenerated,
     52                void(int routing_id, int request_id, int audio_array_size,
     53                     int video_array_size));
     54   MOCK_METHOD2(OnStreamGenerationFailed, void(int routing_id, int request_id));
     55   MOCK_METHOD1(OnStopGeneratedStreamFromBrowser,
     56                void(int routing_id));
     57 
     58   // Accessor to private functions.
     59   void OnGenerateStream(int page_request_id,
     60                         const StreamOptions& components,
     61                         const base::Closure& quit_closure) {
     62     quit_closure_ = quit_closure;
     63     MediaStreamDispatcherHost::OnGenerateStream(
     64         kRenderId, page_request_id, components, GURL());
     65   }
     66 
     67   void OnStopGeneratedStream(const std::string& label) {
     68     MediaStreamDispatcherHost::OnStopGeneratedStream(kRenderId, label);
     69   }
     70 
     71   // Return the number of streams that have been opened or is being open.
     72   size_t NumberOfStreams() {
     73     return streams_.size();
     74   }
     75 
     76   std::string label_;
     77   StreamDeviceInfoArray audio_devices_;
     78   StreamDeviceInfoArray video_devices_;
     79 
     80  private:
     81   virtual ~MockMediaStreamDispatcherHost() {}
     82 
     83   // This method is used to dispatch IPC messages to the renderer. We intercept
     84   // these messages here and dispatch to our mock methods to verify the
     85   // conversation between this object and the renderer.
     86   virtual bool Send(IPC::Message* message) OVERRIDE {
     87     CHECK(message);
     88 
     89     // In this method we dispatch the messages to the according handlers as if
     90     // we are the renderer.
     91     bool handled = true;
     92     IPC_BEGIN_MESSAGE_MAP(MockMediaStreamDispatcherHost, *message)
     93       IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerated, OnStreamGenerated)
     94       IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerationFailed,
     95                           OnStreamGenerationFailed)
     96       IPC_MESSAGE_HANDLER(MediaStreamMsg_StopGeneratedStream,
     97                           OnStopGeneratedStreamFromBrowser)
     98       IPC_MESSAGE_UNHANDLED(handled = false)
     99     IPC_END_MESSAGE_MAP()
    100     EXPECT_TRUE(handled);
    101 
    102     delete message;
    103     return true;
    104   }
    105 
    106   // These handler methods do minimal things and delegate to the mock methods.
    107   void OnStreamGenerated(
    108       const IPC::Message& msg,
    109       int request_id,
    110       std::string label,
    111       StreamDeviceInfoArray audio_device_list,
    112       StreamDeviceInfoArray video_device_list) {
    113     OnStreamGenerated(msg.routing_id(), request_id, audio_device_list.size(),
    114         video_device_list.size());
    115     // Notify that the event have occured.
    116     message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure_));
    117     label_ = label;
    118     audio_devices_ = audio_device_list;
    119     video_devices_ = video_device_list;
    120   }
    121 
    122   void OnStreamGenerationFailed(const IPC::Message& msg, int request_id) {
    123     OnStreamGenerationFailed(msg.routing_id(), request_id);
    124     if (!quit_closure_.is_null())
    125       message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure_));
    126     label_= "";
    127   }
    128 
    129   void OnStopGeneratedStreamFromBrowser(const IPC::Message& msg,
    130                                         const std::string& label) {
    131     OnStopGeneratedStreamFromBrowser(msg.routing_id());
    132     // Notify that the event have occured.
    133     if (!quit_closure_.is_null())
    134       message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure_));
    135     label_ = "";
    136   }
    137 
    138   scoped_refptr<base::MessageLoopProxy> message_loop_;
    139   base::Closure quit_closure_;
    140 };
    141 
    142 class MockMediaStreamUIProxy : public FakeMediaStreamUIProxy {
    143  public:
    144   MOCK_METHOD1(OnStarted, void(const base::Closure& stop));
    145 };
    146 
    147 class MediaStreamDispatcherHostTest : public testing::Test {
    148  public:
    149   MediaStreamDispatcherHostTest()
    150       : old_browser_client_(NULL),
    151         thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
    152     // Create our own MediaStreamManager.
    153     audio_manager_.reset(media::AudioManager::Create());
    154     media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
    155     // Make sure we use fake devices to avoid long delays.
    156     media_stream_manager_->UseFakeDevice();
    157 
    158     host_ = new MockMediaStreamDispatcherHost(base::MessageLoopProxy::current(),
    159                                               media_stream_manager_.get());
    160 
    161     // Use the fake content client and browser.
    162     content_client_.reset(new TestContentClient());
    163     SetContentClient(content_client_.get());
    164     old_browser_client_ = SetBrowserClientForTesting(host_.get());
    165   }
    166 
    167   virtual ~MediaStreamDispatcherHostTest() {
    168     // Recover the old browser client and content client.
    169     SetBrowserClientForTesting(old_browser_client_);
    170     content_client_.reset();
    171     media_stream_manager_->WillDestroyCurrentMessageLoop();
    172   }
    173 
    174  protected:
    175   virtual void SetupFakeUI(bool expect_started) {
    176     scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
    177     if (expect_started) {
    178       EXPECT_CALL(*stream_ui, OnStarted(_));
    179     }
    180     media_stream_manager_->UseFakeUI(
    181         stream_ui.PassAs<FakeMediaStreamUIProxy>());
    182   }
    183 
    184   void GenerateStreamAndWaitForResult(int page_request_id,
    185                                       const StreamOptions& options) {
    186     base::RunLoop run_loop;
    187     host_->OnGenerateStream(page_request_id, options, run_loop.QuitClosure());
    188     run_loop.Run();
    189   }
    190 
    191   scoped_refptr<MockMediaStreamDispatcherHost> host_;
    192   scoped_ptr<media::AudioManager> audio_manager_;
    193   scoped_ptr<MediaStreamManager> media_stream_manager_;
    194   ContentBrowserClient* old_browser_client_;
    195   scoped_ptr<ContentClient> content_client_;
    196   content::TestBrowserThreadBundle thread_bundle_;
    197 };
    198 
    199 TEST_F(MediaStreamDispatcherHostTest, GenerateStream) {
    200   StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
    201 
    202   SetupFakeUI(true);
    203   EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
    204   GenerateStreamAndWaitForResult(kPageRequestId, options);
    205 
    206   std::string label =  host_->label_;
    207 
    208   EXPECT_EQ(host_->audio_devices_.size(), 0u);
    209   EXPECT_EQ(host_->video_devices_.size(), 1u);
    210   EXPECT_EQ(host_->NumberOfStreams(), 1u);
    211 
    212   host_->OnStopGeneratedStream(label);
    213   EXPECT_EQ(host_->NumberOfStreams(), 0u);
    214 }
    215 
    216 TEST_F(MediaStreamDispatcherHostTest, GenerateThreeStreams) {
    217   // This test opens three video capture devices. Two fake devices exists and it
    218   // is expected the last call to |Open()| will open the first device again, but
    219   // with a different label.
    220   StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
    221 
    222   // Generate first stream.
    223   SetupFakeUI(true);
    224   EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
    225   GenerateStreamAndWaitForResult(kPageRequestId, options);
    226 
    227   // Check the latest generated stream.
    228   EXPECT_EQ(host_->audio_devices_.size(), 0u);
    229   EXPECT_EQ(host_->video_devices_.size(), 1u);
    230   std::string label1 = host_->label_;
    231   std::string device_id1 = host_->video_devices_.front().device.id;
    232 
    233   // Check that we now have one opened streams.
    234   EXPECT_EQ(host_->NumberOfStreams(), 1u);
    235 
    236   // Generate second stream.
    237   SetupFakeUI(true);
    238   EXPECT_CALL(*host_.get(),
    239               OnStreamGenerated(kRenderId, kPageRequestId + 1, 0, 1));
    240   GenerateStreamAndWaitForResult(kPageRequestId + 1, options);
    241 
    242   // Check the latest generated stream.
    243   EXPECT_EQ(host_->audio_devices_.size(), 0u);
    244   EXPECT_EQ(host_->video_devices_.size(), 1u);
    245   std::string label2 = host_->label_;
    246   std::string device_id2 = host_->video_devices_.front().device.id;
    247   EXPECT_EQ(device_id1, device_id2);
    248   EXPECT_NE(label1, label2);
    249 
    250   // Check that we now have two opened streams.
    251   EXPECT_EQ(2u, host_->NumberOfStreams());
    252 
    253   // Generate third stream.
    254   SetupFakeUI(true);
    255   EXPECT_CALL(*host_.get(),
    256               OnStreamGenerated(kRenderId, kPageRequestId + 2, 0, 1));
    257   GenerateStreamAndWaitForResult(kPageRequestId + 2, options);
    258 
    259   // Check the latest generated stream.
    260   EXPECT_EQ(host_->audio_devices_.size(), 0u);
    261   EXPECT_EQ(host_->video_devices_.size(), 1u);
    262   std::string label3 = host_->label_;
    263   std::string device_id3 = host_->video_devices_.front().device.id;
    264   EXPECT_EQ(device_id1, device_id3);
    265   EXPECT_NE(label1, label3);
    266   EXPECT_NE(label2, label3);
    267 
    268   // Check that we now have three opened streams.
    269   EXPECT_EQ(host_->NumberOfStreams(), 3u);
    270 
    271   host_->OnStopGeneratedStream(label1);
    272   host_->OnStopGeneratedStream(label2);
    273   host_->OnStopGeneratedStream(label3);
    274   EXPECT_EQ(host_->NumberOfStreams(), 0u);
    275 }
    276 
    277 TEST_F(MediaStreamDispatcherHostTest, FailOpenVideoDevice) {
    278   StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
    279 
    280   media::FakeVideoCaptureDevice::SetFailNextCreate();
    281   SetupFakeUI(false);
    282   EXPECT_CALL(*host_.get(),
    283               OnStreamGenerationFailed(kRenderId, kPageRequestId));
    284   GenerateStreamAndWaitForResult(kPageRequestId, options);
    285 }
    286 
    287 TEST_F(MediaStreamDispatcherHostTest, CancelPendingStreamsOnChannelClosing) {
    288   StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
    289 
    290   base::RunLoop run_loop;
    291 
    292   // Create multiple GenerateStream requests.
    293   size_t streams = 5;
    294   for (size_t i = 1; i <= streams; ++i) {
    295     host_->OnGenerateStream(
    296         kPageRequestId + i, options, run_loop.QuitClosure());
    297     EXPECT_EQ(host_->NumberOfStreams(), i);
    298   }
    299 
    300   // Calling OnChannelClosing() to cancel all the pending requests.
    301   host_->OnChannelClosing();
    302   run_loop.RunUntilIdle();
    303 
    304   // Streams should have been cleaned up.
    305   EXPECT_EQ(host_->NumberOfStreams(), 0u);
    306 }
    307 
    308 TEST_F(MediaStreamDispatcherHostTest, StopGeneratedStreamsOnChannelClosing) {
    309   StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
    310 
    311   // Create first group of streams.
    312   size_t generated_streams = 3;
    313   for (size_t i = 0; i < generated_streams; ++i) {
    314     SetupFakeUI(true);
    315     EXPECT_CALL(*host_.get(),
    316                 OnStreamGenerated(kRenderId, kPageRequestId + i, 0, 1));
    317     GenerateStreamAndWaitForResult(kPageRequestId + i, options);
    318   }
    319   EXPECT_EQ(host_->NumberOfStreams(), generated_streams);
    320 
    321   // Calling OnChannelClosing() to cancel all the pending/generated streams.
    322   host_->OnChannelClosing();
    323   base::RunLoop().RunUntilIdle();
    324 
    325   // Streams should have been cleaned up.
    326   EXPECT_EQ(host_->NumberOfStreams(), 0u);
    327 }
    328 
    329 TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
    330   StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
    331 
    332   base::Closure close_callback;
    333   scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
    334   EXPECT_CALL(*stream_ui, OnStarted(_))
    335       .WillOnce(SaveArg<0>(&close_callback));
    336   media_stream_manager_->UseFakeUI(stream_ui.PassAs<FakeMediaStreamUIProxy>());
    337 
    338   EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
    339   EXPECT_CALL(*host_.get(), OnStopGeneratedStreamFromBrowser(kRenderId));
    340   GenerateStreamAndWaitForResult(kPageRequestId, options);
    341 
    342   EXPECT_EQ(host_->audio_devices_.size(), 0u);
    343   EXPECT_EQ(host_->video_devices_.size(), 1u);
    344   EXPECT_EQ(host_->NumberOfStreams(), 1u);
    345 
    346   ASSERT_FALSE(close_callback.is_null());
    347   close_callback.Run();
    348   base::RunLoop().RunUntilIdle();
    349 
    350   EXPECT_EQ(host_->NumberOfStreams(), 0u);
    351 }
    352 
    353 };  // namespace content
    354