summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/common/render_messages_params.h2
-rw-r--r--chrome/renderer/media/audio_renderer_impl.h1
-rw-r--r--media/audio/audio_input_controller.h1
-rw-r--r--media/audio/audio_io.h76
-rw-r--r--media/audio/audio_manager.cc59
-rw-r--r--media/audio/audio_manager.h101
-rw-r--r--media/audio/audio_manager_base.cc19
-rw-r--r--media/audio/audio_manager_base.h35
-rw-r--r--media/audio/audio_output_controller.cc108
-rw-r--r--media/audio/audio_output_controller.h14
-rw-r--r--media/audio/audio_output_controller_unittest.cc43
-rw-r--r--media/audio/fake_audio_input_stream_unittest.cc2
-rw-r--r--media/audio/linux/alsa_output.cc16
-rw-r--r--media/audio/linux/alsa_output.h2
-rw-r--r--media/audio/linux/audio_manager_linux.cc33
-rw-r--r--media/audio/linux/audio_manager_linux.h9
-rw-r--r--media/audio/mac/audio_manager_mac.cc22
-rw-r--r--media/audio/mac/audio_manager_mac.h4
-rw-r--r--media/audio/openbsd/audio_manager_openbsd.cc7
-rw-r--r--media/audio/openbsd/audio_manager_openbsd.h2
-rw-r--r--media/audio/simple_sources_unittest.cc1
-rw-r--r--media/audio/win/audio_manager_win.cc17
-rw-r--r--media/audio/win/audio_manager_win.h4
-rw-r--r--media/filters/audio_renderer_impl.cc1
-rw-r--r--media/media.gyp4
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',