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

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

Issue 1711823004: Let default device in PulseAudio be the system default device (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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);
173 174
174 // Set sample specifications. 175 // Set sample specifications.
175 pa_sample_spec sample_specifications; 176 pa_sample_spec sample_specifications;
176 sample_specifications.format = BitsToPASampleFormat( 177 sample_specifications.format = BitsToPASampleFormat(
177 params.bits_per_sample()); 178 params.bits_per_sample());
178 sample_specifications.rate = params.sample_rate(); 179 sample_specifications.rate = params.sample_rate();
179 sample_specifications.channels = params.channels(); 180 sample_specifications.channels = params.channels();
180 181
181 // Get channel mapping and open recording stream. 182 // Get channel mapping and open recording stream.
182 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap( 183 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap(
(...skipping 21 matching lines...) Expand all
204 buffer_attributes.maxlength = static_cast<uint32_t>(-1); 205 buffer_attributes.maxlength = static_cast<uint32_t>(-1);
205 buffer_attributes.tlength = buffer_size; 206 buffer_attributes.tlength = buffer_size;
206 buffer_attributes.minreq = buffer_size; 207 buffer_attributes.minreq = buffer_size;
207 buffer_attributes.prebuf = static_cast<uint32_t>(-1); 208 buffer_attributes.prebuf = static_cast<uint32_t>(-1);
208 buffer_attributes.fragsize = buffer_size; 209 buffer_attributes.fragsize = buffer_size;
209 int flags = PA_STREAM_AUTO_TIMING_UPDATE | 210 int flags = PA_STREAM_AUTO_TIMING_UPDATE |
210 PA_STREAM_INTERPOLATE_TIMING | 211 PA_STREAM_INTERPOLATE_TIMING |
211 PA_STREAM_ADJUST_LATENCY | 212 PA_STREAM_ADJUST_LATENCY |
212 PA_STREAM_START_CORKED; 213 PA_STREAM_START_CORKED;
213 RETURN_ON_FAILURE( 214 RETURN_ON_FAILURE(
214 pa_stream_connect_record( 215 pa_stream_connect_record(*stream, device_id.c_str(), &buffer_attributes,
215 *stream, 216 static_cast<pa_stream_flags_t>(flags)) == 0,
216 device_id == AudioManagerBase::kDefaultDeviceId ?
217 NULL : device_id.c_str(),
218 &buffer_attributes,
219 static_cast<pa_stream_flags_t>(flags)) == 0,
220 "pa_stream_connect_record FAILED "); 217 "pa_stream_connect_record FAILED ");
221 218
222 // Wait for the stream to be ready. 219 // Wait for the stream to be ready.
223 while (true) { 220 while (true) {
224 pa_stream_state_t stream_state = pa_stream_get_state(*stream); 221 pa_stream_state_t stream_state = pa_stream_get_state(*stream);
225 RETURN_ON_FAILURE( 222 RETURN_ON_FAILURE(
226 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state"); 223 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state");
227 if (stream_state == PA_STREAM_READY) 224 if (stream_state == PA_STREAM_READY)
228 break; 225 break;
229 pa_threaded_mainloop_wait(mainloop); 226 pa_threaded_mainloop_wait(mainloop);
230 } 227 }
231 228
232 return true; 229 return true;
233 } 230 }
234 231
235 bool CreateOutputStream(pa_threaded_mainloop** mainloop, 232 bool CreateOutputStream(pa_threaded_mainloop* mainloop,
236 pa_context** context, 233 pa_context* context,
237 pa_stream** stream, 234 pa_stream** stream,
238 const AudioParameters& params, 235 const AudioParameters& params,
239 const std::string& device_id, 236 const std::string& device_id,
240 const std::string& app_name, 237 const std::string& app_name,
241 pa_stream_notify_cb_t stream_callback, 238 pa_stream_notify_cb_t stream_callback,
242 pa_stream_request_cb_t write_callback, 239 pa_stream_request_cb_t write_callback,
243 void* user_data) { 240 void* user_data) {
244 DCHECK(!*mainloop); 241 DCHECK(mainloop);
245 DCHECK(!*context); 242 DCHECK(context);
246 243 DCHECK(device_id != AudioManagerBase::kDefaultDeviceId);
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 }
280 244
281 // Set sample specifications. 245 // Set sample specifications.
282 pa_sample_spec sample_specifications; 246 pa_sample_spec sample_specifications;
283 sample_specifications.format = BitsToPASampleFormat( 247 sample_specifications.format = BitsToPASampleFormat(
284 params.bits_per_sample()); 248 params.bits_per_sample());
285 sample_specifications.rate = params.sample_rate(); 249 sample_specifications.rate = params.sample_rate();
286 sample_specifications.channels = params.channels(); 250 sample_specifications.channels = params.channels();
287 251
288 // Get channel mapping. 252 // Get channel mapping.
289 pa_channel_map* map = NULL; 253 pa_channel_map* map = NULL;
290 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap( 254 pa_channel_map source_channel_map = ChannelLayoutToPAChannelMap(
291 params.channel_layout()); 255 params.channel_layout());
292 if (source_channel_map.channels != 0) { 256 if (source_channel_map.channels != 0) {
293 // The source data uses a supported channel map so we will use it rather 257 // The source data uses a supported channel map so we will use it rather
294 // than the default channel map (NULL). 258 // than the default channel map (NULL).
295 map = &source_channel_map; 259 map = &source_channel_map;
296 } 260 }
297 261
298 // Open playback stream and 262 // Open playback stream and
299 // tell PulseAudio what the stream icon should be. 263 // tell PulseAudio what the stream icon should be.
300 ScopedPropertyList property_list; 264 ScopedPropertyList property_list;
301 pa_proplist_sets(property_list.get(), PA_PROP_APPLICATION_ICON_NAME, 265 pa_proplist_sets(property_list.get(), PA_PROP_APPLICATION_ICON_NAME,
302 kBrowserDisplayName); 266 kBrowserDisplayName);
303 *stream = pa_stream_new_with_proplist( 267 *stream = pa_stream_new_with_proplist(
304 *context, "Playback", &sample_specifications, map, property_list.get()); 268 context, "Playback", &sample_specifications, map, property_list.get());
305 RETURN_ON_FAILURE(*stream, "failed to create PA playback stream"); 269 RETURN_ON_FAILURE(*stream, "failed to create PA playback stream");
306 270
307 pa_stream_set_state_callback(*stream, stream_callback, user_data); 271 pa_stream_set_state_callback(*stream, stream_callback, user_data);
308 272
309 // Even though we start the stream corked above, PulseAudio will issue one 273 // Even though we start the stream corked above, PulseAudio will issue one
310 // stream request after setup. write_callback() must fulfill the write. 274 // stream request after setup. write_callback() must fulfill the write.
311 pa_stream_set_write_callback(*stream, write_callback, user_data); 275 pa_stream_set_write_callback(*stream, write_callback, user_data);
312 276
313 // Pulse is very finicky with the small buffer sizes used by Chrome. The 277 // Pulse is very finicky with the small buffer sizes used by Chrome. The
314 // settings below are mostly found through trial and error. Essentially we 278 // settings below are mostly found through trial and error. Essentially we
(...skipping 10 matching lines...) Expand all
325 pa_buffer_attributes.minreq = params.GetBytesPerBuffer() / 2; 289 pa_buffer_attributes.minreq = params.GetBytesPerBuffer() / 2;
326 pa_buffer_attributes.prebuf = static_cast<uint32_t>(-1); 290 pa_buffer_attributes.prebuf = static_cast<uint32_t>(-1);
327 pa_buffer_attributes.tlength = params.GetBytesPerBuffer() * 3; 291 pa_buffer_attributes.tlength = params.GetBytesPerBuffer() * 3;
328 pa_buffer_attributes.fragsize = static_cast<uint32_t>(-1); 292 pa_buffer_attributes.fragsize = static_cast<uint32_t>(-1);
329 293
330 // Connect playback stream. Like pa_buffer_attr, the pa_stream_flags have a 294 // Connect playback stream. Like pa_buffer_attr, the pa_stream_flags have a
331 // huge impact on the performance of the stream and were chosen through trial 295 // huge impact on the performance of the stream and were chosen through trial
332 // and error. 296 // and error.
333 RETURN_ON_FAILURE( 297 RETURN_ON_FAILURE(
334 pa_stream_connect_playback( 298 pa_stream_connect_playback(
335 *stream, 299 *stream, device_id.c_str(), &pa_buffer_attributes,
336 device_id == AudioManagerBase::kDefaultDeviceId ?
337 NULL : device_id.c_str(),
338 &pa_buffer_attributes,
339 static_cast<pa_stream_flags_t>( 300 static_cast<pa_stream_flags_t>(
340 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | 301 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY |
341 PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC | 302 PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC |
342 PA_STREAM_START_CORKED), 303 PA_STREAM_START_CORKED),
343 NULL, 304 NULL, NULL) == 0,
344 NULL) == 0,
345 "pa_stream_connect_playback FAILED "); 305 "pa_stream_connect_playback FAILED ");
346 306
347 // Wait for the stream to be ready. 307 // Wait for the stream to be ready.
348 while (true) { 308 while (true) {
349 pa_stream_state_t stream_state = pa_stream_get_state(*stream); 309 pa_stream_state_t stream_state = pa_stream_get_state(*stream);
350 RETURN_ON_FAILURE( 310 RETURN_ON_FAILURE(
351 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state"); 311 PA_STREAM_IS_GOOD(stream_state), "Invalid PulseAudio stream state");
352 if (stream_state == PA_STREAM_READY) 312 if (stream_state == PA_STREAM_READY)
353 break; 313 break;
354 pa_threaded_mainloop_wait(*mainloop); 314 pa_threaded_mainloop_wait(mainloop);
355 } 315 }
356 316
357 return true; 317 return true;
358 } 318 }
359 319
360 #undef RETURN_ON_FAILURE 320 #undef RETURN_ON_FAILURE
361 321
362 } // namespace pulse 322 } // namespace pulse
363 323
364 } // namespace media 324 } // 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