Make WebRtcAudioDeviceImpl::RemoveAudioRenderer not to change "playing_" flag.
[chromium-blink-merge.git] / content / renderer / media / webrtc_audio_device_impl.cc
bloba0817200c8f1e1e8d1d5f13f7d9b18bd87205adb
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/webrtc_audio_device_impl.h"
7 #include "base/bind.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h"
10 #include "base/win/windows_version.h"
11 #include "content/renderer/media/media_stream_audio_processor.h"
12 #include "content/renderer/media/webrtc_audio_capturer.h"
13 #include "content/renderer/media/webrtc_audio_renderer.h"
14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_parameters.h"
16 #include "media/audio/sample_rates.h"
18 using media::AudioParameters;
19 using media::ChannelLayout;
21 namespace content {
23 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
24 : ref_count_(0),
25 audio_transport_callback_(NULL),
26 output_delay_ms_(0),
27 initialized_(false),
28 playing_(false),
29 recording_(false),
30 microphone_volume_(0) {
31 DVLOG(1) << "WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()";
32 // This object can be constructed on either the signaling thread or the main
33 // thread, so we need to detach these thread checkers here and have them
34 // initialize automatically when the first methods are called.
35 signaling_thread_checker_.DetachFromThread();
36 main_thread_checker_.DetachFromThread();
38 worker_thread_checker_.DetachFromThread();
41 WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl() {
42 DVLOG(1) << "WebRtcAudioDeviceImpl::~WebRtcAudioDeviceImpl()";
43 DCHECK(main_thread_checker_.CalledOnValidThread());
44 Terminate();
47 int32_t WebRtcAudioDeviceImpl::AddRef() {
48 // We can be AddRefed and released on both the UI thread as well as
49 // libjingle's signaling thread.
50 return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1);
53 int32_t WebRtcAudioDeviceImpl::Release() {
54 // We can be AddRefed and released on both the UI thread as well as
55 // libjingle's signaling thread.
56 int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1);
57 if (ret == 0) {
58 delete this;
60 return ret;
63 void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus,
64 int sample_rate,
65 int audio_delay_milliseconds,
66 base::TimeDelta* current_time) {
68 base::AutoLock auto_lock(lock_);
69 if (!playing_) {
70 return;
72 DCHECK(audio_transport_callback_);
73 // Store the reported audio delay locally.
74 output_delay_ms_ = audio_delay_milliseconds;
77 render_buffer_.resize(audio_bus->frames() * audio_bus->channels());
78 int frames_per_10_ms = (sample_rate / 100);
79 int bytes_per_sample = sizeof(render_buffer_[0]);
80 const int bytes_per_10_ms =
81 audio_bus->channels() * frames_per_10_ms * bytes_per_sample;
82 DCHECK_EQ(audio_bus->frames() % frames_per_10_ms, 0);
84 // Get audio frames in blocks of 10 milliseconds from the registered
85 // webrtc::AudioTransport source. Keep reading until our internal buffer
86 // is full.
87 int accumulated_audio_frames = 0;
88 int16* audio_data = &render_buffer_[0];
89 while (accumulated_audio_frames < audio_bus->frames()) {
90 // Get 10ms and append output to temporary byte buffer.
91 int64_t elapsed_time_ms = -1;
92 int64_t ntp_time_ms = -1;
93 static const int kBitsPerByte = 8;
94 audio_transport_callback_->PullRenderData(bytes_per_sample * kBitsPerByte,
95 sample_rate,
96 audio_bus->channels(),
97 frames_per_10_ms,
98 audio_data,
99 &elapsed_time_ms,
100 &ntp_time_ms);
101 accumulated_audio_frames += frames_per_10_ms;
102 if (elapsed_time_ms >= 0) {
103 *current_time = base::TimeDelta::FromMilliseconds(elapsed_time_ms);
105 audio_data += bytes_per_10_ms;
108 // De-interleave each channel and convert to 32-bit floating-point
109 // with nominal range -1.0 -> +1.0 to match the callback format.
110 audio_bus->FromInterleaved(&render_buffer_[0],
111 audio_bus->frames(),
112 bytes_per_sample);
114 // Pass the render data to the playout sinks.
115 base::AutoLock auto_lock(lock_);
116 for (PlayoutDataSinkList::const_iterator it = playout_sinks_.begin();
117 it != playout_sinks_.end(); ++it) {
118 (*it)->OnPlayoutData(audio_bus, sample_rate, audio_delay_milliseconds);
122 void WebRtcAudioDeviceImpl::RemoveAudioRenderer(WebRtcAudioRenderer* renderer) {
123 DCHECK(main_thread_checker_.CalledOnValidThread());
124 base::AutoLock auto_lock(lock_);
125 DCHECK_EQ(renderer, renderer_.get());
126 // Notify the playout sink of the change.
127 for (PlayoutDataSinkList::const_iterator it = playout_sinks_.begin();
128 it != playout_sinks_.end(); ++it) {
129 (*it)->OnPlayoutDataSourceChanged();
132 renderer_ = NULL;
135 int32_t WebRtcAudioDeviceImpl::RegisterAudioCallback(
136 webrtc::AudioTransport* audio_callback) {
137 DVLOG(1) << "WebRtcAudioDeviceImpl::RegisterAudioCallback()";
138 DCHECK(signaling_thread_checker_.CalledOnValidThread());
139 base::AutoLock lock(lock_);
140 DCHECK_EQ(audio_transport_callback_ == NULL, audio_callback != NULL);
141 audio_transport_callback_ = audio_callback;
142 return 0;
145 int32_t WebRtcAudioDeviceImpl::Init() {
146 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()";
147 DCHECK(signaling_thread_checker_.CalledOnValidThread());
149 // We need to return a success to continue the initialization of WebRtc VoE
150 // because failure on the capturer_ initialization should not prevent WebRTC
151 // from working. See issue http://crbug.com/144421 for details.
152 initialized_ = true;
154 return 0;
157 int32_t WebRtcAudioDeviceImpl::Terminate() {
158 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()";
159 DCHECK(signaling_thread_checker_.CalledOnValidThread());
161 // Calling Terminate() multiple times in a row is OK.
162 if (!initialized_)
163 return 0;
165 StopRecording();
166 StopPlayout();
168 DCHECK(!renderer_.get() || !renderer_->IsStarted())
169 << "The shared audio renderer shouldn't be running";
171 // Stop all the capturers to ensure no further OnData() and
172 // RemoveAudioCapturer() callback.
173 // Cache the capturers in a local list since WebRtcAudioCapturer::Stop()
174 // will trigger RemoveAudioCapturer() callback.
175 CapturerList capturers;
176 capturers.swap(capturers_);
177 for (CapturerList::const_iterator iter = capturers.begin();
178 iter != capturers.end(); ++iter) {
179 (*iter)->Stop();
182 initialized_ = false;
183 return 0;
186 bool WebRtcAudioDeviceImpl::Initialized() const {
187 DCHECK(signaling_thread_checker_.CalledOnValidThread());
188 return initialized_;
191 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) {
192 DCHECK(signaling_thread_checker_.CalledOnValidThread());
193 *available = initialized_;
194 return 0;
197 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const {
198 DCHECK(signaling_thread_checker_.CalledOnValidThread());
199 return initialized_;
202 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) {
203 DCHECK(signaling_thread_checker_.CalledOnValidThread());
204 base::AutoLock auto_lock(lock_);
205 *available = (!capturers_.empty());
206 return 0;
209 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const {
210 DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()";
211 DCHECK(signaling_thread_checker_.CalledOnValidThread());
212 base::AutoLock auto_lock(lock_);
213 return (!capturers_.empty());
216 int32_t WebRtcAudioDeviceImpl::StartPlayout() {
217 DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()";
218 DCHECK(worker_thread_checker_.CalledOnValidThread());
219 base::AutoLock auto_lock(lock_);
220 if (!audio_transport_callback_) {
221 LOG(ERROR) << "Audio transport is missing";
222 return 0;
225 // webrtc::VoiceEngine assumes that it is OK to call Start() twice and
226 // that the call is ignored the second time.
227 playing_ = true;
228 return 0;
231 int32_t WebRtcAudioDeviceImpl::StopPlayout() {
232 DVLOG(1) << "WebRtcAudioDeviceImpl::StopPlayout()";
233 DCHECK(initialized_);
234 // Can be called both from the worker thread (e.g. when called from webrtc)
235 // or the signaling thread (e.g. when we call it ourselves internally).
236 // The order in this check is important so that we won't incorrectly
237 // initialize worker_thread_checker_ on the signaling thread.
238 DCHECK(signaling_thread_checker_.CalledOnValidThread() ||
239 worker_thread_checker_.CalledOnValidThread());
240 base::AutoLock auto_lock(lock_);
241 // webrtc::VoiceEngine assumes that it is OK to call Stop() multiple times.
242 playing_ = false;
243 return 0;
246 bool WebRtcAudioDeviceImpl::Playing() const {
247 DCHECK(worker_thread_checker_.CalledOnValidThread());
248 base::AutoLock auto_lock(lock_);
249 return playing_;
252 int32_t WebRtcAudioDeviceImpl::StartRecording() {
253 DVLOG(1) << "WebRtcAudioDeviceImpl::StartRecording()";
254 DCHECK(worker_thread_checker_.CalledOnValidThread());
255 DCHECK(initialized_);
256 base::AutoLock auto_lock(lock_);
257 if (!audio_transport_callback_) {
258 LOG(ERROR) << "Audio transport is missing";
259 return -1;
262 recording_ = true;
264 return 0;
267 int32_t WebRtcAudioDeviceImpl::StopRecording() {
268 DVLOG(1) << "WebRtcAudioDeviceImpl::StopRecording()";
269 DCHECK(initialized_);
270 // Can be called both from the worker thread (e.g. when called from webrtc)
271 // or the signaling thread (e.g. when we call it ourselves internally).
272 // The order in this check is important so that we won't incorrectly
273 // initialize worker_thread_checker_ on the signaling thread.
274 DCHECK(signaling_thread_checker_.CalledOnValidThread() ||
275 worker_thread_checker_.CalledOnValidThread());
277 base::AutoLock auto_lock(lock_);
278 recording_ = false;
279 return 0;
282 bool WebRtcAudioDeviceImpl::Recording() const {
283 DCHECK(worker_thread_checker_.CalledOnValidThread());
284 base::AutoLock auto_lock(lock_);
285 return recording_;
288 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
289 DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")";
290 DCHECK(signaling_thread_checker_.CalledOnValidThread());
291 DCHECK(initialized_);
293 // Only one microphone is supported at the moment, which is represented by
294 // the default capturer.
295 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
296 if (!capturer.get())
297 return -1;
299 capturer->SetVolume(volume);
300 return 0;
303 // TODO(henrika): sort out calling thread once we start using this API.
304 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
305 DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()";
306 DCHECK(signaling_thread_checker_.CalledOnValidThread());
307 // We only support one microphone now, which is accessed via the default
308 // capturer.
309 DCHECK(initialized_);
310 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
311 if (!capturer.get())
312 return -1;
314 *volume = static_cast<uint32_t>(capturer->Volume());
316 return 0;
319 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
320 DCHECK(initialized_);
321 DCHECK(signaling_thread_checker_.CalledOnValidThread());
322 *max_volume = kMaxVolumeLevel;
323 return 0;
326 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const {
327 DCHECK(signaling_thread_checker_.CalledOnValidThread());
328 *min_volume = 0;
329 return 0;
332 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const {
333 DCHECK(initialized_);
334 // This method is called during initialization on the signaling thread and
335 // then later on the worker thread. Due to this we cannot DCHECK on what
336 // thread we're on since it might incorrectly initialize the
337 // worker_thread_checker_.
338 base::AutoLock auto_lock(lock_);
339 *available = renderer_.get() && renderer_->channels() == 2;
340 return 0;
343 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable(
344 bool* available) const {
345 DCHECK(initialized_);
346 // This method is called during initialization on the signaling thread and
347 // then later on the worker thread. Due to this we cannot DCHECK on what
348 // thread we're on since it might incorrectly initialize the
349 // worker_thread_checker_.
351 // TODO(xians): These kind of hardware methods do not make much sense since we
352 // support multiple sources. Remove or figure out new APIs for such methods.
353 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
354 if (!capturer.get())
355 return -1;
357 *available = (capturer->source_audio_parameters().channels() == 2);
358 return 0;
361 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const {
362 DCHECK(worker_thread_checker_.CalledOnValidThread());
363 base::AutoLock auto_lock(lock_);
364 *delay_ms = static_cast<uint16_t>(output_delay_ms_);
365 return 0;
368 int32_t WebRtcAudioDeviceImpl::RecordingDelay(uint16_t* delay_ms) const {
369 DCHECK(signaling_thread_checker_.CalledOnValidThread());
371 // There is no way to report a correct delay value to WebRTC since there
372 // might be multiple WebRtcAudioCapturer instances.
373 NOTREACHED();
374 return -1;
377 int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
378 uint32_t* sample_rate) const {
379 DCHECK(signaling_thread_checker_.CalledOnValidThread());
380 // We use the default capturer as the recording sample rate.
381 scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
382 if (!capturer.get())
383 return -1;
385 *sample_rate = static_cast<uint32_t>(
386 capturer->source_audio_parameters().sample_rate());
387 return 0;
390 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate(
391 uint32_t* sample_rate) const {
392 DCHECK(signaling_thread_checker_.CalledOnValidThread());
393 *sample_rate = renderer_.get() ? renderer_->sample_rate() : 0;
394 return 0;
397 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) {
398 DCHECK(main_thread_checker_.CalledOnValidThread());
399 DCHECK(renderer);
401 // Here we acquire |lock_| in order to protect the internal state.
403 base::AutoLock auto_lock(lock_);
404 if (renderer_.get())
405 return false;
408 // We release |lock_| here because invoking |renderer|->Initialize while
409 // holding |lock_| would result in locks taken in the sequence
410 // (|this->lock_|, |renderer->lock_|) while another thread (i.e, the
411 // AudioOutputDevice thread) might concurrently invoke a renderer method,
412 // which can itself invoke a method from |this|, resulting in locks taken in
413 // the sequence (|renderer->lock_|, |this->lock_|) in that thread.
414 // This order discrepancy can cause a deadlock (see Issue 433993).
415 // However, we do not need to hold |this->lock_| in order to invoke
416 // |renderer|->Initialize, since it does not involve any unprotected access to
417 // the internal state of |this|.
418 if (!renderer->Initialize(this))
419 return false;
421 // We acquire |lock_| again and assert our precondition, since we are
422 // accessing the internal state again.
423 base::AutoLock auto_lock(lock_);
424 DCHECK(!renderer_.get());
425 renderer_ = renderer;
426 return true;
429 void WebRtcAudioDeviceImpl::AddAudioCapturer(
430 const scoped_refptr<WebRtcAudioCapturer>& capturer) {
431 DCHECK(main_thread_checker_.CalledOnValidThread());
432 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
433 DCHECK(capturer.get());
434 DCHECK(!capturer->device_id().empty());
436 base::AutoLock auto_lock(lock_);
437 DCHECK(std::find(capturers_.begin(), capturers_.end(), capturer) ==
438 capturers_.end());
439 capturers_.push_back(capturer);
442 void WebRtcAudioDeviceImpl::RemoveAudioCapturer(
443 const scoped_refptr<WebRtcAudioCapturer>& capturer) {
444 DCHECK(main_thread_checker_.CalledOnValidThread());
445 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
446 DCHECK(capturer.get());
447 base::AutoLock auto_lock(lock_);
448 capturers_.remove(capturer);
451 scoped_refptr<WebRtcAudioCapturer>
452 WebRtcAudioDeviceImpl::GetDefaultCapturer() const {
453 // Called on the signaling thread (during initialization), worker
454 // thread during capture or main thread for a WebAudio source.
455 // We can't DCHECK on those three checks here since GetDefaultCapturer
456 // may be the first call and therefore could incorrectly initialize the
457 // thread checkers.
458 DCHECK(initialized_);
459 base::AutoLock auto_lock(lock_);
460 // Use the last |capturer| which is from the latest getUserMedia call as
461 // the default capture device.
462 return capturers_.empty() ? NULL : capturers_.back();
465 void WebRtcAudioDeviceImpl::AddPlayoutSink(
466 WebRtcPlayoutDataSource::Sink* sink) {
467 DCHECK(main_thread_checker_.CalledOnValidThread());
468 DCHECK(sink);
469 base::AutoLock auto_lock(lock_);
470 DCHECK(std::find(playout_sinks_.begin(), playout_sinks_.end(), sink) ==
471 playout_sinks_.end());
472 playout_sinks_.push_back(sink);
475 void WebRtcAudioDeviceImpl::RemovePlayoutSink(
476 WebRtcPlayoutDataSource::Sink* sink) {
477 DCHECK(main_thread_checker_.CalledOnValidThread());
478 DCHECK(sink);
479 base::AutoLock auto_lock(lock_);
480 playout_sinks_.remove(sink);
483 bool WebRtcAudioDeviceImpl::GetAuthorizedDeviceInfoForAudioRenderer(
484 int* session_id,
485 int* output_sample_rate,
486 int* output_frames_per_buffer) {
487 DCHECK(main_thread_checker_.CalledOnValidThread());
488 base::AutoLock lock(lock_);
489 // If there is no capturer or there are more than one open capture devices,
490 // return false.
491 if (capturers_.size() != 1)
492 return false;
494 return capturers_.back()->GetPairedOutputParameters(
495 session_id, output_sample_rate, output_frames_per_buffer);
498 } // namespace content