OLD | NEW |
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/pulse/pulse_input.h" | 5 #include "media/audio/pulse/pulse_input.h" |
6 | 6 |
7 #include <pulse/pulseaudio.h> | |
8 | |
9 #include "base/logging.h" | 7 #include "base/logging.h" |
10 #include "media/audio/pulse/audio_manager_pulse.h" | 8 #include "media/audio/pulse/audio_manager_pulse.h" |
11 #include "media/audio/pulse/pulse_util.h" | 9 #include "media/audio/pulse/pulse_util.h" |
12 | 10 |
13 namespace media { | 11 namespace media { |
14 | 12 |
15 using pulse::AutoPulseLock; | 13 using pulse::AutoPulseLock; |
16 using pulse::WaitForOperationCompletion; | 14 using pulse::WaitForOperationCompletion; |
17 | 15 |
18 // Number of blocks of buffers used in the |fifo_|. | 16 // Number of blocks of buffers used in the |fifo_|. |
19 const int kNumberOfBlocksBufferInFifo = 2; | 17 const int kNumberOfBlocksBufferInFifo = 2; |
20 | 18 |
21 PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager, | 19 PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager, |
22 const std::string& device_name, | 20 const std::string& device_name, |
23 const AudioParameters& params, | 21 const AudioParameters& params, |
24 pa_threaded_mainloop* mainloop, | 22 pa_threaded_mainloop* mainloop, |
25 pa_context* context) | 23 pa_context* context) |
26 : audio_manager_(audio_manager), | 24 : audio_manager_(audio_manager), |
27 callback_(NULL), | 25 callback_(NULL), |
28 device_name_(device_name), | 26 device_name_(device_name), |
29 params_(params), | 27 params_(params), |
30 channels_(0), | 28 channels_(0), |
31 volume_(0.0), | 29 volume_(0.0), |
32 stream_started_(false), | 30 stream_started_(false), |
| 31 muted_(false), |
33 fifo_(params.channels(), | 32 fifo_(params.channels(), |
34 params.frames_per_buffer(), | 33 params.frames_per_buffer(), |
35 kNumberOfBlocksBufferInFifo), | 34 kNumberOfBlocksBufferInFifo), |
36 pa_mainloop_(mainloop), | 35 pa_mainloop_(mainloop), |
37 pa_context_(context), | 36 pa_context_(context), |
38 handle_(NULL), | 37 handle_(NULL), |
39 context_state_changed_(false) { | 38 context_state_changed_(false) { |
40 DCHECK(mainloop); | 39 DCHECK(mainloop); |
41 DCHECK(context); | 40 DCHECK(context); |
42 CHECK(params_.IsValid()); | 41 CHECK(params_.IsValid()); |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 | 177 |
179 size_t index = pa_stream_get_device_index(handle_); | 178 size_t index = pa_stream_get_device_index(handle_); |
180 pa_operation* operation = pa_context_get_source_info_by_index( | 179 pa_operation* operation = pa_context_get_source_info_by_index( |
181 pa_context_, index, &VolumeCallback, this); | 180 pa_context_, index, &VolumeCallback, this); |
182 // Do not wait for the operation since we can't block the pulse thread. | 181 // Do not wait for the operation since we can't block the pulse thread. |
183 pa_operation_unref(operation); | 182 pa_operation_unref(operation); |
184 | 183 |
185 // Return zero and the callback will asynchronously update the |volume_|. | 184 // Return zero and the callback will asynchronously update the |volume_|. |
186 return 0.0; | 185 return 0.0; |
187 } else { | 186 } else { |
188 // Called by other thread, put an AutoPulseLock and wait for the operation. | 187 GetSourceInformation(&VolumeCallback); |
189 AutoPulseLock auto_lock(pa_mainloop_); | |
190 if (!handle_) | |
191 return 0.0; | |
192 | |
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); | |
197 | |
198 return volume_; | 188 return volume_; |
199 } | 189 } |
200 } | 190 } |
201 | 191 |
| 192 bool PulseAudioInputStream::IsMuted() { |
| 193 DCHECK(thread_checker_.CalledOnValidThread()); |
| 194 GetSourceInformation(&MuteCallback); |
| 195 return muted_; |
| 196 } |
| 197 |
202 // static, used by pa_stream_set_read_callback. | 198 // static, used by pa_stream_set_read_callback. |
203 void PulseAudioInputStream::ReadCallback(pa_stream* handle, | 199 void PulseAudioInputStream::ReadCallback(pa_stream* handle, |
204 size_t length, | 200 size_t length, |
205 void* user_data) { | 201 void* user_data) { |
206 PulseAudioInputStream* stream = | 202 PulseAudioInputStream* stream = |
207 reinterpret_cast<PulseAudioInputStream*>(user_data); | 203 reinterpret_cast<PulseAudioInputStream*>(user_data); |
208 | 204 |
209 stream->ReadData(); | 205 stream->ReadData(); |
210 } | 206 } |
211 | 207 |
(...skipping 17 matching lines...) Expand all Loading... |
229 for (int i = 0; i < stream->channels_; ++i) { | 225 for (int i = 0; i < stream->channels_; ++i) { |
230 if (volume < info->volume.values[i]) | 226 if (volume < info->volume.values[i]) |
231 volume = info->volume.values[i]; | 227 volume = info->volume.values[i]; |
232 } | 228 } |
233 | 229 |
234 // It is safe to access |volume_| here since VolumeCallback() is running | 230 // It is safe to access |volume_| here since VolumeCallback() is running |
235 // under PulseLock. | 231 // under PulseLock. |
236 stream->volume_ = static_cast<double>(volume); | 232 stream->volume_ = static_cast<double>(volume); |
237 } | 233 } |
238 | 234 |
| 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); |
| 245 |
| 246 // Avoid infinite wait loop in case of error. |
| 247 if (error) { |
| 248 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0); |
| 249 return; |
| 250 } |
| 251 |
| 252 stream->muted_ = info->mute != 0; |
| 253 } |
| 254 |
239 // static, used by pa_stream_set_state_callback. | 255 // static, used by pa_stream_set_state_callback. |
240 void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s, | 256 void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s, |
241 void* user_data) { | 257 void* user_data) { |
242 PulseAudioInputStream* stream = | 258 PulseAudioInputStream* stream = |
243 reinterpret_cast<PulseAudioInputStream*>(user_data); | 259 reinterpret_cast<PulseAudioInputStream*>(user_data); |
| 260 |
244 if (s && stream->callback_ && | 261 if (s && stream->callback_ && |
245 pa_stream_get_state(s) == PA_STREAM_FAILED) { | 262 pa_stream_get_state(s) == PA_STREAM_FAILED) { |
246 stream->callback_->OnError(stream); | 263 stream->callback_->OnError(stream); |
247 } | 264 } |
248 | 265 |
249 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0); | 266 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0); |
250 } | 267 } |
251 | 268 |
252 void PulseAudioInputStream::ReadData() { | 269 void PulseAudioInputStream::ReadData() { |
253 uint32 hardware_delay = pulse::GetHardwareLatencyInBytes( | 270 uint32 hardware_delay = pulse::GetHardwareLatencyInBytes( |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 | 311 |
295 // Sleep 5ms to wait until render consumes the data in order to avoid | 312 // Sleep 5ms to wait until render consumes the data in order to avoid |
296 // back to back OnData() method. | 313 // back to back OnData() method. |
297 if (fifo_.available_blocks()) | 314 if (fifo_.available_blocks()) |
298 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); | 315 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); |
299 } | 316 } |
300 | 317 |
301 pa_threaded_mainloop_signal(pa_mainloop_, 0); | 318 pa_threaded_mainloop_signal(pa_mainloop_, 0); |
302 } | 319 } |
303 | 320 |
| 321 bool PulseAudioInputStream::GetSourceInformation(pa_source_info_cb_t callback) { |
| 322 AutoPulseLock auto_lock(pa_mainloop_); |
| 323 if (!handle_) |
| 324 return false; |
| 325 |
| 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; |
| 331 } |
| 332 |
304 } // namespace media | 333 } // namespace media |
OLD | NEW |