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

Side by Side 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: code review 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/renderer/media/webrtc_audio_device_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/webrtc_audio_device_impl.h" 5 #include "content/renderer/media/webrtc_audio_device_impl.h"
6 6
7 #include "base/string_util.h" 7 #include "base/string_util.h"
8 #include "media/audio/audio_util.h" 8 #include "media/audio/audio_util.h"
9 9
10 // TODO(henrika): come up with suitable value(s) for all platforms. 10 // TODO(henrika): come up with suitable value(s) for all platforms.
11 // Max supported size for input and output buffers. 11 // Max supported size for input and output buffers.
12 // Unit is in #(audio frames), hence 1440 <=> 30ms @ 48kHz. 12 // Unit is in #(audio frames), hence 1440 <=> 30ms @ 48kHz.
13 static const size_t kMaxBufferSize = 1440; 13 static const size_t kMaxBufferSize = 1440;
14 static const int kMaxChannels = 2; 14 static const int kMaxChannels = 2;
15 static const int64 kMillisecondsBetweenProcessCalls = 5000; 15 static const int64 kMillisecondsBetweenProcessCalls = 5000;
16 static const char kVersion[] = "WebRTC AudioDevice 1.0.0.Chrome"; 16 static const char kVersion[] = "WebRTC AudioDevice 1.0.0.Chrome";
17 17
18 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl( 18 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl(
19 size_t input_buffer_size, size_t output_buffer_size, 19 size_t input_buffer_size, size_t output_buffer_size,
20 int input_channels, int output_channels, 20 int input_channels, int output_channels,
21 double input_sample_rate, double output_sample_rate) 21 double input_sample_rate, double output_sample_rate)
22 : audio_transport_callback_(NULL), 22 : audio_transport_callback_(NULL),
23 last_error_(AudioDeviceModule::kAdmErrNone), 23 last_error_(AudioDeviceModule::kAdmErrNone),
24 input_buffer_size_(input_buffer_size), 24 input_buffer_size_(input_buffer_size),
25 output_buffer_size_(output_buffer_size), 25 output_buffer_size_(output_buffer_size),
26 input_channels_(input_channels), 26 input_channels_(input_channels),
27 output_channels_(output_channels), 27 output_channels_(output_channels),
28 input_sample_rate_(input_sample_rate), 28 input_sample_rate_(input_sample_rate),
29 output_sample_rate_(output_sample_rate), 29 output_sample_rate_(output_sample_rate),
30 adm_thread_("WebRtcAudioDeviceImpl"),
31 recording_stop_event_(false, false),
30 initialized_(false), 32 initialized_(false),
31 playing_(false), 33 playing_(false),
32 recording_(false), 34 recording_state_(kStopped),
33 input_delay_ms_(0), 35 input_delay_ms_(0),
34 output_delay_ms_(0), 36 output_delay_ms_(0),
35 last_process_time_(base::TimeTicks::Now()) { 37 last_process_time_(base::TimeTicks::Now()) {
36 VLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()"; 38 VLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
37 39
40 adm_thread_.Start();
41 adm_message_loop_ = adm_thread_.message_loop_proxy();
42
38 // Create an AudioInputDevice client if the requested buffer size 43 // Create an AudioInputDevice client if the requested buffer size
39 // is an even multiple of 10 milliseconds. 44 // is an even multiple of 10 milliseconds.
40 if (BufferSizeIsValid(input_buffer_size, input_sample_rate)) { 45 if (BufferSizeIsValid(input_buffer_size, input_sample_rate)) {
41 audio_input_device_ = new AudioInputDevice( 46 audio_input_device_ = new AudioInputDevice(
42 input_buffer_size, 47 input_buffer_size,
43 input_channels, 48 input_channels,
44 input_sample_rate, 49 input_sample_rate,
50 adm_message_loop_.get(),
51 this,
45 this); 52 this);
46 } 53 }
47 54
48 // Create an AudioDevice client if the requested buffer size 55 // Create an AudioDevice client if the requested buffer size
49 // is an even multiple of 10 milliseconds. 56 // is an even multiple of 10 milliseconds.
50 if (BufferSizeIsValid(output_buffer_size, output_sample_rate)) { 57 if (BufferSizeIsValid(output_buffer_size, output_sample_rate)) {
51 audio_output_device_ = new AudioDevice( 58 audio_output_device_ = new AudioDevice(
52 output_buffer_size, 59 output_buffer_size,
53 output_channels, 60 output_channels,
54 output_sample_rate, 61 output_sample_rate,
55 this); 62 this);
56 } 63 }
57 DCHECK(audio_input_device_); 64 DCHECK(audio_input_device_);
58 DCHECK(audio_output_device_); 65 DCHECK(audio_output_device_);
59 66
60 input_buffer_.reset(new int16[kMaxBufferSize * kMaxChannels]); 67 input_buffer_.reset(new int16[kMaxBufferSize * kMaxChannels]);
61 output_buffer_.reset(new int16[kMaxBufferSize * kMaxChannels]); 68 output_buffer_.reset(new int16[kMaxBufferSize * kMaxChannels]);
62 69
63 bytes_per_sample_ = sizeof(*input_buffer_.get()); 70 bytes_per_sample_ = sizeof(*input_buffer_.get());
64 } 71 }
65 72
66 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() { 73 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() {
67 VLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()"; 74 VLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
68 if (playing_) 75 if (playing_)
69 StopPlayout(); 76 StopPlayout();
70 if (recording_) 77 StopRecording();
71 StopRecording();
72 if (initialized_) 78 if (initialized_)
73 Terminate(); 79 Terminate();
80 adm_thread_.Stop();
74 } 81 }
75 82
76 void WebRtcAudioDeviceImpl::Render( 83 void WebRtcAudioDeviceImpl::Render(
77 const std::vector<float*>& audio_data, 84 const std::vector<float*>& audio_data,
78 size_t number_of_frames, 85 size_t number_of_frames,
79 size_t audio_delay_milliseconds) { 86 size_t audio_delay_milliseconds) {
80 DCHECK_LE(number_of_frames, kMaxBufferSize); 87 DCHECK_LE(number_of_frames, kMaxBufferSize);
81 88
82 // Store the reported audio delay locally. 89 // Store the reported audio delay locally.
90 lock_.Acquire();
83 output_delay_ms_ = audio_delay_milliseconds; 91 output_delay_ms_ = audio_delay_milliseconds;
92 lock_.Release();
84 93
85 const int channels = audio_data.size(); 94 const int channels = audio_data.size();
86 DCHECK_LE(channels, kMaxChannels); 95 DCHECK_LE(channels, kMaxChannels);
87 96
88 const int samples_per_sec = static_cast<int>(input_sample_rate_); 97 const int samples_per_sec = static_cast<int>(input_sample_rate_);
89 uint32_t samples_per_10_msec = (samples_per_sec / 100); 98 uint32_t samples_per_10_msec = (samples_per_sec / 100);
90 const int bytes_per_10_msec = 99 const int bytes_per_10_msec =
91 channels * samples_per_10_msec * bytes_per_sample_; 100 channels * samples_per_10_msec * bytes_per_sample_;
92 101
93 uint32_t num_audio_samples = 0; 102 uint32_t num_audio_samples = 0;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 const int bytes_per_10_msec = 156 const int bytes_per_10_msec =
148 channels * samples_per_10_msec * bytes_per_sample_; 157 channels * samples_per_10_msec * bytes_per_sample_;
149 size_t accumulated_audio_samples = 0; 158 size_t accumulated_audio_samples = 0;
150 159
151 char* audio_byte_buffer = reinterpret_cast<char*>(input_buffer_.get()); 160 char* audio_byte_buffer = reinterpret_cast<char*>(input_buffer_.get());
152 161
153 // Write audio samples in blocks of 10 milliseconds to the registered 162 // Write audio samples in blocks of 10 milliseconds to the registered
154 // webrtc::AudioTransport sink. Keep writing until our internal byte 163 // webrtc::AudioTransport sink. Keep writing until our internal byte
155 // buffer is empty. 164 // buffer is empty.
156 while (accumulated_audio_samples < number_of_frames) { 165 while (accumulated_audio_samples < number_of_frames) {
166 lock_.Acquire();
167 int output_delay_ms = output_delay_ms_;
168 lock_.Release();
157 // Deliver 10ms of recorded PCM audio. 169 // Deliver 10ms of recorded PCM audio.
158 // TODO(henrika): add support for analog AGC? 170 // TODO(henrika): add support for analog AGC?
159 audio_transport_callback_->RecordedDataIsAvailable( 171 audio_transport_callback_->RecordedDataIsAvailable(
160 audio_byte_buffer, 172 audio_byte_buffer,
161 samples_per_10_msec, 173 samples_per_10_msec,
162 bytes_per_sample_, 174 bytes_per_sample_,
163 channels, 175 channels,
164 samples_per_sec, 176 samples_per_sec,
165 input_delay_ms_ + output_delay_ms_, 177 input_delay_ms_ + output_delay_ms,
166 0, // clock_drift 178 0, // clock_drift
167 0, // current_mic_level 179 0, // current_mic_level
168 new_mic_level); // not used 180 new_mic_level); // not used
169 accumulated_audio_samples += samples_per_10_msec; 181 accumulated_audio_samples += samples_per_10_msec;
170 audio_byte_buffer += bytes_per_10_msec; 182 audio_byte_buffer += bytes_per_10_msec;
171 } 183 }
172 } 184 }
173 185
174 int32_t WebRtcAudioDeviceImpl::Version(char* version, 186 int32_t WebRtcAudioDeviceImpl::Version(char* version,
175 uint32_t& remaining_buffer_in_bytes, 187 uint32_t& remaining_buffer_in_bytes,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 int32_t WebRtcAudioDeviceImpl::RegisterEventObserver( 237 int32_t WebRtcAudioDeviceImpl::RegisterEventObserver(
226 webrtc::AudioDeviceObserver* event_callback) { 238 webrtc::AudioDeviceObserver* event_callback) {
227 VLOG(1) << "RegisterEventObserver()"; 239 VLOG(1) << "RegisterEventObserver()";
228 NOTIMPLEMENTED(); 240 NOTIMPLEMENTED();
229 return -1; 241 return -1;
230 } 242 }
231 243
232 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback( 244 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
233 webrtc::AudioTransport* audio_callback) { 245 webrtc::AudioTransport* audio_callback) {
234 VLOG(1) << "RegisterAudioCallback()"; 246 VLOG(1) << "RegisterAudioCallback()";
235 if (playing_ || recording_) { 247 int32_t error = 0;
248 base::WaitableEvent event(false, false);
249 adm_message_loop_->PostTask(FROM_HERE,
250 NewRunnableMethod(
251 this,
252 &WebRtcAudioDeviceImpl::RegisterAudioCallbackOnAdmThread,
253 audio_callback, &error, &event));
254 event.Wait();
255 return error;
256 }
257
258 void WebRtcAudioDeviceImpl::RegisterAudioCallbackOnAdmThread(
259 webrtc::AudioTransport* audio_callback,
260 int32_t* error,
261 base::WaitableEvent* event) {
262 VLOG(1) << "RegisterAudioCallbackOnAdmThread()";
263 if (playing_ || recording_state_ != kStopped) {
236 LOG(ERROR) << "Unable to (de)register transport during active media"; 264 LOG(ERROR) << "Unable to (de)register transport during active media";
237 return -1; 265 *error = -1;
266 return;
238 } 267 }
239 audio_transport_callback_ = audio_callback; 268 audio_transport_callback_ = audio_callback;
240 return 0; 269 *error = 0;
270 event->Signal();
241 } 271 }
242 272
243 int32_t WebRtcAudioDeviceImpl::Init() { 273 int32_t WebRtcAudioDeviceImpl::Init() {
244 VLOG(1) << "Init()"; 274 VLOG(1) << "Init()";
245 if (initialized_) 275 if (initialized_)
246 return 0; 276 return 0;
247 initialized_ = true; 277 initialized_ = true;
248 return 0; 278 return 0;
249 } 279 }
250 280
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 playing_ = !audio_output_device_->Stop(); 401 playing_ = !audio_output_device_->Stop();
372 return (!playing_ ? 0 : -1); 402 return (!playing_ ? 0 : -1);
373 } 403 }
374 404
375 bool WebRtcAudioDeviceImpl::Playing() const { 405 bool WebRtcAudioDeviceImpl::Playing() const {
376 return playing_; 406 return playing_;
377 } 407 }
378 408
379 int32_t WebRtcAudioDeviceImpl::StartRecording() { 409 int32_t WebRtcAudioDeviceImpl::StartRecording() {
380 VLOG(1) << "StartRecording()"; 410 VLOG(1) << "StartRecording()";
381 LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing"; 411 adm_message_loop_->PostTask(FROM_HERE,
382 if (!audio_transport_callback_) { 412 NewRunnableMethod(this,
383 LOG(ERROR) << "Audio transport is missing"; 413 &WebRtcAudioDeviceImpl::StartRecordingOnAdmThread));
384 return -1; 414 return 0;
385 } 415 }
386 if (recording_) { 416
417 void WebRtcAudioDeviceImpl::StartRecordingOnAdmThread() {
418 VLOG(1) << "StartRecordingOnAdmThread()";
419 // Required to set audio_transport_callback_ before starting recording.
420 DCHECK(audio_transport_callback_);
421 if (recording_state_ != kStopped) {
387 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and 422 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
388 // that the call is ignored the second time. 423 // that the call is ignored the second time.
389 LOG(WARNING) << "Recording is already active"; 424 LOG(WARNING) << "Recording is already active";
390 return 0; 425 return;
391 } 426 }
392 recording_ = audio_input_device_->Start(); 427 audio_input_device_->Start();
393 return (recording_ ? 0 : -1); 428 recording_state_ = kStarting;
394 } 429 }
395 430
396 int32_t WebRtcAudioDeviceImpl::StopRecording() { 431 int32_t WebRtcAudioDeviceImpl::StopRecording() {
397 VLOG(1) << "StopRecording()"; 432 VLOG(1) << "StopRecording()";
398 DCHECK(audio_input_device_); 433 adm_message_loop_->PostTask(FROM_HERE,
399 if (!recording_) { 434 NewRunnableMethod(this,
435 &WebRtcAudioDeviceImpl::StopRecordingOnAdmThread));
436 recording_stop_event_.Wait();
437 return 0;
438 }
439
440 void WebRtcAudioDeviceImpl::StopRecordingOnAdmThread() {
441 VLOG(1) << "StopRecordingOnAdmThread()";
442 // Client never sees kStopping state since it's always blocked on
443 // StopRecording() call.
444 DCHECK_NE(recording_state_, kStopping);
445 if (recording_state_ == kStopped) {
400 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case. 446 // webrtc::VoiceEngine assumes that it is OK to call Stop() just in case.
401 LOG(WARNING) << "Recording was already stopped"; 447 LOG(WARNING) << "Recording was already stopped";
402 return 0; 448 recording_stop_event_.Signal();
449 return;
403 } 450 }
404 recording_ = !audio_input_device_->Stop(); 451 audio_input_device_->Stop();
405 return (!recording_ ? 0 : -1); 452 recording_state_ = kStopping;
453 }
454
455 void WebRtcAudioDeviceImpl::OnRecordingStarted() {
456 VLOG(1) << "OnRecordingStarted()";
457 adm_message_loop_->PostTask(FROM_HERE,
458 NewRunnableMethod(this,
459 &WebRtcAudioDeviceImpl::OnRecordingStartedOnAdmThread));
460 }
461
462 void WebRtcAudioDeviceImpl::OnRecordingStartedOnAdmThread() {
463 VLOG(1) << "OnRecordingStartedOnAdmThread()";
464 recording_state_ = kStarted;
465 }
466
467 void WebRtcAudioDeviceImpl::OnRecordingStopped() {
468 VLOG(1) << "OnRecordingStopped()";
469 adm_message_loop_->PostTask(FROM_HERE,
470 NewRunnableMethod(this,
471 &WebRtcAudioDeviceImpl::OnRecordingStoppedOnAdmThread));
472 }
473
474 void WebRtcAudioDeviceImpl::OnRecordingStoppedOnAdmThread() {
475 VLOG(1) << "OnRecordingStoppedOnAdmThread()";
476 recording_state_ = kStopped;
477 // Always signal "stopped" since client must be waiting for it.
478 recording_stop_event_.Signal();
406 } 479 }
407 480
408 bool WebRtcAudioDeviceImpl::Recording() const { 481 bool WebRtcAudioDeviceImpl::Recording() const {
409 return recording_; 482 bool recording = false;
483 base::WaitableEvent event(false, false);
484 adm_message_loop_->PostTask(FROM_HERE,
485 NewRunnableMethod(this,
486 &WebRtcAudioDeviceImpl::GetRecordingOnAdmThread,
487 &recording, &event));
488 event.Wait();
489 return recording;
490 }
491
492 void WebRtcAudioDeviceImpl::GetRecordingOnAdmThread(
493 bool* recording,
494 base::WaitableEvent* event) const {
495 *recording = recording_state_ == kStarting ||
496 recording_state_ == kStarted ||
497 recording_state_ == kStopping;
498 event->Signal();
410 } 499 }
411 500
412 int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) { 501 int32_t WebRtcAudioDeviceImpl::SetAGC(bool enable) {
413 NOTIMPLEMENTED(); 502 NOTIMPLEMENTED();
414 return -1; 503 return -1;
415 } 504 }
416 505
417 bool WebRtcAudioDeviceImpl::AGC() const { 506 bool WebRtcAudioDeviceImpl::AGC() const {
418 NOTIMPLEMENTED(); 507 NOTIMPLEMENTED();
419 return false; 508 return false;
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 return -1; 726 return -1;
638 } 727 }
639 728
640 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const { 729 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const {
641 // Report the cached output delay value. 730 // Report the cached output delay value.
642 *delay_ms = static_cast<uint16_t>(output_delay_ms_); 731 *delay_ms = static_cast<uint16_t>(output_delay_ms_);
643 return 0; 732 return 0;
644 } 733 }
645 734
646 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const { 735 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
647 // Report the cached output delay value. 736 base::WaitableEvent event(false, false);
648 *delay_ms = static_cast<uint16_t>(input_delay_ms_); 737 adm_message_loop_->PostTask(FROM_HERE,
738 NewRunnableMethod(this,
739 &WebRtcAudioDeviceImpl::GetRecordingDelayOnAdmThread,
740 delay_ms, &event));
741 event.Wait();
649 return 0; 742 return 0;
650 } 743 }
651 744
745 void WebRtcAudioDeviceImpl::GetRecordingDelayOnAdmThread(
746 uint16_t* delay_ms,
747 base::WaitableEvent* event) const {
748 // Report the cached output delay value.
749 *delay_ms = static_cast<uint16_t>(input_delay_ms_);
750 event->Signal();
751 }
752
652 int32_t WebRtcAudioDeviceImpl::CPULoad(uint16_t* load) const { 753 int32_t WebRtcAudioDeviceImpl::CPULoad(uint16_t* load) const {
653 NOTIMPLEMENTED(); 754 NOTIMPLEMENTED();
654 return -1; 755 return -1;
655 } 756 }
656 757
657 int32_t WebRtcAudioDeviceImpl::StartRawOutputFileRecording( 758 int32_t WebRtcAudioDeviceImpl::StartRawOutputFileRecording(
658 const char pcm_file_name_utf8[webrtc::kAdmMaxFileNameSize]) { 759 const char pcm_file_name_utf8[webrtc::kAdmMaxFileNameSize]) {
659 NOTIMPLEMENTED(); 760 NOTIMPLEMENTED();
660 return -1; 761 return -1;
661 } 762 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 size_t buffer_size, float sample_rate) const { 824 size_t buffer_size, float sample_rate) const {
724 const int samples_per_sec = static_cast<int>(sample_rate); 825 const int samples_per_sec = static_cast<int>(sample_rate);
725 const int samples_per_10_msec = (samples_per_sec / 100); 826 const int samples_per_10_msec = (samples_per_sec / 100);
726 bool size_is_valid = (((buffer_size % samples_per_10_msec) == 0) && 827 bool size_is_valid = (((buffer_size % samples_per_10_msec) == 0) &&
727 (buffer_size <= kMaxBufferSize)); 828 (buffer_size <= kMaxBufferSize));
728 DLOG_IF(WARNING, !size_is_valid) << "Size of buffer must be and even " 829 DLOG_IF(WARNING, !size_is_valid) << "Size of buffer must be and even "
729 << "multiple of 10 ms and less than " 830 << "multiple of 10 ms and less than "
730 << kMaxBufferSize; 831 << kMaxBufferSize;
731 return size_is_valid; 832 return size_is_valid;
732 } 833 }
OLDNEW
« no previous file with comments | « content/renderer/media/webrtc_audio_device_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698