diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-16 19:03:25 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-16 19:03:25 +0000 |
commit | 5fb88964b6a7df7fc3be69811a734ff08fbcbdc5 (patch) | |
tree | 55a1acb1ab3dd33c822773bfce170946def82c0b /chrome | |
parent | b7e62b5dcc16b6a7e87e1af59d2673ecd7edde6a (diff) | |
download | chromium_src-5fb88964b6a7df7fc3be69811a734ff08fbcbdc5.zip chromium_src-5fb88964b6a7df7fc3be69811a734ff08fbcbdc5.tar.gz chromium_src-5fb88964b6a7df7fc3be69811a734ff08fbcbdc5.tar.bz2 |
Handles audio messages on IO thread in render process
First step to have smoother audio playback. We previously
performed audio messages handling on render thread, which
gave us huge amount of latency, especially when renderer
is busy compositing or is blocked by synchronous IPC call.
A lot of these latencies are eliminated by moving audio
messages handling to IO thread, this is the first step to
see if sharing the regular IPC channel for audio messages
is creating too much stress for the IPC channel. Also
doubled the audio packet size to 8192 samples, ~194ms of
audio for 16bit/44.1khz/2ch.
Review URL: http://codereview.chromium.org/62125
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13863 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/chrome.gyp | 12 | ||||
-rw-r--r-- | chrome/renderer/audio_message_filter.cc | 109 | ||||
-rw-r--r-- | chrome/renderer/audio_message_filter.h | 84 | ||||
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.cc | 151 | ||||
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.h | 134 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 105 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 40 | ||||
-rw-r--r-- | chrome/renderer/renderer.vcproj | 8 | ||||
-rw-r--r-- | chrome/renderer/webmediaplayer_delegate_impl.cc | 16 | ||||
-rw-r--r-- | chrome/renderer/webmediaplayer_delegate_impl.h | 4 |
10 files changed, 390 insertions, 273 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 1ccb9d8..8b869f9 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1220,6 +1220,8 @@ 'browser/views/options/content_page_view.h', 'browser/views/options/cookies_view.cc', 'browser/views/options/cookies_view.h', + 'browser/views/options/exceptions_page_view.cc', + 'browser/views/options/exceptions_page_view.h', 'browser/views/options/fonts_languages_window_view.cc', 'browser/views/options/fonts_languages_window_view.h', 'browser/views/options/fonts_page_view.cc', @@ -1235,12 +1237,12 @@ 'browser/views/options/options_page_view.cc', 'browser/views/options/options_page_view.h', 'browser/views/options/options_window_view.cc', + 'browser/views/options/passwords_exceptions_window_view.cc', + 'browser/views/options/passwords_exceptions_window_view.h', + 'browser/views/options/passwords_page_view.cc', + 'browser/views/options/passwords_page_view.h', 'browser/views/page_info_window.cc', 'browser/views/page_info_window.h', - 'browser/views/password_manager_exceptions_view.cc', - 'browser/views/password_manager_exceptions_view.h', - 'browser/views/password_manager_view.cc', - 'browser/views/password_manager_view.h', 'browser/views/repost_form_warning_view.cc', 'browser/views/repost_form_warning_view.h', 'browser/views/restart_message_box.cc', @@ -1459,6 +1461,8 @@ 'renderer/net/render_dns_queue.h', 'renderer/about_handler.cc', 'renderer/about_handler.h', + 'renderer/audio_message_filter.cc', + 'renderer/audio_message_filter.h', 'renderer/debug_message_handler.cc', 'renderer/debug_message_handler.h', 'renderer/devtools_agent.cc', diff --git a/chrome/renderer/audio_message_filter.cc b/chrome/renderer/audio_message_filter.cc new file mode 100644 index 0000000..6e22bbd --- /dev/null +++ b/chrome/renderer/audio_message_filter.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2009 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. + +#include "base/message_loop.h" +#include "chrome/common/render_messages.h" +#include "chrome/renderer/audio_message_filter.h" + +AudioMessageFilter::AudioMessageFilter(int32 route_id) + : channel_(NULL), + route_id_(route_id), + message_loop_(NULL) { +} + +AudioMessageFilter::~AudioMessageFilter() { +} + +// Called on the IPC thread. +bool AudioMessageFilter::Send(IPC::Message* message) { + if (!channel_) { + delete message; + return false; + } + 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(ViewMsg_RequestAudioPacket, OnRequestPacket) + IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamCreated, OnStreamCreated) + IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamStateChanged, + OnStreamStateChanged) + IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamVolume, OnStreamVolume) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void AudioMessageFilter::OnFilterAdded(IPC::Channel* channel) { + // Captures the message loop for IPC. + message_loop_ = MessageLoop::current(); + channel_ = channel; +} + +void AudioMessageFilter::OnFilterRemoved() { + channel_ = NULL; +} + +void AudioMessageFilter::OnChannelClosing() { + channel_ = NULL; +} + +void AudioMessageFilter::OnRequestPacket(int stream_id) { + Delegate* delegate = delegates_.Lookup(stream_id); + if (!delegate) { + DLOG(WARNING) << "Got audio packet request for a non-existent or removed" + " audio renderer."; + return; + } + delegate->OnRequestPacket(); +} + +void AudioMessageFilter::OnStreamCreated(int stream_id, + base::SharedMemoryHandle handle, + int length) { + Delegate* delegate = delegates_.Lookup(stream_id); + if (!delegate) { + DLOG(WARNING) << "Got audio stream event for a non-existent or removed" + " audio renderer."; + return; + } + delegate->OnCreated(handle, length); +} + +void AudioMessageFilter::OnStreamStateChanged(int stream_id, + AudioOutputStream::State state, + int info) { + Delegate* delegate = delegates_.Lookup(stream_id); + if (!delegate) { + DLOG(WARNING) << "Got audio stream event for a non-existent or removed" + " audio renderer."; + return; + } + delegate->OnStateChanged(state, info); +} + +void AudioMessageFilter::OnStreamVolume(int stream_id, + double left, double right) { + Delegate* delegate = delegates_.Lookup(stream_id); + if (!delegate) { + DLOG(WARNING) << "Got audio stream event for a non-existent or removed" + " audio renderer."; + return; + } + delegate->OnVolume(left, right); +} + +int32 AudioMessageFilter::AddDelegate(Delegate* delegate) { + return delegates_.Add(delegate); +} + +void AudioMessageFilter::RemoveDelegate(int32 id) { + delegates_.Remove(id); +} diff --git a/chrome/renderer/audio_message_filter.h b/chrome/renderer/audio_message_filter.h new file mode 100644 index 0000000..8514c1e --- /dev/null +++ b/chrome/renderer/audio_message_filter.h @@ -0,0 +1,84 @@ +// Copyright (c) 2009 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. +// +// 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 +// and process them on IO thread since these messages are time critical. + +#ifndef CHROME_RENDERER_AUDIO_MESSAGE_FILTER_H_ +#define CHROME_RENDERER_AUDIO_MESSAGE_FILTER_H_ + +#include "base/id_map.h" +#include "base/shared_memory.h" +#include "chrome/common/ipc_channel_proxy.h" +#include "media/audio/audio_output.h" + +class AudioMessageFilter : public IPC::ChannelProxy::MessageFilter { + public: + class Delegate { + public: + // Called when an audio packet is requested from the browser process. + virtual void OnRequestPacket() = 0; + + // Called when state of an audio stream has changed in the browser process. + virtual void OnStateChanged(AudioOutputStream::State state, int info) = 0; + + // Called when an audio stream has been created in the browser process. + virtual void OnCreated(base::SharedMemoryHandle handle, size_t length) = 0; + + // Called when notification of stream volume is received from the browser + // process. + virtual void OnVolume(double left, double right) = 0; + }; + + AudioMessageFilter(int32 route_id); + ~AudioMessageFilter(); + + // Add a delegate to the map and return id of the entry. + int32 AddDelegate(Delegate* delegate); + + // Remove a delegate referenced by |id| from the map. + void RemoveDelegate(int32 id); + + // Sends an IPC message using |channel_|. + bool Send(IPC::Message* message); + + MessageLoop* message_loop() { return message_loop_; } + + private: + // IPC::ChannelProxy::MessageFilter override. Called on IO thread. + virtual bool OnMessageReceived(const IPC::Message& message); + virtual void OnFilterAdded(IPC::Channel* channel); + virtual void OnFilterRemoved(); + virtual void OnChannelClosing(); + + // Received when browser process wants more audio packet. + void OnRequestPacket(int stream_id); + + // Received when browser process has created an audio output stream. + void OnStreamCreated(int stream_id, base::SharedMemoryHandle handle, + int length); + + // Received when internal state of browser process' audio output device has + // changed. + void OnStreamStateChanged(int stream_id, AudioOutputStream::State state, + int info); + + // Notification of volume property of an audio output stream. + void OnStreamVolume(int stream_id, double left, double right); + + // A map of stream ids to delegates. + IDMap<Delegate> delegates_; + + IPC::Channel* channel_; + + int32 route_id_; + + MessageLoop* message_loop_; + + DISALLOW_COPY_AND_ASSIGN(AudioMessageFilter); +}; + +#endif // CHROME_RENDERER_AUDIO_MESSAGE_FITLER_H_ diff --git a/chrome/renderer/media/audio_renderer_impl.cc b/chrome/renderer/media/audio_renderer_impl.cc index a0b6ae3..4f0627c 100644 --- a/chrome/renderer/media/audio_renderer_impl.cc +++ b/chrome/renderer/media/audio_renderer_impl.cc @@ -2,32 +2,42 @@ // source code is governed by a BSD-style license that can be found in the // LICENSE file. +#include "chrome/common/render_messages.h" +#include "chrome/renderer/audio_message_filter.h" #include "chrome/renderer/media/audio_renderer_impl.h" #include "chrome/renderer/render_view.h" #include "chrome/renderer/render_thread.h" -#include "chrome/renderer/webmediaplayer_delegate_impl.h" #include "media/base/filter_host.h" -// We'll try to fill 4096 samples per buffer, which is roughly ~92ms of audio +// We'll try to fill 8192 samples per buffer, which is roughly ~194ms of audio // data for a 44.1kHz audio source. -static const size_t kSamplesPerBuffer = 4096; +static const size_t kSamplesPerBuffer = 8192; -AudioRendererImpl::AudioRendererImpl(WebMediaPlayerDelegateImpl* delegate) +AudioRendererImpl::AudioRendererImpl(AudioMessageFilter* filter) : AudioRendererBase(kDefaultMaxQueueSize), - delegate_(delegate), + filter_(filter), stream_id_(0), shared_memory_(NULL), shared_memory_size_(0), - packet_requested_(false), - render_loop_(RenderThread::current()->message_loop()), - resource_release_event_(true, false) { - // TODO(hclam): do we need to move this method call to render thread? - delegate_->SetAudioRenderer(this); + io_loop_(filter->message_loop()), + stopped_(false), + packet_request_event_(true, false) { + DCHECK(io_loop_); } AudioRendererImpl::~AudioRendererImpl() { } +bool AudioRendererImpl::HasStopped() { + AutoLock auto_lock(lock_); + return stopped_; +} + +void AudioRendererImpl::SignalStop() { + AutoLock auto_lock(lock_); + stopped_ = true; +} + bool AudioRendererImpl::IsMediaFormatSupported( const media::MediaFormat& media_format) { int channels; @@ -47,32 +57,37 @@ bool AudioRendererImpl::OnInitialize(const media::MediaFormat& media_format) { // Create the audio output stream in browser process. size_t packet_size = kSamplesPerBuffer * channels * sample_bits / 8; - render_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioRendererImpl::OnCreateAudioStream, + io_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::OnCreateStream, AudioManager::AUDIO_PCM_LINEAR, channels, sample_rate, sample_bits, packet_size)); return true; } void AudioRendererImpl::OnStop() { - delegate_->SetAudioRenderer(NULL); - if (!resource_release_event_.IsSignaled()) { - render_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, - &AudioRendererImpl::ReleaseResources, false)); - resource_release_event_.Wait(); - } + if (HasStopped()) + return; + + SignalStop(); + io_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::OnDestroy)); } void AudioRendererImpl::OnReadComplete(media::Buffer* buffer_in) { + if (HasStopped()) + return; + // Use the base class to queue the buffer. AudioRendererBase::OnReadComplete(buffer_in); // Post a task to render thread to notify a packet reception. - render_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioRendererImpl::OnNotifyAudioPacketReady)); + io_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::OnNotifyPacketReady)); } void AudioRendererImpl::SetPlaybackRate(float rate) { + if (HasStopped()) + return; + // TODO(hclam): handle playback rates not equal to 1.0. if (rate == 1.0f) { // TODO(hclam): what should I do here? OnCreated has fired StartAudioStream @@ -83,30 +98,45 @@ void AudioRendererImpl::SetPlaybackRate(float rate) { } void AudioRendererImpl::SetVolume(float volume) { + if (HasStopped()) + return; + // TODO(hclam): change this to multichannel if possible. - render_loop_->PostTask(FROM_HERE, + io_loop_->PostTask(FROM_HERE, NewRunnableMethod( - this, &AudioRendererImpl::OnSetAudioVolume, volume, volume)); + this, &AudioRendererImpl::OnSetVolume, volume, volume)); } void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle, size_t length) { + DCHECK(MessageLoop::current() == io_loop_); + + if (HasStopped()) + return; + shared_memory_.reset(new base::SharedMemory(handle, false)); shared_memory_->Map(length); shared_memory_size_ = length; - // TODO(hclam): is there any better place to do this? - OnStartAudioStream(); + + filter_->Send(new ViewHostMsg_StartAudioStream(0, stream_id_)); } void AudioRendererImpl::OnRequestPacket() { - packet_requested_ = true; - // Post a task to render thread and try to grab a packet for sending back. - render_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &AudioRendererImpl::OnNotifyAudioPacketReady)); + DCHECK(MessageLoop::current() == io_loop_); + + packet_request_event_.Signal(); + + // Try to fill in the fulfil the packet request. + OnNotifyPacketReady(); } void AudioRendererImpl::OnStateChanged(AudioOutputStream::State state, int info) { + DCHECK(MessageLoop::current() == io_loop_); + + if (HasStopped()) + return; + switch (state) { case AudioOutputStream::STATE_ERROR: host_->Error(media::PIPELINE_ERROR_AUDIO_HARDWARE); @@ -122,46 +152,67 @@ void AudioRendererImpl::OnStateChanged(AudioOutputStream::State state, } void AudioRendererImpl::OnVolume(double left, double right) { + if (HasStopped()) + return; + // TODO(hclam): decide whether we need to report the current volume to // pipeline. } -void AudioRendererImpl::ReleaseResources(bool is_render_thread_dying) { - if (!is_render_thread_dying) - OnCloseAudioStream(); - resource_release_event_.Signal(); -} - -void AudioRendererImpl::OnCreateAudioStream( +void AudioRendererImpl::OnCreateStream( AudioManager::Format format, int channels, int sample_rate, int bits_per_sample, size_t packet_size) { - stream_id_ = delegate_->view()->CreateAudioStream( - this, format, channels, sample_rate, bits_per_sample, packet_size); -} + DCHECK(MessageLoop::current() == io_loop_); + + if (HasStopped()) + return; -void AudioRendererImpl::OnStartAudioStream() { - delegate_->view()->StartAudioStream(stream_id_); + // Make sure we don't call create more than once. + DCHECK_EQ(0, stream_id_); + stream_id_ = filter_->AddDelegate(this); + + ViewHostMsg_Audio_CreateStream params; + params.format = format; + params.channels = channels; + params.sample_rate = sample_rate; + params.bits_per_sample = bits_per_sample; + params.packet_size = packet_size; + + filter_->Send(new ViewHostMsg_CreateAudioStream(0, stream_id_, params)); } -void AudioRendererImpl::OnCloseAudioStream() { - // Unregister ourself from RenderView, we will not be called anymore. - delegate_->view()->CloseAudioStream(stream_id_); +void AudioRendererImpl::OnDestroy() { + DCHECK(MessageLoop::current() == io_loop_); + + filter_->RemoveDelegate(stream_id_); + filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_)); } -void AudioRendererImpl::OnSetAudioVolume(double left, double right) { - delegate_->view()->SetAudioVolume(stream_id_, left, right); +void AudioRendererImpl::OnSetVolume(double left, double right) { + DCHECK(MessageLoop::current() == io_loop_); + + if (HasStopped()) + return; + + filter_->Send(new ViewHostMsg_SetAudioVolume(0, stream_id_, left, right)); } -void AudioRendererImpl::OnNotifyAudioPacketReady() { - if (packet_requested_) { +void AudioRendererImpl::OnNotifyPacketReady() { + DCHECK(MessageLoop::current() == io_loop_); + + if (HasStopped()) + return; + + if (packet_request_event_.IsSignaled()) { DCHECK(shared_memory_.get()); // Fill into the shared memory. size_t filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()), shared_memory_size_); if (filled > 0) { - packet_requested_ = false; + packet_request_event_.Reset(); // Then tell browser process we are done filling into the buffer. - delegate_->view()->NotifyAudioPacketReady(stream_id_, filled); + filter_->Send( + new ViewHostMsg_NotifyAudioPacketReady(0, stream_id_, filled)); } } } diff --git a/chrome/renderer/media/audio_renderer_impl.h b/chrome/renderer/media/audio_renderer_impl.h index 6945f8a..3628e44 100644 --- a/chrome/renderer/media/audio_renderer_impl.h +++ b/chrome/renderer/media/audio_renderer_impl.h @@ -7,27 +7,27 @@ // // Relationship of classes. // -// AudioRendererHost AudioRendererImpl -// ^ ^ -// | | -// v IPC v -// ResourceMessageFilter <---------> RenderView +// AudioRendererHost AudioRendererImpl +// ^ ^ +// | | +// v IPC v +// ResourceMessageFilter <---------> AudioMessageFilter // // Implementation of interface with audio device is in AudioRendererHost and // it provides services and entry points in ResourceMessageFilter, allowing -// usage of IPC calls to interact with audio device. RenderView acts as a portal -// for IPC calls and does no more than delegation. +// usage of IPC calls to interact with audio device. AudioMessageFilter acts +// as a portal for IPC calls and does no more than delegation. // // Transportation of audio buffer is done by using shared memory, after -// OnCreateAudioStream is executed, OnCreated would be called along with a +// OnCreateStream is executed, OnCreated would be called along with a // SharedMemoryHandle upon successful creation of audio output stream in the // browser process. The same piece of shared memory would be used during the // lifetime of this unit. // // This class lives inside three threads during it's lifetime, namely: -// 1. Render thread -// The thread within which this class is constructed and destroyed, -// interfacing with RenderView should only happen here. +// 1. IO thread. +// The thread within which this class receives all the IPC messages and +// IPC communications can only happen in this thread. // 2. Pipeline thread // Initialization of filter and proper stopping of filters happens here. // Properties of this filter is also set in this thread. @@ -39,32 +39,33 @@ // Render thread // +-- CreateFactory() // | Helper method for construction this class. -// |-- IsMetidFormatSupported() -// | Helper method to identify media formats accepted by this class for -// | construction. -// |-- OnCreateAudioStream() -// | Calls RenderView::CreateAudioStream(). -// |-- OnStartAudioStream() -// | Calls RenderView::StartAudioStream(). -// |-- OnCloseAudioStream() -// | Calls RenderView::CloseAudioStream(). -// |-- OnSetAudioVolume() -// | Calls RenderView::SetAudioVolume(). -// |-- OnNotifyAudioPacketReady -// | Calls RenderView::NotifyAudioPacketReady(). +// \-- IsMediaFormatSupported() +// Helper method to identify media formats accepted by this class for +// construction. +// +// IO thread (Main thread in render process) +// +-- OnCreateStream() +// | Sends an IPC message to browser to create audio output stream and +// | register this object with AudioMessageFilter. +// |-- OnSetVolume() +// | Sends an IPC message to browser to set volume. +// |-- OnNotifyPacketReady +// | Try to fill the shared memory with decoded audio packet and sends IPC +// | messages to browser if packet is ready. // |-- OnRequestPacket() -// | Called from RenderView when an audio packet requested is received -// | from browser process. +// | Called from AudioMessageFilter when an audio packet requested is +// | received from browser process. // |-- OnStateChanged() -// | Called from RenderView upon state change of the audio output stream -// | in the browser process. Error of the output stream is reported here. +// | Called from AudioMessageFilter upon state change of the audio output +// | stream in the browser process. Error of the stream is reported here. // |-- OnCreated() -// | Called from RenderView upon successful creation of audio output stream -// | in the browser process, called along with a SharedMemoryHandle. +// | Called from AudioMessageFilter upon successful creation of audio output +// | stream in the browser process, called along with a SharedMemoryHandle. // |-- OnVolume() -// | Called from RenderView about the volume of the audio output stream. -// \-- ReleaseResource() -// Release resources that live inside render thread. +// | Called from AudioMessageFilter about the volume of the audio output +// | stream. +// \-- OnDestroy() +// Release resources that live inside io thread. // // Pipeline thread // +-- AudioRendererImpl() @@ -90,38 +91,35 @@ #ifndef CHROME_RENDERER_MEDIA_AUDIO_RENDERER_IMPL_H_ #define CHROME_RENDERER_MEDIA_AUDIO_RENDERER_IMPL_H_ +#include "base/lock.h" #include "base/shared_memory.h" #include "base/waitable_event.h" +#include "chrome/renderer/audio_message_filter.h" #include "media/audio/audio_output.h" #include "media/base/factory.h" #include "media/base/filters.h" #include "media/filters/audio_renderer_base.h" -class WebMediaPlayerDelegateImpl; +class AudioMessageFilter; -class AudioRendererImpl : public media::AudioRendererBase { +class AudioRendererImpl : public media::AudioRendererBase, + public AudioMessageFilter::Delegate { public: // Methods called on render thread ------------------------------------------ // Methods called during construction. - static media::FilterFactory* CreateFactory( - WebMediaPlayerDelegateImpl* delegate) { + static media::FilterFactory* CreateFactory(AudioMessageFilter* filter) { return new media::FilterFactoryImpl1<AudioRendererImpl, - WebMediaPlayerDelegateImpl*>(delegate); + AudioMessageFilter*>(filter); } static bool IsMediaFormatSupported(const media::MediaFormat& format); - // Methods call from RenderView when audio related IPC messages are received - // from browser process. + // Methods called on IO thread ---------------------------------------------- + // AudioMessageFilter::Delegate methods, called by AudioMessageFilter. void OnRequestPacket(); void OnStateChanged(AudioOutputStream::State state, int info); void OnCreated(base::SharedMemoryHandle handle, size_t length); void OnVolume(double left, double right); - // Release resources that lives in renderer thread, i.e. audio output streams. - // |render_thread_is_dying| tells us if render thread is being destroyed, - // if true it's not safe to access any object that lives inside render thread. - void ReleaseResources(bool render_thread_is_dying); - // Methods called on pipeline thread ---------------------------------------- // media::MediaFilter implementation. virtual void SetPlaybackRate(float rate); @@ -140,25 +138,26 @@ class AudioRendererImpl : public media::AudioRendererBase { private: friend class media::FilterFactoryImpl1<AudioRendererImpl, - WebMediaPlayerDelegateImpl*>; + AudioMessageFilter*>; - explicit AudioRendererImpl(WebMediaPlayerDelegateImpl* delegate); + explicit AudioRendererImpl(AudioMessageFilter* filter); virtual ~AudioRendererImpl(); - // Methods call on render thread -------------------------------------------- - // The following methods are tasks posted on the render thread that needs to - // be executed on that thread. They interact with WebMediaPlayerDelegateImpl - // and the containing RenderView, because method calls to RenderView must be - // executed on render thread. - void OnCreateAudioStream(AudioManager::Format format, int channels, - int sample_rate, int bits_per_sample, - size_t packet_size); - void OnStartAudioStream(); - void OnCloseAudioStream(); - void OnSetAudioVolume(double left, double right); - void OnNotifyAudioPacketReady(); - - WebMediaPlayerDelegateImpl* delegate_; + bool HasStopped(); + void SignalStop(); + + // Methods call 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 OnCreateStream(AudioManager::Format format, int channels, + int sample_rate, int bits_per_sample, + size_t packet_size); + void OnSetVolume(double left, double right); + void OnNotifyPacketReady(); + void OnDestroy(); + + scoped_refptr<AudioMessageFilter> filter_; // ID of the stream created in the browser process. int32 stream_id_; @@ -167,15 +166,12 @@ class AudioRendererImpl : public media::AudioRendererBase { scoped_ptr<base::SharedMemory> shared_memory_; size_t shared_memory_size_; - // Flag that tells whether we have any unfulfilled packet request. - bool packet_requested_; - - // Message loop for the render thread, it's the message loop where this class - // is constructed. - MessageLoop* render_loop_; + // Message loop for the io thread. + MessageLoop* io_loop_; - // Event for releasing resources that live in render thread. - base::WaitableEvent resource_release_event_; + Lock lock_; + bool stopped_; + base::WaitableEvent packet_request_event_; DISALLOW_COPY_AND_ASSIGN(AudioRendererImpl); }; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 967e2a1..f5ca189 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -28,6 +28,7 @@ #include "chrome/common/thumbnail_score.h" #include "chrome/common/url_constants.h" #include "chrome/renderer/about_handler.h" +#include "chrome/renderer/audio_message_filter.h" #include "chrome/renderer/debug_message_handler.h" #include "chrome/renderer/devtools_agent.h" #include "chrome/renderer/devtools_agent_filter.h" @@ -219,6 +220,7 @@ RenderView::~RenderView() { render_thread_->RemoveFilter(debug_message_handler_); if (devtools_agent_filter_.get()) render_thread_->RemoveFilter(devtools_agent_filter_); + render_thread_->RemoveFilter(audio_message_filter_); #ifdef CHROME_PERSONALIZATION Personalization::CleanupRendererPersonalization(personalization_); @@ -355,6 +357,9 @@ void RenderView::Init(gfx::NativeViewId parent_hwnd, render_thread_->AddFilter(debug_message_handler_); if (dev_tools_enabled) render_thread_->AddFilter(devtools_agent_filter_); + + audio_message_filter_ = new AudioMessageFilter(routing_id_); + render_thread_->AddFilter(audio_message_filter_); } void RenderView::OnMessageReceived(const IPC::Message& message) { @@ -445,11 +450,6 @@ void RenderView::OnMessageReceived(const IPC::Message& message) { OnReceivedAutofillSuggestions) IPC_MESSAGE_HANDLER(ViewMsg_PopupNotificationVisiblityChanged, OnPopupNotificationVisiblityChanged) - IPC_MESSAGE_HANDLER(ViewMsg_RequestAudioPacket, OnRequestAudioPacket) - IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamCreated, OnAudioStreamCreated) - IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamStateChanged, - OnAudioStreamStateChanged) - IPC_MESSAGE_HANDLER(ViewMsg_NotifyAudioStreamVolume, OnAudioStreamVolume) IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted) IPC_MESSAGE_HANDLER(ViewMsg_ExtensionResponse, OnExtensionResponse) IPC_MESSAGE_HANDLER(ViewMsg_ClearFocusedNode, OnClearFocusedNode) @@ -2937,106 +2937,11 @@ MessageLoop* RenderView::GetMessageLoopForIO() { return NULL; } -void RenderView::OnRequestAudioPacket(int stream_id) { - AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer) { - // It is possible that AudioRendererImpl is un-registered but we still - // receives packet requests here, because of closing a stream is not a - // synchronous operation with the browser process. - return; - } - audio_renderer->OnRequestPacket(); -} - -void RenderView::OnAudioStreamCreated( - int stream_id, base::SharedMemoryHandle handle, int length) { - AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer) { - return; - } - audio_renderer->OnCreated(handle, length); -} - -void RenderView::OnAudioStreamStateChanged( - int stream_id, AudioOutputStream::State state, int info) { - AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer) { - return; - } - audio_renderer->OnStateChanged(state, info); -} - -void RenderView::OnAudioStreamVolume(int stream_id, double left, double right) { - AudioRendererImpl* audio_renderer = audio_renderers_.Lookup(stream_id); - if (!audio_renderer) { - return; - } - audio_renderer->OnVolume(left, right); -} - void RenderView::OnMoveOrResizeStarted() { if (webview()) webview()->HideAutofillPopup(); } -int32 RenderView::CreateAudioStream(AudioRendererImpl* audio_renderer, - AudioManager::Format format, int channels, - int sample_rate, int bits_per_sample, - size_t packet_size) { - DCHECK(RenderThread::current()->message_loop() == MessageLoop::current()); - // Loop through the map and make sure there's no renderer already in the map. - for (IDMap<AudioRendererImpl>::const_iterator iter = audio_renderers_.begin(); - iter != audio_renderers_.end(); ++iter) { - DCHECK(iter->second != audio_renderer); - } - - // Add to map and send the IPC to browser process. - int32 stream_id = audio_renderers_.Add(audio_renderer); - ViewHostMsg_Audio_CreateStream params; - params.format = format; - params.channels = channels; - params.sample_rate = sample_rate; - params.bits_per_sample = bits_per_sample; - params.packet_size = packet_size; - Send(new ViewHostMsg_CreateAudioStream(routing_id_, stream_id, params)); - return stream_id; -} - -void RenderView::StartAudioStream(int stream_id) { - DCHECK(RenderThread::current()->message_loop() == MessageLoop::current()); - DCHECK(audio_renderers_.Lookup(stream_id) != NULL); - Send(new ViewHostMsg_StartAudioStream(routing_id_, stream_id)); -} - -void RenderView::CloseAudioStream(int stream_id) { - DCHECK(RenderThread::current()->message_loop() == MessageLoop::current()); - if (audio_renderers_.Lookup(stream_id) != NULL) { - // Remove the entry from the map and send a close message to browser - // process, we won't be getting anything back from browser even if there's - // an error. - audio_renderers_.Remove(stream_id); - Send(new ViewHostMsg_CloseAudioStream(routing_id_, stream_id)); - } -} - -void RenderView::NotifyAudioPacketReady(int stream_id, size_t size) { - DCHECK(RenderThread::current()->message_loop() == MessageLoop::current()); - DCHECK(audio_renderers_.Lookup(stream_id) != NULL); - Send(new ViewHostMsg_NotifyAudioPacketReady(routing_id_, stream_id, size)); -} - -void RenderView::GetAudioVolume(int stream_id) { - DCHECK(RenderThread::current()->message_loop() == MessageLoop::current()); - DCHECK(audio_renderers_.Lookup(stream_id) != NULL); - Send(new ViewHostMsg_GetAudioVolume(routing_id_, stream_id)); -} - -void RenderView::SetAudioVolume(int stream_id, double left, double right) { - DCHECK(RenderThread::current()->message_loop() == MessageLoop::current()); - DCHECK(audio_renderers_.Lookup(stream_id) != NULL); - Send(new ViewHostMsg_SetAudioVolume(routing_id_, stream_id, left, right)); -} - void RenderView::OnResize(const gfx::Size& new_size, const gfx::Rect& resizer_rect) { if (webview()) diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index d0264f3..f6bd01b 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -26,7 +26,6 @@ #include "chrome/renderer/external_host_bindings.h" #include "chrome/renderer/external_js_object.h" #include "chrome/renderer/render_widget.h" -#include "media/audio/audio_output.h" #include "testing/gtest/include/gtest/gtest_prod.h" #include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h" #include "webkit/glue/dom_serializer_delegate.h" @@ -44,7 +43,7 @@ #pragma warning(disable: 4250) #endif -class AudioRendererImpl; +class AudioMessageFilter; class DictionaryValue; class DebugMessageHandler; class DevToolsAgent; @@ -372,18 +371,7 @@ class RenderView : public RenderWidget, // the renderer, which processes all IPC, to any I/O should be non-blocking. MessageLoop* GetMessageLoopForIO(); - // Register the audio renderer and try to create an audio output stream in the - // browser process. Always return a stream id. Audio renderer will then - // receive state change notification messages. - int32 CreateAudioStream(AudioRendererImpl* renderer, - AudioManager::Format format, int channels, - int sample_rate, int bits_per_sample, - size_t packet_size); - void StartAudioStream(int stream_id); - void CloseAudioStream(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); + AudioMessageFilter* audio_message_filter() { return audio_message_filter_; } void OnClearFocusedNode(); @@ -591,21 +579,6 @@ class RenderView : public RenderWidget, // grouping, and should form our own grouping. void OnDisassociateFromPopupCount(); - // Received when browser process wants more audio packet. - void OnRequestAudioPacket(int stream_id); - - // Received when browser process has created an audio output stream for us. - void OnAudioStreamCreated(int stream_id, base::SharedMemoryHandle handle, - int length); - - // Received when internal state of browser process' audio output device has - // changed. - void OnAudioStreamStateChanged(int stream_id, AudioOutputStream::State state, - int info); - - // Notification of volume property of an audio output stream. - void OnAudioStreamVolume(int stream_id, double left, double right); - // Sends the selection text to the browser. void OnRequestSelectionText(); @@ -833,12 +806,15 @@ class RenderView : public RenderWidget, // change but is overridden by tests. int delay_seconds_for_form_state_sync_; - // A set of audio renderers registered to use IPC for audio output. - IDMap<AudioRendererImpl> audio_renderers_; - // Maps pending callback IDs to their frames. IDMap<WebFrame> pending_extension_callbacks_; + scoped_refptr<AudioMessageFilter> audio_message_filter_; + + // The currently selected text. This is currently only updated on Linux, where + // it's for the selection clipboard. + std::string selection_text_; + DISALLOW_COPY_AND_ASSIGN(RenderView); }; diff --git a/chrome/renderer/renderer.vcproj b/chrome/renderer/renderer.vcproj index 56f9e82..5a388fd 100644 --- a/chrome/renderer/renderer.vcproj +++ b/chrome/renderer/renderer.vcproj @@ -222,6 +222,14 @@ > </File> <File + RelativePath=".\audio_message_filter.cc" + > + </File> + <File + RelativePath=".\audio_message_filter.h" + > + </File> + <File RelativePath=".\debug_message_handler.cc" > </File> diff --git a/chrome/renderer/webmediaplayer_delegate_impl.cc b/chrome/renderer/webmediaplayer_delegate_impl.cc index 5a0f1c2..d605a99 100644 --- a/chrome/renderer/webmediaplayer_delegate_impl.cc +++ b/chrome/renderer/webmediaplayer_delegate_impl.cc @@ -57,7 +57,6 @@ WebMediaPlayerDelegateImpl::WebMediaPlayerDelegateImpl(RenderView* view) ready_state_(webkit_glue::WebMediaPlayer::HAVE_NOTHING), main_loop_(NULL), filter_factory_(new media::FilterFactoryCollection()), - audio_renderer_(NULL), video_renderer_(NULL), data_source_(NULL), web_media_player_(NULL), @@ -70,7 +69,8 @@ WebMediaPlayerDelegateImpl::WebMediaPlayerDelegateImpl(RenderView* view) filter_factory_->AddFactory(media::FFmpegAudioDecoder::CreateFactory()); filter_factory_->AddFactory(media::FFmpegVideoDecoder::CreateFactory()); #endif - filter_factory_->AddFactory(AudioRendererImpl::CreateFactory(this)); + filter_factory_->AddFactory(AudioRendererImpl::CreateFactory( + view_->audio_message_filter())); filter_factory_->AddFactory(VideoRendererImpl::CreateFactory(this)); filter_factory_->AddFactory(DataSourceImpl::CreateFactory(this)); } @@ -315,15 +315,8 @@ void WebMediaPlayerDelegateImpl::DidInitializePipeline(bool successful) { &webkit_glue::WebMediaPlayer::NotifyReadyStateChange); } -void WebMediaPlayerDelegateImpl::SetAudioRenderer( - AudioRendererImpl* audio_renderer) { - DCHECK(!audio_renderer_); - audio_renderer_ = audio_renderer; -} - void WebMediaPlayerDelegateImpl::SetVideoRenderer( VideoRendererImpl* video_renderer) { - DCHECK(!video_renderer_); video_renderer_ = video_renderer; } @@ -373,11 +366,6 @@ void WebMediaPlayerDelegateImpl::StopPipeline(bool render_thread_is_dying) { // Instruct the renderers and data source to release all Renderer related // resources during destruction of render thread, because they won't have any // chance to release these resources on render thread by posting tasks on it. - if (audio_renderer_) { - audio_renderer_->ReleaseResources(render_thread_is_dying); - audio_renderer_ = NULL; - } - if (data_source_) { data_source_->ReleaseResources(render_thread_is_dying); data_source_ = NULL; diff --git a/chrome/renderer/webmediaplayer_delegate_impl.h b/chrome/renderer/webmediaplayer_delegate_impl.h index fc976bf..b104ee6 100644 --- a/chrome/renderer/webmediaplayer_delegate_impl.h +++ b/chrome/renderer/webmediaplayer_delegate_impl.h @@ -188,10 +188,6 @@ class WebMediaPlayerDelegateImpl : public webkit_glue::WebMediaPlayerDelegate, // the same lifetime as the pipeline. media::PipelineImpl pipeline_; - // Holds a pointer to the audio renderer so we can tell it to stop during - // render thread destruction. - scoped_refptr<AudioRendererImpl> audio_renderer_; - // We have the interface to VideoRenderer to delegate paint messages to it // from WebKit. scoped_refptr<VideoRendererImpl> video_renderer_; |