audio_output_resampler.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/command_line.h"
10#include "base/compiler_specific.h"
11#include "base/message_loop.h"
12#include "base/metrics/histogram.h"
13#include "base/time.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/audio_util.h"
18#include "media/audio/sample_rates.h"
19#include "media/base/audio_pull_fifo.h"
20#include "media/base/channel_mixer.h"
21#include "media/base/limits.h"
22#include "media/base/media_switches.h"
23#include "media/base/multi_channel_resampler.h"
24
25namespace media {
26
27class OnMoreDataResampler : public AudioOutputStream::AudioSourceCallback {
28 public:
29  OnMoreDataResampler(double io_ratio,
30                      const AudioParameters& input_params,
31                      const AudioParameters& output_params);
32  virtual ~OnMoreDataResampler();
33
34  // AudioSourceCallback interface.
35  virtual int OnMoreData(AudioBus* dest,
36                         AudioBuffersState buffers_state) OVERRIDE;
37  virtual int OnMoreIOData(AudioBus* source,
38                           AudioBus* dest,
39                           AudioBuffersState buffers_state) OVERRIDE;
40  virtual void OnError(AudioOutputStream* stream, int code) OVERRIDE;
41  virtual void WaitTillDataReady() OVERRIDE;
42
43  // Sets |source_callback_|.  If this is not a new object, then Stop() must be
44  // called before Start().
45  void Start(AudioOutputStream::AudioSourceCallback* callback);
46
47  // Clears |source_callback_| and flushes the resampler.
48  void Stop();
49
50 private:
51  // Called by MultiChannelResampler when more data is necessary.
52  void ProvideInput(AudioBus* audio_bus);
53
54  // Called by AudioPullFifo when more data is necessary.  Requires
55  // |source_lock_| to have been acquired.
56  void SourceCallback_Locked(AudioBus* audio_bus);
57
58  // Passes through |source| to the |source_callback_| OnMoreIOData() call.
59  void SourceIOCallback_Locked(AudioBus* source, AudioBus* dest);
60
61  // Ratio of input bytes to output bytes used to correct playback delay with
62  // regard to buffering and resampling.
63  double io_ratio_;
64
65  // Source callback and associated lock.
66  base::Lock source_lock_;
67  AudioOutputStream::AudioSourceCallback* source_callback_;
68
69  // Last AudioBuffersState object received via OnMoreData(), used to correct
70  // playback delay by ProvideInput() and passed on to |source_callback_|.
71  AudioBuffersState current_buffers_state_;
72
73  // Total number of bytes (in terms of output parameters) stored in resampler
74  // or FIFO buffers which have not been sent to the audio device.
75  int outstanding_audio_bytes_;
76
77  // Used to buffer data between the client and the output device in cases where
78  // the client buffer size is not the same as the output device buffer size.
79  // Bound to SourceCallback_Locked() so must only be used when |source_lock_|
80  // has already been acquired.
81  scoped_ptr<AudioPullFifo> audio_fifo_;
82
83  // Handles resampling.
84  scoped_ptr<MultiChannelResampler> resampler_;
85
86  // Handles channel transforms.  |unmixed_audio_| is a temporary destination
87  // for audio data before it goes into the channel mixer.
88  scoped_ptr<ChannelMixer> channel_mixer_;
89  scoped_ptr<AudioBus> unmixed_audio_;
90
91  int output_bytes_per_frame_;
92  int input_bytes_per_frame_;
93
94  // Since resampling is expensive, figure out if we should downmix channels
95  // before resampling.
96  bool downmix_early_;
97
98  DISALLOW_COPY_AND_ASSIGN(OnMoreDataResampler);
99};
100
101// Record UMA statistics for hardware output configuration.
102static void RecordStats(const AudioParameters& output_params) {
103  UMA_HISTOGRAM_ENUMERATION(
104      "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(),
105      limits::kMaxBitsPerSample);
106  UMA_HISTOGRAM_ENUMERATION(
107      "Media.HardwareAudioChannelLayout", output_params.channel_layout(),
108      CHANNEL_LAYOUT_MAX);
109  UMA_HISTOGRAM_ENUMERATION(
110      "Media.HardwareAudioChannelCount", output_params.channels(),
111      limits::kMaxChannels);
112
113  AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
114  if (asr != kUnexpectedAudioSampleRate) {
115    UMA_HISTOGRAM_ENUMERATION(
116        "Media.HardwareAudioSamplesPerSecond", asr, kUnexpectedAudioSampleRate);
117  } else {
118    UMA_HISTOGRAM_COUNTS(
119        "Media.HardwareAudioSamplesPerSecondUnexpected",
120        output_params.sample_rate());
121  }
122}
123
124// Record UMA statistics for hardware output configuration after fallback.
125static void RecordFallbackStats(const AudioParameters& output_params) {
126  UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", true);
127  UMA_HISTOGRAM_ENUMERATION(
128      "Media.FallbackHardwareAudioBitsPerChannel",
129      output_params.bits_per_sample(), limits::kMaxBitsPerSample);
130  UMA_HISTOGRAM_ENUMERATION(
131      "Media.FallbackHardwareAudioChannelLayout",
132      output_params.channel_layout(), CHANNEL_LAYOUT_MAX);
133  UMA_HISTOGRAM_ENUMERATION(
134      "Media.FallbackHardwareAudioChannelCount",
135      output_params.channels(), limits::kMaxChannels);
136
137  AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
138  if (asr != kUnexpectedAudioSampleRate) {
139    UMA_HISTOGRAM_ENUMERATION(
140        "Media.FallbackHardwareAudioSamplesPerSecond",
141        asr, kUnexpectedAudioSampleRate);
142  } else {
143    UMA_HISTOGRAM_COUNTS(
144        "Media.FallbackHardwareAudioSamplesPerSecondUnexpected",
145        output_params.sample_rate());
146  }
147}
148
149// Converts low latency based |output_params| into high latency appropriate
150// output parameters in error situations.
151static AudioParameters SetupFallbackParams(
152    const AudioParameters& input_params, const AudioParameters& output_params) {
153  // Choose AudioParameters appropriate for opening the device in high latency
154  // mode.  |kMinLowLatencyFrameSize| is arbitrarily based on Pepper Flash's
155  // MAXIMUM frame size for low latency.
156  static const int kMinLowLatencyFrameSize = 2048;
157  int frames_per_buffer = std::min(
158      std::max(input_params.frames_per_buffer(), kMinLowLatencyFrameSize),
159      static_cast<int>(
160          GetHighLatencyOutputBufferSize(input_params.sample_rate())));
161
162  return AudioParameters(
163      AudioParameters::AUDIO_PCM_LINEAR, input_params.channel_layout(),
164      input_params.sample_rate(), input_params.bits_per_sample(),
165      frames_per_buffer);
166}
167
168AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
169                                           const AudioParameters& input_params,
170                                           const AudioParameters& output_params,
171                                           const base::TimeDelta& close_delay)
172    : AudioOutputDispatcher(audio_manager, input_params),
173      io_ratio_(1),
174      close_delay_(close_delay),
175      output_params_(output_params),
176      streams_opened_(false) {
177  DCHECK(input_params.IsValid());
178  DCHECK(output_params.IsValid());
179  DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
180
181  // Record UMA statistics for the hardware configuration.
182  RecordStats(output_params);
183
184  Initialize();
185}
186
187AudioOutputResampler::~AudioOutputResampler() {
188  DCHECK(callbacks_.empty());
189}
190
191void AudioOutputResampler::Initialize() {
192  DCHECK(!streams_opened_);
193  DCHECK(callbacks_.empty());
194
195  io_ratio_ = 1;
196
197  // Only resample or rebuffer if the input parameters don't match the output
198  // parameters to avoid any unnecessary work.
199  if (params_.channels() != output_params_.channels() ||
200      params_.sample_rate() != output_params_.sample_rate() ||
201      params_.bits_per_sample() != output_params_.bits_per_sample() ||
202      params_.frames_per_buffer() != output_params_.frames_per_buffer()) {
203    if (params_.sample_rate() != output_params_.sample_rate()) {
204      double io_sample_rate_ratio = params_.sample_rate() /
205          static_cast<double>(output_params_.sample_rate());
206      // Include the I/O resampling ratio in our global I/O ratio.
207      io_ratio_ *= io_sample_rate_ratio;
208    }
209
210    // Include bits per channel differences.
211    io_ratio_ *= static_cast<double>(params_.bits_per_sample()) /
212        output_params_.bits_per_sample();
213
214    // Include channel count differences.
215    io_ratio_ *= static_cast<double>(params_.channels()) /
216        output_params_.channels();
217
218    DVLOG(1) << "I/O ratio is " << io_ratio_;
219  } else {
220    DVLOG(1) << "Input and output params are the same; in pass-through mode.";
221  }
222
223  // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once
224  // we've stabilized the issues there.
225  dispatcher_ = new AudioOutputDispatcherImpl(
226      audio_manager_, output_params_, close_delay_);
227}
228
229bool AudioOutputResampler::OpenStream() {
230  DCHECK_EQ(MessageLoop::current(), message_loop_);
231
232  if (dispatcher_->OpenStream()) {
233    // Only record the UMA statistic if we didn't fallback during construction
234    // and only for the first stream we open.
235    if (!streams_opened_ &&
236        output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
237      UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false);
238    }
239    streams_opened_ = true;
240    return true;
241  }
242
243  // If we've already tried to open the stream in high latency mode or we've
244  // successfully opened a stream previously, there's nothing more to be done.
245  if (output_params_.format() == AudioParameters::AUDIO_PCM_LINEAR ||
246      streams_opened_ || !callbacks_.empty()) {
247    return false;
248  }
249
250  DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
251
252  if (CommandLine::ForCurrentProcess()->HasSwitch(
253          switches::kDisableAudioFallback)) {
254    LOG(ERROR) << "Open failed and automatic fallback to high latency audio "
255               << "path is disabled, aborting.";
256    return false;
257  }
258
259  DLOG(ERROR) << "Unable to open audio device in low latency mode.  Falling "
260              << "back to high latency audio output.";
261
262  // Record UMA statistics about the hardware which triggered the failure so
263  // we can debug and triage later.
264  RecordFallbackStats(output_params_);
265  output_params_ = SetupFallbackParams(params_, output_params_);
266  Initialize();
267
268  // Retry, if this fails, there's nothing left to do but report the error back.
269  return dispatcher_->OpenStream();
270}
271
272bool AudioOutputResampler::StartStream(
273    AudioOutputStream::AudioSourceCallback* callback,
274    AudioOutputProxy* stream_proxy) {
275  DCHECK_EQ(MessageLoop::current(), message_loop_);
276
277  OnMoreDataResampler* resampler_callback = NULL;
278  CallbackMap::iterator it = callbacks_.find(stream_proxy);
279  if (it == callbacks_.end()) {
280    resampler_callback = new OnMoreDataResampler(
281        io_ratio_, params_, output_params_);
282    callbacks_[stream_proxy] = resampler_callback;
283  } else {
284    resampler_callback = it->second;
285  }
286  resampler_callback->Start(callback);
287  return dispatcher_->StartStream(resampler_callback, stream_proxy);
288}
289
290void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
291                                           double volume) {
292  DCHECK_EQ(MessageLoop::current(), message_loop_);
293  dispatcher_->StreamVolumeSet(stream_proxy, volume);
294}
295
296void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
297  DCHECK_EQ(MessageLoop::current(), message_loop_);
298  dispatcher_->StopStream(stream_proxy);
299
300  // Now that StopStream() has completed the underlying physical stream should
301  // be stopped and no longer calling OnMoreData(), making it safe to Stop() the
302  // OnMoreDataResampler.
303  CallbackMap::iterator it = callbacks_.find(stream_proxy);
304  if (it != callbacks_.end())
305    it->second->Stop();
306}
307
308void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
309  DCHECK_EQ(MessageLoop::current(), message_loop_);
310  dispatcher_->CloseStream(stream_proxy);
311
312  // We assume that StopStream() is always called prior to CloseStream(), so
313  // that it is safe to delete the OnMoreDataResampler here.
314  CallbackMap::iterator it = callbacks_.find(stream_proxy);
315  if (it != callbacks_.end()) {
316    delete it->second;
317    callbacks_.erase(it);
318  }
319}
320
321void AudioOutputResampler::Shutdown() {
322  DCHECK_EQ(MessageLoop::current(), message_loop_);
323
324  // No AudioOutputProxy objects should hold a reference to us when we get
325  // to this stage.
326  DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
327
328  dispatcher_->Shutdown();
329  DCHECK(callbacks_.empty());
330}
331
332OnMoreDataResampler::OnMoreDataResampler(
333    double io_ratio, const AudioParameters& input_params,
334    const AudioParameters& output_params)
335    : io_ratio_(io_ratio),
336      source_callback_(NULL),
337      outstanding_audio_bytes_(0),
338      output_bytes_per_frame_(output_params.GetBytesPerFrame()),
339      input_bytes_per_frame_(input_params.GetBytesPerFrame()),
340      downmix_early_(false) {
341  // Handle different input and output channel layouts.
342  if (input_params.channel_layout() != output_params.channel_layout()) {
343    DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout()
344             << " to " << output_params.channel_layout() << "; from "
345             << input_params.channels() << " channels to "
346             << output_params.channels() << " channels.";
347    channel_mixer_.reset(new ChannelMixer(
348        input_params.channel_layout(), output_params.channel_layout()));
349
350    // Pare off data as early as we can for efficiency.
351    downmix_early_ = input_params.channels() > output_params.channels();
352    if (downmix_early_) {
353      DVLOG(1) << "Remixing channel layout prior to resampling.";
354      // If we're downmixing early we need a temporary AudioBus which matches
355      // the the input channel count and input frame size since we're passing
356      // |unmixed_audio_| directly to the |source_callback_|.
357      unmixed_audio_ = AudioBus::Create(input_params);
358    } else {
359      // Instead, if we're not downmixing early we need a temporary AudioBus
360      // which matches the input channel count but uses the output frame size
361      // since we'll mix into the AudioBus from the output stream.
362      unmixed_audio_ = AudioBus::Create(
363          input_params.channels(), output_params.frames_per_buffer());
364    }
365  }
366
367  // Only resample if necessary since it's expensive.
368  if (input_params.sample_rate() != output_params.sample_rate()) {
369    DVLOG(1) << "Resampling from " << input_params.sample_rate() << " to "
370             << output_params.sample_rate();
371    double io_sample_rate_ratio = input_params.sample_rate() /
372        static_cast<double>(output_params.sample_rate());
373    resampler_.reset(new MultiChannelResampler(
374        downmix_early_ ? output_params.channels() :
375            input_params.channels(),
376        io_sample_rate_ratio, base::Bind(
377            &OnMoreDataResampler::ProvideInput, base::Unretained(this))));
378  }
379
380  // Since the resampler / output device may want a different buffer size than
381  // the caller asked for, we need to use a FIFO to ensure that both sides
382  // read in chunk sizes they're configured for.
383  if (input_params.sample_rate() != output_params.sample_rate() ||
384      input_params.frames_per_buffer() != output_params.frames_per_buffer()) {
385    DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer()
386             << " to " << output_params.frames_per_buffer();
387    audio_fifo_.reset(new AudioPullFifo(
388        downmix_early_ ? output_params.channels() :
389            input_params.channels(),
390        input_params.frames_per_buffer(), base::Bind(
391            &OnMoreDataResampler::SourceCallback_Locked,
392            base::Unretained(this))));
393  }
394}
395
396OnMoreDataResampler::~OnMoreDataResampler() {}
397
398void OnMoreDataResampler::Start(
399    AudioOutputStream::AudioSourceCallback* callback) {
400  base::AutoLock auto_lock(source_lock_);
401  DCHECK(!source_callback_);
402  source_callback_ = callback;
403}
404
405void OnMoreDataResampler::Stop() {
406  base::AutoLock auto_lock(source_lock_);
407  source_callback_ = NULL;
408  outstanding_audio_bytes_ = 0;
409  if (audio_fifo_)
410    audio_fifo_->Clear();
411  if (resampler_)
412    resampler_->Flush();
413}
414
415int OnMoreDataResampler::OnMoreData(AudioBus* dest,
416                                    AudioBuffersState buffers_state) {
417  return OnMoreIOData(NULL, dest, buffers_state);
418}
419
420int OnMoreDataResampler::OnMoreIOData(AudioBus* source,
421                                      AudioBus* dest,
422                                      AudioBuffersState buffers_state) {
423  base::AutoLock auto_lock(source_lock_);
424  // While we waited for |source_lock_| the callback might have been cleared.
425  if (!source_callback_) {
426    dest->Zero();
427    return dest->frames();
428  }
429
430  current_buffers_state_ = buffers_state;
431
432  bool needs_mixing = channel_mixer_ && !downmix_early_;
433  AudioBus* temp_dest = needs_mixing ? unmixed_audio_.get() : dest;
434
435  if (!resampler_ && !audio_fifo_) {
436    // We have no internal buffers, so clear any outstanding audio data.
437    outstanding_audio_bytes_ = 0;
438    SourceIOCallback_Locked(source, temp_dest);
439  } else {
440    if (resampler_)
441      resampler_->Resample(temp_dest, temp_dest->frames());
442    else
443      ProvideInput(temp_dest);
444
445    // Calculate how much data is left in the internal FIFO and resampler.
446    outstanding_audio_bytes_ -= temp_dest->frames() * output_bytes_per_frame_;
447  }
448
449  if (needs_mixing) {
450    DCHECK_EQ(temp_dest->frames(), dest->frames());
451    channel_mixer_->Transform(temp_dest, dest);
452  }
453
454  // Due to rounding errors while multiplying against |io_ratio_|,
455  // |outstanding_audio_bytes_| might (rarely) slip below zero.
456  if (outstanding_audio_bytes_ < 0) {
457    DLOG(ERROR) << "Outstanding audio bytes went negative! Value: "
458                << outstanding_audio_bytes_;
459    outstanding_audio_bytes_ = 0;
460  }
461
462  // Always return the full number of frames requested, ProvideInput() will pad
463  // with silence if it wasn't able to acquire enough data.
464  return dest->frames();
465}
466
467void OnMoreDataResampler::SourceCallback_Locked(AudioBus* dest) {
468  SourceIOCallback_Locked(NULL, dest);
469}
470
471void OnMoreDataResampler::SourceIOCallback_Locked(AudioBus* source,
472                                                  AudioBus* dest) {
473  source_lock_.AssertAcquired();
474
475  // Adjust playback delay to include the state of the internal buffers used by
476  // the resampler and/or the FIFO.  Since the sample rate and bits per channel
477  // may be different, we need to scale this value appropriately.
478  AudioBuffersState new_buffers_state;
479  new_buffers_state.pending_bytes = io_ratio_ *
480      (current_buffers_state_.total_bytes() + outstanding_audio_bytes_);
481
482  bool needs_downmix = channel_mixer_ && downmix_early_;
483  AudioBus* temp_dest = needs_downmix ? unmixed_audio_.get() : dest;
484
485  // Retrieve data from the original callback.  Zero any unfilled frames.
486  int frames = source_callback_->OnMoreIOData(
487      source, temp_dest, new_buffers_state);
488  if (frames < temp_dest->frames())
489    temp_dest->ZeroFramesPartial(frames, temp_dest->frames() - frames);
490
491  // Scale the number of frames we got back in terms of input bytes to output
492  // bytes accordingly.
493  outstanding_audio_bytes_ +=
494      (temp_dest->frames() * input_bytes_per_frame_) / io_ratio_;
495
496  if (needs_downmix) {
497    DCHECK_EQ(temp_dest->frames(), dest->frames());
498    channel_mixer_->Transform(temp_dest, dest);
499  }
500}
501
502void OnMoreDataResampler::ProvideInput(AudioBus* audio_bus) {
503  audio_fifo_->Consume(audio_bus, audio_bus->frames());
504}
505
506void OnMoreDataResampler::OnError(AudioOutputStream* stream, int code) {
507  base::AutoLock auto_lock(source_lock_);
508  if (source_callback_)
509    source_callback_->OnError(stream, code);
510}
511
512void OnMoreDataResampler::WaitTillDataReady() {
513  base::AutoLock auto_lock(source_lock_);
514  if (source_callback_ && !outstanding_audio_bytes_)
515    source_callback_->WaitTillDataReady();
516}
517
518}  // namespace media
519