diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-21 06:10:23 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-21 06:10:23 +0000 |
commit | 841803c39354971f380399cd2dfeacbc5e0e245c (patch) | |
tree | 89ecf2efdfac3bfabf7d154a7ced1f8b55fe106e /media/audio | |
parent | fe24ccff145ec31f31b3504419440f1639581862 (diff) | |
download | chromium_src-841803c39354971f380399cd2dfeacbc5e0e245c.zip chromium_src-841803c39354971f380399cd2dfeacbc5e0e245c.tar.gz chromium_src-841803c39354971f380399cd2dfeacbc5e0e245c.tar.bz2 |
Revert http://codereview.chromium.org/115276
Review URL: http://codereview.chromium.org/115624
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16584 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio')
-rw-r--r-- | media/audio/audio_output.h | 9 | ||||
-rw-r--r-- | media/audio/linux/alsa_output.cc | 521 | ||||
-rw-r--r-- | media/audio/linux/alsa_output.h | 165 | ||||
-rw-r--r-- | media/audio/linux/audio_manager_linux.cc | 67 | ||||
-rw-r--r-- | media/audio/linux/audio_manager_linux.h | 32 |
5 files changed, 4 insertions, 790 deletions
diff --git a/media/audio/audio_output.h b/media/audio/audio_output.h index 4793e71..289b2af 100644 --- a/media/audio/audio_output.h +++ b/media/audio/audio_output.h @@ -43,11 +43,9 @@ class AudioOutputStream { public: enum State { STATE_CREATED = 0, // The output stream is created. - STATE_OPENED, // The output stream is opened. STATE_STARTED, // The output stream is started. STATE_PAUSED, // The output stream is paused. STATE_STOPPED, // The output stream is stopped. - STATE_CLOSING, // The output stream is being closed. STATE_CLOSED, // The output stream is closed. STATE_ERROR, // The output stream is in error state. }; @@ -84,9 +82,6 @@ class AudioOutputStream { // two buffers of |packet_size| size are created, one will be locked for // playback and one will be ready to be filled in the call to // AudioSourceCallback::OnMoreData(). - // - // TODO(ajwong): Streams are not reusable, so try to move packet_size into the - // constructor. virtual bool Open(size_t packet_size) = 0; // Starts playing audio and generating AudioSourceCallback::OnMoreData(). @@ -94,11 +89,9 @@ class AudioOutputStream { // after calling this method initial buffers are fetched. User of this // object should prepare |AudioOutputStream::GetNumBuffers()| before calling // AudioOutputStream::Start(). - // - // The output stream does not take ownership of this callback. virtual void Start(AudioSourceCallback* callback) = 0; - // Stops playing audio. Effect might not be instantaneous as the hardware + // Stops playing audio. Effect might no be instantaneous as the hardware // might have locked audio data that is processing. virtual void Stop() = 0; diff --git a/media/audio/linux/alsa_output.cc b/media/audio/linux/alsa_output.cc deleted file mode 100644 index 0dc9ca9..0000000 --- a/media/audio/linux/alsa_output.cc +++ /dev/null @@ -1,521 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// The audio stream implementation is made difficult because different methods -// are available for calling depending on what state the stream is. Here is the -// state transition table for the stream. -// -// STATE_CREATED -> Open() -> STATE_OPENED -// STATE_OPENED -> Start() -> STATE_STARTED -// STATE_OPENED -> Close() -> STATE_CLOSED -// STATE_STARTED -> Stop() -> STATE_STOPPED -// STATE_STARTED -> Close() -> STATE_CLOSING | STATE_CLOSED -// STATE_STOPPED -> Close() -> STATE_CLOSING | STATE_CLOSED -// STATE_CLOSING -> [automatic] -> STATE_CLOSED -// -// Error states and resource management: -// -// Entrance into STATE_STOPPED signals schedules a call to ReleaseResources(). -// -// Any state may transition to STATE_ERROR. On transitioning into STATE_ERROR, -// the function doing the transition is reponsible for scheduling a call to -// ReleaseResources() or otherwise ensuring resources are cleaned (eg., as is -// done in Open()). This should be done while holding the lock to avoid a -// destruction race condition where the stream is deleted via ref-count before -// the ReleaseResources() task is scheduled. In particular, be careful of -// resource management in a transtiion from STATE_STOPPED -> STATE_ERROR if -// that becomes necessary in the future. -// -// STATE_ERROR may transition to STATE_CLOSED. In this situation, no further -// resource management is done because it is assumed that the resource -// reclaimation was executed at the point of the state transition into -// STATE_ERROR. -// -// Entrance into STATE_CLOSED implies a transition through STATE_STOPPED, which -// triggers the resource management code. -// -// The destructor is not responsible for ultimate cleanup of resources. -// Instead, it only checks that the stream is in a state where all resources -// have been cleaned up. These states are STATE_CREATED, STATE_CLOSED, -// STATE_ERROR. -// -// TODO(ajwong): This incorrectly handles the period size for filling of the -// ALSA device buffer. Currently the period size is hardcoded, and not -// reported to the sound device. Also, there are options that let the device -// wait until the buffer is minimally filled before playing. Those should be -// explored. Also consider doing the device interactions either outside of the -// class lock, or under a different lock to avoid unecessarily blocking other -// threads. - -#include "media/audio/linux/alsa_output.h" - -#include <algorithm> - -#include "base/logging.h" -#include "base/stl_util-inl.h" -#include "base/time.h" - -// Require 10ms latency from the audio device. Taken from ALSA documentation -// example. -// TODO(ajwong): Figure out what this parameter actually does, and what a good -// value would be. -static const unsigned int kTargetLatencyMicroseconds = 10000; - -// Minimal amount of time to sleep. If any future event is expected to -// execute within this timeframe, treat it as if it should execute immediately. -// -// TODO(ajwong): Determine if there is a sensible minimum sleep resolution and -// adjust accordingly. -static const int64 kMinSleepMilliseconds = 10L; - -const char* AlsaPCMOutputStream::kDefaultDevice = "plug:default"; - -AlsaPCMOutputStream::AlsaPCMOutputStream(const std::string& device_name, - int min_buffer_ms, - AudioManager::Format format, - int channels, - int sample_rate, - char bits_per_sample) - : state_(STATE_CREATED), - device_name_(device_name), - playback_handle_(NULL), - source_callback_(NULL), - playback_thread_("PlaybackThread"), - channels_(channels), - sample_rate_(sample_rate), - bits_per_sample_(bits_per_sample), - min_buffer_frames_((min_buffer_ms * sample_rate_) / - base::Time::kMillisecondsPerSecond), - packet_size_(0), - device_write_suspended_(true), // Start suspended. - resources_released_(false) { - CHECK(channels_ == 2) << "Only 2-channel audio is supported right now."; - CHECK(AudioManager::AUDIO_PCM_LINEAR == format) - << "Only linear PCM supported."; - CHECK(bits_per_sample % 8 == 0) << "Only allow byte-aligned samples"; - - // Reference self to avoid accidental deletion before the message loop is - // done. - AddRef(); - - switch (bits_per_sample) { - case 8: - pcm_format_ = SND_PCM_FORMAT_S8; - break; - - case 16: - pcm_format_ = SND_PCM_FORMAT_S16; - break; - - case 24: - pcm_format_ = SND_PCM_FORMAT_S24; - break; - - case 32: - pcm_format_ = SND_PCM_FORMAT_S32; - break; - - default: - LOG(DFATAL) << "Unsupported bits per sample: " << bits_per_sample_; - state_ = STATE_ERROR; - break; - } - - // Interleaved audio is expected, so each frame has one sample per channel. - bytes_per_frame_ = channels_ * (bits_per_sample_ / 8); -} - -AlsaPCMOutputStream::~AlsaPCMOutputStream() { - AutoLock l(lock_); - // In STATE_CREATED, STATE_CLOSED, and STATE_ERROR, resources are guaranteed - // to be released. - CHECK(state_ == STATE_CREATED || - state_ == STATE_CLOSED || - state_ == STATE_ERROR); -} - -bool AlsaPCMOutputStream::Open(size_t packet_size) { - AutoLock l(lock_); - - // Check that stream is coming from the correct state and early out if not. - if (state_ == STATE_ERROR) { - return false; - } - if (state_ != STATE_CREATED) { - NOTREACHED() << "Stream must be in STATE_CREATED on Open. Instead in: " - << state_; - return false; - } - - // Open the device and set the parameters. - // TODO(ajwong): Can device open block? Probably. If yes, we need to move - // the open call into a different thread. - int error = snd_pcm_open(&playback_handle_, device_name_.c_str(), - SND_PCM_STREAM_PLAYBACK, 0); - if (error < 0) { - LOG(ERROR) << "Cannot open audio device (" << device_name_ << "): " - << snd_strerror(error); - EnterStateError_Locked(); - return false; - } - if ((error = snd_pcm_set_params(playback_handle_, - pcm_format_, - SND_PCM_ACCESS_RW_INTERLEAVED, - channels_, - sample_rate_, - 1, // soft_resample -- let ALSA resample - kTargetLatencyMicroseconds)) < 0) { - LOG(ERROR) << "Unable to set PCM parameters: " << snd_strerror(error); - if (!CloseDevice_Locked()) { - LOG(WARNING) << "Unable to close audio device. Leaking handle."; - } - playback_handle_ = NULL; - EnterStateError_Locked(); - return false; - } - - // Configure the buffering. - packet_size_ = packet_size; - DCHECK_EQ(0U, packet_size_ % bytes_per_frame_) - << "Buffers should end on a frame boundary. Frame size: " - << bytes_per_frame_; - - // Everything is okay. Stream is officially STATE_OPENED for business. - state_ = STATE_OPENED; - - return true; -} - -void AlsaPCMOutputStream::Start(AudioSourceCallback* callback) { - AutoLock l(lock_); - - // Check that stream is coming from the correct state and early out if not. - if (state_ == STATE_ERROR) { - return; - } - if (state_ != STATE_OPENED) { - NOTREACHED() << "Can only be started from STATE_OPEN. Current state: " - << state_; - return; - } - - source_callback_ = callback; - - playback_thread_.Start(); - playback_thread_.message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &AlsaPCMOutputStream::BufferPackets)); - - state_ = STATE_STARTED; -} - -void AlsaPCMOutputStream::Stop() { - AutoLock l(lock_); - // If the stream is in STATE_ERROR, it is effectively stopped already. - if (state_ == STATE_ERROR) { - return; - } - StopInternal_Locked(); -} - -void AlsaPCMOutputStream::StopInternal_Locked() { - // Check the lock is held in a debug build. - DCHECK((lock_.AssertAcquired(), true)); - - if (state_ != STATE_STARTED) { - NOTREACHED() << "Stream must be in STATE_STARTED to Stop. Instead in: " - << state_; - return; - } - - // Move immediately to STATE_STOPPED to signal that all functions should cease - // working at this point. Then post a task to the playback thread to release - // resources. - state_ = STATE_STOPPED; - - playback_thread_.message_loop()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &AlsaPCMOutputStream::ReleaseResources)); -} - -void AlsaPCMOutputStream::EnterStateError_Locked() { - // Check the lock is held in a debug build. - DCHECK((lock_.AssertAcquired(), true)); - - state_ = STATE_ERROR; - resources_released_ = true; - - // TODO(ajwong): Call OnError() on source_callback_. -} - -void AlsaPCMOutputStream::Close() { - AutoLock l(lock_); - - // If in STATE_ERROR, all asynchronous resource reclaimation is finished, so - // just change states and release this instance to delete ourself. - if (state_ == STATE_ERROR) { - Release(); - state_ = STATE_CLOSED; - return; - } - - // Otherwise, cleanup as necessary. - if (state_ == STATE_CLOSED || state_ == STATE_CLOSING) { - NOTREACHED() << "Attempting to close twice."; - return; - } - - // If the stream is still running, stop it. - if (state_ == STATE_STARTED) { - StopInternal_Locked(); - } - - // If it is stopped (we may have just transitioned here in the previous if - // block), check if the resources have been released. If they have, - // transition immediately to STATE_CLOSED. Otherwise, move to - // STATE_CLOSING, and the ReleaseResources() task will move to STATE_CLOSED - // for us. - // - // If the stream has been stopped, close. - if (state_ == STATE_STOPPED) { - if (resources_released_) { - state_ = STATE_CLOSED; - } else { - state_ = STATE_CLOSING; - } - } else { - // TODO(ajwong): Can we safely handle state_ == STATE_CREATED? - NOTREACHED() << "Invalid state on close: " << state_; - // In release, just move to STATE_ERROR, and hope for the best. - EnterStateError_Locked(); - } -} - -bool AlsaPCMOutputStream::CloseDevice_Locked() { - // Check the lock is held in a debug build. - DCHECK((lock_.AssertAcquired(), true)); - - int error = snd_pcm_close(playback_handle_); - if (error < 0) { - LOG(ERROR) << "Cannot close audio device (" << device_name_ << "): " - << snd_strerror(error); - return false; - } - - return true; -} - -void AlsaPCMOutputStream::ReleaseResources() { - AutoLock l(lock_); - - // Shutdown the audio device. - if (!CloseDevice_Locked()) { - LOG(WARNING) << "Unable to close audio device. Leaking handle."; - playback_handle_ = NULL; - } - - // Delete all the buffers. - STLDeleteElements(&buffered_packets_); - - // Release the source callback. - source_callback_->OnClose(this); - - // Shutdown the thread. - DCHECK_EQ(PlatformThread::CurrentId(), playback_thread_.thread_id()); - playback_thread_.message_loop()->Quit(); - - // TODO(ajwong): Do we need to join the playback thread? - - // If the stream is closing, then this function has just completed the last - // bit needed before closing. Transition to STATE_CLOSED. - if (state_ == STATE_CLOSING) { - state_ = STATE_CLOSED; - } - - // TODO(ajwong): Currently, the stream is leaked after the |playback_thread_| - // is stopped. Find a way to schedule its deletion on another thread, maybe - // using a DestructionObserver. -} - -snd_pcm_sframes_t AlsaPCMOutputStream::GetFramesOfDelay_Locked() { - // Check the lock is held in a debug build. - DCHECK((lock_.AssertAcquired(), true)); - - // Find the number of frames queued in the sound device. - snd_pcm_sframes_t delay_frames = 0; - int error = snd_pcm_delay(playback_handle_, &delay_frames); - if (error < 0) { - error = snd_pcm_recover(playback_handle_, - error /* Original error. */, - 0 /* Silenty recover. */); - } - if (error < 0) { - LOG(ERROR) << "Could not query sound device for delay. Assuming 0: " - << snd_strerror(error); - } - - for (std::deque<Packet*>::const_iterator it = buffered_packets_.begin(); - it != buffered_packets_.end(); - ++it) { - delay_frames += ((*it)->size - (*it)->used) / bytes_per_frame_; - } - - return delay_frames; -} - -void AlsaPCMOutputStream::BufferPackets() { - AutoLock l(lock_); - - // Handle early outs for errored, stopped, or closing streams. - if (state_ == STATE_ERROR || - state_ == STATE_STOPPED || - state_ == STATE_CLOSING) { - return; - } - if (state_ != STATE_STARTED) { - NOTREACHED() << "Invalid stream state while buffering. " - << "Expected STATE_STARTED. Current state: " << state_; - return; - } - - // Early out if the buffer is already full. - snd_pcm_sframes_t delay_frames = GetFramesOfDelay_Locked(); - if (delay_frames < min_buffer_frames_) { - // Grab one packet. Drop the lock for the synchronous call. This will - // still stall the playback thread, but at least it will not block any - // other threads. - // - // TODO(ajwong): Move to cpu@'s non-blocking audio source. - scoped_ptr<Packet> packet; - size_t capacity = packet_size_; // Snag it for non-locked usage. - { - AutoUnlock synchronous_data_fetch(lock_); - packet.reset(new Packet(capacity)); - size_t used = source_callback_->OnMoreData(this, packet->buffer.get(), - packet->capacity); - CHECK(used <= capacity) << "Data source overran buffer. Aborting."; - packet->size = used; - // TODO(ajwong): Do more buffer validation here, like checking that the - // packet is correctly aligned to frames, etc. - } - // After reacquiring the lock, recheck state to make sure it is still - // STATE_STARTED. - if (state_ != STATE_STARTED) { - return; - } - buffered_packets_.push_back(packet.release()); - - // Recalculate delay frames. - delay_frames = GetFramesOfDelay_Locked(); - } - - // Since the current implementation of OnMoreData() blocks, only try to grab - // one packet per task. If the buffer is still too low, post another - // BufferPackets() task immediately. Otherwise, calculate when the buffer is - // likely to need filling and schedule a poll for the future. - int next_fill_time_ms = (delay_frames - min_buffer_frames_) / sample_rate_; - if (next_fill_time_ms <= kMinSleepMilliseconds) { - playback_thread_.message_loop()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &AlsaPCMOutputStream::BufferPackets)); - } else { - // TODO(ajwong): Measure the reliability of the delay interval. Use - // base/histogram.h. - playback_thread_.message_loop()->PostDelayedTask( - FROM_HERE, - NewRunnableMethod(this, &AlsaPCMOutputStream::BufferPackets), - next_fill_time_ms); - } - - // If the |device_write_suspended_|, the audio device write tasks have - // stopped scheduling themselves due to an underrun of the in-memory buffer. - // Post a new task to restart it since we now have data. - if (device_write_suspended_) { - device_write_suspended_ = false; - playback_thread_.message_loop()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &AlsaPCMOutputStream::FillAlsaDeviceBuffer)); - } -} - -void AlsaPCMOutputStream::FillAlsaDeviceBuffer() { - // TODO(ajwong): Try to move some of this code out from underneath the lock. - AutoLock l(lock_); - - // Find the number of frames that the device can accept right now. - snd_pcm_sframes_t device_buffer_frames_avail = - snd_pcm_avail_update(playback_handle_); - - // Write up to |device_buffer_frames_avail| frames to the ALSA device. - while (device_buffer_frames_avail > 0) { - if (buffered_packets_.empty()) { - device_write_suspended_ = true; - break; - } - - Packet* current_packet = buffered_packets_.front(); - - // Only process non 0-lengthed packets. - if (current_packet->used < current_packet->size) { - // Calculate the number of frames we have to write. - char* buffer_pos = current_packet->buffer.get() + current_packet->used; - snd_pcm_sframes_t buffer_frames = - (current_packet->size - current_packet->used) / - bytes_per_frame_; - snd_pcm_sframes_t frames_to_write = - std::min(buffer_frames, device_buffer_frames_avail); - - // Check that device_buffer_frames_avail isn't < 0. - DCHECK_GT(frames_to_write, 0); - - // Write it to the device. - int frames_written = - snd_pcm_writei(playback_handle_, buffer_pos, frames_to_write); - if (frames_written < 0) { - // Recover from EINTR, EPIPE (overrun/underrun), ESTRPIPE (stream - // suspended). - // - // TODO(ajwong): Check that we do not need to loop on recover, here and - // anywhere else we use recover. - frames_written = snd_pcm_recover(playback_handle_, - frames_written /* Original error. */, - 0 /* Silenty recover. */); - } - if (frames_written < 0) { - LOG(ERROR) << "Failed to write to pcm device: " - << snd_strerror(frames_written); - ReleaseResources(); - EnterStateError_Locked(); - break; - } else { - current_packet->used += frames_written * bytes_per_frame_; - DCHECK_LE(current_packet->used, current_packet->size); - } - } - - if (current_packet->used >= current_packet->size) { - delete current_packet; - buffered_packets_.pop_front(); - } - } - - // If the memory buffer was not underrun, schedule another fill in the future. - if (!device_write_suspended_) { - playback_thread_.message_loop()->PostDelayedTask( - FROM_HERE, - NewRunnableMethod(this, &AlsaPCMOutputStream::FillAlsaDeviceBuffer), - kTargetLatencyMicroseconds / base::Time::kMicrosecondsPerMillisecond); - } -} - -void AlsaPCMOutputStream::SetVolume(double left_level, double right_level) { - NOTIMPLEMENTED(); -} - -void AlsaPCMOutputStream::GetVolume(double* left_level, double* right_level) { - NOTIMPLEMENTED(); -} - -size_t AlsaPCMOutputStream::GetNumBuffers() { - return 0; -} diff --git a/media/audio/linux/alsa_output.h b/media/audio/linux/alsa_output.h deleted file mode 100644 index b6d405b..0000000 --- a/media/audio/linux/alsa_output.h +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Creates an output stream based on the ALSA PCM interface. The current -// implementation creates one thread per ALSA playback handle that is -// responsible for synchronously pulling data from the audio data source. -// -// This output stream buffers in two places: -// (1) In the ALSA device -// (2) In an in-memory buffer. -// -// The ALSA device buffer is kept as full as possible. The in-memory buffer -// attempts to keep enough extra data so that |min_buffer_ms| worth of data -// is available between the in-memory buffer and the device buffer. Requests -// to the audio data source are made if the total amount buffered falls below -// |min_buffer_ms|. -// -// On device write failure, the stream will move into an invalid state. No -// more data will be pulled from the data source, and the playback thread will -// be stopped. -// -// If the stream is successfully opened, Close() must be called before the -// stream is deleted. - -#ifndef MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ -#define MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ - -#include <alsa/asoundlib.h> - -#include <deque> -#include <string> - -#include "base/lock.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" -#include "base/thread.h" -#include "media/audio/audio_output.h" - -class Thread; - -class AlsaPCMOutputStream : - public AudioOutputStream, - public base::RefCountedThreadSafe<AlsaPCMOutputStream> { - public: - // Set to "plug:default" which should allow ALSA to do whatever is - // necessary to simulate an audio device capable of handling our PCMs. - static const char* kDefaultDevice; - - // Create a PCM Output stream for the ALSA device identified by - // |device_name|. If unsure of hte device_name, use kDefaultDevice. - AlsaPCMOutputStream(const std::string& device_name, - int min_buffer_ms, - AudioManager::Format format, - int channels, - int sample_rate, - char bits_per_sample); - virtual ~AlsaPCMOutputStream(); - - // Implementation of AudioOutputStream. - virtual bool Open(size_t packet_size); - virtual void Close(); - virtual void Start(AudioSourceCallback* callback); - virtual void Stop(); - virtual void SetVolume(double left_level, double right_level); - virtual void GetVolume(double* left_level, double* right_level); - virtual size_t GetNumBuffers(); - - private: - // Closes the playback handle, reporting errors if any occur. Returns true - // if the device was successfully closed. - bool CloseDevice_Locked(); - - // Stops playback, ignoring state checks. - void StopInternal_Locked(); - - // Moves the stream into the error state, setting the correct internal flags. - // Ensure that all resources are cleaned up before executing this function. - void EnterStateError_Locked(); - - // Releases all the resources in the audio stream. This method will also - // terminate the playback thread itself. - // - // This method must be run in the |playback_thead_|. - void ReleaseResources(); - - // Retrieve the total number of frames buffered in both memory and in the - // audio device. Use this to determine if more data should be requested from - // the audio source. - snd_pcm_sframes_t GetFramesOfDelay_Locked(); - - // Buffer more packets from data source if necessary. - // - // This function must be run in the |playback_thread_|. - void BufferPackets(); - - // Returns true if our buffer is underfull. - bool ShouldBufferMore_NoLock(); - - // Write as many buffered packets into the device as there is room in the - // device buffer. - // - // This function must be run in the |playback_thread_|. - void FillAlsaDeviceBuffer(); - - // State of the stream. - State state_; - - // The ALSA device name to use. - std::string device_name_; - - // Handle to the actual PCM playback device. - snd_pcm_t* playback_handle_; - - // Period size for ALSA ring-buffer. Basically, how long to wait between - // writes. - snd_pcm_sframes_t period_size_; - - // Callback used to request more data from the data source. - AudioSourceCallback* source_callback_; - - // Playback thread. - base::Thread playback_thread_; - - // Lock for field access to this object. - Lock lock_; - - // Sample format configuration. - snd_pcm_format_t pcm_format_; - const int channels_; - const int sample_rate_; - const char bits_per_sample_; - char bytes_per_frame_; - - // In-memory buffer to hold sound samples before pushing to the sound device. - // TODO(ajwong): There are now about 3 buffer queue implementations. Factor - // them out. - struct Packet { - explicit Packet(int new_capacity) - : capacity(new_capacity), - size(0), - used(0), - buffer(new char[capacity]) { - } - size_t capacity; - size_t size; - size_t used; - scoped_array<char> buffer; - }; - int min_buffer_frames_; - std::deque<Packet*> buffered_packets_; - size_t packet_size_; - - // Flag indiciating the device write tasks have stopped scheduling - // themselves. This should only be modified by the BufferPackets() and - // FillAlsaDeviceBuffer() methods. - bool device_write_suspended_; - - // Flag indicating that the resources are already cleaned. - bool resources_released_; - - DISALLOW_COPY_AND_ASSIGN(AlsaPCMOutputStream); -}; - -#endif // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc index afe1c3c..15a13b2 100644 --- a/media/audio/linux/audio_manager_linux.cc +++ b/media/audio/linux/audio_manager_linux.cc @@ -2,70 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "media/audio/linux/audio_manager_linux.h" - -#include "base/at_exit.h" -#include "base/logging.h" -#include "media/audio/linux/alsa_output.h" - -namespace { -AudioManagerLinux* g_audio_manager = NULL; -} // namespace - -// Implementation of AudioManager. -bool AudioManagerLinux::HasAudioDevices() { - // TODO(ajwong): Make this actually query audio devices. - return true; -} - -AudioOutputStream* AudioManagerLinux::MakeAudioStream(Format format, - int channels, - int sample_rate, - char bits_per_sample) { - // TODO(ajwong): Do we want to be able to configure the device? plug:default - // should work correctly for all mono/stereo, but not surround, which needs - // surround40, surround51, etc. - // - // http://0pointer.de/blog/projects/guide-to-sound-apis.html - AlsaPCMOutputStream* stream = - new AlsaPCMOutputStream(AlsaPCMOutputStream::kDefaultDevice, - 100 /* 100ms minimal buffer */, - format, channels, sample_rate, bits_per_sample); - return stream; -} - -AudioManagerLinux::AudioManagerLinux() { -} - -AudioManagerLinux::~AudioManagerLinux() { -} - -void AudioManagerLinux::MuteAll() { - // TODO(ajwong): Implement. - NOTIMPLEMENTED(); -} - -void AudioManagerLinux::UnMuteAll() { - // TODO(ajwong): Implement. - NOTIMPLEMENTED(); -} - -const void* AudioManagerLinux::GetLastMockBuffer() { - // TODO(ajwong): Implement. - NOTIMPLEMENTED(); - return NULL; -} - -// TODO(ajwong): Collapse this with the windows version. -void DestroyAudioManagerLinux(void* not_used) { - delete g_audio_manager; - g_audio_manager = NULL; -} +#include "media/audio/audio_output.h" +// TODO(hclam): Do something more useful than returning NULL. AudioManager* AudioManager::GetAudioManager() { - if (!g_audio_manager) { - g_audio_manager = new AudioManagerLinux(); - base::AtExitManager::RegisterCallback(&DestroyAudioManagerLinux, NULL); - } - return g_audio_manager; + return NULL; } diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/linux/audio_manager_linux.h deleted file mode 100644 index 5b369a1..0000000 --- a/media/audio/linux/audio_manager_linux.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_AUDIO_LINUX_AUDIO_MANAGER_LINUX_H_ -#define MEDIA_AUDIO_LINUX_AUDIO_MANAGER_LINUX_H_ - -#include "base/thread.h" -#include "media/audio/audio_output.h" - -class AudioManagerLinux : public AudioManager { - public: - AudioManagerLinux(); - - // Implementation of AudioManager. - virtual bool HasAudioDevices(); - virtual AudioOutputStream* MakeAudioStream(Format format, int channels, - int sample_rate, - char bits_per_sample); - virtual void MuteAll(); - virtual void UnMuteAll(); - virtual const void* GetLastMockBuffer(); - - private: - // Friend function for invoking the private destructor at exit. - friend void DestroyAudioManagerLinux(void*); - virtual ~AudioManagerLinux(); - - DISALLOW_COPY_AND_ASSIGN(AudioManagerLinux); -}; - -#endif // MEDIA_AUDIO_LINUX_AUDIO_MANAGER_LINUX_H_ |