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

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

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