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