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