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

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

Powered by Google App Engine
This is Rietveld 408576698