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

Side by Side Diff: media/audio/pulse/pulse_output.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: latest 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_output.h" 5 #include "media/audio/pulse/pulse_output.h"
6 6
7 #include <pulse/pulseaudio.h> 7 #include <pulse/pulseaudio.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include "base/single_thread_task_runner.h" 10 #include "base/single_thread_task_runner.h"
11 #include "media/audio/audio_manager_base.h" 11 #include "media/audio/audio_manager_base.h"
12 #include "media/audio/pulse/pulse_util.h" 12 #include "media/audio/pulse/pulse_util.h"
13 13
14 namespace {
15
16 // pa_context_get_server_info callback. It's used by
17 // GetSystemDefaultOutputDevice to set |default_system_device_name_| to the
18 // default system output device.
19 void GetSystemDefaultOutputDeviceCallback(pa_context* context,
20 const pa_server_info* info,
21 void* user_data) {
22 media::PulseAudioOutputStream* stream =
23 reinterpret_cast<media::PulseAudioOutputStream*>(user_data);
24 stream->SetDefaultSystemDeviceName(info->default_sink_name);
25 pa_threaded_mainloop* pa_mainloop = stream->GetPAMainloop();
26 pa_threaded_mainloop_signal(pa_mainloop, 0);
Henrik Grunell 2016/03/10 00:57:07 You could just use stream->GetPAMainloop() directl
rchtara 2016/03/10 13:20:35 Done.
27 }
28 }
29
14 namespace media { 30 namespace media {
15 31
16 using pulse::AutoPulseLock; 32 using pulse::AutoPulseLock;
17 using pulse::WaitForOperationCompletion; 33 using pulse::WaitForOperationCompletion;
18 34
35 // Helper macro to avoid code spam and string bloat.
36 #define RETURN_ON_FAILURE(expression, message) \
37 do { \
38 if (!(expression)) { \
39 DLOG(ERROR) << message; \
40 return false; \
41 } \
42 } while (0)
43
19 // static, pa_stream_notify_cb 44 // static, pa_stream_notify_cb
20 void PulseAudioOutputStream::StreamNotifyCallback(pa_stream* s, void* p_this) { 45 void PulseAudioOutputStream::StreamNotifyCallback(pa_stream* s, void* p_this) {
21 PulseAudioOutputStream* stream = static_cast<PulseAudioOutputStream*>(p_this); 46 PulseAudioOutputStream* stream = static_cast<PulseAudioOutputStream*>(p_this);
22 47
23 // Forward unexpected failures to the AudioSourceCallback if available. All 48 // Forward unexpected failures to the AudioSourceCallback if available. All
24 // these variables are only modified under pa_threaded_mainloop_lock() so this 49 // these variables are only modified under pa_threaded_mainloop_lock() so this
25 // should be thread safe. 50 // should be thread safe.
26 if (s && stream->source_callback_ && 51 if (s && stream->source_callback_ &&
27 pa_stream_get_state(s) == PA_STREAM_FAILED) { 52 pa_stream_get_state(s) == PA_STREAM_FAILED) {
28 stream->source_callback_->OnError(stream); 53 stream->source_callback_->OnError(stream);
(...skipping 25 matching lines...) Expand all
54 } 79 }
55 80
56 PulseAudioOutputStream::~PulseAudioOutputStream() { 81 PulseAudioOutputStream::~PulseAudioOutputStream() {
57 // All internal structures should already have been freed in Close(), which 82 // All internal structures should already have been freed in Close(), which
58 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object. 83 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object.
59 DCHECK(!pa_stream_); 84 DCHECK(!pa_stream_);
60 DCHECK(!pa_context_); 85 DCHECK(!pa_context_);
61 DCHECK(!pa_mainloop_); 86 DCHECK(!pa_mainloop_);
62 } 87 }
63 88
89 void PulseAudioOutputStream::GetSystemDefaultOutputDevice() {
90 DCHECK(pa_mainloop_);
91 DCHECK(pa_context_);
92 pa_operation* operation = pa_context_get_server_info(
93 pa_context_, GetSystemDefaultOutputDeviceCallback, this);
94 WaitForOperationCompletion(pa_mainloop_, operation);
95 }
96
97 bool PulseAudioOutputStream::InitializeMainloopAndContext() {
98 DCHECK(!pa_mainloop_);
99 DCHECK(!pa_context_);
100 DCHECK(thread_checker_.CalledOnValidThread());
101 std::string app_name = AudioManager::GetGlobalAppName();
Henrik Grunell 2016/03/10 00:57:07 Move this line to just before where it's used (pa_
rchtara 2016/03/10 13:20:35 Done.
102 pa_mainloop_ = pa_threaded_mainloop_new();
103 RETURN_ON_FAILURE(pa_mainloop_, "Failed to create PulseAudio main loop.");
104
105 pa_mainloop_api* pa_mainloop_api = pa_threaded_mainloop_get_api(pa_mainloop_);
106 pa_context_ = pa_context_new(
107 pa_mainloop_api, app_name.empty() ? "Chromium" : app_name.c_str());
108 RETURN_ON_FAILURE(pa_context_, "Failed to create PulseAudio context.");
109
110 // A state callback must be set before calling pa_threaded_mainloop_lock() or
111 // pa_threaded_mainloop_wait() calls may lead to dead lock.
112 pa_context_set_state_callback(pa_context_, &pulse::ContextStateCallback,
113 pa_mainloop_);
114 {
115 // Lock the main loop while setting up the context. Failure to do so may
116 // lead to crashes as the PulseAudio thread tries to run before things are
117 // ready.
118 AutoPulseLock auto_lock(pa_mainloop_);
119
120 RETURN_ON_FAILURE(pa_threaded_mainloop_start(pa_mainloop_) == 0,
121 "Failed to start PulseAudio main loop.");
122 RETURN_ON_FAILURE(pa_context_connect(pa_context_, NULL,
123 PA_CONTEXT_NOAUTOSPAWN, NULL) == 0,
124 "Failed to connect PulseAudio context.");
125
126 // Wait until |pa_context_| is ready. pa_threaded_mainloop_wait() must be
127 // called after pa_context_get_state() in case the context is already ready,
128 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
129 while (true) {
130 pa_context_state_t context_state = pa_context_get_state(pa_context_);
131 RETURN_ON_FAILURE(PA_CONTEXT_IS_GOOD(context_state),
132 "Invalid PulseAudio context state.");
133 if (context_state == PA_CONTEXT_READY)
134 break;
135 pa_threaded_mainloop_wait(pa_mainloop_);
136 }
137 }
138
139 return true;
140 }
141
64 bool PulseAudioOutputStream::Open() { 142 bool PulseAudioOutputStream::Open() {
65 DCHECK(thread_checker_.CalledOnValidThread()); 143 std::string app_name = AudioManager::GetGlobalAppName();
144 std::string device_name_to_use;
145 if (!InitializeMainloopAndContext()) {
146 return false;
147 }
148
149 device_name_to_use = device_id_;
Henrik Grunell 2016/03/10 00:57:07 std::string device_name_to_use = device_id_; Then
rchtara 2016/03/10 13:20:35 Done.
150 if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
151 GetSystemDefaultOutputDevice();
Henrik Grunell 2016/03/10 00:57:07 I wonder if we should have the lock when calling t
rchtara 2016/03/10 13:20:35 I tied to use a lock before calling it but the bro
Henrik Grunell 2016/03/10 20:07:34 OK, what was the crash? And why doesn't it crash o
rchtara 2016/03/11 10:13:09 I rechecked it, and now it's working : the crash w
152 device_name_to_use = default_system_device_name_;
153 }
154
66 return pulse::CreateOutputStream( 155 return pulse::CreateOutputStream(
67 &pa_mainloop_, &pa_context_, &pa_stream_, params_, device_id_, 156 pa_mainloop_, pa_context_, &pa_stream_, params_, device_name_to_use,
68 AudioManager::GetGlobalAppName(), &StreamNotifyCallback, 157 app_name, &StreamNotifyCallback, &StreamRequestCallback, this);
Henrik Grunell 2016/03/10 00:57:07 Use AudioManager::GetGlobalAppName() here, remove
rchtara 2016/03/10 13:20:35 Done.
69 &StreamRequestCallback, this);
70 } 158 }
71 159
72 void PulseAudioOutputStream::Reset() { 160 void PulseAudioOutputStream::Reset() {
73 if (!pa_mainloop_) { 161 if (!pa_mainloop_) {
74 DCHECK(!pa_stream_); 162 DCHECK(!pa_stream_);
75 DCHECK(!pa_context_); 163 DCHECK(!pa_context_);
76 return; 164 return;
77 } 165 }
78 166
79 { 167 {
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 316
229 volume_ = static_cast<float>(volume); 317 volume_ = static_cast<float>(volume);
230 } 318 }
231 319
232 void PulseAudioOutputStream::GetVolume(double* volume) { 320 void PulseAudioOutputStream::GetVolume(double* volume) {
233 DCHECK(thread_checker_.CalledOnValidThread()); 321 DCHECK(thread_checker_.CalledOnValidThread());
234 322
235 *volume = volume_; 323 *volume = volume_;
236 } 324 }
237 325
326 pa_threaded_mainloop* PulseAudioOutputStream::GetPAMainloop() {
Henrik Grunell 2016/03/10 00:57:07 Put the function definitions in the same order as
rchtara 2016/03/10 13:20:35 They're not ordered as in the header. But I'm doin
Henrik Grunell 2016/03/10 20:07:34 Ah, OK. Well, best effort is fine then.
rchtara 2016/03/11 10:13:09 Done.
327 return pa_mainloop_;
328 }
329
330 void PulseAudioOutputStream::SetDefaultSystemDeviceName(
331 const std::string& name) {
332 default_system_device_name_ = name;
333 }
334
335 #undef RETURN_ON_FAILURE
336
238 } // namespace media 337 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698