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> | 7 #include <pulse/pulseaudio.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 pa_cvolume pa_volume; | 210 pa_cvolume pa_volume; |
211 pa_cvolume_set(&pa_volume, channels_, volume); | 211 pa_cvolume_set(&pa_volume, channels_, volume); |
212 operation = pa_context_set_source_volume_by_index( | 212 operation = pa_context_set_source_volume_by_index( |
213 pa_context_, index, &pa_volume, NULL, NULL); | 213 pa_context_, index, &pa_volume, NULL, NULL); |
214 | 214 |
215 // Don't need to wait for this task to complete. | 215 // Don't need to wait for this task to complete. |
216 pa_operation_unref(operation); | 216 pa_operation_unref(operation); |
217 } | 217 } |
218 | 218 |
219 double PulseAudioInputStream::GetVolume() { | 219 double PulseAudioInputStream::GetVolume() { |
220 AutoPulseLock auto_lock(pa_mainloop_); | 220 if (pa_threaded_mainloop_in_thread(pa_mainloop_)) { |
221 if (!handle_) | 221 // When being called by the pulse thread, GetVolume() is asynchronous and |
| 222 // called under AutoPulseLock. |
| 223 if (!handle_) |
| 224 return 0.0; |
| 225 |
| 226 size_t index = pa_stream_get_device_index(handle_); |
| 227 pa_operation* operation = pa_context_get_source_info_by_index( |
| 228 pa_context_, index, &VolumeCallback, this); |
| 229 // Do not wait for the operation since we can't block the pulse thread. |
| 230 pa_operation_unref(operation); |
| 231 |
| 232 // Return zero and the callback will asynchronously update the |volume_|. |
222 return 0.0; | 233 return 0.0; |
| 234 } else { |
| 235 // Called by other thread, put an AutoPulseLock and wait for the operation. |
| 236 AutoPulseLock auto_lock(pa_mainloop_); |
| 237 if (!handle_) |
| 238 return 0.0; |
223 | 239 |
224 size_t index = pa_stream_get_device_index(handle_); | 240 size_t index = pa_stream_get_device_index(handle_); |
225 pa_operation* operation = pa_context_get_source_info_by_index( | 241 pa_operation* operation = pa_context_get_source_info_by_index( |
226 pa_context_, index, &VolumeCallback, this); | 242 pa_context_, index, &VolumeCallback, this); |
227 WaitForOperationCompletion(pa_mainloop_, operation); | 243 WaitForOperationCompletion(pa_mainloop_, operation); |
228 | 244 |
229 return volume_; | 245 return volume_; |
| 246 } |
230 } | 247 } |
231 | 248 |
232 // static, used by pa_stream_set_read_callback. | 249 // static, used by pa_stream_set_read_callback. |
233 void PulseAudioInputStream::ReadCallback(pa_stream* handle, | 250 void PulseAudioInputStream::ReadCallback(pa_stream* handle, |
234 size_t length, | 251 size_t length, |
235 void* user_data) { | 252 void* user_data) { |
236 PulseAudioInputStream* stream = | 253 PulseAudioInputStream* stream = |
237 reinterpret_cast<PulseAudioInputStream*>(user_data); | 254 reinterpret_cast<PulseAudioInputStream*>(user_data); |
238 | 255 |
239 stream->ReadData(); | 256 stream->ReadData(); |
(...skipping 14 matching lines...) Expand all Loading... |
254 if (stream->channels_ != info->channel_map.channels) | 271 if (stream->channels_ != info->channel_map.channels) |
255 stream->channels_ = info->channel_map.channels; | 272 stream->channels_ = info->channel_map.channels; |
256 | 273 |
257 pa_volume_t volume = PA_VOLUME_MUTED; // Minimum possible value. | 274 pa_volume_t volume = PA_VOLUME_MUTED; // Minimum possible value. |
258 // Use the max volume of any channel as the volume. | 275 // Use the max volume of any channel as the volume. |
259 for (int i = 0; i < stream->channels_; ++i) { | 276 for (int i = 0; i < stream->channels_; ++i) { |
260 if (volume < info->volume.values[i]) | 277 if (volume < info->volume.values[i]) |
261 volume = info->volume.values[i]; | 278 volume = info->volume.values[i]; |
262 } | 279 } |
263 | 280 |
| 281 // It is safe to access |volume_| here since VolumeCallback() is running |
| 282 // under PulseLock. |
264 stream->volume_ = static_cast<double>(volume); | 283 stream->volume_ = static_cast<double>(volume); |
265 } | 284 } |
266 | 285 |
267 // static, used by pa_stream_set_state_callback. | 286 // static, used by pa_stream_set_state_callback. |
268 void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s, | 287 void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s, |
269 void* user_data) { | 288 void* user_data) { |
270 PulseAudioInputStream* stream = | 289 PulseAudioInputStream* stream = |
271 reinterpret_cast<PulseAudioInputStream*>(user_data); | 290 reinterpret_cast<PulseAudioInputStream*>(user_data); |
272 if (s && stream->callback_ && | 291 if (s && stream->callback_ && |
273 pa_stream_get_state(s) == PA_STREAM_FAILED) { | 292 pa_stream_get_state(s) == PA_STREAM_FAILED) { |
274 stream->callback_->OnError(stream, pa_context_errno(stream->pa_context_)); | 293 stream->callback_->OnError(stream, pa_context_errno(stream->pa_context_)); |
275 } | 294 } |
276 | 295 |
277 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0); | 296 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0); |
278 } | 297 } |
279 | 298 |
280 void PulseAudioInputStream::ReadData() { | 299 void PulseAudioInputStream::ReadData() { |
281 uint32 hardware_delay = pulse::GetHardwareLatencyInBytes( | 300 uint32 hardware_delay = pulse::GetHardwareLatencyInBytes( |
282 handle_, params_.sample_rate(), params_.GetBytesPerFrame()); | 301 handle_, params_.sample_rate(), params_.GetBytesPerFrame()); |
283 | 302 |
284 // Update the AGC volume level once every second. Note that, | 303 // Update the AGC volume level once every second. Note that, |
285 // |volume| is also updated each time SetVolume() is called | 304 // |volume| is also updated each time SetVolume() is called |
286 // through IPC by the render-side AGC. | 305 // through IPC by the render-side AGC. |
| 306 // QueryAgcVolume() will trigger a callback to asynchronously update the |
| 307 // |volume_|, we disregard the |normalized_volume| from QueryAgcVolume() |
| 308 // and use the value calculated by |volume_|. |
287 double normalized_volume = 0.0; | 309 double normalized_volume = 0.0; |
288 QueryAgcVolume(&normalized_volume); | 310 QueryAgcVolume(&normalized_volume); |
| 311 normalized_volume = volume_ / GetMaxVolume(); |
289 | 312 |
290 do { | 313 do { |
291 size_t length = 0; | 314 size_t length = 0; |
292 const void* data = NULL; | 315 const void* data = NULL; |
293 pa_stream_peek(handle_, &data, &length); | 316 pa_stream_peek(handle_, &data, &length); |
294 if (!data || length == 0) | 317 if (!data || length == 0) |
295 break; | 318 break; |
296 | 319 |
297 buffer_->Append(reinterpret_cast<const uint8*>(data), length); | 320 buffer_->Append(reinterpret_cast<const uint8*>(data), length); |
298 | 321 |
(...skipping 15 matching lines...) Expand all Loading... |
314 DLOG(WARNING) << "OnData is being called consecutively, sleep 5ms to " | 337 DLOG(WARNING) << "OnData is being called consecutively, sleep 5ms to " |
315 << "wait until render consumes the data"; | 338 << "wait until render consumes the data"; |
316 base::PlatformThread::Sleep( | 339 base::PlatformThread::Sleep( |
317 base::TimeDelta::FromMilliseconds(5)); | 340 base::TimeDelta::FromMilliseconds(5)); |
318 } | 341 } |
319 | 342 |
320 pa_threaded_mainloop_signal(pa_mainloop_, 0); | 343 pa_threaded_mainloop_signal(pa_mainloop_, 0); |
321 } | 344 } |
322 | 345 |
323 } // namespace media | 346 } // namespace media |
OLD | NEW |