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

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

Issue 7661017: Refactor AudioInputDevice to remove race conditions and allow more flexible calling sequences. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Minor changes based on review by Andrew Created 9 years, 4 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
« no previous file with comments | « content/renderer/media/audio_input_device.h ('k') | content/renderer/media/audio_input_message_filter.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/media/audio_input_device.cc
===================================================================
--- content/renderer/media/audio_input_device.cc (revision 98001)
+++ content/renderer/media/audio_input_device.cc (working copy)
@@ -5,12 +5,19 @@
#include "content/renderer/media/audio_input_device.h"
#include "base/message_loop.h"
+#include "base/time.h"
#include "content/common/child_process.h"
#include "content/common/media/audio_messages.h"
#include "content/common/view_messages.h"
#include "content/renderer/render_thread.h"
#include "media/audio/audio_util.h"
+// Max waiting time for Stop() to complete. If this time limit is passed,
+// we will stop waiting and return false. It ensures that Stop() can't block
+// the calling thread forever.
+static const base::TimeDelta kMaxTimeOut =
+ base::TimeDelta::FromMilliseconds(1000);
+
AudioInputDevice::AudioInputDevice(size_t buffer_size,
int channels,
double sample_rate,
@@ -32,19 +39,15 @@
}
AudioInputDevice::~AudioInputDevice() {
- // Make sure we have been shut down.
- DCHECK_EQ(0, stream_id_);
- Stop();
+ // TODO(henrika): The current design requires that the user calls
+ // Stop before deleting this class.
+ CHECK_EQ(0, stream_id_);
for (int i = 0; i < channels_; ++i)
delete [] audio_data_[i];
}
-bool AudioInputDevice::Start() {
- // Make sure we don't call Start() more than once.
- DCHECK_EQ(0, stream_id_);
- if (stream_id_)
- return false;
-
+void AudioInputDevice::Start() {
+ VLOG(1) << "Start()";
AudioParameters params;
// TODO(henrika): add support for low-latency mode?
params.format = AudioParameters::AUDIO_PCM_LINEAR;
@@ -56,21 +59,32 @@
ChildProcess::current()->io_message_loop()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread, params));
-
- return true;
}
bool AudioInputDevice::Stop() {
- if (!stream_id_)
- return false;
+ VLOG(1) << "Stop()";
+ base::WaitableEvent completion(false, false);
ChildProcess::current()->io_message_loop()->PostTask(
FROM_HERE,
- NewRunnableMethod(this, &AudioInputDevice::ShutDownOnIOThread));
+ NewRunnableMethod(this, &AudioInputDevice::ShutDownOnIOThread,
+ &completion));
- if (audio_thread_.get()) {
- socket_->Close();
- audio_thread_->Join();
+ // We wait here for the IO task to be completed to remove race conflicts
+ // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
+ // function call.
+ if (completion.TimedWait(kMaxTimeOut)) {
+ if (audio_thread_.get()) {
+ // Terminate the main thread function in the audio thread.
+ socket_->Close();
+ // Wait for the audio thread to exit.
+ audio_thread_->Join();
+ // Ensures that we can call Stop() multiple times.
+ audio_thread_.reset(NULL);
+ }
+ } else {
+ LOG(ERROR) << "Failed to shut down audio input on IO thread";
+ return false;
}
return true;
@@ -87,26 +101,39 @@
}
void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) {
+ DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+ // Make sure we don't call Start() more than once.
+ DCHECK_EQ(0, stream_id_);
+ if (stream_id_)
+ return;
+
stream_id_ = filter_->AddDelegate(this);
Send(new AudioInputHostMsg_CreateStream(stream_id_, params, true));
}
void AudioInputDevice::StartOnIOThread() {
+ DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
if (stream_id_)
Send(new AudioInputHostMsg_RecordStream(stream_id_));
}
-void AudioInputDevice::ShutDownOnIOThread() {
+void AudioInputDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
+ DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
// Make sure we don't call shutdown more than once.
- if (!stream_id_)
+ if (!stream_id_) {
+ completion->Signal();
return;
+ }
filter_->RemoveDelegate(stream_id_);
Send(new AudioInputHostMsg_CloseStream(stream_id_));
stream_id_ = 0;
+
+ completion->Signal();
}
void AudioInputDevice::SetVolumeOnIOThread(double volume) {
+ DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
if (stream_id_)
Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
}
@@ -125,13 +152,21 @@
#endif
DCHECK(length);
+ VLOG(1) << "OnLowLatencyCreated (stream_id=" << stream_id_ << ")";
+ // Takes care of the case when Stop() is called before OnLowLatencyCreated().
+ if (!stream_id_) {
+ base::SharedMemory::CloseHandle(handle);
+ base::SyncSocket socket(socket_handle);
+ return;
+ }
+
shared_memory_.reset(new base::SharedMemory(handle, false));
shared_memory_->Map(length);
socket_.reset(new base::SyncSocket(socket_handle));
audio_thread_.reset(
- new base::DelegateSimpleThread(this, "renderer_audio_input_thread"));
+ new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
audio_thread_->Start();
MessageLoop::current()->PostTask(
@@ -158,7 +193,7 @@
while (sizeof(pending_data) == socket_->Receive(&pending_data,
sizeof(pending_data)) &&
- pending_data >= 0) {
+ pending_data >= 0) {
// TODO(henrika): investigate the provided |pending_data| value
// and ensure that it is actually an accurate delay estimation.
« no previous file with comments | « content/renderer/media/audio_input_device.h ('k') | content/renderer/media/audio_input_message_filter.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698