diff options
author | xians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-20 17:28:44 +0000 |
---|---|---|
committer | xians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-20 17:28:44 +0000 |
commit | 855cb828e518efd40ac97d08107ad58d996698be (patch) | |
tree | 1a28a6429c873ac637362ebcc8000011095c5779 /content/browser | |
parent | a42a7ee454165d73e161448383cdf3dc3b1f164a (diff) | |
download | chromium_src-855cb828e518efd40ac97d08107ad58d996698be.zip chromium_src-855cb828e518efd40ac97d08107ad58d996698be.tar.gz chromium_src-855cb828e518efd40ac97d08107ad58d996698be.tar.bz2 |
Hooking up AudioInputDeviceManager to AudioInputRendererHost and MediaStreamManager.
Review URL: http://codereview.chromium.org/7462012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@101975 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser')
7 files changed, 185 insertions, 31 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 8fafb01..e1970c1 100644 --- a/content/browser/renderer_host/media/audio_input_device_manager.cc +++ b/content/browser/renderer_host/media/audio_input_device_manager.cc @@ -11,8 +11,8 @@ namespace media_stream { -const int AudioInputDeviceManager::kFakeOpenSessionId = 0; -const int AudioInputDeviceManager::kInvalidSessionId = -1; +const int AudioInputDeviceManager::kFakeOpenSessionId = 1; +const int AudioInputDeviceManager::kInvalidSessionId = 0; const int AudioInputDeviceManager::kInvalidDevice = -1; const int AudioInputDeviceManager::kDefaultDeviceIndex = 0; @@ -111,14 +111,14 @@ void AudioInputDeviceManager::Start( // And we do not store the info for the kFakeOpenSessionId but return // the callback immediately. if (session_id == kFakeOpenSessionId) { - event_handler->OnStartDevice(session_id, kDefaultDeviceIndex); + event_handler->OnDeviceStarted(session_id, kDefaultDeviceIndex); return; } // If session has been started, post a callback with an error. if (event_handlers_.find(session_id) != event_handlers_.end()) { // Session has been started, post a callback with error. - event_handler->OnStartDevice(session_id, kInvalidDevice); + event_handler->OnDeviceStarted(session_id, kInvalidDevice); return; } @@ -265,7 +265,7 @@ void AudioInputDeviceManager::ClosedOnIOThread(int session_id) { EventHandlerMap::iterator it = event_handlers_.find(session_id); if (it != event_handlers_.end()) { // The device hasn't been stopped, send stop signal. - it->second->OnStopDevice(session_id); + it->second->OnDeviceStopped(session_id); event_handlers_.erase(session_id); } listener_->Closed(kAudioCapture, session_id); @@ -286,8 +286,8 @@ void AudioInputDeviceManager::StartedOnIOThread(int session_id, int index) { if (it == event_handlers_.end()) return; - // Post a callback through the event handler to start the device. - it->second->OnStartDevice(session_id, index); + // Post a callback through the event handler to create an audio stream. + it->second->OnDeviceStarted(session_id, index); } void AudioInputDeviceManager::StoppedOnIOThread(int session_id) { diff --git a/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h b/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h index 75cb984..3790e4e 100644 --- a/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h +++ b/content/browser/renderer_host/media/audio_input_device_manager_event_handler.h @@ -12,12 +12,14 @@ namespace media_stream { class AudioInputDeviceManagerEventHandler { public: - // Used to start the device referenced by session id and index. - virtual void OnStartDevice(int session_id, int index) = 0; - - // Used to stop the device referenced by session id. This method is used - // only when users call Close() without calling Stop() on a started device. - virtual void OnStopDevice(int session_id) = 0; + // Called by AudioInputDeviceManager to create an audio stream using the + // device index when the device has been started. + virtual void OnDeviceStarted(int session_id, int index) = 0; + + // Called by AudioInputDeviceManager to stop the audio stream when a device + // has been stopped. This method is used only when users call Close() without + // calling Stop() on a started device. + virtual void OnDeviceStopped(int session_id) = 0; virtual ~AudioInputDeviceManagerEventHandler() {} }; 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 de27d5d..f7cc6ff 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 @@ -52,8 +52,8 @@ class MockAudioInputDeviceManagerEventHandler MockAudioInputDeviceManagerEventHandler() {} virtual ~MockAudioInputDeviceManagerEventHandler() {} - MOCK_METHOD2(OnStartDevice, void(int, int)); - MOCK_METHOD1(OnStopDevice, void(int)); + MOCK_METHOD2(OnDeviceStarted, void(int, int)); + MOCK_METHOD1(OnDeviceStopped, void(int)); private: DISALLOW_COPY_AND_ASSIGN(MockAudioInputDeviceManagerEventHandler); @@ -294,7 +294,7 @@ TEST_F(AudioInputDeviceManagerTest, StartAndStopDevice) { session_id[index])) .Times(1); EXPECT_CALL(*audio_input_event_handler, - OnStartDevice(session_id[index], index)) + OnDeviceStarted(session_id[index], index)) .Times(1); EXPECT_CALL(*audio_input_listener_, Closed(kAudioCapture, session_id[index])) @@ -332,12 +332,12 @@ TEST_F(AudioInputDeviceManagerTest, CloseWithoutStopDevice) { session_id[index])) .Times(1); EXPECT_CALL(*audio_input_event_handler, - OnStartDevice(session_id[index], index)) + OnDeviceStarted(session_id[index], index)) .Times(1); // Event Handler should get a stop device notification as no stop is called // before closing the device. EXPECT_CALL(*audio_input_event_handler, - OnStopDevice(session_id[index])) + OnDeviceStopped(session_id[index])) .Times(1); EXPECT_CALL(*audio_input_listener_, Closed(kAudioCapture, session_id[index])) @@ -381,10 +381,10 @@ TEST_F(AudioInputDeviceManagerTest, StartDeviceTwice) { EXPECT_CALL(*audio_input_listener_, Opened(kAudioCapture, second_session_id)) .Times(1); EXPECT_CALL(*first_audio_input_event_handler, - OnStartDevice(first_session_id, 0)) + OnDeviceStarted(first_session_id, 0)) .Times(1); EXPECT_CALL(*second_audio_input_event_handler, - OnStartDevice(second_session_id, 0)) + OnDeviceStarted(second_session_id, 0)) .Times(1); EXPECT_CALL(*audio_input_listener_, Closed(kAudioCapture, first_session_id)) .Times(1); 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 f8b92db..84532ba 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc @@ -8,7 +8,9 @@ #include "base/process.h" #include "base/shared_memory.h" #include "content/browser/renderer_host/media/audio_common.h" +#include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/browser/renderer_host/media/audio_input_sync_writer.h" +#include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/common/media/audio_messages.h" #include "ipc/ipc_logging.h" @@ -167,6 +169,7 @@ bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message, bool* message_was_ok) { bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(AudioInputRendererHost, message, *message_was_ok) + IPC_MESSAGE_HANDLER(AudioInputHostMsg_StartDevice, OnStartDevice) IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream) IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream) IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream) @@ -177,6 +180,25 @@ bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message, return handled; } +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. + // TODO(mflodman): Get AudioInputDeviceManager from MediaStreamManager. + media_stream::AudioInputDeviceManager* audio_input_man = NULL; + if (!audio_input_man) { + SendErrorMessage(stream_id); + return; + } + + // 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); +} void AudioInputRendererHost::OnCreateStream( int stream_id, const AudioParameters& params, bool low_latency) { @@ -257,6 +279,11 @@ void AudioInputRendererHost::OnCloseStream(int stream_id) { if (entry) CloseAndDeleteStream(entry); + + int session_id = LookupSessionById(stream_id); + + if (session_id) + StopAndDeleteDevice(session_id); } void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) { @@ -300,6 +327,54 @@ void AudioInputRendererHost::DeleteEntries() { } } +void AudioInputRendererHost::OnDeviceStarted(int session_id, int index) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + SessionEntryMap::iterator it = session_entries_.find(session_id); + if (it == session_entries_.end()) { + DLOG(WARNING) << "AudioInputRendererHost::OnDeviceStarted()" + " session does not exist."; + return; + } + + // Notify the renderer that the device has been started. + Send(new AudioInputMsg_NotifyDeviceStarted(it->second, index)); +} + +void AudioInputRendererHost::OnDeviceStopped(int session_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + SessionEntryMap::iterator it = session_entries_.find(session_id); + // Return if the stream has been closed. + if (it == session_entries_.end()) + return; + + int stream_id = it->second; + AudioEntry* entry = LookupById(stream_id); + + if (entry) { + // Device has been stopped, close the input stream. + CloseAndDeleteStream(entry); + // Notify the renderer that the state of the input stream has changed. + Send(new AudioInputMsg_NotifyStreamStateChanged(stream_id, + kAudioStreamPaused)); + } + + // Delete the session entry. + session_entries_.erase(it); +} + +void AudioInputRendererHost::StopAndDeleteDevice(int session_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + // TODO(mflodman): Get AudioInputDeviceManager from MediaStreamManager. + media_stream::AudioInputDeviceManager* audio_input_man = NULL; + if (audio_input_man) + audio_input_man->Stop(session_id); + + // Delete the session entry. + session_entries_.erase(session_id); +} + void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) { if (!entry->pending_close) { entry->pending_close = true; @@ -360,3 +435,15 @@ AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController( } return NULL; } + +int AudioInputRendererHost::LookupSessionById(int stream_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + for (SessionEntryMap::iterator it = session_entries_.begin(); + it != session_entries_.end(); ++it) { + if (stream_id == it->second) { + return it->first; + } + } + return 0; +} 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 5fde275..94ef85e 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.h +++ b/content/browser/renderer_host/media/audio_input_renderer_host.h @@ -5,6 +5,42 @@ // AudioInputRendererHost serves audio related requests from audio capturer // which lives inside the render process and provide access to audio hardware. // +// OnCreateStream() request is only available in the low latency mode. It will +// creates a shared memory, a SyncWriter and a AudioInputController for the +// input stream. + +// OnCloseStream() will close the input stream. +// +// Create stream sequence: +// +// OnCreateStream -> AudioInputController::CreateLowLatency() -> +// DoCompleteCreation -> AudioInputMsg_NotifyLowLatencyStreamCreated +// +// Close stream sequence: +// OnCloseStream -> AudioInputController::Close +// +// For the OnStartDevice() request, AudioInputRendererHost starts the device +// referenced by the session id, and a OnDeviceStarted() callback with the +// index of the opened device will be received later. Then it will send a IPC +// message to notify the renderer that the device is ready, so that renderer +// can continue with the OnCreateStream() request. +// +// OnDeviceStopped() is called when the user closes the device through +// AudioInputDeviceManager without calling Stop() before. What +// AudioInputRenderHost::OnDeviceStopped() does is to send a IPC mesaage to +// notify the renderer in order to stop the stream. +// +// Start device sequence: +// +// OnStartDevice -> AudioInputDeviceManager::Start -> +// AudioInputDeviceManagerEventHandler::OnDeviceStarted -> +// AudioInputMsg_NotifyDeviceStarted +// +// Shutdown device sequence: +// +// OnDeviceStopped -> CloseAndDeleteStream +// AudioInputMsg_NotifyStreamStateChanged +// // This class is owned by BrowserRenderProcessHost and instantiated on UI // thread. All other operations and method calls happen on IO thread, so we // need to be extra careful about the lifetime of this object. AudioManager is a @@ -28,6 +64,7 @@ #include "base/shared_memory.h" #include "content/browser/browser_message_filter.h" #include "content/browser/browser_thread.h" +#include "content/browser/renderer_host/media/audio_input_device_manager_event_handler.h" #include "media/audio/audio_input_controller.h" #include "media/audio/audio_io.h" #include "media/audio/simple_sources.h" @@ -37,7 +74,8 @@ struct AudioParameters; class AudioInputRendererHost : public BrowserMessageFilter, - public media::AudioInputController::EventHandler { + public media::AudioInputController::EventHandler, + public media_stream::AudioInputDeviceManagerEventHandler { public: struct AudioEntry { AudioEntry(); @@ -60,8 +98,6 @@ class AudioInputRendererHost bool pending_close; }; - typedef std::map<int, AudioEntry*> AudioEntryMap; - // Called from UI thread from the owner of this object. AudioInputRendererHost(); @@ -80,6 +116,10 @@ class AudioInputRendererHost const uint8* data, uint32 size); + // media_stream::AudioInputDeviceManagerEventHandler implementation. + virtual void OnDeviceStarted(int session_id, int index); + virtual void OnDeviceStopped(int session_id); + private: // TODO(henrika): extend test suite (compare AudioRenderHost) friend class BrowserThread; @@ -89,6 +129,10 @@ class AudioInputRendererHost // Methods called on IO thread ---------------------------------------------- + // Start the audio input device with the session id. If the device + // starts successfully, it will trigger OnDeviceStarted() callback. + void OnStartDevice(int stream_id, int session_id); + // Audio related IPC message handlers. // Creates an audio input stream with the specified format. If this call is // successful this object would keep an internal entry of the stream for the @@ -139,6 +183,9 @@ class AudioInputRendererHost // Delete audio entry and close the related audio input stream. void DeleteEntryOnError(AudioEntry* entry); + // Stop the device and delete its audio session entry. + void StopAndDeleteDevice(int stream_id); + // A helper method to look up a AudioEntry identified by |stream_id|. // Returns NULL if not found. AudioEntry* LookupById(int stream_id); @@ -148,9 +195,18 @@ class AudioInputRendererHost // event is received. AudioEntry* LookupByController(media::AudioInputController* controller); + // A helper method to look up a session identified by |stream_id|. + // Returns 0 if not found. + int LookupSessionById(int stream_id); + // A map of stream IDs to audio sources. + typedef std::map<int, AudioEntry*> AudioEntryMap; AudioEntryMap audio_entries_; + // A map of session IDs to audio session sources. + typedef std::map<int, int> SessionEntryMap; + SessionEntryMap session_entries_; + DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHost); }; diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 786cb26..3348a1b9 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc @@ -17,7 +17,7 @@ namespace media_stream { -// TODO(mflodman) Find out who should own MediaStreamManager. +// TODO(mflodman): Find out who should own MediaStreamManager. base::LazyInstance<MediaStreamManager> g_media_stream_manager( base::LINKER_INITIALIZED); @@ -63,6 +63,12 @@ VideoCaptureManager* MediaStreamManager::video_capture_manager() { return video_capture_manager_; } +AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + // TODO(mflodman): Add when audio input manager is available. + return NULL; +} + void MediaStreamManager::GenerateStream(MediaStreamRequester* requester, int render_process_id, int render_view_id, @@ -71,7 +77,7 @@ void MediaStreamManager::GenerateStream(MediaStreamRequester* requester, std::string* label) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - // TODO(mflodman) Remove next line when audio is supported. + // TODO(mflodman): Remove next line when audio is supported. (const_cast<StreamOptions&>(options)).audio = false; // Create a new request based on options. @@ -111,7 +117,7 @@ void MediaStreamManager::CancelRequests(MediaStreamRequester* requester) { request->audio_devices.begin(); it != request->audio_devices.end(); ++it) { if (it->in_use == true) { - // TODO(mflodman) Add when audio input device manager is available. + // TODO(mflodman): Add when audio input device manager is available. } } } @@ -139,7 +145,7 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) { for (StreamDeviceInfoArray::iterator audio_it = it->second.audio_devices.begin(); audio_it != it->second.audio_devices.end(); ++audio_it) { - // TODO(mflodman) Add code when audio input manager exists. + // TODO(mflodman): Add code when audio input manager exists. NOTREACHED(); } for (StreamDeviceInfoArray::iterator video_it = @@ -356,7 +362,7 @@ void MediaStreamManager::UseFakeDevice() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); video_capture_manager_->UseFakeDevice(); device_settings_->UseFakeUI(); - // TODO(mflodman) Add audio manager when available. + // TODO(mflodman): Add audio manager when available. } bool MediaStreamManager::RequestDone(const DeviceRequest& request) const { @@ -389,7 +395,7 @@ MediaStreamProvider* MediaStreamManager::GetDeviceManager( if (stream_type == kVideoCapture) { return video_capture_manager_; } else if (stream_type == kAudioCapture) { - // TODO(mflodman) Add support when audio input manager is available. + // TODO(mflodman): Add support when audio input manager is available. NOTREACHED(); return NULL; } @@ -404,7 +410,7 @@ MediaStreamManager::MediaStreamManager() device_settings_(NULL) { device_settings_ = new MediaStreamDeviceSettings(this); video_capture_manager_->Register(this); - // TODO(mflodman) Add when audio input manager is available. + // TODO(mflodman): Add when audio input manager is available. } MediaStreamManager::DeviceRequest::DeviceRequest() diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h index f5792ce..27fea0c 100644 --- a/content/browser/renderer_host/media/media_stream_manager.h +++ b/content/browser/renderer_host/media/media_stream_manager.h @@ -30,6 +30,7 @@ namespace media_stream { +class AudioInputDeviceManager; class MediaStreamDeviceSettings; class MediaStreamRequester; class VideoCaptureManager; @@ -49,6 +50,9 @@ class MediaStreamManager // Used to access VideoCaptuerManager. VideoCaptureManager* video_capture_manager(); + // Used to access AudioInputDeviceManager. + AudioInputDeviceManager* audio_input_device_manager(); + // GenerateStream opens new media devices according to |components|. The // request is identified using |label|, which is pointing to an already // created std::string. @@ -113,7 +117,6 @@ class MediaStreamManager MediaStreamManager(); VideoCaptureManager* video_capture_manager_; - // TODO(mflodman) Add AudioInputManager. // Keeps track of device types currently being enumerated to not enumerate // when not necessary. |