diff options
25 files changed, 354 insertions, 229 deletions
diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h index abf2b028..594db9f 100644 --- a/chrome/common/render_messages_params.h +++ b/chrome/common/render_messages_params.h @@ -26,7 +26,7 @@ #include "chrome/common/window_container_type.h" #include "googleurl/src/gurl.h" #include "ipc/ipc_param_traits.h" -#include "media/audio/audio_io.h" +#include "media/audio/audio_manager.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileSystem.h" #include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h" #include "webkit/glue/password_form.h" diff --git a/chrome/renderer/media/audio_renderer_impl.h b/chrome/renderer/media/audio_renderer_impl.h index 5c34a7d..30ac36f 100644 --- a/chrome/renderer/media/audio_renderer_impl.h +++ b/chrome/renderer/media/audio_renderer_impl.h @@ -44,6 +44,7 @@ #include "base/shared_memory.h" #include "chrome/renderer/audio_message_filter.h" #include "media/audio/audio_io.h" +#include "media/audio/audio_manager.h" #include "media/base/factory.h" #include "media/base/filters.h" #include "media/filters/audio_renderer_base.h" diff --git a/media/audio/audio_input_controller.h b/media/audio/audio_input_controller.h index a00e2bc..deded58 100644 --- a/media/audio/audio_input_controller.h +++ b/media/audio/audio_input_controller.h @@ -10,6 +10,7 @@ #include "base/scoped_ptr.h" #include "base/thread.h" #include "media/audio/audio_io.h" +#include "media/audio/audio_manager.h" // An AudioInputController controls an AudioInputStream and records data // from this input stream. It has an important function that it executes diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h index 6e1e289..4f23686 100644 --- a/media/audio/audio_io.h +++ b/media/audio/audio_io.h @@ -153,80 +153,4 @@ class AudioInputStream { virtual ~AudioInputStream() {} }; -// Manages all audio resources. In particular it owns the AudioOutputStream -// objects. Provides some convenience functions that avoid the need to provide -// iterators over the existing streams. -class AudioManager { - public: - enum Format { - AUDIO_PCM_LINEAR = 0, // PCM is 'raw' amplitude samples. - AUDIO_PCM_LOW_LATENCY, // Linear PCM, low latency requested. - AUDIO_MOCK, // Creates a dummy AudioOutputStream object. - AUDIO_LAST_FORMAT // Only used for validation of format. - }; - - // Telephone quality sample rate, mostly for speech-only audio. - static const uint32 kTelephoneSampleRate = 8000; - // CD sampling rate is 44.1 KHz or conveniently 2x2x3x3x5x5x7x7. - static const uint32 kAudioCDSampleRate = 44100; - // Digital Audio Tape sample rate. - static const uint32 kAudioDATSampleRate = 48000; - - // Returns true if the OS reports existence of audio devices. This does not - // guarantee that the existing devices support all formats and sample rates. - virtual bool HasAudioOutputDevices() = 0; - - // Returns true if the OS reports existence of audio recording devices. This - // does not guarantee that the existing devices support all formats and - // sample rates. - virtual bool HasAudioInputDevices() = 0; - - // Factory for all the supported stream formats. The |channels| can be 1 to 5. - // The |sample_rate| is in hertz and can be any value supported by the - // platform. For some future formats the |sample_rate| and |bits_per_sample| - // can take special values. - // Returns NULL if the combination of the parameters is not supported, or if - // we have reached some other platform specific limit. - // - // AUDIO_PCM_LOW_LATENCY can be passed to this method and it has two effects: - // 1- Instead of triple buffered the audio will be double buffered. - // 2- A low latency driver or alternative audio subsystem will be used when - // available. - // - // Do not free the returned AudioOutputStream. It is owned by AudioManager. - virtual AudioOutputStream* MakeAudioOutputStream(Format format, int channels, - int sample_rate, - char bits_per_sample) = 0; - - // Factory to create audio recording streams. - // |channels| can be 1 or 2. - // |sample_rate| is in hertz and can be any value supported by the platform. - // |bits_per_sample| can be any value supported by the platform. - // |samples_per_packet| is in hertz as well and can be 0 to |sample_rate|, - // with 0 suggesting that the implementation use a default value for that - // platform. - // Returns NULL if the combination of the parameters is not supported, or if - // we have reached some other platform specific limit. - // - // Do not free the returned AudioInputStream. It is owned by AudioManager. - // When you are done with it, call |Stop()| and |Close()| to release it. - virtual AudioInputStream* MakeAudioInputStream(Format format, int channels, - int sample_rate, - char bits_per_sample, - uint32 samples_per_packet) = 0; - - // Muting continues playback but effectively the volume is set to zero. - // Un-muting returns the volume to the previous level. - virtual void MuteAll() = 0; - virtual void UnMuteAll() = 0; - - // Get AudioManager singleton. - // TODO(cpu): Define threading requirements for interacting with AudioManager. - static AudioManager* GetAudioManager(); - - protected: - virtual ~AudioManager() {} -}; - - #endif // MEDIA_AUDIO_AUDIO_IO_H_ diff --git a/media/audio/audio_manager.cc b/media/audio/audio_manager.cc new file mode 100644 index 0000000..7148d21 --- /dev/null +++ b/media/audio/audio_manager.cc @@ -0,0 +1,59 @@ +// 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_manager.h" + +#include "base/at_exit.h" +#include "base/logging.h" + +namespace { + +AudioManager* g_audio_manager = NULL; + +// NullAudioManager is the audio manager used on the systems that have no +// audio support. +class NullAudioManager : public AudioManager { + public: + NullAudioManager() { } + + // Implementation of AudioManager. + virtual bool HasAudioOutputDevices() { return false; } + virtual bool HasAudioInputDevices() { return false; } + virtual AudioOutputStream* MakeAudioOutputStream(Format format, int channels, + int sample_rate, + char bits_per_sample) { + NOTIMPLEMENTED(); + return NULL; + } + virtual AudioInputStream* MakeAudioInputStream(Format format, int channels, + int sample_rate, + char bits_per_sample, + uint32 samples_per_packet) { + NOTIMPLEMENTED(); + return NULL; + } + virtual void MuteAll() { NOTIMPLEMENTED(); } + virtual void UnMuteAll() { NOTIMPLEMENTED(); } + + private: + DISALLOW_COPY_AND_ASSIGN(NullAudioManager); +}; + +} // namespace + +// static +void AudioManager::Destroy(void* not_used) { + delete g_audio_manager; + g_audio_manager = NULL; +} + +// static +AudioManager* AudioManager::GetAudioManager() { + if (!g_audio_manager) { + g_audio_manager = CreateAudioManager(); + g_audio_manager->Init(); + base::AtExitManager::RegisterCallback(&AudioManager::Destroy, NULL); + } + return g_audio_manager; +} diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h new file mode 100644 index 0000000..2185950 --- /dev/null +++ b/media/audio/audio_manager.h @@ -0,0 +1,101 @@ +// 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_MANAGER_H_ +#define MEDIA_AUDIO_AUDIO_MANAGER_H_ + +#include "base/basictypes.h" + +class AudioInputStream; +class AudioOutputStream; +class MessageLoop; + +// Manages all audio resources. In particular it owns the AudioOutputStream +// objects. Provides some convenience functions that avoid the need to provide +// iterators over the existing streams. +class AudioManager { + public: + enum Format { + AUDIO_PCM_LINEAR = 0, // PCM is 'raw' amplitude samples. + AUDIO_PCM_LOW_LATENCY, // Linear PCM, low latency requested. + AUDIO_MOCK, // Creates a dummy AudioOutputStream object. + AUDIO_LAST_FORMAT // Only used for validation of format. + }; + + // Telephone quality sample rate, mostly for speech-only audio. + static const uint32 kTelephoneSampleRate = 8000; + // CD sampling rate is 44.1 KHz or conveniently 2x2x3x3x5x5x7x7. + static const uint32 kAudioCDSampleRate = 44100; + // Digital Audio Tape sample rate. + static const uint32 kAudioDATSampleRate = 48000; + + // Returns true if the OS reports existence of audio devices. This does not + // guarantee that the existing devices support all formats and sample rates. + virtual bool HasAudioOutputDevices() = 0; + + // Returns true if the OS reports existence of audio recording devices. This + // does not guarantee that the existing devices support all formats and + // sample rates. + virtual bool HasAudioInputDevices() = 0; + + // Factory for all the supported stream formats. The |channels| can be 1 to 5. + // The |sample_rate| is in hertz and can be any value supported by the + // platform. For some future formats the |sample_rate| and |bits_per_sample| + // can take special values. + // Returns NULL if the combination of the parameters is not supported, or if + // we have reached some other platform specific limit. + // + // AUDIO_PCM_LOW_LATENCY can be passed to this method and it has two effects: + // 1- Instead of triple buffered the audio will be double buffered. + // 2- A low latency driver or alternative audio subsystem will be used when + // available. + // + // Do not free the returned AudioOutputStream. It is owned by AudioManager. + virtual AudioOutputStream* MakeAudioOutputStream(Format format, int channels, + int sample_rate, + char bits_per_sample) = 0; + + // Factory to create audio recording streams. + // |channels| can be 1 or 2. + // |sample_rate| is in hertz and can be any value supported by the platform. + // |bits_per_sample| can be any value supported by the platform. + // |samples_per_packet| is in hertz as well and can be 0 to |sample_rate|, + // with 0 suggesting that the implementation use a default value for that + // platform. + // Returns NULL if the combination of the parameters is not supported, or if + // we have reached some other platform specific limit. + // + // Do not free the returned AudioInputStream. It is owned by AudioManager. + // When you are done with it, call |Stop()| and |Close()| to release it. + virtual AudioInputStream* MakeAudioInputStream(Format format, int channels, + int sample_rate, + char bits_per_sample, + uint32 samples_per_packet) = 0; + + // Muting continues playback but effectively the volume is set to zero. + // Un-muting returns the volume to the previous level. + virtual void MuteAll() = 0; + virtual void UnMuteAll() = 0; + + // Returns message loop used for audio IO. + virtual MessageLoop* GetMessageLoop() = 0; + + // Get AudioManager singleton. + // TODO(cpu): Define threading requirements for interacting with AudioManager. + static AudioManager* GetAudioManager(); + + protected: + virtual ~AudioManager() {} + + // Called from GetAudioManager() to initialiaze the instance. + virtual void Init() = 0; + + private: + static void Destroy(void*); + + // Called by GetAudioManager() to create platform-specific audio manager. + static AudioManager* CreateAudioManager(); +}; + +#endif // MEDIA_AUDIO_AUDIO_MANAGER_H_ diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc new file mode 100644 index 0000000..7fa4761 --- /dev/null +++ b/media/audio/audio_manager_base.cc @@ -0,0 +1,19 @@ +// 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_manager_base.h" + +AudioManagerBase::AudioManagerBase() + : audio_thread_("AudioThread"), + initialized_(false) { +} + +void AudioManagerBase::Init() { + initialized_ = audio_thread_.Start(); +} + +MessageLoop* AudioManagerBase::GetMessageLoop() { + DCHECK(initialized_); + return audio_thread_.message_loop(); +} diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h new file mode 100644 index 0000000..ed8ab0e --- /dev/null +++ b/media/audio/audio_manager_base.h @@ -0,0 +1,35 @@ +// 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_MANAGER_BASE_H_ +#define MEDIA_AUDIO_AUDIO_MANAGER_BASE_H_ + +#include "base/thread.h" +#include "media/audio/audio_manager.h" + +// AudioManagerBase provides AudioManager functions common for all platforms. +class AudioManagerBase : public AudioManager { + public: + AudioManagerBase(); + + virtual void Init(); + + virtual MessageLoop* GetMessageLoop(); + + protected: + virtual ~AudioManagerBase() {} + + bool initialized() { return initialized_; } + + protected: + // Thread used to interact with AudioOutputStreams created by this + // audio manger. + base::Thread audio_thread_; + + bool initialized_; + + DISALLOW_COPY_AND_ASSIGN(AudioManagerBase); +}; + +#endif // MEDIA_AUDIO_AUDIO_MANAGER_BASE_H_ diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index 74e2261..27938f9 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -4,6 +4,8 @@ #include "media/audio/audio_output_controller.h" +#include "base/message_loop.h" + // The following parameters limit the request buffer and packet size from the // renderer to avoid renderer from requesting too much memory. static const uint32 kMegabytes = 1024 * 1024; @@ -35,12 +37,12 @@ AudioOutputController::AudioOutputController(EventHandler* handler, uint32 capacity, SyncReader* sync_reader) : handler_(handler), + stream_(NULL), volume_(1.0), state_(kEmpty), hardware_pending_bytes_(0), buffer_capacity_(capacity), - sync_reader_(sync_reader), - thread_("AudioOutputControllerThread") { + sync_reader_(sync_reader) { } AudioOutputController::~AudioOutputController() { @@ -65,10 +67,9 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create( scoped_refptr<AudioOutputController> controller = new AudioOutputController( event_handler, buffer_capacity, NULL); - // Start the audio controller thread and post a task to create the - // audio stream. - controller->thread_.Start(); - controller->thread_.message_loop()->PostTask( + controller->message_loop_ = + AudioManager::GetAudioManager()->GetMessageLoop(); + controller->message_loop_->PostTask( FROM_HERE, NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate, format, channels, sample_rate, bits_per_sample, @@ -96,10 +97,9 @@ scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( scoped_refptr<AudioOutputController> controller = new AudioOutputController( event_handler, 0, sync_reader); - // Start the audio controller thread and post a task to create the - // audio stream. - controller->thread_.Start(); - controller->thread_.message_loop()->PostTask( + controller->message_loop_ = + AudioManager::GetAudioManager()->GetMessageLoop(); + controller->message_loop_->PostTask( FROM_HERE, NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate, format, channels, sample_rate, bits_per_sample, @@ -108,43 +108,43 @@ scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( } void AudioOutputController::Play() { - DCHECK(thread_.IsRunning()); - thread_.message_loop()->PostTask( + DCHECK(message_loop_); + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &AudioOutputController::DoPlay)); } void AudioOutputController::Pause() { - DCHECK(thread_.IsRunning()); - thread_.message_loop()->PostTask( + DCHECK(message_loop_); + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &AudioOutputController::DoPause)); } void AudioOutputController::Flush() { - DCHECK(thread_.IsRunning()); - thread_.message_loop()->PostTask( + DCHECK(message_loop_); + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &AudioOutputController::DoFlush)); } void AudioOutputController::Close() { - if (!thread_.IsRunning()) { - // If the thread is not running make sure we are stopped. - DCHECK_EQ(kClosed, state_); - return; + { + AutoLock auto_lock(lock_); + // Don't do anything if the stream is already closed. + if (state_ == kClosed) + return; + state_ = kClosed; } - // Wait for all tasks to complete on the audio thread. - thread_.message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &AudioOutputController::DoClose)); - thread_.Stop(); } void AudioOutputController::SetVolume(double volume) { - DCHECK(thread_.IsRunning()); - thread_.message_loop()->PostTask( + DCHECK(message_loop_); + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &AudioOutputController::DoSetVolume, volume)); } @@ -159,8 +159,14 @@ void AudioOutputController::EnqueueData(const uint8* data, uint32 size) { void AudioOutputController::DoCreate(AudioManager::Format format, int channels, int sample_rate, int bits_per_sample, uint32 hardware_buffer_size) { - DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); - DCHECK_EQ(kEmpty, state_); + DCHECK_EQ(message_loop_, MessageLoop::current()); + + AutoLock auto_lock(lock_); + + // Close() can be called before DoCreate() is executed. + if (state_ == kClosed) + return; + DCHECK(state_ == kEmpty); // Create the stream in the first place. stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStream( @@ -191,22 +197,20 @@ void AudioOutputController::DoCreate(AudioManager::Format format, int channels, // If in normal latency mode then start buffering. if (!LowLatencyMode()) { - AutoLock auto_lock(lock_); SubmitOnMoreData_Locked(); } } void AudioOutputController::DoPlay() { - DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); - - // We can start from created or paused state. - if (state_ != kCreated && state_ != kPaused) - return; + DCHECK_EQ(message_loop_, MessageLoop::current()); State old_state; // Update the |state_| to kPlaying. { AutoLock auto_lock(lock_); + // We can start from created or paused state. + if (state_ != kCreated && state_ != kPaused) + return; old_state = state_; state_ = kPlaying; } @@ -219,15 +223,14 @@ void AudioOutputController::DoPlay() { } void AudioOutputController::DoPause() { - DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); - - // We can pause from started state. - if (state_ != kPlaying) - return; + DCHECK_EQ(message_loop_, MessageLoop::current()); // Sets the |state_| to kPaused so we don't draw more audio data. { AutoLock auto_lock(lock_); + // We can pause from started state. + if (state_ != kPlaying) + return; state_ = kPaused; } @@ -240,24 +243,22 @@ void AudioOutputController::DoPause() { } void AudioOutputController::DoFlush() { - DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); - - if (state_ != kPaused) - return; + DCHECK_EQ(message_loop_, MessageLoop::current()); // 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_); + if (state_ != kPaused) + return; push_source_.ClearAll(); } } void AudioOutputController::DoClose() { - DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); - DCHECK_NE(kClosed, state_); - + DCHECK_EQ(message_loop_, MessageLoop::current()); + DCHECK_EQ(kClosed, state_); // |stream_| can be null if creating the device failed in DoCreate(). if (stream_) { stream_->Stop(); @@ -265,27 +266,26 @@ void AudioOutputController::DoClose() { // After stream is closed it is destroyed, so don't keep a reference to it. stream_ = NULL; } - - // 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 AudioOutputController::DoSetVolume(double volume) { - DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + DCHECK_EQ(message_loop_, MessageLoop::current()); // Saves the volume to a member first. We may not be able to set the volume // right away but when the stream is created we'll set the volume. volume_ = volume; - if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) - return; + { + AutoLock auto_lock(lock_); + if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) + return; + } stream_->SetVolume(volume_); } void AudioOutputController::DoReportError(int code) { - DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); + DCHECK_EQ(message_loop_, MessageLoop::current()); handler_->OnError(this, code); } @@ -332,7 +332,7 @@ void AudioOutputController::OnClose(AudioOutputStream* stream) { void AudioOutputController::OnError(AudioOutputStream* stream, int code) { // Handle error on the audio controller thread. - thread_.message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &AudioOutputController::DoReportError, code)); } diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h index 10e3d03..4600067 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -8,11 +8,13 @@ #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_io.h" +#include "media/audio/audio_manager.h" #include "media/audio/simple_sources.h" +class MessageLoop; + // An AudioOutputController 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, @@ -138,9 +140,9 @@ class AudioOutputController // 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. + // Closes the audio output stream. It changes state to kClosed and returns + // right away. The physical resources are freed on the audio thread if + // neccessary. // // It is safe to call this method more than once. Calls after the first one // will have no effect. @@ -203,8 +205,8 @@ class AudioOutputController // 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_; + // The message loop of audio thread that this object runs on. + MessageLoop* message_loop_; DISALLOW_COPY_AND_ASSIGN(AudioOutputController); }; diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc index a68571a..df96f4a 100644 --- a/media/audio/audio_output_controller_unittest.cc +++ b/media/audio/audio_output_controller_unittest.cc @@ -14,6 +14,7 @@ using ::testing::AtLeast; using ::testing::Exactly; using ::testing::InvokeWithoutArgs; using ::testing::NotNull; +using ::testing::Return; static const int kSampleRate = AudioManager::kAudioCDSampleRate; static const int kBitsPerSample = 16; @@ -68,6 +69,10 @@ static bool IsRunningHeadless() { return false; } +ACTION_P(SignalEvent, event) { + event->Signal(); +} + ACTION_P3(SignalEvent, event, count, limit) { if (++*count >= limit) { event->Signal(); @@ -86,7 +91,10 @@ TEST(AudioOutputControllerTest, CreateAndClose) { kHardwareBufferSize, kBufferCapacity); ASSERT_TRUE(controller.get()); - // Close the controller immediately. + // Close the controller immediately. At this point, chances are that + // DoCreate() hasn't been called yet. In any case, it should be safe to call + // Close() and it should not try to call |event_handler| later (the test + // would crash otherwise). controller->Close(); } @@ -100,7 +108,7 @@ TEST(AudioOutputControllerTest, PlayAndClose) { // If OnCreated is called then signal the event. EXPECT_CALL(event_handler, OnCreated(NotNull())) - .WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal)); + .WillOnce(SignalEvent(&event)); // OnPlaying() will be called only once. EXPECT_CALL(event_handler, OnPlaying(NotNull())) @@ -120,14 +128,13 @@ TEST(AudioOutputControllerTest, PlayAndClose) { // 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. + // Now stop the controller. The object is freed later after DoClose() is + // executed. controller->Close(); } @@ -178,8 +185,8 @@ TEST(AudioOutputControllerTest, PlayPauseClose) { controller->Pause(); event.Wait(); - // Now stop the controller. This should shutdown the internal - // thread and we hold the only reference to it. + // Now stop the controller. The object is freed later after DoClose() is + // executed. controller->Close(); } @@ -242,8 +249,8 @@ TEST(AudioOutputControllerTest, PlayPausePlay) { controller->Play(); event.Wait(); - // Now stop the controller. This should shutdown the internal - // thread and we hold the only reference to it. + // Now stop the controller. The object is freed later after DoClose() is + // executed. controller->Close(); } @@ -270,6 +277,17 @@ TEST(AudioOutputControllerTest, CloseTwice) { return; MockAudioOutputControllerEventHandler event_handler; + base::WaitableEvent event(false, false); + + // If OnCreated is called then signal the event. + EXPECT_CALL(event_handler, OnCreated(NotNull())) + .WillOnce(SignalEvent(&event)); + + // One OnMoreData() is expected. + EXPECT_CALL(event_handler, OnMoreData(NotNull(), _, 0)) + .Times(AtLeast(1)) + .WillRepeatedly(SignalEvent(&event)); + scoped_refptr<AudioOutputController> controller = AudioOutputController::Create(&event_handler, AudioManager::AUDIO_PCM_LINEAR, kChannels, @@ -277,7 +295,12 @@ TEST(AudioOutputControllerTest, CloseTwice) { kHardwareBufferSize, kBufferCapacity); ASSERT_TRUE(controller.get()); - // Close the controller immediately. + // Wait for OnCreated() to be called. + event.Wait(); + + // Wait for OnMoreData() to be called. + event.Wait(); + controller->Close(); controller->Close(); } diff --git a/media/audio/fake_audio_input_stream_unittest.cc b/media/audio/fake_audio_input_stream_unittest.cc index 16e86a4..473ed10 100644 --- a/media/audio/fake_audio_input_stream_unittest.cc +++ b/media/audio/fake_audio_input_stream_unittest.cc @@ -5,6 +5,7 @@ #include "base/basictypes.h" #include "base/platform_thread.h" #include "media/audio/audio_io.h" +#include "media/audio/audio_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -48,4 +49,3 @@ TEST(FakeAudioInputTest, BasicCallbacks) { stream->Stop(); stream->Close(); } - diff --git a/media/audio/linux/alsa_output.cc b/media/audio/linux/alsa_output.cc index 1358dc3..e8ebc5c 100644 --- a/media/audio/linux/alsa_output.cc +++ b/media/audio/linux/alsa_output.cc @@ -376,7 +376,7 @@ void AlsaPcmOutputStream::GetVolume(double* volume) { } void AlsaPcmOutputStream::OpenTask(uint32 packet_size) { - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); // Initialize the configuration variables. packet_size_ = packet_size; @@ -422,7 +422,7 @@ void AlsaPcmOutputStream::OpenTask(uint32 packet_size) { } void AlsaPcmOutputStream::StartTask() { - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); if (stop_stream_) { return; @@ -454,7 +454,7 @@ void AlsaPcmOutputStream::StartTask() { void AlsaPcmOutputStream::CloseTask() { // NOTE: Keep this function idempotent to handle errors that might cause // multiple CloseTasks to be posted. - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); // Shutdown the audio device. if (playback_handle_ && !CloseDevice(playback_handle_)) { @@ -470,7 +470,7 @@ void AlsaPcmOutputStream::CloseTask() { } void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); // If stopped, simulate a 0-lengthed packet. if (stop_stream_) { @@ -558,7 +558,7 @@ void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { } void AlsaPcmOutputStream::WritePacket() { - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); // If the device is in error, just eat the bytes. if (stop_stream_) { @@ -611,7 +611,7 @@ void AlsaPcmOutputStream::WritePacket() { } void AlsaPcmOutputStream::WriteTask() { - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); if (stop_stream_) { return; @@ -625,7 +625,7 @@ void AlsaPcmOutputStream::WriteTask() { } void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); if (stop_stream_) { return; @@ -778,7 +778,7 @@ bool AlsaPcmOutputStream::CloseDevice(snd_pcm_t* handle) { } snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() { - DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK_EQ(message_loop_, MessageLoop::current()); if (stop_stream_) { return 0; diff --git a/media/audio/linux/alsa_output.h b/media/audio/linux/alsa_output.h index 0fb5ac5..f98f2c0 100644 --- a/media/audio/linux/alsa_output.h +++ b/media/audio/linux/alsa_output.h @@ -36,8 +36,8 @@ #include "base/lock.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" -#include "base/thread.h" #include "media/audio/audio_io.h" +#include "media/audio/audio_manager_base.h" namespace media { class SeekableBuffer; diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc index 17a1f74..713a753 100644 --- a/media/audio/linux/audio_manager_linux.cc +++ b/media/audio/linux/audio_manager_linux.cc @@ -4,7 +4,6 @@ #include "media/audio/linux/audio_manager_linux.h" -#include "base/at_exit.h" #include "base/command_line.h" #include "base/logging.h" #include "media/audio/fake_audio_input_stream.h" @@ -13,12 +12,6 @@ #include "media/audio/linux/alsa_wrapper.h" #include "media/base/media_switches.h" - -namespace { - -AudioManagerLinux* g_audio_manager = NULL; -} // namespace - // Implementation of AudioManager. bool AudioManagerLinux::HasAudioOutputDevices() { // TODO(ajwong): Make this actually query audio devices. @@ -56,7 +49,7 @@ AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream( return FakeAudioOutputStream::MakeFakeStream(); } - if (!initialized_) { + if (!initialized()) { return NULL; } @@ -68,16 +61,14 @@ AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream( AlsaPcmOutputStream* stream = new AlsaPcmOutputStream(device_name, format, channels, sample_rate, bits_per_sample, wrapper_.get(), this, - audio_thread_.message_loop()); + GetMessageLoop()); AutoLock l(lock_); active_streams_[stream] = scoped_refptr<AlsaPcmOutputStream>(stream); return stream; } -AudioManagerLinux::AudioManagerLinux() - : audio_thread_("AudioThread"), - initialized_(false) { +AudioManagerLinux::AudioManagerLinux() { } AudioManagerLinux::~AudioManagerLinux() { @@ -91,7 +82,7 @@ AudioManagerLinux::~AudioManagerLinux() { } void AudioManagerLinux::Init() { - initialized_ = audio_thread_.Start(); + AudioManagerBase::Init(); wrapper_.reset(new AlsaWrapper()); } @@ -110,17 +101,7 @@ void AudioManagerLinux::ReleaseOutputStream(AlsaPcmOutputStream* stream) { } } -// TODO(ajwong): Collapse this with the windows version. -void DestroyAudioManagerLinux(void* not_used) { - delete g_audio_manager; - g_audio_manager = NULL; -} - -AudioManager* AudioManager::GetAudioManager() { - if (!g_audio_manager) { - g_audio_manager = new AudioManagerLinux(); - g_audio_manager->Init(); - base::AtExitManager::RegisterCallback(&DestroyAudioManagerLinux, NULL); - } - return g_audio_manager; +// static +AudioManager* AudioManager::CreateAudioManager() { + return new AudioManagerLinux(); } diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/linux/audio_manager_linux.h index ea335f0..2703eed 100644 --- a/media/audio/linux/audio_manager_linux.h +++ b/media/audio/linux/audio_manager_linux.h @@ -11,12 +11,12 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/thread.h" -#include "media/audio/audio_io.h" +#include "media/audio/audio_manager_base.h" class AlsaPcmOutputStream; class AlsaWrapper; -class AudioManagerLinux : public AudioManager { +class AudioManagerLinux : public AudioManagerBase { public: AudioManagerLinux(); @@ -44,17 +44,12 @@ class AudioManagerLinux : public AudioManager { virtual ~AudioManagerLinux(); private: - // Thread used to interact with AudioOutputStreams created by this - // audio manger. - base::Thread audio_thread_; scoped_ptr<AlsaWrapper> wrapper_; Lock lock_; std::map<AlsaPcmOutputStream*, scoped_refptr<AlsaPcmOutputStream> > active_streams_; - bool initialized_; - DISALLOW_COPY_AND_ASSIGN(AudioManagerLinux); }; diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 312ecbb..528fd6e 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -4,7 +4,6 @@ #include <CoreAudio/AudioHardware.h> -#include "base/at_exit.h" #include "media/audio/fake_audio_input_stream.h" #include "media/audio/fake_audio_output_stream.h" #include "media/audio/mac/audio_manager_mac.h" @@ -75,22 +74,7 @@ void AudioManagerMac::ReleaseOutputStream( delete stream; } -namespace { - -AudioManagerMac* g_audio_manager = NULL; - -} // namespace. - -void DestroyAudioManagerMac(void* param) { - delete g_audio_manager; - g_audio_manager = NULL; -} - -// By convention, the AudioManager is not thread safe. -AudioManager* AudioManager::GetAudioManager() { - if (!g_audio_manager) { - g_audio_manager = new AudioManagerMac(); - base::AtExitManager::RegisterCallback(&DestroyAudioManagerMac, NULL); - } - return g_audio_manager; +// static +AudioManager* AudioManager::CreateAudioManager() { + return new AudioManagerMac(); } diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index c05e092..fa25ece 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h @@ -6,14 +6,14 @@ #define MEDIA_AUDIO_MAC_AUDIO_MANAGER_MAC_H_ #include "base/basictypes.h" -#include "media/audio/audio_io.h" +#include "media/audio/audio_manager_base.h" class PCMQueueOutAudioOutputStream; // Mac OS X implementation of the AudioManager singleton. This class is internal // to the audio output and only internal users can call methods not exposed by // the AudioManager class. -class AudioManagerMac : public AudioManager { +class AudioManagerMac : public AudioManagerBase { public: AudioManagerMac() {}; diff --git a/media/audio/openbsd/audio_manager_openbsd.cc b/media/audio/openbsd/audio_manager_openbsd.cc index 7d7a249..c2c7b98 100644 --- a/media/audio/openbsd/audio_manager_openbsd.cc +++ b/media/audio/openbsd/audio_manager_openbsd.cc @@ -4,7 +4,6 @@ #include "media/audio/openbsd/audio_manager_openbsd.h" -#include "base/at_exit.h" #include "base/logging.h" namespace { @@ -48,6 +47,7 @@ AudioManagerOpenBSD::~AudioManagerOpenBSD() { } void AudioManagerOpenBSD::Init() { + AudioManagerBase::Init(); } void AudioManagerOpenBSD::MuteAll() { @@ -71,3 +71,8 @@ AudioManager* AudioManager::GetAudioManager() { } return g_audio_manager; } + +// static +AudioManager* AudioManager::CreateAudioManager() { + return new AudioManagerOpenBSD(); +} diff --git a/media/audio/openbsd/audio_manager_openbsd.h b/media/audio/openbsd/audio_manager_openbsd.h index ddbce23..fc35a37 100644 --- a/media/audio/openbsd/audio_manager_openbsd.h +++ b/media/audio/openbsd/audio_manager_openbsd.h @@ -7,7 +7,7 @@ #include "media/audio/audio_io.h" -class AudioManagerOpenBSD : public AudioManager { +class AudioManagerOpenBSD : public AudioManagerBase { public: AudioManagerOpenBSD(); diff --git a/media/audio/simple_sources_unittest.cc b/media/audio/simple_sources_unittest.cc index 7ddc23f..029d565 100644 --- a/media/audio/simple_sources_unittest.cc +++ b/media/audio/simple_sources_unittest.cc @@ -6,6 +6,7 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "base/time.h" +#include "media/audio/audio_manager.h" #include "media/audio/fake_audio_output_stream.h" #include "media/audio/simple_sources.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index 061d2d8..6c4a606 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc @@ -7,7 +7,6 @@ #include <windows.h> #include <mmsystem.h> -#include "base/at_exit.h" #include "base/basictypes.h" #include "media/audio/fake_audio_input_stream.h" #include "media/audio/fake_audio_output_stream.h" @@ -42,8 +41,6 @@ const int kMaxSamplesPerPacket = kMaxSampleRate; // play. const int kNumInputBuffers = 3; -AudioManagerWin* g_audio_manager = NULL; - } // namespace. bool AudioManagerWin::HasAudioOutputDevices() { @@ -125,15 +122,7 @@ void AudioManagerWin::UnMuteAll() { AudioManagerWin::~AudioManagerWin() { } -void DestroyAudioManagerWin(void* param) { - delete g_audio_manager; - g_audio_manager = NULL; -} - -AudioManager* AudioManager::GetAudioManager() { - if (!g_audio_manager) { - g_audio_manager = new AudioManagerWin(); - base::AtExitManager::RegisterCallback(&DestroyAudioManagerWin, NULL); - } - return g_audio_manager; +// static +AudioManager* AudioManager::CreateAudioManager() { + return new AudioManagerWin(); } diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index 21a4014..b8bd579 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -8,7 +8,7 @@ #include <windows.h> #include "base/basictypes.h" -#include "media/audio/audio_io.h" +#include "media/audio/audio_manager_base.h" class PCMWaveInAudioInputStream; class PCMWaveOutAudioOutputStream; @@ -16,7 +16,7 @@ class PCMWaveOutAudioOutputStream; // Windows implementation of the AudioManager singleton. This class is internal // to the audio output and only internal users can call methods not exposed by // the AudioManager class. -class AudioManagerWin : public AudioManager { +class AudioManagerWin : public AudioManagerBase { public: AudioManagerWin() {} // Implementation of AudioManager. diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc index 0f4a053..9fd1034 100644 --- a/media/filters/audio_renderer_impl.cc +++ b/media/filters/audio_renderer_impl.cc @@ -7,6 +7,7 @@ #include <math.h> #include "media/base/filter_host.h" +#include "media/audio/audio_manager.h" namespace media { diff --git a/media/media.gyp b/media/media.gyp index 45815e72..eec7678 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -23,6 +23,10 @@ 'audio/audio_io.h', 'audio/audio_input_controller.cc', 'audio/audio_input_controller.h', + 'audio/audio_manager.h', + 'audio/audio_manager.cc', + 'audio/audio_manager_base.h', + 'audio/audio_manager_base.cc', 'audio/audio_output_controller.cc', 'audio/audio_output_controller.h', 'audio/audio_util.cc', |