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 { |