Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / media / audio / audio_output_controller.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/audio/audio_output_controller.h"
6
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9 #include "base/metrics/histogram.h"
10 #include "base/task_runner_util.h"
11 #include "base/threading/platform_thread.h"
12 #include "base/time/time.h"
13 #include "build/build_config.h"
14 #include "media/base/scoped_histogram_timer.h"
15
16 using base::TimeDelta;
17
18 namespace media {
19
20 #if defined(AUDIO_POWER_MONITORING)
21 // Time constant for AudioPowerMonitor.  See AudioPowerMonitor ctor comments for
22 // semantics.  This value was arbitrarily chosen, but seems to work well.
23 static const int kPowerMeasurementTimeConstantMillis = 10;
24
25 // Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
26 // power levels in the audio signal.
27 static const int kPowerMeasurementsPerSecond = 4;
28 #endif
29
30 // Polling-related constants.
31 const int AudioOutputController::kPollNumAttempts = 3;
32 const int AudioOutputController::kPollPauseInMilliseconds = 3;
33
34 AudioOutputController::AudioOutputController(
35     AudioManager* audio_manager,
36     EventHandler* handler,
37     const AudioParameters& params,
38     const std::string& output_device_id,
39     const std::string& input_device_id,
40     SyncReader* sync_reader)
41     : audio_manager_(audio_manager),
42       params_(params),
43       handler_(handler),
44       output_device_id_(output_device_id),
45       input_device_id_(input_device_id),
46       stream_(NULL),
47       diverting_to_stream_(NULL),
48       volume_(1.0),
49       state_(kEmpty),
50       num_allowed_io_(0),
51       sync_reader_(sync_reader),
52       message_loop_(audio_manager->GetTaskRunner()),
53 #if defined(AUDIO_POWER_MONITORING)
54       power_monitor_(
55           params.sample_rate(),
56           TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
57 #endif
58       on_more_io_data_called_(0) {
59   DCHECK(audio_manager);
60   DCHECK(handler_);
61   DCHECK(sync_reader_);
62   DCHECK(message_loop_.get());
63 }
64
65 AudioOutputController::~AudioOutputController() {
66   DCHECK_EQ(kClosed, state_);
67 }
68
69 // static
70 scoped_refptr<AudioOutputController> AudioOutputController::Create(
71     AudioManager* audio_manager,
72     EventHandler* event_handler,
73     const AudioParameters& params,
74     const std::string& output_device_id,
75     const std::string& input_device_id,
76     SyncReader* sync_reader) {
77   DCHECK(audio_manager);
78   DCHECK(sync_reader);
79
80   if (!params.IsValid() || !audio_manager)
81     return NULL;
82
83   scoped_refptr<AudioOutputController> controller(new AudioOutputController(
84       audio_manager, event_handler, params, output_device_id, input_device_id,
85       sync_reader));
86   controller->message_loop_->PostTask(FROM_HERE, base::Bind(
87       &AudioOutputController::DoCreate, controller, false));
88   return controller;
89 }
90
91 void AudioOutputController::Play() {
92   message_loop_->PostTask(FROM_HERE, base::Bind(
93       &AudioOutputController::DoPlay, this));
94 }
95
96 void AudioOutputController::Pause() {
97   message_loop_->PostTask(FROM_HERE, base::Bind(
98       &AudioOutputController::DoPause, this));
99 }
100
101 void AudioOutputController::Close(const base::Closure& closed_task) {
102   DCHECK(!closed_task.is_null());
103   message_loop_->PostTaskAndReply(FROM_HERE, base::Bind(
104       &AudioOutputController::DoClose, this), closed_task);
105 }
106
107 void AudioOutputController::SetVolume(double volume) {
108   message_loop_->PostTask(FROM_HERE, base::Bind(
109       &AudioOutputController::DoSetVolume, this, volume));
110 }
111
112 void AudioOutputController::GetOutputDeviceId(
113     base::Callback<void(const std::string&)> callback) const {
114   base::PostTaskAndReplyWithResult(
115       message_loop_.get(),
116       FROM_HERE,
117       base::Bind(&AudioOutputController::DoGetOutputDeviceId, this),
118       callback);
119 }
120
121 void AudioOutputController::SwitchOutputDevice(
122     const std::string& output_device_id, const base::Closure& callback) {
123   message_loop_->PostTaskAndReply(
124       FROM_HERE,
125       base::Bind(&AudioOutputController::DoSwitchOutputDevice, this,
126                  output_device_id),
127       callback);
128 }
129
130 void AudioOutputController::DoCreate(bool is_for_device_change) {
131   DCHECK(message_loop_->BelongsToCurrentThread());
132   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CreateTime");
133   TRACE_EVENT0("audio", "AudioOutputController::DoCreate");
134
135   // Close() can be called before DoCreate() is executed.
136   if (state_ == kClosed)
137     return;
138
139   DoStopCloseAndClearStream();  // Calls RemoveOutputDeviceChangeListener().
140   DCHECK_EQ(kEmpty, state_);
141
142   stream_ = diverting_to_stream_ ?
143       diverting_to_stream_ :
144       audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
145                                                  input_device_id_);
146   if (!stream_) {
147     state_ = kError;
148     handler_->OnError();
149     return;
150   }
151
152   if (!stream_->Open()) {
153     DoStopCloseAndClearStream();
154     state_ = kError;
155     handler_->OnError();
156     return;
157   }
158
159   // Everything started okay, so re-register for state change callbacks if
160   // stream_ was created via AudioManager.
161   if (stream_ != diverting_to_stream_)
162     audio_manager_->AddOutputDeviceChangeListener(this);
163
164   // We have successfully opened the stream. Set the initial volume.
165   stream_->SetVolume(volume_);
166
167   // Finally set the state to kCreated.
168   state_ = kCreated;
169
170   // And then report we have been created if we haven't done so already.
171   if (!is_for_device_change)
172     handler_->OnCreated();
173 }
174
175 void AudioOutputController::DoPlay() {
176   DCHECK(message_loop_->BelongsToCurrentThread());
177   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
178   TRACE_EVENT0("audio", "AudioOutputController::DoPlay");
179
180   // We can start from created or paused state.
181   if (state_ != kCreated && state_ != kPaused)
182     return;
183
184   // Ask for first packet.
185   sync_reader_->UpdatePendingBytes(0);
186
187   state_ = kPlaying;
188
189 #if defined(AUDIO_POWER_MONITORING)
190   power_monitor_.Reset();
191   power_poll_callback_.Reset(
192       base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
193                  this));
194   // Run the callback to send an initial notification that we're starting in
195   // silence, and to schedule periodic callbacks.
196   power_poll_callback_.callback().Run();
197 #endif
198
199   on_more_io_data_called_ = 0;
200   AllowEntryToOnMoreIOData();
201   stream_->Start(this);
202
203   // For UMA tracking purposes, start the wedge detection timer.  This allows us
204   // to record statistics about the number of wedged playbacks in the field.
205   //
206   // WedgeCheck() will look to see if |on_more_io_data_called_| is true after
207   // the timeout expires.  Care must be taken to ensure the wedge check delay is
208   // large enough that the value isn't queried while OnMoreDataIO() is setting
209   // it.
210   //
211   // Timer self-manages its lifetime and WedgeCheck() will only record the UMA
212   // statistic if state is still kPlaying.  Additional Start() calls will
213   // invalidate the previous timer.
214   wedge_timer_.reset(new base::OneShotTimer<AudioOutputController>());
215   wedge_timer_->Start(
216       FROM_HERE, TimeDelta::FromSeconds(5), this,
217       &AudioOutputController::WedgeCheck);
218
219   handler_->OnPlaying();
220 }
221
222 #if defined(AUDIO_POWER_MONITORING)
223 void AudioOutputController::ReportPowerMeasurementPeriodically() {
224   DCHECK(message_loop_->BelongsToCurrentThread());
225   const std::pair<float, bool>& reading =
226       power_monitor_.ReadCurrentPowerAndClip();
227   handler_->OnPowerMeasured(reading.first, reading.second);
228   message_loop_->PostDelayedTask(
229       FROM_HERE, power_poll_callback_.callback(),
230       TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond);
231 }
232 #endif
233
234 void AudioOutputController::StopStream() {
235   DCHECK(message_loop_->BelongsToCurrentThread());
236
237   if (state_ == kPlaying) {
238     wedge_timer_.reset();
239     stream_->Stop();
240     DisallowEntryToOnMoreIOData();
241
242 #if defined(AUDIO_POWER_MONITORING)
243     power_poll_callback_.Cancel();
244 #endif
245
246     state_ = kPaused;
247   }
248 }
249
250 void AudioOutputController::DoPause() {
251   DCHECK(message_loop_->BelongsToCurrentThread());
252   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime");
253   TRACE_EVENT0("audio", "AudioOutputController::DoPause");
254
255   StopStream();
256
257   if (state_ != kPaused)
258     return;
259
260   // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
261   // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
262   // a better way to know when it should exit PPB_Audio_Shared::Run().
263   sync_reader_->UpdatePendingBytes(-1);
264
265 #if defined(AUDIO_POWER_MONITORING)
266   // Paused means silence follows.
267   handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
268 #endif
269
270   handler_->OnPaused();
271 }
272
273 void AudioOutputController::DoClose() {
274   DCHECK(message_loop_->BelongsToCurrentThread());
275   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime");
276   TRACE_EVENT0("audio", "AudioOutputController::DoClose");
277
278   if (state_ != kClosed) {
279     DoStopCloseAndClearStream();
280     sync_reader_->Close();
281     state_ = kClosed;
282   }
283 }
284
285 void AudioOutputController::DoSetVolume(double volume) {
286   DCHECK(message_loop_->BelongsToCurrentThread());
287
288   // Saves the volume to a member first. We may not be able to set the volume
289   // right away but when the stream is created we'll set the volume.
290   volume_ = volume;
291
292   switch (state_) {
293     case kCreated:
294     case kPlaying:
295     case kPaused:
296       stream_->SetVolume(volume_);
297       break;
298     default:
299       return;
300   }
301 }
302
303 std::string AudioOutputController::DoGetOutputDeviceId() const {
304   DCHECK(message_loop_->BelongsToCurrentThread());
305   return output_device_id_;
306 }
307
308 void AudioOutputController::DoSwitchOutputDevice(
309     const std::string& output_device_id) {
310   DCHECK(message_loop_->BelongsToCurrentThread());
311
312   if (state_ == kClosed)
313     return;
314
315   if (output_device_id == output_device_id_)
316     return;
317
318   output_device_id_ = output_device_id;
319
320   // If output is currently diverted, we must not call OnDeviceChange
321   // since it would break the diverted setup. Once diversion is
322   // finished using StopDiverting() the output will switch to the new
323   // device ID.
324   if (stream_ != diverting_to_stream_)
325     OnDeviceChange();
326 }
327
328 void AudioOutputController::DoReportError() {
329   DCHECK(message_loop_->BelongsToCurrentThread());
330   if (state_ != kClosed)
331     handler_->OnError();
332 }
333
334 int AudioOutputController::OnMoreData(AudioBus* dest,
335                                       AudioBuffersState buffers_state) {
336   return OnMoreIOData(NULL, dest, buffers_state);
337 }
338
339 int AudioOutputController::OnMoreIOData(AudioBus* source,
340                                         AudioBus* dest,
341                                         AudioBuffersState buffers_state) {
342   DisallowEntryToOnMoreIOData();
343   TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
344
345   // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
346   // may have already fired if OnMoreIOData() took an abnormal amount of time).
347   // Since this thread is the only writer of |on_more_io_data_called_| once the
348   // thread starts, its safe to compare and then increment.
349   if (base::AtomicRefCountIsZero(&on_more_io_data_called_))
350     base::AtomicRefCountInc(&on_more_io_data_called_);
351
352   sync_reader_->Read(source, dest);
353
354   const int frames = dest->frames();
355   sync_reader_->UpdatePendingBytes(
356       buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
357
358 #if defined(AUDIO_POWER_MONITORING)
359   power_monitor_.Scan(*dest, frames);
360 #endif
361
362   AllowEntryToOnMoreIOData();
363   return frames;
364 }
365
366 void AudioOutputController::OnError(AudioOutputStream* stream) {
367   // Handle error on the audio controller thread.
368   message_loop_->PostTask(FROM_HERE, base::Bind(
369       &AudioOutputController::DoReportError, this));
370 }
371
372 void AudioOutputController::DoStopCloseAndClearStream() {
373   DCHECK(message_loop_->BelongsToCurrentThread());
374
375   // Allow calling unconditionally and bail if we don't have a stream_ to close.
376   if (stream_) {
377     // De-register from state change callbacks if stream_ was created via
378     // AudioManager.
379     if (stream_ != diverting_to_stream_)
380       audio_manager_->RemoveOutputDeviceChangeListener(this);
381
382     StopStream();
383     stream_->Close();
384     if (stream_ == diverting_to_stream_)
385       diverting_to_stream_ = NULL;
386     stream_ = NULL;
387   }
388
389   state_ = kEmpty;
390 }
391
392 void AudioOutputController::OnDeviceChange() {
393   DCHECK(message_loop_->BelongsToCurrentThread());
394   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.DeviceChangeTime");
395   TRACE_EVENT0("audio", "AudioOutputController::OnDeviceChange");
396
397   // TODO(dalecurtis): Notify the renderer side that a device change has
398   // occurred.  Currently querying the hardware information here will lead to
399   // crashes on OSX.  See http://crbug.com/158170.
400
401   // Recreate the stream (DoCreate() will first shut down an existing stream).
402   // Exit if we ran into an error.
403   const State original_state = state_;
404   DoCreate(true);
405   if (!stream_ || state_ == kError)
406     return;
407
408   // Get us back to the original state or an equivalent state.
409   switch (original_state) {
410     case kPlaying:
411       DoPlay();
412       return;
413     case kCreated:
414     case kPaused:
415       // From the outside these two states are equivalent.
416       return;
417     default:
418       NOTREACHED() << "Invalid original state.";
419   }
420 }
421
422 const AudioParameters& AudioOutputController::GetAudioParameters() {
423   return params_;
424 }
425
426 void AudioOutputController::StartDiverting(AudioOutputStream* to_stream) {
427   message_loop_->PostTask(
428       FROM_HERE,
429       base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream));
430 }
431
432 void AudioOutputController::StopDiverting() {
433   message_loop_->PostTask(
434       FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
435 }
436
437 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
438   DCHECK(message_loop_->BelongsToCurrentThread());
439
440   if (state_ == kClosed)
441     return;
442
443   DCHECK(!diverting_to_stream_);
444   diverting_to_stream_ = to_stream;
445   // Note: OnDeviceChange() will engage the "re-create" process, which will
446   // detect and use the alternate AudioOutputStream rather than create a new one
447   // via AudioManager.
448   OnDeviceChange();
449 }
450
451 void AudioOutputController::DoStopDiverting() {
452   DCHECK(message_loop_->BelongsToCurrentThread());
453
454   if (state_ == kClosed)
455     return;
456
457   // Note: OnDeviceChange() will cause the existing stream (the consumer of the
458   // diverted audio data) to be closed, and diverting_to_stream_ will be set
459   // back to NULL.
460   OnDeviceChange();
461   DCHECK(!diverting_to_stream_);
462 }
463
464 void AudioOutputController::AllowEntryToOnMoreIOData() {
465   DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
466   base::AtomicRefCountInc(&num_allowed_io_);
467 }
468
469 void AudioOutputController::DisallowEntryToOnMoreIOData() {
470   const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
471   DCHECK(is_zero);
472 }
473
474 void AudioOutputController::WedgeCheck() {
475   DCHECK(message_loop_->BelongsToCurrentThread());
476
477   // If we should be playing and we haven't, that's a wedge.
478   if (state_ == kPlaying) {
479     const bool playback_success =
480         base::AtomicRefCountIsOne(&on_more_io_data_called_);
481
482     UMA_HISTOGRAM_BOOLEAN(
483         "Media.AudioOutputControllerPlaybackStartupSuccess", playback_success);
484
485     // Let the AudioManager try and fix it.
486     if (!playback_success)
487       audio_manager_->FixWedgedAudio();
488   }
489 }
490
491 }  // namespace media