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