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

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

Issue 7497025: refactor AudioInputDevice to remove race condition. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rebase + minor update 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
Index: content/renderer/media/webrtc_audio_device_impl.cc
===================================================================
--- content/renderer/media/webrtc_audio_device_impl.cc (revision 95453)
+++ content/renderer/media/webrtc_audio_device_impl.cc (working copy)
@@ -16,9 +16,9 @@
static const char kVersion[] = "WebRTC AudioDevice 1.0.0.Chrome";
WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl(
- size_t input_buffer_size, size_t output_buffer_size,
- int input_channels, int output_channels,
- double input_sample_rate, double output_sample_rate)
+ size_t input_buffer_size, size_t output_buffer_size,
+ int input_channels, int output_channels,
+ double input_sample_rate, double output_sample_rate)
: audio_transport_callback_(NULL),
last_error_(AudioDeviceModule::kAdmErrNone),
input_buffer_size_(input_buffer_size),
@@ -27,14 +27,19 @@
output_channels_(output_channels),
input_sample_rate_(input_sample_rate),
output_sample_rate_(output_sample_rate),
+ adm_thread_("WebRtcAudioDeviceImpl"),
+ recording_stop_event_(false, false),
initialized_(false),
playing_(false),
- recording_(false),
+ recording_state_(kStopped),
input_delay_ms_(0),
output_delay_ms_(0),
last_process_time_(base::TimeTicks::Now()) {
VLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
+ adm_thread_.Start();
+ adm_message_loop_ = adm_thread_.message_loop_proxy();
+
// Create an AudioInputDevice client if the requested buffer size
// is an even multiple of 10 milliseconds.
if (BufferSizeIsValid(input_buffer_size, input_sample_rate)) {
@@ -42,6 +47,8 @@
input_buffer_size,
input_channels,
input_sample_rate,
+ adm_message_loop_.get(),
henrika_dont_use 2011/08/07 16:52:27 Perhaps add a comment on what we want to achieve b
wjia(left Chromium) 2011/08/09 01:40:36 Added some comments in AudioInputDevice constructo
+ this,
this);
}
@@ -67,10 +74,10 @@
VLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
if (playing_)
StopPlayout();
- if (recording_)
- StopRecording();
+ StopRecording();
if (initialized_)
Terminate();
+ adm_thread_.Stop();
}
void WebRtcAudioDeviceImpl::Render(
@@ -80,7 +87,9 @@
DCHECK_LE(number_of_frames, kMaxBufferSize);
// Store the reported audio delay locally.
+ lock_.Acquire();
output_delay_ms_ = audio_delay_milliseconds;
+ lock_.Release();
const int channels = audio_data.size();
DCHECK_LE(channels, kMaxChannels);
@@ -154,6 +163,9 @@
// webrtc::AudioTransport sink. Keep writing until our internal byte
// buffer is empty.
while (accumulated_audio_samples < number_of_frames) {
+ lock_.Acquire();
+ int output_delay_ms = output_delay_ms_;
+ lock_.Release();
// Deliver 10ms of recorded PCM audio.
// TODO(henrika): add support for analog AGC?
audio_transport_callback_->RecordedDataIsAvailable(
@@ -162,7 +174,7 @@
bytes_per_sample_,
channels,
samples_per_sec,
- input_delay_ms_ + output_delay_ms_,
+ input_delay_ms_ + output_delay_ms,
0, // clock_drift
0, // current_mic_level
new_mic_level); // not used
@@ -232,12 +244,30 @@
int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
webrtc::AudioTransport* audio_callback) {
VLOG(1) << "RegisterAudioCallback()";
- if (playing_ || recording_) {
+ int32_t error = 0;
+ base::WaitableEvent event(false, false);
+ adm_message_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &WebRtcAudioDeviceImpl::RegisterAudioCallbackOnAdmThread,
+ audio_callback, &error, &event));
+ event.Wait();
+ return error;
+}
+
+void WebRtcAudioDeviceImpl::RegisterAudioCallbackOnAdmThread(
+ webrtc::AudioTransport* audio_callback,
+ int32_t* error,
+ base::WaitableEvent* event) {
+ VLOG(1) << "RegisterAudioCallbackOnAdmThread()";
+ if (playing_ || recording_state_ != kStopped) {
LOG(ERROR) << "Unable to (de)register transport during active media";
- return -1;
+ *error = -1;
+ return;
}
audio_transport_callback_ = audio_callback;
- return 0;
+ *error = 0;
+ event->Signal();
}
int32_t WebRtcAudioDeviceImpl::Init() {
@@ -378,37 +408,96 @@
int32_t WebRtcAudioDeviceImpl::StartRecording() {
VLOG(1) << "StartRecording()";
- LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing";
- if (!audio_transport_callback_) {
- LOG(ERROR) << "Audio transport is missing";
- return -1;
- }
- if (recording_) {
+ adm_message_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &WebRtcAudioDeviceImpl::StartRecordingOnAdmThread));
+ return 0;
+}
+
+void WebRtcAudioDeviceImpl::StartRecordingOnAdmThread() {
+ VLOG(1) << "StartRecordingOnAdmThread()";
+ // Required to set audio_transport_callback_ before starting recording.
+ DCHECK(audio_transport_callback_);
+ if (recording_state_ != kStopped) {
// webrtc::VoiceEngine assumes that it is OK to call Start() twice and
// that the call is ignored the second time.
LOG(WARNING) << "Recording is already active";
- return 0;
+ return;
}
- recording_ = audio_input_device_->Start();
- return (recording_ ? 0 : -1);
+ audio_input_device_->Start();
+ recording_state_ = kStarting;
}
int32_t WebRtcAudioDeviceImpl::StopRecording() {
VLOG(1) << "StopRecording()";
- DCHECK(audio_input_device_);
- if (!recording_) {
+ adm_message_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &WebRtcAudioDeviceImpl::StopRecordingOnAdmThread));
+ recording_stop_event_.Wait();
+ return 0;
+}
+
+void WebRtcAudioDeviceImpl::StopRecordingOnAdmThread() {
+ VLOG(1) << "StopRecordingOnAdmThread()";
+ // Client never sees kStopping state since it's always blocked on
+ // StopRecording() call.
+ DCHECK_NE(recording_state_, kStopping);
+ if (recording_state_ == kStopped) {
// webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
LOG(WARNING) << "Recording was already stopped";
- return 0;
+ recording_stop_event_.Signal();
+ return;
}
- recording_ = !audio_input_device_->Stop();
- return (!recording_ ? 0 : -1);
+ audio_input_device_->Stop();
+ recording_state_ = kStopping;
}
+void WebRtcAudioDeviceImpl::OnRecordingStarted() {
+ VLOG(1) << "OnRecordingStarted()";
+ adm_message_loop_->PostTask(FROM_HERE,
henrika_dont_use 2011/08/07 16:52:27 Can't we set state in this method directly? It is
wjia(left Chromium) 2011/08/09 01:40:36 Setting state here put some assumption on AudioInp
+ NewRunnableMethod(this,
+ &WebRtcAudioDeviceImpl::OnRecordingStartedOnAdmThread));
+}
+
+void WebRtcAudioDeviceImpl::OnRecordingStartedOnAdmThread() {
+ VLOG(1) << "OnRecordingStartedOnAdmThread()";
+ recording_state_ = kStarted;
+}
+
+void WebRtcAudioDeviceImpl::OnRecordingStopped() {
+ VLOG(1) << "OnRecordingStopped()";
+ adm_message_loop_->PostTask(FROM_HERE,
henrika_dont_use 2011/08/07 16:52:27 Same comment as for Start.
wjia(left Chromium) 2011/08/09 01:40:36 See comments above.
+ NewRunnableMethod(this,
+ &WebRtcAudioDeviceImpl::OnRecordingStoppedOnAdmThread));
+}
+
+void WebRtcAudioDeviceImpl::OnRecordingStoppedOnAdmThread() {
+ VLOG(1) << "OnRecordingStoppedOnAdmThread()";
+ recording_state_ = kStopped;
+ // Always signal "stopped" since client must be waiting for it.
+ recording_stop_event_.Signal();
+}
+
bool WebRtcAudioDeviceImpl::Recording() const {
- return recording_;
+ bool recording = false;
+ base::WaitableEvent event(false, false);
+ adm_message_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &WebRtcAudioDeviceImpl::GetRecordingOnAdmThread,
+ &recording, &event));
+ event.Wait();
+ return recording;
}
+void WebRtcAudioDeviceImpl::GetRecordingOnAdmThread(
+ bool* recording,
+ base::WaitableEvent* event) const {
+ *recording = recording_state_ == kStarting ||
+ recording_state_ == kStarted ||
+ recording_state_ == kStopping;
+ event->Signal();
+}
+
int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) {
NOTIMPLEMENTED();
return -1;
@@ -644,9 +733,21 @@
}
int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
+ base::WaitableEvent event(false, false);
+ adm_message_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &WebRtcAudioDeviceImpl::GetRecordingDelayOnAdmThread,
+ delay_ms, &event));
+ event.Wait();
+ return 0;
+}
+
+void WebRtcAudioDeviceImpl::GetRecordingDelayOnAdmThread(
+ uint16_t* delay_ms,
+ base::WaitableEvent* event) const {
// Report the cached output delay value.
*delay_ms = static_cast<uint16_t>(input_delay_ms_);
- return 0;
+ event->Signal();
}
int32_t WebRtcAudioDeviceImpl::CPULoad(uint16_t* load) const {

Powered by Google App Engine
This is Rietveld 408576698