summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-12 10:19:51 +0000
committerhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-12 10:19:51 +0000
commitf7eb0a394522b0c3d6e9c16b54072e0bbafa0957 (patch)
tree922a5de3698273b57aad5d40206514b75466fb3c
parent8b241822a6eb2ee3ae99eeeac4dd11dda343c42e (diff)
downloadchromium_src-f7eb0a394522b0c3d6e9c16b54072e0bbafa0957.zip
chromium_src-f7eb0a394522b0c3d6e9c16b54072e0bbafa0957.tar.gz
chromium_src-f7eb0a394522b0c3d6e9c16b54072e0bbafa0957.tar.bz2
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
-rw-r--r--chrome/browser/media/media_internals.cc26
-rw-r--r--chrome/browser/media/media_internals.h17
-rw-r--r--content/browser/renderer_host/media/audio_input_renderer_host.cc64
-rw-r--r--content/browser/renderer_host/media/audio_input_renderer_host.h32
-rw-r--r--content/browser/renderer_host/media/audio_renderer_host.cc103
-rw-r--r--content/browser/renderer_host/media/audio_renderer_host.h44
-rw-r--r--content/browser/renderer_host/media/audio_renderer_host_unittest.cc103
-rw-r--r--content/browser/renderer_host/media/media_observer.h14
-rw-r--r--content/browser/renderer_host/media/mock_media_observer.h19
-rw-r--r--content/common/media/audio_messages.h167
-rw-r--r--content/renderer/media/audio_device.cc87
-rw-r--r--content/renderer/media/audio_device.h87
-rw-r--r--content/renderer/media/audio_input_device.cc82
-rw-r--r--content/renderer/media/audio_input_device.h80
-rw-r--r--content/renderer/media/audio_input_message_filter.cc30
-rw-r--r--content/renderer/media/audio_input_message_filter.h14
-rw-r--r--content/renderer/media/audio_message_filter.cc28
-rw-r--r--content/renderer/media/audio_message_filter.h16
-rw-r--r--content/renderer/media/audio_message_filter_unittest.cc31
-rw-r--r--content/renderer/media/audio_renderer_impl.cc107
-rw-r--r--content/renderer/media/audio_renderer_impl.h14
-rw-r--r--content/renderer/media/audio_renderer_impl_unittest.cc276
-rw-r--r--content/renderer/pepper_plugin_delegate_impl.cc36
-rw-r--r--content/renderer/render_thread.cc16
-rw-r--r--content/renderer/render_thread.h12
-rw-r--r--content/renderer/render_view.cc9
-rw-r--r--content/renderer/render_view.h6
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<MediaInternalsObserver>()) {}
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<AudioEntry> 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<int32, int> AudioEntryId;
-
struct AudioEntry {
AudioEntry();
~AudioEntry();
@@ -47,9 +45,6 @@ class AudioInputRendererHost : public BrowserMessageFilter,
// The AudioInputController that manages the audio input stream.
scoped_refptr<media::AudioInputController> 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<AudioEntryId, AudioEntry*> AudioEntryMap;
+ typedef std::map<int, AudioEntry*> 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<AudioEntry> 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<int32, int> AudioEntryId;
-
struct AudioEntry {
AudioEntry();
~AudioEntry();
@@ -85,10 +83,7 @@ class AudioRendererHost : public BrowserMessageFilter,
// The AudioOutputController that manages the audio stream.
scoped_refptr<media::AudioOutputController> 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<AudioEntryId, AudioEntry*> AudioEntryMap;
+ typedef std::map<int, AudioEntry*> 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<base::SharedMemory> 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<AudioMessageFilter> 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<AudioMessageFilterCreator>::get();
- }
-
- private:
- scoped_refptr<AudioMessageFilter> 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<int>(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<AudioDevice> {
@@ -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<AudioMessageFilter> filter_;
+ // Cached audio message filter (lives on the main render thread).
+ scoped_refptr<AudioMessageFilter> 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<base::SharedMemory> shared_memory_;
scoped_ptr<base::SyncSocket> 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<AudioInputMessageFilter> 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<AudioInputMessageFilterCreator>::get();
- }
-
- private:
- scoped_refptr<AudioInputMessageFilter> 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<int>(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<AudioInputMessageFilter> filter_;
+ // Cached audio input message filter (lives on the main render thread).
+ scoped_refptr<AudioInputMessageFilter> 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<base::SharedMemory> 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<AudioMessageFilter> filter(new AudioMessageFilter(kRouteId));
+ scoped_refptr<AudioMessageFilter> 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<AudioMessageFilter> filter(new AudioMessageFilter(kRouteId));
+ scoped_refptr<AudioMessageFilter> 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 <math.h>
+#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<AudioMessageFilter> filter_;
-
// ID of the stream created in the browser process.
int32 stream_id_;
@@ -156,15 +158,15 @@ class AudioRendererImpl : public media::AudioRendererBase,
scoped_ptr<base::SharedMemory> shared_memory_;
uint32 shared_memory_size_;
+ // Cached audio message filter (lives on the main render thread).
+ scoped_refptr<AudioMessageFilter> filter_;
+
// Low latency IPC stuff.
scoped_ptr<base::SyncSocket> socket_;
// That thread waits for audio input.
scoped_ptr<base::DelegateSimpleThread> 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<DelegateCaller> {
+ 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<DelegateCaller>;
+ virtual ~DelegateCaller() {}
+
+ scoped_refptr<AudioRendererImpl> 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<MessageLoop> message_loop_;
- scoped_refptr<AudioMessageFilter> 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<IPC::Channel> channel_;
+ RenderThread* render_thread_; // owned by mock_process_
+ scoped_ptr<MockRenderProcess> mock_process_;
base::SharedMemory shared_mem_;
media::MockFilterHost host_;
scoped_refptr<media::MockAudioDecoder> decoder_;
scoped_refptr<AudioRendererImpl> renderer_;
+ scoped_ptr<base::WaitableEvent> event_;
+ scoped_refptr<DelegateCaller> 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<media::Buffer> 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<media::Buffer> 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<PlatformAudioImpl> {
public:
- explicit PlatformAudioImpl(scoped_refptr<AudioMessageFilter> 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<PlatformAudioImpl> audio(
- new PlatformAudioImpl(render_view_->audio_message_filter()));
+ scoped_refptr<PlatformAudioImpl> 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<DBMessageFilter> db_message_filter_;
+ scoped_refptr<AudioInputMessageFilter> audio_input_message_filter_;
+ scoped_refptr<AudioMessageFilter> audio_message_filter_;
// Used on multiple threads.
scoped_refptr<VideoCaptureImplManager> 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<webkit_glue::WebVideoRenderer> 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<AudioMessageFilter> 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<WebKit::WebAccessibilityCache> accessibility_;