Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / audio / audio_output_resampler.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_resampler.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h"
10 #include "base/metrics/histogram.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/time/time.h"
13 #include "build/build_config.h"
14 #include "media/audio/audio_io.h"
15 #include "media/audio/audio_output_dispatcher_impl.h"
16 #include "media/audio/audio_output_proxy.h"
17 #include "media/audio/sample_rates.h"
18 #include "media/base/audio_converter.h"
19 #include "media/base/limits.h"
20
21 namespace media {
22
23 class OnMoreDataConverter
24     : public AudioOutputStream::AudioSourceCallback,
25       public AudioConverter::InputCallback {
26  public:
27   OnMoreDataConverter(const AudioParameters& input_params,
28                       const AudioParameters& output_params);
29   virtual ~OnMoreDataConverter();
30
31   // AudioSourceCallback interface.
32   virtual int OnMoreData(AudioBus* dest,
33                          AudioBuffersState buffers_state) OVERRIDE;
34   virtual int OnMoreIOData(AudioBus* source,
35                            AudioBus* dest,
36                            AudioBuffersState buffers_state) OVERRIDE;
37   virtual void OnError(AudioOutputStream* stream) OVERRIDE;
38
39   // Sets |source_callback_|.  If this is not a new object, then Stop() must be
40   // called before Start().
41   void Start(AudioOutputStream::AudioSourceCallback* callback);
42
43   // Clears |source_callback_| and flushes the resampler.
44   void Stop();
45
46   bool started() { return source_callback_ != NULL; }
47
48  private:
49   // AudioConverter::InputCallback implementation.
50   virtual double ProvideInput(AudioBus* audio_bus,
51                               base::TimeDelta buffer_delay) OVERRIDE;
52
53   // Ratio of input bytes to output bytes used to correct playback delay with
54   // regard to buffering and resampling.
55   const double io_ratio_;
56
57   // Source callback.
58   AudioOutputStream::AudioSourceCallback* source_callback_;
59
60   // Last AudioBuffersState object received via OnMoreData(), used to correct
61   // playback delay by ProvideInput() and passed on to |source_callback_|.
62   AudioBuffersState current_buffers_state_;
63
64   const int input_bytes_per_second_;
65
66   // Handles resampling, buffering, and channel mixing between input and output
67   // parameters.
68   AudioConverter audio_converter_;
69
70   DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter);
71 };
72
73 // Record UMA statistics for hardware output configuration.
74 static void RecordStats(const AudioParameters& output_params) {
75   UMA_HISTOGRAM_ENUMERATION(
76       "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(),
77       limits::kMaxBitsPerSample);
78   UMA_HISTOGRAM_ENUMERATION(
79       "Media.HardwareAudioChannelLayout", output_params.channel_layout(),
80       CHANNEL_LAYOUT_MAX);
81   UMA_HISTOGRAM_ENUMERATION(
82       "Media.HardwareAudioChannelCount", output_params.channels(),
83       limits::kMaxChannels);
84
85   AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
86   if (asr != kUnexpectedAudioSampleRate) {
87     UMA_HISTOGRAM_ENUMERATION(
88         "Media.HardwareAudioSamplesPerSecond", asr, kUnexpectedAudioSampleRate);
89   } else {
90     UMA_HISTOGRAM_COUNTS(
91         "Media.HardwareAudioSamplesPerSecondUnexpected",
92         output_params.sample_rate());
93   }
94 }
95
96 // Record UMA statistics for hardware output configuration after fallback.
97 static void RecordFallbackStats(const AudioParameters& output_params) {
98   UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", true);
99   UMA_HISTOGRAM_ENUMERATION(
100       "Media.FallbackHardwareAudioBitsPerChannel",
101       output_params.bits_per_sample(), limits::kMaxBitsPerSample);
102   UMA_HISTOGRAM_ENUMERATION(
103       "Media.FallbackHardwareAudioChannelLayout",
104       output_params.channel_layout(), CHANNEL_LAYOUT_MAX);
105   UMA_HISTOGRAM_ENUMERATION(
106       "Media.FallbackHardwareAudioChannelCount",
107       output_params.channels(), limits::kMaxChannels);
108
109   AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
110   if (asr != kUnexpectedAudioSampleRate) {
111     UMA_HISTOGRAM_ENUMERATION(
112         "Media.FallbackHardwareAudioSamplesPerSecond",
113         asr, kUnexpectedAudioSampleRate);
114   } else {
115     UMA_HISTOGRAM_COUNTS(
116         "Media.FallbackHardwareAudioSamplesPerSecondUnexpected",
117         output_params.sample_rate());
118   }
119 }
120
121 // Converts low latency based |output_params| into high latency appropriate
122 // output parameters in error situations.
123 void AudioOutputResampler::SetupFallbackParams() {
124 // Only Windows has a high latency output driver that is not the same as the low
125 // latency path.
126 #if defined(OS_WIN)
127   // Choose AudioParameters appropriate for opening the device in high latency
128   // mode.  |kMinLowLatencyFrameSize| is arbitrarily based on Pepper Flash's
129   // MAXIMUM frame size for low latency.
130   static const int kMinLowLatencyFrameSize = 2048;
131   const int frames_per_buffer =
132       std::max(params_.frames_per_buffer(), kMinLowLatencyFrameSize);
133
134   output_params_ = AudioParameters(
135       AudioParameters::AUDIO_PCM_LINEAR, params_.channel_layout(),
136       params_.sample_rate(), params_.bits_per_sample(),
137       frames_per_buffer);
138   device_id_ = "";
139   Initialize();
140 #endif
141 }
142
143 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
144                                            const AudioParameters& input_params,
145                                            const AudioParameters& output_params,
146                                            const std::string& output_device_id,
147                                            const base::TimeDelta& close_delay)
148     : AudioOutputDispatcher(audio_manager, input_params, output_device_id),
149       close_delay_(close_delay),
150       output_params_(output_params),
151       streams_opened_(false) {
152   DCHECK(input_params.IsValid());
153   DCHECK(output_params.IsValid());
154   DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
155
156   // Record UMA statistics for the hardware configuration.
157   RecordStats(output_params);
158
159   Initialize();
160 }
161
162 AudioOutputResampler::~AudioOutputResampler() {
163   DCHECK(callbacks_.empty());
164 }
165
166 void AudioOutputResampler::Initialize() {
167   DCHECK(!streams_opened_);
168   DCHECK(callbacks_.empty());
169   dispatcher_ = new AudioOutputDispatcherImpl(
170       audio_manager_, output_params_, device_id_, close_delay_);
171 }
172
173 bool AudioOutputResampler::OpenStream() {
174   DCHECK(task_runner_->BelongsToCurrentThread());
175
176   if (dispatcher_->OpenStream()) {
177     // Only record the UMA statistic if we didn't fallback during construction
178     // and only for the first stream we open.
179     if (!streams_opened_ &&
180         output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
181       UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false);
182     }
183     streams_opened_ = true;
184     return true;
185   }
186
187   // If we've already tried to open the stream in high latency mode or we've
188   // successfully opened a stream previously, there's nothing more to be done.
189   if (output_params_.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY ||
190       streams_opened_ || !callbacks_.empty()) {
191     return false;
192   }
193
194   DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
195
196   // Record UMA statistics about the hardware which triggered the failure so
197   // we can debug and triage later.
198   RecordFallbackStats(output_params_);
199
200   // Only Windows has a high latency output driver that is not the same as the
201   // low latency path.
202 #if defined(OS_WIN)
203   DLOG(ERROR) << "Unable to open audio device in low latency mode.  Falling "
204               << "back to high latency audio output.";
205
206   SetupFallbackParams();
207   if (dispatcher_->OpenStream()) {
208     streams_opened_ = true;
209     return true;
210   }
211 #endif
212
213   DLOG(ERROR) << "Unable to open audio device in high latency mode.  Falling "
214               << "back to fake audio output.";
215
216   // Finally fall back to a fake audio output device.
217   output_params_.Reset(
218       AudioParameters::AUDIO_FAKE, params_.channel_layout(),
219       params_.channels(), params_.input_channels(), params_.sample_rate(),
220       params_.bits_per_sample(), params_.frames_per_buffer());
221   Initialize();
222   if (dispatcher_->OpenStream()) {
223     streams_opened_ = true;
224     return true;
225   }
226
227   return false;
228 }
229
230 bool AudioOutputResampler::StartStream(
231     AudioOutputStream::AudioSourceCallback* callback,
232     AudioOutputProxy* stream_proxy) {
233   DCHECK(task_runner_->BelongsToCurrentThread());
234
235   OnMoreDataConverter* resampler_callback = NULL;
236   CallbackMap::iterator it = callbacks_.find(stream_proxy);
237   if (it == callbacks_.end()) {
238     resampler_callback = new OnMoreDataConverter(params_, output_params_);
239     callbacks_[stream_proxy] = resampler_callback;
240   } else {
241     resampler_callback = it->second;
242   }
243
244   resampler_callback->Start(callback);
245   bool result = dispatcher_->StartStream(resampler_callback, stream_proxy);
246   if (!result)
247     resampler_callback->Stop();
248   return result;
249 }
250
251 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
252                                            double volume) {
253   DCHECK(task_runner_->BelongsToCurrentThread());
254   dispatcher_->StreamVolumeSet(stream_proxy, volume);
255 }
256
257 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
258   DCHECK(task_runner_->BelongsToCurrentThread());
259   dispatcher_->StopStream(stream_proxy);
260
261   // Now that StopStream() has completed the underlying physical stream should
262   // be stopped and no longer calling OnMoreData(), making it safe to Stop() the
263   // OnMoreDataConverter.
264   CallbackMap::iterator it = callbacks_.find(stream_proxy);
265   if (it != callbacks_.end())
266     it->second->Stop();
267 }
268
269 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
270   DCHECK(task_runner_->BelongsToCurrentThread());
271   dispatcher_->CloseStream(stream_proxy);
272
273   // We assume that StopStream() is always called prior to CloseStream(), so
274   // that it is safe to delete the OnMoreDataConverter here.
275   CallbackMap::iterator it = callbacks_.find(stream_proxy);
276   if (it != callbacks_.end()) {
277     delete it->second;
278     callbacks_.erase(it);
279   }
280 }
281
282 void AudioOutputResampler::Shutdown() {
283   DCHECK(task_runner_->BelongsToCurrentThread());
284
285   // No AudioOutputProxy objects should hold a reference to us when we get
286   // to this stage.
287   DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
288
289   dispatcher_->Shutdown();
290   DCHECK(callbacks_.empty());
291 }
292
293 void AudioOutputResampler::CloseStreamsForWedgeFix() {
294   DCHECK(task_runner_->BelongsToCurrentThread());
295
296   // Stop and close all active streams.  Once all streams across all dispatchers
297   // have been closed the AudioManager will call RestartStreamsForWedgeFix().
298   for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
299        ++it) {
300     if (it->second->started())
301       dispatcher_->StopStream(it->first);
302     dispatcher_->CloseStream(it->first);
303   }
304
305   // Close all idle streams as well.
306   dispatcher_->CloseStreamsForWedgeFix();
307 }
308
309 void AudioOutputResampler::RestartStreamsForWedgeFix() {
310   DCHECK(task_runner_->BelongsToCurrentThread());
311   // By opening all streams first and then starting them one by one we ensure
312   // the dispatcher only opens streams for those which will actually be used.
313   for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
314        ++it) {
315     dispatcher_->OpenStream();
316   }
317   for (CallbackMap::iterator it = callbacks_.begin(); it != callbacks_.end();
318        ++it) {
319     if (it->second->started())
320       dispatcher_->StartStream(it->second, it->first);
321   }
322 }
323
324 OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params,
325                                          const AudioParameters& output_params)
326     : io_ratio_(static_cast<double>(input_params.GetBytesPerSecond()) /
327                 output_params.GetBytesPerSecond()),
328       source_callback_(NULL),
329       input_bytes_per_second_(input_params.GetBytesPerSecond()),
330       audio_converter_(input_params, output_params, false) {}
331
332 OnMoreDataConverter::~OnMoreDataConverter() {
333   // Ensure Stop() has been called so we don't end up with an AudioOutputStream
334   // calling back into OnMoreData() after destruction.
335   CHECK(!source_callback_);
336 }
337
338 void OnMoreDataConverter::Start(
339     AudioOutputStream::AudioSourceCallback* callback) {
340   CHECK(!source_callback_);
341   source_callback_ = callback;
342
343   // While AudioConverter can handle multiple inputs, we're using it only with
344   // a single input currently.  Eventually this may be the basis for a browser
345   // side mixer.
346   audio_converter_.AddInput(this);
347 }
348
349 void OnMoreDataConverter::Stop() {
350   CHECK(source_callback_);
351   source_callback_ = NULL;
352   audio_converter_.RemoveInput(this);
353 }
354
355 int OnMoreDataConverter::OnMoreData(AudioBus* dest,
356                                     AudioBuffersState buffers_state) {
357   return OnMoreIOData(NULL, dest, buffers_state);
358 }
359
360 int OnMoreDataConverter::OnMoreIOData(AudioBus* source,
361                                       AudioBus* dest,
362                                       AudioBuffersState buffers_state) {
363   // Note: The input portion of OnMoreIOData() is not supported when a converter
364   // has been injected.  Downstream clients prefer silence to potentially split
365   // apart input data.
366
367   current_buffers_state_ = buffers_state;
368   audio_converter_.Convert(dest);
369
370   // Always return the full number of frames requested, ProvideInput()
371   // will pad with silence if it wasn't able to acquire enough data.
372   return dest->frames();
373 }
374
375 double OnMoreDataConverter::ProvideInput(AudioBus* dest,
376                                          base::TimeDelta buffer_delay) {
377   // Adjust playback delay to include |buffer_delay|.
378   // TODO(dalecurtis): Stop passing bytes around, it doesn't make sense since
379   // AudioBus is just float data.  Use TimeDelta instead.
380   AudioBuffersState new_buffers_state;
381   new_buffers_state.pending_bytes =
382       io_ratio_ * (current_buffers_state_.total_bytes() +
383                    buffer_delay.InSecondsF() * input_bytes_per_second_);
384
385   // Retrieve data from the original callback.
386   const int frames = source_callback_->OnMoreIOData(
387       NULL, dest, new_buffers_state);
388
389   // Zero any unfilled frames if anything was filled, otherwise we'll just
390   // return a volume of zero and let AudioConverter drop the output.
391   if (frames > 0 && frames < dest->frames())
392     dest->ZeroFramesPartial(frames, dest->frames() - frames);
393   return frames > 0 ? 1 : 0;
394 }
395
396 void OnMoreDataConverter::OnError(AudioOutputStream* stream) {
397   source_callback_->OnError(stream);
398 }
399
400 }  // namespace media