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"
9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
10a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/metrics/histogram.h"
111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/task_runner_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "build/build_config.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "media/base/scoped_histogram_timer.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(AUDIO_POWER_MONITORING)
23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Time constant for AudioPowerMonitor.  See AudioPowerMonitor ctor comments for
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// semantics.  This value was arbitrarily chosen, but seems to work well.
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic const int kPowerMeasurementTimeConstantMillis = 10;
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// power levels in the audio signal.
2968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static const int kPowerMeasurementsPerSecond = 4;
3068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Polling-related constants.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int AudioOutputController::kPollNumAttempts = 3;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int AudioOutputController::kPollPauseInMilliseconds = 3;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)AudioOutputController::AudioOutputController(
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AudioManager* audio_manager,
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EventHandler* handler,
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const AudioParameters& params,
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& output_device_id,
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& input_device_id,
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    SyncReader* sync_reader)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : audio_manager_(audio_manager),
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params_(params),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handler_(handler),
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      output_device_id_(output_device_id),
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()),
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(AUDIO_POWER_MONITORING)
56c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      power_monitor_(
57c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch          params.sample_rate(),
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      on_more_io_data_called_(0) {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(audio_manager);
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(handler_);
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(sync_reader_);
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(message_loop_.get());
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputController::~AudioOutputController() {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(kClosed, state_);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<AudioOutputController> AudioOutputController::Create(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AudioManager* audio_manager,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EventHandler* event_handler,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioParameters& params,
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& output_device_id,
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& input_device_id,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncReader* sync_reader) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_manager);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_reader);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!params.IsValid() || !audio_manager)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<AudioOutputController> controller(new AudioOutputController(
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      audio_manager, event_handler, params, output_device_id, input_device_id,
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      sync_reader));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  controller->message_loop_->PostTask(FROM_HERE, base::Bind(
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &AudioOutputController::DoCreate, controller, false));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return controller;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Play() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoPlay, this));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Pause() {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoPause, this));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Close(const base::Closure& closed_task) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!closed_task.is_null());
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTaskAndReply(FROM_HERE, base::Bind(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoClose, this), closed_task);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::SetVolume(double volume) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoSetVolume, this, volume));
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AudioOutputController::GetOutputDeviceId(
1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::Callback<void(const std::string&)> callback) const {
1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      message_loop_.get(),
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(&AudioOutputController::DoGetOutputDeviceId, this),
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      callback);
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AudioOutputController::SwitchOutputDevice(
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& output_device_id, const base::Closure& callback) {
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  message_loop_->PostTaskAndReply(
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(&AudioOutputController::DoSwitchOutputDevice, this,
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                 output_device_id),
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      callback);
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoCreate(bool is_for_device_change) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoCreate");
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close() can be called before DoCreate() is executed.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == kClosed)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoStopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(kEmpty, state_);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  stream_ = diverting_to_stream_ ?
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      diverting_to_stream_ :
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                                 input_device_id_);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kError;
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_->Open()) {
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoStopCloseAndClearStream();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kError;
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Everything started okay, so re-register for state change callbacks if
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // stream_ was created via AudioManager.
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (stream_ != diverting_to_stream_)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    audio_manager_->AddOutputDeviceChangeListener(this);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We have successfully opened the stream. Set the initial volume.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_->SetVolume(volume_);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally set the state to kCreated.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = kCreated;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And then report we have been created if we haven't done so already.
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_for_device_change)
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnCreated();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoPlay() {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoPlay");
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can start from created or paused state.
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ != kCreated && state_ != kPaused)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ask for first packet.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_reader_->UpdatePendingBytes(0);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = kPlaying;
190ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
19168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(AUDIO_POWER_MONITORING)
192c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  power_monitor_.Reset();
193c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  power_poll_callback_.Reset(
194c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
195c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                 this));
196c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Run the callback to send an initial notification that we're starting in
197c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // silence, and to schedule periodic callbacks.
198c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  power_poll_callback_.callback().Run();
19968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  on_more_io_data_called_ = 0;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AllowEntryToOnMoreIOData();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_->Start(this);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // For UMA tracking purposes, start the wedge detection timer.  This allows us
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // to record statistics about the number of wedged playbacks in the field.
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  //
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // the timeout expires.  Care must be taken to ensure the wedge check delay is
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // large enough that the value isn't queried while OnMoreDataIO() is setting
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // it.
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  //
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Timer self-manages its lifetime and WedgeCheck() will only record the UMA
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // statistic if state is still kPlaying.  Additional Start() calls will
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // invalidate the previous timer.
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>());
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  wedge_timer_->Start(
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE, TimeDelta::FromSeconds(5), this,
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      &AudioOutputController::WedgeCheck);
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handler_->OnPlaying();
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(AUDIO_POWER_MONITORING)
225c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid AudioOutputController::ReportPowerMeasurementPeriodically() {
226c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  DCHECK(message_loop_->BelongsToCurrentThread());
227c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  const std::pair<float, bool>& reading =
228c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      power_monitor_.ReadCurrentPowerAndClip();
229c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  handler_->OnPowerMeasured(reading.first, reading.second);
230c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  message_loop_->PostDelayedTask(
231c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      FROM_HERE, power_poll_callback_.callback(),
232c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond);
233c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
23468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
235c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StopStream() {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == kPlaying) {
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    wedge_timer_.reset();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_->Stop();
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DisallowEntryToOnMoreIOData();
243ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
24468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(AUDIO_POWER_MONITORING)
245c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    power_poll_callback_.Cancel();
24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
247ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_ = kPaused;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoPause() {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoPause");
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StopStream();
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ != kPaused)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // a better way to know when it should exit PPB_Audio_Shared::Run().
2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sync_reader_->UpdatePendingBytes(-1);
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(AUDIO_POWER_MONITORING)
268ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Paused means silence follows.
269ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
27068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
271ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handler_->OnPaused();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoClose() {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoClose");
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != kClosed) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoStopCloseAndClearStream();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_reader_->Close();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kClosed;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoSetVolume(double volume) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Saves the volume to a member first. We may not be able to set the volume
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // right away but when the stream is created we'll set the volume.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  volume_ = volume;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCreated:
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPlaying:
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPaused:
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_->SetVolume(volume_);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)std::string AudioOutputController::DoGetOutputDeviceId() const {
3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return output_device_id_;
3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AudioOutputController::DoSwitchOutputDevice(
3111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& output_device_id) {
3121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (state_ == kClosed)
3151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
3161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (output_device_id == output_device_id_)
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  output_device_id_ = output_device_id;
3211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // If output is currently diverted, we must not call OnDeviceChange
3231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // since it would break the diverted setup. Once diversion is
3241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // finished using StopDiverting() the output will switch to the new
3251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // device ID.
3261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (stream_ != diverting_to_stream_)
3271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    OnDeviceChange();
3281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoReportError() {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != kClosed)
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AudioOutputController::OnMoreData(AudioBus* dest,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      AudioBuffersState buffers_state) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OnMoreIOData(NULL, dest, buffers_state);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AudioOutputController::OnMoreIOData(AudioBus* source,
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        AudioBus* dest,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        AudioBuffersState buffers_state) {
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DisallowEntryToOnMoreIOData();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // may have already fired if OnMoreIOData() took an abnormal amount of time).
349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Since this thread is the only writer of |on_more_io_data_called_| once the
350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // thread starts, its safe to compare and then increment.
351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (base::AtomicRefCountIsZero(&on_more_io_data_called_))
352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::AtomicRefCountInc(&on_more_io_data_called_);
353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sync_reader_->Read(source, dest);
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const int frames = dest->frames();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_reader_->UpdatePendingBytes(
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
36068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(AUDIO_POWER_MONITORING)
361c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  power_monitor_.Scan(*dest, frames);
36268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AllowEntryToOnMoreIOData();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return frames;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::OnError(AudioOutputStream* stream) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle error on the audio controller thread.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &AudioOutputController::DoReportError, this));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStopCloseAndClearStream() {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allow calling unconditionally and bail if we don't have a stream_ to close.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stream_) {
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // De-register from state change callbacks if stream_ was created via
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // AudioManager.
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_ != diverting_to_stream_)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      audio_manager_->RemoveOutputDeviceChangeListener(this);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StopStream();
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_->Close();
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_ == diverting_to_stream_)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      diverting_to_stream_ = NULL;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_ = NULL;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = kEmpty;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::OnDeviceChange() {
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange");
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(dalecurtis): Notify the renderer side that a device change has
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // occurred.  Currently querying the hardware information here will lead to
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // crashes on OSX.  See http://crbug.com/158170.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Recreate the stream (DoCreate() will first shut down an existing stream).
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Exit if we ran into an error.
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const State original_state = state_;
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoCreate(true);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_ || state_ == kError)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get us back to the original state or an equivalent state.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (original_state) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPlaying:
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoPlay();
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCreated:
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPaused:
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // From the outside these two states are equivalent.
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Invalid original state.";
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const AudioParameters& AudioOutputController::GetAudioParameters() {
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return params_;
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_loop_->PostTask(
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StopDiverting() {
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_loop_->PostTask(
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == kClosed)
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!diverting_to_stream_);
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  diverting_to_stream_ = to_stream;
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note: OnDeviceChange() will engage the "re-create" process, which will
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // detect and use the alternate AudioOutputStream rather than create a new one
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // via AudioManager.
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDeviceChange();
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStopDiverting() {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == kClosed)
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note: OnDeviceChange() will cause the existing stream (the consumer of the
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // diverted audio data) to be closed, and diverting_to_stream_ will be set
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // back to NULL.
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDeviceChange();
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!diverting_to_stream_);
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::AllowEntryToOnMoreIOData() {
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AtomicRefCountInc(&num_allowed_io_);
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DisallowEntryToOnMoreIOData() {
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(is_zero);
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioOutputController::WedgeCheck() {
477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If we should be playing and we haven't, that's a wedge.
480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (state_ == kPlaying) {
481a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const bool playback_success =
482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        base::AtomicRefCountIsOne(&on_more_io_data_called_);
483a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN(
485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success);
486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Let the AudioManager try and fix it.
488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!playback_success)
489a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      audio_manager_->FixWedgedAudio();
490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
494