// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "content/common/media/media_stream_messages.h" #include "content/public/common/media_stream_request.h" #include "content/renderer/media/media_stream_dispatcher.h" #include "content/renderer/media/media_stream_dispatcher_eventhandler.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { namespace { const int kRouteId = 0; const int kAudioSessionId = 3; const int kVideoSessionId = 5; const int kRequestId1 = 10; const int kRequestId2 = 20; const int kRequestId3 = 30; const int kRequestId4 = 40; static const char kLabel[] = "test"; const MediaStreamType kAudioType = MEDIA_DEVICE_AUDIO_CAPTURE; const MediaStreamType kVideoType = MEDIA_DEVICE_VIDEO_CAPTURE; const MediaStreamType kNoAudioType = MEDIA_NO_SERVICE; class MockMediaStreamDispatcherEventHandler : public MediaStreamDispatcherEventHandler, public base::SupportsWeakPtr { public: MockMediaStreamDispatcherEventHandler() : request_id_(-1) {} virtual void OnStreamGenerated( int request_id, const std::string &label, const StreamDeviceInfoArray& audio_device_array, const StreamDeviceInfoArray& video_device_array) OVERRIDE { request_id_ = request_id; label_ = label; } virtual void OnStreamGenerationFailed(int request_id) OVERRIDE { request_id_ = request_id; } virtual void OnDevicesEnumerated( int request_id, const StreamDeviceInfoArray& device_array) OVERRIDE { request_id_ = request_id; } virtual void OnDevicesEnumerationFailed(int request_id) OVERRIDE { request_id_ = request_id; } virtual void OnDeviceOpened( int request_id, const std::string& label, const StreamDeviceInfo& video_device) OVERRIDE { request_id_ = request_id; label_ = label; } virtual void OnDeviceOpenFailed(int request_id) OVERRIDE { request_id_ = request_id; } int request_id_; std::string label_; DISALLOW_COPY_AND_ASSIGN(MockMediaStreamDispatcherEventHandler); }; } // namespace TEST(MediaStreamDispatcherTest, BasicStream) { scoped_ptr message_loop(new base::MessageLoop()); scoped_ptr dispatcher(new MediaStreamDispatcher(NULL)); scoped_ptr handler(new MockMediaStreamDispatcherEventHandler); StreamOptions components(kAudioType, kVideoType); GURL security_origin; int ipc_request_id1 = dispatcher->next_ipc_id_; dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), components, security_origin); int ipc_request_id2 = dispatcher->next_ipc_id_; EXPECT_NE(ipc_request_id1, ipc_request_id2); dispatcher->GenerateStream(kRequestId2, handler.get()->AsWeakPtr(), components, security_origin); EXPECT_EQ(dispatcher->requests_.size(), size_t(2)); StreamDeviceInfoArray audio_device_array(1); StreamDeviceInfo audio_device_info; audio_device_info.device.name = "Microphone"; audio_device_info.device.type = kAudioType; audio_device_info.session_id = kAudioSessionId; audio_device_array[0] = audio_device_info; StreamDeviceInfoArray video_device_array(1); StreamDeviceInfo video_device_info; video_device_info.device.name = "Camera"; video_device_info.device.type = kVideoType; video_device_info.session_id = kVideoSessionId; video_device_array[0] = video_device_info; // Complete the creation of stream1. std::string stream_label1 = std::string("stream1"); dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( kRouteId, ipc_request_id1, stream_label1, audio_device_array, video_device_array)); EXPECT_EQ(handler->request_id_, kRequestId1); EXPECT_EQ(handler->label_, stream_label1); // Complete the creation of stream2. std::string stream_label2 = std::string("stream2"); dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( kRouteId, ipc_request_id2, stream_label2, audio_device_array, video_device_array)); EXPECT_EQ(handler->request_id_, kRequestId2); EXPECT_EQ(handler->label_, stream_label2); EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(2)); // Check the session_id of stream2. EXPECT_EQ(dispatcher->audio_session_id(stream_label2, 0), kAudioSessionId); EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), kVideoSessionId); // Stop stream2. dispatcher->StopStream(stream_label2); EXPECT_EQ(dispatcher->audio_session_id(stream_label2, 0), StreamDeviceInfo::kNoId); EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), StreamDeviceInfo::kNoId); // Stop stream1. dispatcher->StopStream(stream_label1); EXPECT_EQ(dispatcher->audio_session_id(stream_label1, 0), StreamDeviceInfo::kNoId); EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), StreamDeviceInfo::kNoId); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); // Verify that the request has been completed. EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); } TEST(MediaStreamDispatcherTest, BasicStreamForDevice) { static const char kDeviceId[] = "/dev/video0"; scoped_ptr message_loop(new base::MessageLoop()); scoped_ptr dispatcher(new MediaStreamDispatcher(NULL)); scoped_ptr handler(new MockMediaStreamDispatcherEventHandler); StreamOptions components(kNoAudioType, kVideoType); components.audio_device_id = kDeviceId; components.video_device_id = kDeviceId; GURL security_origin; int ipc_request_id1 = dispatcher->next_ipc_id_; dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), components, security_origin); int ipc_request_id2 = dispatcher->next_ipc_id_; EXPECT_NE(ipc_request_id1, ipc_request_id2); dispatcher->GenerateStream(kRequestId2, handler.get()->AsWeakPtr(), components, security_origin); EXPECT_EQ(dispatcher->requests_.size(), size_t(2)); // No audio requested. StreamDeviceInfoArray audio_device_array; StreamDeviceInfoArray video_device_array(1); StreamDeviceInfo video_device_info; video_device_info.device.name = "Fake Video Capture Device"; video_device_info.device.type = kVideoType; video_device_info.session_id = kVideoSessionId; video_device_array[0] = video_device_info; // Complete the creation of stream1. std::string stream_label1 = std::string("stream1"); dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( kRouteId, ipc_request_id1, stream_label1, audio_device_array, video_device_array)); EXPECT_EQ(handler->request_id_, kRequestId1); EXPECT_EQ(handler->label_, stream_label1); // Complete the creation of stream2. std::string stream_label2 = std::string("stream2"); dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( kRouteId, ipc_request_id2, stream_label2, audio_device_array, video_device_array)); EXPECT_EQ(handler->request_id_, kRequestId2); EXPECT_EQ(handler->label_, stream_label2); EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(2)); // Check the session_id of stream2. EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), kVideoSessionId); // Stop stream2. dispatcher->StopStream(stream_label2); EXPECT_EQ(dispatcher->audio_session_id(stream_label2, 0), StreamDeviceInfo::kNoId); EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), StreamDeviceInfo::kNoId); // Stop stream1. dispatcher->StopStream(stream_label1); EXPECT_EQ(dispatcher->audio_session_id(stream_label1, 0), StreamDeviceInfo::kNoId); EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), StreamDeviceInfo::kNoId); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); // Verify that the request has been completed. EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); } TEST(MediaStreamDispatcherTest, BasicVideoDevice) { scoped_ptr message_loop(new base::MessageLoop()); scoped_ptr dispatcher(new MediaStreamDispatcher(NULL)); scoped_ptr handler1(new MockMediaStreamDispatcherEventHandler); scoped_ptr handler2(new MockMediaStreamDispatcherEventHandler); GURL security_origin; int ipc_request_id1 = dispatcher->next_ipc_id_; dispatcher->EnumerateDevices( kRequestId1, handler1.get()->AsWeakPtr(), kVideoType, security_origin); int ipc_request_id2 = dispatcher->next_ipc_id_; EXPECT_NE(ipc_request_id1, ipc_request_id2); dispatcher->EnumerateDevices( kRequestId2, handler2.get()->AsWeakPtr(), kVideoType, security_origin); EXPECT_EQ(dispatcher->video_enumeration_state_.requests.size(), size_t(2)); StreamDeviceInfoArray video_device_array(1); StreamDeviceInfo video_device_info; video_device_info.device.name = "Camera"; video_device_info.device.id = "device_path"; video_device_info.device.type = kVideoType; video_device_info.session_id = kVideoSessionId; video_device_array[0] = video_device_info; // Complete the enumeration request and all requesters should receive reply. dispatcher->OnMessageReceived(MediaStreamMsg_DevicesEnumerated( kRouteId, ipc_request_id1, kLabel, video_device_array)); EXPECT_EQ(handler1->request_id_, kRequestId1); EXPECT_EQ(handler2->request_id_, kRequestId2); EXPECT_EQ(dispatcher->video_enumeration_state_.requests.size(), size_t(2)); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); int ipc_request_id3 = dispatcher->next_ipc_id_; dispatcher->OpenDevice(kRequestId3, handler1.get()->AsWeakPtr(), video_device_info.device.id, kVideoType, security_origin); int ipc_request_id4 = dispatcher->next_ipc_id_; EXPECT_NE(ipc_request_id3, ipc_request_id4); dispatcher->OpenDevice(kRequestId4, handler1.get()->AsWeakPtr(), video_device_info.device.id, kVideoType, security_origin); EXPECT_EQ(dispatcher->requests_.size(), size_t(2)); // Complete the OpenDevice of request 1. std::string stream_label1 = std::string("stream1"); dispatcher->OnMessageReceived(MediaStreamMsg_DeviceOpened( kRouteId, ipc_request_id3, stream_label1, video_device_info)); EXPECT_EQ(handler1->request_id_, kRequestId3); // Complete the OpenDevice of request 2. std::string stream_label2 = std::string("stream2"); dispatcher->OnMessageReceived(MediaStreamMsg_DeviceOpened( kRouteId, ipc_request_id4, stream_label2, video_device_info)); EXPECT_EQ(handler1->request_id_, kRequestId4); EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(2)); // Check the video_session_id. EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), kVideoSessionId); EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), kVideoSessionId); // Stop stream2. dispatcher->StopStream(stream_label2); EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), StreamDeviceInfo::kNoId); // Stop stream1. dispatcher->StopStream(stream_label1); EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), StreamDeviceInfo::kNoId); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); // Verify that the request have been completed. EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); } TEST(MediaStreamDispatcherTest, TestFailure) { scoped_ptr message_loop(new base::MessageLoop()); scoped_ptr dispatcher(new MediaStreamDispatcher(NULL)); scoped_ptr handler(new MockMediaStreamDispatcherEventHandler); StreamOptions components(kAudioType, kVideoType); GURL security_origin; // Test failure when creating a stream. int ipc_request_id1 = dispatcher->next_ipc_id_; dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), components, security_origin); dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerationFailed( kRouteId, ipc_request_id1)); // Verify that the request have been completed. EXPECT_EQ(handler->request_id_, kRequestId1); EXPECT_EQ(dispatcher->requests_.size(), size_t(0)); // Create a new stream. ipc_request_id1 = dispatcher->next_ipc_id_; dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), components, security_origin); StreamDeviceInfoArray audio_device_array(1); StreamDeviceInfo audio_device_info; audio_device_info.device.name = "Microphone"; audio_device_info.device.type = kAudioType; audio_device_info.session_id = kAudioSessionId; audio_device_array[0] = audio_device_info; StreamDeviceInfoArray video_device_array(1); StreamDeviceInfo video_device_info; video_device_info.device.name = "Camera"; video_device_info.device.type = kVideoType; video_device_info.session_id = kVideoSessionId; video_device_array[0] = video_device_info; // Complete the creation of stream1. std::string stream_label1 = std::string("stream1"); dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( kRouteId, ipc_request_id1, stream_label1, audio_device_array, video_device_array)); EXPECT_EQ(handler->request_id_, kRequestId1); EXPECT_EQ(handler->label_, stream_label1); EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0), kVideoSessionId); // Stop stream1. dispatcher->StopStream(stream_label1); EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0)); } TEST(MediaStreamDispatcherTest, CancelGenerateStream) { scoped_ptr message_loop(new base::MessageLoop()); scoped_ptr dispatcher(new MediaStreamDispatcher(NULL)); scoped_ptr handler(new MockMediaStreamDispatcherEventHandler); StreamOptions components(kAudioType, kVideoType); int ipc_request_id1 = dispatcher->next_ipc_id_; dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(), components, GURL()); dispatcher->GenerateStream(kRequestId2, handler.get()->AsWeakPtr(), components, GURL()); EXPECT_EQ(2u, dispatcher->requests_.size()); dispatcher->CancelGenerateStream(kRequestId2); EXPECT_EQ(1u, dispatcher->requests_.size()); // Complete the creation of stream1. StreamDeviceInfo audio_device_info; audio_device_info.device.name = "Microphone"; audio_device_info.device.type = kAudioType; audio_device_info.session_id = kAudioSessionId; StreamDeviceInfoArray audio_device_array(1); audio_device_array[0] = audio_device_info; StreamDeviceInfo video_device_info; video_device_info.device.name = "Camera"; video_device_info.device.type = kVideoType; video_device_info.session_id = kVideoSessionId; StreamDeviceInfoArray video_device_array(1); video_device_array[0] = video_device_info; std::string stream_label1 = "stream1"; dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated( kRouteId, ipc_request_id1, stream_label1, audio_device_array, video_device_array)); EXPECT_EQ(handler->request_id_, kRequestId1); EXPECT_EQ(handler->label_, stream_label1); EXPECT_EQ(0u, dispatcher->requests_.size()); } } // namespace content