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

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

Issue 2784433002: Ensures that audio tasks cannot run after AudioManager is deleted. (Closed)
Patch Set: rebase Created 3 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/audio_manager_pulse.h ('k') | media/audio/pulse/pulse_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
10 #include "base/logging.h" 9 #include "base/logging.h"
11 #include "base/nix/xdg_util.h" 10 #include "base/nix/xdg_util.h"
12 #include "base/stl_util.h" 11 #include "base/stl_util.h"
13 #if defined(USE_ALSA) 12 #if defined(USE_ALSA)
14 #include "media/audio/alsa/audio_manager_alsa.h" 13 #include "media/audio/alsa/audio_manager_alsa.h"
15 #endif 14 #endif
16 #include "media/audio/audio_device_description.h" 15 #include "media/audio/audio_device_description.h"
17 #include "media/audio/pulse/pulse_input.h" 16 #include "media/audio/pulse/pulse_input.h"
18 #include "media/audio/pulse/pulse_output.h" 17 #include "media/audio/pulse/pulse_output.h"
19 #include "media/audio/pulse/pulse_util.h" 18 #include "media/audio/pulse/pulse_util.h"
20 #include "media/base/audio_parameters.h" 19 #include "media/base/audio_parameters.h"
21 #include "media/base/channel_layout.h" 20 #include "media/base/channel_layout.h"
22 21
23 #if defined(DLOPEN_PULSEAUDIO)
24 #include "media/audio/pulse/pulse_stubs.h"
25
26 using media_audio_pulse::kModulePulse;
27 using media_audio_pulse::InitializeStubs;
28 using media_audio_pulse::StubPathMap;
29 #endif // defined(DLOPEN_PULSEAUDIO)
30
31 namespace media { 22 namespace media {
32 23
33 using pulse::AutoPulseLock; 24 using pulse::AutoPulseLock;
34 using pulse::WaitForOperationCompletion; 25 using pulse::WaitForOperationCompletion;
35 26
36 // Maximum number of output streams that can be open simultaneously. 27 // Maximum number of output streams that can be open simultaneously.
37 static const int kMaxOutputStreams = 50; 28 static const int kMaxOutputStreams = 50;
38 29
39 // Define bounds for the output buffer size. 30 // Define bounds for the output buffer size.
40 static const int kMinimumOutputBufferSize = 512; 31 static const int kMinimumOutputBufferSize = 512;
41 static const int kMaximumOutputBufferSize = 8192; 32 static const int kMaximumOutputBufferSize = 8192;
42 33
43 // Default input buffer size. 34 // Default input buffer size.
44 static const int kDefaultInputBufferSize = 1024; 35 static const int kDefaultInputBufferSize = 1024;
45 36
46 #if defined(DLOPEN_PULSEAUDIO) 37 AudioManagerPulse::AudioManagerPulse(std::unique_ptr<AudioThread> audio_thread,
47 static const base::FilePath::CharType kPulseLib[] = 38 AudioLogFactory* audio_log_factory,
48 FILE_PATH_LITERAL("libpulse.so.0"); 39 pa_threaded_mainloop* pa_mainloop,
49 #endif 40 pa_context* pa_context)
50 41 : AudioManagerBase(std::move(audio_thread), audio_log_factory),
51 AudioManagerPulse::AudioManagerPulse( 42 input_mainloop_(pa_mainloop),
52 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 43 input_context_(pa_context),
53 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
54 AudioLogFactory* audio_log_factory)
55 : AudioManagerBase(std::move(task_runner),
56 std::move(worker_task_runner),
57 audio_log_factory),
58 input_mainloop_(NULL),
59 input_context_(NULL),
60 devices_(NULL), 44 devices_(NULL),
61 native_input_sample_rate_(0), 45 native_input_sample_rate_(0),
62 native_channel_count_(0) { 46 native_channel_count_(0) {
47 DCHECK(input_mainloop_);
48 DCHECK(input_context_);
63 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 49 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
64 } 50 }
65 51
66 AudioManagerPulse::~AudioManagerPulse() { 52 AudioManagerPulse::~AudioManagerPulse() = default;
67 Shutdown(); 53
68 // The Pulse objects are the last things to be destroyed since Shutdown() 54 void AudioManagerPulse::ShutdownOnAudioThread() {
69 // needs them. 55 AudioManagerBase::ShutdownOnAudioThread();
70 DestroyPulse(); 56 // The Pulse objects are the last things to be destroyed since
57 // AudioManagerBase::ShutdownOnAudioThread() needs them.
58 pulse::DestroyPulse(input_mainloop_, input_context_);
71 } 59 }
72 60
73 bool AudioManagerPulse::Init() {
74 // TODO(alokp): Investigate if InitPulse can happen on the audio thread.
75 // It currently needs to happen on the main thread so that is InitPulse fails,
76 // we can fallback to ALSA implementation. Initializing it on audio thread
77 // would unblock the main thread and make InitPulse consistent with
78 // DestroyPulse which happens on the audio thread.
79 return InitPulse();
80 }
81
82 // Implementation of AudioManager.
83 bool AudioManagerPulse::HasAudioOutputDevices() { 61 bool AudioManagerPulse::HasAudioOutputDevices() {
84 AudioDeviceNames devices; 62 AudioDeviceNames devices;
85 GetAudioOutputDeviceNames(&devices); 63 GetAudioOutputDeviceNames(&devices);
86 return !devices.empty(); 64 return !devices.empty();
87 } 65 }
88 66
89 bool AudioManagerPulse::HasAudioInputDevices() { 67 bool AudioManagerPulse::HasAudioInputDevices() {
90 AudioDeviceNames devices; 68 AudioDeviceNames devices;
91 GetAudioInputDeviceNames(&devices); 69 GetAudioInputDeviceNames(&devices);
92 return !devices.empty(); 70 return !devices.empty();
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 204
227 void AudioManagerPulse::UpdateNativeAudioHardwareInfo() { 205 void AudioManagerPulse::UpdateNativeAudioHardwareInfo() {
228 DCHECK(input_mainloop_); 206 DCHECK(input_mainloop_);
229 DCHECK(input_context_); 207 DCHECK(input_context_);
230 AutoPulseLock auto_lock(input_mainloop_); 208 AutoPulseLock auto_lock(input_mainloop_);
231 pa_operation* operation = pa_context_get_server_info( 209 pa_operation* operation = pa_context_get_server_info(
232 input_context_, AudioHardwareInfoCallback, this); 210 input_context_, AudioHardwareInfoCallback, this);
233 WaitForOperationCompletion(input_mainloop_, operation); 211 WaitForOperationCompletion(input_mainloop_, operation);
234 } 212 }
235 213
236 bool AudioManagerPulse::InitPulse() {
237 DCHECK(!input_mainloop_);
238
239 #if defined(DLOPEN_PULSEAUDIO)
240 StubPathMap paths;
241
242 // Check if the pulse library is avialbale.
243 paths[kModulePulse].push_back(kPulseLib);
244 if (!InitializeStubs(paths)) {
245 VLOG(1) << "Failed on loading the Pulse library and symbols";
246 return false;
247 }
248 #endif // defined(DLOPEN_PULSEAUDIO)
249
250 // Create a mainloop API and connect to the default server.
251 // The mainloop is the internal asynchronous API event loop.
252 input_mainloop_ = pa_threaded_mainloop_new();
253 if (!input_mainloop_)
254 return false;
255
256 // Start the threaded mainloop.
257 if (pa_threaded_mainloop_start(input_mainloop_))
258 return false;
259
260 // Lock the event loop object, effectively blocking the event loop thread
261 // from processing events. This is necessary.
262 AutoPulseLock auto_lock(input_mainloop_);
263
264 pa_mainloop_api* pa_mainloop_api =
265 pa_threaded_mainloop_get_api(input_mainloop_);
266 input_context_ = pa_context_new(pa_mainloop_api, "Chrome input");
267 if (!input_context_)
268 return false;
269
270 pa_context_set_state_callback(input_context_, &pulse::ContextStateCallback,
271 input_mainloop_);
272 if (pa_context_connect(input_context_, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
273 VLOG(1) << "Failed to connect to the context. Error: "
274 << pa_strerror(pa_context_errno(input_context_));
275 return false;
276 }
277
278 // Wait until |input_context_| is ready. pa_threaded_mainloop_wait() must be
279 // called after pa_context_get_state() in case the context is already ready,
280 // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
281 while (true) {
282 pa_context_state_t context_state = pa_context_get_state(input_context_);
283 if (!PA_CONTEXT_IS_GOOD(context_state))
284 return false;
285 if (context_state == PA_CONTEXT_READY)
286 break;
287 pa_threaded_mainloop_wait(input_mainloop_);
288 }
289
290 return true;
291 }
292
293 void AudioManagerPulse::DestroyPulse() {
294 if (!input_mainloop_) {
295 DCHECK(!input_context_);
296 return;
297 }
298
299 {
300 AutoPulseLock auto_lock(input_mainloop_);
301 if (input_context_) {
302 // Clear our state callback.
303 pa_context_set_state_callback(input_context_, NULL, NULL);
304 pa_context_disconnect(input_context_);
305 pa_context_unref(input_context_);
306 input_context_ = NULL;
307 }
308 }
309
310 pa_threaded_mainloop_stop(input_mainloop_);
311 pa_threaded_mainloop_free(input_mainloop_);
312 input_mainloop_ = NULL;
313 }
314
315 void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context, 214 void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
316 const pa_source_info* info, 215 const pa_source_info* info,
317 int error, void *user_data) { 216 int error, void *user_data) {
318 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data); 217 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
319 218
320 if (error) { 219 if (error) {
321 // Signal the pulse object that it is done. 220 // Signal the pulse object that it is done.
322 pa_threaded_mainloop_signal(manager->input_mainloop_, 0); 221 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
323 return; 222 return;
324 } 223 }
(...skipping 24 matching lines...) Expand all
349 const pa_server_info* info, 248 const pa_server_info* info,
350 void* user_data) { 249 void* user_data) {
351 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data); 250 AudioManagerPulse* manager = reinterpret_cast<AudioManagerPulse*>(user_data);
352 251
353 manager->native_input_sample_rate_ = info->sample_spec.rate; 252 manager->native_input_sample_rate_ = info->sample_spec.rate;
354 manager->native_channel_count_ = info->sample_spec.channels; 253 manager->native_channel_count_ = info->sample_spec.channels;
355 pa_threaded_mainloop_signal(manager->input_mainloop_, 0); 254 pa_threaded_mainloop_signal(manager->input_mainloop_, 0);
356 } 255 }
357 256
358 } // namespace media 257 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/pulse/audio_manager_pulse.h ('k') | media/audio/pulse/pulse_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698