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

Side by Side Diff: media/audio/pulse/pulse_util.cc

Issue 1998173002: Use "application default" audio device as default PulseAudio device. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2704
Patch Set: Created 4 years, 7 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
« no previous file with comments | « media/audio/pulse/pulse_util.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_util.h" 5 #include "media/audio/pulse/pulse_util.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 163
164 bool CreateInputStream(pa_threaded_mainloop* mainloop, 164 bool CreateInputStream(pa_threaded_mainloop* mainloop,
165 pa_context* context, 165 pa_context* context,
166 pa_stream** stream, 166 pa_stream** stream,
167 const AudioParameters& params, 167 const AudioParameters& params,
168 const std::string& device_id, 168 const std::string& device_id,
169 pa_stream_notify_cb_t stream_callback, 169 pa_stream_notify_cb_t stream_callback,
170 void* user_data) { 170 void* user_data) {
171 DCHECK(mainloop); 171 DCHECK(mainloop);
172 DCHECK(context); 172 DCHECK(context);
173 DCHECK_NE(device_id, AudioManagerBase::kDefaultDeviceId);
174 173
175 // Set sample specifications. 174 // Set sample specifications.
176 pa_sample_spec sample_specifications; 175 pa_sample_spec sample_specifications;
177 sample_specifications.format = BitsToPASampleFormat( 176 sample_specifications.format = BitsToPASampleFormat(
178 params.bits_per_sample()); 177 params.bits_per_sample());
179 sample_specifications.rate = params.sample_rate(); 178 sample_specifications.rate = params.sample_rate();
180 sample_specifications.channels = params.channels(); 179 sample_specifications.channels = params.channels();
181 180
182 // Get channel mapping and open recording stream. 181 // Get channel mapping and open recording stream.
183 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap( 182 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap(
(...skipping 21 matching lines...) Expand all
205 buffer_attributes.maxlength = static_cast<uint32_t>(-1); 204 buffer_attributes.maxlength = static_cast<uint32_t>(-1);
206 buffer_attributes.tlength = buffer_size; 205 buffer_attributes.tlength = buffer_size;
207 buffer_attributes.minreq = buffer_size; 206 buffer_attributes.minreq = buffer_size;
208 buffer_attributes.prebuf = static_cast<uint32_t>(-1); 207 buffer_attributes.prebuf = static_cast<uint32_t>(-1);
209 buffer_attributes.fragsize = buffer_size; 208 buffer_attributes.fragsize = buffer_size;
210 int flags = PA_STREAM_AUTO_TIMING_UPDATE | 209 int flags = PA_STREAM_AUTO_TIMING_UPDATE |
211 PA_STREAM_INTERPOLATE_TIMING | 210 PA_STREAM_INTERPOLATE_TIMING |
212 PA_STREAM_ADJUST_LATENCY | 211 PA_STREAM_ADJUST_LATENCY |
213 PA_STREAM_START_CORKED; 212 PA_STREAM_START_CORKED;
214 RETURN_ON_FAILURE( 213 RETURN_ON_FAILURE(
215 pa_stream_connect_record(*stream, device_id.c_str(), &buffer_attributes, 214 pa_stream_connect_record(
216 static_cast<pa_stream_flags_t>(flags)) == 0, 215 *stream,
216 device_id == AudioManagerBase::kDefaultDeviceId ?
217 NULL : device_id.c_str(),
218 &buffer_attributes,
219 static_cast<pa_stream_flags_t>(flags)) == 0,
217 "pa_stream_connect_record FAILED "); 220 "pa_stream_connect_record FAILED ");
218 221
219 // Wait for the stream to be ready. 222 // Wait for the stream to be ready.
220 while (true) { 223 while (true) {
221 pa_stream_state_t stream_state = pa_stream_get_state(*stream); 224 pa_stream_state_t stream_state = pa_stream_get_state(*stream);
222 RETURN_ON_FAILURE( 225 RETURN_ON_FAILURE(
223 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state"); 226 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state");
224 if (stream_state == PA_STREAM_READY) 227 if (stream_state == PA_STREAM_READY)
225 break; 228 break;
226 pa_threaded_mainloop_wait(mainloop); 229 pa_threaded_mainloop_wait(mainloop);
227 } 230 }
228 231
229 return true; 232 return true;
230 } 233 }
231 234
232 bool CreateOutputStream(pa_threaded_mainloop* mainloop, 235 bool CreateOutputStream(pa_threaded_mainloop** mainloop,
233 pa_context* context, 236 pa_context** context,
234 pa_stream** stream, 237 pa_stream** stream,
235 const AudioParameters& params, 238 const AudioParameters& params,
236 const std::string& device_id, 239 const std::string& device_id,
237 const std::string& app_name, 240 const std::string& app_name,
238 pa_stream_notify_cb_t stream_callback, 241 pa_stream_notify_cb_t stream_callback,
239 pa_stream_request_cb_t write_callback, 242 pa_stream_request_cb_t write_callback,
240 void* user_data) { 243 void* user_data) {
241 DCHECK(mainloop); 244 DCHECK(!*mainloop);
242 DCHECK(context); 245 DCHECK(!*context);
243 DCHECK(device_id != AudioManagerBase::kDefaultDeviceId); 246
247 *mainloop = pa_threaded_mainloop_new();
248 RETURN_ON_FAILURE(*mainloop, "Failed to create PulseAudio main loop.");
249
250 pa_mainloop_api* pa_mainloop_api = pa_threaded_mainloop_get_api(*mainloop);
251 *context = pa_context_new(pa_mainloop_api,
252 app_name.empty() ? "Chromium" : app_name.c_str());
253 RETURN_ON_FAILURE(*context, "Failed to create PulseAudio context.");
254
255 // A state callback must be set before calling pa_threaded_mainloop_lock() or
256 // pa_threaded_mainloop_wait() calls may lead to dead lock.
257 pa_context_set_state_callback(*context, &ContextStateCallback, *mainloop);
258
259 // Lock the main loop while setting up the context. Failure to do so may lead
260 // to crashes as the PulseAudio thread tries to run before things are ready.
261 AutoPulseLock auto_lock(*mainloop);
262
263 RETURN_ON_FAILURE(pa_threaded_mainloop_start(*mainloop) == 0,
264 "Failed to start PulseAudio main loop.");
265 RETURN_ON_FAILURE(
266 pa_context_connect(*context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) == 0,
267 "Failed to connect PulseAudio context.");
268
269 // Wait until |pa_context_| is ready. pa_threaded_mainloop_wait() must be
270 // called after pa_context_get_state() in case the context is already ready,
271 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
272 while (true) {
273 pa_context_state_t context_state = pa_context_get_state(*context);
274 RETURN_ON_FAILURE(
275 PA_CONTEXT_IS_GOOD(context_state), "Invalid PulseAudio context state.");
276 if (context_state == PA_CONTEXT_READY)
277 break;
278 pa_threaded_mainloop_wait(*mainloop);
279 }
244 280
245 // Set sample specifications. 281 // Set sample specifications.
246 pa_sample_spec sample_specifications; 282 pa_sample_spec sample_specifications;
247 sample_specifications.format = BitsToPASampleFormat( 283 sample_specifications.format = BitsToPASampleFormat(
248 params.bits_per_sample()); 284 params.bits_per_sample());
249 sample_specifications.rate = params.sample_rate(); 285 sample_specifications.rate = params.sample_rate();
250 sample_specifications.channels = params.channels(); 286 sample_specifications.channels = params.channels();
251 287
252 // Get channel mapping. 288 // Get channel mapping.
253 pa_channel_map* map = NULL; 289 pa_channel_map* map = NULL;
254 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap( 290 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap(
255 params.channel_layout()); 291 params.channel_layout());
256 if (source_channel_map.channels != 0) { 292 if (source_channel_map.channels != 0) {
257 // The source data uses a supported channel map so we will use it rather 293 // The source data uses a supported channel map so we will use it rather
258 // than the default channel map (NULL). 294 // than the default channel map (NULL).
259 map = &source_channel_map; 295 map = &source_channel_map;
260 } 296 }
261 297
262 // Open playback stream and 298 // Open playback stream and
263 // tell PulseAudio what the stream icon should be. 299 // tell PulseAudio what the stream icon should be.
264 ScopedPropertyList property_list; 300 ScopedPropertyList property_list;
265 pa_proplist_sets(property_list.get(), PA_PROP_APPLICATION_ICON_NAME, 301 pa_proplist_sets(property_list.get(), PA_PROP_APPLICATION_ICON_NAME,
266 kBrowserDisplayName); 302 kBrowserDisplayName);
267 *stream = pa_stream_new_with_proplist( 303 *stream = pa_stream_new_with_proplist(
268 context, "Playback", &sample_specifications, map, property_list.get()); 304 *context, "Playback", &sample_specifications, map, property_list.get());
269 RETURN_ON_FAILURE(*stream, "failed to create PA playback stream"); 305 RETURN_ON_FAILURE(*stream, "failed to create PA playback stream");
270 306
271 pa_stream_set_state_callback(*stream, stream_callback, user_data); 307 pa_stream_set_state_callback(*stream, stream_callback, user_data);
272 308
273 // Even though we start the stream corked above, PulseAudio will issue one 309 // Even though we start the stream corked above, PulseAudio will issue one
274 // stream request after setup. write_callback() must fulfill the write. 310 // stream request after setup. write_callback() must fulfill the write.
275 pa_stream_set_write_callback(*stream, write_callback, user_data); 311 pa_stream_set_write_callback(*stream, write_callback, user_data);
276 312
277 // Pulse is very finicky with the small buffer sizes used by Chrome. The 313 // Pulse is very finicky with the small buffer sizes used by Chrome. The
278 // settings below are mostly found through trial and error. Essentially we 314 // settings below are mostly found through trial and error. Essentially we
(...skipping 10 matching lines...) Expand all
289 pa_buffer_attributes.minreq = params.GetBytesPerBuffer() / 2; 325 pa_buffer_attributes.minreq = params.GetBytesPerBuffer() / 2;
290 pa_buffer_attributes.prebuf = static_cast<uint32_t>(-1); 326 pa_buffer_attributes.prebuf = static_cast<uint32_t>(-1);
291 pa_buffer_attributes.tlength = params.GetBytesPerBuffer() * 3; 327 pa_buffer_attributes.tlength = params.GetBytesPerBuffer() * 3;
292 pa_buffer_attributes.fragsize = static_cast<uint32_t>(-1); 328 pa_buffer_attributes.fragsize = static_cast<uint32_t>(-1);
293 329
294 // Connect playback stream. Like pa_buffer_attr, the pa_stream_flags have a 330 // Connect playback stream. Like pa_buffer_attr, the pa_stream_flags have a
295 // huge impact on the performance of the stream and were chosen through trial 331 // huge impact on the performance of the stream and were chosen through trial
296 // and error. 332 // and error.
297 RETURN_ON_FAILURE( 333 RETURN_ON_FAILURE(
298 pa_stream_connect_playback( 334 pa_stream_connect_playback(
299 *stream, device_id.c_str(), &pa_buffer_attributes, 335 *stream,
336 device_id == AudioManagerBase::kDefaultDeviceId ?
337 NULL : device_id.c_str(),
338 &pa_buffer_attributes,
300 static_cast<pa_stream_flags_t>( 339 static_cast<pa_stream_flags_t>(
301 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | 340 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY |
302 PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC | 341 PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC |
303 PA_STREAM_START_CORKED), 342 PA_STREAM_START_CORKED),
304 NULL, NULL) == 0, 343 NULL,
344 NULL) == 0,
305 "pa_stream_connect_playback FAILED "); 345 "pa_stream_connect_playback FAILED ");
306 346
307 // Wait for the stream to be ready. 347 // Wait for the stream to be ready.
308 while (true) { 348 while (true) {
309 pa_stream_state_t stream_state = pa_stream_get_state(*stream); 349 pa_stream_state_t stream_state = pa_stream_get_state(*stream);
310 RETURN_ON_FAILURE( 350 RETURN_ON_FAILURE(
311 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state"); 351 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state");
312 if (stream_state == PA_STREAM_READY) 352 if (stream_state == PA_STREAM_READY)
313 break; 353 break;
314 pa_threaded_mainloop_wait(mainloop); 354 pa_threaded_mainloop_wait(*mainloop);
315 } 355 }
316 356
317 return true; 357 return true;
318 } 358 }
319 359
320 #undef RETURN_ON_FAILURE 360 #undef RETURN_ON_FAILURE
321 361
322 } // namespace pulse 362 } // namespace pulse
323 363
324 } // namespace media 364 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/pulse/pulse_util.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698