diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-10 22:40:31 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-10 22:40:31 +0000 |
commit | 8db216ee756d4e06fbd05676b045784da3a5928c (patch) | |
tree | 36b7bf2b42bf6ccb1fab70cfbe35dd29514c9cb7 /chrome/renderer/media | |
parent | e00e0cc2284c3a8e0b74841ace6b9dad9bd1df94 (diff) | |
download | chromium_src-8db216ee756d4e06fbd05676b045784da3a5928c.zip chromium_src-8db216ee756d4e06fbd05676b045784da3a5928c.tar.gz chromium_src-8db216ee756d4e06fbd05676b045784da3a5928c.tar.bz2 |
Implemented AudioRendererImpl in renderer process using API
provided by RenderView for accessing audio device in the
browser using IPC, subclassing from media::AudioRendererBase
for buffer filling.
Review URL: http://codereview.chromium.org/28081
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11392 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/media')
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.cc | 150 | ||||
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.h | 163 |
2 files changed, 279 insertions, 34 deletions
diff --git a/chrome/renderer/media/audio_renderer_impl.cc b/chrome/renderer/media/audio_renderer_impl.cc index 9dbd392..5df76ba 100644 --- a/chrome/renderer/media/audio_renderer_impl.cc +++ b/chrome/renderer/media/audio_renderer_impl.cc @@ -3,50 +3,160 @@ // LICENSE file. #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 +// data for a 44.1kHz audio source. +static const size_t kSamplesPerBuffer = 4096; AudioRendererImpl::AudioRendererImpl(WebMediaPlayerDelegateImpl* delegate) - : delegate_(delegate) { + : AudioRendererBase(kDefaultMaxQueueSize), + delegate_(delegate), + 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); } AudioRendererImpl::~AudioRendererImpl() { } -void AudioRendererImpl::Stop() { - // TODO(scherkus): implement Stop. - NOTIMPLEMENTED(); +bool AudioRendererImpl::IsMediaFormatSupported( + const media::MediaFormat* media_format) { + int channels; + int sample_rate; + int sample_bits; + return ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits); } -bool AudioRendererImpl::Initialize(media::AudioDecoder* decoder) { - // TODO(scherkus): implement Initialize. - NOTIMPLEMENTED(); - return false; +bool AudioRendererImpl::OnInitialize(const media::MediaFormat* media_format) { + // Parse integer values in MediaFormat. + int channels; + int sample_rate; + int sample_bits; + if (!ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits)) { + return false; + } + + // 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, + AudioManager::AUDIO_PCM_LINEAR, channels, sample_rate, sample_bits, + packet_size)); + return true; } -void AudioRendererImpl::SetVolume(float volume) { - // TODO(scherkus): implement SetVolume. - NOTIMPLEMENTED(); +void AudioRendererImpl::OnStop() { + if (!resource_release_event_.IsSignaled()) { + render_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::ReleaseRendererResources)); + resource_release_event_.Wait(); + } } -bool AudioRendererImpl::IsMediaFormatSupported( - const media::MediaFormat* format) { - // TODO(hclam): check the format correct. - return true; +void AudioRendererImpl::OnAssignment(media::Buffer* buffer_in) { + // Use the base class to queue the buffer. + AudioRendererBase::OnAssignment(buffer_in); + // Post a task to render thread to notify a packet reception. + render_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &AudioRendererImpl::OnNotifyAudioPacketReady)); } -void AudioRendererImpl::OnRequestPacket() { - // TODO(hclam): implement this. +void AudioRendererImpl::SetPlaybackRate(float rate) { + // 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 + // in the browser process, it seems there's nothing to do here. + } else { + NOTIMPLEMENTED(); + } +} + +void AudioRendererImpl::SetVolume(float volume) { + // TODO(hclam): change this to multichannel if possible. + render_loop_->PostTask(FROM_HERE, + NewRunnableMethod( + this, &AudioRendererImpl::OnSetAudioVolume, volume, volume)); } void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle, size_t length) { - // TODO(hclam): implement this. + shared_memory_.reset(new base::SharedMemory(handle, false)); + shared_memory_size_ = length; + // TODO(hclam): is there any better place to do this? + OnStartAudioStream(); +} + +void AudioRendererImpl::OnRequestPacket() { + packet_requested_ = true; } void AudioRendererImpl::OnStateChanged(AudioOutputStream::State state, int info) { - // TODO(hclam): implement this. + switch (state) { + case AudioOutputStream::STATE_ERROR: + host_->Error(media::PIPELINE_ERROR_AUDIO_HARDWARE); + break; + // TODO(hclam): handle these events. + case AudioOutputStream::STATE_STARTED: + case AudioOutputStream::STATE_PAUSED: + break; + default: + NOTREACHED(); + break; + } } void AudioRendererImpl::OnVolume(double left, double right) { - // TODO(hclam): implement this. + // TODO(hclam): decide whether we need to report the current volume to + // pipeline. +} + +void AudioRendererImpl::ReleaseRendererResources() { + OnCloseAudioStream(); + resource_release_event_.Signal(); +} + +void AudioRendererImpl::OnCreateAudioStream( + 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); +} + +void AudioRendererImpl::OnStartAudioStream() { + delegate_->view()->StartAudioStream(stream_id_); +} + +void AudioRendererImpl::OnCloseAudioStream() { + // Unregister ourself from RenderView, we will not be called anymore. + delegate_->view()->CloseAudioStream(stream_id_); +} + +void AudioRendererImpl::OnSetAudioVolume(double left, double right) { + delegate_->view()->SetAudioVolume(stream_id_, left, right); +} + +void AudioRendererImpl::OnNotifyAudioPacketReady() { + if (packet_requested_) { + DCHECK(shared_memory_.get()); + // Fill into the shared memory. + size_t filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()), + shared_memory_size_); + packet_requested_ = false; + // Then tell browser process we are done filling into the buffer. + delegate_->view()->NotifyAudioPacketReady(stream_id_, filled); + } +} + +const media::MediaFormat* AudioRendererImpl::GetMediaFormat() { + return &media_format_; } diff --git a/chrome/renderer/media/audio_renderer_impl.h b/chrome/renderer/media/audio_renderer_impl.h index 9d6b0b4..c0a8257 100644 --- a/chrome/renderer/media/audio_renderer_impl.h +++ b/chrome/renderer/media/audio_renderer_impl.h @@ -1,49 +1,184 @@ // 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. +// +// Audio rendering unit utilizing audio output stream provided by browser +// process through IPC. +// +// Relationship of classes. +// +// AudioRendererHost AudioRendererImpl +// ^ ^ +// | | +// v IPC v +// ResourceMessageFilter <---------> RenderView +// +// 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. +// +// Transportation of audio buffer is done by using shared memory, after +// OnCreateAudioStream 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. +// 2. Pipeline thread +// Initialization of filter and proper stopping of filters happens here. +// Properties of this filter is also set in this thread. +// 3. Audio decoder thread (If there's one.) +// Responsible for decoding audio data and gives raw PCM data to this object. +// +// Methods categorized according to the thread(s) they are running on. +// +// 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(). +// |-- OnRequestPacket() +// | Called from RenderView 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. +// |-- OnCreated() +// | Called from RenderView 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. +// \-- ReleaseRendererResource() +// Release resources that live inside render thread. +// +// Pipeline thread +// +-- AudioRendererImpl() +// | Constructor method. +// |-- ~AudioRendererImpl() +// | Destructor method. +// |-- SetPlaybackRate() +// | Given the playback rate information. +// |-- GetMediaFormat() +// | Obtain the current media format of this unit. +// |-- SetVolume() +// | Given the volume information. +// |-- OnInitialize() +// | Called from AudioRendererBase for initialization event. +// \-- OnStop() +// Called from AudioRendererBase for stop event. +// +// Audio decoder thread (If there's one.) +// \-- OnAssignment() +// A raw PCM audio packet buffer is recevied here, this method is called +// from pipeline thread if audio decoder thread does not exist. #ifndef CHROME_RENDERER_MEDIA_AUDIO_RENDERER_IMPL_H_ #define CHROME_RENDERER_MEDIA_AUDIO_RENDERER_IMPL_H_ #include "base/shared_memory.h" +#include "base/waitable_event.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 AudioRendererImpl : public media::AudioRenderer { +class AudioRendererImpl : public media::AudioRendererBase { public: - AudioRendererImpl(WebMediaPlayerDelegateImpl* delegate); - - // media::MediaFilter implementation. - virtual void Stop(); - - // media::AudioRenderer implementation. - virtual bool Initialize(media::AudioDecoder* decoder); - virtual void SetVolume(float volume); - - // Static method for creating factory for this object. + // Methods called on render thread ------------------------------------------ + // Methods called during construction. static media::FilterFactory* CreateFactory( WebMediaPlayerDelegateImpl* delegate) { return new media::FilterFactoryImpl1<AudioRendererImpl, WebMediaPlayerDelegateImpl*>(delegate); } - - // Answers question from the factory to see if we accept |format|. static bool IsMediaFormatSupported(const media::MediaFormat* format); + // Methods call from RenderView when audio related IPC messages are received + // from browser process. 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. + void ReleaseRendererResources(); + + // Methods called on pipeline thread ---------------------------------------- + // media::MediaFilter implementation. + virtual void SetPlaybackRate(float rate); + const media::MediaFormat* GetMediaFormat(); + + // media::AudioRenderer implementation. + virtual void SetVolume(float volume); + + // AssignableBuffer<AudioRendererBase, BufferInterface> implementation. + virtual void OnAssignment(media::Buffer* buffer_in); + protected: - virtual ~AudioRendererImpl(); + // Methods called on audio renderer thread ---------------------------------- + // These methods are called from AudioRendererBase. + virtual bool OnInitialize(const media::MediaFormat* media_format); + virtual void OnStop(); private: + friend class media::FilterFactoryImpl1<AudioRendererImpl, + WebMediaPlayerDelegateImpl*>; + + explicit AudioRendererImpl(WebMediaPlayerDelegateImpl* delegate); + 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_; + // A map of media format information. + media::MediaFormat media_format_; + + // ID of the stream created in the browser process. + int32 stream_id_; + + // Memory shared by the browser process for audio buffer. + 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_; + + // Event for releasing resources that live in render thread. + base::WaitableEvent resource_release_event_; + DISALLOW_COPY_AND_ASSIGN(AudioRendererImpl); }; |