diff options
Diffstat (limited to 'content/browser/renderer_host/media')
19 files changed, 304 insertions, 375 deletions
diff --git a/content/browser/renderer_host/media/audio_input_device_manager.cc b/content/browser/renderer_host/media/audio_input_device_manager.cc index 00e37f9a..76eca28 100644 --- a/content/browser/renderer_host/media/audio_input_device_manager.cc +++ b/content/browser/renderer_host/media/audio_input_device_manager.cc @@ -31,10 +31,14 @@ AudioInputDeviceManager::AudioInputDeviceManager( AudioInputDeviceManager::~AudioInputDeviceManager() { } -void AudioInputDeviceManager::Register(MediaStreamProviderListener* listener) { +void AudioInputDeviceManager::Register( + MediaStreamProviderListener* listener, + base::MessageLoopProxy* device_thread_loop) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(!listener_); + DCHECK(!device_loop_); listener_ = listener; + device_loop_ = device_thread_loop; } void AudioInputDeviceManager::Unregister() { @@ -47,6 +51,36 @@ void AudioInputDeviceManager::EnumerateDevices() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(listener_); + device_loop_->PostTask( + FROM_HERE, + base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread, this)); +} + +int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + // Generates a new id for this device. + int session_id = next_capture_session_id_++; + device_loop_->PostTask( + FROM_HERE, + base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread, + this, session_id, device)); + + return session_id; +} + +void AudioInputDeviceManager::Close(int session_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(listener_); + device_loop_->PostTask( + FROM_HERE, + base::Bind(&AudioInputDeviceManager::CloseOnDeviceThread, + this, session_id)); +} + +void AudioInputDeviceManager::EnumerateOnDeviceThread() { + DCHECK(IsOnDeviceThread()); + // AudioManager is guaranteed to outlive MediaStreamManager in + // BrowserMainloop. media::AudioDeviceNames device_names; audio_manager_->GetAudioInputDeviceNames(&device_names); @@ -69,19 +103,14 @@ void AudioInputDeviceManager::EnumerateDevices() { devices)); } -int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - // Generates a new id for this device. - int session_id = next_capture_session_id_++; +void AudioInputDeviceManager::OpenOnDeviceThread( + int session_id, const StreamDeviceInfo& device) { + DCHECK(IsOnDeviceThread()); DCHECK(devices_.find(session_id) == devices_.end()); - media::AudioDeviceName audio_input_device_name; - audio_input_device_name.device_name = device.name; - audio_input_device_name.unique_id = device.device_id; - // Adds the session_id and device to the list. - devices_[session_id] = audio_input_device_name; + media::AudioDeviceName target_device(device.name, device.device_id); + devices_[session_id] = target_device; // Returns the |session_id| through the listener by posting a task on // IO thread since MediaStreamManager handles the callback asynchronously. @@ -90,13 +119,10 @@ int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { base::Bind(&AudioInputDeviceManager::OpenedOnIOThread, this, session_id)); - - return session_id; } -void AudioInputDeviceManager::Close(int session_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK(listener_); +void AudioInputDeviceManager::CloseOnDeviceThread(int session_id) { + DCHECK(IsOnDeviceThread()); if (devices_.find(session_id) != devices_.end()) devices_.erase(session_id); @@ -181,4 +207,8 @@ void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { session_id); } +bool AudioInputDeviceManager::IsOnDeviceThread() const { + return device_loop_->BelongsToCurrentThread(); +} + } // namespace media_stream diff --git a/content/browser/renderer_host/media/audio_input_device_manager.h b/content/browser/renderer_host/media/audio_input_device_manager.h index 96bff65..3d79dc9 100644 --- a/content/browser/renderer_host/media/audio_input_device_manager.h +++ b/content/browser/renderer_host/media/audio_input_device_manager.h @@ -6,8 +6,8 @@ // communicates with MediaStreamManager and AudioInputRendererHost on the // browser IO thread, handles queries like enumerate/open/close from // MediaStreamManager and start/stop from AudioInputRendererHost. - -// All the queries and work are handled on the IO thread. +// The work for enumerate/open/close is handled asynchronously on Media Stream +// device thread, while start/stop are synchronous on the IO thread. #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_INPUT_DEVICE_MANAGER_H_ #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_INPUT_DEVICE_MANAGER_H_ @@ -44,7 +44,8 @@ class CONTENT_EXPORT AudioInputDeviceManager explicit AudioInputDeviceManager(media::AudioManager* audio_manager); // MediaStreamProvider implementation, called on IO thread. - virtual void Register(MediaStreamProviderListener* listener) OVERRIDE; + virtual void Register(MediaStreamProviderListener* listener, + base::MessageLoopProxy* device_thread_loop) OVERRIDE; virtual void Unregister() OVERRIDE; virtual void EnumerateDevices() OVERRIDE; virtual int Open(const StreamDeviceInfo& device) OVERRIDE; @@ -61,21 +62,33 @@ class CONTENT_EXPORT AudioInputDeviceManager friend class base::RefCountedThreadSafe<AudioInputDeviceManager>; virtual ~AudioInputDeviceManager(); + // Executed on media stream device thread. + void EnumerateOnDeviceThread(); + void OpenOnDeviceThread(int session_id, const StreamDeviceInfo& device); + void CloseOnDeviceThread(int session_id); + // Executed on IO thread to call Listener. void DevicesEnumeratedOnIOThread(StreamDeviceInfoArray* devices); void OpenedOnIOThread(int session_id); void ClosedOnIOThread(int session_id); void ErrorOnIOThread(int session_id, MediaStreamProviderError error); + bool IsOnDeviceThread() const; + + // Only accessed on Browser::IO thread. MediaStreamProviderListener* listener_; int next_capture_session_id_; typedef std::map<int, AudioInputDeviceManagerEventHandler*> EventHandlerMap; EventHandlerMap event_handlers_; + + // Only accessed from media stream device thread. typedef std::map<int, media::AudioDeviceName> AudioInputDeviceMap; AudioInputDeviceMap devices_; - // TODO(tommi): Is it necessary to store this as a member? media::AudioManager* audio_manager_; + // The message loop of media stream device thread that this object runs on. + scoped_refptr<base::MessageLoopProxy> device_loop_; + DISALLOW_COPY_AND_ASSIGN(AudioInputDeviceManager); }; diff --git a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc index fe57150..257cec7 100644 --- a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc +++ b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc @@ -87,12 +87,7 @@ ACTION_P(ExitMessageLoop, message_loop) { class AudioInputDeviceManagerTest : public testing::Test { public: - AudioInputDeviceManagerTest() - : message_loop_(), - io_thread_(), - manager_(), - audio_input_listener_() { - } + AudioInputDeviceManagerTest() {} // Returns true iff machine has an audio input device. bool CanRunAudioInputDeviceTests() { @@ -100,27 +95,28 @@ class AudioInputDeviceManagerTest : public testing::Test { } protected: - virtual void SetUp() { + virtual void SetUp() OVERRIDE { // The test must run on Browser::IO. message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, message_loop_.get())); - audio_manager_.reset(media::AudioManager::Create()); + audio_manager_.reset(media::AudioManager::Create()); manager_ = new AudioInputDeviceManager(audio_manager_.get()); audio_input_listener_.reset(new MockAudioInputDeviceManagerListener()); - manager_->Register(audio_input_listener_.get()); + manager_->Register(audio_input_listener_.get(), + message_loop_->message_loop_proxy()); // Gets the enumerated device list from the AudioInputDeviceManager. manager_->EnumerateDevices(); EXPECT_CALL(*audio_input_listener_, DevicesEnumerated(_)) .Times(1); - // Waits for the callback. + // Wait until we get the list. message_loop_->RunAllPending(); } - virtual void TearDown() { + virtual void TearDown() OVERRIDE { manager_->Unregister(); io_thread_.reset(); } diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc index 8362330..4af7b61 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc @@ -24,10 +24,10 @@ AudioInputRendererHost::AudioEntry::AudioEntry() AudioInputRendererHost::AudioEntry::~AudioEntry() {} AudioInputRendererHost::AudioInputRendererHost( - content::ResourceContext* resource_context, - media::AudioManager* audio_manager) - : resource_context_(resource_context), - audio_manager_(audio_manager) { + media::AudioManager* audio_manager, + media_stream::MediaStreamManager* media_stream_manager) + : audio_manager_(audio_manager), + media_stream_manager_(media_stream_manager) { } AudioInputRendererHost::~AudioInputRendererHost() { @@ -182,17 +182,12 @@ void AudioInputRendererHost::OnStartDevice(int stream_id, int session_id) { VLOG(1) << "AudioInputRendererHost::OnStartDevice(stream_id=" << stream_id << ", session_id = " << session_id << ")"; - // Get access to the AudioInputDeviceManager to start the device. - media_stream::AudioInputDeviceManager* audio_input_man = - media_stream::MediaStreamManager::GetForResourceContext( - resource_context_, audio_manager_)->audio_input_device_manager(); - // Add the session entry to the map. session_entries_[session_id] = stream_id; // Start the device with the session_id. If the device is started // successfully, OnDeviceStarted() callback will be triggered. - audio_input_man->Start(session_id, this); + media_stream_manager_->audio_input_device_manager()->Start(session_id, this); } void AudioInputRendererHost::OnCreateStream( @@ -349,10 +344,7 @@ void AudioInputRendererHost::OnDeviceStopped(int session_id) { void AudioInputRendererHost::StopAndDeleteDevice(int session_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - media_stream::AudioInputDeviceManager* audio_input_man = - media_stream::MediaStreamManager::GetForResourceContext( - resource_context_, audio_manager_)->audio_input_device_manager(); - audio_input_man->Stop(session_id); + media_stream_manager_->audio_input_device_manager()->Stop(session_id); // Delete the session entry. session_entries_.erase(session_id); diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.h b/content/browser/renderer_host/media/audio_input_renderer_host.h index e8bec46..0cfba06 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.h +++ b/content/browser/renderer_host/media/audio_input_renderer_host.h @@ -64,15 +64,15 @@ #include "media/audio/audio_io.h" #include "media/audio/simple_sources.h" -namespace content { -class ResourceContext; -} - namespace media { class AudioManager; class AudioParameters; } +namespace media_stream { +class MediaStreamManager; +} + class CONTENT_EXPORT AudioInputRendererHost : public content::BrowserMessageFilter, public media::AudioInputController::EventHandler, @@ -100,8 +100,9 @@ class CONTENT_EXPORT AudioInputRendererHost }; // Called from UI thread from the owner of this object. - AudioInputRendererHost(content::ResourceContext* resource_context, - media::AudioManager* audio_manager); + AudioInputRendererHost( + media::AudioManager* audio_manager, + media_stream::MediaStreamManager* media_stream_manager); // content::BrowserMessageFilter implementation. virtual void OnChannelClosing() OVERRIDE; @@ -197,10 +198,12 @@ class CONTENT_EXPORT AudioInputRendererHost // Returns 0 if not found. int LookupSessionById(int stream_id); - // Used to get an instance of AudioInputDeviceManager. - content::ResourceContext* resource_context_; + // Used to create an AudioInputController. media::AudioManager* audio_manager_; + // Used to access to AudioInputDeviceManager. + media_stream::MediaStreamManager* media_stream_manager_; + // A map of stream IDs to audio sources. typedef std::map<int, AudioEntry*> AudioEntryMap; AudioEntryMap audio_entries_; diff --git a/content/browser/renderer_host/media/media_stream_device_settings.cc b/content/browser/renderer_host/media/media_stream_device_settings.cc index f16818b..c3a3350 100644 --- a/content/browser/renderer_host/media/media_stream_device_settings.cc +++ b/content/browser/renderer_host/media/media_stream_device_settings.cc @@ -137,7 +137,6 @@ MediaStreamDeviceSettings::MediaStreamDeviceSettings( : requester_(requester), use_fake_ui_(false) { DCHECK(requester_); - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); } MediaStreamDeviceSettings::~MediaStreamDeviceSettings() { diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc index 7ae8e2d..27a628f 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc @@ -4,10 +4,12 @@ #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h" +#include "content/browser/browser_main_loop.h" #include "content/common/media/media_stream_messages.h" #include "content/common/media/media_stream_options.h" #include "googleurl/src/gurl.h" +using content::BrowserMainLoop; using content::BrowserMessageFilter; using content::BrowserThread; @@ -24,13 +26,8 @@ struct MediaStreamDispatcherHost::StreamRequest { int page_request_id; }; -MediaStreamDispatcherHost::MediaStreamDispatcherHost( - content::ResourceContext* resource_context, - int render_process_id, - media::AudioManager* audio_manager) - : resource_context_(resource_context), - render_process_id_(render_process_id), - audio_manager_(audio_manager) { +MediaStreamDispatcherHost::MediaStreamDispatcherHost(int render_process_id) + : render_process_id_(render_process_id) { } void MediaStreamDispatcherHost::StreamGenerated( @@ -178,12 +175,12 @@ void MediaStreamDispatcherHost::OnChannelClosing() { // Since the IPC channel is gone, cancel pending requests and close all // requested VideoCaptureDevices. - manager()->CancelRequests(this); + GetManager()->CancelRequests(this); for (StreamMap::iterator it = streams_.begin(); it != streams_.end(); it++) { std::string label = it->first; - manager()->StopGeneratedStream(label); + GetManager()->StopGeneratedStream(label); } } @@ -203,7 +200,7 @@ void MediaStreamDispatcherHost::OnGenerateStream( << security_origin.spec() << ")"; std::string label; - manager()->GenerateStream(this, render_process_id_, render_view_id, + GetManager()->GenerateStream(this, render_process_id_, render_view_id, components, security_origin, &label); DCHECK(!label.empty()); streams_[label] = StreamRequest(render_view_id, page_request_id); @@ -218,7 +215,7 @@ void MediaStreamDispatcherHost::OnCancelGenerateStream(int render_view_id, for (StreamMap::iterator it = streams_.begin(); it != streams_.end(); ++it) { if (it->second.render_view_id == render_view_id && it->second.page_request_id == page_request_id) { - manager()->CancelGenerateStream(it->first); + GetManager()->CancelGenerateStream(it->first); } } } @@ -230,7 +227,7 @@ void MediaStreamDispatcherHost::OnStopGeneratedStream( StreamMap::iterator it = streams_.find(label); DCHECK(it != streams_.end()); - manager()->StopGeneratedStream(label); + GetManager()->StopGeneratedStream(label); streams_.erase(it); } @@ -246,7 +243,7 @@ void MediaStreamDispatcherHost::OnEnumerateDevices( << security_origin.spec() << ")"; std::string label; - manager()->EnumerateDevices(this, render_process_id_, render_view_id, + GetManager()->EnumerateDevices(this, render_process_id_, render_view_id, type, security_origin, &label); DCHECK(!label.empty()); streams_[label] = StreamRequest(render_view_id, page_request_id); @@ -266,15 +263,14 @@ void MediaStreamDispatcherHost::OnOpenDevice( << security_origin.spec() << ")"; std::string label; - manager()->OpenDevice(this, render_process_id_, render_view_id, + GetManager()->OpenDevice(this, render_process_id_, render_view_id, device_id, type, security_origin, &label); DCHECK(!label.empty()); streams_[label] = StreamRequest(render_view_id, page_request_id); } -MediaStreamManager* MediaStreamDispatcherHost::manager() { - return MediaStreamManager::GetForResourceContext( - resource_context_, audio_manager_); +MediaStreamManager* MediaStreamDispatcherHost::GetManager() { + return BrowserMainLoop::GetMediaStreamManager(); } } // namespace media_stream diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.h b/content/browser/renderer_host/media/media_stream_dispatcher_host.h index 4218d7c..8ed45a0 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host.h +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.h @@ -15,10 +15,6 @@ #include "content/common/media/media_stream_options.h" #include "content/public/browser/browser_message_filter.h" -namespace content { -class ResourceContext; -} // namespace content - namespace media_stream { // MediaStreamDispatcherHost is a delegate for Media Stream API messages used by @@ -28,9 +24,7 @@ class CONTENT_EXPORT MediaStreamDispatcherHost : public content::BrowserMessageFilter, public MediaStreamRequester { public: - MediaStreamDispatcherHost(content::ResourceContext* resource_context, - int render_process_id, - media::AudioManager* audio_manager); + explicit MediaStreamDispatcherHost(int render_process_id); // MediaStreamRequester implementation. virtual void StreamGenerated( @@ -78,12 +72,11 @@ class CONTENT_EXPORT MediaStreamDispatcherHost const GURL& security_origin); // Returns the media stream manager to forward events to, - // creating one if needed. - MediaStreamManager* manager(); + // creating one if needed. It is a virtual function so that the unit tests + // can inject their own MediaStreamManager. + virtual MediaStreamManager* GetManager(); - content::ResourceContext* resource_context_; int render_process_id_; - media::AudioManager* audio_manager_; struct StreamRequest; typedef std::map<std::string, StreamRequest> StreamMap; diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc index 0539bb8..8c6d1b0 100644 --- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/message_loop.h" #include "content/browser/browser_thread_impl.h" +#include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h" #include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/browser/renderer_host/media/mock_media_observer.h" @@ -39,11 +40,11 @@ namespace media_stream { class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost, public content::TestContentBrowserClient { public: - MockMediaStreamDispatcherHost(content::ResourceContext* resource_context, - MessageLoop* message_loop, - media::AudioManager* audio_manager) - : MediaStreamDispatcherHost(resource_context, kProcessId, audio_manager), - message_loop_(message_loop) {} + MockMediaStreamDispatcherHost(MessageLoop* message_loop, + MediaStreamManager* manager) + : MediaStreamDispatcherHost(kProcessId), + message_loop_(message_loop), + manager_(manager) {} // A list of mock methods. MOCK_METHOD4(OnStreamGenerated, @@ -80,7 +81,7 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost, // This method is used to dispatch IPC messages to the renderer. We intercept // these messages here and dispatch to our mock methods to verify the // conversation between this object and the renderer. - virtual bool Send(IPC::Message* message) { + virtual bool Send(IPC::Message* message) OVERRIDE { CHECK(message); // In this method we dispatch the messages to the according handlers as if @@ -102,6 +103,11 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost, return true; } + // Use our own MediaStreamManager. + virtual MediaStreamManager* GetManager() OVERRIDE { + return manager_; + } + // These handler methods do minimal things and delegate to the mock methods. void OnStreamGenerated( const IPC::Message& msg, @@ -141,38 +147,43 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost, } MessageLoop* message_loop_; + MediaStreamManager* manager_; }; class MediaStreamDispatcherHostTest : public testing::Test { public: MediaStreamDispatcherHostTest() : old_client_(NULL), old_browser_client_(NULL) {} + virtual ~MediaStreamDispatcherHostTest() {} void WaitForResult() { message_loop_->Run(); } protected: - virtual void SetUp() { - message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); - // ResourceContext must be created on UI thread. - ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI, - message_loop_.get())); + virtual void SetUp() OVERRIDE { // MediaStreamManager must be created and called on IO thread. + message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, message_loop_.get())); - audio_manager_.reset(media::AudioManager::Create()); - // Create our own media observer. media_observer_.reset(new MockMediaObserver()); + // Create our own MediaStreamManager. + audio_manager_.reset(media::AudioManager::Create()); + scoped_refptr<media_stream::AudioInputDeviceManager> + audio_input_device_manager( + new media_stream::AudioInputDeviceManager(audio_manager_.get())); + scoped_refptr<media_stream::VideoCaptureManager> video_capture_manager( + new media_stream::VideoCaptureManager()); + media_stream_manager_.reset(new media_stream::MediaStreamManager( + audio_input_device_manager, video_capture_manager)); // Make sure we use fake devices to avoid long delays. - MediaStreamManager::GetForResourceContext( - &resource_context_, audio_manager_.get())->UseFakeDevice(); + media_stream_manager_->UseFakeDevice(); - host_ = new MockMediaStreamDispatcherHost( - &resource_context_, message_loop_.get(), audio_manager_.get()); + host_ = new MockMediaStreamDispatcherHost(message_loop_.get(), + media_stream_manager_.get()); // Use the fake content client and browser. old_client_ = content::GetContentClient(); @@ -182,9 +193,8 @@ class MediaStreamDispatcherHostTest : public testing::Test { content_client_->set_browser_for_testing(host_); } - virtual void TearDown() { - // Needed to make sure the manager finishes all tasks on its own thread. - SyncWithVideoCaptureManagerThread(); + virtual void TearDown() OVERRIDE { + message_loop_->RunAllPending(); // Recover the old browser client and content client. content::GetContentClient()->set_browser_for_testing(old_browser_client_); @@ -192,41 +202,11 @@ class MediaStreamDispatcherHostTest : public testing::Test { content_client_.reset(); } - // Called on the VideoCaptureManager thread. - static void PostQuitMessageLoop(MessageLoop* message_loop) { - message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); - } - - // Called on the main thread. - static void PostQuitOnVideoCaptureManagerThread( - MessageLoop* message_loop, - media_stream::MediaStreamManager* media_stream_manager) { - media_stream_manager->video_capture_manager()->GetMessageLoop()-> - PostTask(FROM_HERE, - base::Bind(&PostQuitMessageLoop, message_loop)); - } - - // SyncWithVideoCaptureManagerThread() waits until all pending tasks on the - // video_capture_manager thread are executed while also processing pending - // task in message_loop_ on the current thread. It is used to synchronize - // with the video capture manager thread when we are stopping a video - // capture device. - void SyncWithVideoCaptureManagerThread() { - message_loop_->PostTask( - FROM_HERE, - base::Bind(&PostQuitOnVideoCaptureManagerThread, - message_loop_.get(), - MediaStreamManager::GetForResourceContext( - &resource_context_, audio_manager_.get()))); - message_loop_->Run(); - } - scoped_refptr<MockMediaStreamDispatcherHost> host_; scoped_ptr<MessageLoop> message_loop_; - scoped_ptr<BrowserThreadImpl> ui_thread_; scoped_ptr<BrowserThreadImpl> io_thread_; scoped_ptr<media::AudioManager> audio_manager_; - content::MockResourceContext resource_context_; + scoped_ptr<MediaStreamManager> media_stream_manager_; content::ContentClient* old_client_; content::ContentBrowserClient* old_browser_client_; scoped_ptr<content::ContentClient> content_client_; @@ -346,9 +326,7 @@ TEST_F(MediaStreamDispatcherHostTest, FailDevice) { EXPECT_CALL(*host_, OnVideoDeviceFailed(kRenderId, 0)); int session_id = host_->video_devices_[0].session_id; - MediaStreamManager::GetForResourceContext( - &resource_context_, audio_manager_.get())-> - video_capture_manager()->Error(session_id); + media_stream_manager_->video_capture_manager()->Error(session_id); WaitForResult(); EXPECT_EQ(host_->video_devices_.size(), 0u); EXPECT_EQ(host_->NumberOfStreams(), 1u); diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index d6b2e60..3f5a804 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc @@ -14,18 +14,14 @@ #include "content/browser/renderer_host/media/media_stream_device_settings.h" #include "content/browser/renderer_host/media/media_stream_requester.h" #include "content/browser/renderer_host/media/video_capture_manager.h" -#include "content/browser/resource_context_impl.h" #include "content/common/media/media_stream_options.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/media_observer.h" #include "googleurl/src/gurl.h" -#include "media/audio/audio_manager.h" using content::BrowserThread; -static const char* kMediaStreamManagerKeyName = "content_media_stream_manager"; - namespace media_stream { // Creates a random label used to identify requests. @@ -116,50 +112,36 @@ struct MediaStreamManager::DeviceRequest { StreamDeviceInfoArray video_devices; }; -// static -MediaStreamManager* MediaStreamManager::GetForResourceContext( - content::ResourceContext* resource_context, - media::AudioManager* audio_manager) { - MediaStreamManager* rv = static_cast<MediaStreamManager*>( - resource_context->GetUserData(kMediaStreamManagerKeyName)); - if (!rv) { - rv = new MediaStreamManager(audio_manager); - resource_context->SetUserData(kMediaStreamManagerKeyName, rv); - } - return rv; -} - -MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager) +MediaStreamManager::MediaStreamManager( + AudioInputDeviceManager* audio_input_device_manager, + VideoCaptureManager* video_capture_manager) : ALLOW_THIS_IN_INITIALIZER_LIST( device_settings_(new MediaStreamDeviceSettings(this))), - enumeration_in_progress_(content::NUM_MEDIA_STREAM_DEVICE_TYPES, false), - audio_manager_(audio_manager) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + audio_input_device_manager_(audio_input_device_manager), + video_capture_manager_(video_capture_manager), + enumeration_in_progress_(content::NUM_MEDIA_STREAM_DEVICE_TYPES, false) { } MediaStreamManager::~MediaStreamManager() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (video_capture_manager_.get()) + if (device_thread_.get()) { video_capture_manager_->Unregister(); - if (audio_input_device_manager_.get()) audio_input_device_manager_->Unregister(); + device_thread_->Stop(); + } } VideoCaptureManager* MediaStreamManager::video_capture_manager() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (!video_capture_manager_.get()) { - video_capture_manager_ = new VideoCaptureManager(); - video_capture_manager_->Register(this); - } + DCHECK(video_capture_manager_.get()); + EnsureDeviceThreadAndListener(); return video_capture_manager_.get(); } AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (!audio_input_device_manager_.get()) { - audio_input_device_manager_ = new AudioInputDeviceManager(audio_manager_); - audio_input_device_manager_->Register(this); - } + DCHECK(audio_input_device_manager_.get()); + EnsureDeviceThreadAndListener(); return audio_input_device_manager_.get(); } @@ -367,6 +349,19 @@ void MediaStreamManager::StartEnumeration( (*label) = request_label; } +void MediaStreamManager::EnsureDeviceThreadAndListener() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (device_thread_.get()) + return; + + device_thread_.reset(new DeviceThread("MediaStreamDeviceThread")); + CHECK(device_thread_->Start()); + + audio_input_device_manager_->Register(this, + device_thread_->message_loop_proxy()); + video_capture_manager_->Register(this, device_thread_->message_loop_proxy()); +} + void MediaStreamManager::Opened(MediaStreamType stream_type, int capture_session_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h index 17f863e..3082ac0 100644 --- a/content/browser/renderer_host/media/media_stream_manager.h +++ b/content/browser/renderer_host/media/media_stream_manager.h @@ -29,19 +29,15 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/memory/ref_counted.h" -#include "base/supports_user_data.h" +#include "base/threading/thread.h" +#include "base/win/scoped_com_initializer.h" #include "content/browser/renderer_host/media/media_stream_provider.h" #include "content/browser/renderer_host/media/media_stream_settings_requester.h" #include "content/common/media/media_stream_options.h" #include "content/common/content_export.h" +#include "content/public/browser/browser_thread.h" -namespace content { -class ResourceContext; -} - -namespace media { -class AudioManager; -} +using base::win::ScopedCOMInitializer; namespace media_stream { @@ -50,22 +46,31 @@ class MediaStreamDeviceSettings; class MediaStreamRequester; class VideoCaptureManager; +// Thread that enters MTA on windows, and is base::Thread on linux and mac. +class DeviceThread : public base::Thread { + public: + explicit DeviceThread(const char* name) + : base::Thread(name), + com_init_(ScopedCOMInitializer::kMTA) {} + + private: + ScopedCOMInitializer com_init_; + DISALLOW_COPY_AND_ASSIGN(DeviceThread); +}; + // MediaStreamManager is used to generate and close new media devices, not to // start the media flow. // The classes requesting new media streams are answered using // MediaStreamManager::Listener. class CONTENT_EXPORT MediaStreamManager : public MediaStreamProviderListener, - public SettingsRequester, - public base::SupportsUserData::Data { + public SettingsRequester { public: - // Returns the MediaStreamManager for the given ResourceContext. If it hasn't - // been created yet, it will be constructed with the given AudioManager. - static MediaStreamManager* GetForResourceContext( - content::ResourceContext* resource_context, - media::AudioManager* audio_manager); + // This class takes the ownerships of the |audio_input_device_manager| + // and |video_capture_manager|. + MediaStreamManager(AudioInputDeviceManager* audio_input_device_manager, + VideoCaptureManager* video_capture_manager); - explicit MediaStreamManager(media::AudioManager* audio_manager); virtual ~MediaStreamManager(); // Used to access VideoCaptureManager. @@ -130,6 +135,8 @@ class CONTENT_EXPORT MediaStreamManager // Used by unit test to make sure fake devices are used instead of a real // devices, which is needed for server based testing. + // TODO(xians): Remove this hack since we can create our own + // MediaStreamManager in our unit tests. void UseFakeDevice(); private: @@ -149,9 +156,16 @@ class CONTENT_EXPORT MediaStreamManager void StartEnumeration(DeviceRequest* new_request, std::string* label); + // Helper to ensure the device thread and pass the message loop to device + // managers, it also register itself as the listener to the device managers. + void EnsureDeviceThreadAndListener(); + + // Device thread shared by VideoCaptureManager and AudioInputDeviceManager. + scoped_ptr<base::Thread> device_thread_; + scoped_ptr<MediaStreamDeviceSettings> device_settings_; - scoped_refptr<VideoCaptureManager> video_capture_manager_; scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_; + scoped_refptr<VideoCaptureManager> video_capture_manager_; // Keeps track of device types currently being enumerated to not enumerate // when not necessary. @@ -160,7 +174,6 @@ class CONTENT_EXPORT MediaStreamManager // All non-closed request. typedef std::map<std::string, DeviceRequest> DeviceRequests; DeviceRequests requests_; - media::AudioManager* audio_manager_; DISALLOW_COPY_AND_ASSIGN(MediaStreamManager); }; diff --git a/content/browser/renderer_host/media/media_stream_provider.h b/content/browser/renderer_host/media/media_stream_provider.h index cab027a..6218b2e 100644 --- a/content/browser/renderer_host/media/media_stream_provider.h +++ b/content/browser/renderer_host/media/media_stream_provider.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -18,6 +18,10 @@ #include "content/common/content_export.h" #include "content/common/media/media_stream_options.h" +namespace base { +class MessageLoopProxy; +} + namespace media_stream { enum MediaStreamProviderError { @@ -59,8 +63,9 @@ class CONTENT_EXPORT MediaStreamProviderListener { // Implemented by a manager class providing captured media. class CONTENT_EXPORT MediaStreamProvider { public: - // Registers a listener, only one listener is allowed. - virtual void Register(MediaStreamProviderListener* listener) = 0; + // Registers a listener and a device message loop. + virtual void Register(MediaStreamProviderListener* listener, + base::MessageLoopProxy* device_thread_loop) = 0; // Unregisters the previously registered listener. virtual void Unregister() = 0; diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc index 47c0c29..449d4c4 100644 --- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc @@ -151,7 +151,7 @@ class VideoCaptureControllerTest : public testing::Test { virtual ~VideoCaptureControllerTest() {} protected: - virtual void SetUp() { + virtual void SetUp() OVERRIDE { message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE, message_loop_.get())); @@ -166,8 +166,7 @@ class VideoCaptureControllerTest : public testing::Test { message_loop_.get())); } - virtual void TearDown() { - } + virtual void TearDown() OVERRIDE {} scoped_ptr<MessageLoop> message_loop_; scoped_ptr<BrowserThreadImpl> file_thread_; diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc index 97da80d..4bf69f1 100644 --- a/content/browser/renderer_host/media/video_capture_host.cc +++ b/content/browser/renderer_host/media/video_capture_host.cc @@ -7,10 +7,12 @@ #include "base/bind.h" #include "base/memory/scoped_ptr.h" #include "base/stl_util.h" +#include "content/browser/browser_main_loop.h" #include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/browser/renderer_host/media/video_capture_manager.h" #include "content/common/media/video_capture_messages.h" +using content::BrowserMainLoop; using content::BrowserMessageFilter; using content::BrowserThread; @@ -23,11 +25,7 @@ struct VideoCaptureHost::Entry { scoped_refptr<VideoCaptureController> controller; }; -VideoCaptureHost::VideoCaptureHost(content::ResourceContext* resource_context, - media::AudioManager* audio_manager) - : resource_context_(resource_context), - audio_manager_(audio_manager) { -} +VideoCaptureHost::VideoCaptureHost() {} VideoCaptureHost::~VideoCaptureHost() {} @@ -281,6 +279,5 @@ void VideoCaptureHost::DeleteVideoCaptureControllerOnIOThread( media_stream::VideoCaptureManager* VideoCaptureHost::GetVideoCaptureManager() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - return media_stream::MediaStreamManager::GetForResourceContext( - resource_context_, audio_manager_)->video_capture_manager(); + return BrowserMainLoop::GetMediaStreamManager()->video_capture_manager(); } diff --git a/content/browser/renderer_host/media/video_capture_host.h b/content/browser/renderer_host/media/video_capture_host.h index a66f475..dbb8cbe 100644 --- a/content/browser/renderer_host/media/video_capture_host.h +++ b/content/browser/renderer_host/media/video_capture_host.h @@ -45,20 +45,11 @@ #include "content/public/browser/browser_message_filter.h" #include "ipc/ipc_message.h" -namespace content { -class ResourceContext; -} // namespace content - -namespace media { -class AudioManager; -} - class CONTENT_EXPORT VideoCaptureHost : public content::BrowserMessageFilter, public VideoCaptureControllerEventHandler { public: - explicit VideoCaptureHost(content::ResourceContext* resource_context, - media::AudioManager* audio_manager); + VideoCaptureHost(); // content::BrowserMessageFilter implementation. virtual void OnChannelClosing() OVERRIDE; @@ -140,18 +131,15 @@ class CONTENT_EXPORT VideoCaptureHost void DeleteVideoCaptureControllerOnIOThread( const VideoCaptureControllerID& controller_id); - // Helpers. - media_stream::VideoCaptureManager* GetVideoCaptureManager(); + // Returns the video capture manager. This is a virtual function so that + // the unit tests can inject their own MediaStreamManager. + virtual media_stream::VideoCaptureManager* GetVideoCaptureManager(); struct Entry; typedef std::map<VideoCaptureControllerID, Entry*> EntryMap; // A map of VideoCaptureControllerID to its state and VideoCaptureController. EntryMap entries_; - // Used to get a pointer to VideoCaptureManager to start/stop capture devices. - content::ResourceContext* resource_context_; - media::AudioManager* audio_manager_; - DISALLOW_COPY_AND_ASSIGN(VideoCaptureHost); }; diff --git a/content/browser/renderer_host/media/video_capture_host_unittest.cc b/content/browser/renderer_host/media/video_capture_host_unittest.cc index f7f31e6..4aca90b 100644 --- a/content/browser/renderer_host/media/video_capture_host_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_host_unittest.cc @@ -13,6 +13,7 @@ #include "base/stl_util.h" #include "base/stringprintf.h" #include "content/browser/browser_thread_impl.h" +#include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/browser/renderer_host/media/video_capture_host.h" #include "content/browser/renderer_host/media/video_capture_manager.h" @@ -71,11 +72,11 @@ class DumpVideo { class MockVideoCaptureHost : public VideoCaptureHost { public: - MockVideoCaptureHost(content::ResourceContext* resource_context, - media::AudioManager* audio_manager) - : VideoCaptureHost(resource_context, audio_manager), + MockVideoCaptureHost(media_stream::MediaStreamManager* manager) + : VideoCaptureHost(), return_buffers_(false), - dump_video_(false) {} + dump_video_(false), + manager_(manager) {} // A list of mock methods. MOCK_METHOD4(OnNewBufferCreated, @@ -125,7 +126,7 @@ class MockVideoCaptureHost : public VideoCaptureHost { // This method is used to dispatch IPC messages to the renderer. We intercept // these messages here and dispatch to our mock methods to verify the // conversation between this object and the renderer. - virtual bool Send(IPC::Message* message) { + virtual bool Send(IPC::Message* message) OVERRIDE { CHECK(message); // In this method we dispatch the messages to the according handlers as if @@ -144,6 +145,10 @@ class MockVideoCaptureHost : public VideoCaptureHost { return true; } + virtual media_stream::VideoCaptureManager* GetVideoCaptureManager() OVERRIDE { + return manager_->video_capture_manager(); + } + // These handler methods do minimal things and delegate to the mock methods. void OnNewBufferCreatedDispatch(int device_id, base::SharedMemoryHandle handle, @@ -185,6 +190,7 @@ class MockVideoCaptureHost : public VideoCaptureHost { bool return_buffers_; bool dump_video_; DumpVideo dumper_; + media_stream::MediaStreamManager* manager_; }; ACTION_P(ExitMessageLoop, message_loop) { @@ -196,32 +202,35 @@ class VideoCaptureHostTest : public testing::Test { VideoCaptureHostTest() {} protected: - virtual void SetUp() { + virtual void SetUp() OVERRIDE { // Create a message loop so VideoCaptureHostTest can use it. message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); - // ResourceContext must be created on the UI thread. - ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI, - message_loop_.get())); - // MediaStreamManager must be created on the IO thread. io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, message_loop_.get())); + // Create our own MediaStreamManager. audio_manager_.reset(media::AudioManager::Create()); + scoped_refptr<media_stream::AudioInputDeviceManager> + audio_input_device_manager( + new media_stream::AudioInputDeviceManager(audio_manager_.get())); + scoped_refptr<media_stream::VideoCaptureManager> video_capture_manager( + new media_stream::VideoCaptureManager()); + media_stream_manager_.reset(new media_stream::MediaStreamManager( + audio_input_device_manager, video_capture_manager)); #ifndef TEST_REAL_CAPTURE_DEVICE - media_stream::MediaStreamManager::GetForResourceContext( - &resource_context_, audio_manager_.get())->UseFakeDevice(); + media_stream_manager_->UseFakeDevice(); #endif - host_ = new MockVideoCaptureHost(&resource_context_, audio_manager_.get()); + host_ = new MockVideoCaptureHost(media_stream_manager_.get()); // Simulate IPC channel connected. host_->OnChannelConnected(base::GetCurrentProcId()); } - virtual void TearDown() { + virtual void TearDown() OVERRIDE { // Verifies and removes the expectations on host_ and // returns true iff successful. Mock::VerifyAndClearExpectations(host_); @@ -238,36 +247,7 @@ class VideoCaptureHostTest : public testing::Test { host_ = NULL; // We need to continue running message_loop_ to complete all destructions. - SyncWithVideoCaptureManagerThread(); - } - - // Called on the VideoCaptureManager thread. - static void PostQuitMessageLoop(MessageLoop* message_loop) { - message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); - } - - // Called on the main thread. - static void PostQuitOnVideoCaptureManagerThread( - MessageLoop* message_loop, content::ResourceContext* resource_context, - media:: AudioManager* audio_manager) { - media_stream::MediaStreamManager* manager = - media_stream::MediaStreamManager::GetForResourceContext( - resource_context, audio_manager); - manager->video_capture_manager()->GetMessageLoop()->PostTask( - FROM_HERE, base::Bind(&PostQuitMessageLoop, message_loop)); - } - - // SyncWithVideoCaptureManagerThread() waits until all pending tasks on the - // video_capture_manager thread are executed while also processing pending - // task in message_loop_ on the current thread. It is used to synchronize - // with the video capture manager thread when we are stopping a video - // capture device. - void SyncWithVideoCaptureManagerThread() { - message_loop_->PostTask( - FROM_HERE, - base::Bind(&PostQuitOnVideoCaptureManagerThread, message_loop_.get(), - &resource_context_, audio_manager_.get())); - message_loop_->Run(); + message_loop_->RunAllPending(); } void StartCapture() { @@ -325,13 +305,14 @@ class VideoCaptureHostTest : public testing::Test { void StopCapture() { EXPECT_CALL(*host_, OnStateChanged(kDeviceId, video_capture::kStopped)) - .Times(AtLeast(1)); + .WillOnce(ExitMessageLoop(message_loop_.get())); host_->OnStopCapture(kDeviceId); host_->SetReturnReceviedDibs(true); host_->ReturnReceivedDibs(kDeviceId); - SyncWithVideoCaptureManagerThread(); + message_loop_->Run(); + host_->SetReturnReceviedDibs(false); // Expect the VideoCaptureDevice has been stopped EXPECT_EQ(0u, host_->entries_.size()); @@ -356,17 +337,17 @@ class VideoCaptureHostTest : public testing::Test { .Times(1); VideoCaptureControllerID id(kDeviceId); host_->OnError(id); - SyncWithVideoCaptureManagerThread(); + // Wait for the error callback. + message_loop_->RunAllPending(); } scoped_refptr<MockVideoCaptureHost> host_; private: scoped_ptr<MessageLoop> message_loop_; - scoped_ptr<BrowserThreadImpl> ui_thread_; scoped_ptr<BrowserThreadImpl> io_thread_; scoped_ptr<media::AudioManager> audio_manager_; - content::MockResourceContext resource_context_; + scoped_ptr<media_stream::MediaStreamManager> media_stream_manager_; DISALLOW_COPY_AND_ASSIGN(VideoCaptureHostTest); }; diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc index be5738d..3786efa 100644 --- a/content/browser/renderer_host/media/video_capture_manager.cc +++ b/content/browser/renderer_host/media/video_capture_manager.cc @@ -39,23 +39,23 @@ struct VideoCaptureManager::Controller { }; VideoCaptureManager::VideoCaptureManager() - : vc_device_thread_("VideoCaptureManagerThread"), - listener_(NULL), - new_capture_session_id_(kFirstSessionId), - use_fake_device_(false) { - vc_device_thread_.Start(); + : listener_(NULL), + new_capture_session_id_(kFirstSessionId), + use_fake_device_(false) { } VideoCaptureManager::~VideoCaptureManager() { - vc_device_thread_.Stop(); DCHECK(devices_.empty()); DCHECK(controllers_.empty()); } -void VideoCaptureManager::Register(MediaStreamProviderListener* listener) { +void VideoCaptureManager::Register(MediaStreamProviderListener* listener, + base::MessageLoopProxy* device_thread_loop) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(!listener_); + DCHECK(!device_loop_); listener_ = listener; + device_loop_ = device_thread_loop; } void VideoCaptureManager::Unregister() { @@ -67,8 +67,7 @@ void VideoCaptureManager::Unregister() { void VideoCaptureManager::EnumerateDevices() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(listener_); - - vc_device_thread_.message_loop()->PostTask( + device_loop_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::OnEnumerateDevices, this)); } @@ -80,7 +79,7 @@ int VideoCaptureManager::Open(const StreamDeviceInfo& device) { // Generate a new id for this device. int video_capture_session_id = new_capture_session_id_++; - vc_device_thread_.message_loop()->PostTask( + device_loop_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::OnOpen, this, video_capture_session_id, device)); @@ -91,8 +90,7 @@ int VideoCaptureManager::Open(const StreamDeviceInfo& device) { void VideoCaptureManager::Close(int capture_session_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(listener_); - - vc_device_thread_.message_loop()->PostTask( + device_loop_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::OnClose, this, capture_session_id)); } @@ -101,8 +99,7 @@ void VideoCaptureManager::Start( const media::VideoCaptureParams& capture_params, media::VideoCaptureDevice::EventHandler* video_capture_receiver) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - vc_device_thread_.message_loop()->PostTask( + device_loop_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::OnStart, this, capture_params, video_capture_receiver)); @@ -112,8 +109,7 @@ void VideoCaptureManager::Stop( const media::VideoCaptureSessionId& capture_session_id, base::Closure stopped_cb) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - vc_device_thread_.message_loop()->PostTask( + device_loop_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::OnStop, this, capture_session_id, stopped_cb)); @@ -128,12 +124,8 @@ void VideoCaptureManager::UseFakeDevice() { use_fake_device_ = true; } -MessageLoop* VideoCaptureManager::GetMessageLoop() { - return vc_device_thread_.message_loop(); -} - void VideoCaptureManager::OnEnumerateDevices() { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); media::VideoCaptureDevice::Names device_names; GetAvailableDevices(&device_names); @@ -152,7 +144,7 @@ void VideoCaptureManager::OnEnumerateDevices() { void VideoCaptureManager::OnOpen(int capture_session_id, const StreamDeviceInfo& device) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); DCHECK(devices_.find(capture_session_id) == devices_.end()); DVLOG(1) << "VideoCaptureManager::OnOpen, id " << capture_session_id; @@ -186,7 +178,7 @@ void VideoCaptureManager::OnOpen(int capture_session_id, } void VideoCaptureManager::OnClose(int capture_session_id) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); DVLOG(1) << "VideoCaptureManager::OnClose, id " << capture_session_id; media::VideoCaptureDevice* video_capture_device = NULL; @@ -222,7 +214,7 @@ void VideoCaptureManager::OnClose(int capture_session_id) { void VideoCaptureManager::OnStart( const media::VideoCaptureParams capture_params, media::VideoCaptureDevice::EventHandler* video_capture_receiver) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); DCHECK(video_capture_receiver != NULL); DVLOG(1) << "VideoCaptureManager::OnStart, (" << capture_params.width << ", " << capture_params.height @@ -253,7 +245,7 @@ void VideoCaptureManager::OnStart( void VideoCaptureManager::OnStop( const media::VideoCaptureSessionId capture_session_id, base::Closure stopped_cb) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); DVLOG(1) << "VideoCaptureManager::OnStop, id " << capture_session_id; VideoCaptureDevices::iterator it = devices_.find(capture_session_id); @@ -325,7 +317,7 @@ void VideoCaptureManager::OnError(int capture_session_id, } void VideoCaptureManager::PostOnOpened(int capture_session_id) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(&VideoCaptureManager::OnOpened, this, @@ -333,7 +325,7 @@ void VideoCaptureManager::PostOnOpened(int capture_session_id) { } void VideoCaptureManager::PostOnClosed(int capture_session_id) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(&VideoCaptureManager::OnClosed, this, @@ -342,7 +334,7 @@ void VideoCaptureManager::PostOnClosed(int capture_session_id) { void VideoCaptureManager::PostOnDevicesEnumerated( const StreamDeviceInfoArray& devices) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(&VideoCaptureManager::OnDevicesEnumerated, @@ -359,13 +351,13 @@ void VideoCaptureManager::PostOnError(int capture_session_id, capture_session_id, error)); } -bool VideoCaptureManager::IsOnCaptureDeviceThread() const { - return MessageLoop::current() == vc_device_thread_.message_loop(); +bool VideoCaptureManager::IsOnDeviceThread() const { + return device_loop_->BelongsToCurrentThread(); } void VideoCaptureManager::GetAvailableDevices( media::VideoCaptureDevice::Names* device_names) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); if (!use_fake_device_) { media::VideoCaptureDevice::GetDeviceNames(device_names); @@ -376,7 +368,7 @@ void VideoCaptureManager::GetAvailableDevices( bool VideoCaptureManager::DeviceOpened( const media::VideoCaptureDevice::Name& device_name) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); for (VideoCaptureDevices::iterator it = devices_.begin(); it != devices_.end(); ++it) { @@ -390,7 +382,7 @@ bool VideoCaptureManager::DeviceOpened( media::VideoCaptureDevice* VideoCaptureManager::GetOpenedDevice( const StreamDeviceInfo& device_info) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); for (VideoCaptureDevices::iterator it = devices_.begin(); it != devices_.end(); it++) { @@ -403,7 +395,7 @@ media::VideoCaptureDevice* VideoCaptureManager::GetOpenedDevice( bool VideoCaptureManager::DeviceInUse( const media::VideoCaptureDevice* video_capture_device) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); for (VideoCaptureDevices::iterator it = devices_.begin(); it != devices_.end(); ++it) { @@ -420,7 +412,7 @@ void VideoCaptureManager::AddController( VideoCaptureControllerEventHandler* handler, base::Callback<void(VideoCaptureController*)> added_cb) { DCHECK(handler); - vc_device_thread_.message_loop()->PostTask( + device_loop_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::DoAddControllerOnDeviceThread, this, capture_params, handler, added_cb)); @@ -430,7 +422,7 @@ void VideoCaptureManager::DoAddControllerOnDeviceThread( const media::VideoCaptureParams capture_params, VideoCaptureControllerEventHandler* handler, base::Callback<void(VideoCaptureController*)> added_cb) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); media::VideoCaptureDevice* video_capture_device = GetDeviceInternal(capture_params.session_id); @@ -452,7 +444,7 @@ void VideoCaptureManager::RemoveController( VideoCaptureController* controller, VideoCaptureControllerEventHandler* handler) { DCHECK(handler); - vc_device_thread_.message_loop()->PostTask( + device_loop_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::DoRemoveControllerOnDeviceThread, this, make_scoped_refptr(controller), handler)); @@ -461,7 +453,7 @@ void VideoCaptureManager::RemoveController( void VideoCaptureManager::DoRemoveControllerOnDeviceThread( VideoCaptureController* controller, VideoCaptureControllerEventHandler* handler) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); for (Controllers::iterator cit = controllers_.begin(); cit != controllers_.end(); ++cit) { @@ -485,7 +477,7 @@ void VideoCaptureManager::DoRemoveControllerOnDeviceThread( media::VideoCaptureDevice* VideoCaptureManager::GetDeviceInternal( int capture_session_id) { - DCHECK(IsOnCaptureDeviceThread()); + DCHECK(IsOnDeviceThread()); VideoCaptureDevices::iterator dit = devices_.find(capture_session_id); if (dit != devices_.end()) { return dit->second; diff --git a/content/browser/renderer_host/media/video_capture_manager.h b/content/browser/renderer_host/media/video_capture_manager.h index 1a06287..4a2f554 100644 --- a/content/browser/renderer_host/media/video_capture_manager.h +++ b/content/browser/renderer_host/media/video_capture_manager.h @@ -15,7 +15,6 @@ #include <map> #include "base/memory/ref_counted.h" -#include "base/threading/thread.h" #include "content/browser/renderer_host/media/media_stream_provider.h" #include "content/common/content_export.h" #include "content/common/media/media_stream_options.h" @@ -30,13 +29,8 @@ class VideoCaptureControllerEventHandler; namespace media_stream { // VideoCaptureManager opens/closes and start/stops video capture devices. -// It is deleted on the FILE thread so that it can call base::Thread::Stop() -// there without blocking UI/IO threads. This is also needed for incognito -// window. When incognito window is closed, IO thread is not in shutdown mode -// and base::Thread::Stop() can't be called on IO thread. class CONTENT_EXPORT VideoCaptureManager - : public base::RefCountedThreadSafe<VideoCaptureManager, - content::BrowserThread::DeleteOnFileThread>, + : public base::RefCountedThreadSafe<VideoCaptureManager>, public MediaStreamProvider { public: // Calling |Start| of this id will open the first device, even though open has @@ -47,7 +41,8 @@ class CONTENT_EXPORT VideoCaptureManager VideoCaptureManager(); // Implements MediaStreamProvider. - virtual void Register(MediaStreamProviderListener* listener) OVERRIDE; + virtual void Register(MediaStreamProviderListener* listener, + base::MessageLoopProxy* device_thread_loop) OVERRIDE; virtual void Unregister() OVERRIDE; @@ -78,7 +73,6 @@ class CONTENT_EXPORT VideoCaptureManager // video capture device. Due to timing requirements, the function must be // called before EnumerateDevices and Open. void UseFakeDevice(); - MessageLoop* GetMessageLoop(); // Called by VideoCaptureHost to get a controller for |capture_params|. // The controller is returned via calling |added_cb|. @@ -93,18 +87,14 @@ class CONTENT_EXPORT VideoCaptureManager private: friend class ::MockVideoCaptureManager; - friend struct content::BrowserThread::DeleteOnThread< - content::BrowserThread::FILE>; - friend class base::DeleteHelper<VideoCaptureManager>; - friend class base::RefCountedThreadSafe<VideoCaptureManager, - content::BrowserThread::DeleteOnFileThread>; + friend class base::RefCountedThreadSafe<VideoCaptureManager>; virtual ~VideoCaptureManager(); typedef std::list<VideoCaptureControllerEventHandler*> Handlers; struct Controller; - // Called by the public functions, executed on vc_device_thread_. + // Called by the public functions, executed on device thread. void OnEnumerateDevices(); void OnOpen(int capture_session_id, const StreamDeviceInfo& device); void OnClose(int capture_session_id); @@ -126,7 +116,7 @@ class CONTENT_EXPORT VideoCaptureManager void OnDevicesEnumerated(const StreamDeviceInfoArray& devices); void OnError(int capture_session_id, MediaStreamProviderError error); - // Executed on vc_device_thread_ to make sure Listener is called from + // Executed on device thread to make sure Listener is called from // Browser::IO thread. void PostOnOpened(int capture_session_id); void PostOnClosed(int capture_session_id); @@ -139,17 +129,17 @@ class CONTENT_EXPORT VideoCaptureManager bool DeviceInUse(const media::VideoCaptureDevice* video_capture_device); media::VideoCaptureDevice* GetOpenedDevice( const StreamDeviceInfo& device_info); - bool IsOnCaptureDeviceThread() const; + bool IsOnDeviceThread() const; media::VideoCaptureDevice* GetDeviceInternal(int capture_session_id); - // Thread for all calls to VideoCaptureDevice. - base::Thread vc_device_thread_; + // The message loop of media stream device thread that this object runs on. + scoped_refptr<base::MessageLoopProxy> device_loop_; // Only accessed on Browser::IO thread. MediaStreamProviderListener* listener_; int new_capture_session_id_; - // Only accessed from vc_device_thread_. + // Only accessed from device thread. // VideoCaptureManager owns all VideoCaptureDevices and is responsible for // deleting the instances when they are not used any longer. typedef std::map<int, media::VideoCaptureDevice*> VideoCaptureDevices; @@ -158,7 +148,7 @@ class CONTENT_EXPORT VideoCaptureManager // Set to true if using fake devices for testing, false by default. bool use_fake_device_; - // Only accessed from vc_device_thread_. + // Only accessed from device thread. // VideoCaptureManager owns all VideoCaptureController's and is responsible // for deleting the instances when they are not used any longer. // VideoCaptureDevice is one-to-one mapped to VideoCaptureController. diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc index 9b18576..2b063b3 100644 --- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc @@ -43,8 +43,9 @@ class MockMediaStreamProviderListener : public MediaStreamProviderListener { MOCK_METHOD3(Error, void(MediaStreamType, int, MediaStreamProviderError)); - virtual void DevicesEnumerated(MediaStreamType stream_type, - const StreamDeviceInfoArray& devices) { + virtual void DevicesEnumerated( + MediaStreamType stream_type, + const StreamDeviceInfoArray& devices) OVERRIDE { devices_.clear(); for (StreamDeviceInfoArray::const_iterator it = devices.begin(); it != devices.end(); @@ -62,66 +63,34 @@ class MockMediaStreamProviderListener : public MediaStreamProviderListener { namespace { // Needed as an input argument to Start(). -class MockFrameObserver: public media::VideoCaptureDevice::EventHandler { +class MockFrameObserver : public media::VideoCaptureDevice::EventHandler { public: - virtual void OnError() {} + virtual void OnError() OVERRIDE {} void OnFrameInfo(const media::VideoCaptureCapability& info) {} virtual void OnIncomingCapturedFrame(const uint8* data, int length, - base::Time timestamp) {} + base::Time timestamp) OVERRIDE {} }; // Test class class VideoCaptureManagerTest : public testing::Test { public: - VideoCaptureManagerTest() - : vcm_(), - listener_(), - message_loop_(), - io_thread_(), - frame_observer_() { - } + VideoCaptureManagerTest() {} virtual ~VideoCaptureManagerTest() {} protected: - virtual void SetUp() { + virtual void SetUp() OVERRIDE { listener_.reset(new media_stream::MockMediaStreamProviderListener()); message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, message_loop_.get())); vcm_ = new media_stream::VideoCaptureManager(); vcm_->UseFakeDevice(); - vcm_->Register(listener_.get()); + vcm_->Register(listener_.get(), message_loop_->message_loop_proxy()); frame_observer_.reset(new MockFrameObserver()); } - virtual void TearDown() { - io_thread_.reset(); - } - - // Called on the VideoCaptureManager thread. - static void PostQuitMessageLoop(MessageLoop* message_loop) { - message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); - } + virtual void TearDown() OVERRIDE {} - // Called on the main thread. - static void PostQuitOnVideoCaptureManagerThread( - MessageLoop* message_loop, media_stream::VideoCaptureManager* vcm) { - vcm->GetMessageLoop()->PostTask( - FROM_HERE, base::Bind(&PostQuitMessageLoop, message_loop)); - } - - // SyncWithVideoCaptureManagerThread() waits until all pending tasks on the - // video_capture_manager internal thread are executed while also processing - // pending task in message_loop_ on the current thread. It is used to - // synchronize with the video capture manager thread when we are stopping a - // video capture device. - void SyncWithVideoCaptureManagerThread() { - message_loop_->PostTask( - FROM_HERE, base::Bind(&PostQuitOnVideoCaptureManagerThread, - message_loop_.get(), - vcm_)); - message_loop_->Run(); - } scoped_refptr<media_stream::VideoCaptureManager> vcm_; scoped_ptr<media_stream::MockMediaStreamProviderListener> listener_; scoped_ptr<MessageLoop> message_loop_; @@ -149,7 +118,7 @@ TEST_F(VideoCaptureManagerTest, CreateAndClose) { vcm_->EnumerateDevices(); // Wait to get device callback. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); int video_session_id = vcm_->Open(listener_->devices_.front()); @@ -164,7 +133,7 @@ TEST_F(VideoCaptureManagerTest, CreateAndClose) { vcm_->Close(video_session_id); // Wait to check callbacks before removing the listener. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); vcm_->Unregister(); } @@ -183,7 +152,7 @@ TEST_F(VideoCaptureManagerTest, OpenTwice) { vcm_->EnumerateDevices(); // Wait to get device callback. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); int video_session_id_first = vcm_->Open(listener_->devices_.front()); @@ -196,7 +165,7 @@ TEST_F(VideoCaptureManagerTest, OpenTwice) { vcm_->Close(video_session_id_second); // Wait to check callbacks before removing the listener. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); vcm_->Unregister(); } @@ -215,7 +184,7 @@ TEST_F(VideoCaptureManagerTest, OpenTwo) { vcm_->EnumerateDevices(); // Wait to get device callback. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); media_stream::StreamDeviceInfoArray::iterator it = listener_->devices_.begin(); @@ -228,7 +197,7 @@ TEST_F(VideoCaptureManagerTest, OpenTwo) { vcm_->Close(video_session_id_second); // Wait to check callbacks before removing the listener. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); vcm_->Unregister(); } @@ -244,7 +213,7 @@ TEST_F(VideoCaptureManagerTest, OpenNotExisting) { vcm_->EnumerateDevices(); // Wait to get device callback. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); media_stream::MediaStreamType stream_type = content::MEDIA_STREAM_DEVICE_TYPE_VIDEO_CAPTURE; @@ -257,7 +226,7 @@ TEST_F(VideoCaptureManagerTest, OpenNotExisting) { vcm_->Open(dummy_device); // Wait to check callbacks before removing the listener. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); vcm_->Unregister(); } @@ -286,7 +255,7 @@ TEST_F(VideoCaptureManagerTest, StartUsingId) { base::Closure()); // Wait to check callbacks before removing the listener. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); vcm_->Unregister(); } @@ -305,7 +274,7 @@ TEST_F(VideoCaptureManagerTest, CloseWithoutStop) { vcm_->EnumerateDevices(); // Wait to get device callback. - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); int video_session_id = vcm_->Open(listener_->devices_.front()); @@ -322,7 +291,7 @@ TEST_F(VideoCaptureManagerTest, CloseWithoutStop) { vcm_->Stop(video_session_id, base::Closure()); // Wait to check callbacks before removing the listener - SyncWithVideoCaptureManagerThread(); + message_loop_->RunAllPending(); vcm_->Unregister(); } |