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

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

Issue 1806313003: Pass task runners to AudioManager constructor. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: removed AudioManagerBase::Shutdown Created 4 years, 8 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/audio_manager_pulse.h" 5 #include "media/audio/pulse/audio_manager_pulse.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/environment.h" 8 #include "base/environment.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 29 matching lines...) Expand all
40 static const int kMaximumOutputBufferSize = 8192; 40 static const int kMaximumOutputBufferSize = 8192;
41 41
42 // Default input buffer size. 42 // Default input buffer size.
43 static const int kDefaultInputBufferSize = 1024; 43 static const int kDefaultInputBufferSize = 1024;
44 44
45 #if defined(DLOPEN_PULSEAUDIO) 45 #if defined(DLOPEN_PULSEAUDIO)
46 static const base::FilePath::CharType kPulseLib[] = 46 static const base::FilePath::CharType kPulseLib[] =
47 FILE_PATH_LITERAL("libpulse.so.0"); 47 FILE_PATH_LITERAL("libpulse.so.0");
48 #endif 48 #endif
49 49
50 // static 50 namespace {
51 AudioManager* AudioManagerPulse::Create(AudioLogFactory* audio_log_factory) { 51 void DestroyPulse(pa_threaded_mainloop* input_mainloop,
52 scoped_ptr<AudioManagerPulse> ret(new AudioManagerPulse(audio_log_factory)); 52 pa_context* input_context) {
53 if (ret->Init()) 53 DCHECK(input_mainloop);
54 return ret.release();
55 54
56 DVLOG(1) << "PulseAudio is not available on the OS"; 55 {
57 return NULL; 56 AutoPulseLock auto_lock(input_mainloop);
57 if (input_context) {
58 // Clear our state callback.
59 pa_context_set_state_callback(input_context, NULL, NULL);
60 pa_context_disconnect(input_context);
61 pa_context_unref(input_context);
62 }
63 }
64
65 pa_threaded_mainloop_stop(input_mainloop);
66 pa_threaded_mainloop_free(input_mainloop);
58 } 67 }
59 68
60 AudioManagerPulse::AudioManagerPulse(AudioLogFactory* audio_log_factory) 69 bool InitPulse(pa_threaded_mainloop** input_mainloop,
61 : AudioManagerBase(audio_log_factory), 70 pa_context** input_context) {
71 #if defined(DLOPEN_PULSEAUDIO)
72 StubPathMap paths;
73
74 // Check if the pulse library is avialbale.
75 paths[kModulePulse].push_back(kPulseLib);
76 if (!InitializeStubs(paths)) {
77 VLOG(1) << "Failed on loading the Pulse library and symbols";
78 return false;
79 }
80 #endif // defined(DLOPEN_PULSEAUDIO)
81
82 // Create a mainloop API and connect to the default server.
83 // The mainloop is the internal asynchronous API event loop.
84 pa_threaded_mainloop* mainloop = pa_threaded_mainloop_new();
85 if (!mainloop)
86 return false;
87
88 // Start the threaded mainloop.
89 if (pa_threaded_mainloop_start(mainloop)) {
90 DestroyPulse(mainloop, nullptr);
91 return false;
92 }
93
94 // Lock the event loop object, effectively blocking the event loop thread
95 // from processing events. This is necessary.
96 AutoPulseLock auto_lock(mainloop);
97
98 pa_mainloop_api* mainloop_api = pa_threaded_mainloop_get_api(mainloop);
99 pa_context* context = pa_context_new(mainloop_api, "Chrome input");
100 if (!context) {
101 DestroyPulse(mainloop, nullptr);
102 return false;
103 }
104
105 pa_context_set_state_callback(context, &pulse::ContextStateCallback,
106 mainloop);
107 if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
108 VLOG(1) << "Failed to connect to the context. Error: "
109 << pa_strerror(pa_context_errno(context));
110 DestroyPulse(mainloop, context);
111 return false;
112 }
113
114 // Wait until |input_context_| is ready. pa_threaded_mainloop_wait() must be
115 // called after pa_context_get_state() in case the context is already ready,
116 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
117 while (true) {
118 pa_context_state_t context_state = pa_context_get_state(context);
119 if (!PA_CONTEXT_IS_GOOD(context_state)) {
120 DestroyPulse(mainloop, context);
121 return false;
122 }
123 if (context_state == PA_CONTEXT_READY)
124 break;
125 pa_threaded_mainloop_wait(mainloop);
126 }
127
128 *input_mainloop = mainloop;
129 *input_context = context;
130 return true;
131 }
132 } // namespace
133
134 AudioManagerPulse::AudioManagerPulse(
135 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
136 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
137 AudioLogFactory* audio_log_factory)
138 : AudioManagerBase(std::move(task_runner),
139 std::move(worker_task_runner),
140 audio_log_factory),
62 input_mainloop_(NULL), 141 input_mainloop_(NULL),
63 input_context_(NULL), 142 input_context_(NULL),
64 devices_(NULL), 143 devices_(NULL),
65 native_input_sample_rate_(0) { 144 native_input_sample_rate_(0) {
66 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 145 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
67 } 146 }
68 147
69 AudioManagerPulse::~AudioManagerPulse() { 148 AudioManagerPulse::~AudioManagerPulse() {
70 Shutdown(); 149 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
150 // Do not destroy pulse here since AudioManagerBase destructor needs it.
151 if (input_mainloop_) {
152 GetTaskRunner()->PostTask(
153 FROM_HERE, base::Bind(&DestroyPulse, input_mainloop_, input_context_));
154 } else {
155 DCHECK(!input_context_);
156 }
157 }
71 158
72 // The Pulse objects are the last things to be destroyed since Shutdown() 159 bool AudioManagerPulse::Init() {
73 // needs them. 160 DCHECK(!input_mainloop_);
74 DestroyPulse(); 161 // TODO(alokp): Investigate if InitPulse can happen on the audio thread.
162 // It currently needs to happen on the main thread so that is InitPulse fails,
163 // we can fallback to ALSA implementation. Initializing it on audio thread
164 // would unblock the main thread and make InitPulse consistent with
165 // DestroyPulse which happens on the audio thread.
166 return InitPulse(&input_mainloop_, &input_context_);
75 } 167 }
76 168
77 // Implementation of AudioManager. 169 // Implementation of AudioManager.
78 bool AudioManagerPulse::HasAudioOutputDevices() { 170 bool AudioManagerPulse::HasAudioOutputDevices() {
79 AudioDeviceNames devices; 171 AudioDeviceNames devices;
80 GetAudioOutputDeviceNames(&devices); 172 GetAudioOutputDeviceNames(&devices);
81 return !devices.empty(); 173 return !devices.empty();
82 } 174 }
83 175
84 bool AudioManagerPulse::HasAudioInputDevices() { 176 bool AudioManagerPulse::HasAudioInputDevices() {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 DCHECK(input_mainloop_); 302 DCHECK(input_mainloop_);
211 DCHECK(input_context_); 303 DCHECK(input_context_);
212 AutoPulseLock auto_lock(input_mainloop_); 304 AutoPulseLock auto_lock(input_mainloop_);
213 pa_operation* operation = pa_context_get_server_info( 305 pa_operation* operation = pa_context_get_server_info(
214 input_context_, SampleRateInfoCallback, this); 306 input_context_, SampleRateInfoCallback, this);
215 WaitForOperationCompletion(input_mainloop_, operation); 307 WaitForOperationCompletion(input_mainloop_, operation);
216 308
217 return native_input_sample_rate_; 309 return native_input_sample_rate_;
218 } 310 }
219 311
220 bool AudioManagerPulse::Init() {
221 DCHECK(!input_mainloop_);
222
223 #if defined(DLOPEN_PULSEAUDIO)
224 StubPathMap paths;
225
226 // Check if the pulse library is avialbale.
227 paths[kModulePulse].push_back(kPulseLib);
228 if (!InitializeStubs(paths)) {
229 VLOG(1) << "Failed on loading the Pulse library and symbols";
230 return false;
231 }
232 #endif // defined(DLOPEN_PULSEAUDIO)
233
234 // Create a mainloop API and connect to the default server.
235 // The mainloop is the internal asynchronous API event loop.
236 input_mainloop_ = pa_threaded_mainloop_new();
237 if (!input_mainloop_)
238 return false;
239
240 // Start the threaded mainloop.
241 if (pa_threaded_mainloop_start(input_mainloop_))
242 return false;
243
244 // Lock the event loop object, effectively blocking the event loop thread
245 // from processing events. This is necessary.
246 AutoPulseLock auto_lock(input_mainloop_);
247
248 pa_mainloop_api* pa_mainloop_api =
249 pa_threaded_mainloop_get_api(input_mainloop_);
250 input_context_ = pa_context_new(pa_mainloop_api, "Chrome input");
251 if (!input_context_)
252 return false;
253
254 pa_context_set_state_callback(input_context_, &pulse::ContextStateCallback,
255 input_mainloop_);
256 if (pa_context_connect(input_context_, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
257 VLOG(1) << "Failed to connect to the context. Error: "
258 << pa_strerror(pa_context_errno(input_context_));
259 return false;
260 }
261
262 // Wait until |input_context_| is ready. pa_threaded_mainloop_wait() must be
263 // called after pa_context_get_state() in case the context is already ready,
264 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
265 while (true) {
266 pa_context_state_t context_state = pa_context_get_state(input_context_);
267 if (!PA_CONTEXT_IS_GOOD(context_state))
268 return false;
269 if (context_state == PA_CONTEXT_READY)
270 break;
271 pa_threaded_mainloop_wait(input_mainloop_);
272 }
273
274 return true;
275 }
276
277 void AudioManagerPulse::DestroyPulse() {
278 if (!input_mainloop_) {
279 DCHECK(!input_context_);
280 return;
281 }
282
283 {
284 AutoPulseLock auto_lock(input_mainloop_);
285 if (input_context_) {
286 // Clear our state callback.
287 pa_context_set_state_callback(input_context_, NULL, NULL);
288 pa_context_disconnect(input_context_);
289 pa_context_unref(input_context_);
290 input_context_ = NULL;
291 }
292 }
293
294 pa_threaded_mainloop_stop(input_mainloop_);
295 pa_threaded_mainloop_free(input_mainloop_);
296 input_mainloop_ = NULL;
297 }
298
299 void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context, 312 void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
300 const pa_source_info* info, 313 const pa_source_info* info,
301 int error, void *user_data) { 314 int error, void *user_data) {
302 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data); 315 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
303 316
304 if (error) { 317 if (error) {
305 // Signal the pulse object that it is done. 318 // Signal the pulse object that it is done.
306 pa_threaded_mainloop_signal(manager->input_mainloop_, 0); 319 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
307 return; 320 return;
308 } 321 }
(...skipping 23 matching lines...) Expand all
332 void AudioManagerPulse::SampleRateInfoCallback(pa_context* context, 345 void AudioManagerPulse::SampleRateInfoCallback(pa_context* context,
333 const pa_server_info* info, 346 const pa_server_info* info,
334 void* user_data) { 347 void* user_data) {
335 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data); 348 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
336 349
337 manager->native_input_sample_rate_ = info->sample_spec.rate; 350 manager->native_input_sample_rate_ = info->sample_spec.rate;
338 pa_threaded_mainloop_signal(manager->input_mainloop_, 0); 351 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
339 } 352 }
340 353
341 } // namespace media 354 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698