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

Unified Diff: media/audio/audio_input_device.cc

Issue 12383016: Merge AssociateStreamWithProducer message into CreateStream message for both audio output and input. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed review comments. Created 7 years, 9 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: media/audio/audio_input_device.cc
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index 5c5bcf756f31a113b41a99d1236606c43e77de81..08eed35f16eb4dd7ddf9cdbedaf30c071162d038 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -4,6 +4,7 @@
#include "media/audio/audio_input_device.h"
+#include "base/basictypes.h"
#include "base/bind.h"
#include "base/message_loop.h"
#include "base/threading/thread_restrictions.h"
@@ -37,17 +38,25 @@ class AudioInputDevice::AudioThreadCallback
};
AudioInputDevice::AudioInputDevice(
- AudioInputIPC* ipc,
+ scoped_ptr<AudioInputIPC> ipc,
const scoped_refptr<base::MessageLoopProxy>& io_loop)
: ScopedLoopObserver(io_loop),
callback_(NULL),
event_handler_(NULL),
- ipc_(ipc),
- stream_id_(0),
+ ipc_(ipc.Pass()),
+ state_(IDLE),
session_id_(0),
- pending_device_ready_(false),
- agc_is_enabled_(false) {
+ agc_is_enabled_(false),
+ stopping_hack_(false) {
CHECK(ipc_);
+
+ // The correctness of the code depends on the relative values assigned in the
+ // State enum.
+ COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0);
+ COMPILE_ASSERT(IDLE < STARTING_DEVICE, invalid_enum_value_assignment_1);
+ COMPILE_ASSERT(STARTING_DEVICE < CREATING_STREAM,
+ invalid_enum_value_assignment_2);
+ COMPILE_ASSERT(CREATING_STREAM < RECORDING, invalid_enum_value_assignment_3);
}
void AudioInputDevice::Initialize(const AudioParameters& params,
@@ -55,6 +64,7 @@ void AudioInputDevice::Initialize(const AudioParameters& params,
CaptureEventHandler* event_handler) {
DCHECK(!callback_);
DCHECK(!event_handler_);
+ DCHECK(params.IsValid());
audio_parameters_ = params;
callback_ = callback;
event_handler_ = event_handler;
@@ -67,9 +77,10 @@ void AudioInputDevice::SetDevice(int session_id) {
}
void AudioInputDevice::Start() {
+ DCHECK(callback_) << "Initialize hasn't been called";
DVLOG(1) << "Start()";
message_loop()->PostTask(FROM_HERE,
- base::Bind(&AudioInputDevice::InitializeOnIOThread, this));
+ base::Bind(&AudioInputDevice::StartUpOnIOThread, this));
}
void AudioInputDevice::Stop() {
@@ -78,6 +89,7 @@ void AudioInputDevice::Stop() {
{
base::AutoLock auto_lock(audio_thread_lock_);
audio_thread_.Stop(MessageLoop::current());
+ stopping_hack_ = true;
}
message_loop()->PostTask(FROM_HERE,
@@ -113,17 +125,17 @@ void AudioInputDevice::OnStreamCreated(
DCHECK_GE(handle.fd, 0);
DCHECK_GE(socket_handle, 0);
#endif
- DCHECK(length);
- DVLOG(1) << "OnStreamCreated (stream_id=" << stream_id_ << ")";
+ DCHECK_GT(length, 0);
- // 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 AudioInputDevice instance is not registered as a
- // delegate and hence it should not receive callbacks.
- DCHECK(stream_id_);
+ if (state_ != CREATING_STREAM)
+ return;
base::AutoLock auto_lock(audio_thread_lock_);
+ // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice.
+ // Interface changes need to be made; likely, after AudioInputDevice is merged
+ // into AudioOutputDevice (http://crbug.com/179597).
+ if (stopping_hack_)
+ return;
DCHECK(audio_thread_.IsStopped());
audio_callback_.reset(
@@ -131,8 +143,8 @@ void AudioInputDevice::OnStreamCreated(
length, callback_));
audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice");
- MessageLoop::current()->PostTask(FROM_HERE,
- base::Bind(&AudioInputDevice::StartOnIOThread, this));
+ state_ = RECORDING;
+ ipc_->RecordStream();
}
void AudioInputDevice::OnVolume(double volume) {
@@ -144,22 +156,16 @@ void AudioInputDevice::OnStateChanged(
DCHECK(message_loop()->BelongsToCurrentThread());
// Do nothing if the stream has been closed.
- if (!stream_id_)
+ if (state_ < STARTING_DEVICE)
return;
+ // TODO(miu): Clean-up inconsistent and incomplete handling here.
+ // http://crbug.com/180640
switch (state) {
case AudioInputIPCDelegate::kStopped:
- // TODO(xians): Should we just call ShutDownOnIOThread here instead?
- ipc_->RemoveDelegate(stream_id_);
-
- audio_thread_.Stop(MessageLoop::current());
- audio_callback_.reset();
-
if (event_handler_)
event_handler_->OnDeviceStopped();
-
- stream_id_ = 0;
- pending_device_ready_ = false;
+ ShutDownOnIOThread();
break;
case AudioInputIPCDelegate::kRecording:
NOTIMPLEMENTED();
@@ -186,79 +192,70 @@ void AudioInputDevice::OnDeviceReady(const std::string& device_id) {
DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")";
// Takes care of the case when Stop() is called before OnDeviceReady().
- if (!pending_device_ready_)
+ if (state_ != STARTING_DEVICE)
return;
// If AudioInputDeviceManager returns an empty string, it means no device
// is ready for start.
if (device_id.empty()) {
- ipc_->RemoveDelegate(stream_id_);
- stream_id_ = 0;
+ ipc_->CloseStream();
+ state_ = IDLE;
} else {
- ipc_->CreateStream(stream_id_, audio_parameters_, device_id,
- agc_is_enabled_);
+ state_ = CREATING_STREAM;
+ ipc_->CreateStream(this, audio_parameters_, device_id, agc_is_enabled_);
}
- pending_device_ready_ = false;
// Notify the client that the device has been started.
if (event_handler_)
event_handler_->OnDeviceStarted(device_id);
}
void AudioInputDevice::OnIPCClosed() {
- ipc_ = NULL;
+ DCHECK(message_loop()->BelongsToCurrentThread());
+ state_ = IPC_CLOSED;
+ ipc_.reset();
}
AudioInputDevice::~AudioInputDevice() {
// TODO(henrika): The current design requires that the user calls
// Stop before deleting this class.
- CHECK_EQ(0, stream_id_);
+ DCHECK(audio_thread_.IsStopped());
}
-void AudioInputDevice::InitializeOnIOThread() {
+void AudioInputDevice::StartUpOnIOThread() {
DCHECK(message_loop()->BelongsToCurrentThread());
+
// Make sure we don't call Start() more than once.
- DCHECK_EQ(0, stream_id_);
- if (stream_id_)
+ if (state_ != IDLE)
return;
- stream_id_ = ipc_->AddDelegate(this);
- // If |session_id_| is not specified, it will directly create the stream;
- // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser
- // and create the stream when getting a OnDeviceReady() callback.
+ // If |session_id_| is not specified, directly create the stream. Otherwise,
+ // send a AudioInputHostMsg_StartDevice msg to the browser and create the
+ // stream after receiving a reply via the OnDeviceReady() callback.
if (!session_id_) {
- ipc_->CreateStream(stream_id_, audio_parameters_,
- AudioManagerBase::kDefaultDeviceId, agc_is_enabled_);
+ state_ = CREATING_STREAM;
+ ipc_->CreateStream(this, audio_parameters_,
+ AudioManagerBase::kDefaultDeviceId, agc_is_enabled_);
} else {
- ipc_->StartDevice(stream_id_, session_id_);
- pending_device_ready_ = true;
+ state_ = STARTING_DEVICE;
+ ipc_->StartDevice(this, session_id_);
}
}
void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
DCHECK(message_loop()->BelongsToCurrentThread());
+ DCHECK_EQ(state_, IDLE);
session_id_ = session_id;
}
-void AudioInputDevice::StartOnIOThread() {
- DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_)
- ipc_->RecordStream(stream_id_);
-}
-
void AudioInputDevice::ShutDownOnIOThread() {
DCHECK(message_loop()->BelongsToCurrentThread());
- // NOTE: |completion| may be NULL.
- // Make sure we don't call shutdown more than once.
- if (stream_id_) {
- if (ipc_) {
- ipc_->CloseStream(stream_id_);
- ipc_->RemoveDelegate(stream_id_);
- }
-
- stream_id_ = 0;
+
+ // Close the stream, if we haven't already.
+ if (state_ >= STARTING_DEVICE) {
+ ipc_->CloseStream();
+ state_ = IDLE;
session_id_ = 0;
- pending_device_ready_ = false;
agc_is_enabled_ = false;
}
@@ -266,26 +263,30 @@ void AudioInputDevice::ShutDownOnIOThread() {
// 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::AutoLock auto_lock_(audio_thread_lock_);
base::ThreadRestrictions::ScopedAllowIO allow_io;
audio_thread_.Stop(NULL);
audio_callback_.reset();
+ stopping_hack_ = false;
}
void AudioInputDevice::SetVolumeOnIOThread(double volume) {
DCHECK(message_loop()->BelongsToCurrentThread());
- if (stream_id_)
- ipc_->SetVolume(stream_id_, volume);
+ if (state_ >= CREATING_STREAM)
+ ipc_->SetVolume(volume);
}
void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
DCHECK(message_loop()->BelongsToCurrentThread());
- DCHECK_EQ(0, stream_id_) <<
- "The AGC state can not be modified while capturing is active.";
- if (stream_id_)
+
+ if (state_ >= STARTING_DEVICE) {
+ DLOG(WARNING) << "The AGC state can not be modified after starting.";
return;
+ }
// We simply store the new AGC setting here. This value will be used when
// a new stream is initialized and by GetAutomaticGainControl().

Powered by Google App Engine
This is Rietveld 408576698