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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: media/audio/pulse/audio_manager_pulse.cc
diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc
index d6e9543183a0f86c8130b1459f8cd6a65e54ef2d..e9e27707a8c17848742d9492258942d12c7879c7 100644
--- a/media/audio/pulse/audio_manager_pulse.cc
+++ b/media/audio/pulse/audio_manager_pulse.cc
@@ -47,18 +47,97 @@ static const base::FilePath::CharType kPulseLib[] =
FILE_PATH_LITERAL("libpulse.so.0");
#endif
-// static
-AudioManager* AudioManagerPulse::Create(AudioLogFactory* audio_log_factory) {
- scoped_ptr<AudioManagerPulse> ret(new AudioManagerPulse(audio_log_factory));
- if (ret->Init())
- return ret.release();
-
- DVLOG(1) << "PulseAudio is not available on the OS";
- return NULL;
+namespace {
+void DestroyPulse(pa_threaded_mainloop* input_mainloop,
+ pa_context* input_context) {
+ DCHECK(input_mainloop);
+
+ {
+ AutoPulseLock auto_lock(input_mainloop);
+ if (input_context) {
+ // Clear our state callback.
+ pa_context_set_state_callback(input_context, NULL, NULL);
+ pa_context_disconnect(input_context);
+ pa_context_unref(input_context);
+ }
+ }
+
+ pa_threaded_mainloop_stop(input_mainloop);
+ pa_threaded_mainloop_free(input_mainloop);
}
-AudioManagerPulse::AudioManagerPulse(AudioLogFactory* audio_log_factory)
- : AudioManagerBase(audio_log_factory),
+bool InitPulse(pa_threaded_mainloop** input_mainloop,
+ pa_context** input_context) {
+#if defined(DLOPEN_PULSEAUDIO)
+ StubPathMap paths;
+
+ // Check if the pulse library is avialbale.
+ paths[kModulePulse].push_back(kPulseLib);
+ if (!InitializeStubs(paths)) {
+ VLOG(1) << "Failed on loading the Pulse library and symbols";
+ return false;
+ }
+#endif // defined(DLOPEN_PULSEAUDIO)
+
+ // Create a mainloop API and connect to the default server.
+ // The mainloop is the internal asynchronous API event loop.
+ pa_threaded_mainloop* mainloop = pa_threaded_mainloop_new();
+ if (!mainloop)
+ return false;
+
+ // Start the threaded mainloop.
+ if (pa_threaded_mainloop_start(mainloop)) {
+ DestroyPulse(mainloop, nullptr);
+ return false;
+ }
+
+ // Lock the event loop object, effectively blocking the event loop thread
+ // from processing events. This is necessary.
+ AutoPulseLock auto_lock(mainloop);
+
+ pa_mainloop_api* mainloop_api = pa_threaded_mainloop_get_api(mainloop);
+ pa_context* context = pa_context_new(mainloop_api, "Chrome input");
+ if (!context) {
+ DestroyPulse(mainloop, nullptr);
+ return false;
+ }
+
+ pa_context_set_state_callback(context, &pulse::ContextStateCallback,
+ mainloop);
+ if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
+ VLOG(1) << "Failed to connect to the context. Error: "
+ << pa_strerror(pa_context_errno(context));
+ DestroyPulse(mainloop, context);
+ return false;
+ }
+
+ // Wait until |input_context_| is ready. pa_threaded_mainloop_wait() must be
+ // called after pa_context_get_state() in case the context is already ready,
+ // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
+ while (true) {
+ pa_context_state_t context_state = pa_context_get_state(context);
+ if (!PA_CONTEXT_IS_GOOD(context_state)) {
+ DestroyPulse(mainloop, context);
+ return false;
+ }
+ if (context_state == PA_CONTEXT_READY)
+ break;
+ pa_threaded_mainloop_wait(mainloop);
+ }
+
+ *input_mainloop = mainloop;
+ *input_context = context;
+ return true;
+}
+} // namespace
+
+AudioManagerPulse::AudioManagerPulse(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
+ AudioLogFactory* audio_log_factory)
+ : AudioManagerBase(std::move(task_runner),
+ std::move(worker_task_runner),
+ audio_log_factory),
input_mainloop_(NULL),
input_context_(NULL),
devices_(NULL),
@@ -67,11 +146,24 @@ AudioManagerPulse::AudioManagerPulse(AudioLogFactory* audio_log_factory)
}
AudioManagerPulse::~AudioManagerPulse() {
- Shutdown();
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ // Do not destroy pulse here since AudioManagerBase destructor needs it.
+ if (input_mainloop_) {
+ GetTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&DestroyPulse, input_mainloop_, input_context_));
+ } else {
+ DCHECK(!input_context_);
+ }
+}
- // The Pulse objects are the last things to be destroyed since Shutdown()
- // needs them.
- DestroyPulse();
+bool AudioManagerPulse::Init() {
+ DCHECK(!input_mainloop_);
+ // TODO(alokp): Investigate if InitPulse can happen on the audio thread.
+ // It currently needs to happen on the main thread so that is InitPulse fails,
+ // we can fallback to ALSA implementation. Initializing it on audio thread
+ // would unblock the main thread and make InitPulse consistent with
+ // DestroyPulse which happens on the audio thread.
+ return InitPulse(&input_mainloop_, &input_context_);
}
// Implementation of AudioManager.
@@ -217,85 +309,6 @@ int AudioManagerPulse::GetNativeSampleRate() {
return native_input_sample_rate_;
}
-bool AudioManagerPulse::Init() {
- DCHECK(!input_mainloop_);
-
-#if defined(DLOPEN_PULSEAUDIO)
- StubPathMap paths;
-
- // Check if the pulse library is avialbale.
- paths[kModulePulse].push_back(kPulseLib);
- if (!InitializeStubs(paths)) {
- VLOG(1) << "Failed on loading the Pulse library and symbols";
- return false;
- }
-#endif // defined(DLOPEN_PULSEAUDIO)
-
- // Create a mainloop API and connect to the default server.
- // The mainloop is the internal asynchronous API event loop.
- input_mainloop_ = pa_threaded_mainloop_new();
- if (!input_mainloop_)
- return false;
-
- // Start the threaded mainloop.
- if (pa_threaded_mainloop_start(input_mainloop_))
- return false;
-
- // Lock the event loop object, effectively blocking the event loop thread
- // from processing events. This is necessary.
- AutoPulseLock auto_lock(input_mainloop_);
-
- pa_mainloop_api* pa_mainloop_api =
- pa_threaded_mainloop_get_api(input_mainloop_);
- input_context_ = pa_context_new(pa_mainloop_api, "Chrome input");
- if (!input_context_)
- return false;
-
- pa_context_set_state_callback(input_context_, &pulse::ContextStateCallback,
- input_mainloop_);
- if (pa_context_connect(input_context_, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
- VLOG(1) << "Failed to connect to the context. Error: "
- << pa_strerror(pa_context_errno(input_context_));
- return false;
- }
-
- // Wait until |input_context_| is ready. pa_threaded_mainloop_wait() must be
- // called after pa_context_get_state() in case the context is already ready,
- // otherwise pa_threaded_mainloop_wait() will hang indefinitely.
- while (true) {
- pa_context_state_t context_state = pa_context_get_state(input_context_);
- if (!PA_CONTEXT_IS_GOOD(context_state))
- return false;
- if (context_state == PA_CONTEXT_READY)
- break;
- pa_threaded_mainloop_wait(input_mainloop_);
- }
-
- return true;
-}
-
-void AudioManagerPulse::DestroyPulse() {
- if (!input_mainloop_) {
- DCHECK(!input_context_);
- return;
- }
-
- {
- AutoPulseLock auto_lock(input_mainloop_);
- if (input_context_) {
- // Clear our state callback.
- pa_context_set_state_callback(input_context_, NULL, NULL);
- pa_context_disconnect(input_context_);
- pa_context_unref(input_context_);
- input_context_ = NULL;
- }
- }
-
- pa_threaded_mainloop_stop(input_mainloop_);
- pa_threaded_mainloop_free(input_mainloop_);
- input_mainloop_ = NULL;
-}
-
void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
const pa_source_info* info,
int error, void *user_data) {

Powered by Google App Engine
This is Rietveld 408576698