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 <pulse/pulseaudio.h>
9 #include "base/logging.h"
10 #include "media/audio/pulse/audio_manager_pulse.h"
11 #include "media/audio/pulse/pulse_util.h"
15 using pulse::AutoPulseLock;
16 using pulse::WaitForOperationCompletion;
18 // Number of blocks of buffers used in the |fifo_|.
19 const int kNumberOfBlocksBufferInFifo = 2;
21 PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager,
22 const std::string& device_name,
23 const AudioParameters& params,
24 pa_threaded_mainloop* mainloop,
26 : audio_manager_(audio_manager),
28 device_name_(device_name),
32 stream_started_(false),
33 fifo_(params.channels(),
34 params.frames_per_buffer(),
35 kNumberOfBlocksBufferInFifo),
36 pa_mainloop_(mainloop),
39 context_state_changed_(false) {
42 CHECK(params_.IsValid());
45 PulseAudioInputStream::~PulseAudioInputStream() {
46 // All internal structures should already have been freed in Close(),
47 // which calls AudioManagerPulse::Release which deletes this object.
51 bool PulseAudioInputStream::Open() {
52 DCHECK(thread_checker_.CalledOnValidThread());
53 AutoPulseLock auto_lock(pa_mainloop_);
54 if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &handle_, params_,
55 device_name_, &StreamNotifyCallback, this)) {
64 void PulseAudioInputStream::Start(AudioInputCallback* callback) {
65 DCHECK(thread_checker_.CalledOnValidThread());
69 // AGC needs to be started out of the lock.
72 AutoPulseLock auto_lock(pa_mainloop_);
77 // Clean up the old buffer.
78 pa_stream_drop(handle_);
81 // Start the streaming.
83 pa_stream_set_read_callback(handle_, &ReadCallback, this);
84 pa_stream_readable_size(handle_);
85 stream_started_ = true;
87 pa_operation* operation = pa_stream_cork(handle_, 0, NULL, NULL);
88 WaitForOperationCompletion(pa_mainloop_, operation);
91 void PulseAudioInputStream::Stop() {
92 DCHECK(thread_checker_.CalledOnValidThread());
93 AutoPulseLock auto_lock(pa_mainloop_);
99 // Set the flag to false to stop filling new data to soundcard.
100 stream_started_ = false;
102 pa_operation* operation = pa_stream_flush(handle_,
103 &pulse::StreamSuccessCallback,
105 WaitForOperationCompletion(pa_mainloop_, operation);
108 pa_stream_set_read_callback(handle_, NULL, NULL);
109 operation = pa_stream_cork(handle_, 1, &pulse::StreamSuccessCallback,
111 WaitForOperationCompletion(pa_mainloop_, operation);
115 void PulseAudioInputStream::Close() {
116 DCHECK(thread_checker_.CalledOnValidThread());
118 AutoPulseLock auto_lock(pa_mainloop_);
120 // Disable all the callbacks before disconnecting.
121 pa_stream_set_state_callback(handle_, NULL, NULL);
122 pa_operation* operation = pa_stream_flush(
123 handle_, &pulse::StreamSuccessCallback, pa_mainloop_);
124 WaitForOperationCompletion(pa_mainloop_, operation);
126 if (pa_stream_get_state(handle_) != PA_STREAM_UNCONNECTED)
127 pa_stream_disconnect(handle_);
129 // Release PulseAudio structures.
130 pa_stream_unref(handle_);
135 // Signal to the manager that we're closed and can be removed.
136 // This should be the last call in the function as it deletes "this".
137 audio_manager_->ReleaseInputStream(this);
140 double PulseAudioInputStream::GetMaxVolume() {
141 return static_cast<double>(PA_VOLUME_NORM);
144 void PulseAudioInputStream::SetVolume(double volume) {
145 AutoPulseLock auto_lock(pa_mainloop_);
149 size_t index = pa_stream_get_device_index(handle_);
150 pa_operation* operation = NULL;
152 // Get the number of channels for the source only when the |channels_| is 0.
153 // We are assuming the stream source is not changed on the fly here.
154 operation = pa_context_get_source_info_by_index(
155 pa_context_, index, &VolumeCallback, this);
156 WaitForOperationCompletion(pa_mainloop_, operation);
158 DLOG(WARNING) << "Failed to get the number of channels for the source";
163 pa_cvolume pa_volume;
164 pa_cvolume_set(&pa_volume, channels_, volume);
165 operation = pa_context_set_source_volume_by_index(
166 pa_context_, index, &pa_volume, NULL, NULL);
168 // Don't need to wait for this task to complete.
169 pa_operation_unref(operation);
172 double PulseAudioInputStream::GetVolume() {
173 if (pa_threaded_mainloop_in_thread(pa_mainloop_)) {
174 // When being called by the pulse thread, GetVolume() is asynchronous and
175 // called under AutoPulseLock.
179 size_t index = pa_stream_get_device_index(handle_);
180 pa_operation* operation = pa_context_get_source_info_by_index(
181 pa_context_, index, &VolumeCallback, this);
182 // Do not wait for the operation since we can't block the pulse thread.
183 pa_operation_unref(operation);
185 // Return zero and the callback will asynchronously update the |volume_|.
188 // Called by other thread, put an AutoPulseLock and wait for the operation.
189 AutoPulseLock auto_lock(pa_mainloop_);
193 size_t index = pa_stream_get_device_index(handle_);
194 pa_operation* operation = pa_context_get_source_info_by_index(
195 pa_context_, index, &VolumeCallback, this);
196 WaitForOperationCompletion(pa_mainloop_, operation);
202 // static, used by pa_stream_set_read_callback.
203 void PulseAudioInputStream::ReadCallback(pa_stream* handle,
206 PulseAudioInputStream* stream =
207 reinterpret_cast<PulseAudioInputStream*>(user_data);
212 // static, used by pa_context_get_source_info_by_index.
213 void PulseAudioInputStream::VolumeCallback(pa_context* context,
214 const pa_source_info* info,
215 int error, void* user_data) {
216 PulseAudioInputStream* stream =
217 reinterpret_cast<PulseAudioInputStream*>(user_data);
220 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
224 if (stream->channels_ != info->channel_map.channels)
225 stream->channels_ = info->channel_map.channels;
227 pa_volume_t volume = PA_VOLUME_MUTED; // Minimum possible value.
228 // Use the max volume of any channel as the volume.
229 for (int i = 0; i < stream->channels_; ++i) {
230 if (volume < info->volume.values[i])
231 volume = info->volume.values[i];
234 // It is safe to access |volume_| here since VolumeCallback() is running
236 stream->volume_ = static_cast<double>(volume);
239 // static, used by pa_stream_set_state_callback.
240 void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s,
242 PulseAudioInputStream* stream =
243 reinterpret_cast<PulseAudioInputStream*>(user_data);
244 if (s && stream->callback_ &&
245 pa_stream_get_state(s) == PA_STREAM_FAILED) {
246 stream->callback_->OnError(stream);
249 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
252 void PulseAudioInputStream::ReadData() {
253 uint32 hardware_delay = pulse::GetHardwareLatencyInBytes(
254 handle_, params_.sample_rate(), params_.GetBytesPerFrame());
256 // Update the AGC volume level once every second. Note that,
257 // |volume| is also updated each time SetVolume() is called
258 // through IPC by the render-side AGC.
259 // We disregard the |normalized_volume| from GetAgcVolume()
260 // and use the value calculated by |volume_|.
261 double normalized_volume = 0.0;
262 GetAgcVolume(&normalized_volume);
263 normalized_volume = volume_ / GetMaxVolume();
267 const void* data = NULL;
268 pa_stream_peek(handle_, &data, &length);
269 if (!data || length == 0)
272 const int number_of_frames = length / params_.GetBytesPerFrame();
273 if (number_of_frames > fifo_.GetUnfilledFrames()) {
274 // Dynamically increase capacity to the FIFO to handle larger buffer got
276 const int increase_blocks_of_buffer = static_cast<int>(
277 (number_of_frames - fifo_.GetUnfilledFrames()) /
278 params_.frames_per_buffer()) + 1;
279 fifo_.IncreaseCapacity(increase_blocks_of_buffer);
282 fifo_.Push(data, number_of_frames, params_.bits_per_sample() / 8);
284 // Checks if we still have data.
285 pa_stream_drop(handle_);
286 } while (pa_stream_readable_size(handle_) > 0);
288 while (fifo_.available_blocks()) {
289 const AudioBus* audio_bus = fifo_.Consume();
291 // Compensate the audio delay caused by the FIFO.
292 hardware_delay += fifo_.GetAvailableFrames() * params_.GetBytesPerFrame();
293 callback_->OnData(this, audio_bus, hardware_delay, normalized_volume);
295 // Sleep 5ms to wait until render consumes the data in order to avoid
296 // back to back OnData() method.
297 if (fifo_.available_blocks())
298 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
301 pa_threaded_mainloop_signal(pa_mainloop_, 0);