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

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: 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 media { 14 namespace media {
15 15
16 using pulse::AutoPulseLock; 16 using pulse::AutoPulseLock;
17 using pulse::WaitForOperationCompletion; 17 using pulse::WaitForOperationCompletion;
18 18
19 // Helper function to avoid code spam and string bloat.
20 // Return true if |expression| is true, otherwise return false and print
21 // |message|.
22 inline bool LogOnFailure(bool expression, const char* message) {
23 do {
tommi (sloooow) - chröme 2016/03/19 13:44:17 Since this is now a function and not a macro, the
rchtara 2016/03/22 16:45:49 Done.
24 if (!(expression)) {
25 DLOG(ERROR) << message;
26 return false;
27 }
28 } while (0);
29 return true;
30 }
31
19 // static, pa_stream_notify_cb 32 // static, pa_stream_notify_cb
20 void PulseAudioOutputStream::StreamNotifyCallback(pa_stream* s, void* p_this) { 33 void PulseAudioOutputStream::StreamNotifyCallback(pa_stream* s, void* p_this) {
21 PulseAudioOutputStream* stream = static_cast<PulseAudioOutputStream*>(p_this); 34 PulseAudioOutputStream* stream = static_cast<PulseAudioOutputStream*>(p_this);
22 35
23 // Forward unexpected failures to the AudioSourceCallback if available. All 36 // Forward unexpected failures to the AudioSourceCallback if available. All
24 // these variables are only modified under pa_threaded_mainloop_lock() so this 37 // these variables are only modified under pa_threaded_mainloop_lock() so this
25 // should be thread safe. 38 // should be thread safe.
26 if (s && stream->source_callback_ && 39 if (s && stream->source_callback_ &&
27 pa_stream_get_state(s) == PA_STREAM_FAILED) { 40 pa_stream_get_state(s) == PA_STREAM_FAILED) {
28 stream->source_callback_->OnError(stream); 41 stream->source_callback_->OnError(stream);
(...skipping 25 matching lines...) Expand all
54 } 67 }
55 68
56 PulseAudioOutputStream::~PulseAudioOutputStream() { 69 PulseAudioOutputStream::~PulseAudioOutputStream() {
57 // All internal structures should already have been freed in Close(), which 70 // All internal structures should already have been freed in Close(), which
58 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object. 71 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object.
59 DCHECK(!pa_stream_); 72 DCHECK(!pa_stream_);
60 DCHECK(!pa_context_); 73 DCHECK(!pa_context_);
61 DCHECK(!pa_mainloop_); 74 DCHECK(!pa_mainloop_);
62 } 75 }
63 76
77 bool PulseAudioOutputStream::InitializeMainloopAndContext() {
78 DCHECK(!pa_mainloop_);
79 DCHECK(!pa_context_);
80 DCHECK(thread_checker_.CalledOnValidThread());
81 pa_mainloop_ = pa_threaded_mainloop_new();
82 if (!LogOnFailure(pa_mainloop_, "Failed to create PulseAudio main loop.")) {
tommi (sloooow) - chröme 2016/03/19 13:44:17 It's a little misleading to check the return value
rchtara 2016/03/22 16:45:49 Done.
83 return false;
84 }
85
86 pa_mainloop_api* pa_mainloop_api = pa_threaded_mainloop_get_api(pa_mainloop_);
87 std::string app_name = AudioManager::GetGlobalAppName();
88 pa_context_ = pa_context_new(
89 pa_mainloop_api, app_name.empty() ? "Chromium" : app_name.c_str());
90 if (!LogOnFailure(pa_context_, "Failed to create PulseAudio context.")) {
91 return false;
92 }
93
94 // A state callback must be set before calling pa_threaded_mainloop_lock() or
95 // pa_threaded_mainloop_wait() calls may lead to dead lock.
96 pa_context_set_state_callback(pa_context_, &pulse::ContextStateCallback,
97 pa_mainloop_);
98 {
99 // Lock the main loop while setting up the context. Failure to do so may
100 // lead to crashes as the PulseAudio thread tries to run before things are
101 // ready.
102 AutoPulseLock auto_lock(pa_mainloop_);
103
104 if (!LogOnFailure(pa_threaded_mainloop_start(pa_mainloop_) == 0,
105 "Failed to start PulseAudio main loop.")) {
106 return false;
107 }
108
109 if (!LogOnFailure(pa_context_connect(pa_context_, NULL,
110 PA_CONTEXT_NOAUTOSPAWN, NULL) == 0,
111 "Failed to connect PulseAudio context.")) {
112 return false;
113 }
114
115 // Wait until |pa_context_| is ready. pa_threaded_mainloop_wait() must be
116 // called after pa_context_get_state() in case the context is already ready,
117 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
118 while (true) {
119 pa_context_state_t context_state = pa_context_get_state(pa_context_);
120 if (!LogOnFailure(PA_CONTEXT_IS_GOOD(context_state),
121 "Invalid PulseAudio context state.")) {
122 return false;
123 }
124
125 if (context_state == PA_CONTEXT_READY)
126 break;
127 pa_threaded_mainloop_wait(pa_mainloop_);
128 }
129 }
130
131 return true;
132 }
133
134 // static, used by pa_context_get_server_info.
135 void PulseAudioOutputStream::GetSystemDefaultOutputDeviceCallback(
136 pa_context* context,
137 const pa_server_info* info,
138 void* user_data) {
139 media::PulseAudioOutputStream* stream =
140 static_cast<media::PulseAudioOutputStream*>(user_data);
141 stream->default_system_device_name_ = info->default_sink_name;
142 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
143 }
144
145 void PulseAudioOutputStream::GetSystemDefaultOutputDevice() {
146 DCHECK(pa_mainloop_);
147 DCHECK(pa_context_);
148 pa_operation* operation = pa_context_get_server_info(
149 pa_context_, PulseAudioOutputStream::GetSystemDefaultOutputDeviceCallback,
150 this);
151 WaitForOperationCompletion(pa_mainloop_, operation);
152 }
153
64 bool PulseAudioOutputStream::Open() { 154 bool PulseAudioOutputStream::Open() {
65 DCHECK(thread_checker_.CalledOnValidThread()); 155 if (!InitializeMainloopAndContext()) {
156 return false;
157 }
158
159 AutoPulseLock auto_lock(pa_mainloop_);
160
161 std::string device_name_to_use = device_id_;
162 if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
163 GetSystemDefaultOutputDevice();
164 device_name_to_use = default_system_device_name_;
165 }
166
66 return pulse::CreateOutputStream( 167 return pulse::CreateOutputStream(
67 &pa_mainloop_, &pa_context_, &pa_stream_, params_, device_id_, 168 pa_mainloop_, pa_context_, &pa_stream_, params_, device_name_to_use,
68 AudioManager::GetGlobalAppName(), &StreamNotifyCallback, 169 AudioManager::GetGlobalAppName(), &StreamNotifyCallback,
69 &StreamRequestCallback, this); 170 &StreamRequestCallback, this);
70 } 171 }
71 172
72 void PulseAudioOutputStream::Reset() { 173 void PulseAudioOutputStream::Reset() {
73 if (!pa_mainloop_) { 174 if (!pa_mainloop_) {
74 DCHECK(!pa_stream_); 175 DCHECK(!pa_stream_);
75 DCHECK(!pa_context_); 176 DCHECK(!pa_context_);
76 return; 177 return;
77 } 178 }
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 volume_ = static_cast<float>(volume); 330 volume_ = static_cast<float>(volume);
230 } 331 }
231 332
232 void PulseAudioOutputStream::GetVolume(double* volume) { 333 void PulseAudioOutputStream::GetVolume(double* volume) {
233 DCHECK(thread_checker_.CalledOnValidThread()); 334 DCHECK(thread_checker_.CalledOnValidThread());
234 335
235 *volume = volume_; 336 *volume = volume_;
236 } 337 }
237 338
238 } // namespace media 339 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698