cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / audio / audio_output_resampler.cc
blob6db0e2fb2fe58547052fdfa3597a7565e5295c62
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.
5 #include "media/audio/audio_output_resampler.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/metrics/histogram.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/audio_util.h"
18 #include "media/audio/sample_rates.h"
19 #include "media/base/audio_converter.h"
20 #include "media/base/limits.h"
22 namespace media {
24 class OnMoreDataConverter
25 : public AudioOutputStream::AudioSourceCallback,
26 public AudioConverter::InputCallback {
27 public:
28 OnMoreDataConverter(const AudioParameters& input_params,
29 const AudioParameters& output_params);
30 virtual ~OnMoreDataConverter();
32 // AudioSourceCallback interface.
33 virtual int OnMoreData(AudioBus* dest,
34 AudioBuffersState buffers_state) OVERRIDE;
35 virtual int OnMoreIOData(AudioBus* source,
36 AudioBus* dest,
37 AudioBuffersState buffers_state) OVERRIDE;
38 virtual void OnError(AudioOutputStream* stream) OVERRIDE;
40 // Sets |source_callback_|. If this is not a new object, then Stop() must be
41 // called before Start().
42 void Start(AudioOutputStream::AudioSourceCallback* callback);
44 // Clears |source_callback_| and flushes the resampler.
45 void Stop();
47 private:
48 // AudioConverter::InputCallback implementation.
49 virtual double ProvideInput(AudioBus* audio_bus,
50 base::TimeDelta buffer_delay) OVERRIDE;
52 // Ratio of input bytes to output bytes used to correct playback delay with
53 // regard to buffering and resampling.
54 double io_ratio_;
56 // Source callback and associated lock.
57 base::Lock source_lock_;
58 AudioOutputStream::AudioSourceCallback* source_callback_;
60 // |source| passed to OnMoreIOData() which should be passed downstream.
61 AudioBus* source_bus_;
63 // Last AudioBuffersState object received via OnMoreData(), used to correct
64 // playback delay by ProvideInput() and passed on to |source_callback_|.
65 AudioBuffersState current_buffers_state_;
67 const int input_bytes_per_second_;
69 // Handles resampling, buffering, and channel mixing between input and output
70 // parameters.
71 AudioConverter audio_converter_;
73 DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter);
76 // Record UMA statistics for hardware output configuration.
77 static void RecordStats(const AudioParameters& output_params) {
78 UMA_HISTOGRAM_ENUMERATION(
79 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(),
80 limits::kMaxBitsPerSample);
81 UMA_HISTOGRAM_ENUMERATION(
82 "Media.HardwareAudioChannelLayout", output_params.channel_layout(),
83 CHANNEL_LAYOUT_MAX);
84 UMA_HISTOGRAM_ENUMERATION(
85 "Media.HardwareAudioChannelCount", output_params.channels(),
86 limits::kMaxChannels);
88 AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
89 if (asr != kUnexpectedAudioSampleRate) {
90 UMA_HISTOGRAM_ENUMERATION(
91 "Media.HardwareAudioSamplesPerSecond", asr, kUnexpectedAudioSampleRate);
92 } else {
93 UMA_HISTOGRAM_COUNTS(
94 "Media.HardwareAudioSamplesPerSecondUnexpected",
95 output_params.sample_rate());
99 // Record UMA statistics for hardware output configuration after fallback.
100 static void RecordFallbackStats(const AudioParameters& output_params) {
101 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", true);
102 UMA_HISTOGRAM_ENUMERATION(
103 "Media.FallbackHardwareAudioBitsPerChannel",
104 output_params.bits_per_sample(), limits::kMaxBitsPerSample);
105 UMA_HISTOGRAM_ENUMERATION(
106 "Media.FallbackHardwareAudioChannelLayout",
107 output_params.channel_layout(), CHANNEL_LAYOUT_MAX);
108 UMA_HISTOGRAM_ENUMERATION(
109 "Media.FallbackHardwareAudioChannelCount",
110 output_params.channels(), limits::kMaxChannels);
112 AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
113 if (asr != kUnexpectedAudioSampleRate) {
114 UMA_HISTOGRAM_ENUMERATION(
115 "Media.FallbackHardwareAudioSamplesPerSecond",
116 asr, kUnexpectedAudioSampleRate);
117 } else {
118 UMA_HISTOGRAM_COUNTS(
119 "Media.FallbackHardwareAudioSamplesPerSecondUnexpected",
120 output_params.sample_rate());
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 // Converts low latency based |output_params| into high latency appropriate
128 // output parameters in error situations.
129 static AudioParameters SetupFallbackParams(
130 const AudioParameters& input_params, const AudioParameters& output_params) {
131 // Choose AudioParameters appropriate for opening the device in high latency
132 // mode. |kMinLowLatencyFrameSize| is arbitrarily based on Pepper Flash's
133 // MAXIMUM frame size for low latency.
134 static const int kMinLowLatencyFrameSize = 2048;
135 int frames_per_buffer = std::min(
136 std::max(input_params.frames_per_buffer(), kMinLowLatencyFrameSize),
137 static_cast<int>(
138 GetHighLatencyOutputBufferSize(input_params.sample_rate())));
140 return AudioParameters(
141 AudioParameters::AUDIO_PCM_LINEAR, input_params.channel_layout(),
142 input_params.sample_rate(), input_params.bits_per_sample(),
143 frames_per_buffer);
145 #endif
147 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
148 const AudioParameters& input_params,
149 const AudioParameters& output_params,
150 const std::string& input_device_id,
151 const base::TimeDelta& close_delay)
152 : AudioOutputDispatcher(audio_manager, input_params, input_device_id),
153 close_delay_(close_delay),
154 output_params_(output_params),
155 input_device_id_(input_device_id),
156 streams_opened_(false) {
157 DCHECK(input_params.IsValid());
158 DCHECK(output_params.IsValid());
159 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
161 // Record UMA statistics for the hardware configuration.
162 RecordStats(output_params);
164 Initialize();
167 AudioOutputResampler::~AudioOutputResampler() {
168 DCHECK(callbacks_.empty());
171 void AudioOutputResampler::Initialize() {
172 DCHECK(!streams_opened_);
173 DCHECK(callbacks_.empty());
174 dispatcher_ = new AudioOutputDispatcherImpl(
175 audio_manager_, output_params_, input_device_id_, close_delay_);
178 bool AudioOutputResampler::OpenStream() {
179 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
181 if (dispatcher_->OpenStream()) {
182 // Only record the UMA statistic if we didn't fallback during construction
183 // and only for the first stream we open.
184 if (!streams_opened_ &&
185 output_params_.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
186 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false);
188 streams_opened_ = true;
189 return true;
192 // If we've already tried to open the stream in high latency mode or we've
193 // successfully opened a stream previously, there's nothing more to be done.
194 if (output_params_.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY ||
195 streams_opened_ || !callbacks_.empty()) {
196 return false;
199 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
201 // Record UMA statistics about the hardware which triggered the failure so
202 // we can debug and triage later.
203 RecordFallbackStats(output_params_);
205 // Only Windows has a high latency output driver that is not the same as the
206 // low latency path.
207 #if defined(OS_WIN)
208 DLOG(ERROR) << "Unable to open audio device in low latency mode. Falling "
209 << "back to high latency audio output.";
211 output_params_ = SetupFallbackParams(params_, output_params_);
212 Initialize();
213 if (dispatcher_->OpenStream()) {
214 streams_opened_ = true;
215 return true;
217 #endif
219 DLOG(ERROR) << "Unable to open audio device in high latency mode. Falling "
220 << "back to fake audio output.";
222 // Finally fall back to a fake audio output device.
223 output_params_.Reset(
224 AudioParameters::AUDIO_FAKE, params_.channel_layout(),
225 params_.channels(), params_.input_channels(), params_.sample_rate(),
226 params_.bits_per_sample(), params_.frames_per_buffer());
227 Initialize();
228 if (dispatcher_->OpenStream()) {
229 streams_opened_ = true;
230 return true;
233 return false;
236 bool AudioOutputResampler::StartStream(
237 AudioOutputStream::AudioSourceCallback* callback,
238 AudioOutputProxy* stream_proxy) {
239 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
241 OnMoreDataConverter* resampler_callback = NULL;
242 CallbackMap::iterator it = callbacks_.find(stream_proxy);
243 if (it == callbacks_.end()) {
244 resampler_callback = new OnMoreDataConverter(params_, output_params_);
245 callbacks_[stream_proxy] = resampler_callback;
246 } else {
247 resampler_callback = it->second;
250 resampler_callback->Start(callback);
251 bool result = dispatcher_->StartStream(resampler_callback, stream_proxy);
252 if (!result)
253 resampler_callback->Stop();
254 return result;
257 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
258 double volume) {
259 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
260 dispatcher_->StreamVolumeSet(stream_proxy, volume);
263 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
264 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
265 dispatcher_->StopStream(stream_proxy);
267 // Now that StopStream() has completed the underlying physical stream should
268 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the
269 // OnMoreDataConverter.
270 CallbackMap::iterator it = callbacks_.find(stream_proxy);
271 if (it != callbacks_.end())
272 it->second->Stop();
275 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
276 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
277 dispatcher_->CloseStream(stream_proxy);
279 // We assume that StopStream() is always called prior to CloseStream(), so
280 // that it is safe to delete the OnMoreDataConverter here.
281 CallbackMap::iterator it = callbacks_.find(stream_proxy);
282 if (it != callbacks_.end()) {
283 delete it->second;
284 callbacks_.erase(it);
288 void AudioOutputResampler::Shutdown() {
289 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
291 // No AudioOutputProxy objects should hold a reference to us when we get
292 // to this stage.
293 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
295 dispatcher_->Shutdown();
296 DCHECK(callbacks_.empty());
299 OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params,
300 const AudioParameters& output_params)
301 : source_callback_(NULL),
302 source_bus_(NULL),
303 input_bytes_per_second_(input_params.GetBytesPerSecond()),
304 audio_converter_(input_params, output_params, false) {
305 io_ratio_ =
306 static_cast<double>(input_params.GetBytesPerSecond()) /
307 output_params.GetBytesPerSecond();
310 OnMoreDataConverter::~OnMoreDataConverter() {
311 // Ensure Stop() has been called so we don't end up with an AudioOutputStream
312 // calling back into OnMoreData() after destruction.
313 CHECK(!source_callback_);
316 void OnMoreDataConverter::Start(
317 AudioOutputStream::AudioSourceCallback* callback) {
318 base::AutoLock auto_lock(source_lock_);
319 CHECK(!source_callback_);
320 source_callback_ = callback;
322 // While AudioConverter can handle multiple inputs, we're using it only with
323 // a single input currently. Eventually this may be the basis for a browser
324 // side mixer.
325 audio_converter_.AddInput(this);
328 void OnMoreDataConverter::Stop() {
329 base::AutoLock auto_lock(source_lock_);
330 CHECK(source_callback_);
331 source_callback_ = NULL;
332 audio_converter_.RemoveInput(this);
335 int OnMoreDataConverter::OnMoreData(AudioBus* dest,
336 AudioBuffersState buffers_state) {
337 return OnMoreIOData(NULL, dest, buffers_state);
340 int OnMoreDataConverter::OnMoreIOData(AudioBus* source,
341 AudioBus* dest,
342 AudioBuffersState buffers_state) {
343 base::AutoLock auto_lock(source_lock_);
344 // While we waited for |source_lock_| the callback might have been cleared.
345 if (!source_callback_) {
346 dest->Zero();
347 return dest->frames();
350 source_bus_ = source;
351 current_buffers_state_ = buffers_state;
352 audio_converter_.Convert(dest);
354 // Always return the full number of frames requested, ProvideInput_Locked()
355 // will pad with silence if it wasn't able to acquire enough data.
356 return dest->frames();
359 double OnMoreDataConverter::ProvideInput(AudioBus* dest,
360 base::TimeDelta buffer_delay) {
361 source_lock_.AssertAcquired();
363 // Adjust playback delay to include |buffer_delay|.
364 // TODO(dalecurtis): Stop passing bytes around, it doesn't make sense since
365 // AudioBus is just float data. Use TimeDelta instead.
366 AudioBuffersState new_buffers_state;
367 new_buffers_state.pending_bytes =
368 io_ratio_ * (current_buffers_state_.total_bytes() +
369 buffer_delay.InSecondsF() * input_bytes_per_second_);
371 // Retrieve data from the original callback.
372 int frames = source_callback_->OnMoreIOData(
373 source_bus_, dest, new_buffers_state);
375 // |source_bus_| should only be provided once.
376 // TODO(dalecurtis, crogers): This is not a complete fix. If ProvideInput()
377 // is called multiple times, we need to do something more clever here.
378 source_bus_ = NULL;
380 // Zero any unfilled frames if anything was filled, otherwise we'll just
381 // return a volume of zero and let AudioConverter drop the output.
382 if (frames > 0 && frames < dest->frames())
383 dest->ZeroFramesPartial(frames, dest->frames() - frames);
385 // TODO(dalecurtis): Return the correct volume here.
386 return frames > 0 ? 1 : 0;
389 void OnMoreDataConverter::OnError(AudioOutputStream* stream) {
390 base::AutoLock auto_lock(source_lock_);
391 if (source_callback_)
392 source_callback_->OnError(stream);
395 } // namespace media