diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-10 18:53:39 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-10 18:53:39 +0000 |
commit | 43f55738f0922bc479ee00b5d3d3c264e080f512 (patch) | |
tree | 2d407c6501e6958fa0e98a25594568c859b9dd2f | |
parent | ac4425387548c5ee59348760784959fa841ece76 (diff) | |
download | chromium_src-43f55738f0922bc479ee00b5d3d3c264e080f512.zip chromium_src-43f55738f0922bc479ee00b5d3d3c264e080f512.tar.gz chromium_src-43f55738f0922bc479ee00b5d3d3c264e080f512.tar.bz2 |
Checking in default implementation of AudioRenderer interface, AudioRendererImpl.
Review URL: http://codereview.chromium.org/20123
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9489 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/build/media.vcproj | 12 | ||||
-rw-r--r-- | media/filters/audio_renderer_impl.cc | 205 | ||||
-rw-r--r-- | media/filters/audio_renderer_impl.h | 85 | ||||
-rw-r--r-- | media/media_lib.scons | 4 |
4 files changed, 306 insertions, 0 deletions
diff --git a/media/build/media.vcproj b/media/build/media.vcproj index 36e1395..c15fc81 100644 --- a/media/build/media.vcproj +++ b/media/build/media.vcproj @@ -186,6 +186,18 @@ </File> </Filter> <Filter + Name="filters" + > + <File + RelativePath="..\filters\audio_renderer_impl.cc" + > + </File> + <File + RelativePath="..\filters\audio_renderer_impl.h" + > + </File> + </Filter> + <Filter Name="audio" > <File diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc new file mode 100644 index 0000000..f17cce5 --- /dev/null +++ b/media/filters/audio_renderer_impl.cc @@ -0,0 +1,205 @@ +// 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 "media/base/filter_host.h" +#include "media/filters/audio_renderer_impl.h" + +namespace media { + +// The number of initial reads to perform for buffering. There should never +// be more than |kInitialReads| in the queue since we read only after we're +// finished with a buffer in the callback thread. +// +// This is sort of a magic number, but for 44.1kHz stereo audio this will give +// us enough data to fill approximately 4 complete callback buffers. +static const size_t kInitialReads = 16; + +// 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() + : decoder_(NULL), + stream_(NULL), + initialized_(false), + data_offset_(0) { +} + +AudioRendererImpl::~AudioRendererImpl() { + // Empty buffer queue (callback will simply keep exiting). + input_lock_.Acquire(); + while (!input_queue_.empty()) { + Buffer* buffer = input_queue_.front(); + input_queue_.pop_front(); + buffer->Release(); + } + input_lock_.Release(); + + // Close down the audio device. + if (stream_) { + stream_->Stop(); + stream_->Close(); + } +} + +bool AudioRendererImpl::IsMediaFormatSupported( + const MediaFormat* media_format) { + int channels; + int sample_rate; + int sample_bits; + return ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits); +} + +void AudioRendererImpl::Stop() { + DCHECK(stream_); + stream_->Stop(); +} + +void AudioRendererImpl::SetPlaybackRate(float playback_rate) { + DCHECK(stream_); + // TODO(scherkus): handle playback rates not equal to 1.0. + if (playback_rate == 1.0f) { + stream_->Start(this); + } else { + NOTIMPLEMENTED(); + } +} + +bool AudioRendererImpl::Initialize(AudioDecoder* decoder) { + decoder_ = decoder; + const MediaFormat* media_format = decoder_->GetMediaFormat(); + std::string mime_type; + int channels; + int sample_rate; + int sample_bits; + if (!ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits)) { + return false; + } + + // Create our audio stream. + stream_ = AudioManager::GetAudioManager()->MakeAudioStream( + AudioManager::AUDIO_PCM_LINEAR, channels, sample_rate, sample_bits); + DCHECK(stream_); + + // Calculate buffer size and open the stream. + size_t size = kSamplesPerBuffer * channels * sample_bits / 8; + if (!stream_->Open(size)) { + stream_->Close(); + stream_ = NULL; + return false; + } + + // Schedule our initial reads. + for (size_t i = 0; i < kInitialReads; ++i) { + ScheduleRead(); + } + + // Defer initialization until all scheduled reads have completed. + return true; +} + +void AudioRendererImpl::SetVolume(float volume) { + stream_->SetVolume(volume, volume); +} + +void AudioRendererImpl::OnAssignment(Buffer* buffer_in) { + AutoLock auto_lock(input_lock_); + buffer_in->AddRef(); + input_queue_.push_back(buffer_in); + DCHECK(input_queue_.size() <= kInitialReads); + + // See if we're finally initialized. + // TODO(scherkus): handle end of stream. + if (!initialized_ && input_queue_.size() == kInitialReads) { + initialized_ = true; + host_->InitializationComplete(); + } +} + +size_t AudioRendererImpl::OnMoreData(AudioOutputStream* stream, void* dest_void, + size_t len) { + // TODO(scherkus): handle end of stream. + DCHECK(stream_ == stream); + + // TODO(scherkus): maybe change interface to pass in char/uint8 or similar. + char* dest = reinterpret_cast<char*>(dest_void); + size_t result = 0; + + // Loop until the buffer has been filled. + while (len > 0) { + Buffer* buffer = NULL; + { + AutoLock auto_lock(input_lock_); + if (input_queue_.empty()) { + // TODO(scherkus): consider blocking here until more data arrives. + return result; + } + + // Access the front buffer. + buffer = input_queue_.front(); + } + + // Determine how much to copy. + const char* data = buffer->GetData() + data_offset_; + size_t data_len = buffer->GetDataSize() - data_offset_; + data_len = std::min(len, data_len); + + // Copy into buffer. + memcpy(dest, data, data_len); + len -= data_len; + dest += data_len; + data_offset_ += data_len; + result += data_len; + + // Check to see if we're finished with the front buffer. + if (data_offset_ == buffer->GetDataSize()) { + // Update the clock. + host_->SetTime(buffer->GetTimestamp()); + + // Dequeue the buffer. + { + AutoLock auto_lock(input_lock_); + input_queue_.pop_front(); + } + + // Release and request another buffer from the decoder. + buffer->Release(); + ScheduleRead(); + + // Reset our offset into the front buffer. + data_offset_ = 0; + } + } + return result; +} + +void AudioRendererImpl::OnClose(AudioOutputStream* stream) { + // TODO(scherkus): implement OnClose. + NOTIMPLEMENTED(); +} + +void AudioRendererImpl::OnError(AudioOutputStream* stream, int code) { + // TODO(scherkus): implement OnError. + NOTIMPLEMENTED(); +} + +// static +bool AudioRendererImpl::ParseMediaFormat(const MediaFormat* media_format, + int* channels_out, + int* sample_rate_out, + int* sample_bits_out) { + std::string mime_type; + return media_format->GetAsString(MediaFormat::kMimeType, &mime_type) && + media_format->GetAsInteger(MediaFormat::kChannels, channels_out) && + media_format->GetAsInteger(MediaFormat::kSampleRate, sample_rate_out) && + media_format->GetAsInteger(MediaFormat::kSampleBits, sample_bits_out) && + mime_type.compare(mime_type::kUncompressedAudio) == 0; +} + +void AudioRendererImpl::ScheduleRead() { + host_->PostTask(NewRunnableMethod(decoder_, &AudioDecoder::Read, + new AssignableBuffer<AudioRendererImpl, Buffer>(this))); +} + +} // namespace media diff --git a/media/filters/audio_renderer_impl.h b/media/filters/audio_renderer_impl.h new file mode 100644 index 0000000..0dd4bc0 --- /dev/null +++ b/media/filters/audio_renderer_impl.h @@ -0,0 +1,85 @@ +// 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. + +#ifndef MEDIA_FILTERS_AUDIO_RENDERER_IMPL_H_ +#define MEDIA_FILTERS_AUDIO_RENDERER_IMPL_H_ + +// This is the default implementation of AudioRenderer, which uses the audio +// interfaces to open an audio device. Although it cannot be used in the +// sandbox, it serves as a reference implementation and can be used in other +// applications such as the test player. + +#include <deque> + +#include "base/lock.h" +#include "media/audio/audio_output.h" +#include "media/base/buffers.h" +#include "media/base/factory.h" +#include "media/base/filters.h" + +namespace media { + +class AudioRendererImpl : public AudioRenderer, + public AudioOutputStream::AudioSourceCallback { + public: + static FilterFactory* CreateFilterFactory() { + return new FilterFactoryImpl0<AudioRendererImpl>(); + } + + static bool IsMediaFormatSupported(const MediaFormat* media_format); + + // MediaFilter implementation. + virtual void Stop(); + virtual void SetPlaybackRate(float playback_rate); + + // AudioRenderer implementation. + virtual bool Initialize(AudioDecoder* decoder); + virtual void SetVolume(float volume); + + // AssignableBuffer<AudioRendererImpl, BufferInterface> implementation. + void OnAssignment(Buffer* buffer_in); + + // AudioSourceCallback implementation. + virtual size_t OnMoreData(AudioOutputStream* stream, void* dest, size_t len); + virtual void OnClose(AudioOutputStream* stream); + virtual void OnError(AudioOutputStream* stream, int code); + + private: + friend class FilterFactoryImpl0<AudioRendererImpl>; + AudioRendererImpl(); + virtual ~AudioRendererImpl(); + + // Helper to parse a media format and return whether we were successful + // retrieving all the information we care about. + static bool ParseMediaFormat(const MediaFormat* media_format, + int* channels_out, int* sample_rate_out, + int* sample_bits_out); + + // Posts a task on the pipeline thread to read a sample from the decoder. + // Safe to call on any thread. + void ScheduleRead(); + + // Audio decoder. + AudioDecoder* decoder_; + + // Audio output stream device. + AudioOutputStream* stream_; + + // Whether or not we have initialized. + bool initialized_; + + // Queued audio data. + typedef std::deque<Buffer*> BufferQueue; + BufferQueue input_queue_; + Lock input_lock_; + + // Holds any remaining audio data that couldn't fit into the callback buffer. + size_t data_offset_; + + DISALLOW_COPY_AND_ASSIGN(AudioRendererImpl); +}; + +} // namespace media + +#endif // MEDIA_FILTERS_AUDIO_RENDERER_IMPL_H_ diff --git a/media/media_lib.scons b/media/media_lib.scons index bb5b7a4..0e017b1 100644 --- a/media/media_lib.scons +++ b/media/media_lib.scons @@ -41,6 +41,10 @@ input_files = ChromeFileList([ 'base/synchronizer.cc', 'base/synchronizer.h', ]), + MSVSFilter('filters', [ + 'filters/audio_renderer_impl.cc', + 'filters/audio_renderer_impl.h', + ]), MSVSFilter('audio', [ 'audio/win/audio_manager_win.h', 'audio/audio_output.h', |