Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Side by Side Diff: media/audio/audio_output_resampler.cc

Issue 10909151: Automatically fall back to non-low latency on open() failure. (Closed) Base URL: http://git.chromium.org/chromium/src.git@resampler2
Patch Set: Rebase. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/audio/audio_output_resampler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_output_resampler.h" 5 #include "media/audio/audio_output_resampler.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/time.h" 12 #include "base/time.h"
13 #include "media/audio/audio_io.h" 13 #include "media/audio/audio_io.h"
14 #include "media/audio/audio_output_dispatcher_impl.h" 14 #include "media/audio/audio_output_dispatcher_impl.h"
15 #include "media/audio/audio_output_proxy.h" 15 #include "media/audio/audio_output_proxy.h"
16 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
17 #include "media/audio/sample_rates.h" 17 #include "media/audio/sample_rates.h"
18 #include "media/base/audio_pull_fifo.h" 18 #include "media/base/audio_pull_fifo.h"
19 #include "media/base/limits.h" 19 #include "media/base/limits.h"
20 #include "media/base/multi_channel_resampler.h" 20 #include "media/base/multi_channel_resampler.h"
21 21
22 namespace media { 22 namespace media {
23 23
24 // Record UMA statistics for hardware output configuration.
24 static void RecordStats(const AudioParameters& output_params) { 25 static void RecordStats(const AudioParameters& output_params) {
25 UMA_HISTOGRAM_ENUMERATION( 26 UMA_HISTOGRAM_ENUMERATION(
26 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(), 27 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(),
27 limits::kMaxBitsPerSample); 28 limits::kMaxBitsPerSample);
28 UMA_HISTOGRAM_ENUMERATION( 29 UMA_HISTOGRAM_ENUMERATION(
29 "Media.HardwareAudioChannelLayout", output_params.channel_layout(), 30 "Media.HardwareAudioChannelLayout", output_params.channel_layout(),
30 CHANNEL_LAYOUT_MAX); 31 CHANNEL_LAYOUT_MAX);
31 UMA_HISTOGRAM_ENUMERATION( 32 UMA_HISTOGRAM_ENUMERATION(
32 "Media.HardwareAudioChannelCount", output_params.channels(), 33 "Media.HardwareAudioChannelCount", output_params.channels(),
33 limits::kMaxChannels); 34 limits::kMaxChannels);
34 35
35 AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate()); 36 AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
36 if (asr != kUnexpectedAudioSampleRate) { 37 if (asr != kUnexpectedAudioSampleRate) {
37 UMA_HISTOGRAM_ENUMERATION( 38 UMA_HISTOGRAM_ENUMERATION(
38 "Media.HardwareAudioSamplesPerSecond", asr, kUnexpectedAudioSampleRate); 39 "Media.HardwareAudioSamplesPerSecond", asr, kUnexpectedAudioSampleRate);
39 } else { 40 } else {
40 UMA_HISTOGRAM_COUNTS( 41 UMA_HISTOGRAM_COUNTS(
41 "Media.HardwareAudioSamplesPerSecondUnexpected", 42 "Media.HardwareAudioSamplesPerSecondUnexpected",
42 output_params.sample_rate()); 43 output_params.sample_rate());
43 } 44 }
44 } 45 }
45 46
47 // Record UMA statistics for hardware output configuration after fallback.
48 static void RecordFallbackStats(const AudioParameters& output_params) {
49 UMA_HISTOGRAM_ENUMERATION(
50 "Media.FallbackHardwareAudioBitsPerChannel",
51 output_params.bits_per_sample(), limits::kMaxBitsPerSample);
52 UMA_HISTOGRAM_ENUMERATION(
53 "Media.FallbackHardwareAudioChannelLayout",
54 output_params.channel_layout(), CHANNEL_LAYOUT_MAX);
55 UMA_HISTOGRAM_ENUMERATION(
56 "Media.FallbackHardwareAudioChannelCount",
57 output_params.channels(), limits::kMaxChannels);
Chris Rogers 2012/09/12 18:45:45 Any chance we can record the buffer-size - frames_
58
59 AudioSampleRate asr = media::AsAudioSampleRate(output_params.sample_rate());
60 if (asr != kUnexpectedAudioSampleRate) {
61 UMA_HISTOGRAM_ENUMERATION(
62 "Media.FallbackHardwareAudioSamplesPerSecond",
63 asr, kUnexpectedAudioSampleRate);
64 } else {
65 UMA_HISTOGRAM_COUNTS(
66 "Media.FallbackHardwareAudioSamplesPerSecondUnexpected",
67 output_params.sample_rate());
68 }
69 }
70
46 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager, 71 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
47 const AudioParameters& input_params, 72 const AudioParameters& input_params,
48 const AudioParameters& output_params, 73 const AudioParameters& output_params,
49 const base::TimeDelta& close_delay) 74 const base::TimeDelta& close_delay)
50 : AudioOutputDispatcher(audio_manager, input_params), 75 : AudioOutputDispatcher(audio_manager, input_params),
51 source_callback_(NULL), 76 source_callback_(NULL),
52 io_ratio_(1), 77 io_ratio_(1),
53 input_bytes_per_frame_(input_params.GetBytesPerFrame()), 78 close_delay_(close_delay),
54 output_bytes_per_frame_(output_params.GetBytesPerFrame()), 79 outstanding_audio_bytes_(0),
55 outstanding_audio_bytes_(0) { 80 output_params_(output_params) {
81 Initialize();
82 // Record UMA statistics for the hardware configuration.
83 RecordStats(output_params_);
84 }
85
86 AudioOutputResampler::~AudioOutputResampler() {}
87
88 void AudioOutputResampler::Initialize() {
89 io_ratio_ = 1;
90
56 // TODO(dalecurtis): Add channel remixing. http://crbug.com/138762 91 // TODO(dalecurtis): Add channel remixing. http://crbug.com/138762
57 DCHECK_EQ(input_params.channels(), output_params.channels()); 92 DCHECK_EQ(params_.channels(), output_params_.channels());
58 // Only resample or rebuffer if the input parameters don't match the output 93 // Only resample or rebuffer if the input parameters don't match the output
59 // parameters to avoid any unnecessary work. 94 // parameters to avoid any unnecessary work.
60 if (input_params.channels() != output_params.channels() || 95 if (params_.channels() != output_params_.channels() ||
61 input_params.sample_rate() != output_params.sample_rate() || 96 params_.sample_rate() != output_params_.sample_rate() ||
62 input_params.bits_per_sample() != output_params.bits_per_sample() || 97 params_.bits_per_sample() != output_params_.bits_per_sample() ||
63 input_params.frames_per_buffer() != output_params.frames_per_buffer()) { 98 params_.frames_per_buffer() != output_params_.frames_per_buffer()) {
64 // Only resample if necessary since it's expensive. 99 // Only resample if necessary since it's expensive.
65 if (input_params.sample_rate() != output_params.sample_rate()) { 100 if (params_.sample_rate() != output_params_.sample_rate()) {
66 DVLOG(1) << "Resampling from " << input_params.sample_rate() << " to " 101 DVLOG(1) << "Resampling from " << params_.sample_rate() << " to "
67 << output_params.sample_rate(); 102 << output_params_.sample_rate();
68 double io_sample_rate_ratio = input_params.sample_rate() / 103 double io_sample_rate_ratio = params_.sample_rate() /
69 static_cast<double>(output_params.sample_rate()); 104 static_cast<double>(output_params_.sample_rate());
70 // Include the I/O resampling ratio in our global I/O ratio. 105 // Include the I/O resampling ratio in our global I/O ratio.
71 io_ratio_ *= io_sample_rate_ratio; 106 io_ratio_ *= io_sample_rate_ratio;
72 resampler_.reset(new MultiChannelResampler( 107 resampler_.reset(new MultiChannelResampler(
73 output_params.channels(), io_sample_rate_ratio, base::Bind( 108 output_params_.channels(), io_sample_rate_ratio, base::Bind(
74 &AudioOutputResampler::ProvideInput, base::Unretained(this)))); 109 &AudioOutputResampler::ProvideInput, base::Unretained(this))));
75 } 110 }
76 111
77 // Include bits per channel differences. 112 // Include bits per channel differences.
78 io_ratio_ *= static_cast<double>(input_params.bits_per_sample()) / 113 io_ratio_ *= static_cast<double>(params_.bits_per_sample()) /
79 output_params.bits_per_sample(); 114 output_params_.bits_per_sample();
80 115
81 // Include channel count differences. 116 // Include channel count differences.
82 io_ratio_ *= static_cast<double>(input_params.channels()) / 117 io_ratio_ *= static_cast<double>(params_.channels()) /
83 output_params.channels(); 118 output_params_.channels();
84 119
85 // Since the resampler / output device may want a different buffer size than 120 // Since the resampler / output device may want a different buffer size than
86 // the caller asked for, we need to use a FIFO to ensure that both sides 121 // the caller asked for, we need to use a FIFO to ensure that both sides
87 // read in chunk sizes they're configured for. 122 // read in chunk sizes they're configured for.
88 if (input_params.sample_rate() != output_params.sample_rate() || 123 if (params_.sample_rate() != output_params_.sample_rate() ||
89 input_params.frames_per_buffer() != output_params.frames_per_buffer()) { 124 params_.frames_per_buffer() != output_params_.frames_per_buffer()) {
90 DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer() 125 DVLOG(1) << "Rebuffering from " << params_.frames_per_buffer()
91 << " to " << output_params.frames_per_buffer(); 126 << " to " << output_params_.frames_per_buffer();
92 audio_fifo_.reset(new AudioPullFifo( 127 audio_fifo_.reset(new AudioPullFifo(
93 input_params.channels(), input_params.frames_per_buffer(), base::Bind( 128 params_.channels(), params_.frames_per_buffer(), base::Bind(
94 &AudioOutputResampler::SourceCallback_Locked, 129 &AudioOutputResampler::SourceCallback_Locked,
95 base::Unretained(this)))); 130 base::Unretained(this))));
96 } 131 }
97 132
98 DVLOG(1) << "I/O ratio is " << io_ratio_; 133 DVLOG(1) << "I/O ratio is " << io_ratio_;
99 } 134 }
100 135
101 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once 136 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once
102 // we've stabilized the issues there. 137 // we've stabilized the issues there.
103 dispatcher_ = new AudioOutputDispatcherImpl( 138 dispatcher_ = new AudioOutputDispatcherImpl(
104 audio_manager, output_params, close_delay); 139 audio_manager_, output_params_, close_delay_);
105
106 // Record UMA statistics for the hardware configuration.
107 RecordStats(output_params);
108 } 140 }
109 141
110 AudioOutputResampler::~AudioOutputResampler() {} 142 bool AudioOutputResampler::OpenStream() {
143 if (dispatcher_->OpenStream()) {
144 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", false);
145 return true;
146 }
111 147
112 bool AudioOutputResampler::OpenStream() { 148 // If we've already tried to open the stream in high latency mode, there's
113 // TODO(dalecurtis): Automatically revert to high latency path if OpenStream() 149 // nothing more to be done.
114 // fails; use default high latency output values + rebuffering / resampling. 150 if (output_params_.format() == AudioParameters::AUDIO_PCM_LINEAR)
151 return false;
152
153 DLOG(ERROR) << "Unable to open audio device in low latency mode. Falling "
154 << "back to high latency audio output.";
155
156 // Record UMA statistics about the hardware which triggered the failure so we
157 // can debug and triage later.
158 UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", true);
159 RecordFallbackStats(output_params_);
160
161 // Open failed! Attempt to open the output device in high latency mode using
162 // a new high latency appropriate buffer size. |kMinLowLatencyFrameSize| is
163 // arbitrarily based on Pepper Flash's MAXIMUM frame size for low latency.
164 static const int kMinLowLatencyFrameSize = 2048;
165 int frames_per_buffer = std::max(
166 std::min(params_.frames_per_buffer(), kMinLowLatencyFrameSize),
167 static_cast<int>(GetHighLatencyOutputBufferSize(params_.sample_rate())));
168
169 output_params_ = AudioParameters(
170 AudioParameters::AUDIO_PCM_LINEAR, params_.channel_layout(),
171 params_.sample_rate(), params_.bits_per_sample(), frames_per_buffer);
172 Initialize();
173
174 // Retry, if this fails, there's nothing left to do but report the error back.
115 return dispatcher_->OpenStream(); 175 return dispatcher_->OpenStream();
116 } 176 }
117 177
118 bool AudioOutputResampler::StartStream( 178 bool AudioOutputResampler::StartStream(
119 AudioOutputStream::AudioSourceCallback* callback, 179 AudioOutputStream::AudioSourceCallback* callback,
120 AudioOutputProxy* stream_proxy) { 180 AudioOutputProxy* stream_proxy) {
121 { 181 {
122 base::AutoLock auto_lock(source_lock_); 182 base::AutoLock auto_lock(source_lock_);
123 source_callback_ = callback; 183 source_callback_ = callback;
124 } 184 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 SourceCallback_Locked(dest); 238 SourceCallback_Locked(dest);
179 return dest->frames(); 239 return dest->frames();
180 } 240 }
181 241
182 if (resampler_.get()) 242 if (resampler_.get())
183 resampler_->Resample(dest, dest->frames()); 243 resampler_->Resample(dest, dest->frames());
184 else 244 else
185 ProvideInput(dest); 245 ProvideInput(dest);
186 246
187 // Calculate how much data is left in the internal FIFO and resampler buffers. 247 // Calculate how much data is left in the internal FIFO and resampler buffers.
188 outstanding_audio_bytes_ -= dest->frames() * output_bytes_per_frame_; 248 outstanding_audio_bytes_ -=
249 dest->frames() * output_params_.GetBytesPerFrame();
250
189 // Due to rounding errors while multiplying against |io_ratio_|, 251 // Due to rounding errors while multiplying against |io_ratio_|,
190 // |outstanding_audio_bytes_| might (rarely) slip below zero. 252 // |outstanding_audio_bytes_| might (rarely) slip below zero.
191 if (outstanding_audio_bytes_ < 0) { 253 if (outstanding_audio_bytes_ < 0) {
192 DLOG(ERROR) << "Outstanding audio bytes went negative! Value: " 254 DLOG(ERROR) << "Outstanding audio bytes went negative! Value: "
193 << outstanding_audio_bytes_; 255 << outstanding_audio_bytes_;
194 outstanding_audio_bytes_ = 0; 256 outstanding_audio_bytes_ = 0;
195 } 257 }
196 258
197 // Always return the full number of frames requested, ProvideInput() will pad 259 // Always return the full number of frames requested, ProvideInput() will pad
198 // with silence if it wasn't able to acquire enough data. 260 // with silence if it wasn't able to acquire enough data.
(...skipping 11 matching lines...) Expand all
210 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_); 272 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_);
211 273
212 // Retrieve data from the original callback. Zero any unfilled frames. 274 // Retrieve data from the original callback. Zero any unfilled frames.
213 int frames = source_callback_->OnMoreData(audio_bus, new_buffers_state); 275 int frames = source_callback_->OnMoreData(audio_bus, new_buffers_state);
214 if (frames < audio_bus->frames()) 276 if (frames < audio_bus->frames())
215 audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames); 277 audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames);
216 278
217 // Scale the number of frames we got back in terms of input bytes to output 279 // Scale the number of frames we got back in terms of input bytes to output
218 // bytes accordingly. 280 // bytes accordingly.
219 outstanding_audio_bytes_ += 281 outstanding_audio_bytes_ +=
220 (audio_bus->frames() * input_bytes_per_frame_) / io_ratio_; 282 (audio_bus->frames() * params_.GetBytesPerFrame()) / io_ratio_;
221 } 283 }
222 284
223 void AudioOutputResampler::ProvideInput(AudioBus* audio_bus) { 285 void AudioOutputResampler::ProvideInput(AudioBus* audio_bus) {
224 audio_fifo_->Consume(audio_bus, audio_bus->frames()); 286 audio_fifo_->Consume(audio_bus, audio_bus->frames());
225 } 287 }
226 288
227 void AudioOutputResampler::OnError(AudioOutputStream* stream, int code) { 289 void AudioOutputResampler::OnError(AudioOutputStream* stream, int code) {
228 base::AutoLock auto_lock(source_lock_); 290 base::AutoLock auto_lock(source_lock_);
229 if (source_callback_) 291 if (source_callback_)
230 source_callback_->OnError(stream, code); 292 source_callback_->OnError(stream, code);
231 } 293 }
232 294
233 void AudioOutputResampler::WaitTillDataReady() { 295 void AudioOutputResampler::WaitTillDataReady() {
234 base::AutoLock auto_lock(source_lock_); 296 base::AutoLock auto_lock(source_lock_);
235 if (source_callback_ && !outstanding_audio_bytes_) 297 if (source_callback_ && !outstanding_audio_bytes_)
236 source_callback_->WaitTillDataReady(); 298 source_callback_->WaitTillDataReady();
237 } 299 }
238 300
239 } // namespace media 301 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_resampler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698