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

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: First draft! 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
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/stringprintf.h"
10 #include "base/compiler_specific.h"
scherkus (not reviewing) 2012/09/07 13:30:16 a->z ordering
DaleCurtis 2012/09/10 12:06:24 Removed.
11 #include "base/message_loop.h"
12 #include "base/time.h"
13 #include "media/audio/audio_io.h"
14 #include "media/audio/audio_output_dispatcher_impl.h"
15 #include "media/audio/audio_output_proxy.h"
16 #include "media/audio/audio_util.h"
17 #include "media/base/audio_fifo.h"
18 #include "media/base/multi_channel_resampler.h"
19
20
21 namespace media {
22
23 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
24 const AudioParameters& input_params,
25 const base::TimeDelta& close_delay)
26 : AudioOutputDispatcher(audio_manager, input_params),
27 source_callback_(NULL),
28 outstanding_audio_bytes_(0),
29 io_ratio_(0),
30 output_bytes_per_frame_(0),
31 input_bytes_per_frame_(0) {
32 AudioParameters output_params = input_params;
33 int hardware_sample_rate = GetAudioHardwareSampleRate();
34 int hardware_buffer_size = GetAudioHardwareBufferSize();
35
36 // Only resample if necessary since it's expensive.
37 // TODO(dalecurtis): Restrict to PCM low latency before landing. Right now it
38 // converts all non-low latency calls as well for testing.
39 if (input_params.sample_rate() != hardware_sample_rate ||
40 input_params.frames_per_buffer() != hardware_buffer_size) {
41 // Create output parameters based on the audio hardware configuration.
42 // TODO(dalecurtis): This should include channel count and bit depth.
43 output_params = AudioParameters(
44 AudioParameters::AUDIO_PCM_LOW_LATENCY, input_params.channel_layout(),
45 hardware_sample_rate, 16, GetAudioHardwareBufferSize());
46 input_bytes_per_frame_ = input_params.GetBytesPerFrame();
47 output_bytes_per_frame_ = output_params.GetBytesPerFrame();
48
49 // Calculate the first part of the I/O ratio for the resampler.
50 io_ratio_ =
51 input_params.sample_rate() / static_cast<double>(hardware_sample_rate);
52 resampler_.reset(new MultiChannelResampler(
53 output_params.channels(),
54 io_ratio_,
55 base::Bind(
56 &AudioOutputResampler::ProvideInput, base::Unretained(this))));
57
58 // Include the difference in output bits per sample.
59 io_ratio_ *= static_cast<double>(input_params.bits_per_sample()) /
60 output_params.bits_per_sample();
61
62 // TODO(dalecurtis): Initialize AudioPullFIFO(input_params.buffer_frames()).
63 temp_bus_ = AudioBus::Create(input_params);
64 audio_fifo_.reset(new AudioFifo(
Chris Rogers 2012/09/06 19:18:25 Even if we're not doing sample-rate conversion, we
DaleCurtis 2012/09/07 14:17:35 Good point, I'll rework it so buffer size differen
DaleCurtis 2012/09/10 12:06:24 Done.
65 input_params.channels(), input_params.frames_per_buffer()));
66 }
67
68 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once
69 // we've stabilized the issues there.
70 dispatcher_ = new AudioOutputDispatcherImpl(
71 audio_manager, output_params, close_delay);
72 }
73
74 AudioOutputResampler::~AudioOutputResampler() {}
75
76 bool AudioOutputResampler::OpenStream() {
77 return dispatcher_->OpenStream();
78 }
79
80 bool AudioOutputResampler::StartStream(
81 AudioOutputStream::AudioSourceCallback* callback,
82 AudioOutputProxy* stream_proxy) {
83 {
84 base::AutoLock auto_lock(source_lock_);
85 source_callback_ = callback;
86 }
87 return dispatcher_->StartStream(this, stream_proxy);
scherkus (not reviewing) 2012/09/07 13:30:16 which thread is calling these methods? is dispatc
DaleCurtis 2012/09/07 14:17:35 Called by the audio thread, AudioOutputDispatcherI
88 }
89
90 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
91 {
92 base::AutoLock auto_lock(source_lock_);
93 source_callback_ = NULL;
94 outstanding_audio_bytes_ = 0;
95 audio_fifo_->Clear();
96 resampler_->Flush();
97 }
98 dispatcher_->StopStream(stream_proxy);
99 }
100
101 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy,
102 double volume) {
103 dispatcher_->StreamVolumeSet(stream_proxy, volume);
104 }
105
106 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) {
107 {
108 base::AutoLock auto_lock(source_lock_);
109 source_callback_ = NULL;
110 outstanding_audio_bytes_ = 0;
111 audio_fifo_->Clear();
112 resampler_->Flush();
113 }
114 dispatcher_->CloseStream(stream_proxy);
115 }
116
117 void AudioOutputResampler::Shutdown() {
118 {
119 base::AutoLock auto_lock(source_lock_);
120 source_callback_ = NULL;
121 outstanding_audio_bytes_ = 0;
122 audio_fifo_->Clear();
123 resampler_->Flush();
124 }
125 dispatcher_->Shutdown();
126 }
127
128 int AudioOutputResampler::OnMoreData(AudioBus* audio_bus,
129 AudioBuffersState buffers_state) {
130 if (!resampler_.get()) {
131 // TODO(dalecurtis): Copy ASB to local variable, release lock prior to call?
scherkus (not reviewing) 2012/09/07 13:30:16 what's ASB?
DaleCurtis 2012/09/07 14:17:35 A typo :) Should be ASCB.. Essentially instead of
132 base::AutoLock auto_lock(source_lock_);
133 return source_callback_->OnMoreData(audio_bus, buffers_state);
Chris Rogers 2012/09/06 19:18:25 We need to have a conditional here to check if we
DaleCurtis 2012/09/07 14:17:35 Will investigate, shouldn't be too hard.
DaleCurtis 2012/09/10 12:06:24 Done.
134 }
135
136 current_buffers_state_ = buffers_state;
137 resampler_->Resample(audio_bus, audio_bus->frames());
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 CHECK_GE(outstanding_audio_bytes_, 0);
142
143 // Always return the full number of frames requested, ProvideInput() will pad
144 // with silence if it wasn't able to acquire enough data.
145 // NOTE: This will not work with the current non-low latency <audio> pipeline.
146 return audio_bus->frames();
147 }
148
149 void AudioOutputResampler::ProvideInput(AudioBus* audio_bus) {
150 // TODO(dalecurtis): Copy ASB to local variable, release lock prior to call?
151 base::AutoLock auto_lock(source_lock_);
152 // We may have waited for |source_lock_| while a call cleared the callback.
153 if (!source_callback_)
154 return;
155
156 // Serve frames out of the FIFO if they're available.
157 int frames_to_write = audio_bus->frames();
158 if (audio_fifo_->frames_in_fifo() > 0) {
159 int frames = std::min(audio_bus->frames(), audio_fifo_->frames_in_fifo());
160 CHECK(audio_fifo_->Consume(audio_bus, 0, frames));
scherkus (not reviewing) 2012/09/07 13:30:17 :)
161 frames_to_write -= frames;
162 }
163
164 // If we were able to fulfill the request from the FIFO, we're done.
165 if (frames_to_write == 0)
166 return;
167
168 // Adjust playback delay to include the state of the internal buffers used by
169 // the resampler and the FIFO. Since the sample rate and bits per channel
170 // may be different, we need to scale this value appropriately
171 // TODO(dalecurtis): Move to the FIFO side callback once the FIFO is added.
172 AudioBuffersState new_buffers_state;
173 new_buffers_state.pending_bytes = io_ratio_ *
174 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_);
175
176 // Retrieve data from the original callback.
177 int frames = source_callback_->OnMoreData(temp_bus_.get(), new_buffers_state);
178
179 // TODO(dalecurtis): Technically only <audio> returns fewer frames than
180 // requested and it won't use this path... but since I tested with <audio> on
181 // the high latency path it was necessary. Remove later.
182
183 // Scale the number of frames we got back in terms of input bytes to output
184 // bytes accordingly.
185 outstanding_audio_bytes_ += (frames * input_bytes_per_frame_) / io_ratio_;
186
187 // Put everything into the FIFO and fulfill the rest of the request.
188 CHECK(audio_fifo_->Push(temp_bus_.get(), frames));
189 CHECK(audio_fifo_->Consume(
190 audio_bus, audio_bus->frames() - frames_to_write, frames_to_write));
191 }
192
193 void AudioOutputResampler::OnError(AudioOutputStream* stream, int code) {
194 // TODO(dalecurtis): Copy ASB to local variable, release lock prior to call?
195 base::AutoLock auto_lock(source_lock_);
196 if (source_callback_)
197 source_callback_->OnError(stream, code);
198 }
199
200 void AudioOutputResampler::WaitTillDataReady() {
201 // TODO(dalecurtis): Copy ASB to local variable, release lock prior to call?
202 base::AutoLock auto_lock(source_lock_);
203 if (source_callback_ && !outstanding_audio_bytes_)
204 source_callback_->WaitTillDataReady();
205 }
206
207 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698