summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-27 23:51:16 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-27 23:51:16 +0000
commit2ee2329e9d55fdf601752a10abbe16581eefbe9d (patch)
treed22a9cde12c1ac9e331ea7e0d38f7ae13e6f63f3
parent96b74c572398e400c58cb6255d61394eacebf270 (diff)
downloadchromium_src-2ee2329e9d55fdf601752a10abbe16581eefbe9d.zip
chromium_src-2ee2329e9d55fdf601752a10abbe16581eefbe9d.tar.gz
chromium_src-2ee2329e9d55fdf601752a10abbe16581eefbe9d.tar.bz2
Implementation of AudioRendererHost
Completing the implementation of AudioRendererHost in chrome/browser/renderer_host/audio_renderer_host.cc with ResourceMessageFilter actually delegating calls to it when corresponding IPC messages are received. With this patch we should be able to send audio related IPC messages to browser with working audio, but we still need to complete the singleton paradigm for AudioManager to start using it in unit test and renderer. Review URL: http://codereview.chromium.org/21494 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10647 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.cc262
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.h158
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc34
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h3
-rwxr-xr-xchrome/common/render_messages.h8
-rw-r--r--chrome/common/render_messages_internal.h5
-rw-r--r--chrome/renderer/render_view.cc4
-rw-r--r--chrome/renderer/render_view.h2
8 files changed, 300 insertions, 176 deletions
diff --git a/chrome/browser/renderer_host/audio_renderer_host.cc b/chrome/browser/renderer_host/audio_renderer_host.cc
index f8851d4..58f2f40 100644
--- a/chrome/browser/renderer_host/audio_renderer_host.cc
+++ b/chrome/browser/renderer_host/audio_renderer_host.cc
@@ -4,26 +4,30 @@
#include "base/message_loop.h"
#include "base/process.h"
+#include "base/shared_memory.h"
+#include "base/waitable_event.h"
#include "chrome/browser/renderer_host/audio_renderer_host.h"
+#include "chrome/common/render_messages.h"
+
+//-----------------------------------------------------------------------------
+// AudioRendererHost::IPCAudioSource implementations.
AudioRendererHost::IPCAudioSource::IPCAudioSource(
AudioRendererHost* host,
int32 render_view_id,
int32 stream_id,
AudioOutputStream* stream,
- IPC::Message::Sender* sender,
- base::ProcessHandle process,
size_t packet_size)
: host_(host),
render_view_id_(render_view_id),
stream_id_(stream_id),
stream_(stream),
- sender_(sender) {
+ closed_(false),
+ packet_read_event_(false, false),
+ last_packet_size_(0) {
// Make sure we can create and map the shared memory.
DCHECK(shared_memory_.Create(L"", false, false, packet_size) &&
shared_memory_.Map(packet_size));
- // Also make sure we can create the buffer and share to render process.
- DCHECK(shared_memory_.ShareToProcess(process, &foreign_memory_handle_));
}
AudioRendererHost::IPCAudioSource::~IPCAudioSource() {
@@ -32,42 +36,51 @@ AudioRendererHost::IPCAudioSource::~IPCAudioSource() {
size_t AudioRendererHost::IPCAudioSource::OnMoreData(AudioOutputStream* stream,
void* dest,
size_t max_size) {
- // TODO(hclam): send an IPC message to renderer provided with a
- // SharedMemoryHandle for audio renderer inside render process to fill in.
- // We should sleep until we receive a notification from render process that
- // the buffer is ready or this source is closed or an error is encountered.
- // Stuff do there here:
- // 1. Prepare the SharedMemory.
- // 2. Send an IPC.
- // 3. Wait until we receive notification.
- return 0;
+ host_->Send(new ViewMsg_RequestAudioPacket(render_view_id_, stream_id_));
+ packet_read_event_.Wait();
+ if (closed_)
+ return 0;
+ // Make sure it's safe to copy.
+ if (last_packet_size_ > max_size){
+ host_->SendErrorMessage(render_view_id_, stream_id_, 0);
+ host_->DestroySource(this);
+ return 0;
+ }
+ memcpy(dest, shared_memory_.memory(), last_packet_size_);
+ return last_packet_size_;
}
void AudioRendererHost::IPCAudioSource::OnClose(AudioOutputStream* stream) {
- // TODO(hclam): should set a flag here and wakes up the thread waiting for
- // audio buffer. Should also make sure this call come from the thread as this
- // object is created.
- // Stuff to do here:
- // 1. Send an IPC to renderer about close complete.
- // 2. Remove this object from host.
- host_->DestroySource(render_view_id_, stream_id_);
+ closed_ = true;
+ packet_read_event_.Signal();
}
void AudioRendererHost::IPCAudioSource::OnError(AudioOutputStream* stream,
int code) {
- // TODO(hclam): make sure this method is received in the same thread as this
- // object is created and remove this object and from the map gracefully.
- // Stuff to do here:
- // 1. Send an IPC to renderer about the error.
- // 2. Close the stream so it would get closed.
- // TODO(cpu): make sure it is safe to close() in this method.
- stream_->Close();
+ host_->SendErrorMessage(render_view_id_, stream_id_, code);
+ // The following method call would cause this object to be destroyed on IO
+ // thread.
+ host_->DestroySource(this);
}
-void AudioRendererHost::IPCAudioSource::NotifyPacketReady() {
- // TODO(hclam): wake the thread waiting for buffer.
+void AudioRendererHost::IPCAudioSource::NotifyPacketReady(size_t packet_size) {
+ // If reported size is greater than capacity of the shared memory, close the
+ // stream.
+ if (packet_size > shared_memory_.max_size()) {
+ host_->SendErrorMessage(render_view_id_, stream_id_, 0);
+ // We don't need to do packet_read_event_.Signal() here because the
+ // contained stream should be closed by the following call and OnClose will
+ // be received.
+ host_->DestroySource(this);
+ } else {
+ last_packet_size_ = packet_size;
+ packet_read_event_.Signal();
+ }
}
+//-----------------------------------------------------------------------------
+// AudioRendererHost implementations.
+
AudioRendererHost::AudioRendererHost(MessageLoop* message_loop)
: io_loop_(message_loop) {
// Make sure we perform actual initialization operations in the thread where
@@ -79,10 +92,17 @@ AudioRendererHost::AudioRendererHost(MessageLoop* message_loop)
AudioRendererHost::~AudioRendererHost() {
}
-bool AudioRendererHost::CreateStream(
- IPC::Message::Sender* sender, base::ProcessHandle handle,
- int32 render_view_id, int32 stream_id, AudioManager::Format format,
- int channels, int sample_rate, int bits_per_sample, size_t packet_size) {
+void AudioRendererHost::Destroy() {
+ // Post a message to the thread where this object should live and do the
+ // actual operations there.
+ io_loop_->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &AudioRendererHost::OnDestroyed));
+}
+
+void AudioRendererHost::CreateStream(
+ base::ProcessHandle process_handle, int32 render_view_id, int32 stream_id,
+ AudioManager::Format format, int channels, int sample_rate,
+ int bits_per_sample, size_t packet_size) {
DCHECK(MessageLoop::current() == io_loop_);
DCHECK(Lookup(render_view_id, stream_id) == NULL);
@@ -90,112 +110,104 @@ bool AudioRendererHost::CreateStream(
AudioOutputStream* stream = AudioManager::GetAudioManager()->MakeAudioStream(
format, channels, sample_rate, bits_per_sample);
if (!stream)
- return false;
-
- // Try to open the stream if we can create it.
- if (stream->Open(packet_size)) {
- // Create the containing IPCAudioSource and save it to the map.
- IPCAudioSource* source =
- new IPCAudioSource(this, render_view_id, stream_id, stream, sender,
- handle, packet_size);
- sources_.insert(make_pair(
- SourceID(source->render_view_id(), source->stream_id()), source));
- return true;
+ return;
+ if (!stream->Open(packet_size)) {
+ stream->Close();
+ stream = NULL;
+ return;
}
- return false;
-}
-bool AudioRendererHost::Start(int32 render_view_id, int32 stream_id) {
- DCHECK(MessageLoop::current() == io_loop_);
- IPCAudioSource* source = Lookup(render_view_id, stream_id);
- if (source) {
- source->stream()->Start(source);
- return true;
+ IPCAudioSource* source = new IPCAudioSource(
+ this, render_view_id, stream_id, stream, packet_size);
+ // If we can open the stream, proceed with sharing the shared memory.
+ base::SharedMemoryHandle foreign_memory_handle;
+ if (source->shared_memory()->ShareToProcess(process_handle,
+ &foreign_memory_handle)) {
+ sources_.insert(make_pair(SourceID(render_view_id, stream_id), source));
+ Send(new ViewMsg_NotifyAudioStreamCreated(
+ render_view_id, stream_id, foreign_memory_handle, packet_size));
+ } else {
+ DestroySource(source);
+ SendErrorMessage(render_view_id, stream_id, 0);
}
- return false;
}
-bool AudioRendererHost::Stop(int32 render_view_id, int32 stream_id) {
+void AudioRendererHost::Start(int32 render_view_id, int32 stream_id) {
DCHECK(MessageLoop::current() == io_loop_);
IPCAudioSource* source = Lookup(render_view_id, stream_id);
if (source) {
- source->stream()->Stop();
- return true;
+ source->stream()->Start(source);
+ Send(new ViewMsg_NotifyAudioStreamStateChanged(
+ render_view_id, stream_id, AudioOutputStream::STATE_STARTED, 0));
+ } else {
+ SendErrorMessage(render_view_id, stream_id, 0);
}
- return false;
}
-bool AudioRendererHost::Close(int32 render_view_id, int32 stream_id) {
+void AudioRendererHost::Close(int32 render_view_id, int32 stream_id) {
DCHECK(MessageLoop::current() == io_loop_);
IPCAudioSource* source = Lookup(render_view_id, stream_id);
+ // When we get called here, audio renderer in renderer process has been
+ // destroyed, we don't bother to an error message back, just destroy if we
+ // can.
if (source) {
- source->stream()->Close();
- return true;
+ DestroySource(source);
}
- return false;
}
-bool AudioRendererHost::SetVolume(int32 render_view_id, int32 stream_id,
+void AudioRendererHost::SetVolume(int32 render_view_id, int32 stream_id,
double left_channel, double right_channel) {
DCHECK(MessageLoop::current() == io_loop_);
IPCAudioSource* source = Lookup(render_view_id, stream_id);
if (source) {
source->stream()->SetVolume(left_channel, right_channel);
+ } else {
+ SendErrorMessage(render_view_id, stream_id, 0);
}
- return false;
}
-bool AudioRendererHost::GetVolume(int32 render_view_id, int32 stream_id,
- double* left_channel, double* right_channel) {
+void AudioRendererHost::GetVolume(int32 render_view_id, int32 stream_id) {
DCHECK(MessageLoop::current() == io_loop_);
IPCAudioSource* source = Lookup(render_view_id, stream_id);
if (source) {
- source->stream()->GetVolume(left_channel, right_channel);
- return true;
+ double left_channel, right_channel;
+ source->stream()->GetVolume(&left_channel, &right_channel);
+ Send(new ViewMsg_NotifyAudioStreamVolume(
+ render_view_id, stream_id, left_channel, right_channel));
+ } else {
+ SendErrorMessage(render_view_id, stream_id, 0);
}
- return false;
}
void AudioRendererHost::NotifyPacketReady(int32 render_view_id,
- int32 stream_id) {
+ int32 stream_id, size_t packet_size) {
DCHECK(MessageLoop::current() == io_loop_);
IPCAudioSource* source = Lookup(render_view_id, stream_id);
if (source) {
- source->NotifyPacketReady();
+ source->NotifyPacketReady(packet_size);
+ } else {
+ SendErrorMessage(render_view_id, stream_id, 0);
}
}
-void AudioRendererHost::DestroyAllStreams() {
+// Event received when IPC channel is connected to the renderer process.
+void AudioRendererHost::IPCChannelConnected(IPC::Message::Sender* ipc_sender) {
DCHECK(MessageLoop::current() == io_loop_);
- // TODO(hclam): iterate on the map, close and delete every stream, and clear
- // the map.
+ ipc_sender_ = ipc_sender;
}
-void AudioRendererHost::DestroySource(int32 render_view_id, int32 stream_id) {
+// Event received when IPC channel is closing.
+void AudioRendererHost::IPCChannelClosing() {
DCHECK(MessageLoop::current() == io_loop_);
- SourceMap::iterator i = sources_.find(SourceID(render_view_id, stream_id));
- if (i != sources_.end()) {
- // Remove the entry from the map.
- sources_.erase(i);
- // Also delete the IPCAudioSource object.
- delete i->second;
- }
-}
-
-void AudioRendererHost::Destroy() {
- // Post a message to the thread where this object should live and do the
- // actual operations there.
- io_loop_->PostTask(
- FROM_HERE, NewRunnableMethod(this, &AudioRendererHost::OnDestroyed));
+ ipc_sender_ = NULL;
+ DestroyAllSources();
}
void AudioRendererHost::OnInitialized() {
DCHECK(MessageLoop::current() == io_loop_);
-
// Increase the ref count of this object so it is active until we do
// Release().
AddRef();
-
// Also create the AudioManager singleton in this thread.
// TODO(hclam): figure out a better location to initialize the AudioManager
// singleton. The following method call seems to create a memory leak.
@@ -204,20 +216,76 @@ void AudioRendererHost::OnInitialized() {
void AudioRendererHost::OnDestroyed() {
DCHECK(MessageLoop::current() == io_loop_);
-
- // Destroy audio streams only in the thread it should happen.
- // TODO(hclam): make sure we don't call IPC::Message::Sender inside
- // IPCAudioSource because it is most likely be destroyed.
- DestroyAllStreams();
-
+ ipc_sender_ = NULL;
+ DestroyAllSources();
// Decrease the reference to this object, which may lead to self-destruction.
Release();
}
+void AudioRendererHost::OnSend(IPC::Message* message) {
+ DCHECK(MessageLoop::current() == io_loop_);
+ if (ipc_sender_) {
+ ipc_sender_->Send(message);
+ }
+}
+
+void AudioRendererHost::OnDestroySource(IPCAudioSource* source) {
+ DCHECK(MessageLoop::current() == io_loop_);
+ if (source) {
+ sources_.erase(SourceID(source->render_view_id(), source->stream_id()));
+ source->stream()->Stop();
+ source->stream()->Close();
+ delete source;
+ }
+}
+
+void AudioRendererHost::DestroyAllSources() {
+ DCHECK(MessageLoop::current() == io_loop_);
+ std::vector<IPCAudioSource*> sources;
+ for (SourceMap::iterator i = sources_.begin(); i != sources_.end(); ++i) {
+ sources.push_back(i->second);
+ }
+ for (size_t i = 0; i < sources.size(); ++i) {
+ DestroySource(sources[i]);
+ }
+ DCHECK(sources_.empty());
+}
+
AudioRendererHost::IPCAudioSource* AudioRendererHost::Lookup(int render_view_id,
int stream_id) {
+ DCHECK(MessageLoop::current() == io_loop_);
SourceMap::iterator i = sources_.find(SourceID(render_view_id, stream_id));
if (i != sources_.end())
return i->second;
return NULL;
}
+
+void AudioRendererHost::Send(IPC::Message* message) {
+ if (MessageLoop::current() == io_loop_) {
+ OnSend(message);
+ } else {
+ // TODO(hclam): make sure it's always safe to post a task to IO loop.
+ // It is possible that IO message loop is destroyed but there's still some
+ // dangling audio hardware threads that try to call this method.
+ io_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &AudioRendererHost::OnSend, message));
+ }
+}
+
+void AudioRendererHost::SendErrorMessage(int32 render_view_id,
+ int32 stream_id, int info) {
+ Send(new ViewMsg_NotifyAudioStreamStateChanged(
+ render_view_id, stream_id, AudioOutputStream::STATE_ERROR, info));
+}
+
+void AudioRendererHost::DestroySource(IPCAudioSource* source) {
+ if (MessageLoop::current() == io_loop_) {
+ OnDestroySource(source);
+ } else {
+ // TODO(hclam): make sure it's always safe to post a task to IO loop.
+ // It is possible that IO message loop is destroyed but there's still some
+ // dangling audio hardware threads that try to call this method.
+ io_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &AudioRendererHost::OnDestroySource, source));
+ }
+}
diff --git a/chrome/browser/renderer_host/audio_renderer_host.h b/chrome/browser/renderer_host/audio_renderer_host.h
index bcdf640..9ddeada0 100644
--- a/chrome/browser/renderer_host/audio_renderer_host.h
+++ b/chrome/browser/renderer_host/audio_renderer_host.h
@@ -30,20 +30,18 @@
// OnDestroyed(), audio output streams are destroyed and Release() is called
// which may result in self-destruction.
//
-// TODO(hclam): Have these things done before having real implementations:
+// TODO(hclam): Have these things done:
// 1. Make AudioManager a singleton and construct/destruct it properly.
-// 2. Make sure this class has greater or equal lifetime to
-// IPC:Message::Sender, essentially ResourceMessageFilter.
-// 3. Listen to destruction event of the browser and do cleanup in case this
-// class is not destructed nicely during browser close.
#ifndef CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_
#include <map>
+#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/shared_memory.h"
+#include "base/waitable_event.h"
#include "chrome/common/ipc_message.h"
#include "media/audio/audio_output.h"
@@ -51,77 +49,127 @@ class AudioManager;
class MessageLoop;
class AudioRendererHost : public base::RefCountedThreadSafe<AudioRendererHost> {
+ private:
+ class IPCAudioSource;
+ friend class AudioRendererHost::IPCAudioSource;
public:
+ // Called from UI thread from the owner of this object.
explicit AudioRendererHost(MessageLoop* message_loop);
+
+ // Destruction can happen on either UI thread or IO thread, but at destruction
+ // all associated sources are destroyed and streams are closed.
~AudioRendererHost();
- // Creates an audio output stream with the specified format, returns the
- // true if successful. If this call is successful this object would keep an
- // internal entry of the stream about the required properties, renderer
- // process handle and IPC channel for sending buffer request messages.
- bool CreateStream(IPC::Message::Sender* sender, base::ProcessHandle handle,
- int32 render_view_id, int32 stream_id,
- AudioManager::Format format, int channels, int sample_rate,
- int bits_per_sample, size_t packet_size);
-
- // Start the audio output strean, return false if stream doesn't exist or the
- // cannot start.
- bool Start(int32 render_view_id, int32 stream_id);
-
- // Stop the audio output stream, return false if stream doesn't exist or
- // cannot stop.
- bool Stop(int32 render_view_id, int32 stream_id);
-
- // Close the audio output stream, return false if stream doesn't exist or
- // cannot close. If this call is successful, the AudioOutputStream correspond
- // to (|render_view_id|, |stream_id|) would go unmanaged by this class,
- // subsequent calls to this object with the same
- // (|render_view_id|, |stream_id|) would fail.
- bool Close(int32 render_view_id, int32 stream_id);
-
- // Set the volume for the stream specified, returns true if successful, false
- // if stream doesn't exist or cann't set volume.
- bool SetVolume(int32 render_view_id, int32 stream_id,
+ // Called from UI thread from the owner of this object to kick start
+ // destruction of streams in IO thread.
+ void Destroy();
+
+ //---------------------------------------------------------------------------
+ // The following public methods are called from ResourceMessageFilter in the
+ // IO thread.
+
+ // Creates an audio output stream with the specified format. If this call is
+ // successful this object would keep an internal entry of the stream about the
+ // required properties.
+ // ViewMsg_NotifyAudioStreamCreated is sent to renderer if this call is
+ // successful, else ViewMsg_NotifyAudioStreamStateChanged with error.
+ void CreateStream(base::ProcessHandle process_handle, int32 render_view_id,
+ int32 stream_id, AudioManager::Format format, int channels,
+ int sample_rate, int bits_per_sample, size_t packet_size);
+
+ // Start the audio output strean. ViewMsg_NotifyAudioStreamStateChanged will
+ // be sent back to renderer, with
+ // ViewMsg_AudioStreamState::AUDIO_STREAM_STARTED upon success,
+ // ViewMsg_AudioStreamState::AUDIO_STREAM_ERROR upon error.
+ void Start(int32 render_view_id, int32 stream_id);
+
+ // Close the audio output stream. If this call is successful, the
+ // AudioOutputStream correspond to (|render_view_id|, |stream_id|) would go
+ // unmanaged by this class, subsequent calls to this object with the same
+ // (|render_view_id|, |stream_id|) would fail. This method call does not
+ // generate a return IPC message back to the renderer.
+ void Close(int32 render_view_id, int32 stream_id);
+
+ // Set the volume for the stream specified. No returning IPC message to
+ // renderer upon success, ViewMsg_NotifyAudioStreamStateChanged with
+ // ViewMsg_AudioStreamState::AUDIO_STREAM_ERROR is sent upon error.
+ void SetVolume(int32 render_view_id, int32 stream_id,
double left_channel, double right_channel);
- // Get the volume of the stream specified, returns true if successful, false
- // is stream doesn't exist or can't get volume.
- bool GetVolume(int32 render_view_id, int32 stream_id,
- double* left_channel, double* right_channel);
+ // Get the volume of the stream specified. NotifyAudioStreamVolume is sent
+ // back to renderer upon success. ViewMsg_NotifyAudioStreamStateChanged with
+ // ViewMsg_AudioStreamState::AUDIO_STREAM_ERROR is sent upon error.
+ void GetVolume(int32 render_view_id, int32 stream_id);
// Notify packet has been prepared for stream specified by |stream_id|. The
// buffer associated with (|render_view_id|, |stream_id|) has been filled and
// is ready to be consumed.
- void NotifyPacketReady(int32 render_view_id, int32 stream_id);
+ void NotifyPacketReady(int32 render_view_id, int32 stream_id,
+ size_t packet_size);
- // Called from UI thread from the owner of this object.
- void Destroy();
+ // Event received when IPC channel is connected with the renderer process.
+ void IPCChannelConnected(IPC::Message::Sender* ipc_sender);
- // Destroy the stream specified by (|render_view_id|, |stream_id|) and remove
- // it from map.
- // *DO NOT* call this method other than from IPCAudioSource.
- void DestroySource(int32 render_view_id, int32 stream_id);
+ // Event received when IPC channel is closing.
+ void IPCChannelClosing();
private:
+ //---------------------------------------------------------------------------
// Methods called on IO thread.
+
// Called on IO thread when this object is created and initialized.
void OnInitialized();
+
// Called on IO thread when this object needs to be destroyed and after
// Destroy() is called from owner of this class in UI thread.
void OnDestroyed();
- // Destroy all audio output streams.
- void DestroyAllStreams();
+ // Send IPC messages using ipc_sender_.
+ void OnSend(IPC::Message* message);
+
+ // A helper method that does the following things:
+ // 1. Stop the audio stream contained in the source.
+ // 2. Close the audio stream contained in the source.
+ // 3. Remove the source from the map.
+ // 4. Destruct the source.
+ // Destruction of source and associated stream should always be done by this
+ // method. *DO NOT* call this method from other than IPCAudioSource and from
+ // this class.
+ void OnDestroySource(IPCAudioSource* source);
+
+ // A helper method that destroy all IPCAudioSource and associated audio
+ // output streams.
+ void DestroyAllSources();
+
+ // A helper method to look up a IPCAudioSource with a tuple of render view id
+ // and stream id. Returns NULL if not found.
+ IPCAudioSource* Lookup(int render_view_id, int stream_id);
+
+ //---------------------------------------------------------------------------
+ // Helper methods called from IPCAudioSource or from this class, since
+ // methods in IPCAudioSource maybe called from hardware audio threads, these
+ // methods make sure the actual tasks happen on IO thread.
+
+ // A helper method to send an IPC message to renderer process on IO thread.
+ void Send(IPC::Message* message);
+
+ // A helper method for sending error IPC messages.
+ void SendErrorMessage(int32 render_view_id, int32 stream_id, int info);
+
+ // A helper method for calling OnDestroySource on IO thread.
+ void DestroySource(IPCAudioSource* source);
// The container for AudioOutputStream and serves audio packet for it by IPC.
+ // This class does nothing more than sending IPC when OnMoreData is called
+ // or error is received from the hardware audio thread, it also serves the
+ // purpose of containing the audio output stream and associated information.
+ // Lifetime of the audio output stream is not controlled by this class.
class IPCAudioSource : public AudioOutputStream::AudioSourceCallback {
public:
IPCAudioSource(AudioRendererHost* host, // Host of this source.
int32 render_view_id, // Routing ID to RenderView.
int32 stream_id, // ID of this source.
AudioOutputStream* stream, // Stream associated.
- IPC::Message::Sender* sender, // IPC sender to user.
- base::ProcessHandle process, // Render process handle.
size_t packet_size); // Size of shared memory
// buffer for writing.
~IPCAudioSource();
@@ -134,33 +182,31 @@ class AudioRendererHost : public base::RefCountedThreadSafe<AudioRendererHost> {
// Notify this source that buffer has been filled and is ready to be
// consumed.
- void NotifyPacketReady();
+ void NotifyPacketReady(size_t packet_size);
+ AudioOutputStream* stream() { return stream_; }
+ base::SharedMemory* shared_memory() { return &shared_memory_; }
int32 render_view_id() { return render_view_id_; }
int32 stream_id() { return stream_id_; }
- AudioOutputStream* stream() { return stream_; }
private:
AudioRendererHost* host_;
int32 render_view_id_;
int32 stream_id_;
AudioOutputStream* stream_;
- IPC::Message::Sender* sender_;
+ bool closed_;
base::SharedMemory shared_memory_;
- base::SharedMemoryHandle foreign_memory_handle_;
+ base::WaitableEvent packet_read_event_;
+ size_t last_packet_size_;
};
- // Look up a IPCAudioSource with a tuple of render view id and stream id.
- // Return NULL if not found.
- IPCAudioSource* Lookup(int render_view_id, int stream_id);
+ IPC::Message::Sender* ipc_sender_;
// A map of id to audio sources.
typedef std::pair<int32, int32> SourceID;
typedef std::map<SourceID, IPCAudioSource*> SourceMap;
SourceMap sources_;
- // Only used for DCHECKs to make sure all methods calls are from the same
- // thread as this object is created.
MessageLoop* io_loop_;
DISALLOW_COPY_AND_ASSIGN(AudioRendererHost);
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index a6ec016..bf6c8b9 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -117,9 +117,9 @@ ResourceMessageFilter::ResourceMessageFilter(
profile_(profile),
render_widget_helper_(render_widget_helper),
audio_renderer_host_(audio_renderer_host) {
-
DCHECK(request_context_.get());
DCHECK(request_context_->cookie_store());
+ DCHECK(audio_renderer_host_.get());
}
ResourceMessageFilter::~ResourceMessageFilter() {
@@ -151,6 +151,9 @@ void ResourceMessageFilter::OnChannelConnected(int32 peer_pid) {
DCHECK(!render_handle_);
render_handle_ = base::OpenProcessHandle(peer_pid);
DCHECK(render_handle_);
+ // Hook AudioRendererHost to this object after channel is connected so it can
+ // this object for sending messages.
+ audio_renderer_host_->IPCChannelConnected(this);
}
// Called on the IPC thread:
@@ -160,6 +163,9 @@ void ResourceMessageFilter::OnChannelClosing() {
// Unhook us from all pending network requests so they don't get sent to a
// deleted object.
resource_dispatcher_host_->CancelRequestsForProcess(render_process_host_id_);
+
+ // Unhook AudioRendererHost.
+ audio_renderer_host_->IPCChannelClosing();
}
// Called on the IPC thread:
@@ -809,38 +815,40 @@ void ResourceMessageFilter::OnRendererHistograms(
}
void ResourceMessageFilter::OnCreateAudioStream(
- const IPC::Message& msg, int stream_id,
- const ViewHostMsg_Audio_CreateStream& params) {
- // TODO(hclam): call to AudioRendererHost::CreateStream and send a message to
- // renderer to notify the result.
+ const IPC::Message& msg, int stream_id,
+ const ViewHostMsg_Audio_CreateStream& params) {
+ audio_renderer_host_->CreateStream(
+ render_handle_, msg.routing_id(), stream_id, params.format,
+ params.channels, params.sample_rate, params.bits_per_sample,
+ params.packet_size);
}
void ResourceMessageFilter::OnNotifyAudioPacketReady(
- const IPC::Message& msg, int stream_id) {
- // TODO(hclam): delegate to AudioRendererHost and handle this message.
+ const IPC::Message& msg, int stream_id, size_t packet_size) {
+ audio_renderer_host_->NotifyPacketReady(msg.routing_id(),
+ stream_id, packet_size);
}
void ResourceMessageFilter::OnStartAudioStream(
const IPC::Message& msg, int stream_id) {
- // TODO(hclam): delegate to AudioRendererHost and handle this message.
+ audio_renderer_host_->Start(msg.routing_id(), stream_id);
}
-
void ResourceMessageFilter::OnCloseAudioStream(
const IPC::Message& msg, int stream_id) {
- // TODO(hclam): delegate to AudioRendererHost and handle this message.
+ audio_renderer_host_->Close(msg.routing_id(), stream_id);
}
void ResourceMessageFilter::OnGetAudioVolume(
const IPC::Message& msg, int stream_id) {
- // TODO(hclam): delegate to AudioRendererHost and handle this message. Send
- // a message about the volume.
+ audio_renderer_host_->GetVolume(msg.routing_id(), stream_id);
}
void ResourceMessageFilter::OnSetAudioVolume(
const IPC::Message& msg, int stream_id,
double left_channel, double right_channel) {
- // TODO(hclam): delegate to AudioRendererHost and handle this message.
+ audio_renderer_host_->SetVolume(
+ msg.routing_id(), stream_id, left_channel, right_channel);
}
#if defined(OS_MACOSX)
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index ab60be0..537c937 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -202,7 +202,8 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
// Audio related IPC message handlers.
void OnCreateAudioStream(const IPC::Message& msg, int stream_id,
const ViewHostMsg_Audio_CreateStream& params);
- void OnNotifyAudioPacketReady(const IPC::Message& msg, int stream_id);
+ void OnNotifyAudioPacketReady(const IPC::Message& msg, int stream_id,
+ size_t packet_size);
void OnStartAudioStream(const IPC::Message& msg, int stream_id);
void OnCloseAudioStream(const IPC::Message& msg, int stream_id);
void OnGetAudioVolume(const IPC::Message& msg, int stream_id);
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 7fa88de..e91bdf0 100755
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -1726,14 +1726,14 @@ struct ParamTraits<AudioOutputStream::State> {
std::wstring state;
switch (p) {
case AudioOutputStream::STATE_PAUSED:
- state = L"AUDIO_STREAM_PAUSED";
+ state = L"AudioOutputStream::STATE_PAUSED";
break;
case AudioOutputStream::STATE_STARTED:
- state = L"AUDIO_STREAM_STARTED";
+ state = L"AudioOutputStream::STATE_STARTED";
break;
case AudioOutputStream::STATE_ERROR:
- state = L"AUDIO_STREAM_ERROR";
- break;
+ state = L"AudioOutputStream::STATE_ERROR";
+ break;
default:
state = L"UNKNOWN";
break;
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index e7ec9ed..b81610d 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -1159,8 +1159,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
// Tell the browser the audio buffer prepared for stream
// (render_view_id, stream_id) is filled and is ready to be consumed.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_NotifyAudioPacketReady,
- int /* stream_id */)
+ IPC_MESSAGE_ROUTED2(ViewHostMsg_NotifyAudioPacketReady,
+ int /* stream_id */,
+ size_t /* packet size */)
// Start playing the audio stream specified by (render_view_id, stream_id).
IPC_MESSAGE_ROUTED1(ViewHostMsg_StartAudioStream,
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 043a2b9..6d41678 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -2962,10 +2962,10 @@ void RenderView::CloseAudioStream(int stream_id) {
Send(new ViewHostMsg_CloseAudioStream(routing_id_, stream_id));
}
-void RenderView::NotifyAudioPacketReady(int stream_id) {
+void RenderView::NotifyAudioPacketReady(int stream_id, size_t size) {
// TODO(hclam): make sure this method is called on render thread.
DCHECK(audio_renderers_.Lookup(stream_id) != NULL);
- Send(new ViewHostMsg_NotifyAudioPacketReady(routing_id_, stream_id));
+ Send(new ViewHostMsg_NotifyAudioPacketReady(routing_id_, stream_id, size));
}
void RenderView::GetAudioVolume(int stream_id) {
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 1f7dce0..78da819 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -358,7 +358,7 @@ class RenderView : public RenderWidget,
size_t packet_size);
void StartAudioStream(int stream_id);
void CloseAudioStream(int stream_id);
- void NotifyAudioPacketReady(int stream_id);
+ void NotifyAudioPacketReady(int stream_id, size_t size);
void GetAudioVolume(int stream_id);
void SetAudioVolume(int stream_id, double left, double right);