audio_output_controller.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_output_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
10a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/metrics/histogram.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "build/build_config.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/audio/audio_silence_detector.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/shared_memory_util.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "media/base/scoped_histogram_timer.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Amount of contiguous time where all audio is silent before considering the
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// stream to have transitioned and EventHandler::OnAudible() should be called.
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static const int kQuestionableSilencePeriodMillis = 50;
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Sample value range below which audio is considered indistinguishably silent.
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(miu): This value should be specified in dbFS units rather than full
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// scale.  See TODO in audio_silence_detector.h.
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static const float kIndistinguishableSilenceThreshold =
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    1.0f / 4096.0f;  // Note: This is approximately -72 dbFS.
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Polling-related constants.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int AudioOutputController::kPollNumAttempts = 3;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int AudioOutputController::kPollPauseInMilliseconds = 3;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputController::AudioOutputController(AudioManager* audio_manager,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             EventHandler* handler,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const AudioParameters& params,
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             const std::string& input_device_id,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             SyncReader* sync_reader)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : audio_manager_(audio_manager),
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params_(params),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handler_(handler),
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      input_device_id_(input_device_id),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_(NULL),
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      diverting_to_stream_(NULL),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      volume_(1.0),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(kEmpty),
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      num_allowed_io_(0),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_reader_(sync_reader),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_loop_(audio_manager->GetMessageLoop()),
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      number_polling_attempts_left_(0) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(audio_manager);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(handler_);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(sync_reader_);
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(message_loop_.get());
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputController::~AudioOutputController() {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(kClosed, state_);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<AudioOutputController> AudioOutputController::Create(
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AudioManager* audio_manager,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EventHandler* event_handler,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioParameters& params,
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& input_device_id,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncReader* sync_reader) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_manager);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_reader);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!params.IsValid() || !audio_manager)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<AudioOutputController> controller(new AudioOutputController(
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      audio_manager, event_handler, params, input_device_id, sync_reader));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  controller->message_loop_->PostTask(FROM_HERE, base::Bind(
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &AudioOutputController::DoCreate, controller, false));
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return controller;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Play() {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoPlay, this));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Pause() {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoPause, this));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Close(const base::Closure& closed_task) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!closed_task.is_null());
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTaskAndReply(FROM_HERE, base::Bind(
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoClose, this), closed_task);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::SetVolume(double volume) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoSetVolume, this, volume));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoCreate(bool is_for_device_change) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close() can be called before DoCreate() is executed.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == kClosed)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoStopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(kEmpty, state_);
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  stream_ = diverting_to_stream_ ? diverting_to_stream_ :
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      audio_manager_->MakeAudioOutputStreamProxy(params_, input_device_id_);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kError;
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_->Open()) {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoStopCloseAndClearStream();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kError;
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Everything started okay, so re-register for state change callbacks if
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // stream_ was created via AudioManager.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (stream_ != diverting_to_stream_)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    audio_manager_->AddOutputDeviceChangeListener(this);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We have successfully opened the stream. Set the initial volume.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_->SetVolume(volume_);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally set the state to kCreated.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = kCreated;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And then report we have been created if we haven't done so already.
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_for_device_change)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnCreated();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoPlay() {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can start from created or paused state.
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ != kCreated && state_ != kPaused)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ask for first packet.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_reader_->UpdatePendingBytes(0);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = kPlaying;
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  silence_detector_.reset(new AudioSilenceDetector(
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      params_.sample_rate(),
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis),
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kIndistinguishableSilenceThreshold));
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We start the AudioOutputStream lazily.
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AllowEntryToOnMoreIOData();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_->Start(this);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Tell the event handler that we are now playing, and also start the silence
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // detection notifications.
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handler_->OnPlaying();
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  silence_detector_->Start(
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&EventHandler::OnAudible, base::Unretained(handler_)));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StopStream() {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == kPlaying) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_->Stop();
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DisallowEntryToOnMoreIOData();
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    silence_detector_->Stop(true);
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    silence_detector_.reset();
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_ = kPaused;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoPause() {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StopStream();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ != kPaused)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send a special pause mark to the low-latency audio thread.
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sync_reader_->UpdatePendingBytes(kPauseMark);
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handler_->OnPaused();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoClose() {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != kClosed) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoStopCloseAndClearStream();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_reader_->Close();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kClosed;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoSetVolume(double volume) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Saves the volume to a member first. We may not be able to set the volume
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // right away but when the stream is created we'll set the volume.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  volume_ = volume;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCreated:
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPlaying:
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPaused:
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_->SetVolume(volume_);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoReportError() {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != kClosed)
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AudioOutputController::OnMoreData(AudioBus* dest,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      AudioBuffersState buffers_state) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OnMoreIOData(NULL, dest, buffers_state);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AudioOutputController::OnMoreIOData(AudioBus* source,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        AudioBus* dest,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        AudioBuffersState buffers_state) {
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DisallowEntryToOnMoreIOData();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The OS level audio APIs on Linux and Windows all have problems requesting
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // data on a fixed interval.  Sometimes they will issue calls back to back
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // which can cause glitching, so wait until the renderer is ready.
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  //
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // We also need to wait when diverting since the virtual stream will call this
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // multiple times without waiting.
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  //
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // NEVER wait on OSX unless a virtual stream is connected, otherwise we can
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // end up hanging the entire OS.
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See many bugs for context behind this decision: http://crbug.com/170498,
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // http://crbug.com/171651, http://crbug.com/174985, and more.
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) || defined(OS_LINUX)
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const bool kShouldBlock = true;
264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#else
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const bool kShouldBlock = diverting_to_stream_ != NULL;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const int frames = sync_reader_->Read(kShouldBlock, source, dest);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LE(0, frames);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_reader_->UpdatePendingBytes(
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  silence_detector_->Scan(dest, frames);
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AllowEntryToOnMoreIOData();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return frames;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::OnError(AudioOutputStream* stream) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle error on the audio controller thread.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &AudioOutputController::DoReportError, this));
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStopCloseAndClearStream() {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allow calling unconditionally and bail if we don't have a stream_ to close.
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stream_) {
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // De-register from state change callbacks if stream_ was created via
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // AudioManager.
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_ != diverting_to_stream_)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      audio_manager_->RemoveOutputDeviceChangeListener(this);
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StopStream();
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_->Close();
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_ == diverting_to_stream_)
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      diverting_to_stream_ = NULL;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_ = NULL;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = kEmpty;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::OnDeviceChange() {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(dalecurtis): Notify the renderer side that a device change has
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // occurred.  Currently querying the hardware information here will lead to
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // crashes on OSX.  See http://crbug.com/158170.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Recreate the stream (DoCreate() will first shut down an existing stream).
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Exit if we ran into an error.
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const State original_state = state_;
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoCreate(true);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_ || state_ == kError)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get us back to the original state or an equivalent state.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (original_state) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPlaying:
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoPlay();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCreated:
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPaused:
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // From the outside these two states are equivalent.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Invalid original state.";
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const AudioParameters& AudioOutputController::GetAudioParameters() {
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return params_;
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_loop_->PostTask(
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StopDiverting() {
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_loop_->PostTask(
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == kClosed)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!diverting_to_stream_);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  diverting_to_stream_ = to_stream;
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note: OnDeviceChange() will engage the "re-create" process, which will
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // detect and use the alternate AudioOutputStream rather than create a new one
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // via AudioManager.
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDeviceChange();
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStopDiverting() {
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == kClosed)
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note: OnDeviceChange() will cause the existing stream (the consumer of the
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // diverted audio data) to be closed, and diverting_to_stream_ will be set
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // back to NULL.
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDeviceChange();
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!diverting_to_stream_);
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::AllowEntryToOnMoreIOData() {
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AtomicRefCountInc(&num_allowed_io_);
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DisallowEntryToOnMoreIOData() {
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(is_zero);
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
387