diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 19:06:49 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 19:06:49 +0000 |
commit | 9c32098368e6df8b1c80c5da20131db25b422d40 (patch) | |
tree | 86ddf9f4f2b8d0beea3a46fbf2d779b04afdb3ef | |
parent | ffbdb354dc57a938943478fd391a7cc49b4f8649 (diff) | |
download | chromium_src-9c32098368e6df8b1c80c5da20131db25b422d40.zip chromium_src-9c32098368e6df8b1c80c5da20131db25b422d40.tar.gz chromium_src-9c32098368e6df8b1c80c5da20131db25b422d40.tar.bz2 |
AudioController to perform audio operations on a separate thread
Added AudioController as a wrapper over AudioOutputStream to operate methods of
AudioOutputStream on a separate thread managed by AudioController. This way most
of the audio operations will be non-blocking.
Next step is to modify AudioRendererHost to use AudioController.
TEST=media_unittests --gtest_filter=AudioControllerTest.*
BUG=39885
Review URL: http://codereview.chromium.org/2477005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49079 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/renderer_host/audio_renderer_host.cc | 8 | ||||
-rw-r--r-- | media/audio/audio_controller.cc | 329 | ||||
-rw-r--r-- | media/audio/audio_controller.h | 202 | ||||
-rw-r--r-- | media/audio/audio_controller_unittest.cc | 164 | ||||
-rw-r--r-- | media/audio/simple_sources.cc | 4 | ||||
-rw-r--r-- | media/audio/simple_sources.h | 5 | ||||
-rw-r--r-- | media/media.gyp | 3 |
7 files changed, 705 insertions, 10 deletions
diff --git a/chrome/browser/renderer_host/audio_renderer_host.cc b/chrome/browser/renderer_host/audio_renderer_host.cc index 0fbc5e6..4d3226c 100644 --- a/chrome/browser/renderer_host/audio_renderer_host.cc +++ b/chrome/browser/renderer_host/audio_renderer_host.cc @@ -280,7 +280,7 @@ void AudioRendererHost::IPCAudioSource::Flush() { if (state_ != kPaused) return; - // The following operation is atomic in PushSource so we don't need to lock. + AutoLock auto_lock(lock_); push_source_.ClearAll(); } @@ -351,10 +351,12 @@ uint32 AudioRendererHost::IPCAudioSource::OnMoreData(AudioOutputStream* stream, void AudioRendererHost::IPCAudioSource::OnClose(AudioOutputStream* stream) { // Push source doesn't need to know the stream so just pass in NULL. - if (!shared_socket_.get()) + if (!shared_socket_.get()) { + AutoLock auto_lock(lock_); push_source_.OnClose(NULL); - else + } else { shared_socket_->Close(); + } } void AudioRendererHost::IPCAudioSource::OnError(AudioOutputStream* stream, diff --git a/media/audio/audio_controller.cc b/media/audio/audio_controller.cc new file mode 100644 index 0000000..8e9357b --- /dev/null +++ b/media/audio/audio_controller.cc @@ -0,0 +1,329 @@ +// Copyright (c) 2010 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/audio/audio_controller.h" + +// This constant governs the hardware audio buffer size, this value should be +// choosen carefully and is platform specific. +static const int kSamplesPerHardwarePacket = 8192; + +static const uint32 kMegabytes = 1024 * 1024; + +// The following parameters limit the request buffer and packet size from the +// renderer to avoid renderer from requesting too much memory. +static const uint32 kMaxDecodedPacketSize = 2 * kMegabytes; +static const uint32 kMaxBufferCapacity = 5 * kMegabytes; +static const int kMaxChannels = 32; +static const int kMaxBitsPerSample = 64; +static const int kMaxSampleRate = 192000; + +// Return true if the parameters for creating an audio stream is valid. +// Return false otherwise. +static bool CheckParameters(int channels, int sample_rate, + int bits_per_sample) { + if (channels <= 0 || channels > kMaxChannels) + return false; + if (sample_rate <= 0 || sample_rate > kMaxSampleRate) + return false; + if (bits_per_sample <= 0 || bits_per_sample > kMaxBitsPerSample) + return false; + return true; +} + +namespace media { + +AudioController::AudioController(EventHandler* handler, uint32 capacity, + SyncReader* sync_reader) + : handler_(handler), + state_(kCreated), + hardware_pending_bytes_(0), + buffer_capacity_(capacity), + sync_reader_(sync_reader), + thread_("AudioControllerThread") { +} + +AudioController::~AudioController() { + DCHECK(kClosed == state_ || kCreated == state_); +} + +// static +scoped_refptr<AudioController> AudioController::Create( + EventHandler* event_handler, + AudioManager::Format format, + int channels, + int sample_rate, + int bits_per_sample, + uint32 buffer_capacity) { + + if (!CheckParameters(channels, sample_rate, bits_per_sample)) + return NULL; + + // Starts the audio controller thread. + scoped_refptr<AudioController> source = new AudioController( + event_handler, buffer_capacity, NULL); + + // Start the audio controller thread and post a task to create the + // audio stream. + source->thread_.Start(); + source->thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(source.get(), &AudioController::DoCreate, + format, channels, sample_rate, bits_per_sample)); + return source; +} + +// static +scoped_refptr<AudioController> AudioController::CreateLowLatency( + EventHandler* event_handler, + AudioManager::Format format, + int channels, + int sample_rate, + int bits_per_sample, + SyncReader* sync_reader) { + + DCHECK(sync_reader); + + if (!CheckParameters(channels, sample_rate, bits_per_sample)) + return NULL; + + // Starts the audio controller thread. + scoped_refptr<AudioController> source = new AudioController( + event_handler, 0, sync_reader); + + // Start the audio controller thread and post a task to create the + // audio stream. + source->thread_.Start(); + source->thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(source.get(), &AudioController::DoCreate, + format, channels, sample_rate, bits_per_sample)); + return source; +} + +void AudioController::Play() { + DCHECK(thread_.IsRunning()); + thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioController::DoPlay)); +} + +void AudioController::Pause() { + DCHECK(thread_.IsRunning()); + thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioController::DoPause)); +} + +void AudioController::Flush() { + DCHECK(thread_.IsRunning()); + thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioController::DoFlush)); +} + +void AudioController::Close() { + DCHECK(thread_.IsRunning()); + thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioController::DoClose)); + thread_.Stop(); +} + +void AudioController::SetVolume(double volume) { + DCHECK(thread_.IsRunning()); + thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioController::DoSetVolume, volume)); +} + +void AudioController::EnqueueData(const uint8* data, uint32 size) { + // Write data to the push source and ask for more data if needed. + AutoLock auto_lock(lock_); + push_source_.Write(data, size); + SubmitOnMoreData_Locked(); +} + +void AudioController::DoCreate(AudioManager::Format format, int channels, + int sample_rate, int bits_per_sample) { + // Create the stream in the first place. + stream_ = AudioManager::GetAudioManager()->MakeAudioStream( + format, channels, sample_rate, bits_per_sample); + + if (!stream_) { + // TODO(hclam): Define error types. + handler_->OnError(this, 0); + return; + } + + uint32 hardware_packet_size = kSamplesPerHardwarePacket * channels * + bits_per_sample / 8; + if (stream_ && !stream_->Open(hardware_packet_size)) { + stream_->Close(); + stream_ = NULL; + + // TODO(hclam): Define error types. + handler_->OnError(this, 0); + return; + } + handler_->OnCreated(this); +} + +void AudioController::DoPlay() { + DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + + // We can start from created or paused state. + if (state_ != kCreated && state_ != kPaused) + return; + + State old_state; + // Update the |state_| to kPlaying. + { + AutoLock auto_lock(lock_); + old_state = state_; + state_ = kPlaying; + } + + // We start the AudioOutputStream lazily. + if (old_state == kCreated) { + stream_->Start(this); + } + + // Tell the event handler that we are now playing. + handler_->OnPlaying(this); +} + +void AudioController::DoPause() { + DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + + // We can pause from started state. + if (state_ != kPlaying) + return; + + // Sets the |state_| to kPaused so we don't draw more audio data. + // TODO(hclam): Actually pause the audio device. + { + AutoLock auto_lock(lock_); + state_ = kPaused; + } + + handler_->OnPaused(this); +} + +void AudioController::DoFlush() { + DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + + if (state_ != kPaused) + return; + + // TODO(hclam): Actually flush the audio device. + + // If we are in the regular latency mode then flush the push source. + if (!sync_reader_) { + AutoLock auto_lock(lock_); + push_source_.ClearAll(); + } +} + +void AudioController::DoClose() { + DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + DCHECK_NE(kClosed, state_); + + // |stream_| can be null if creating the device failed in DoCreate(). + if (stream_) { + stream_->Stop(); + stream_->Close(); + // After stream is closed it is destroyed, so don't keep a reference to it. + stream_ = NULL; + } + + // If we are in low latency mode then also close the SyncReader. + // TODO(hclam): The shutdown procedure for low latency mode if not complete, + // especially when OnModeData() is blocked on SyncReader for read and the + // above Stop() would deadlock. + if (sync_reader_) + sync_reader_->Close(); + + // Update the current state. Since the stream is closed at this point + // there's no other threads reading |state_| so we don't need to lock. + state_ = kClosed; +} + +void AudioController::DoSetVolume(double volume) { + DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + + if (state_ == kError || state_ == kEmpty) + return; + + stream_->SetVolume(volume); +} + +void AudioController::DoReportError(int code) { + DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + handler_->OnError(this, code); +} + +uint32 AudioController::OnMoreData(AudioOutputStream* stream, + void* dest, + uint32 max_size, + uint32 pending_bytes) { + // If regular latency mode is used. + if (!sync_reader_) { + AutoLock auto_lock(lock_); + + // Record the callback time. + last_callback_time_ = base::Time::Now(); + + if (state_ != kPlaying) { + // Don't read anything. Save the number of bytes in the hardware buffer. + hardware_pending_bytes_ = pending_bytes; + return 0; + } + + // Push source doesn't need to know the stream and number of pending bytes. + // So just pass in NULL and 0. + uint32 size = push_source_.OnMoreData(NULL, dest, max_size, 0); + hardware_pending_bytes_ = pending_bytes + size; + SubmitOnMoreData_Locked(); + return size; + } + + // Low latency mode. + uint32 size = sync_reader_->Read(dest, max_size); + sync_reader_->UpdatePendingBytes(pending_bytes + size); + return size; +} + +void AudioController::OnClose(AudioOutputStream* stream) { + // Push source doesn't need to know the stream so just pass in NULL. + if (!sync_reader_) { + AutoLock auto_lock(lock_); + push_source_.OnClose(NULL); + } +} + +void AudioController::OnError(AudioOutputStream* stream, int code) { + // Handle error on the audio controller thread. + thread_.message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &AudioController::DoReportError, code)); +} + +void AudioController::SubmitOnMoreData_Locked() { + lock_.AssertAcquired(); + + if (push_source_.UnProcessedBytes() > buffer_capacity_) + return; + + base::Time timestamp = last_callback_time_; + uint32 pending_bytes = hardware_pending_bytes_ + + push_source_.UnProcessedBytes(); + + // If we need more data then call the event handler to ask for more data. + // It is okay that we don't lock in this block because the parameters are + // correct and in the worst case we are just asking more data than needed. + AutoUnlock auto_unlock(lock_); + handler_->OnMoreData(this, timestamp, pending_bytes); +} + +} // namespace media diff --git a/media/audio/audio_controller.h b/media/audio/audio_controller.h new file mode 100644 index 0000000..dae3d58 --- /dev/null +++ b/media/audio/audio_controller.h @@ -0,0 +1,202 @@ +// Copyright (c) 2010 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_AUDIO_AUDIO_CONTROLLER_H_ +#define MEDIA_AUDIO_AUDIO_CONTROLLER_H_ + +#include "base/lock.h" +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/thread.h" +#include "base/time.h" +#include "media/audio/audio_output.h" +#include "media/audio/simple_sources.h" + +// An AudioController controls an AudioOutputStream and provides data +// to this output stream. It has an important function that it executes +// audio operations like play, pause, stop, etc. on a separate thread, +// namely the audio controller thread. +// +// All the public methods of AudioController are non-blocking except close, +// the actual operations are performed on the audio controller thread. +// +// Here is a state diagram for the AudioController: +// +// .----> [ Closed / Error ] <------. +// | ^ | +// | | | +// [ Created ] --> [ Playing ] --> [ Paused ] +// ^ ^ | +// | | | +// *[ Empty ] `-----------------' +// +// * Initial state +// +// There are two modes of buffering operations supported by this class. +// +// Regular latency mode: +// In this mode we receive signals from AudioController and then we +// enqueue data into it. +// +// Low latency mode: +// In this mode a DataSource object is given to the AudioController +// and AudioController reads from it synchronously. +// +namespace media { + +class AudioController : public base::RefCountedThreadSafe<AudioController>, + public AudioOutputStream::AudioSourceCallback { + public: + // Internal state of the source. + enum State { + kEmpty, + kCreated, + kPlaying, + kPaused, + kClosed, + kError, + }; + + // An event handler that receives events from the AudioController. The + // following methods are called on the audio controller thread. + class EventHandler { + public: + virtual ~EventHandler() {} + virtual void OnCreated(AudioController* controller) = 0; + virtual void OnPlaying(AudioController* controller) = 0; + virtual void OnPaused(AudioController* controller) = 0; + virtual void OnError(AudioController* controller, int error_code) = 0; + + // Audio controller asks for more data. + // |pending_bytes| is the number of bytes still on the controller. + // |timestamp| is then time when |pending_bytes| is recorded. + virtual void OnMoreData(AudioController* controller, + base::Time timestamp, + uint32 pending_bytes) = 0; + }; + + // A synchronous reader interface used by AudioController for synchronous + // reading. + class SyncReader { + public: + virtual ~SyncReader() {} + + // Notify the synchronous reader the number of bytes in the AudioController + // not yet played. This is used by SyncReader to prepare more data and + // perform synchronization. + virtual void UpdatePendingBytes(uint32 bytes) = 0; + + // Read certain amount of data into |data|. This method returns if some + // data is available. + virtual uint32 Read(void* data, uint32 size) = 0; + + // Close this synchronous reader. + virtual void Close() = 0; + }; + + virtual ~AudioController(); + + // Factory method for creating an AudioController, returns NULL if failed. + // If successful, an audio controller thread is created. The audio device + // will be created on the audio controller thread and when that is done + // event handler will receive a OnCreated() call. + static scoped_refptr<AudioController> Create( + EventHandler* event_handler, + AudioManager::Format format, // Format of the stream. + int channels, // Number of channels. + int sample_rate, // Sampling frequency/rate. + int bits_per_sample, // Number of bits per sample. + + // Soft limit for buffer capacity in this controller. This parameter + // is used only in regular latency mode. + uint32 buffer_capacity); + + // Factory method for creating a low latency audio stream. + static scoped_refptr<AudioController> CreateLowLatency( + EventHandler* event_handler, + AudioManager::Format format, // Format of the stream. + int channels, // Number of channels. + int sample_rate, // Sampling frequency/rate. + int bits_per_sample, // Number of bits per sample. + + // External synchronous reader for audio controller. + SyncReader* sync_reader); + + // Methods to control playback of the stream. + + // Starts the playback of this audio output stream. + void Play(); + + // Pause this audio output stream. + void Pause(); + + // Discard all audio data buffered in this output stream. This method only + // has effect when the stream is paused. + void Flush(); + + // Closes the audio output stream and shutdown the audio controller thread. + // This method returns only after all operations are completed. This + // controller cannot be used after this method is called. + void Close(); + + // Sets the volume of the audio output stream. + void SetVolume(double volume); + + // Enqueue audio |data| into the controller. This method is used only in + // the regular latency mode and it is illegal to call this method when + // SyncReader is present. + void EnqueueData(const uint8* data, uint32 size); + + /////////////////////////////////////////////////////////////////////////// + // AudioSourceCallback methods. + virtual uint32 OnMoreData(AudioOutputStream* stream, void* dest, + uint32 max_size, uint32 pending_bytes); + virtual void OnClose(AudioOutputStream* stream); + virtual void OnError(AudioOutputStream* stream, int code); + + private: + AudioController(EventHandler* handler, + uint32 capacity, SyncReader* sync_reader); + + // The following methods are executed on the audio controller thread. + void DoCreate(AudioManager::Format format, int channels, + int sample_rate, int bits_per_sample); + void DoPlay(); + void DoPause(); + void DoFlush(); + void DoClose(); + void DoSetVolume(double volume); + void DoReportError(int code); + + // Helper method to submit a OnMoreData() call to the event handler. + void SubmitOnMoreData_Locked(); + + EventHandler* handler_; + AudioOutputStream* stream_; + + // |state_| is written on the audio controller thread and is read on the + // hardware audio thread. These operations need to be locked. But lock + // is not required for reading on the audio controller thread. + State state_; + + uint32 hardware_pending_bytes_; + base::Time last_callback_time_; + Lock lock_; + + // PushSource role is to buffer and it's only used in regular latency mode. + PushSource push_source_; + uint32 buffer_capacity_; + + // SyncReader is used only in low latency mode for synchronous reading. + SyncReader* sync_reader_; + + // The audio controller thread that this object runs on. + base::Thread thread_; + + DISALLOW_COPY_AND_ASSIGN(AudioController); +}; + +} // namespace media + +#endif // MEDIA_AUDIO_AUDIO_CONTROLLER_H_ diff --git a/media/audio/audio_controller_unittest.cc b/media/audio/audio_controller_unittest.cc new file mode 100644 index 0000000..5c5a522 --- /dev/null +++ b/media/audio/audio_controller_unittest.cc @@ -0,0 +1,164 @@ +// Copyright (c) 2010 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/env_var.h" +#include "base/basictypes.h" +#include "base/waitable_event.h" +#include "media/audio/audio_controller.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Exactly; +using ::testing::InvokeWithoutArgs; +using ::testing::NotNull; + +namespace media { + +class MockAudioControllerEventHandler : public AudioController::EventHandler { + public: + MockAudioControllerEventHandler() {} + + MOCK_METHOD1(OnCreated, void(AudioController* controller)); + MOCK_METHOD1(OnPlaying, void(AudioController* controller)); + MOCK_METHOD1(OnPaused, void(AudioController* controller)); + MOCK_METHOD2(OnError, void(AudioController* controller, int error_code)); + MOCK_METHOD3(OnMoreData, + void(AudioController* controller, + base::Time timestamp, uint32 pending_bytes)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockAudioControllerEventHandler); +}; + +class MockAudioControllerSyncReader : public AudioController::SyncReader { + public: + MockAudioControllerSyncReader() {} + + MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes)); + MOCK_METHOD2(Read, uint32(void* data, uint32 size)); + MOCK_METHOD0(Close, void()); + + private: + DISALLOW_COPY_AND_ASSIGN(MockAudioControllerSyncReader); +}; + +static bool HasAudioDevices() { + AudioManager* audio_man = AudioManager::GetAudioManager(); + CHECK(audio_man); + return audio_man->HasAudioDevices(); +} + +static bool IsRunningHeadless() { + scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create()); + if (env->HasEnv("CHROME_HEADLESS")) + return true; + return false; +} + +ACTION_P3(SignalEvent, event, count, limit) { + if (++*count >= limit) { + event->Signal(); + } +} + +TEST(AudioControllerTest, PlayAndClose) { + if (!HasAudioDevices() || IsRunningHeadless()) + return; + + MockAudioControllerEventHandler event_handler; + base::WaitableEvent event(false, false); + int count = 0; + + // If OnCreated is called then signal the event. + EXPECT_CALL(event_handler, OnCreated(NotNull())) + .WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal)); + + // OnPlaying() will be called only once. + EXPECT_CALL(event_handler, OnPlaying(NotNull())) + .Times(Exactly(1)); + + // If OnMoreData is called enough then signal the event. + EXPECT_CALL(event_handler, OnMoreData(NotNull(), _, 0)) + .Times(AtLeast(10)) + .WillRepeatedly(SignalEvent(&event, &count, 10)); + + scoped_refptr<AudioController> controller = AudioController::Create( + &event_handler, AudioManager::AUDIO_PCM_LINEAR, 1, + AudioManager::kAudioCDSampleRate, 16, 4096); + ASSERT_TRUE(controller.get()); + + // Wait for OnCreated() to be called. + event.Wait(); + event.Reset(); + + // Play and then wait for the event to be signaled. + controller->Play(); + event.Wait(); + + // Now stop the controller. This should shutdown the internal + // thread and we hold the only reference to it. + controller->Close(); + + // TODO(hclam): Make sure releasing the reference to this + // object actually destruct it. + controller = NULL; +} + +TEST(AudioControllerTest, PlayPauseClose) { + if (!HasAudioDevices() || IsRunningHeadless()) + return; + + MockAudioControllerEventHandler event_handler; + base::WaitableEvent event(false, false); + int count = 0; + + // If OnCreated is called then signal the event. + EXPECT_CALL(event_handler, OnCreated(NotNull())) + .Times(Exactly(1)) + .WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal)); + + // OnPlaying() will be called only once. + EXPECT_CALL(event_handler, OnPlaying(NotNull())) + .Times(Exactly(1)); + + // If OnMoreData is called enough then signal the event. + EXPECT_CALL(event_handler, OnMoreData(NotNull(), _, 0)) + .Times(AtLeast(10)) + .WillRepeatedly(SignalEvent(&event, &count, 10)); + + // And then OnPaused() will be called. + EXPECT_CALL(event_handler, OnPaused(NotNull())) + .Times(Exactly(1)) + .WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal)); + + scoped_refptr<AudioController> controller = AudioController::Create( + &event_handler, AudioManager::AUDIO_PCM_LINEAR, 1, + AudioManager::kAudioCDSampleRate, 16, 4096); + ASSERT_TRUE(controller.get()); + + // Wait for OnCreated() to be called. + event.Wait(); + event.Reset(); + + // Play and then wait for the event to be signaled. + controller->Play(); + event.Wait(); + event.Reset(); + + // And then wait for pause to complete. + controller->Pause(); + event.Wait(); + + // Now stop the controller. This should shutdown the internal + // thread and we hold the only reference to it. + controller->Close(); + + // TODO(hclam): Make sure releasing the reference to this + // object actually destruct it. + controller = NULL; +} + +} // namespace media diff --git a/media/audio/simple_sources.cc b/media/audio/simple_sources.cc index 4b2ce29..d1669daa 100644 --- a/media/audio/simple_sources.cc +++ b/media/audio/simple_sources.cc @@ -60,7 +60,6 @@ PushSource::~PushSource() { } uint32 PushSource::OnMoreData(AudioOutputStream* stream, void* dest, uint32 max_size, uint32 pending_bytes) { - AutoLock auto_lock(buffer_lock_); return buffer_.Read(static_cast<uint8*>(dest), max_size); } @@ -78,13 +77,11 @@ bool PushSource::Write(const void *data, uint32 len) { NOTREACHED(); return false; } - AutoLock auto_lock(buffer_lock_); buffer_.Append(static_cast<const uint8*>(data), len); return true; } uint32 PushSource::UnProcessedBytes() { - AutoLock auto_lock(buffer_lock_); return buffer_.forward_bytes(); } @@ -94,6 +91,5 @@ void PushSource::ClearAll() { } void PushSource::CleanUp() { - AutoLock auto_lock(buffer_lock_); buffer_.Clear(); } diff --git a/media/audio/simple_sources.h b/media/audio/simple_sources.h index 0ab457b..5c7765c 100644 --- a/media/audio/simple_sources.h +++ b/media/audio/simple_sources.h @@ -56,10 +56,11 @@ class PushAudioOutput { // A fairly basic class to connect a push model provider PushAudioOutput to // a pull model provider AudioSourceCallback. Fundamentally it manages a series // of audio buffers and is unaware of the actual audio format. +// Note that the PushSource is not thread safe and user need to provide locking. class PushSource : public AudioOutputStream::AudioSourceCallback, public PushAudioOutput { public: - explicit PushSource(); + PushSource(); virtual ~PushSource(); // Write one buffer. @@ -82,8 +83,6 @@ class PushSource : public AudioOutputStream::AudioSourceCallback, void CleanUp(); media::SeekableBuffer buffer_; - // Serialize access to |buffer_| using this lock. - Lock buffer_lock_; }; #endif // MEDIA_AUDIO_SIMPLE_SOURCES_H_ diff --git a/media/media.gyp b/media/media.gyp index 6821aac..abd32d9 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -21,6 +21,8 @@ ], 'msvs_guid': '6AE76406-B03B-11DD-94B1-80B556D89593', 'sources': [ + 'audio/audio_controller.cc', + 'audio/audio_controller.h', 'audio/audio_output.h', 'audio/audio_util.cc', 'audio/audio_util.h', @@ -180,6 +182,7 @@ '../third_party/openmax/omx_stub.cc', ], 'sources': [ + 'audio/audio_controller_unittest.cc', 'audio/audio_util_unittest.cc', 'audio/linux/alsa_output_unittest.cc', 'audio/mac/audio_output_mac_unittest.cc', |