From 167f04a4dfab2b1d7834c7348185ce2b2ccb0dc8 Mon Sep 17 00:00:00 2001 From: Jay-716 <13422525511@163.com> Date: Thu, 25 Jan 2024 22:51:07 +0800 Subject: [PATCH 1/2] pulseaudio: reconnect context when pulseaudio server restarts When pulseaudio server restarts, the context is not reconnect automatically. So the pulseaudio module will stop updating. --- src/util/audio_backend.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/util/audio_backend.cpp b/src/util/audio_backend.cpp index 7eef1448..b7319d58 100644 --- a/src/util/audio_backend.cpp +++ b/src/util/audio_backend.cpp @@ -80,7 +80,22 @@ void AudioBackend::contextStateCb(pa_context *c, void *data) { nullptr, nullptr); break; case PA_CONTEXT_FAILED: - backend->mainloop_api_->quit(backend->mainloop_api_, 1); + // When pulseaudio server restarts, the connection is "failed". Try to reconnect. + // pa_threaded_mainloop_lock is already acquired in callback threads. + // So there is no need to lock it again. + if (backend->context_ != nullptr) { + pa_context_disconnect(backend->context_); + } + backend->context_ = pa_context_new(backend->mainloop_api_, "waybar"); + if (backend->context_ == nullptr) { + throw std::runtime_error("pa_context_new() failed."); + } + pa_context_set_state_callback(backend->context_, contextStateCb, data); + if (pa_context_connect(backend->context_, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) { + auto err = + fmt::format("pa_context_connect() failed: {}", pa_strerror(pa_context_errno(backend->context_))); + throw std::runtime_error(err); + } break; case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: From 14d168c254828cdb9b29b92fddc0f2634d656d0b Mon Sep 17 00:00:00 2001 From: Jay-716 <13422525511@163.com> Date: Sat, 27 Jan 2024 23:44:32 +0800 Subject: [PATCH 2/2] pulseaudio: extract context connecting into `connectContext()` --- include/util/audio_backend.hpp | 1 + src/util/audio_backend.cpp | 35 +++++++++++++++------------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/include/util/audio_backend.hpp b/include/util/audio_backend.hpp index 8d9b6f2f..2f53103e 100644 --- a/include/util/audio_backend.hpp +++ b/include/util/audio_backend.hpp @@ -22,6 +22,7 @@ class AudioBackend { static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data); static void serverInfoCb(pa_context*, const pa_server_info*, void*); static void volumeModifyCb(pa_context*, int, void*); + void connectContext(); pa_threaded_mainloop* mainloop_; pa_mainloop_api* mainloop_api_; diff --git a/src/util/audio_backend.cpp b/src/util/audio_backend.cpp index b7319d58..f4dd72c4 100644 --- a/src/util/audio_backend.cpp +++ b/src/util/audio_backend.cpp @@ -28,16 +28,7 @@ AudioBackend::AudioBackend(std::function on_updated_cb, private_construc } pa_threaded_mainloop_lock(mainloop_); mainloop_api_ = pa_threaded_mainloop_get_api(mainloop_); - context_ = pa_context_new(mainloop_api_, "waybar"); - if (context_ == nullptr) { - throw std::runtime_error("pa_context_new() failed."); - } - if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) { - auto err = - fmt::format("pa_context_connect() failed: {}", pa_strerror(pa_context_errno(context_))); - throw std::runtime_error(err); - } - pa_context_set_state_callback(context_, contextStateCb, this); + connectContext(); if (pa_threaded_mainloop_start(mainloop_) < 0) { throw std::runtime_error("pa_mainloop_run() failed."); } @@ -61,6 +52,19 @@ std::shared_ptr AudioBackend::getInstance(std::function on return std::make_shared(on_updated_cb, tag); } +void AudioBackend::connectContext() { + context_ = pa_context_new(mainloop_api_, "waybar"); + if (context_ == nullptr) { + throw std::runtime_error("pa_context_new() failed."); + } + pa_context_set_state_callback(context_, contextStateCb, this); + if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) { + auto err = + fmt::format("pa_context_connect() failed: {}", pa_strerror(pa_context_errno(context_))); + throw std::runtime_error(err); + } +} + void AudioBackend::contextStateCb(pa_context *c, void *data) { auto backend = static_cast(data); switch (pa_context_get_state(c)) { @@ -86,16 +90,7 @@ void AudioBackend::contextStateCb(pa_context *c, void *data) { if (backend->context_ != nullptr) { pa_context_disconnect(backend->context_); } - backend->context_ = pa_context_new(backend->mainloop_api_, "waybar"); - if (backend->context_ == nullptr) { - throw std::runtime_error("pa_context_new() failed."); - } - pa_context_set_state_callback(backend->context_, contextStateCb, data); - if (pa_context_connect(backend->context_, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) { - auto err = - fmt::format("pa_context_connect() failed: {}", pa_strerror(pa_context_errno(backend->context_))); - throw std::runtime_error(err); - } + backend->connectContext(); break; case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: