diff options
author | neb@chromium.org <neb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-08 21:08:19 +0000 |
---|---|---|
committer | neb@chromium.org <neb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-08 21:08:19 +0000 |
commit | 7d74aaab9390a7502dac835ddcd2a5175224702e (patch) | |
tree | 4baccf95f53be95803724bce220436bacf5ccce0 /chrome/renderer | |
parent | 22c379ac0a813d0b3e0fd34819aad2d3e48c39b7 (diff) | |
download | chromium_src-7d74aaab9390a7502dac835ddcd2a5175224702e.zip chromium_src-7d74aaab9390a7502dac835ddcd2a5175224702e.tar.gz chromium_src-7d74aaab9390a7502dac835ddcd2a5175224702e.tar.bz2 |
Implement low-latency audio on Pepper.
BUG=28292
TEST=none
Review URL: http://codereview.chromium.org/577019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38392 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/audio_message_filter.cc | 23 | ||||
-rw-r--r-- | chrome/renderer/audio_message_filter.h | 18 | ||||
-rw-r--r-- | chrome/renderer/audio_message_filter_unittest.cc | 5 | ||||
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.cc | 6 | ||||
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.h | 3 | ||||
-rw-r--r-- | chrome/renderer/pepper_devices.cc | 72 | ||||
-rw-r--r-- | chrome/renderer/pepper_devices.h | 23 |
7 files changed, 138 insertions, 12 deletions
diff --git a/chrome/renderer/audio_message_filter.cc b/chrome/renderer/audio_message_filter.cc index 31c1df4..de209d9 100644 --- a/chrome/renderer/audio_message_filter.cc +++ b/chrome/renderer/audio_message_filter.cc @@ -35,6 +35,8 @@ bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(AudioMessageFilter, message) IPC_MESSAGE_HANDLER(ViewMsg_RequestAudioPacket, OnRequestPacket) IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamCreated, OnStreamCreated) + IPC_MESSAGE_HANDLER(ViewMsg_NotifyLowLatencyAudioStreamCreated, + OnLowLatencyStreamCreated) IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamStateChanged, OnStreamStateChanged) IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamVolume, OnStreamVolume) @@ -84,6 +86,27 @@ void AudioMessageFilter::OnStreamCreated(int stream_id, delegate->OnCreated(handle, length); } +void AudioMessageFilter::OnLowLatencyStreamCreated( + int stream_id, + base::SharedMemoryHandle handle, +#if defined(OS_WIN) + base::SyncSocket::Handle socket_handle, +#else + base::FileDescriptor socket_descriptor, +#endif + uint32 length) { + Delegate* delegate = delegates_.Lookup(stream_id); + if (!delegate) { + DLOG(WARNING) << "Got audio stream event for a non-existent or removed" + " audio renderer."; + return; + } +#if !defined(OS_WIN) + base::SyncSocket::Handle socket_handle = socket_descriptor.fd; +#endif + delegate->OnLowLatencyCreated(handle, socket_handle, length); +} + void AudioMessageFilter::OnStreamStateChanged( int stream_id, const ViewMsg_AudioStreamState_Params& state) { diff --git a/chrome/renderer/audio_message_filter.h b/chrome/renderer/audio_message_filter.h index 3dfacdc..6b4f736 100644 --- a/chrome/renderer/audio_message_filter.h +++ b/chrome/renderer/audio_message_filter.h @@ -12,6 +12,7 @@ #include "base/id_map.h" #include "base/shared_memory.h" +#include "base/sync_socket.h" #include "base/time.h" #include "ipc/ipc_channel_proxy.h" #include "testing/gtest/include/gtest/gtest_prod.h" @@ -33,6 +34,12 @@ class AudioMessageFilter : public IPC::ChannelProxy::MessageFilter { // Called when an audio stream has been created in the browser process. virtual void OnCreated(base::SharedMemoryHandle handle, uint32 length) = 0; + // Called when a low-latency audio stream has been created in the browser + // process. + virtual void OnLowLatencyCreated(base::SharedMemoryHandle handle, + base::SyncSocket::Handle socket_handle, + uint32 length) = 0; + // Called when notification of stream volume is received from the browser // process. virtual void OnVolume(double volume) = 0; @@ -76,6 +83,17 @@ class AudioMessageFilter : public IPC::ChannelProxy::MessageFilter { void OnStreamCreated(int stream_id, base::SharedMemoryHandle handle, uint32 length); + // Received when browser process has created an audio output stream of low + // latency. + void OnLowLatencyStreamCreated(int stream_id, base::SharedMemoryHandle handle, +#if defined(OS_WIN) + base::SyncSocket::Handle socket_handle, +#else + base::FileDescriptor socket_descriptor, +#endif + uint32 length); + + // Received when internal state of browser process' audio output device has // changed. void OnStreamStateChanged(int stream_id, diff --git a/chrome/renderer/audio_message_filter_unittest.cc b/chrome/renderer/audio_message_filter_unittest.cc index 3dce864..e4be68c 100644 --- a/chrome/renderer/audio_message_filter_unittest.cc +++ b/chrome/renderer/audio_message_filter_unittest.cc @@ -34,6 +34,11 @@ class MockAudioDelegate : public AudioMessageFilter::Delegate { length_ = length; } + virtual void OnLowLatencyCreated(base::SharedMemoryHandle handle, + base::SyncSocket::Handle, + uint32 length) { + } + virtual void OnVolume(double volume) { volume_received_ = true; volume_ = volume; diff --git a/chrome/renderer/media/audio_renderer_impl.cc b/chrome/renderer/media/audio_renderer_impl.cc index 3aba1c1..b03ba9e 100644 --- a/chrome/renderer/media/audio_renderer_impl.cc +++ b/chrome/renderer/media/audio_renderer_impl.cc @@ -174,6 +174,12 @@ void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle, shared_memory_size_ = length; } +void AudioRendererImpl::OnLowLatencyCreated(base::SharedMemoryHandle, + base::SyncSocket::Handle, uint32) { + // AudioRenderer should not have a low-latency audio channel. + NOTREACHED(); +} + void AudioRendererImpl::OnRequestPacket(uint32 bytes_in_buffer, const base::Time& message_timestamp) { DCHECK(MessageLoop::current() == io_loop_); diff --git a/chrome/renderer/media/audio_renderer_impl.h b/chrome/renderer/media/audio_renderer_impl.h index 2c4d990..2e714ee 100644 --- a/chrome/renderer/media/audio_renderer_impl.h +++ b/chrome/renderer/media/audio_renderer_impl.h @@ -122,6 +122,9 @@ class AudioRendererImpl : public media::AudioRendererBase, const base::Time& message_timestamp); void OnStateChanged(const ViewMsg_AudioStreamState_Params& state); void OnCreated(base::SharedMemoryHandle handle, uint32 length); + void OnLowLatencyCreated(base::SharedMemoryHandle handle, + base::SyncSocket::Handle socket_handle, + uint32 length); void OnVolume(double volume); // Methods called on pipeline thread ---------------------------------------- diff --git a/chrome/renderer/pepper_devices.cc b/chrome/renderer/pepper_devices.cc index 3b14d16..4a831f4 100644 --- a/chrome/renderer/pepper_devices.cc +++ b/chrome/renderer/pepper_devices.cc @@ -98,14 +98,18 @@ AudioDeviceContext::~AudioDeviceContext() { } } -NPError AudioDeviceContext::Initialize( - AudioMessageFilter* filter, const NPDeviceContextAudioConfig* config, - NPDeviceContextAudio* context) { - filter_ = filter; - context_= context; +NPError AudioDeviceContext::Initialize(AudioMessageFilter* filter, + const NPDeviceContextAudioConfig* config, + NPDeviceContextAudio* context) { + DCHECK(filter); // Make sure we don't call init more than once. DCHECK_EQ(0, stream_id_); - stream_id_ = filter_->AddDelegate(this); + + if (!config || !context) { + return NPERR_INVALID_PARAM; + } + filter_ = filter; + context_= context; ViewHostMsg_Audio_CreateStream_Params params; params.format = AudioManager::AUDIO_PCM_LINEAR; @@ -133,6 +137,7 @@ NPError AudioDeviceContext::Initialize( config->sampleFrameCount << "Hz, " << params.bits_per_sample << " bits, " << config->outputChannelMap << "channels"; + stream_id_ = filter_->AddDelegate(this); filter->Send(new ViewHostMsg_CreateAudioStream(0, stream_id_, params)); return NPERR_NO_ERROR; } @@ -143,13 +148,17 @@ void AudioDeviceContext::OnDestroy() { filter_->RemoveDelegate(stream_id_); filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_)); stream_id_ = 0; + if (audio_thread_.get()) { + socket_->Close(); + audio_thread_->Join(); + } } void AudioDeviceContext::OnRequestPacket( uint32 bytes_in_buffer, const base::Time& message_timestamp) { - context_->config.callback(context_); + FireAudioCallback(); filter_->Send(new ViewHostMsg_NotifyAudioPacketReady(0, stream_id_, - shared_memory_size_)); + shared_memory_size_)); } void AudioDeviceContext::OnStateChanged( @@ -158,15 +167,60 @@ void AudioDeviceContext::OnStateChanged( void AudioDeviceContext::OnCreated( base::SharedMemoryHandle handle, uint32 length) { +#if defined(OS_WIN) + DCHECK(handle); +#else + DCHECK_NE(-1, handle.fd); +#endif + DCHECK(length); + DCHECK(context_); + + shared_memory_.reset(new base::SharedMemory(handle, false)); + shared_memory_->Map(length); + shared_memory_size_ = length; + + context_->outBuffer = shared_memory_->memory(); + FireAudioCallback(); + filter_->Send(new ViewHostMsg_PlayAudioStream(0, stream_id_)); +} + +void AudioDeviceContext::OnLowLatencyCreated( + base::SharedMemoryHandle handle, base::SyncSocket::Handle socket_handle, + uint32 length) { +#if defined(OS_WIN) + DCHECK(handle); + DCHECK(socket_handle); +#else + DCHECK_NE(-1, handle.fd); + DCHECK_NE(-1, socket_handle); +#endif + DCHECK(length); + DCHECK(context_); + DCHECK(!audio_thread_.get()); shared_memory_.reset(new base::SharedMemory(handle, false)); shared_memory_->Map(length); shared_memory_size_ = length; context_->outBuffer = shared_memory_->memory(); - // TODO(neb): call play after prefilling + socket_.reset(new base::SyncSocket(socket_handle)); + if (context_->config.callback) { + FireAudioCallback(); + audio_thread_.reset( + new base::DelegateSimpleThread(this, "plugin_audio_thread")); + audio_thread_->Start(); + } filter_->Send(new ViewHostMsg_PlayAudioStream(0, stream_id_)); } void AudioDeviceContext::OnVolume(double volume) { } +void AudioDeviceContext::Run() { + int pending_data; + while (sizeof(pending_data) == socket_->Receive(&pending_data, + sizeof(pending_data)) && + pending_data >= 0) { + FireAudioCallback(); + } +} + diff --git a/chrome/renderer/pepper_devices.h b/chrome/renderer/pepper_devices.h index 31a2d11..2aa0b54 100644 --- a/chrome/renderer/pepper_devices.h +++ b/chrome/renderer/pepper_devices.h @@ -9,6 +9,7 @@ #include "base/scoped_ptr.h" #include "base/shared_memory.h" +#include "base/simple_thread.h" #include "base/gfx/rect.h" #include "chrome/common/render_messages.h" #include "chrome/common/transport_dib.h" @@ -46,7 +47,8 @@ class Graphics2DDeviceContext { // Each instance of AudioDeviceContext corresponds to one host stream (and one // audio context). NPDeviceContextAudio contains the id of the context's // stream in the privatePtr member. -class AudioDeviceContext : public AudioMessageFilter::Delegate { +class AudioDeviceContext : public AudioMessageFilter::Delegate, + public base::DelegateSimpleThread::Delegate { public: // TODO(neb): if plugin_delegate parameter is indeed unused, remove it explicit AudioDeviceContext() : stream_id_(0) { @@ -57,24 +59,39 @@ class AudioDeviceContext : public AudioMessageFilter::Delegate { const NPDeviceContextAudioConfig* config, NPDeviceContextAudio* context); + base::SharedMemory* shared_memory() { return shared_memory_.get(); } + + private: + // AudioMessageFilter::Delegate implementation virtual void OnRequestPacket(uint32 bytes_in_buffer, const base::Time& message_timestamp); virtual void OnStateChanged(const ViewMsg_AudioStreamState_Params& state); virtual void OnCreated(base::SharedMemoryHandle handle, uint32 length); + virtual void OnLowLatencyCreated(base::SharedMemoryHandle handle, + base::SyncSocket::Handle socket_handle, + uint32 length); virtual void OnVolume(double volume); // End of AudioMessageFilter::Delegate implementation - base::SharedMemory* shared_memory() { return shared_memory_.get(); } + // DelegateSimpleThread::Delegate implementation + virtual void Run(); + // End of DelegateSimpleThread::Delegate implementation - private: void OnDestroy(); + void FireAudioCallback() { + if (context_ && context_->config.callback) { + context_->config.callback(context_); + } + } NPDeviceContextAudio* context_; scoped_refptr<AudioMessageFilter> filter_; int32 stream_id_; scoped_ptr<base::SharedMemory> shared_memory_; uint32 shared_memory_size_; + scoped_ptr<base::SyncSocket> socket_; + scoped_ptr<base::DelegateSimpleThread> audio_thread_; }; #endif // CHROME_RENDERER_PEPPER_DEVICES_H_ |