Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / audio / audio_output_controller.cc
index 4f008c9..fb01254 100644 (file)
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/task_runner_util.h"
 #include "base/threading/platform_thread.h"
@@ -14,7 +13,6 @@
 #include "build/build_config.h"
 #include "media/base/scoped_histogram_timer.h"
 
-using base::Time;
 using base::TimeDelta;
 
 namespace media {
@@ -23,41 +21,30 @@ namespace media {
 // Time constant for AudioPowerMonitor.  See AudioPowerMonitor ctor comments for
 // semantics.  This value was arbitrarily chosen, but seems to work well.
 static const int kPowerMeasurementTimeConstantMillis = 10;
-
-// Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
-// power levels in the audio signal.
-static const int kPowerMeasurementsPerSecond = 4;
 #endif
 
-// Polling-related constants.
-const int AudioOutputController::kPollNumAttempts = 3;
-const int AudioOutputController::kPollPauseInMilliseconds = 3;
-
 AudioOutputController::AudioOutputController(
     AudioManager* audio_manager,
     EventHandler* handler,
     const AudioParameters& params,
     const std::string& output_device_id,
-    const std::string& input_device_id,
     SyncReader* sync_reader)
     : audio_manager_(audio_manager),
       params_(params),
       handler_(handler),
       output_device_id_(output_device_id),
-      input_device_id_(input_device_id),
       stream_(NULL),
       diverting_to_stream_(NULL),
       volume_(1.0),
       state_(kEmpty),
-      num_allowed_io_(0),
       sync_reader_(sync_reader),
-      message_loop_(audio_manager->GetMessageLoop()),
+      message_loop_(audio_manager->GetTaskRunner()),
 #if defined(AUDIO_POWER_MONITORING)
       power_monitor_(
           params.sample_rate(),
           TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
 #endif
-      number_polling_attempts_left_(0) {
+      on_more_io_data_called_(0) {
   DCHECK(audio_manager);
   DCHECK(handler_);
   DCHECK(sync_reader_);
@@ -74,7 +61,6 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create(
     EventHandler* event_handler,
     const AudioParameters& params,
     const std::string& output_device_id,
-    const std::string& input_device_id,
     SyncReader* sync_reader) {
   DCHECK(audio_manager);
   DCHECK(sync_reader);
@@ -83,8 +69,7 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create(
     return NULL;
 
   scoped_refptr<AudioOutputController> controller(new AudioOutputController(
-      audio_manager, event_handler, params, output_device_id, input_device_id,
-      sync_reader));
+      audio_manager, event_handler, params, output_device_id, sync_reader));
   controller->message_loop_->PostTask(FROM_HERE, base::Bind(
       &AudioOutputController::DoCreate, controller, false));
   return controller;
@@ -132,6 +117,7 @@ void AudioOutputController::SwitchOutputDevice(
 void AudioOutputController::DoCreate(bool is_for_device_change) {
   DCHECK(message_loop_->BelongsToCurrentThread());
   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
+  TRACE_EVENT0("audio", "AudioOutputController::DoCreate");
 
   // Close() can be called before DoCreate() is executed.
   if (state_ == kClosed)
@@ -142,8 +128,7 @@ void AudioOutputController::DoCreate(bool is_for_device_change) {
 
   stream_ = diverting_to_stream_ ?
       diverting_to_stream_ :
-      audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
-                                                 input_device_id_);
+      audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_);
   if (!stream_) {
     state_ = kError;
     handler_->OnError();
@@ -176,6 +161,7 @@ void AudioOutputController::DoCreate(bool is_for_device_change) {
 void AudioOutputController::DoPlay() {
   DCHECK(message_loop_->BelongsToCurrentThread());
   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
+  TRACE_EVENT0("audio", "AudioOutputController::DoPlay");
 
   // We can start from created or paused state.
   if (state_ != kCreated && state_ != kPaused)
@@ -186,44 +172,38 @@ void AudioOutputController::DoPlay() {
 
   state_ = kPlaying;
 
-#if defined(AUDIO_POWER_MONITORING)
-  power_monitor_.Reset();
-  power_poll_callback_.Reset(
-      base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
-                 this));
-  // Run the callback to send an initial notification that we're starting in
-  // silence, and to schedule periodic callbacks.
-  power_poll_callback_.callback().Run();
-#endif
-
-  // We start the AudioOutputStream lazily.
-  AllowEntryToOnMoreIOData();
   stream_->Start(this);
 
-  handler_->OnPlaying();
-}
+  // For UMA tracking purposes, start the wedge detection timer.  This allows us
+  // to record statistics about the number of wedged playbacks in the field.
+  //
+  // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
+  // the timeout expires.  Care must be taken to ensure the wedge check delay is
+  // large enough that the value isn't queried while OnMoreDataIO() is setting
+  // it.
+  //
+  // Timer self-manages its lifetime and WedgeCheck() will only record the UMA
+  // statistic if state is still kPlaying.  Additional Start() calls will
+  // invalidate the previous timer.
+  wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>());
+  wedge_timer_->Start(
+      FROM_HERE, TimeDelta::FromSeconds(5), this,
+      &AudioOutputController::WedgeCheck);
 
-#if defined(AUDIO_POWER_MONITORING)
-void AudioOutputController::ReportPowerMeasurementPeriodically() {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  const std::pair<float, bool>& reading =
-      power_monitor_.ReadCurrentPowerAndClip();
-  handler_->OnPowerMeasured(reading.first, reading.second);
-  message_loop_->PostDelayedTask(
-      FROM_HERE, power_poll_callback_.callback(),
-      TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond);
+  handler_->OnPlaying();
 }
-#endif
 
 void AudioOutputController::StopStream() {
   DCHECK(message_loop_->BelongsToCurrentThread());
 
   if (state_ == kPlaying) {
+    wedge_timer_.reset();
     stream_->Stop();
-    DisallowEntryToOnMoreIOData();
 
 #if defined(AUDIO_POWER_MONITORING)
-    power_poll_callback_.Cancel();
+    // A stopped stream is silent, and power_montior_.Scan() is no longer being
+    // called; so we must reset the power monitor.
+    power_monitor_.Reset();
 #endif
 
     state_ = kPaused;
@@ -233,6 +213,7 @@ void AudioOutputController::StopStream() {
 void AudioOutputController::DoPause() {
   DCHECK(message_loop_->BelongsToCurrentThread());
   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
+  TRACE_EVENT0("audio", "AudioOutputController::DoPause");
 
   StopStream();
 
@@ -242,12 +223,7 @@ void AudioOutputController::DoPause() {
   // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
   // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
   // a better way to know when it should exit PPB_Audio_Shared::Run().
-  sync_reader_->UpdatePendingBytes(-1);
-
-#if defined(AUDIO_POWER_MONITORING)
-  // Paused means silence follows.
-  handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
-#endif
+  sync_reader_->UpdatePendingBytes(kuint32max);
 
   handler_->OnPaused();
 }
@@ -255,6 +231,7 @@ void AudioOutputController::DoPause() {
 void AudioOutputController::DoClose() {
   DCHECK(message_loop_->BelongsToCurrentThread());
   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
+  TRACE_EVENT0("audio", "AudioOutputController::DoClose");
 
   if (state_ != kClosed) {
     DoStopCloseAndClearStream();
@@ -293,6 +270,9 @@ void AudioOutputController::DoSwitchOutputDevice(
   if (state_ == kClosed)
     return;
 
+  if (output_device_id == output_device_id_)
+    return;
+
   output_device_id_ = output_device_id;
 
   // If output is currently diverted, we must not call OnDeviceChange
@@ -311,16 +291,16 @@ void AudioOutputController::DoReportError() {
 
 int AudioOutputController::OnMoreData(AudioBus* dest,
                                       AudioBuffersState buffers_state) {
-  return OnMoreIOData(NULL, dest, buffers_state);
-}
+  TRACE_EVENT0("audio", "AudioOutputController::OnMoreData");
 
-int AudioOutputController::OnMoreIOData(AudioBus* source,
-                                        AudioBus* dest,
-                                        AudioBuffersState buffers_state) {
-  DisallowEntryToOnMoreIOData();
-  TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
+  // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
+  // may have already fired if OnMoreIOData() took an abnormal amount of time).
+  // Since this thread is the only writer of |on_more_io_data_called_| once the
+  // thread starts, its safe to compare and then increment.
+  if (base::AtomicRefCountIsZero(&on_more_io_data_called_))
+    base::AtomicRefCountInc(&on_more_io_data_called_);
 
-  sync_reader_->Read(source, dest);
+  sync_reader_->Read(dest);
 
   const int frames = dest->frames();
   sync_reader_->UpdatePendingBytes(
@@ -330,7 +310,6 @@ int AudioOutputController::OnMoreIOData(AudioBus* source,
   power_monitor_.Scan(*dest, frames);
 #endif
 
-  AllowEntryToOnMoreIOData();
   return frames;
 }
 
@@ -363,6 +342,7 @@ void AudioOutputController::DoStopCloseAndClearStream() {
 void AudioOutputController::OnDeviceChange() {
   DCHECK(message_loop_->BelongsToCurrentThread());
   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
+  TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange");
 
   // TODO(dalecurtis): Notify the renderer side that a device change has
   // occurred.  Currently querying the hardware information here will lead to
@@ -431,14 +411,23 @@ void AudioOutputController::DoStopDiverting() {
   DCHECK(!diverting_to_stream_);
 }
 
-void AudioOutputController::AllowEntryToOnMoreIOData() {
-  DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
-  base::AtomicRefCountInc(&num_allowed_io_);
+std::pair<float, bool> AudioOutputController::ReadCurrentPowerAndClip() {
+#if defined(AUDIO_POWER_MONITORING)
+  return power_monitor_.ReadCurrentPowerAndClip();
+#else
+  NOTREACHED();
+  return std::make_pair(AudioPowerMonitor::zero_power(), false);
+#endif
 }
 
-void AudioOutputController::DisallowEntryToOnMoreIOData() {
-  const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
-  DCHECK(is_zero);
+void AudioOutputController::WedgeCheck() {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
+  // If we should be playing and we haven't, that's a wedge.
+  if (state_ == kPlaying) {
+    UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess",
+                          base::AtomicRefCountIsOne(&on_more_io_data_called_));
+  }
 }
 
 }  // namespace media