Merge pull request #2866 from Jay-716/pa-reconnect

pulseaudio: reconnect context when pulseaudio server restarts
This commit is contained in:
Alexis Rouillard 2024-01-28 17:04:57 +01:00 committed by GitHub
commit ddad6ce136
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 11 deletions

View File

@ -22,6 +22,7 @@ class AudioBackend {
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data); 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 serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*); static void volumeModifyCb(pa_context*, int, void*);
void connectContext();
pa_threaded_mainloop* mainloop_; pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_; pa_mainloop_api* mainloop_api_;

View File

@ -28,16 +28,7 @@ AudioBackend::AudioBackend(std::function<void()> on_updated_cb, private_construc
} }
pa_threaded_mainloop_lock(mainloop_); pa_threaded_mainloop_lock(mainloop_);
mainloop_api_ = pa_threaded_mainloop_get_api(mainloop_); mainloop_api_ = pa_threaded_mainloop_get_api(mainloop_);
context_ = pa_context_new(mainloop_api_, "waybar"); connectContext();
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);
if (pa_threaded_mainloop_start(mainloop_) < 0) { if (pa_threaded_mainloop_start(mainloop_) < 0) {
throw std::runtime_error("pa_mainloop_run() failed."); throw std::runtime_error("pa_mainloop_run() failed.");
} }
@ -61,6 +52,19 @@ std::shared_ptr<AudioBackend> AudioBackend::getInstance(std::function<void()> on
return std::make_shared<AudioBackend>(on_updated_cb, tag); return std::make_shared<AudioBackend>(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) { void AudioBackend::contextStateCb(pa_context *c, void *data) {
auto backend = static_cast<AudioBackend *>(data); auto backend = static_cast<AudioBackend *>(data);
switch (pa_context_get_state(c)) { switch (pa_context_get_state(c)) {
@ -80,7 +84,13 @@ void AudioBackend::contextStateCb(pa_context *c, void *data) {
nullptr, nullptr); nullptr, nullptr);
break; break;
case PA_CONTEXT_FAILED: 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->connectContext();
break; break;
case PA_CONTEXT_CONNECTING: case PA_CONTEXT_CONNECTING:
case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_AUTHORIZING: