Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1718)

Unified Diff: content/renderer/media/audio_device.cc

Issue 8477037: Simplify AudioRendererImpl by using AudioDevice. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/media/audio_device.cc
===================================================================
--- content/renderer/media/audio_device.cc (revision 110348)
+++ content/renderer/media/audio_device.cc (working copy)
@@ -12,28 +12,77 @@
#include "content/common/media/audio_messages.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_thread_impl.h"
+#include "media/audio/audio_output_controller.h"
#include "media/audio/audio_util.h"
+AudioDevice::AudioDevice()
+ : buffer_size_(0),
+ channels_(0),
+ bits_per_sample_(16),
+ sample_rate_(0),
+ latency_format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
+ callback_(0),
+ is_initialized_(false),
+ audio_delay_milliseconds_(0),
+ volume_(1.0),
+ stream_id_(0),
+ play_on_start_(true),
+ is_started_(false),
+ shared_memory_size_(0) {
+ filter_ = RenderThreadImpl::current()->audio_message_filter();
+}
+
AudioDevice::AudioDevice(size_t buffer_size,
int channels,
double sample_rate,
RenderCallback* callback)
- : buffer_size_(buffer_size),
- channels_(channels),
- bits_per_sample_(16),
- sample_rate_(sample_rate),
- callback_(callback),
+ : bits_per_sample_(16),
+ is_initialized_(false),
audio_delay_milliseconds_(0),
volume_(1.0),
- stream_id_(0) {
+ stream_id_(0),
+ play_on_start_(true),
+ is_started_(false),
+ shared_memory_size_(0) {
filter_ = RenderThreadImpl::current()->audio_message_filter();
+ Initialize(buffer_size,
+ channels,
+ sample_rate,
+ AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ callback);
+}
+
+void AudioDevice::Initialize(size_t buffer_size,
+ int channels,
+ double sample_rate,
+ AudioParameters::Format latency_format,
+ RenderCallback* callback) {
+ CHECK_EQ(0, stream_id_) <<
+ "AudioDevice::Initialize() must be called before Start()";
+
+ buffer_size_ = buffer_size;
+ channels_ = channels;
+ sample_rate_ = sample_rate;
+ latency_format_ = latency_format;
+ callback_ = callback;
+
+ // Cleanup from any previous initialization.
+ for (size_t i = 0; i < audio_data_.size(); ++i)
+ delete [] audio_data_[i];
+
audio_data_.reserve(channels);
for (int i = 0; i < channels; ++i) {
float* channel_data = new float[buffer_size];
audio_data_.push_back(channel_data);
}
+
+ is_initialized_ = true;
}
+bool AudioDevice::IsInitialized() {
+ return is_initialized_;
+}
+
AudioDevice::~AudioDevice() {
// The current design requires that the user calls Stop() before deleting
// this class.
@@ -44,7 +93,7 @@
void AudioDevice::Start() {
AudioParameters params;
- params.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
+ params.format = latency_format_;
params.channels = channels_;
params.sample_rate = static_cast<int>(sample_rate_);
params.bits_per_sample = bits_per_sample_;
@@ -71,11 +120,7 @@
// with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
// function call.
if (completion.TimedWait(kMaxTimeOut)) {
- if (audio_thread_.get()) {
- socket_->Close();
- audio_thread_->Join();
- audio_thread_.reset(NULL);
- }
+ ShutDownAudioThread();
} else {
LOG(ERROR) << "Failed to shut down audio output on IO thread";
return false;
@@ -84,6 +129,18 @@
return true;
}
+void AudioDevice::Play() {
+ ChildProcess::current()->io_message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioDevice::PlayOnIOThread, this));
+}
+
+void AudioDevice::Pause(bool flush) {
+ ChildProcess::current()->io_message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioDevice::PauseOnIOThread, this, flush));
+}
+
bool AudioDevice::SetVolume(double volume) {
if (volume < 0 || volume > 1.0)
return false;
@@ -103,7 +160,7 @@
}
void AudioDevice::InitializeOnIOThread(const AudioParameters& params) {
- // Make sure we don't call Start() more than once.
+ // Make sure we don't create the stream more than once.
DCHECK_EQ(0, stream_id_);
if (stream_id_)
return;
@@ -112,15 +169,32 @@
Send(new AudioHostMsg_CreateStream(stream_id_, params, true));
}
-void AudioDevice::StartOnIOThread() {
- if (stream_id_)
+void AudioDevice::PlayOnIOThread() {
no longer working on chromium 2011/11/28 15:17:41 What happens if the clients call Play() or Pause()
vrk (LEFT CHROMIUM) 2011/12/02 22:54:46 This is a good question, but I think it may be som
+ if (stream_id_ && is_started_)
Send(new AudioHostMsg_PlayStream(stream_id_));
+ else
+ play_on_start_ = true;
}
+void AudioDevice::PauseOnIOThread(bool flush) {
no longer working on chromium 2011/11/28 15:17:41 Same question as PlayOnIOThread()
vrk (LEFT CHROMIUM) 2011/12/02 22:54:46 Ditto above.
+ if (stream_id_ && is_started_) {
+ Send(new AudioHostMsg_PauseStream(stream_id_));
+ if (flush)
+ Send(new AudioHostMsg_FlushStream(stream_id_));
+ } else {
+ // Note that |flush| isn't relevant here since this is the case where
+ // the stream is first starting.
+ play_on_start_ = false;
+ }
+}
+
void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
no longer working on chromium 2011/11/28 15:17:41 We should clean up all the states like is_started,
vrk (LEFT CHROMIUM) 2011/12/02 22:54:46 Yeah, these states are probably an indication that
+ is_started_ = false;
+
// Make sure we don't call shutdown more than once.
if (!stream_id_) {
- completion->Signal();
+ if (completion)
+ completion->Signal();
return;
}
@@ -128,7 +202,8 @@
Send(new AudioHostMsg_CloseStream(stream_id_));
vrk (LEFT CHROMIUM) 2011/11/22 01:17:39 Doesn't AudioHostMsg_CloseStream need to be synchr
vrk (LEFT CHROMIUM) 2011/12/02 22:54:46 Since this potential problem was not introduced by
stream_id_ = 0;
- completion->Signal();
+ if (completion)
+ completion->Signal();
}
void AudioDevice::SetVolumeOnIOThread(double volume) {
@@ -138,20 +213,17 @@
void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) {
// This method does not apply to the low-latency system.
- NOTIMPLEMENTED();
}
void AudioDevice::OnStateChanged(AudioStreamState state) {
if (state == kAudioStreamError) {
DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)";
}
- NOTIMPLEMENTED();
}
void AudioDevice::OnCreated(
base::SharedMemoryHandle handle, uint32 length) {
// Not needed in this simple implementation.
- NOTIMPLEMENTED();
}
void AudioDevice::OnLowLatencyCreated(
@@ -178,20 +250,32 @@
shared_memory_.reset(new base::SharedMemory(handle, false));
shared_memory_->Map(length);
+ shared_memory_size_ = length;
DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_);
- socket_.reset(new base::SyncSocket(socket_handle));
- // Allow the client to pre-populate the buffer.
- FireRenderCallback();
+ {
+ // Synchronize with ShutDownAudioThread().
+ base::AutoLock auto_lock(lock_);
- audio_thread_.reset(
- new base::DelegateSimpleThread(this, "renderer_audio_thread"));
- audio_thread_->Start();
+ socket_.reset(new base::SyncSocket(socket_handle));
+ // Allow the client to pre-populate the buffer.
+ FireRenderCallback();
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&AudioDevice::StartOnIOThread, this));
+ DCHECK(!audio_thread_.get());
+ audio_thread_.reset(
+ new base::DelegateSimpleThread(this, "renderer_audio_thread"));
+ audio_thread_->Start();
+ }
+
+ // We handle the case where Play() and/or Pause() may have been called
+ // multiple times before OnLowLatencyCreated() gets called.
+ is_started_ = true;
+ if (play_on_start_) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioDevice::PlayOnIOThread, this));
no longer working on chromium 2011/11/28 15:17:41 One potential racing condition here, for example,
vrk (LEFT CHROMIUM) 2011/12/02 22:54:46 Yes, you're right; good catch! I think calling Pla
+ }
}
void AudioDevice::OnVolume(double volume) {
@@ -210,9 +294,14 @@
const int samples_per_ms = static_cast<int>(sample_rate_) / 1000;
const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms;
- while ((sizeof(pending_data) == socket_->Receive(&pending_data,
- sizeof(pending_data))) &&
- (pending_data >= 0)) {
+ while (sizeof(pending_data) ==
+ socket_->Receive(&pending_data, sizeof(pending_data))) {
+ if (pending_data == media::AudioOutputController::kPauseMark) {
+ memset(shared_memory_data(), 0, shared_memory_size_);
+ continue;
+ } else if (pending_data < 0) {
+ break;
+ }
// Convert the number of pending bytes in the render buffer
// into milliseconds.
audio_delay_milliseconds_ = pending_data / bytes_per_ms;
@@ -228,12 +317,30 @@
callback_->Render(audio_data_, buffer_size_, audio_delay_milliseconds_);
// Interleave, scale, and clip to int16.
+ // TODO(crogers): avoid converting to integer here, and pass the data
+ // to the browser process as float, so we don't lose precision for
+ // audio hardware which has better than 16bit precision.
media::InterleaveFloatToInt16(audio_data_,
static_cast<int16*>(shared_memory_data()),
buffer_size_);
}
}
+void AudioDevice::ShutDownAudioThread() {
no longer working on chromium 2011/11/28 15:17:41 Please see comment in Stop().
vrk (LEFT CHROMIUM) 2011/12/02 22:54:46 Done.
+ // Synchronize with OnLowLatencyCreated().
+ base::AutoLock auto_lock(lock_);
+
+ if (socket_.get()) {
+ socket_->Close();
+ }
+ if (audio_thread_.get()) {
+ audio_thread_->Join();
+ audio_thread_.reset(NULL);
+ }
+ // Note that the socket can't be reset until *after* joining the thread.
+ socket_.reset(NULL);
+}
+
double AudioDevice::GetAudioHardwareSampleRate() {
// Uses cached value if possible.
static double hardware_sample_rate = 0;

Powered by Google App Engine
This is Rietveld 408576698