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

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

Issue 10834033: Move AudioDevice and AudioInputDevice to media. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 months 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 148738)
+++ content/renderer/media/audio_device.cc (working copy)
@@ -1,277 +0,0 @@
-// Copyright (c) 2012 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 "content/renderer/media/audio_device.h"
-
-#include "base/debug/trace_event.h"
-#include "base/message_loop.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/time.h"
-#include "media/audio/audio_output_controller.h"
-#include "media/audio/audio_util.h"
-
-using media::AudioRendererSink;
-
-// Takes care of invoking the render callback on the audio thread.
-// An instance of this class is created for each capture stream in
-// OnStreamCreated().
-class AudioDevice::AudioThreadCallback
- : public AudioDeviceThread::Callback {
- public:
- AudioThreadCallback(const media::AudioParameters& audio_parameters,
- base::SharedMemoryHandle memory,
- int memory_length,
- AudioRendererSink::RenderCallback* render_callback);
- virtual ~AudioThreadCallback();
-
- virtual void MapSharedMemory() OVERRIDE;
-
- // Called whenever we receive notifications about pending data.
- virtual void Process(int pending_data) OVERRIDE;
-
- private:
- AudioRendererSink::RenderCallback* render_callback_;
- DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
-};
-
-AudioDevice::AudioDevice(
- media::AudioOutputIPC* ipc,
- const scoped_refptr<base::MessageLoopProxy>& io_loop)
- : ScopedLoopObserver(io_loop),
- callback_(NULL),
- ipc_(ipc),
- stream_id_(0),
- play_on_start_(true),
- is_started_(false) {
- CHECK(ipc_);
-}
-
-void AudioDevice::Initialize(const media::AudioParameters& params,
- RenderCallback* callback) {
- CHECK_EQ(0, stream_id_) <<
- "AudioDevice::Initialize() must be called before Start()";
-
- CHECK(!callback_); // Calling Initialize() twice?
-
- audio_parameters_ = params;
- callback_ = callback;
-}
-
-AudioDevice::~AudioDevice() {
- // The current design requires that the user calls Stop() before deleting
- // this class.
- CHECK_EQ(0, stream_id_);
-}
-
-void AudioDevice::Start() {
- DCHECK(callback_) << "Initialize hasn't been called";
- message_loop()->PostTask(FROM_HERE,
- base::Bind(&AudioDevice::CreateStreamOnIOThread, this,
- audio_parameters_));
-}
-
-void AudioDevice::Stop() {
- {
- base::AutoLock auto_lock(audio_thread_lock_);
- audio_thread_.Stop(MessageLoop::current());
- }
-
- message_loop()->PostTask(FROM_HERE,
- base::Bind(&AudioDevice::ShutDownOnIOThread, this));
-}
-
-void AudioDevice::Play() {
- message_loop()->PostTask(FROM_HERE,
- base::Bind(&AudioDevice::PlayOnIOThread, this));
-}
-
-void AudioDevice::Pause(bool flush) {
- message_loop()->PostTask(FROM_HERE,
- base::Bind(&AudioDevice::PauseOnIOThread, this, flush));
-}
-
-bool AudioDevice::SetVolume(double volume) {
- if (volume < 0 || volume > 1.0)
- return false;
-
- if (!message_loop()->PostTask(FROM_HERE,
- base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume))) {
- return false;
- }
-
- return true;
-}
-
-void AudioDevice::CreateStreamOnIOThread(const media::AudioParameters& params) {
- DCHECK(message_loop()->BelongsToCurrentThread());
- // Make sure we don't create the stream more than once.
- DCHECK_EQ(0, stream_id_);
- if (stream_id_)
- return;
-
- stream_id_ = ipc_->AddDelegate(this);
- ipc_->CreateStream(stream_id_, params);
-}
-
-void AudioDevice::PlayOnIOThread() {
- DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_ && is_started_)
- ipc_->PlayStream(stream_id_);
- else
- play_on_start_ = true;
-}
-
-void AudioDevice::PauseOnIOThread(bool flush) {
- DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_ && is_started_) {
- ipc_->PauseStream(stream_id_);
- if (flush)
- ipc_->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() {
- DCHECK(message_loop()->BelongsToCurrentThread());
-
- // Make sure we don't call shutdown more than once.
- if (stream_id_) {
- is_started_ = false;
-
- ipc_->CloseStream(stream_id_);
- ipc_->RemoveDelegate(stream_id_);
- stream_id_ = 0;
- }
-
- // We can run into an issue where ShutDownOnIOThread is called right after
- // OnStreamCreated is called in cases where Start/Stop are called before we
- // get the OnStreamCreated callback. To handle that corner case, we call
- // Stop(). In most cases, the thread will already be stopped.
- // Another situation is when the IO thread goes away before Stop() is called
- // in which case, we cannot use the message loop to close the thread handle
- // and can't not rely on the main thread existing either.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- audio_thread_.Stop(NULL);
- audio_callback_.reset();
-}
-
-void AudioDevice::SetVolumeOnIOThread(double volume) {
- DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_)
- ipc_->SetVolume(stream_id_, volume);
-}
-
-void AudioDevice::OnStateChanged(media::AudioOutputIPCDelegate::State state) {
- DCHECK(message_loop()->BelongsToCurrentThread());
-
- // Do nothing if the stream has been closed.
- if (!stream_id_)
- return;
-
- if (state == media::AudioOutputIPCDelegate::kError) {
- DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)";
- // Don't dereference the callback object if the audio thread
- // is stopped or stopping. That could mean that the callback
- // object has been deleted.
- // TODO(tommi): Add an explicit contract for clearing the callback
- // object. Possibly require calling Initialize again or provide
- // a callback object via Start() and clear it in Stop().
- if (!audio_thread_.IsStopped())
- callback_->OnRenderError();
- }
-}
-
-void AudioDevice::OnStreamCreated(
- base::SharedMemoryHandle handle,
- base::SyncSocket::Handle socket_handle,
- int length) {
- DCHECK(message_loop()->BelongsToCurrentThread());
- DCHECK_GE(length, audio_parameters_.GetBytesPerBuffer());
-#if defined(OS_WIN)
- DCHECK(handle);
- DCHECK(socket_handle);
-#else
- DCHECK_GE(handle.fd, 0);
- DCHECK_GE(socket_handle, 0);
-#endif
-
- // We should only get this callback if stream_id_ is valid. If it is not,
- // the IPC layer should have closed the shared memory and socket handles
- // for us and not invoked the callback. The basic assertion is that when
- // stream_id_ is 0 the AudioDevice instance is not registered as a delegate
- // and hence it should not receive callbacks.
- DCHECK(stream_id_);
-
- base::AutoLock auto_lock(audio_thread_lock_);
-
- DCHECK(audio_thread_.IsStopped());
- audio_callback_.reset(new AudioDevice::AudioThreadCallback(audio_parameters_,
- handle, length, callback_));
- audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioDevice");
-
- // We handle the case where Play() and/or Pause() may have been called
- // multiple times before OnStreamCreated() gets called.
- is_started_ = true;
- if (play_on_start_)
- PlayOnIOThread();
-}
-
-void AudioDevice::OnIPCClosed() {
- ipc_ = NULL;
-}
-
-void AudioDevice::WillDestroyCurrentMessageLoop() {
- LOG(ERROR) << "IO loop going away before the audio device has been stopped";
- ShutDownOnIOThread();
-}
-
-// AudioDevice::AudioThreadCallback
-
-AudioDevice::AudioThreadCallback::AudioThreadCallback(
- const media::AudioParameters& audio_parameters,
- base::SharedMemoryHandle memory,
- int memory_length,
- media::AudioRendererSink::RenderCallback* render_callback)
- : AudioDeviceThread::Callback(audio_parameters, memory, memory_length),
- render_callback_(render_callback) {
-}
-
-AudioDevice::AudioThreadCallback::~AudioThreadCallback() {
-}
-
-void AudioDevice::AudioThreadCallback::MapSharedMemory() {
- shared_memory_.Map(media::TotalSharedMemorySizeInBytes(memory_length_));
-}
-
-// Called whenever we receive notifications about pending data.
-void AudioDevice::AudioThreadCallback::Process(int pending_data) {
- if (pending_data == media::AudioOutputController::kPauseMark) {
- memset(shared_memory_.memory(), 0, memory_length_);
- media::SetActualDataSizeInBytes(&shared_memory_, memory_length_, 0);
- return;
- }
-
- // Convert the number of pending bytes in the render buffer
- // into milliseconds.
- int audio_delay_milliseconds = pending_data / bytes_per_ms_;
-
- TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback");
-
- // Update the audio-delay measurement then ask client to render audio.
- size_t num_frames = render_callback_->Render(audio_data_,
- audio_parameters_.frames_per_buffer(), audio_delay_milliseconds);
-
- // Interleave, scale, and clip to int.
- // TODO(crogers/vrk): Figure out a way to avoid the float -> int -> float
- // conversions that happen in the <audio> and WebRTC scenarios.
- media::InterleaveFloatToInt(audio_data_, shared_memory_.memory(),
- num_frames, audio_parameters_.bits_per_sample() / 8);
-
- // Let the host know we are done.
- media::SetActualDataSizeInBytes(&shared_memory_, memory_length_,
- num_frames * audio_parameters_.GetBytesPerFrame());
-}

Powered by Google App Engine
This is Rietveld 408576698