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

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

Issue 10918098: Introduce AudioOutputResampler for browser side resampling. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
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') | media/base/media_switches.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/message_loop.h"
11 #include "base/time.h"
12 #include "media/audio/audio_io.h"
13 #include "media/audio/audio_output_dispatcher_impl.h"
14 #include "media/audio/audio_output_proxy.h"
15 #include "media/audio/audio_util.h"
16 #include "media/base/audio_pull_fifo.h"
17 #include "media/base/multi_channel_resampler.h"
18
19 namespace media {
20
21 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
22 const AudioParameters& input_params,
23 const AudioParameters& output_params,
24 const base::TimeDelta& close_delay)
25 : AudioOutputDispatcher(audio_manager, input_params),
26 source_callback_(NULL),
27 io_ratio_(1),
28 input_bytes_per_frame_(input_params.GetBytesPerFrame()),
29 output_bytes_per_frame_(output_params.GetBytesPerFrame()),
30 outstanding_audio_bytes_(0) {
31 // TODO(dalecurtis): Add channel remixing. http://crbug.com/138762
32 DCHECK_EQ(input_params.channels(), output_params.channels());
33 // Only resample or rebuffer if the input parameters don't match the output
34 // parameters to avoid any unnecessary work.
35 if (input_params.channels() != output_params.channels() ||
36 input_params.sample_rate() != output_params.sample_rate() ||
37 input_params.bits_per_sample() != output_params.bits_per_sample() ||
38 input_params.frames_per_buffer() != output_params.frames_per_buffer()) {
39 // Only resample if necessary since it's expensive.
40 if (input_params.sample_rate() != output_params.sample_rate()) {
41 double io_sample_rate_ratio = input_params.sample_rate() /
42 static_cast<double>(output_params.sample_rate());
43 // Include the I/O resampling ratio in our global I/O ratio.
44 io_ratio_ *= io_sample_rate_ratio;
45 resampler_.reset(new MultiChannelResampler(
46 output_params.channels(), io_sample_rate_ratio, base::Bind(
47 &AudioOutputResampler::ProvideInput, base::Unretained(this))));
48 }
49
50 // Include bits per channel differences.
51 io_ratio_ *= static_cast<double>(input_params.bits_per_sample()) /
52 output_params.bits_per_sample();
53
54 // Include channel count differences.
55 io_ratio_ *= static_cast<double>(input_params.channels()) /
56 output_params.channels();
57
58 // Since the resampler / output device may want a different buffer size than
59 // the caller asked for, we need to use a FIFO to ensure that both sides
60 // read in chunk sizes they're configured for.
61 if (input_params.sample_rate() != output_params.sample_rate() ||
62 input_params.frames_per_buffer() != output_params.frames_per_buffer()) {
63 audio_fifo_.reset(new AudioPullFifo(
64 input_params.channels(), input_params.frames_per_buffer(), base::Bind(
65 &AudioOutputResampler::SourceCallback, base::Unretained(this))));
66 }
67 }
68
69 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once
70 // we've stabilized the issues there.
71 dispatcher_ = new AudioOutputDispatcherImpl(
72 audio_manager, output_params, close_delay);
73 }
74
75 AudioOutputResampler::~AudioOutputResampler() {}
76
77 bool AudioOutputResampler::OpenStream() {
78 // TODO(dalecurtis): Automatically revert to high latency path if OpenStream()
79 // fails; use default high latency output values + rebuffering / resampling.
80 return dispatcher_->OpenStream();
81 }
82
83 bool AudioOutputResampler::StartStream(
84 AudioOutputStream::AudioSourceCallback* callback,
85 AudioOutputProxy* stream_proxy) {
86 {
87 base::AutoLock auto_lock(source_lock_);
88 source_callback_ = callback;
89 }
90 return dispatcher_->StartStream(this, stream_proxy);
91 }
92
93 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
94 double volume) {
95 dispatcher_->StreamVolumeSet(stream_proxy, volume);
96 }
97
98 void AudioOutputResampler::Reset() {
99 base::AutoLock auto_lock(source_lock_);
100 source_callback_ = NULL;
101 outstanding_audio_bytes_ = 0;
102 if (audio_fifo_.get())
103 audio_fifo_->Clear();
104 if (resampler_.get())
105 resampler_->Flush();
106 }
107
108 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
109 Reset();
110 dispatcher_->StopStream(stream_proxy);
111 }
112
113 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
114 Reset();
115 dispatcher_->CloseStream(stream_proxy);
116 }
117
118 void AudioOutputResampler::Shutdown() {
119 Reset();
120 dispatcher_->Shutdown();
121 }
122
123 int AudioOutputResampler::OnMoreData(AudioBus* audio_bus,
124 AudioBuffersState buffers_state) {
125 current_buffers_state_ = buffers_state;
126
127 if (!resampler_.get() && !audio_fifo_.get()) {
128 // We have no internal buffers, so clear any outstanding audio data.
129 outstanding_audio_bytes_ = 0;
130 SourceCallback(audio_bus);
131 return audio_bus->frames();
132 }
133
134 if (resampler_.get())
135 resampler_->Resample(audio_bus, audio_bus->frames());
136 else
137 ProvideInput(audio_bus);
138
139 // Calculate how much data is left in the internal FIFO and resampler buffers.
140 outstanding_audio_bytes_ -= audio_bus->frames() * output_bytes_per_frame_;
141 // Due to rounding errors while multiplying against |io_ratio_|,
142 // |outstanding_audio_bytes_| might (rarely) slip below zero.
143 if (outstanding_audio_bytes_ < 0) {
144 DLOG(ERROR) << "Outstanding audio bytes went negative! Value: "
145 << outstanding_audio_bytes_;
146 outstanding_audio_bytes_ = 0;
147 }
148
149 // Always return the full number of frames requested, ProvideInput() will pad
150 // with silence if it wasn't able to acquire enough data.
151 return audio_bus->frames();
152 }
153
154 void AudioOutputResampler::SourceCallback(AudioBus* audio_bus) {
155 base::AutoLock auto_lock(source_lock_);
156 // While we waited for |source_lock_| it might have been cleared.
157 if (!source_callback_) {
158 audio_bus->Zero();
159 return;
160 }
161
162 // Adjust playback delay to include the state of the internal buffers used by
163 // the resampler and/or the FIFO. Since the sample rate and bits per channel
164 // may be different, we need to scale this value appropriately.
165 AudioBuffersState new_buffers_state;
166 new_buffers_state.pending_bytes = io_ratio_ *
167 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_);
168
169 // Retrieve data from the original callback. Zero any unfilled frames.
170 int frames = source_callback_->OnMoreData(audio_bus, new_buffers_state);
171 if (frames < audio_bus->frames())
172 audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames);
173
174 // Scale the number of frames we got back in terms of input bytes to output
175 // bytes accordingly.
176 outstanding_audio_bytes_ +=
177 (audio_bus->frames() * input_bytes_per_frame_) / io_ratio_;
178 }
179
180 void AudioOutputResampler::ProvideInput(AudioBus* audio_bus) {
181 audio_fifo_->Consume(audio_bus, audio_bus->frames());
182 }
183
184 void AudioOutputResampler::OnError(AudioOutputStream* stream, int code) {
185 base::AutoLock auto_lock(source_lock_);
186 if (source_callback_)
187 source_callback_->OnError(stream, code);
188 }
189
190 void AudioOutputResampler::WaitTillDataReady() {
191 base::AutoLock auto_lock(source_lock_);
192 if (source_callback_ && !outstanding_audio_bytes_)
193 source_callback_->WaitTillDataReady();
194 }
195
196 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_resampler.h ('k') | media/base/media_switches.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698