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"
9a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/metrics/histogram.h"
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/task_runner_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "build/build_config.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "media/base/scoped_histogram_timer.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)AudioOutputController::AudioOutputController(
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AudioManager* audio_manager,
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EventHandler* handler,
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const AudioParameters& params,
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& output_device_id,
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    SyncReader* sync_reader)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : audio_manager_(audio_manager),
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params_(params),
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handler_(handler),
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      output_device_id_(output_device_id),
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_(NULL),
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      diverting_to_stream_(NULL),
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      volume_(1.0),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(kEmpty),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_reader_(sync_reader),
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_loop_(audio_manager->GetTaskRunner()),
36c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      power_monitor_(
37c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch          params.sample_rate(),
3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      on_more_io_data_called_(0) {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(audio_manager);
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(handler_);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(sync_reader_);
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(message_loop_.get());
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputController::~AudioOutputController() {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(kClosed, state_);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<AudioOutputController> AudioOutputController::Create(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AudioManager* audio_manager,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EventHandler* event_handler,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioParameters& params,
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::string& output_device_id,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncReader* sync_reader) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_manager);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_reader);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!params.IsValid() || !audio_manager)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<AudioOutputController> controller(new AudioOutputController(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      audio_manager, event_handler, params, output_device_id, sync_reader));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  controller->message_loop_->PostTask(FROM_HERE, base::Bind(
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &AudioOutputController::DoCreate, controller, false));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return controller;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Play() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoPlay, this));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Pause() {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoPause, this));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::Close(const base::Closure& closed_task) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!closed_task.is_null());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTaskAndReply(FROM_HERE, base::Bind(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoClose, this), closed_task);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::SetVolume(double volume) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioOutputController::DoSetVolume, this, volume));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AudioOutputController::GetOutputDeviceId(
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::Callback<void(const std::string&)> callback) const {
931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      message_loop_.get(),
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(&AudioOutputController::DoGetOutputDeviceId, this),
971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      callback);
981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AudioOutputController::SwitchOutputDevice(
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& output_device_id, const base::Closure& callback) {
1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  message_loop_->PostTaskAndReply(
1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(&AudioOutputController::DoSwitchOutputDevice, this,
1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                 output_device_id),
1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      callback);
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoCreate(bool is_for_device_change) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoCreate");
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close() can be called before DoCreate() is executed.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == kClosed)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoStopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(kEmpty, state_);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  stream_ = diverting_to_stream_ ?
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      diverting_to_stream_ :
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kError;
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_->Open()) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoStopCloseAndClearStream();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kError;
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Everything started okay, so re-register for state change callbacks if
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // stream_ was created via AudioManager.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (stream_ != diverting_to_stream_)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    audio_manager_->AddOutputDeviceChangeListener(this);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We have successfully opened the stream. Set the initial volume.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_->SetVolume(volume_);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally set the state to kCreated.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = kCreated;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And then report we have been created if we haven't done so already.
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_for_device_change)
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnCreated();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoPlay() {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoPlay");
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can start from created or paused state.
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ != kCreated && state_ != kPaused)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ask for first packet.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_reader_->UpdatePendingBytes(0);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = kPlaying;
166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stream_->Start(this);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // For UMA tracking purposes, start the wedge detection timer.  This allows us
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // to record statistics about the number of wedged playbacks in the field.
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  //
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // the timeout expires.  Care must be taken to ensure the wedge check delay is
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // large enough that the value isn't queried while OnMoreDataIO() is setting
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // it.
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  //
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Timer self-manages its lifetime and WedgeCheck() will only record the UMA
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // statistic if state is still kPlaying.  Additional Start() calls will
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // invalidate the previous timer.
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>());
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  wedge_timer_->Start(
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE, TimeDelta::FromSeconds(5), this,
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      &AudioOutputController::WedgeCheck);
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handler_->OnPlaying();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StopStream() {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == kPlaying) {
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    wedge_timer_.reset();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_->Stop();
194ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // A stopped stream is silent, and power_montior_.Scan() is no longer being
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // called; so we must reset the power monitor.
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    power_monitor_.Reset();
198ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    state_ = kPaused;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoPause() {
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoPause");
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StopStream();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ != kPaused)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // a better way to know when it should exit PPB_Audio_Shared::Run().
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sync_reader_->UpdatePendingBytes(kuint32max);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handler_->OnPaused();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoClose() {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::DoClose");
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != kClosed) {
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DoStopCloseAndClearStream();
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_reader_->Close();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = kClosed;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::DoSetVolume(double volume) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Saves the volume to a member first. We may not be able to set the volume
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // right away but when the stream is created we'll set the volume.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  volume_ = volume;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCreated:
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPlaying:
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPaused:
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_->SetVolume(volume_);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)std::string AudioOutputController::DoGetOutputDeviceId() const {
2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return output_device_id_;
2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AudioOutputController::DoSwitchOutputDevice(
2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& output_device_id) {
2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (state_ == kClosed)
2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (output_device_id == output_device_id_)
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  output_device_id_ = output_device_id;
2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // If output is currently diverted, we must not call OnDeviceChange
2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // since it would break the diverted setup. Once diversion is
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // finished using StopDiverting() the output will switch to the new
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // device ID.
2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (stream_ != diverting_to_stream_)
2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    OnDeviceChange();
2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoReportError() {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != kClosed)
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    handler_->OnError();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AudioOutputController::OnMoreData(AudioBus* dest,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      AudioBuffersState buffers_state) {
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::OnMoreData");
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // may have already fired if OnMoreIOData() took an abnormal amount of time).
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Since this thread is the only writer of |on_more_io_data_called_| once the
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // thread starts, its safe to compare and then increment.
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (base::AtomicRefCountIsZero(&on_more_io_data_called_))
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::AtomicRefCountInc(&on_more_io_data_called_);
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  sync_reader_->Read(dest);
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const int frames = dest->frames();
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_reader_->UpdatePendingBytes(
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (will_monitor_audio_levels())
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    power_monitor_.Scan(*dest, frames);
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return frames;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::OnError(AudioOutputStream* stream) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle error on the audio controller thread.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_->PostTask(FROM_HERE, base::Bind(
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &AudioOutputController::DoReportError, this));
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStopCloseAndClearStream() {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allow calling unconditionally and bail if we don't have a stream_ to close.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stream_) {
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // De-register from state change callbacks if stream_ was created via
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // AudioManager.
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_ != diverting_to_stream_)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      audio_manager_->RemoveOutputDeviceChangeListener(this);
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StopStream();
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_->Close();
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (stream_ == diverting_to_stream_)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      diverting_to_stream_ = NULL;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stream_ = NULL;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  state_ = kEmpty;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioOutputController::OnDeviceChange() {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange");
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(dalecurtis): Notify the renderer side that a device change has
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // occurred.  Currently querying the hardware information here will lead to
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // crashes on OSX.  See http://crbug.com/158170.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Recreate the stream (DoCreate() will first shut down an existing stream).
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Exit if we ran into an error.
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const State original_state = state_;
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoCreate(true);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream_ || state_ == kError)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get us back to the original state or an equivalent state.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (original_state) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPlaying:
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoPlay();
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCreated:
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPaused:
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // From the outside these two states are equivalent.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Invalid original state.";
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const AudioParameters& AudioOutputController::GetAudioParameters() {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return params_;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_loop_->PostTask(
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::StopDiverting() {
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_loop_->PostTask(
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == kClosed)
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!diverting_to_stream_);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  diverting_to_stream_ = to_stream;
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note: OnDeviceChange() will engage the "re-create" process, which will
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // detect and use the alternate AudioOutputStream rather than create a new one
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // via AudioManager.
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDeviceChange();
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioOutputController::DoStopDiverting() {
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (state_ == kClosed)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note: OnDeviceChange() will cause the existing stream (the consumer of the
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // diverted audio data) to be closed, and diverting_to_stream_ will be set
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // back to NULL.
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnDeviceChange();
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!diverting_to_stream_);
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::pair<float, bool> AudioOutputController::ReadCurrentPowerAndClip() {
4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(will_monitor_audio_levels());
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return power_monitor_.ReadCurrentPowerAndClip();
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioOutputController::WedgeCheck() {
409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If we should be playing and we haven't, that's a wedge.
412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (state_ == kPlaying) {
413a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess",
414a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                          base::AtomicRefCountIsOne(&on_more_io_data_called_));
415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
419