From f7eb0a394522b0c3d6e9c16b54072e0bbafa0957 Mon Sep 17 00:00:00 2001 From: "henrika@chromium.org" Date: Tue, 12 Jul 2011 10:19:51 +0000 Subject: Ensures that AudioMessageFilter now lives on the main render thread. In addition, removes usage of routing ID by utilizing control messages instead of routed messages. BUG=none TESTS=none Review URL: http://codereview.chromium.org/7157001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92138 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/media/media_internals.cc | 26 +- chrome/browser/media/media_internals.h | 17 +- .../media/audio_input_renderer_host.cc | 64 ++--- .../media/audio_input_renderer_host.h | 32 +-- .../renderer_host/media/audio_renderer_host.cc | 103 ++++---- .../renderer_host/media/audio_renderer_host.h | 44 ++-- .../media/audio_renderer_host_unittest.cc | 103 +++----- .../browser/renderer_host/media/media_observer.h | 14 +- .../renderer_host/media/mock_media_observer.h | 19 +- content/common/media/audio_messages.h | 167 ++++++------- content/renderer/media/audio_device.cc | 87 ++----- content/renderer/media/audio_device.h | 87 +++++-- content/renderer/media/audio_input_device.cc | 82 ++---- content/renderer/media/audio_input_device.h | 80 ++++-- .../renderer/media/audio_input_message_filter.cc | 30 +-- .../renderer/media/audio_input_message_filter.h | 14 +- content/renderer/media/audio_message_filter.cc | 28 +-- content/renderer/media/audio_message_filter.h | 16 +- .../media/audio_message_filter_unittest.cc | 31 +-- content/renderer/media/audio_renderer_impl.cc | 107 ++++---- content/renderer/media/audio_renderer_impl.h | 14 +- .../renderer/media/audio_renderer_impl_unittest.cc | 276 +++++++++++++++++---- content/renderer/pepper_plugin_delegate_impl.cc | 36 +-- content/renderer/render_thread.cc | 16 +- content/renderer/render_thread.h | 12 + content/renderer/render_view.cc | 9 +- content/renderer/render_view.h | 6 - 27 files changed, 803 insertions(+), 717 deletions(-) diff --git a/chrome/browser/media/media_internals.cc b/chrome/browser/media/media_internals.cc index 78d66f3..0eecd64 100644 --- a/chrome/browser/media/media_internals.cc +++ b/chrome/browser/media/media_internals.cc @@ -18,28 +18,27 @@ static const char kSendEverythingFunction[] = "onReceiveEverything"; MediaInternals::~MediaInternals() {} -void MediaInternals::OnDeleteAudioStream( - void* host, int32 render_view, int stream_id) { - std::string stream = base::StringPrintf("audio_streams.%p:%d:%d", - host, render_view, stream_id); +void MediaInternals::OnDeleteAudioStream(void* host, int stream_id) { + std::string stream = base::StringPrintf("audio_streams.%p:%d", + host, stream_id); DeleteItem(stream); } void MediaInternals::OnSetAudioStreamPlaying( - void* host, int32 render_view, int stream_id, bool playing) { - UpdateAudioStream(host, render_view, stream_id, + void* host, int stream_id, bool playing) { + UpdateAudioStream(host, stream_id, "playing", Value::CreateBooleanValue(playing)); } void MediaInternals::OnSetAudioStreamStatus( - void* host, int32 render_view, int stream_id, const std::string& status) { - UpdateAudioStream(host, render_view, stream_id, + void* host, int stream_id, const std::string& status) { + UpdateAudioStream(host, stream_id, "status", Value::CreateStringValue(status)); } void MediaInternals::OnSetAudioStreamVolume( - void* host, int32 render_view, int stream_id, double volume) { - UpdateAudioStream(host, render_view, stream_id, + void* host, int stream_id, double volume) { + UpdateAudioStream(host, stream_id, "volume", Value::CreateDoubleValue(volume)); } @@ -59,10 +58,9 @@ MediaInternals::MediaInternals() : observers_(new ObserverListThreadSafe()) {} void MediaInternals::UpdateAudioStream( - void* host, int32 render_view, int stream_id, - const std::string& property, Value* value) { - std::string stream = base::StringPrintf("audio_streams.%p:%d:%d", - host, render_view, stream_id); + void* host, int stream_id, const std::string& property, Value* value) { + std::string stream = base::StringPrintf("audio_streams.%p:%d", + host, stream_id); UpdateItem(kAudioUpdateFunction, stream, property, value); } diff --git a/chrome/browser/media/media_internals.h b/chrome/browser/media/media_internals.h index 8d8e566..1bda944 100644 --- a/chrome/browser/media/media_internals.h +++ b/chrome/browser/media/media_internals.h @@ -19,14 +19,11 @@ class MediaInternals : public MediaObserver { virtual ~MediaInternals(); // MediaObserver implementation. These are called from the IO thread: - virtual void OnDeleteAudioStream(void* host, int32 render_view, - int stream_id); - virtual void OnSetAudioStreamPlaying(void* host, int32 render_view, - int stream_id, bool playing); - virtual void OnSetAudioStreamStatus(void* host, int32 render_view, - int stream_id, const std::string& status); - virtual void OnSetAudioStreamVolume(void* host, int32 render_view, - int stream_id, double volume); + virtual void OnDeleteAudioStream(void* host, int stream_id); + virtual void OnSetAudioStreamPlaying(void* host, int stream_id, bool playing); + virtual void OnSetAudioStreamStatus(void* host, int stream_id, + const std::string& status); + virtual void OnSetAudioStreamVolume(void* host, int stream_id, double volume); // Methods for observers. Called from the observer's own thread: // UIs should add themselves on construction and remove themselves @@ -42,9 +39,9 @@ class MediaInternals : public MediaObserver { MediaInternals(); // Sets |property| of an audio stream to |value| and notifies observers. - // (host, render_view, stream_id) is a unique id for the audio stream. + // (host, stream_id) is a unique id for the audio stream. // |host| will never be dereferenced. - void UpdateAudioStream(void* host, int32 render_view, int stream_id, + void UpdateAudioStream(void* host, int stream_id, const std::string& property, Value* value); // Removes |item| from |data_|. 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 8298103..f8b92db 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc @@ -14,8 +14,7 @@ AudioInputRendererHost::AudioEntry::AudioEntry() - : render_view_id(0), - stream_id(0), + : stream_id(0), pending_close(false) { } @@ -80,7 +79,6 @@ void AudioInputRendererHost::OnData(media::AudioInputController* controller, void AudioInputRendererHost::DoCompleteCreation( media::AudioInputController* controller) { - VLOG(1) << "AudioInputRendererHost::DoCompleteCreation()"; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); AudioEntry* entry = LookupByController(controller); @@ -129,7 +127,7 @@ void AudioInputRendererHost::DoCompleteCreation( } Send(new AudioInputMsg_NotifyLowLatencyStreamCreated( - entry->render_view_id, entry->stream_id, foreign_memory_handle, + entry->stream_id, foreign_memory_handle, foreign_socket_handle, entry->shared_memory.created_size())); return; } @@ -181,12 +179,11 @@ bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message, } void AudioInputRendererHost::OnCreateStream( - const IPC::Message& msg, int stream_id, - const AudioParameters& params, bool low_latency) { + int stream_id, const AudioParameters& params, bool low_latency) { VLOG(1) << "AudioInputRendererHost::OnCreateStream(stream_id=" << stream_id << ")"; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK(LookupById(msg.routing_id(), stream_id) == NULL); + DCHECK(LookupById(stream_id) == NULL); // Prevent the renderer process from asking for a normal-latency // input stream. @@ -207,7 +204,7 @@ void AudioInputRendererHost::OnCreateStream( // Create the shared memory and share with the renderer process. if (!entry->shared_memory.CreateAndMapAnonymous(packet_size)) { // If creation of shared memory failed then send an error message. - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -217,7 +214,7 @@ void AudioInputRendererHost::OnCreateStream( // Then try to initialize the sync writer. if (!writer->Init()) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -230,50 +227,44 @@ void AudioInputRendererHost::OnCreateStream( entry->writer.get()); if (!entry->controller) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } // If we have created the controller successfully create a entry and add it // to the map. - entry->render_view_id = msg.routing_id(); entry->stream_id = stream_id; - audio_entries_.insert(std::make_pair( - AudioEntryId(msg.routing_id(), stream_id), - entry.release())); + audio_entries_.insert(std::make_pair(stream_id, entry.release())); } -void AudioInputRendererHost::OnRecordStream(const IPC::Message& msg, - int stream_id) { +void AudioInputRendererHost::OnRecordStream(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } entry->controller->Record(); } -void AudioInputRendererHost::OnCloseStream(const IPC::Message& msg, - int stream_id) { +void AudioInputRendererHost::OnCloseStream(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (entry) CloseAndDeleteStream(entry); } -void AudioInputRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id, - double volume) { +void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -281,13 +272,12 @@ void AudioInputRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id, NOTIMPLEMENTED(); } -void AudioInputRendererHost::OnGetVolume(const IPC::Message& msg, - int stream_id) { +void AudioInputRendererHost::OnGetVolume(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -295,11 +285,9 @@ void AudioInputRendererHost::OnGetVolume(const IPC::Message& msg, NOTIMPLEMENTED(); } -void AudioInputRendererHost::SendErrorMessage(int32 render_view_id, - int32 stream_id) { +void AudioInputRendererHost::SendErrorMessage(int stream_id) { // TODO(henrika): error state for audio input is not unique - Send(new AudioMsg_NotifyStreamStateChanged(render_view_id, - stream_id, + Send(new AudioMsg_NotifyStreamStateChanged(stream_id, kAudioStreamError)); } @@ -337,8 +325,7 @@ void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) { scoped_ptr entry_deleter(entry); // Erase the entry from the map. - audio_entries_.erase( - AudioEntryId(entry->render_view_id, entry->stream_id)); + audio_entries_.erase(entry->stream_id); } void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) { @@ -346,16 +333,15 @@ void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) { // Sends the error message first before we close the stream because // |entry| is destroyed in DeleteEntry(). - SendErrorMessage(entry->render_view_id, entry->stream_id); + SendErrorMessage(entry->stream_id); CloseAndDeleteStream(entry); } AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById( - int route_id, int stream_id) { + int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntryMap::iterator i = audio_entries_.find( - AudioEntryId(route_id, stream_id)); + AudioEntryMap::iterator i = audio_entries_.find(stream_id); if (i != audio_entries_.end()) return i->second; return NULL; 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 82b79a3..b7d40b4 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.h +++ b/content/browser/renderer_host/media/audio_input_renderer_host.h @@ -38,8 +38,6 @@ struct AudioParameters; class AudioInputRendererHost : public BrowserMessageFilter, public media::AudioInputController::EventHandler { public: - typedef std::pair AudioEntryId; - struct AudioEntry { AudioEntry(); ~AudioEntry(); @@ -47,9 +45,6 @@ class AudioInputRendererHost : public BrowserMessageFilter, // The AudioInputController that manages the audio input stream. scoped_refptr controller; - // Render view ID that requested the audio input stream. - int32 render_view_id; - // The audio input stream ID in the render view. int stream_id; @@ -64,7 +59,7 @@ class AudioInputRendererHost : public BrowserMessageFilter, bool pending_close; }; - typedef std::map AudioEntryMap; + typedef std::map AudioEntryMap; // Called from UI thread from the owner of this object. AudioInputRendererHost(); @@ -91,30 +86,27 @@ class AudioInputRendererHost : public BrowserMessageFilter, virtual ~AudioInputRendererHost(); - // Methods called on IO thread. - // Returns true if the message is an audio input related message and should - // be handled by this class. - bool IsAudioRendererHostMessage(const IPC::Message& message); + // Methods called on IO thread ---------------------------------------------- // 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 // required properties. - void OnCreateStream(const IPC::Message& msg, int stream_id, + void OnCreateStream(int stream_id, const AudioParameters& params, bool low_latency); // Record the audio input stream referenced by |stream_id|. - void OnRecordStream(const IPC::Message& msg, int stream_id); + void OnRecordStream(int stream_id); // Close the audio stream referenced by |stream_id|. - void OnCloseStream(const IPC::Message& msg, int stream_id); + void OnCloseStream(int stream_id); // Set the volume of the audio stream referenced by |stream_id|. - void OnSetVolume(const IPC::Message& msg, int stream_id, double volume); + void OnSetVolume(int stream_id, double volume); // Get the volume of the audio stream referenced by |stream_id|. - void OnGetVolume(const IPC::Message& msg, int stream_id); + void OnGetVolume(int stream_id); // Complete the process of creating an audio input stream. This will set up // the shared memory or shared socket in low latency mode. @@ -128,7 +120,7 @@ class AudioInputRendererHost : public BrowserMessageFilter, void DoHandleError(media::AudioInputController* controller, int error_code); // Send an error message to the renderer. - void SendErrorMessage(int32 render_view_id, int32 stream_id); + void SendErrorMessage(int stream_id); // Delete all audio entry and all audio streams void DeleteEntries(); @@ -146,16 +138,16 @@ class AudioInputRendererHost : public BrowserMessageFilter, // Delete audio entry and close the related audio input stream. void DeleteEntryOnError(AudioEntry* entry); - // A helper method to look up a AudioEntry with a tuple of render view - // id and stream id. Returns NULL if not found. - AudioEntry* LookupById(int render_view_id, 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); // Search for a AudioEntry having the reference to |controller|. // This method is used to look up an AudioEntry after a controller // event is received. AudioEntry* LookupByController(media::AudioInputController* controller); - // A map of id to audio sources. + // A map of stream IDs to audio sources. AudioEntryMap audio_entries_; DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHost); diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc index d9a4bf1..3c59e4f 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_renderer_host.cc @@ -16,8 +16,7 @@ AudioRendererHost::AudioEntry::AudioEntry() - : render_view_id(0), - stream_id(0), + : stream_id(0), pending_buffer_request(false), pending_close(false) { } @@ -144,7 +143,7 @@ void AudioRendererHost::DoCompleteCreation( } Send(new AudioMsg_NotifyLowLatencyStreamCreated( - entry->render_view_id, entry->stream_id, foreign_memory_handle, + entry->stream_id, foreign_memory_handle, foreign_socket_handle, entry->shared_memory.created_size())); return; } @@ -152,7 +151,7 @@ void AudioRendererHost::DoCompleteCreation( // The normal audio stream has created, send a message to the renderer // process. Send(new AudioMsg_NotifyStreamCreated( - entry->render_view_id, entry->stream_id, foreign_memory_handle, + entry->stream_id, foreign_memory_handle, entry->shared_memory.created_size())); } @@ -165,7 +164,7 @@ void AudioRendererHost::DoSendPlayingMessage( return; Send(new AudioMsg_NotifyStreamStateChanged( - entry->render_view_id, entry->stream_id, kAudioStreamPlaying)); + entry->stream_id, kAudioStreamPlaying)); } void AudioRendererHost::DoSendPausedMessage( @@ -177,7 +176,7 @@ void AudioRendererHost::DoSendPausedMessage( return; Send(new AudioMsg_NotifyStreamStateChanged( - entry->render_view_id, entry->stream_id, kAudioStreamPaused)); + entry->stream_id, kAudioStreamPaused)); } void AudioRendererHost::DoRequestMoreData( @@ -193,7 +192,7 @@ void AudioRendererHost::DoRequestMoreData( DCHECK(!entry->controller->LowLatencyMode()); entry->pending_buffer_request = true; Send(new AudioMsg_RequestPacket( - entry->render_view_id, entry->stream_id, buffers_state)); + entry->stream_id, buffers_state)); } void AudioRendererHost::DoHandleError(media::AudioOutputController* controller, @@ -228,10 +227,9 @@ bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, } void AudioRendererHost::OnCreateStream( - const IPC::Message& msg, int stream_id, - const AudioParameters& params, bool low_latency) { + int stream_id, const AudioParameters& params, bool low_latency) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - DCHECK(LookupById(msg.routing_id(), stream_id) == NULL); + DCHECK(LookupById(stream_id) == NULL); AudioParameters audio_params(params); @@ -245,7 +243,7 @@ void AudioRendererHost::OnCreateStream( // Create the shared memory and share with the renderer process. if (!entry->shared_memory.CreateAndMapAnonymous(packet_size)) { // If creation of shared memory failed then send an error message. - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -256,7 +254,7 @@ void AudioRendererHost::OnCreateStream( // Then try to initialize the sync reader. if (!reader->Init()) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -274,83 +272,78 @@ void AudioRendererHost::OnCreateStream( } if (!entry->controller) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } // If we have created the controller successfully create a entry and add it // to the map. - entry->render_view_id = msg.routing_id(); entry->stream_id = stream_id; - - audio_entries_.insert(std::make_pair( - AudioEntryId(msg.routing_id(), stream_id), - entry.release())); + audio_entries_.insert(std::make_pair(stream_id, entry.release())); resource_context_->media_observer()->OnSetAudioStreamStatus( - this, msg.routing_id(), stream_id, "created"); + this, stream_id, "created"); } -void AudioRendererHost::OnPlayStream(const IPC::Message& msg, int stream_id) { +void AudioRendererHost::OnPlayStream(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } entry->controller->Play(); resource_context_->media_observer()->OnSetAudioStreamPlaying( - this, msg.routing_id(), stream_id, true); + this, stream_id, true); } -void AudioRendererHost::OnPauseStream(const IPC::Message& msg, int stream_id) { +void AudioRendererHost::OnPauseStream(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } entry->controller->Pause(); resource_context_->media_observer()->OnSetAudioStreamPlaying( - this, msg.routing_id(), stream_id, false); + this, stream_id, false); } -void AudioRendererHost::OnFlushStream(const IPC::Message& msg, int stream_id) { +void AudioRendererHost::OnFlushStream(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } entry->controller->Flush(); resource_context_->media_observer()->OnSetAudioStreamStatus( - this, msg.routing_id(), stream_id, "flushed"); + this, stream_id, "flushed"); } -void AudioRendererHost::OnCloseStream(const IPC::Message& msg, int stream_id) { +void AudioRendererHost::OnCloseStream(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); resource_context_->media_observer()->OnSetAudioStreamStatus( - this, msg.routing_id(), stream_id, "closed"); + this, stream_id, "closed"); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (entry) CloseAndDeleteStream(entry); } -void AudioRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id, - double volume) { +void AudioRendererHost::OnSetVolume(int stream_id, double volume) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -359,21 +352,20 @@ void AudioRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id, return; entry->controller->SetVolume(volume); resource_context_->media_observer()->OnSetAudioStreamVolume( - this, msg.routing_id(), stream_id, volume); + this, stream_id, volume); } -void AudioRendererHost::OnGetVolume(const IPC::Message& msg, int stream_id) { +void AudioRendererHost::OnGetVolume(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); NOTREACHED() << "This message shouldn't be received"; } -void AudioRendererHost::OnNotifyPacketReady( - const IPC::Message& msg, int stream_id, uint32 packet_size) { +void AudioRendererHost::OnNotifyPacketReady(int stream_id, uint32 packet_size) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntry* entry = LookupById(msg.routing_id(), stream_id); + AudioEntry* entry = LookupById(stream_id); if (!entry) { - SendErrorMessage(msg.routing_id(), stream_id); + SendErrorMessage(stream_id); return; } @@ -391,10 +383,8 @@ void AudioRendererHost::OnNotifyPacketReady( packet_size); } -void AudioRendererHost::SendErrorMessage(int32 render_view_id, - int32 stream_id) { - Send(new AudioMsg_NotifyStreamStateChanged( - render_view_id, stream_id, kAudioStreamError)); +void AudioRendererHost::SendErrorMessage(int32 stream_id) { + Send(new AudioMsg_NotifyStreamStateChanged(stream_id, kAudioStreamError)); } void AudioRendererHost::DeleteEntries() { @@ -427,13 +417,12 @@ void AudioRendererHost::DeleteEntry(AudioEntry* entry) { // Delete the entry when this method goes out of scope. scoped_ptr entry_deleter(entry); - // Erase the entry from the map. - audio_entries_.erase( - AudioEntryId(entry->render_view_id, entry->stream_id)); + // Erase the entry identified by |stream_id| from the map. + audio_entries_.erase(entry->stream_id); // Notify the media observer. resource_context_->media_observer()->OnDeleteAudioStream( - this, entry->render_view_id, entry->stream_id); + this, entry->stream_id); } void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { @@ -441,19 +430,17 @@ void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { // Sends the error message first before we close the stream because // |entry| is destroyed in DeleteEntry(). - SendErrorMessage(entry->render_view_id, entry->stream_id); + SendErrorMessage(entry->stream_id); resource_context_->media_observer()->OnSetAudioStreamStatus( - this, entry->render_view_id, entry->stream_id, "error"); + this, entry->stream_id, "error"); CloseAndDeleteStream(entry); } -AudioRendererHost::AudioEntry* AudioRendererHost::LookupById( - int route_id, int stream_id) { +AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - AudioEntryMap::iterator i = audio_entries_.find( - AudioEntryId(route_id, stream_id)); + AudioEntryMap::iterator i = audio_entries_.find(stream_id); if (i != audio_entries_.end() && !i->second->pending_close) return i->second; return NULL; diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h index 4ac9109..8837d5a 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.h +++ b/content/browser/renderer_host/media/audio_renderer_host.h @@ -76,8 +76,6 @@ class ResourceContext; class AudioRendererHost : public BrowserMessageFilter, public media::AudioOutputController::EventHandler { public: - typedef std::pair AudioEntryId; - struct AudioEntry { AudioEntry(); ~AudioEntry(); @@ -85,10 +83,7 @@ class AudioRendererHost : public BrowserMessageFilter, // The AudioOutputController that manages the audio stream. scoped_refptr controller; - // Render view ID that requested the audio stream. - int32 render_view_id; - - // The audio stream ID in the render view. + // The audio stream ID. int stream_id; // Shared memory for transmission of the audio data. @@ -104,7 +99,7 @@ class AudioRendererHost : public BrowserMessageFilter, bool pending_close; }; - typedef std::map AudioEntryMap; + typedef std::map AudioEntryMap; // Called from UI thread from the owner of this object. AudioRendererHost(const content::ResourceContext* resource_context); @@ -115,7 +110,6 @@ class AudioRendererHost : public BrowserMessageFilter, virtual bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok); - ///////////////////////////////////////////////////////////////////////////// // AudioOutputController::EventHandler implementations. virtual void OnCreated(media::AudioOutputController* controller); virtual void OnPlaying(media::AudioOutputController* controller); @@ -135,41 +129,36 @@ class AudioRendererHost : public BrowserMessageFilter, virtual ~AudioRendererHost(); - //////////////////////////////////////////////////////////////////////////// - // Methods called on IO thread. - // Returns true if the message is an audio related message and should be - // handled by this class. - bool IsAudioRendererHostMessage(const IPC::Message& message); + // Methods called on IO thread ---------------------------------------------- // Audio related IPC message handlers. // Creates an audio output stream with the specified format. If this call is // successful this object would keep an internal entry of the stream for the // required properties. - void OnCreateStream(const IPC::Message& msg, int stream_id, + void OnCreateStream(int stream_id, const AudioParameters& params, bool low_latency); // Play the audio stream referenced by |stream_id|. - void OnPlayStream(const IPC::Message& msg, int stream_id); + void OnPlayStream(int stream_id); // Pause the audio stream referenced by |stream_id|. - void OnPauseStream(const IPC::Message& msg, int stream_id); + void OnPauseStream(int stream_id); // Discard all audio data in stream referenced by |stream_id|. - void OnFlushStream(const IPC::Message& msg, int stream_id); + void OnFlushStream(int stream_id); // Close the audio stream referenced by |stream_id|. - void OnCloseStream(const IPC::Message& msg, int stream_id); + void OnCloseStream(int stream_id); // Set the volume of the audio stream referenced by |stream_id|. - void OnSetVolume(const IPC::Message& msg, int stream_id, double volume); + void OnSetVolume(int stream_id, double volume); // Get the volume of the audio stream referenced by |stream_id|. - void OnGetVolume(const IPC::Message& msg, int stream_id); + void OnGetVolume(int stream_id); // Notify packet has been prepared for the audio stream. - void OnNotifyPacketReady(const IPC::Message& msg, int stream_id, - uint32 packet_size); + void OnNotifyPacketReady(int stream_id, uint32 packet_size); // Complete the process of creating an audio stream. This will set up the // shared memory or shared socket in low latency mode. @@ -188,7 +177,7 @@ class AudioRendererHost : public BrowserMessageFilter, void DoHandleError(media::AudioOutputController* controller, int error_code); // Send an error message to the renderer. - void SendErrorMessage(int32 render_view_id, int32 stream_id); + void SendErrorMessage(int stream_id); // Delete all audio entry and all audio streams void DeleteEntries(); @@ -207,17 +196,18 @@ class AudioRendererHost : public BrowserMessageFilter, // and error message is send to the renderer. void DeleteEntryOnError(AudioEntry* entry); - // A helper method to look up a AudioEntry with a tuple of render view - // id and stream id. Returns NULL if not found. - AudioEntry* LookupById(int render_view_id, 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); // Search for a AudioEntry having the reference to |controller|. // This method is used to look up an AudioEntry after a controller // event is received. AudioEntry* LookupByController(media::AudioOutputController* controller); - // A map of id to audio sources. + // A map of stream IDs to audio sources. AudioEntryMap audio_entries_; + const content::ResourceContext* resource_context_; DISALLOW_COPY_AND_ASSIGN(AudioRendererHost); diff --git a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc index 9813c0f..8a182e5 100644 --- a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc +++ b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc @@ -27,8 +27,6 @@ using ::testing::Return; using ::testing::SaveArg; using ::testing::SetArgumentPointee; -static const int kInvalidId = -1; -static const int kRouteId = 200; static const int kStreamId = 50; static bool IsRunningHeadless() { @@ -49,18 +47,16 @@ class MockAudioRendererHost : public AudioRendererHost { } // A list of mock methods. - MOCK_METHOD3(OnRequestPacket, - void(int routing_id, int stream_id, - AudioBuffersState buffers_state)); - MOCK_METHOD3(OnStreamCreated, - void(int routing_id, int stream_id, int length)); - MOCK_METHOD3(OnLowLatencyStreamCreated, - void(int routing_id, int stream_id, int length)); - MOCK_METHOD2(OnStreamPlaying, void(int routing_id, int stream_id)); - MOCK_METHOD2(OnStreamPaused, void(int routing_id, int stream_id)); - MOCK_METHOD2(OnStreamError, void(int routing_id, int stream_id)); - MOCK_METHOD3(OnStreamVolume, - void(int routing_id, int stream_id, double volume)); + MOCK_METHOD2(OnRequestPacket, + void(int stream_id, AudioBuffersState buffers_state)); + MOCK_METHOD2(OnStreamCreated, + void(int stream_id, int length)); + MOCK_METHOD2(OnLowLatencyStreamCreated, + void(int stream_id, int length)); + MOCK_METHOD1(OnStreamPlaying, void(int stream_id)); + MOCK_METHOD1(OnStreamPaused, void(int stream_id)); + MOCK_METHOD1(OnStreamError, void(int stream_id)); + MOCK_METHOD2(OnStreamVolume, void(int stream_id, double volume)); base::SharedMemory* shared_memory() { return shared_memory_.get(); } uint32 shared_memory_length() { return shared_memory_length_; } @@ -96,7 +92,7 @@ class MockAudioRendererHost : public AudioRendererHost { // These handler methods do minimal things and delegate to the mock methods. void OnRequestPacket(const IPC::Message& msg, int stream_id, AudioBuffersState buffers_state) { - OnRequestPacket(msg.routing_id(), stream_id, buffers_state); + OnRequestPacket(stream_id, buffers_state); } void OnStreamCreated(const IPC::Message& msg, int stream_id, @@ -108,7 +104,7 @@ class MockAudioRendererHost : public AudioRendererHost { shared_memory_length_ = length; // And then delegate the call to the mock method. - OnStreamCreated(msg.routing_id(), stream_id, length); + OnStreamCreated(stream_id, length); } void OnLowLatencyStreamCreated(const IPC::Message& msg, int stream_id, @@ -135,24 +131,24 @@ class MockAudioRendererHost : public AudioRendererHost { sync_socket_.reset(new base::SyncSocket(sync_socket_handle)); // And then delegate the call to the mock method. - OnLowLatencyStreamCreated(msg.routing_id(), stream_id, length); + OnLowLatencyStreamCreated(stream_id, length); } void OnStreamStateChanged(const IPC::Message& msg, int stream_id, AudioStreamState state) { if (state == kAudioStreamPlaying) { - OnStreamPlaying(msg.routing_id(), stream_id); + OnStreamPlaying(stream_id); } else if (state == kAudioStreamPaused) { - OnStreamPaused(msg.routing_id(), stream_id); + OnStreamPaused(stream_id); } else if (state == kAudioStreamError) { - OnStreamError(msg.routing_id(), stream_id); + OnStreamError(stream_id); } else { FAIL() << "Unknown stream state"; } } void OnStreamVolume(const IPC::Message& msg, int stream_id, double volume) { - OnStreamVolume(msg.routing_id(), stream_id, volume); + OnStreamVolume(stream_id, volume); } scoped_ptr shared_memory_; @@ -208,21 +204,17 @@ class AudioRendererHostTest : public testing::Test { void Create() { EXPECT_CALL(*observer_, - OnSetAudioStreamStatus(_, kRouteId, kStreamId, "created")); - EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kRouteId, kStreamId)); + OnSetAudioStreamStatus(_, kStreamId, "created")); + EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kStreamId)); InSequence s; // 1. We will first receive a OnStreamCreated() signal. - EXPECT_CALL(*host_, - OnStreamCreated(kRouteId, kStreamId, _)); + EXPECT_CALL(*host_, OnStreamCreated(kStreamId, _)); // 2. First packet request will arrive. - EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _)) + EXPECT_CALL(*host_, OnRequestPacket(kStreamId, _)) .WillOnce(QuitMessageLoop(message_loop_.get())); - IPC::Message msg; - msg.set_routing_id(kRouteId); - AudioParameters params; if (mock_stream_) params.format = AudioParameters::AUDIO_MOCK; @@ -235,24 +227,21 @@ class AudioRendererHostTest : public testing::Test { // Send a create stream message to the audio output stream and wait until // we receive the created message. - host_->OnCreateStream(msg, kStreamId, params, false); + host_->OnCreateStream(kStreamId, params, false); message_loop_->Run(); } void CreateLowLatency() { EXPECT_CALL(*observer_, - OnSetAudioStreamStatus(_, kRouteId, kStreamId, "created")); - EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kRouteId, kStreamId)); + OnSetAudioStreamStatus(_, kStreamId, "created")); + EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kStreamId)); InSequence s; // We will first receive a OnLowLatencyStreamCreated() signal. EXPECT_CALL(*host_, - OnLowLatencyStreamCreated(kRouteId, kStreamId, _)) + OnLowLatencyStreamCreated(kStreamId, _)) .WillOnce(QuitMessageLoop(message_loop_.get())); - IPC::Message msg; - msg.set_routing_id(kRouteId); - AudioParameters params; if (mock_stream_) params.format = AudioParameters::AUDIO_MOCK; @@ -265,70 +254,60 @@ class AudioRendererHostTest : public testing::Test { // Send a create stream message to the audio output stream and wait until // we receive the created message. - host_->OnCreateStream(msg, kStreamId, params, true); + host_->OnCreateStream(kStreamId, params, true); message_loop_->Run(); } void Close() { EXPECT_CALL(*observer_, - OnSetAudioStreamStatus(_, kRouteId, kStreamId, "closed")); + OnSetAudioStreamStatus(_, kStreamId, "closed")); // Send a message to AudioRendererHost to tell it we want to close the // stream. - IPC::Message msg; - msg.set_routing_id(kRouteId); - host_->OnCloseStream(msg, kStreamId); + host_->OnCloseStream(kStreamId); message_loop_->RunAllPending(); } void Play() { EXPECT_CALL(*observer_, - OnSetAudioStreamPlaying(_, kRouteId, kStreamId, true)); - EXPECT_CALL(*host_, OnStreamPlaying(kRouteId, kStreamId)) + OnSetAudioStreamPlaying(_, kStreamId, true)); + EXPECT_CALL(*host_, OnStreamPlaying(kStreamId)) .WillOnce(QuitMessageLoop(message_loop_.get())); - IPC::Message msg; - msg.set_routing_id(kRouteId); - host_->OnPlayStream(msg, kStreamId); + host_->OnPlayStream(kStreamId); message_loop_->Run(); } void Pause() { EXPECT_CALL(*observer_, - OnSetAudioStreamPlaying(_, kRouteId, kStreamId, false)); - EXPECT_CALL(*host_, OnStreamPaused(kRouteId, kStreamId)) + OnSetAudioStreamPlaying(_, kStreamId, false)); + EXPECT_CALL(*host_, OnStreamPaused(kStreamId)) .WillOnce(QuitMessageLoop(message_loop_.get())); - IPC::Message msg; - msg.set_routing_id(kRouteId); - host_->OnPauseStream(msg, kStreamId); + host_->OnPauseStream(kStreamId); message_loop_->Run(); } void SetVolume(double volume) { EXPECT_CALL(*observer_, - OnSetAudioStreamVolume(_, kRouteId, kStreamId, volume)); - IPC::Message msg; - msg.set_routing_id(kRouteId); - host_->OnSetVolume(msg, kStreamId, volume); + OnSetAudioStreamVolume(_, kStreamId, volume)); + + host_->OnSetVolume(kStreamId, volume); message_loop_->RunAllPending(); } void NotifyPacketReady() { - EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _)) + EXPECT_CALL(*host_, OnRequestPacket(kStreamId, _)) .WillOnce(QuitMessageLoop(message_loop_.get())); - IPC::Message msg; - msg.set_routing_id(kRouteId); memset(host_->shared_memory()->memory(), 0, host_->shared_memory_length()); - host_->OnNotifyPacketReady(msg, kStreamId, - host_->shared_memory_length()); + host_->OnNotifyPacketReady(kStreamId, host_->shared_memory_length()); message_loop_->Run(); } void SimulateError() { EXPECT_CALL(*observer_, - OnSetAudioStreamStatus(_, kRouteId, kStreamId, "error")); + OnSetAudioStreamStatus(_, kStreamId, "error")); // Find the first AudioOutputController in the AudioRendererHost. CHECK(host_->audio_entries_.size()) << "Calls Create() before calling this method"; @@ -337,7 +316,7 @@ class AudioRendererHostTest : public testing::Test { CHECK(controller) << "AudioOutputController not found"; // Expect an error signal sent through IPC. - EXPECT_CALL(*host_, OnStreamError(kRouteId, kStreamId)); + EXPECT_CALL(*host_, OnStreamError(kStreamId)); // Simulate an error sent from the audio device. host_->OnError(controller, 0); diff --git a/content/browser/renderer_host/media/media_observer.h b/content/browser/renderer_host/media/media_observer.h index 9f8a0ca..50e42e0 100644 --- a/content/browser/renderer_host/media/media_observer.h +++ b/content/browser/renderer_host/media/media_observer.h @@ -13,22 +13,20 @@ class MediaObserver { virtual ~MediaObserver() {} // Called when an audio stream is deleted. - virtual void OnDeleteAudioStream(void* host, int32 render_view, - int stream_id) = 0; + virtual void OnDeleteAudioStream(void* host, int stream_id) = 0; // Called when an audio stream is set to playing or paused. - virtual void OnSetAudioStreamPlaying(void* host, int32 render_view, - int stream_id, bool playing) = 0; + virtual void OnSetAudioStreamPlaying(void* host, int stream_id, + bool playing) = 0; // Called when the status of an audio stream is set to "created", "flushed", // "closed", or "error". - virtual void OnSetAudioStreamStatus(void* host, int32 render_view, - int stream_id, + virtual void OnSetAudioStreamStatus(void* host, int stream_id, const std::string& status) = 0; // Called when the volume of an audio stream is set. - virtual void OnSetAudioStreamVolume(void* host, int32 render_view, - int stream_id, double volume) = 0; + virtual void OnSetAudioStreamVolume(void* host, int stream_id, + double volume) = 0; }; #endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_OBSERVER_H_ diff --git a/content/browser/renderer_host/media/mock_media_observer.h b/content/browser/renderer_host/media/mock_media_observer.h index 4e374fc..3260265 100644 --- a/content/browser/renderer_host/media/mock_media_observer.h +++ b/content/browser/renderer_host/media/mock_media_observer.h @@ -17,17 +17,14 @@ class MockMediaObserver : public MediaObserver { MockMediaObserver(); virtual ~MockMediaObserver(); - MOCK_METHOD3(OnDeleteAudioStream, - void(void* host, int32 render_view, int stream_id)); - MOCK_METHOD4(OnSetAudioStreamPlaying, - void(void* host, int32 render_view, int stream_id, - bool playing)); - MOCK_METHOD4(OnSetAudioStreamStatus, - void(void* host, int32 render_view, int stream_id, - const std::string& status)); - MOCK_METHOD4(OnSetAudioStreamVolume, - void(void* host, int32 render_view, int stream_id, - double volume)); + MOCK_METHOD2(OnDeleteAudioStream, + void(void* host, int stream_id)); + MOCK_METHOD3(OnSetAudioStreamPlaying, + void(void* host, int stream_id, bool playing)); + MOCK_METHOD3(OnSetAudioStreamStatus, + void(void* host, int stream_id, const std::string& status)); + MOCK_METHOD3(OnSetAudioStreamVolume, + void(void* host, int stream_id, double volume)); }; #endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MOCK_MEDIA_OBSERVER_H_ diff --git a/content/common/media/audio_messages.h b/content/common/media/audio_messages.h index 41da486..7a7fde4 100644 --- a/content/common/media/audio_messages.h +++ b/content/common/media/audio_messages.h @@ -36,129 +36,126 @@ IPC_STRUCT_TRAITS_END() // Messages sent from the browser to the renderer. // Sent by AudioRendererHost to renderer to request an audio packet. -IPC_MESSAGE_ROUTED2(AudioMsg_RequestPacket, - int /* stream id */, - AudioBuffersState) +IPC_MESSAGE_CONTROL2(AudioMsg_RequestPacket, + int /* stream id */, + AudioBuffersState) // Tell the renderer process that the audio stream has been created, renderer // process would be given a ShareMemoryHandle that it should write to from // then on. -IPC_MESSAGE_ROUTED3(AudioMsg_NotifyStreamCreated, - int /* stream id */, - base::SharedMemoryHandle /* handle */, - uint32 /* length */) +IPC_MESSAGE_CONTROL3(AudioMsg_NotifyStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + uint32 /* length */) // Tell the renderer process that a low latency audio stream has been created, // renderer process would be given a SyncSocket that it should write to from // then on. #if defined(OS_WIN) -IPC_MESSAGE_ROUTED4(AudioMsg_NotifyLowLatencyStreamCreated, - int /* stream id */, - base::SharedMemoryHandle /* handle */, - base::SyncSocket::Handle /* socket handle */, - uint32 /* length */) +IPC_MESSAGE_CONTROL4(AudioMsg_NotifyLowLatencyStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + base::SyncSocket::Handle /* socket handle */, + uint32 /* length */) #else -IPC_MESSAGE_ROUTED4(AudioMsg_NotifyLowLatencyStreamCreated, - int /* stream id */, - base::SharedMemoryHandle /* handle */, - base::FileDescriptor /* socket handle */, - uint32 /* length */) +IPC_MESSAGE_CONTROL4(AudioMsg_NotifyLowLatencyStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + base::FileDescriptor /* socket handle */, + uint32 /* length */) #endif // Tell the renderer process that a low latency audio input stream has been // created, renderer process would be given a SyncSocket that it should read // from from then on. #if defined(OS_WIN) -IPC_MESSAGE_ROUTED4(AudioInputMsg_NotifyLowLatencyStreamCreated, - int /* stream id */, - base::SharedMemoryHandle /* handle */, - base::SyncSocket::Handle /* socket handle */, - uint32 /* length */) +IPC_MESSAGE_CONTROL4(AudioInputMsg_NotifyLowLatencyStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + base::SyncSocket::Handle /* socket handle */, + uint32 /* length */) #else -IPC_MESSAGE_ROUTED4(AudioInputMsg_NotifyLowLatencyStreamCreated, - int /* stream id */, - base::SharedMemoryHandle /* handle */, - base::FileDescriptor /* socket handle */, - uint32 /* length */) +IPC_MESSAGE_CONTROL4(AudioInputMsg_NotifyLowLatencyStreamCreated, + int /* stream id */, + base::SharedMemoryHandle /* handle */, + base::FileDescriptor /* socket handle */, + uint32 /* length */) #endif // Notification message sent from AudioRendererHost to renderer for state // update after the renderer has requested a Create/Start/Close. -IPC_MESSAGE_ROUTED2(AudioMsg_NotifyStreamStateChanged, - int /* stream id */, - AudioStreamState /* new state */) +IPC_MESSAGE_CONTROL2(AudioMsg_NotifyStreamStateChanged, + int /* stream id */, + AudioStreamState /* new state */) -IPC_MESSAGE_ROUTED2(AudioMsg_NotifyStreamVolume, - int /* stream id */, - double /* volume */) +IPC_MESSAGE_CONTROL2(AudioMsg_NotifyStreamVolume, + int /* stream id */, + double /* volume */) -IPC_MESSAGE_ROUTED2(AudioInputMsg_NotifyStreamVolume, - int /* stream id */, - double /* volume */) +IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyStreamVolume, + int /* stream id */, + double /* volume */) // Messages sent from the renderer to the browser. // Request that got sent to browser for creating an audio output stream -IPC_MESSAGE_ROUTED3(AudioHostMsg_CreateStream, - int /* stream_id */, - AudioParameters /* params */, - bool /* low-latency */) +IPC_MESSAGE_CONTROL3(AudioHostMsg_CreateStream, + int /* stream_id */, + AudioParameters /* params */, + bool /* low-latency */) // Request that got sent to browser for creating an audio input stream -IPC_MESSAGE_ROUTED3(AudioInputHostMsg_CreateStream, - int /* stream_id */, - AudioParameters /* params */, - bool /* low-latency */) - -// Tell the browser the audio buffer prepared for stream -// (render_view_id, stream_id) is filled and is ready to be consumed. -IPC_MESSAGE_ROUTED2(AudioHostMsg_NotifyPacketReady, - int /* stream_id */, - uint32 /* packet size */) - -// Start buffering and play the audio stream specified by -// (render_view_id, stream_id). -IPC_MESSAGE_ROUTED1(AudioHostMsg_PlayStream, - int /* stream_id */) +IPC_MESSAGE_CONTROL3(AudioInputHostMsg_CreateStream, + int /* stream_id */, + AudioParameters /* params */, + bool /* low-latency */) -// Start recording the audio input stream specified by -// (render_view_id, stream_id). -IPC_MESSAGE_ROUTED1(AudioInputHostMsg_RecordStream, - int /* stream_id */) +// Tell the browser the audio buffer prepared for stream (stream_id) is +// filled and is ready to be consumed. +IPC_MESSAGE_CONTROL2(AudioHostMsg_NotifyPacketReady, + int /* stream_id */, + uint32 /* packet size */) + +// Start buffering and play the audio stream specified by stream_id. +IPC_MESSAGE_CONTROL1(AudioHostMsg_PlayStream, + int /* stream_id */) -// Pause the audio stream specified by (render_view_id, stream_id). -IPC_MESSAGE_ROUTED1(AudioHostMsg_PauseStream, - int /* stream_id */) +// Start recording the audio input stream specified by stream_id. +IPC_MESSAGE_CONTROL1(AudioInputHostMsg_RecordStream, + int /* stream_id */) + +// Pause the audio stream specified by stream_id. +IPC_MESSAGE_CONTROL1(AudioHostMsg_PauseStream, + int /* stream_id */) // Discard all buffered audio data for the specified audio stream. -IPC_MESSAGE_ROUTED1(AudioHostMsg_FlushStream, - int /* stream_id */) +IPC_MESSAGE_CONTROL1(AudioHostMsg_FlushStream, + int /* stream_id */) -// Close an audio stream specified by (render_view_id, stream_id). -IPC_MESSAGE_ROUTED1(AudioHostMsg_CloseStream, - int /* stream_id */) +// Close an audio stream specified by stream_id. +IPC_MESSAGE_CONTROL1(AudioHostMsg_CloseStream, + int /* stream_id */) -// Close an audio input stream specified by (render_view_id, stream_id). -IPC_MESSAGE_ROUTED1(AudioInputHostMsg_CloseStream, - int /* stream_id */) +// Close an audio input stream specified by stream_id. +IPC_MESSAGE_CONTROL1(AudioInputHostMsg_CloseStream, + int /* stream_id */) -// Get audio volume of the stream specified by (render_view_id, stream_id). -IPC_MESSAGE_ROUTED1(AudioHostMsg_GetVolume, - int /* stream_id */) +// Get audio volume of the stream specified by stream_id. +IPC_MESSAGE_CONTROL1(AudioHostMsg_GetVolume, + int /* stream_id */) // Get audio volume of the input stream specified by // (render_view_id, stream_id). -IPC_MESSAGE_ROUTED1(AudioInputHostMsg_GetVolume, - int /* stream_id */) +IPC_MESSAGE_CONTROL1(AudioInputHostMsg_GetVolume, + int /* stream_id */) -// Set audio volume of the stream specified by (render_view_id, stream_id). +// Set audio volume of the stream specified by stream_id. // TODO(hclam): change this to vector if we have channel numbers other than 2. -IPC_MESSAGE_ROUTED2(AudioHostMsg_SetVolume, - int /* stream_id */, - double /* volume */) - -// Set audio volume of the input stream specified by -// (render_view_id, stream_id). -IPC_MESSAGE_ROUTED2(AudioInputHostMsg_SetVolume, - int /* stream_id */, - double /* volume */) +IPC_MESSAGE_CONTROL2(AudioHostMsg_SetVolume, + int /* stream_id */, + double /* volume */) + +// Set audio volume of the input stream specified by stream_id. +IPC_MESSAGE_CONTROL2(AudioInputHostMsg_SetVolume, + int /* stream_id */, + double /* volume */) diff --git a/content/renderer/media/audio_device.cc b/content/renderer/media/audio_device.cc index 619c279..e00b370 100644 --- a/content/renderer/media/audio_device.cc +++ b/content/renderer/media/audio_device.cc @@ -4,7 +4,6 @@ #include "content/renderer/media/audio_device.h" -#include "base/memory/singleton.h" #include "base/message_loop.h" #include "content/common/child_process.h" #include "content/common/media/audio_messages.h" @@ -12,39 +11,6 @@ #include "content/renderer/render_thread.h" #include "media/audio/audio_util.h" -scoped_refptr AudioDevice::filter_; - -namespace { - -// AudioMessageFilterCreator is intended to be used as a singleton so we can -// get access to a shared AudioMessageFilter. -// Example usage: -// AudioMessageFilter* filter = AudioMessageFilterCreator::SharedFilter(); - -class AudioMessageFilterCreator { - public: - AudioMessageFilterCreator() { - int routing_id; - RenderThread::current()->Send( - new ViewHostMsg_GenerateRoutingID(&routing_id)); - filter_ = new AudioMessageFilter(routing_id); - RenderThread::current()->AddFilter(filter_); - } - - static AudioMessageFilter* SharedFilter() { - return GetInstance()->filter_.get(); - } - - static AudioMessageFilterCreator* GetInstance() { - return Singleton::get(); - } - - private: - scoped_refptr filter_; -}; - -} // namespace - AudioDevice::AudioDevice(size_t buffer_size, int channels, double sample_rate, @@ -57,13 +23,12 @@ AudioDevice::AudioDevice(size_t buffer_size, audio_delay_milliseconds_(0), volume_(1.0), stream_id_(0) { + filter_ = RenderThread::current()->audio_message_filter(); audio_data_.reserve(channels); for (int i = 0; i < channels; ++i) { float* channel_data = new float[buffer_size]; audio_data_.push_back(channel_data); } - // Lazily create the message filter and share across AudioDevice instances. - filter_ = AudioMessageFilterCreator::SharedFilter(); } AudioDevice::~AudioDevice() { @@ -87,16 +52,8 @@ bool AudioDevice::Start() { params.bits_per_sample = bits_per_sample_; params.samples_per_packet = buffer_size_; - // Ensure that the initialization task is posted on the I/O thread by - // accessing the I/O message loop directly. This approach avoids a race - // condition which could exist if the message loop of the filter was - // used instead. - DCHECK(ChildProcess::current()) << "Must be in the renderer"; - MessageLoop* message_loop = ChildProcess::current()->io_message_loop(); - if (!message_loop) - return false; - - message_loop->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioDevice::InitializeOnIOThread, params)); return true; @@ -106,7 +63,8 @@ bool AudioDevice::Stop() { if (!stream_id_) return false; - filter_->message_loop()->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioDevice::ShutDownOnIOThread)); if (audio_thread_.get()) { @@ -124,7 +82,8 @@ bool AudioDevice::SetVolume(double volume) { if (volume < 0 || volume > 1.0) return false; - filter_->message_loop()->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioDevice::SetVolumeOnIOThread, volume)); volume_ = volume; @@ -144,12 +103,12 @@ bool AudioDevice::GetVolume(double* volume) { void AudioDevice::InitializeOnIOThread(const AudioParameters& params) { stream_id_ = filter_->AddDelegate(this); - filter_->Send(new AudioHostMsg_CreateStream(0, stream_id_, params, true)); + Send(new AudioHostMsg_CreateStream(stream_id_, params, true)); } void AudioDevice::StartOnIOThread() { if (stream_id_) - filter_->Send(new AudioHostMsg_PlayStream(0, stream_id_)); + Send(new AudioHostMsg_PlayStream(stream_id_)); } void AudioDevice::ShutDownOnIOThread() { @@ -157,14 +116,14 @@ void AudioDevice::ShutDownOnIOThread() { if (!stream_id_) return; - filter_->Send(new AudioHostMsg_CloseStream(0, stream_id_)); filter_->RemoveDelegate(stream_id_); + Send(new AudioHostMsg_CloseStream(stream_id_)); stream_id_ = 0; } void AudioDevice::SetVolumeOnIOThread(double volume) { if (stream_id_) - filter_->Send(new AudioHostMsg_SetVolume(0, stream_id_, volume)); + Send(new AudioHostMsg_SetVolume(stream_id_, volume)); } void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) { @@ -189,6 +148,7 @@ void AudioDevice::OnLowLatencyCreated( base::SharedMemoryHandle handle, base::SyncSocket::Handle socket_handle, uint32 length) { + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); #if defined(OS_WIN) DCHECK(handle); DCHECK(socket_handle); @@ -198,8 +158,6 @@ void AudioDevice::OnLowLatencyCreated( #endif DCHECK(length); - // TODO(crogers) : check that length is big enough for buffer_size_ - shared_memory_.reset(new base::SharedMemory(handle, false)); shared_memory_->Map(length); @@ -211,19 +169,22 @@ void AudioDevice::OnLowLatencyCreated( new base::DelegateSimpleThread(this, "renderer_audio_thread")); audio_thread_->Start(); - if (filter_) { - filter_->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioDevice::StartOnIOThread)); - } + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioDevice::StartOnIOThread)); } void AudioDevice::OnVolume(double volume) { NOTIMPLEMENTED(); } +void AudioDevice::Send(IPC::Message* message) { + filter_->Send(message); +} + // Our audio thread runs here. void AudioDevice::Run() { - audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); + audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); int pending_data; const int samples_per_ms = static_cast(sample_rate_) / 1000; @@ -232,11 +193,9 @@ void AudioDevice::Run() { while (sizeof(pending_data) == socket_->Receive(&pending_data, sizeof(pending_data)) && pending_data >= 0) { - { - // Convert the number of pending bytes in the render buffer - // into milliseconds. - audio_delay_milliseconds_ = pending_data / bytes_per_ms; - } + // Convert the number of pending bytes in the render buffer + // into milliseconds. + audio_delay_milliseconds_ = pending_data / bytes_per_ms; FireRenderCallback(); } diff --git a/content/renderer/media/audio_device.h b/content/renderer/media/audio_device.h index 88c2a0c..b53f9bf 100644 --- a/content/renderer/media/audio_device.h +++ b/content/renderer/media/audio_device.h @@ -1,6 +1,47 @@ // Copyright (c) 2011 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. +// +// Low-latency audio rendering unit utilizing audio output stream provided +// by browser process through IPC. +// +// Relationship of classes. +// +// AudioOutputController AudioDevice +// ^ ^ +// | | +// v IPC v +// AudioRendererHost <---------> AudioMessageFilter +// +// Transportation of audio samples from the render to the browser process +// is done by using shared memory in combination with a sync socket pair +// to generate a low latency transport. The AudioDevice user registers an +// AudioDevice::RenderCallback at construction and will be polled by the +// AudioDevice for audio to be played out by the underlying audio layers. +// +// State sequences. +// +// Task [IO thread] IPC [IO thread] +// +// Start -> InitializeOnIOThread ------> AudioHostMsg_CreateStream --------> +// <- OnLowLatencyCreated <- AudioMsg_NotifyLowLatencyStreamCreated <- +// ---> StartOnIOThread -----------> AudioHostMsg_PlayStream --------> +// +// AudioDevice::Render => audio transport on audio thread with low latency => +// | +// Stop --> ShutDownOnIOThread --------> AudioHostMsg_CloseStream -> Close +// +// This class utilizes three threads during its lifetime, namely: +// 1. Creating thread. +// Must be the main render thread. Start and Stop should be called on +// this thread. +// 2. IO thread. +// The thread within which this class receives all the IPC messages and +// IPC communications can only happen in this thread. +// 3. Audio transport thread. +// Responsible for calling the RenderCallback and feed audio samples to +// the audio layer in the browser process using sync sockets and shared +// memory. #ifndef CONTENT_RENDERER_MEDIA_AUDIO_DEVICE_H_ #define CONTENT_RENDERER_MEDIA_AUDIO_DEVICE_H_ @@ -16,9 +57,6 @@ struct AudioParameters; -// Each instance of AudioDevice corresponds to one host stream. -// This class is not thread-safe, so its methods must be called from -// the same thread. class AudioDevice : public AudioMessageFilter::Delegate, public base::DelegateSimpleThread::Delegate, public base::RefCountedThreadSafe { @@ -32,7 +70,7 @@ class AudioDevice : public AudioMessageFilter::Delegate, virtual ~RenderCallback() {} }; - // |buffer_size| is the number of sample-frames. + // Methods called on main render thread ------------------------------------- AudioDevice(size_t buffer_size, int channels, double sample_rate, @@ -56,14 +94,8 @@ class AudioDevice : public AudioMessageFilter::Delegate, double sample_rate() const { return sample_rate_; } size_t buffer_size() const { return buffer_size_; } - private: - // I/O thread backends to above functions. - void InitializeOnIOThread(const AudioParameters& params); - void StartOnIOThread(); - void ShutDownOnIOThread(); - void SetVolumeOnIOThread(double volume); - - // AudioMessageFilter::Delegate implementation. + // Methods called on IO thread ---------------------------------------------- + // AudioMessageFilter::Delegate methods, called by AudioMessageFilter. virtual void OnRequestPacket(AudioBuffersState buffers_state); virtual void OnStateChanged(AudioStreamState state); virtual void OnCreated(base::SharedMemoryHandle handle, uint32 length); @@ -72,6 +104,23 @@ class AudioDevice : public AudioMessageFilter::Delegate, uint32 length); virtual void OnVolume(double volume); + private: + // Methods called on IO thread ---------------------------------------------- + // The following methods are tasks posted on the IO thread that needs to + // be executed on that thread. They interact with AudioMessageFilter and + // sends IPC messages on that thread. + void InitializeOnIOThread(const AudioParameters& params); + void StartOnIOThread(); + void ShutDownOnIOThread(); + void SetVolumeOnIOThread(double volume); + + void Send(IPC::Message* message); + + // Method called on the audio thread (+ one call on the IO thread) ---------- + // Calls the client's callback for rendering audio. There will also be one + // initial call on the IO thread before the audio thread has been created. + void FireRenderCallback(); + // DelegateSimpleThread::Delegate implementation. virtual void Run(); @@ -81,8 +130,6 @@ class AudioDevice : public AudioMessageFilter::Delegate, int bits_per_sample_; double sample_rate_; - // Calls the client's callback for rendering audio. - void FireRenderCallback(); RenderCallback* callback_; // The client callback renders audio into here. @@ -104,18 +151,18 @@ class AudioDevice : public AudioMessageFilter::Delegate, base::SyncSocket* socket() { return socket_.get(); } void* shared_memory_data() { return shared_memory()->memory(); } - // MessageFilter used to send/receive IPC. THIS MUST ONLY BE ACCESSED ON THE - // I/O thread except to send messages and get the message loop. - static scoped_refptr filter_; + // Cached audio message filter (lives on the main render thread). + scoped_refptr filter_; - // Our ID on the message filter. THIS MUST ONLY BE ACCESSED ON THE I/O THREAD - // or else you could race with the initialize function which sets it. + // Our stream ID on the message filter. Only modified on the IO thread. int32 stream_id_; + // Data transfer between browser and render process uses a combination + // of sync sockets and shared memory to provide lowest possible latency. scoped_ptr shared_memory_; scoped_ptr socket_; - DISALLOW_COPY_AND_ASSIGN(AudioDevice); + DISALLOW_IMPLICIT_CONSTRUCTORS(AudioDevice); }; #endif // CONTENT_RENDERER_MEDIA_AUDIO_DEVICE_H_ diff --git a/content/renderer/media/audio_input_device.cc b/content/renderer/media/audio_input_device.cc index 5a821b0..5bfecea 100644 --- a/content/renderer/media/audio_input_device.cc +++ b/content/renderer/media/audio_input_device.cc @@ -4,7 +4,6 @@ #include "content/renderer/media/audio_input_device.h" -#include "base/memory/singleton.h" #include "base/message_loop.h" #include "content/common/child_process.h" #include "content/common/media/audio_messages.h" @@ -12,40 +11,6 @@ #include "content/renderer/render_thread.h" #include "media/audio/audio_util.h" -scoped_refptr AudioInputDevice::filter_; - -namespace { - -// AudioMessageFilterCreator is intended to be used as a singleton so we can -// get access to a shared AudioInputMessageFilter. -// Example usage: -// AudioInputMessageFilter* filter = -// AudioInputMessageFilterCreator::SharedFilter(); - -class AudioInputMessageFilterCreator { - public: - AudioInputMessageFilterCreator() { - int routing_id; - RenderThread::current()->Send( - new ViewHostMsg_GenerateRoutingID(&routing_id)); - filter_ = new AudioInputMessageFilter(routing_id); - RenderThread::current()->AddFilter(filter_); - } - - static AudioInputMessageFilter* SharedFilter() { - return GetInstance()->filter_.get(); - } - - static AudioInputMessageFilterCreator* GetInstance() { - return Singleton::get(); - } - - private: - scoped_refptr filter_; -}; - -} // namespace - AudioInputDevice::AudioInputDevice(size_t buffer_size, int channels, double sample_rate, @@ -58,14 +23,12 @@ AudioInputDevice::AudioInputDevice(size_t buffer_size, audio_delay_milliseconds_(0), volume_(1.0), stream_id_(0) { + filter_ = RenderThread::current()->audio_input_message_filter(); audio_data_.reserve(channels); for (int i = 0; i < channels; ++i) { float* channel_data = new float[buffer_size]; audio_data_.push_back(channel_data); } - // Lazily create the message filter and share across AudioInputDevice - // instances. - filter_ = AudioInputMessageFilterCreator::SharedFilter(); } AudioInputDevice::~AudioInputDevice() { @@ -90,17 +53,9 @@ bool AudioInputDevice::Start() { params.bits_per_sample = bits_per_sample_; params.samples_per_packet = buffer_size_; - // Ensure that the initialization task is posted on the I/O thread by - // accessing the I/O message loop directly. This approach avoids a race - // condition which could exist if the message loop of the filter was - // used instead. - DCHECK(ChildProcess::current()) << "Must be in the renderer"; - MessageLoop* message_loop = ChildProcess::current()->io_message_loop(); - if (!message_loop) - return false; - - message_loop->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread, params)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread, params)); return true; } @@ -109,7 +64,8 @@ bool AudioInputDevice::Stop() { if (!stream_id_) return false; - filter_->message_loop()->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioInputDevice::ShutDownOnIOThread)); if (audio_thread_.get()) { @@ -132,13 +88,12 @@ bool AudioInputDevice::GetVolume(double* volume) { void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) { stream_id_ = filter_->AddDelegate(this); - filter_->Send( - new AudioInputHostMsg_CreateStream(0, stream_id_, params, true)); + Send(new AudioInputHostMsg_CreateStream(stream_id_, params, true)); } void AudioInputDevice::StartOnIOThread() { if (stream_id_) - filter_->Send(new AudioInputHostMsg_RecordStream(0, stream_id_)); + Send(new AudioInputHostMsg_RecordStream(stream_id_)); } void AudioInputDevice::ShutDownOnIOThread() { @@ -146,20 +101,21 @@ void AudioInputDevice::ShutDownOnIOThread() { if (!stream_id_) return; - filter_->Send(new AudioInputHostMsg_CloseStream(0, stream_id_)); filter_->RemoveDelegate(stream_id_); + Send(new AudioInputHostMsg_CloseStream(stream_id_)); stream_id_ = 0; } void AudioInputDevice::SetVolumeOnIOThread(double volume) { if (stream_id_) - filter_->Send(new AudioInputHostMsg_SetVolume(0, stream_id_, volume)); + Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); } void AudioInputDevice::OnLowLatencyCreated( base::SharedMemoryHandle handle, base::SyncSocket::Handle socket_handle, uint32 length) { + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); #if defined(OS_WIN) DCHECK(handle); DCHECK(socket_handle); @@ -169,31 +125,33 @@ void AudioInputDevice::OnLowLatencyCreated( #endif DCHECK(length); - // TODO(henrika) : check that length is big enough for buffer_size_ - shared_memory_.reset(new base::SharedMemory(handle, false)); shared_memory_->Map(length); socket_.reset(new base::SyncSocket(socket_handle)); - // TODO(henrika): we could optionally set the thread to high-priority audio_thread_.reset( new base::DelegateSimpleThread(this, "renderer_audio_input_thread")); audio_thread_->Start(); - if (filter_) { - filter_->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioInputDevice::StartOnIOThread)); - } + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioInputDevice::StartOnIOThread)); } void AudioInputDevice::OnVolume(double volume) { NOTIMPLEMENTED(); } +void AudioInputDevice::Send(IPC::Message* message) { + filter_->Send(message); +} + // Our audio thread runs here. We receive captured audio samples on // this thread. void AudioInputDevice::Run() { + audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); + int pending_data; const int samples_per_ms = static_cast(sample_rate_) / 1000; const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms; diff --git a/content/renderer/media/audio_input_device.h b/content/renderer/media/audio_input_device.h index 7c0c37c..4099452 100644 --- a/content/renderer/media/audio_input_device.h +++ b/content/renderer/media/audio_input_device.h @@ -2,6 +2,47 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Low-latency audio capturing unit utilizing audio input stream provided +// by browser process through IPC. +// +// Relationship of classes. +// +// AudioInputController AudioInputDevice +// ^ ^ +// | | +// v IPC v +// AudioInputRendererHost <---------> AudioInputMessageFilter +// +// Transportation of audio samples from the browser to the render process +// is done by using shared memory in combination with a sync socket pair +// to generate a low latency transport. The AudioInputDevice user registers +// an AudioInputDevice::CaptureCallback at construction and will be called +// by the AudioInputDevice with recorded audio from the underlying audio layers. +// +// State sequences. +// +// Task [IO thread] IPC [IO thread] +// +// Start -> InitializeOnIOThread -----> AudioInputHostMsg_CreateStream -------> +// <- OnLowLatencyCreated <- AudioInputMsg_NotifyLowLatencyStreamCreated <- +// ---> StartOnIOThread ---------> AudioInputHostMsg_PlayStream --------> +// +// AudioInputDevice::Capture => low latency audio transport on audio thread => +// | +// Stop --> ShutDownOnIOThread ------> AudioInputHostMsg_CloseStream -> Close +// +// This class utilizes three threads during its lifetime, namely: +// 1. Creating thread. +// Must be the main render thread. Start and Stop should be called on +// this thread. +// 2. IO thread. +// The thread within which this class receives all the IPC messages and +// IPC communications can only happen in this thread. +// 3. Audio transport thread. +// Responsible for calling the CaptrureCallback and feed audio samples from +// the audio layer in the browser process using sync sockets and shared +// memory. + #ifndef CONTENT_RENDERER_MEDIA_AUDIO_INPUT_DEVICE_H_ #define CONTENT_RENDERER_MEDIA_AUDIO_INPUT_DEVICE_H_ #pragma once @@ -16,10 +57,6 @@ struct AudioParameters; -// Each instance of AudioInputDevice corresponds to one host stream. -// This class is not thread-safe, so its methods must be called from -// the same thread. - // TODO(henrika): This class is based on the AudioDevice class and it has // many components in common. Investigate potential for re-factoring. class AudioInputDevice : public AudioInputMessageFilter::Delegate, @@ -35,7 +72,7 @@ class AudioInputDevice : public AudioInputMessageFilter::Delegate, virtual ~CaptureCallback() {} }; - // |buffer_size| is the number of sample-frames. + // Methods called on main render thread ------------------------------------- AudioInputDevice(size_t buffer_size, int channels, double sample_rate, @@ -57,21 +94,30 @@ class AudioInputDevice : public AudioInputMessageFilter::Delegate, bool GetVolume(double* volume); double sample_rate() const { return sample_rate_; } - size_t buffer_size() const { return buffer_size_; } + // Methods called on IO thread ---------------------------------------------- + // AudioInputMessageFilter::Delegate impl., called by AudioInputMessageFilter + virtual void OnLowLatencyCreated(base::SharedMemoryHandle handle, + base::SyncSocket::Handle socket_handle, + uint32 length); + virtual void OnVolume(double volume); + private: - // I/O thread backends to above functions. + // Methods called on IO thread ---------------------------------------------- + // The following methods are tasks posted on the IO thread that needs to + // be executed on that thread. They interact with AudioInputMessageFilter and + // sends IPC messages on that thread. void InitializeOnIOThread(const AudioParameters& params); void StartOnIOThread(); void ShutDownOnIOThread(); void SetVolumeOnIOThread(double volume); - // AudioInputMessageFilter::Delegate implementation - virtual void OnLowLatencyCreated(base::SharedMemoryHandle handle, - base::SyncSocket::Handle socket_handle, - uint32 length); - virtual void OnVolume(double volume); + void Send(IPC::Message* message); + + // Method called on the audio thread ---------------------------------------- + // Calls the client's callback for capturing audio. + void FireCaptureCallback(); // DelegateSimpleThread::Delegate implementation. virtual void Run(); @@ -82,8 +128,6 @@ class AudioInputDevice : public AudioInputMessageFilter::Delegate, int bits_per_sample_; double sample_rate_; - // Calls the client's callback for capturing audio. - void FireCaptureCallback(); CaptureCallback* callback_; // The client callback receives captured audio here. @@ -105,12 +149,10 @@ class AudioInputDevice : public AudioInputMessageFilter::Delegate, base::SyncSocket* socket() { return socket_.get(); } void* shared_memory_data() { return shared_memory()->memory(); } - // MessageFilter used to send/receive IPC. THIS MUST ONLY BE ACCESSED ON THE - // I/O thread except to send messages and get the message loop. - static scoped_refptr filter_; + // Cached audio input message filter (lives on the main render thread). + scoped_refptr filter_; - // Our ID on the message filter. THIS MUST ONLY BE ACCESSED ON THE I/O THREAD - // or else you could race with the initialize function which sets it. + // Our stream ID on the message filter. Only modified on the IO thread. int32 stream_id_; scoped_ptr shared_memory_; diff --git a/content/renderer/media/audio_input_message_filter.cc b/content/renderer/media/audio_input_message_filter.cc index 0d556ef..a439fe7 100644 --- a/content/renderer/media/audio_input_message_filter.cc +++ b/content/renderer/media/audio_input_message_filter.cc @@ -6,43 +6,38 @@ #include "base/message_loop.h" #include "base/time.h" +#include "content/common/child_process.h" #include "content/common/media/audio_messages.h" #include "ipc/ipc_logging.h" -AudioInputMessageFilter::AudioInputMessageFilter(int32 route_id) - : channel_(NULL), - route_id_(route_id), - message_loop_(NULL) { - VLOG(1) << "AudioInputMessageFilter(route_id=" << route_id << ")"; +AudioInputMessageFilter::AudioInputMessageFilter() + : channel_(NULL) { + VLOG(1) << "AudioInputMessageFilter()"; } -AudioInputMessageFilter::~AudioInputMessageFilter() {} +AudioInputMessageFilter::~AudioInputMessageFilter() { + VLOG(1) << "AudioInputMessageFilter::~AudioInputMessageFilter()"; +} -// Called on the IPC thread. bool AudioInputMessageFilter::Send(IPC::Message* message) { if (!channel_) { delete message; return false; } - if (MessageLoop::current() != message_loop_) { + if (MessageLoop::current() != ChildProcess::current()->io_message_loop()) { // Can only access the IPC::Channel on the IPC thread since it's not thread // safe. - message_loop_->PostTask( - FROM_HERE, NewRunnableMethod(this, - &AudioInputMessageFilter::Send, - message)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioInputMessageFilter::Send, message)); return true; } - message->set_routing_id(route_id_); return channel_->Send(message); } bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) { - if (message.routing_id() != route_id_) - return false; - bool handled = true; IPC_BEGIN_MESSAGE_MAP(AudioInputMessageFilter, message) IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyLowLatencyStreamCreated, @@ -55,8 +50,7 @@ bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) { void AudioInputMessageFilter::OnFilterAdded(IPC::Channel* channel) { VLOG(1) << "AudioInputMessageFilter::OnFilterAdded()"; - // Captures the message loop for IPC. - message_loop_ = MessageLoop::current(); + // Captures the channel for IPC. channel_ = channel; } diff --git a/content/renderer/media/audio_input_message_filter.h b/content/renderer/media/audio_input_message_filter.h index 3721e83..1ea0283 100644 --- a/content/renderer/media/audio_input_message_filter.h +++ b/content/renderer/media/audio_input_message_filter.h @@ -4,7 +4,7 @@ // // MessageFilter that handles audio input messages and delegates them to // audio capturers. Created on render thread, AudioMessageFilter is operated on -// IO thread (main thread of render process), it intercepts audio messages +// IO thread (secondary thread of render process), it intercepts audio messages // and process them on IO thread since these messages are time critical. // This implementation only supports low-latency (based on SyncSocket) // messaging. @@ -39,7 +39,7 @@ class AudioInputMessageFilter : public IPC::ChannelProxy::MessageFilter { virtual ~Delegate() {} }; - explicit AudioInputMessageFilter(int32 route_id); + AudioInputMessageFilter(); virtual ~AudioInputMessageFilter(); // Add a delegate to the map and return id of the entry. @@ -51,11 +51,7 @@ class AudioInputMessageFilter : public IPC::ChannelProxy::MessageFilter { // Sends an IPC message using |channel_|. bool Send(IPC::Message* message); - MessageLoop* message_loop() { return message_loop_; } - private: - // TODO(henrika): add unit tests (compare with AudioMessageFilter) - // IPC::ChannelProxy::MessageFilter override. Called on IO thread. virtual bool OnMessageReceived(const IPC::Message& message); virtual void OnFilterAdded(IPC::Channel* channel); @@ -80,11 +76,7 @@ class AudioInputMessageFilter : public IPC::ChannelProxy::MessageFilter { IPC::Channel* channel_; - int32 route_id_; - - MessageLoop* message_loop_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(AudioInputMessageFilter); + DISALLOW_COPY_AND_ASSIGN(AudioInputMessageFilter); }; #endif // CONTENT_RENDERER_MEDIA_AUDIO_INPUT_MESSAGE_FILTER_H_ diff --git a/content/renderer/media/audio_message_filter.cc b/content/renderer/media/audio_message_filter.cc index d286b47..bb32c22 100644 --- a/content/renderer/media/audio_message_filter.cc +++ b/content/renderer/media/audio_message_filter.cc @@ -6,41 +6,38 @@ #include "base/message_loop.h" #include "base/time.h" +#include "content/common/child_process.h" #include "content/common/media/audio_messages.h" #include "ipc/ipc_logging.h" -AudioMessageFilter::AudioMessageFilter(int32 route_id) - : channel_(NULL), - route_id_(route_id), - message_loop_(NULL) { +AudioMessageFilter::AudioMessageFilter() + : channel_(NULL) { + VLOG(1) << "AudioMessageFilter::AudioMessageFilter()"; } AudioMessageFilter::~AudioMessageFilter() { + VLOG(1) << "AudioMessageFilter::~AudioMessageFilter()"; } -// Called on the IPC thread. bool AudioMessageFilter::Send(IPC::Message* message) { if (!channel_) { delete message; return false; } - if (MessageLoop::current() != message_loop_) { + if (MessageLoop::current() != ChildProcess::current()->io_message_loop()) { // Can only access the IPC::Channel on the IPC thread since it's not thread // safe. - message_loop_->PostTask( - FROM_HERE, NewRunnableMethod(this, &AudioMessageFilter::Send, message)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioMessageFilter::Send, message)); return true; } - message->set_routing_id(route_id_); return channel_->Send(message); } bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) { - if (message.routing_id() != route_id_) - return false; - bool handled = true; IPC_BEGIN_MESSAGE_MAP(AudioMessageFilter, message) IPC_MESSAGE_HANDLER(AudioMsg_RequestPacket, OnRequestPacket) @@ -55,8 +52,8 @@ bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) { } void AudioMessageFilter::OnFilterAdded(IPC::Channel* channel) { - // Captures the message loop for IPC. - message_loop_ = MessageLoop::current(); + VLOG(1) << "AudioMessageFilter::OnFilterAdded()"; + // Captures the channel for IPC. channel_ = channel; } @@ -68,8 +65,7 @@ void AudioMessageFilter::OnChannelClosing() { channel_ = NULL; } -void AudioMessageFilter::OnRequestPacket(const IPC::Message& msg, - int stream_id, +void AudioMessageFilter::OnRequestPacket(int stream_id, AudioBuffersState buffers_state) { Delegate* delegate = delegates_.Lookup(stream_id); if (!delegate) { diff --git a/content/renderer/media/audio_message_filter.h b/content/renderer/media/audio_message_filter.h index 415e981..68b8460 100644 --- a/content/renderer/media/audio_message_filter.h +++ b/content/renderer/media/audio_message_filter.h @@ -4,7 +4,7 @@ // // MessageFilter that handles audio messages and delegates them to audio // renderers. Created on render thread, AudioMessageFilter is operated on -// IO thread (main thread of render process), it intercepts audio messages +// IO thread (secondary thread of render process) it intercepts audio messages // and process them on IO thread since these messages are time critical. #ifndef CONTENT_RENDERER_MEDIA_AUDIO_MESSAGE_FILTER_H_ @@ -52,7 +52,7 @@ class AudioMessageFilter : public IPC::ChannelProxy::MessageFilter { virtual ~Delegate() {} }; - explicit AudioMessageFilter(int32 route_id); + AudioMessageFilter(); virtual ~AudioMessageFilter(); // Add a delegate to the map and return id of the entry. @@ -64,12 +64,7 @@ class AudioMessageFilter : public IPC::ChannelProxy::MessageFilter { // Sends an IPC message using |channel_|. bool Send(IPC::Message* message); - MessageLoop* message_loop() { return message_loop_; } - private: - // For access to |message_loop_|. - friend class AudioRendererImplTest; - FRIEND_TEST_ALL_PREFIXES(AudioMessageFilterTest, Basic); FRIEND_TEST_ALL_PREFIXES(AudioMessageFilterTest, Delegates); @@ -80,8 +75,7 @@ class AudioMessageFilter : public IPC::ChannelProxy::MessageFilter { virtual void OnChannelClosing(); // Received when browser process wants more audio packet. - void OnRequestPacket(const IPC::Message& msg, int stream_id, - AudioBuffersState buffers_state); + void OnRequestPacket(int stream_id, AudioBuffersState buffers_state); // Received when browser process has created an audio output stream. void OnStreamCreated(int stream_id, base::SharedMemoryHandle handle, @@ -110,10 +104,6 @@ class AudioMessageFilter : public IPC::ChannelProxy::MessageFilter { IPC::Channel* channel_; - int32 route_id_; - - MessageLoop* message_loop_; - DISALLOW_COPY_AND_ASSIGN(AudioMessageFilter); }; diff --git a/content/renderer/media/audio_message_filter_unittest.cc b/content/renderer/media/audio_message_filter_unittest.cc index 595e4ff..a8ec475 100644 --- a/content/renderer/media/audio_message_filter_unittest.cc +++ b/content/renderer/media/audio_message_filter_unittest.cc @@ -92,8 +92,7 @@ class MockAudioDelegate : public AudioMessageFilter::Delegate { TEST(AudioMessageFilterTest, Basic) { MessageLoop message_loop(MessageLoop::TYPE_IO); - const int kRouteId = 0; - scoped_refptr filter(new AudioMessageFilter(kRouteId)); + scoped_refptr filter(new AudioMessageFilter()); MockAudioDelegate delegate; int stream_id = filter->AddDelegate(&delegate); @@ -103,8 +102,7 @@ TEST(AudioMessageFilterTest, Basic) { AudioBuffersState buffers_state(kSizeInBuffer, 0); EXPECT_FALSE(delegate.request_packet_received()); - filter->OnMessageReceived(AudioMsg_RequestPacket( - kRouteId, stream_id, buffers_state)); + filter->OnMessageReceived(AudioMsg_RequestPacket(stream_id, buffers_state)); EXPECT_TRUE(delegate.request_packet_received()); EXPECT_EQ(kSizeInBuffer, delegate.buffers_state().pending_bytes); EXPECT_EQ(0, delegate.buffers_state().hardware_delay_bytes); @@ -114,8 +112,7 @@ TEST(AudioMessageFilterTest, Basic) { // AudioMsg_NotifyStreamStateChanged EXPECT_FALSE(delegate.state_changed_received()); filter->OnMessageReceived( - AudioMsg_NotifyStreamStateChanged(kRouteId, stream_id, - kAudioStreamPlaying)); + AudioMsg_NotifyStreamStateChanged(stream_id, kAudioStreamPlaying)); EXPECT_TRUE(delegate.state_changed_received()); EXPECT_TRUE(kAudioStreamPlaying == delegate.state()); delegate.Reset(); @@ -124,8 +121,7 @@ TEST(AudioMessageFilterTest, Basic) { const uint32 kLength = 1024; EXPECT_FALSE(delegate.created_received()); filter->OnMessageReceived( - AudioMsg_NotifyStreamCreated(kRouteId, - stream_id, + AudioMsg_NotifyStreamCreated(stream_id, base::SharedMemory::NULLHandle(), kLength)); EXPECT_TRUE(delegate.created_received()); @@ -137,7 +133,7 @@ TEST(AudioMessageFilterTest, Basic) { const double kVolume = 1.0; EXPECT_FALSE(delegate.volume_received()); filter->OnMessageReceived( - AudioMsg_NotifyStreamVolume(kRouteId, stream_id, kVolume)); + AudioMsg_NotifyStreamVolume(stream_id, kVolume)); EXPECT_TRUE(delegate.volume_received()); EXPECT_EQ(kVolume, delegate.volume()); delegate.Reset(); @@ -148,8 +144,7 @@ TEST(AudioMessageFilterTest, Basic) { TEST(AudioMessageFilterTest, Delegates) { MessageLoop message_loop(MessageLoop::TYPE_IO); - const int kRouteId = 0; - scoped_refptr filter(new AudioMessageFilter(kRouteId)); + scoped_refptr filter(new AudioMessageFilter()); MockAudioDelegate delegate1; MockAudioDelegate delegate2; @@ -161,7 +156,7 @@ TEST(AudioMessageFilterTest, Delegates) { EXPECT_FALSE(delegate1.request_packet_received()); EXPECT_FALSE(delegate2.request_packet_received()); filter->OnMessageReceived( - AudioMsg_RequestPacket(kRouteId, stream_id1, AudioBuffersState())); + AudioMsg_RequestPacket(stream_id1, AudioBuffersState())); EXPECT_TRUE(delegate1.request_packet_received()); EXPECT_FALSE(delegate2.request_packet_received()); delegate1.Reset(); @@ -169,28 +164,22 @@ TEST(AudioMessageFilterTest, Delegates) { EXPECT_FALSE(delegate1.request_packet_received()); EXPECT_FALSE(delegate2.request_packet_received()); filter->OnMessageReceived( - AudioMsg_RequestPacket(kRouteId, stream_id2, AudioBuffersState())); + AudioMsg_RequestPacket(stream_id2, AudioBuffersState())); EXPECT_FALSE(delegate1.request_packet_received()); EXPECT_TRUE(delegate2.request_packet_received()); delegate2.Reset(); - // Send a message of a different route id, a message is not received. - EXPECT_FALSE(delegate1.request_packet_received()); - filter->OnMessageReceived( - AudioMsg_RequestPacket(kRouteId + 1, stream_id1, AudioBuffersState())); - EXPECT_FALSE(delegate1.request_packet_received()); - // Remove the delegates. Make sure they won't get called. filter->RemoveDelegate(stream_id1); EXPECT_FALSE(delegate1.request_packet_received()); filter->OnMessageReceived( - AudioMsg_RequestPacket(kRouteId, stream_id1, AudioBuffersState())); + AudioMsg_RequestPacket(stream_id1, AudioBuffersState())); EXPECT_FALSE(delegate1.request_packet_received()); filter->RemoveDelegate(stream_id2); EXPECT_FALSE(delegate2.request_packet_received()); filter->OnMessageReceived( - AudioMsg_RequestPacket(kRouteId, stream_id2, AudioBuffersState())); + AudioMsg_RequestPacket(stream_id2, AudioBuffersState())); EXPECT_FALSE(delegate2.request_packet_received()); message_loop.RunAllPending(); diff --git a/content/renderer/media/audio_renderer_impl.cc b/content/renderer/media/audio_renderer_impl.cc index 1fbdc8f..480da56 100644 --- a/content/renderer/media/audio_renderer_impl.cc +++ b/content/renderer/media/audio_renderer_impl.cc @@ -6,6 +6,7 @@ #include +#include "content/common/child_process.h" #include "base/command_line.h" #include "content/common/content_switches.h" #include "content/common/media/audio_messages.h" @@ -20,19 +21,17 @@ AudioRendererImpl::LatencyType AudioRendererImpl::latency_type_ = AudioRendererImpl::kUninitializedLatency; -AudioRendererImpl::AudioRendererImpl(AudioMessageFilter* filter) +AudioRendererImpl::AudioRendererImpl() : AudioRendererBase(), bytes_per_second_(0), - filter_(filter), stream_id_(0), shared_memory_(NULL), shared_memory_size_(0), - io_loop_(filter->message_loop()), stopped_(false), pending_request_(false), prerolling_(false), preroll_bytes_(0) { - DCHECK(io_loop_); + filter_ = RenderThread::current()->audio_message_filter(); // Figure out if we are planning to use high or low latency code path. // We are initializing only one variable and double initialization is Ok, // so there would not be any issues caused by CPU memory model. @@ -69,7 +68,8 @@ bool AudioRendererImpl::OnInitialize(const media::AudioDecoderConfig& config) { bytes_per_second_ = params.GetBytesPerSecond(); - io_loop_->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioRendererImpl::CreateStreamTask, params)); return true; } @@ -80,9 +80,8 @@ void AudioRendererImpl::OnStop() { return; stopped_ = true; - // We should never touch |io_loop_| after being stopped, so post our final - // task to clean up. - io_loop_->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioRendererImpl::DestroyTask)); if (audio_thread_.get()) { @@ -94,7 +93,8 @@ void AudioRendererImpl::OnStop() { void AudioRendererImpl::NotifyDataAvailableIfNecessary() { if (latency_type_ == kHighLatency) { // Post a task to render thread to notify a packet reception. - io_loop_->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioRendererImpl::NotifyPacketReadyTask)); } } @@ -117,7 +117,7 @@ void AudioRendererImpl::SetPlaybackRate(float rate) { DCHECK_LE(0.0f, rate); base::AutoLock auto_lock(lock_); - // Handle the case where we stopped due to |io_loop_| dying. + // Handle the case where we stopped due to IO message loop dying. if (stopped_) { AudioRendererBase::SetPlaybackRate(rate); return; @@ -127,12 +127,14 @@ void AudioRendererImpl::SetPlaybackRate(float rate) { // Play: GetPlaybackRate() == 0.0 && rate != 0.0 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { - io_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { // Pause is easy, we can always pause. - io_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); } AudioRendererBase::SetPlaybackRate(rate); @@ -149,7 +151,8 @@ void AudioRendererImpl::Pause(media::FilterCallback* callback) { if (stopped_) return; - io_loop_->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); } @@ -160,7 +163,8 @@ void AudioRendererImpl::Seek(base::TimeDelta time, if (stopped_) return; - io_loop_->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &AudioRendererImpl::SeekTask)); } @@ -172,11 +176,13 @@ void AudioRendererImpl::Play(media::FilterCallback* callback) { return; if (GetPlaybackRate() != 0.0f) { - io_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); } else { - io_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); } } @@ -184,14 +190,14 @@ void AudioRendererImpl::SetVolume(float volume) { base::AutoLock auto_lock(lock_); if (stopped_) return; - io_loop_->PostTask(FROM_HERE, - NewRunnableMethod( - this, &AudioRendererImpl::SetVolumeTask, volume)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::SetVolumeTask, volume)); } void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle, uint32 length) { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); DCHECK_EQ(kHighLatency, latency_type_); base::AutoLock auto_lock(lock_); @@ -224,7 +230,7 @@ void AudioRendererImpl::OnLowLatencyCreated( base::SharedMemoryHandle handle, base::SyncSocket::Handle socket_handle, uint32 length) { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); DCHECK_EQ(kLowLatency, latency_type_); #if defined(OS_WIN) DCHECK(handle); @@ -246,7 +252,7 @@ void AudioRendererImpl::OnLowLatencyCreated( } void AudioRendererImpl::OnRequestPacket(AudioBuffersState buffers_state) { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); DCHECK_EQ(kHighLatency, latency_type_); { base::AutoLock auto_lock(lock_); @@ -260,7 +266,7 @@ void AudioRendererImpl::OnRequestPacket(AudioBuffersState buffers_state) { } void AudioRendererImpl::OnStateChanged(AudioStreamState state) { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); base::AutoLock auto_lock(lock_); if (stopped_) @@ -291,7 +297,7 @@ void AudioRendererImpl::OnVolume(double volume) { } void AudioRendererImpl::CreateStreamTask(const AudioParameters& audio_params) { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); base::AutoLock auto_lock(lock_); if (stopped_) @@ -300,60 +306,59 @@ void AudioRendererImpl::CreateStreamTask(const AudioParameters& audio_params) { // Make sure we don't call create more than once. DCHECK_EQ(0, stream_id_); stream_id_ = filter_->AddDelegate(this); - io_loop_->AddDestructionObserver(this); + ChildProcess::current()->io_message_loop()->AddDestructionObserver(this); AudioParameters params_to_send(audio_params); // Let the browser choose packet size. params_to_send.samples_per_packet = 0; - filter_->Send(new AudioHostMsg_CreateStream(0, - stream_id_, - params_to_send, - latency_type_ == kLowLatency)); + Send(new AudioHostMsg_CreateStream(stream_id_, + params_to_send, + latency_type_ == kLowLatency)); } void AudioRendererImpl::PlayTask() { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); - filter_->Send(new AudioHostMsg_PlayStream(0, stream_id_)); + Send(new AudioHostMsg_PlayStream(stream_id_)); } void AudioRendererImpl::PauseTask() { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); - filter_->Send(new AudioHostMsg_PauseStream(0, stream_id_)); + Send(new AudioHostMsg_PauseStream(stream_id_)); } void AudioRendererImpl::SeekTask() { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); // We have to pause the audio stream before we can flush. - filter_->Send(new AudioHostMsg_PauseStream(0, stream_id_)); - filter_->Send(new AudioHostMsg_FlushStream(0, stream_id_)); + Send(new AudioHostMsg_PauseStream(stream_id_)); + Send(new AudioHostMsg_FlushStream(stream_id_)); } void AudioRendererImpl::DestroyTask() { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); // Make sure we don't call destroy more than once. DCHECK_NE(0, stream_id_); filter_->RemoveDelegate(stream_id_); - filter_->Send(new AudioHostMsg_CloseStream(0, stream_id_)); - io_loop_->RemoveDestructionObserver(this); + Send(new AudioHostMsg_CloseStream(stream_id_)); + ChildProcess::current()->io_message_loop()->RemoveDestructionObserver(this); stream_id_ = 0; } void AudioRendererImpl::SetVolumeTask(double volume) { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); base::AutoLock auto_lock(lock_); if (stopped_) return; - filter_->Send(new AudioHostMsg_SetVolume(0, stream_id_, volume)); + Send(new AudioHostMsg_SetVolume(stream_id_, volume)); } void AudioRendererImpl::NotifyPacketReadyTask() { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); DCHECK_EQ(kHighLatency, latency_type_); base::AutoLock auto_lock(lock_); @@ -393,12 +398,12 @@ void AudioRendererImpl::NotifyPacketReadyTask() { request_buffers_state_.pending_bytes == 0); pending_request_ = false; // Then tell browser process we are done filling into the buffer. - filter_->Send(new AudioHostMsg_NotifyPacketReady(0, stream_id_, filled)); + Send(new AudioHostMsg_NotifyPacketReady(stream_id_, filled)); } } void AudioRendererImpl::WillDestroyCurrentMessageLoop() { - DCHECK(MessageLoop::current() == io_loop_); + DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); // We treat the IO loop going away the same as stopping. base::AutoLock auto_lock(lock_); @@ -416,7 +421,7 @@ void AudioRendererImpl::Run() { int bytes; while (sizeof(bytes) == socket_->Receive(&bytes, sizeof(bytes))) { -LOG(ERROR) << "+++ bytes: " << bytes; + LOG(ERROR) << "+++ bytes: " << bytes; if (bytes == media::AudioOutputController::kPauseMark) continue; else if (bytes < 0) @@ -441,3 +446,7 @@ LOG(ERROR) << "+++ bytes: " << bytes; true /* buffers empty */); } } + +void AudioRendererImpl::Send(IPC::Message* message) { + filter_->Send(message); +} diff --git a/content/renderer/media/audio_renderer_impl.h b/content/renderer/media/audio_renderer_impl.h index 275371c..5ba9bc5 100644 --- a/content/renderer/media/audio_renderer_impl.h +++ b/content/renderer/media/audio_renderer_impl.h @@ -58,7 +58,7 @@ class AudioRendererImpl : public media::AudioRendererBase, public MessageLoop::DestructionObserver { public: // Methods called on Render thread ------------------------------------------ - explicit AudioRendererImpl(AudioMessageFilter* filter); + explicit AudioRendererImpl(); virtual ~AudioRendererImpl(); // Methods called on IO thread ---------------------------------------------- @@ -101,6 +101,7 @@ class AudioRendererImpl : public media::AudioRendererBase, // For access to constructor and IO thread methods. friend class AudioRendererImplTest; + friend class DelegateCaller; FRIEND_TEST_ALL_PREFIXES(AudioRendererImplTest, Stop); FRIEND_TEST_ALL_PREFIXES(AudioRendererImplTest, DestroyedMessageLoop_ConsumeAudioSamples); @@ -144,11 +145,12 @@ class AudioRendererImpl : public media::AudioRendererBase, // Should be called before any class instance is created. static void set_latency_type(LatencyType latency_type); + // Helper method for IPC send calls. + void Send(IPC::Message* message); + // Used to calculate audio delay given bytes. uint32 bytes_per_second_; - scoped_refptr filter_; - // ID of the stream created in the browser process. int32 stream_id_; @@ -156,15 +158,15 @@ class AudioRendererImpl : public media::AudioRendererBase, scoped_ptr shared_memory_; uint32 shared_memory_size_; + // Cached audio message filter (lives on the main render thread). + scoped_refptr filter_; + // Low latency IPC stuff. scoped_ptr socket_; // That thread waits for audio input. scoped_ptr audio_thread_; - // Message loop for the IO thread. - MessageLoop* io_loop_; - // Protects: // - |stopped_| // - |pending_request_| diff --git a/content/renderer/media/audio_renderer_impl_unittest.cc b/content/renderer/media/audio_renderer_impl_unittest.cc index 15ca49a..478eb63 100644 --- a/content/renderer/media/audio_renderer_impl_unittest.cc +++ b/content/renderer/media/audio_renderer_impl_unittest.cc @@ -2,9 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop.h" #include "base/process_util.h" +#include "base/synchronization/waitable_event.h" +#include "base/test/test_timeouts.h" +#include "base/time.h" +#include "content/common/child_process.h" +#include "content/common/child_thread.h" #include "content/common/media/audio_messages.h" #include "content/renderer/media/audio_renderer_impl.h" +#include "content/renderer/mock_content_renderer_client.h" +#include "content/renderer/render_process.h" +#include "content/renderer/render_thread.h" +#include "ipc/ipc_channel.h" #include "media/base/data_buffer.h" #include "media/base/mock_callback.h" #include "media/base/mock_filter_host.h" @@ -13,35 +23,125 @@ using ::testing::Return; -// Class we would be tesing. The only difference between it and "real" one +namespace { +// This class is a mock of the child process singleton which is needed +// to be able to create a RenderThread object. +class MockRenderProcess : public RenderProcess { + public: + MockRenderProcess() {} + virtual ~MockRenderProcess() {} + + // RenderProcess implementation. + virtual skia::PlatformCanvas* GetDrawingCanvas(TransportDIB** memory, + const gfx::Rect& rect) { return NULL; } + virtual void ReleaseTransportDIB(TransportDIB* memory) {} + virtual bool UseInProcessPlugins() const { return false; } + virtual bool HasInitializedMediaLibrary() const { return false; } + + private: + DISALLOW_COPY_AND_ASSIGN(MockRenderProcess); +}; +} + +// This class defines a set of methods which will be used in combination +// with NewRunnableMethod to form tasks which will be posted on the +// IO thread. All methods emulate AudioMessageFilter::Delegate calls. +class DelegateCaller : public base::RefCountedThreadSafe { + public: + explicit DelegateCaller(AudioRendererImpl* renderer) + : renderer_(renderer) {} + + void OnCreated(base::SharedMemoryHandle handle, uint32 length) { + if (renderer_->latency_type() == AudioRendererImpl::kHighLatency) { + renderer_->OnCreated(handle, length); + } else { + renderer_->OnLowLatencyCreated(handle, 0, length); + } + } + void OnStateChanged(AudioStreamState state) { + renderer_->OnStateChanged(state); + } + void OnRequestPacket(AudioBuffersState buffers_state) { + renderer_->OnRequestPacket(buffers_state); + } + void OnVolume(double volume) { + renderer_->OnVolume(volume); + } + void DestroyCurrentMessageLoop() { + renderer_->WillDestroyCurrentMessageLoop(); + } + private: + friend class base::RefCountedThreadSafe; + virtual ~DelegateCaller() {} + + scoped_refptr renderer_; + DISALLOW_COPY_AND_ASSIGN(DelegateCaller); +}; + +// This task can be posted on the IO thread and will signal an event when +// done. The caller can then wait for this signal to ensure that no +// additional tasks remain in the task queue. +class WaitTask : public Task { + public: + explicit WaitTask(base::WaitableEvent* event) + : event_(event) {} + virtual ~WaitTask() {} + virtual void Run() { + event_->Signal(); + } + + private: + base::WaitableEvent* event_; + DISALLOW_COPY_AND_ASSIGN(WaitTask); +}; + +// Class we would be testing. The only difference between it and "real" one // is that test class does not open sockets and launch audio thread. class TestAudioRendererImpl : public AudioRendererImpl { public: - explicit TestAudioRendererImpl(AudioMessageFilter* filter) - : AudioRendererImpl(filter) { + explicit TestAudioRendererImpl() + : AudioRendererImpl() { } private: virtual void CreateSocket(base::SyncSocket::Handle socket_handle) {} virtual void CreateAudioThread() {} }; -class AudioRendererImplTest : public ::testing::Test { +class AudioRendererImplTest + : public ::testing::Test, + public IPC::Channel::Listener { public: - static const int kRouteId = 0; - static const int kSize = 1024; - static void SetUpTestCase() { // Set low latency mode, as it soon would be on by default. AudioRendererImpl::set_latency_type(AudioRendererImpl::kLowLatency); } - AudioRendererImplTest() { - message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); + // IPC::Channel::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& message) { + NOTIMPLEMENTED(); + return true; + } + + static const int kSize; + + AudioRendererImplTest() {} + virtual ~AudioRendererImplTest() {} + + virtual void SetUp() { + // This part sets up a RenderThread environment to ensure that + // RenderThread::current() (<=> TLS pointer) is valid. + // Main parts are inspired by the RenderViewFakeResourcesTest. + // Note that, the IPC part is not utilized in this test. + content::GetContentClient()->set_renderer(&mock_content_renderer_client_); - // TODO(scherkus): use gmock with AudioMessageFilter to verify - // AudioRendererImpl calls or doesn't call Send(). - filter_ = new AudioMessageFilter(kRouteId); - filter_->message_loop_ = message_loop_.get(); + static const char kThreadName[] = "RenderThread"; + channel_.reset(new IPC::Channel(kThreadName, + IPC::Channel::MODE_SERVER, this)); + ASSERT_TRUE(channel_->Connect()); + + mock_process_.reset(new MockRenderProcess); + render_thread_ = new RenderThread(kThreadName); + mock_process_->set_main_thread(render_thread_); // Create temporary shared memory. CHECK(shared_mem_.CreateAnonymous(kSize)); @@ -50,84 +150,128 @@ class AudioRendererImplTest : public ::testing::Test { decoder_ = new media::MockAudioDecoder(); ON_CALL(*decoder_, config()) - .WillByDefault(Return(media::AudioDecoderConfig(16, - CHANNEL_LAYOUT_MONO, - 44100))); + .WillByDefault(Return(media::AudioDecoderConfig(16, + CHANNEL_LAYOUT_MONO, + 44100))); - // Create and initialize audio renderer. - renderer_ = new TestAudioRendererImpl(filter_); + // Create and initialize the audio renderer. + renderer_ = new TestAudioRendererImpl(); renderer_->set_host(&host_); renderer_->Initialize(decoder_, media::NewExpectedCallback()); - // Run pending tasks and simulate responding with a created audio stream. - message_loop_->RunAllPending(); + // Wraps delegate calls into tasks. + delegate_caller_ = new DelegateCaller(renderer_); + + // We need an event to verify that all tasks are done before leaving + // our tests. + event_.reset(new base::WaitableEvent(false, false)); // Duplicate the shared memory handle so both the test and the callee can // close their copy. base::SharedMemoryHandle duplicated_handle; EXPECT_TRUE(shared_mem_.ShareToProcess(base::GetCurrentProcessHandle(), - &duplicated_handle)); - CallOnCreated(duplicated_handle); - } + &duplicated_handle)); - virtual ~AudioRendererImplTest() { + // Set things up and ensure that the call comes from the IO thread + // as all AudioMessageFilter::Delegate methods. + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::OnCreated, duplicated_handle, kSize)); + WaitForIOThreadCompletion(); } - void CallOnCreated(base::SharedMemoryHandle handle) { - if (renderer_->latency_type() == AudioRendererImpl::kHighLatency) { - renderer_->OnCreated(handle, kSize); - } else { - renderer_->OnLowLatencyCreated(handle, 0, kSize); - } + virtual void TearDown() { + mock_process_.reset(); } protected: - // Fixtures. - scoped_ptr message_loop_; - scoped_refptr filter_; + // Posts a final task to the IO message loop and waits for completion. + void WaitForIOThreadCompletion() { + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, new WaitTask(event_.get())); + EXPECT_TRUE(event_->TimedWait( + base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()))); + } + + MessageLoopForIO message_loop_; + content::MockContentRendererClient mock_content_renderer_client_; + scoped_ptr channel_; + RenderThread* render_thread_; // owned by mock_process_ + scoped_ptr mock_process_; base::SharedMemory shared_mem_; media::MockFilterHost host_; scoped_refptr decoder_; scoped_refptr renderer_; + scoped_ptr event_; + scoped_refptr delegate_caller_; private: DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest); }; -TEST_F(AudioRendererImplTest, SetPlaybackRate) { - // Execute SetPlaybackRate() codepath to create an IPC message. +const int AudioRendererImplTest::kSize = 1024; - // Toggle play/pause to generate some IPC messages. +TEST_F(AudioRendererImplTest, SetPlaybackRate) { + // Execute SetPlaybackRate() codepath by toggling play/pause. + // These methods will be called on the pipeline thread but calling from + // here is fine for this test. Tasks will be posted internally on + // the IO thread. renderer_->SetPlaybackRate(0.0f); renderer_->SetPlaybackRate(1.0f); renderer_->SetPlaybackRate(0.0f); renderer_->Stop(media::NewExpectedCallback()); - message_loop_->RunAllPending(); + WaitForIOThreadCompletion(); } TEST_F(AudioRendererImplTest, SetVolume) { - // Execute SetVolume() codepath to create an IPC message. + // Execute SetVolume() codepath. + // This method will be called on the pipeline thread IRL. + // Tasks will be posted internally on the IO thread. renderer_->SetVolume(0.5f); + renderer_->Stop(media::NewExpectedCallback()); - message_loop_->RunAllPending(); + WaitForIOThreadCompletion(); } TEST_F(AudioRendererImplTest, Stop) { - // Execute Stop() codepath to create an IPC message. + // Execute Stop() codepath. + // Tasks will be posted internally on the IO thread. renderer_->Stop(media::NewExpectedCallback()); - message_loop_->RunAllPending(); // Run AudioMessageFilter::Delegate methods, which can be executed after being - // stopped. AudioRendererImpl shouldn't create any messages. + // stopped. AudioRendererImpl shouldn't create any messages in this state. + // All delegate method calls are posted on the IO thread since it is + // a requirement. if (renderer_->latency_type() == AudioRendererImpl::kHighLatency) { - renderer_->OnRequestPacket(AudioBuffersState(kSize, 0)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::OnRequestPacket, AudioBuffersState(kSize, 0))); } - renderer_->OnStateChanged(kAudioStreamError); - renderer_->OnStateChanged(kAudioStreamPlaying); - renderer_->OnStateChanged(kAudioStreamPaused); - CallOnCreated(shared_mem_.handle()); - renderer_->OnVolume(0.5); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::OnStateChanged, kAudioStreamError)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::OnStateChanged, kAudioStreamPlaying)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::OnStateChanged, kAudioStreamPaused)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::OnCreated, shared_mem_.handle(), kSize)); + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::OnVolume, 0.5)); + + WaitForIOThreadCompletion(); // It's possible that the upstream decoder replies right after being stopped. scoped_refptr buffer(new media::DataBuffer(kSize)); @@ -135,8 +279,16 @@ TEST_F(AudioRendererImplTest, Stop) { } TEST_F(AudioRendererImplTest, DestroyedMessageLoop_SetPlaybackRate) { - // Kill the message loop and verify SetPlaybackRate() still works. - message_loop_.reset(); + // Emulate "killing the message loop" and verify that SetPlaybackRate() + // still works. + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::DestroyCurrentMessageLoop)); + WaitForIOThreadCompletion(); + + // No tasks will be posted on the IO thread here since we are in + // a "stopped" state. renderer_->SetPlaybackRate(0.0f); renderer_->SetPlaybackRate(1.0f); renderer_->SetPlaybackRate(0.0f); @@ -144,15 +296,31 @@ TEST_F(AudioRendererImplTest, DestroyedMessageLoop_SetPlaybackRate) { } TEST_F(AudioRendererImplTest, DestroyedMessageLoop_SetVolume) { - // Kill the message loop and verify SetVolume() still works. - message_loop_.reset(); + // Emulate "killing the message loop" and verify that SetVolume() + // still works. + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::DestroyCurrentMessageLoop)); + WaitForIOThreadCompletion(); + + // No tasks will be posted on the IO thread here since we are in + // a "stopped" state. renderer_->SetVolume(0.5f); renderer_->Stop(media::NewExpectedCallback()); } TEST_F(AudioRendererImplTest, DestroyedMessageLoop_ConsumeAudioSamples) { - // Kill the message loop and verify OnReadComplete() still works. - message_loop_.reset(); + // Emulate "killing the message loop" and verify that OnReadComplete() + // still works. + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(delegate_caller_.get(), + &DelegateCaller::DestroyCurrentMessageLoop)); + WaitForIOThreadCompletion(); + + // No tasks will be posted on the IO thread here since we are in + // a "stopped" state. scoped_refptr buffer(new media::DataBuffer(kSize)); renderer_->ConsumeAudioSamples(buffer); renderer_->Stop(media::NewExpectedCallback()); diff --git a/content/renderer/pepper_plugin_delegate_impl.cc b/content/renderer/pepper_plugin_delegate_impl.cc index 087e292..82968f6 100644 --- a/content/renderer/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper_plugin_delegate_impl.cc @@ -17,6 +17,7 @@ #include "base/task.h" #include "base/time.h" #include "content/common/child_process_messages.h" +#include "content/common/child_process.h" #include "content/common/child_thread.h" #include "content/common/content_switches.h" #include "content/common/file_system/file_system_dispatcher.h" @@ -159,10 +160,10 @@ class PlatformAudioImpl public AudioMessageFilter::Delegate, public base::RefCountedThreadSafe { public: - explicit PlatformAudioImpl(scoped_refptr filter) - : client_(NULL), filter_(filter), stream_id_(0), + PlatformAudioImpl() + : client_(NULL), stream_id_(0), main_message_loop_(MessageLoop::current()) { - DCHECK(filter_); + filter_ = RenderThread::current()->audio_message_filter(); } virtual ~PlatformAudioImpl() { @@ -239,7 +240,8 @@ bool PlatformAudioImpl::Initialize( params.bits_per_sample = 16; params.samples_per_packet = sample_count; - filter_->message_loop()->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &PlatformAudioImpl::InitializeOnIOThread, params)); return true; @@ -247,7 +249,8 @@ bool PlatformAudioImpl::Initialize( bool PlatformAudioImpl::StartPlayback() { if (filter_) { - filter_->message_loop()->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &PlatformAudioImpl::StartPlaybackOnIOThread)); return true; } @@ -256,7 +259,8 @@ bool PlatformAudioImpl::StartPlayback() { bool PlatformAudioImpl::StopPlayback() { if (filter_) { - filter_->message_loop()->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &PlatformAudioImpl::StopPlaybackOnIOThread)); return true; } @@ -267,23 +271,24 @@ void PlatformAudioImpl::ShutDown() { // Called on the main thread to stop all audio callbacks. We must only change // the client on the main thread, and the delegates from the I/O thread. client_ = NULL; - filter_->message_loop()->PostTask(FROM_HERE, + ChildProcess::current()->io_message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &PlatformAudioImpl::ShutDownOnIOThread)); } void PlatformAudioImpl::InitializeOnIOThread(const AudioParameters& params) { stream_id_ = filter_->AddDelegate(this); - filter_->Send(new AudioHostMsg_CreateStream(0, stream_id_, params, true)); + filter_->Send(new AudioHostMsg_CreateStream(stream_id_, params, true)); } void PlatformAudioImpl::StartPlaybackOnIOThread() { if (stream_id_) - filter_->Send(new AudioHostMsg_PlayStream(0, stream_id_)); + filter_->Send(new AudioHostMsg_PlayStream(stream_id_)); } void PlatformAudioImpl::StopPlaybackOnIOThread() { if (stream_id_) - filter_->Send(new AudioHostMsg_PauseStream(0, stream_id_)); + filter_->Send(new AudioHostMsg_PauseStream(stream_id_)); } void PlatformAudioImpl::ShutDownOnIOThread() { @@ -291,7 +296,7 @@ void PlatformAudioImpl::ShutDownOnIOThread() { if (!stream_id_) return; - filter_->Send(new AudioHostMsg_CloseStream(0, stream_id_)); + filter_->Send(new AudioHostMsg_CloseStream(stream_id_)); filter_->RemoveDelegate(stream_id_); stream_id_ = 0; @@ -851,8 +856,7 @@ webkit::ppapi::PluginDelegate::PlatformAudio* PepperPluginDelegateImpl::CreateAudio( uint32_t sample_rate, uint32_t sample_count, webkit::ppapi::PluginDelegate::PlatformAudio::Client* client) { - scoped_refptr audio( - new PlatformAudioImpl(render_view_->audio_message_filter())); + scoped_refptr audio(new PlatformAudioImpl()); if (audio->Initialize(sample_rate, sample_count, client)) { // Balanced by Release invoked in PlatformAudioImpl::ShutDownOnIOThread(). return audio.release(); @@ -991,9 +995,9 @@ bool PepperPluginDelegateImpl::ReadDirectory( return file_system_dispatcher->ReadDirectory(directory_path, dispatcher); } -class AsyncOpenFileSystemURLCallbackTranslator : - public fileapi::FileSystemCallbackDispatcher { -public: +class AsyncOpenFileSystemURLCallbackTranslator + : public fileapi::FileSystemCallbackDispatcher { + public: AsyncOpenFileSystemURLCallbackTranslator( webkit::ppapi::PluginDelegate::AsyncOpenFileCallback* callback) : callback_(callback) { diff --git a/content/renderer/render_thread.cc b/content/renderer/render_thread.cc index d9d9d1d..93d240b 100644 --- a/content/renderer/render_thread.cc +++ b/content/renderer/render_thread.cc @@ -37,6 +37,8 @@ #include "content/renderer/gpu/gpu_channel_host.h" #include "content/renderer/gpu/gpu_video_service_host.h" #include "content/renderer/indexed_db_dispatcher.h" +#include "content/renderer/media/audio_input_message_filter.h" +#include "content/renderer/media/audio_message_filter.h" #include "content/renderer/media/video_capture_impl_manager.h" #include "content/renderer/media/video_capture_message_filter.h" #include "content/renderer/plugin_channel_host.h" @@ -174,6 +176,12 @@ void RenderThread::Init() { vc_manager_ = new VideoCaptureImplManager(); AddFilter(vc_manager_->video_capture_message_filter()); + audio_input_message_filter_ = new AudioInputMessageFilter(); + AddFilter(audio_input_message_filter_.get()); + + audio_message_filter_ = new AudioMessageFilter(); + AddFilter(audio_message_filter_.get()); + content::GetContentClient()->renderer()->RenderThreadStarted(); TRACE_EVENT_END_ETW("RenderThread::Init", 0, ""); @@ -188,6 +196,12 @@ RenderThread::~RenderThread() { web_database_observer_impl_->WaitForAllDatabasesToClose(); // Shutdown in reverse of the initialization order. + RemoveFilter(audio_input_message_filter_.get()); + audio_input_message_filter_ = NULL; + + RemoveFilter(audio_message_filter_.get()); + audio_message_filter_ = NULL; + RemoveFilter(vc_manager_->video_capture_message_filter()); RemoveFilter(db_message_filter_.get()); @@ -594,7 +608,7 @@ void RenderThread::EnsureWebKitInitialized() { !command_line.HasSwitch(switches::kDisableGeolocation)); WebKit::WebRuntimeFeatures::enableMediaStream( - command_line.HasSwitch(switches::kEnableMediaStream)); + command_line.HasSwitch(switches::kEnableMediaStream)); #if defined(OS_CHROMEOS) // TODO(crogers): enable once Web Audio has been tested and optimized. diff --git a/content/renderer/render_thread.h b/content/renderer/render_thread.h index e73d1c1..97af783 100644 --- a/content/renderer/render_thread.h +++ b/content/renderer/render_thread.h @@ -22,6 +22,8 @@ #include "ui/gfx/native_widget_types.h" class AppCacheDispatcher; +class AudioInputMessageFilter; +class AudioMessageFilter; class DBMessageFilter; class FilePath; class GpuChannelHost; @@ -165,6 +167,14 @@ class RenderThread : public RenderThreadBase, return indexed_db_dispatcher_.get(); } + AudioInputMessageFilter* audio_input_message_filter() { + return audio_input_message_filter_.get(); + } + + AudioMessageFilter* audio_message_filter() { + return audio_message_filter_.get(); + } + VideoCaptureImplManager* video_capture_impl_manager() const { return vc_manager_.get(); } @@ -251,6 +261,8 @@ class RenderThread : public RenderThreadBase, // Used on the renderer and IPC threads. scoped_refptr db_message_filter_; + scoped_refptr audio_input_message_filter_; + scoped_refptr audio_message_filter_; // Used on multiple threads. scoped_refptr vc_manager_; diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc index 7082f29..aa2493a 100644 --- a/content/renderer/render_view.cc +++ b/content/renderer/render_view.cc @@ -402,9 +402,6 @@ RenderView::RenderView(RenderThreadBase* render_thread, if (command_line.HasSwitch(switches::kEnableAccessibility)) WebAccessibilityCache::enableAccessibility(); - audio_message_filter_ = new AudioMessageFilter(routing_id_); - render_thread_->AddFilter(audio_message_filter_); - #if defined(ENABLE_P2P_APIS) if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableP2PApi)) p2p_socket_dispatcher_ = new P2PSocketDispatcher(this); @@ -436,8 +433,6 @@ RenderView::~RenderView() { } #endif - render_thread_->RemoveFilter(audio_message_filter_); - #ifndef NDEBUG // Make sure we are no longer referenced by the ViewMap. ViewMap* views = g_view_map.Pointer(); @@ -1351,7 +1346,7 @@ void RenderView::didAddMessageToConsole( const WebConsoleMessage& message, const WebString& source_name, unsigned source_line) { logging::LogSeverity log_severity = logging::LOG_VERBOSE; - switch(message.level) { + switch (message.level) { case WebConsoleMessage::LevelTip: log_severity = logging::LOG_VERBOSE; break; @@ -1889,7 +1884,7 @@ WebMediaPlayer* RenderView::createMediaPlayer( const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); if (!cmd_line->HasSwitch(switches::kDisableAudio)) { // Add the chrome specific audio renderer. - collection->AddAudioRenderer(new AudioRendererImpl(audio_message_filter())); + collection->AddAudioRenderer(new AudioRendererImpl()); } scoped_refptr video_renderer; diff --git a/content/renderer/render_view.h b/content/renderer/render_view.h index 0ef0805..cfa86ff 100644 --- a/content/renderer/render_view.h +++ b/content/renderer/render_view.h @@ -209,10 +209,6 @@ class RenderView : public RenderWidget, int page_id() const { return page_id_; } PepperPluginDelegateImpl* pepper_delegate() { return &pepper_delegate_; } - AudioMessageFilter* audio_message_filter() { - return audio_message_filter_; - } - const WebPreferences& webkit_preferences() const { return webkit_preferences_; } @@ -1079,8 +1075,6 @@ class RenderView : public RenderWidget, // Device orientation dispatcher attached to this view; lazily initialized. DeviceOrientationDispatcher* device_orientation_dispatcher_; - scoped_refptr audio_message_filter_; - // Handles accessibility requests into the renderer side, as well as // maintains the cache and other features of the accessibility tree. scoped_ptr accessibility_; -- cgit v1.1