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

Unified Diff: media/audio/pulse/pulse_util.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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/audio/pulse/pulse_util.h ('k') | media/audio/sounds/audio_stream_handler_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/audio/pulse/pulse_util.cc
diff --git a/media/audio/pulse/pulse_util.cc b/media/audio/pulse/pulse_util.cc
index ba4d4bed83757c8135d7d7c9da1b47a02f43f6f5..438d4c8d68dfdca959ce532de4deef83aafbc505 100644
--- a/media/audio/pulse/pulse_util.cc
+++ b/media/audio/pulse/pulse_util.cc
@@ -6,12 +6,22 @@
#include <stdint.h>
+#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "media/audio/audio_device_description.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_timestamp_helper.h"
+#if defined(DLOPEN_PULSEAUDIO)
+#include "media/audio/pulse/pulse_stubs.h"
+
+using media_audio_pulse::kModulePulse;
+using media_audio_pulse::InitializeStubs;
+using media_audio_pulse::StubPathMap;
+#endif // defined(DLOPEN_PULSEAUDIO)
+
namespace media {
namespace pulse {
@@ -24,6 +34,22 @@ static const char kBrowserDisplayName[] = "google-chrome";
static const char kBrowserDisplayName[] = "chromium-browser";
#endif
+#if defined(DLOPEN_PULSEAUDIO)
+static const base::FilePath::CharType kPulseLib[] =
+ FILE_PATH_LITERAL("libpulse.so.0");
+#endif
+
+void DestroyMainloop(pa_threaded_mainloop* mainloop) {
+ pa_threaded_mainloop_stop(mainloop);
+ pa_threaded_mainloop_free(mainloop);
+}
+
+void DestroyContext(pa_context* context) {
+ pa_context_set_state_callback(context, NULL, NULL);
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+}
+
pa_channel_position ChromiumToPAChannelPosition(Channels channel) {
switch (channel) {
// PulseAudio does not differentiate between left/right and
@@ -70,6 +96,87 @@ class ScopedPropertyList {
} // namespace
+bool InitPulse(pa_threaded_mainloop** mainloop, pa_context** 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* pa_mainloop = pa_threaded_mainloop_new();
+ if (!pa_mainloop)
+ return false;
+
+ // Start the threaded mainloop.
+ if (pa_threaded_mainloop_start(pa_mainloop)) {
+ pa_threaded_mainloop_free(pa_mainloop);
+ return false;
+ }
+
+ // Lock the event loop object, effectively blocking the event loop thread
+ // from processing events. This is necessary.
+ auto mainloop_lock = base::MakeUnique<AutoPulseLock>(pa_mainloop);
+
+ pa_mainloop_api* pa_mainloop_api = pa_threaded_mainloop_get_api(pa_mainloop);
+ pa_context* pa_context = pa_context_new(pa_mainloop_api, "Chrome input");
+ if (!pa_context) {
+ mainloop_lock.reset();
+ DestroyMainloop(pa_mainloop);
+ return false;
+ }
+
+ pa_context_set_state_callback(pa_context, &pulse::ContextStateCallback,
+ pa_mainloop);
+ if (pa_context_connect(pa_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) {
+ VLOG(1) << "Failed to connect to the context. Error: "
+ << pa_strerror(pa_context_errno(pa_context));
+ pa_context_set_state_callback(pa_context, NULL, NULL);
+ pa_context_unref(pa_context);
+ mainloop_lock.reset();
+ DestroyMainloop(pa_mainloop);
+ return false;
+ }
+
+ // Wait until |pa_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(pa_context);
+ if (!PA_CONTEXT_IS_GOOD(context_state)) {
+ DestroyContext(pa_context);
+ mainloop_lock.reset();
+ DestroyMainloop(pa_mainloop);
+ return false;
+ }
+ if (context_state == PA_CONTEXT_READY)
+ break;
+ pa_threaded_mainloop_wait(pa_mainloop);
+ }
+
+ *mainloop = pa_mainloop;
+ *context = pa_context;
+ return true;
+}
+
+void DestroyPulse(pa_threaded_mainloop* mainloop, pa_context* context) {
+ DCHECK(mainloop);
+ DCHECK(context);
+
+ {
+ AutoPulseLock auto_lock(mainloop);
+ DestroyContext(context);
+ }
+
+ DestroyMainloop(mainloop);
+}
+
// static, pa_stream_success_cb_t
void StreamSuccessCallback(pa_stream* s, int error, void* mainloop) {
pa_threaded_mainloop* pa_mainloop =
« no previous file with comments | « media/audio/pulse/pulse_util.h ('k') | media/audio/sounds/audio_stream_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698