Files.app: Remove wait for startup animation.
[chromium-blink-merge.git] / media / audio / pulse / pulse_input.cc
blob3d3c770ddaf88b814dd1b898a17fbb2e884be834
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/pulse/pulse_input.h"
7 #include "base/logging.h"
8 #include "media/audio/pulse/audio_manager_pulse.h"
9 #include "media/audio/pulse/pulse_util.h"
11 namespace media {
13 using pulse::AutoPulseLock;
14 using pulse::WaitForOperationCompletion;
16 // Number of blocks of buffers used in the |fifo_|.
17 const int kNumberOfBlocksBufferInFifo = 2;
19 PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager,
20 const std::string& device_name,
21 const AudioParameters& params,
22 pa_threaded_mainloop* mainloop,
23 pa_context* context)
24 : audio_manager_(audio_manager),
25 callback_(NULL),
26 device_name_(device_name),
27 params_(params),
28 channels_(0),
29 volume_(0.0),
30 stream_started_(false),
31 muted_(false),
32 fifo_(params.channels(),
33 params.frames_per_buffer(),
34 kNumberOfBlocksBufferInFifo),
35 pa_mainloop_(mainloop),
36 pa_context_(context),
37 handle_(NULL) {
38 DCHECK(mainloop);
39 DCHECK(context);
40 CHECK(params_.IsValid());
43 PulseAudioInputStream::~PulseAudioInputStream() {
44 // All internal structures should already have been freed in Close(),
45 // which calls AudioManagerPulse::Release which deletes this object.
46 DCHECK(!handle_);
49 bool PulseAudioInputStream::Open() {
50 DCHECK(thread_checker_.CalledOnValidThread());
51 AutoPulseLock auto_lock(pa_mainloop_);
52 if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &handle_, params_,
53 device_name_, &StreamNotifyCallback, this)) {
54 return false;
57 DCHECK(handle_);
59 return true;
62 void PulseAudioInputStream::Start(AudioInputCallback* callback) {
63 DCHECK(thread_checker_.CalledOnValidThread());
64 DCHECK(callback);
65 DCHECK(handle_);
67 // AGC needs to be started out of the lock.
68 StartAgc();
70 AutoPulseLock auto_lock(pa_mainloop_);
72 if (stream_started_)
73 return;
75 // Start the streaming.
76 callback_ = callback;
77 pa_stream_set_read_callback(handle_, &ReadCallback, this);
78 pa_stream_readable_size(handle_);
79 stream_started_ = true;
81 pa_operation* operation =
82 pa_stream_cork(handle_, 0, &pulse::StreamSuccessCallback, pa_mainloop_);
83 WaitForOperationCompletion(pa_mainloop_, operation);
86 void PulseAudioInputStream::Stop() {
87 DCHECK(thread_checker_.CalledOnValidThread());
88 AutoPulseLock auto_lock(pa_mainloop_);
89 if (!stream_started_)
90 return;
92 StopAgc();
94 // Set the flag to false to stop filling new data to soundcard.
95 stream_started_ = false;
97 // Clean up the old buffer.
98 pa_stream_drop(handle_);
99 fifo_.Clear();
101 pa_operation* operation = pa_stream_flush(handle_,
102 &pulse::StreamSuccessCallback,
103 pa_mainloop_);
104 WaitForOperationCompletion(pa_mainloop_, operation);
106 // Stop the stream.
107 pa_stream_set_read_callback(handle_, NULL, NULL);
108 operation = pa_stream_cork(handle_, 1, &pulse::StreamSuccessCallback,
109 pa_mainloop_);
110 WaitForOperationCompletion(pa_mainloop_, operation);
111 callback_ = NULL;
114 void PulseAudioInputStream::Close() {
115 DCHECK(thread_checker_.CalledOnValidThread());
117 AutoPulseLock auto_lock(pa_mainloop_);
118 if (handle_) {
119 // Disable all the callbacks before disconnecting.
120 pa_stream_set_state_callback(handle_, NULL, NULL);
121 pa_operation* operation = pa_stream_flush(
122 handle_, &pulse::StreamSuccessCallback, pa_mainloop_);
123 WaitForOperationCompletion(pa_mainloop_, operation);
125 if (pa_stream_get_state(handle_) != PA_STREAM_UNCONNECTED)
126 pa_stream_disconnect(handle_);
128 // Release PulseAudio structures.
129 pa_stream_unref(handle_);
130 handle_ = NULL;
134 // Signal to the manager that we're closed and can be removed.
135 // This should be the last call in the function as it deletes "this".
136 audio_manager_->ReleaseInputStream(this);
139 double PulseAudioInputStream::GetMaxVolume() {
140 return static_cast<double>(PA_VOLUME_NORM);
143 void PulseAudioInputStream::SetVolume(double volume) {
144 AutoPulseLock auto_lock(pa_mainloop_);
145 if (!handle_)
146 return;
148 size_t index = pa_stream_get_device_index(handle_);
149 pa_operation* operation = NULL;
150 if (!channels_) {
151 // Get the number of channels for the source only when the |channels_| is 0.
152 // We are assuming the stream source is not changed on the fly here.
153 operation = pa_context_get_source_info_by_index(
154 pa_context_, index, &VolumeCallback, this);
155 WaitForOperationCompletion(pa_mainloop_, operation);
156 if (!channels_) {
157 DLOG(WARNING) << "Failed to get the number of channels for the source";
158 return;
162 pa_cvolume pa_volume;
163 pa_cvolume_set(&pa_volume, channels_, volume);
164 operation = pa_context_set_source_volume_by_index(
165 pa_context_, index, &pa_volume, NULL, NULL);
167 // Don't need to wait for this task to complete.
168 pa_operation_unref(operation);
171 double PulseAudioInputStream::GetVolume() {
172 if (pa_threaded_mainloop_in_thread(pa_mainloop_)) {
173 // When being called by the pulse thread, GetVolume() is asynchronous and
174 // called under AutoPulseLock.
175 if (!handle_)
176 return 0.0;
178 size_t index = pa_stream_get_device_index(handle_);
179 pa_operation* operation = pa_context_get_source_info_by_index(
180 pa_context_, index, &VolumeCallback, this);
181 // Do not wait for the operation since we can't block the pulse thread.
182 pa_operation_unref(operation);
184 // Return zero and the callback will asynchronously update the |volume_|.
185 return 0.0;
186 } else {
187 GetSourceInformation(&VolumeCallback);
188 return volume_;
192 bool PulseAudioInputStream::IsMuted() {
193 DCHECK(thread_checker_.CalledOnValidThread());
194 GetSourceInformation(&MuteCallback);
195 return muted_;
198 // static, used by pa_stream_set_read_callback.
199 void PulseAudioInputStream::ReadCallback(pa_stream* handle,
200 size_t length,
201 void* user_data) {
202 PulseAudioInputStream* stream =
203 reinterpret_cast<PulseAudioInputStream*>(user_data);
205 stream->ReadData();
208 // static, used by pa_context_get_source_info_by_index.
209 void PulseAudioInputStream::VolumeCallback(pa_context* context,
210 const pa_source_info* info,
211 int error, void* user_data) {
212 PulseAudioInputStream* stream =
213 reinterpret_cast<PulseAudioInputStream*>(user_data);
215 if (error) {
216 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
217 return;
220 if (stream->channels_ != info->channel_map.channels)
221 stream->channels_ = info->channel_map.channels;
223 pa_volume_t volume = PA_VOLUME_MUTED; // Minimum possible value.
224 // Use the max volume of any channel as the volume.
225 for (int i = 0; i < stream->channels_; ++i) {
226 if (volume < info->volume.values[i])
227 volume = info->volume.values[i];
230 // It is safe to access |volume_| here since VolumeCallback() is running
231 // under PulseLock.
232 stream->volume_ = static_cast<double>(volume);
235 // static, used by pa_context_get_source_info_by_index.
236 void PulseAudioInputStream::MuteCallback(pa_context* context,
237 const pa_source_info* info,
238 int error,
239 void* user_data) {
240 // Runs on PulseAudio callback thread. It might be possible to make this
241 // method more thread safe by passing a struct (or pair) of a local copy of
242 // |pa_mainloop_| and |muted_| instead.
243 PulseAudioInputStream* stream =
244 reinterpret_cast<PulseAudioInputStream*>(user_data);
246 // Avoid infinite wait loop in case of error.
247 if (error) {
248 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
249 return;
252 stream->muted_ = info->mute != 0;
255 // static, used by pa_stream_set_state_callback.
256 void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s,
257 void* user_data) {
258 PulseAudioInputStream* stream =
259 reinterpret_cast<PulseAudioInputStream*>(user_data);
261 if (s && stream->callback_ &&
262 pa_stream_get_state(s) == PA_STREAM_FAILED) {
263 stream->callback_->OnError(stream);
266 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
269 void PulseAudioInputStream::ReadData() {
270 uint32 hardware_delay = pulse::GetHardwareLatencyInBytes(
271 handle_, params_.sample_rate(), params_.GetBytesPerFrame());
273 // Update the AGC volume level once every second. Note that,
274 // |volume| is also updated each time SetVolume() is called
275 // through IPC by the render-side AGC.
276 // We disregard the |normalized_volume| from GetAgcVolume()
277 // and use the value calculated by |volume_|.
278 double normalized_volume = 0.0;
279 GetAgcVolume(&normalized_volume);
280 normalized_volume = volume_ / GetMaxVolume();
282 do {
283 size_t length = 0;
284 const void* data = NULL;
285 pa_stream_peek(handle_, &data, &length);
286 if (!data || length == 0)
287 break;
289 const int number_of_frames = length / params_.GetBytesPerFrame();
290 if (number_of_frames > fifo_.GetUnfilledFrames()) {
291 // Dynamically increase capacity to the FIFO to handle larger buffer got
292 // from Pulse.
293 const int increase_blocks_of_buffer = static_cast<int>(
294 (number_of_frames - fifo_.GetUnfilledFrames()) /
295 params_.frames_per_buffer()) + 1;
296 fifo_.IncreaseCapacity(increase_blocks_of_buffer);
299 fifo_.Push(data, number_of_frames, params_.bits_per_sample() / 8);
301 // Checks if we still have data.
302 pa_stream_drop(handle_);
303 } while (pa_stream_readable_size(handle_) > 0);
305 while (fifo_.available_blocks()) {
306 const AudioBus* audio_bus = fifo_.Consume();
308 // Compensate the audio delay caused by the FIFO.
309 hardware_delay += fifo_.GetAvailableFrames() * params_.GetBytesPerFrame();
310 callback_->OnData(this, audio_bus, hardware_delay, normalized_volume);
312 // Sleep 5ms to wait until render consumes the data in order to avoid
313 // back to back OnData() method.
314 if (fifo_.available_blocks())
315 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
318 pa_threaded_mainloop_signal(pa_mainloop_, 0);
321 bool PulseAudioInputStream::GetSourceInformation(pa_source_info_cb_t callback) {
322 AutoPulseLock auto_lock(pa_mainloop_);
323 if (!handle_)
324 return false;
326 size_t index = pa_stream_get_device_index(handle_);
327 pa_operation* operation =
328 pa_context_get_source_info_by_index(pa_context_, index, callback, this);
329 WaitForOperationCompletion(pa_mainloop_, operation);
330 return true;
333 } // namespace media