MPRTIS change to async

This commit is contained in:
Mathew-D
2026-05-10 12:40:02 -04:00
parent 4d70b4f5c3
commit c6196335fd
2 changed files with 131 additions and 78 deletions
+56 -28
View File
@@ -742,12 +742,18 @@ bool MprisService::seek(const std::string& busName, int64_t offsetUs) {
}
try {
proxyIt->second->callMethod("Seek").onInterface(k_mpris_player_interface).withArguments(offsetUs);
proxyIt->second->callMethodAsync("Seek")
.onInterface(k_mpris_player_interface)
.withArguments(offsetUs)
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
if (err.has_value()) {
kLog.warn("seek failed name={} err={}", busName, err->what());
}
});
m_lastSeekCommandAt[busName] = std::chrono::steady_clock::now();
addOrRefreshPlayer(busName);
return true;
} catch (const sdbus::Error& e) {
kLog.warn("seek failed name={} err={}", busName, e.what());
kLog.warn("seek dispatch failed name={} err={}", busName, e.what());
return false;
}
}
@@ -772,14 +778,7 @@ bool MprisService::setPosition(const std::string& busName, int64_t positionUs) {
}
auto fallback_seek = [&]() {
int64_t currentPositionUs = it->second.positionUs;
try {
const sdbus::Variant positionValue =
proxyIt->second->getProperty("Position").onInterface(k_mpris_player_interface);
currentPositionUs = positionValue.get<int64_t>();
} catch (const sdbus::Error& e) {
kLog.warn("position refresh failed name={} err={}, using cached value", busName, e.what());
}
const int64_t currentPositionUs = it->second.positionUs;
const int64_t offsetUs = positionUs - currentPositionUs;
if (offsetUs == 0) {
@@ -796,14 +795,18 @@ bool MprisService::setPosition(const std::string& busName, int64_t positionUs) {
}
try {
proxyIt->second->callMethod("SetPosition")
proxyIt->second->callMethodAsync("SetPosition")
.onInterface(k_mpris_player_interface)
.withArguments(sdbus::ObjectPath{it->second.trackId}, positionUs);
.withArguments(sdbus::ObjectPath{it->second.trackId}, positionUs)
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
if (err.has_value()) {
kLog.warn("set-position failed name={} err={}", busName, err->what());
}
});
m_lastSeekCommandAt[busName] = std::chrono::steady_clock::now();
addOrRefreshPlayer(busName);
return true;
} catch (const sdbus::Error& e) {
kLog.warn("set-position failed name={} err={}, falling back to Seek", busName, e.what());
kLog.warn("set-position dispatch failed name={} err={}, falling back to Seek", busName, e.what());
return fallback_seek();
}
}
@@ -828,11 +831,17 @@ bool MprisService::setVolume(const std::string& busName, double volume) {
}
try {
proxyIt->second->setProperty("Volume").onInterface(k_mpris_player_interface).toValue(volume);
addOrRefreshPlayer(busName);
proxyIt->second->callMethodAsync("Set")
.onInterface(k_properties_interface)
.withArguments(std::string{k_mpris_player_interface}, std::string{"Volume"}, sdbus::Variant{volume})
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
if (err.has_value()) {
kLog.warn("set-volume failed name={} err={}", busName, err->what());
}
});
return true;
} catch (const sdbus::Error& e) {
kLog.warn("set-volume failed name={} err={}", busName, e.what());
kLog.warn("set-volume dispatch failed name={} err={}", busName, e.what());
return false;
}
}
@@ -857,11 +866,17 @@ bool MprisService::setShuffle(const std::string& busName, bool shuffle) {
}
try {
proxyIt->second->setProperty("Shuffle").onInterface(k_mpris_player_interface).toValue(shuffle);
addOrRefreshPlayer(busName);
proxyIt->second->callMethodAsync("Set")
.onInterface(k_properties_interface)
.withArguments(std::string{k_mpris_player_interface}, std::string{"Shuffle"}, sdbus::Variant{shuffle})
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
if (err.has_value()) {
kLog.warn("set-shuffle failed name={} err={}", busName, err->what());
}
});
return true;
} catch (const sdbus::Error& e) {
kLog.warn("set-shuffle failed name={} err={}", busName, e.what());
kLog.warn("set-shuffle dispatch failed name={} err={}", busName, e.what());
return false;
}
}
@@ -886,11 +901,18 @@ bool MprisService::setLoopStatus(const std::string& busName, std::string loopSta
}
try {
proxyIt->second->setProperty("LoopStatus").onInterface(k_mpris_player_interface).toValue(std::move(loopStatus));
addOrRefreshPlayer(busName);
proxyIt->second->callMethodAsync("Set")
.onInterface(k_properties_interface)
.withArguments(std::string{k_mpris_player_interface}, std::string{"LoopStatus"},
sdbus::Variant{std::move(loopStatus)})
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
if (err.has_value()) {
kLog.warn("set-loop-status failed name={} err={}", busName, err->what());
}
});
return true;
} catch (const sdbus::Error& e) {
kLog.warn("set-loop-status failed name={} err={}", busName, e.what());
kLog.warn("set-loop-status dispatch failed name={} err={}", busName, e.what());
return false;
}
}
@@ -1801,12 +1823,18 @@ bool MprisService::callPlayerMethod(const std::string& busName, const char* meth
}
try {
it->second->callMethod(methodName).onInterface(k_mpris_player_interface);
addOrRefreshPlayer(busName);
kLog.debug("control name={} method={}", busName, methodName);
it->second->callMethodAsync(methodName)
.onInterface(k_mpris_player_interface)
.uponReplyInvoke([busName, methodName](std::optional<sdbus::Error> err) {
if (err.has_value()) {
kLog.warn("control failed name={} method={} err={}", busName, methodName, err->what());
return;
}
kLog.debug("control name={} method={}", busName, methodName);
});
return true;
} catch (const sdbus::Error& e) {
kLog.warn("control failed name={} method={} err={}", busName, methodName, e.what());
kLog.warn("control dispatch failed name={} method={} err={}", busName, methodName, e.what());
return false;
}
}
+75 -50
View File
@@ -1,5 +1,6 @@
#include "shell/control_center/media_tab.h"
#include "core/deferred_call.h"
#include "core/log.h"
#include "dbus/mpris/mpris_art.h"
#include "dbus/mpris/mpris_service.h"
@@ -271,16 +272,17 @@ std::unique_ptr<Flex> MediaTab::create() {
m_pendingSeekUs = targetUs;
m_pendingSeekUntil = now + std::chrono::milliseconds(3000);
bool seekIssued = false;
if (!seekBusName.empty()) {
seekIssued = m_mpris->setPosition(seekBusName, targetUs);
} else {
seekIssued = m_mpris->setPositionActive(targetUs);
}
if (!seekIssued) {
// Keep the thumb stable briefly even if transport seek dispatch races.
m_pendingSeekUntil = now + std::chrono::milliseconds(750);
}
DeferredCall::callLater([this, seekBusName, targetUs]() {
if (m_mpris == nullptr) {
return;
}
if (!seekBusName.empty()) {
(void)m_mpris->setPosition(seekBusName, targetUs);
} else {
(void)m_mpris->setPositionActive(targetUs);
}
PanelManager::instance().refresh();
});
});
m_progressSlider = progress.get();
mediaStack->addChild(std::move(progress));
@@ -305,13 +307,15 @@ std::unique_ptr<Flex> MediaTab::create() {
repeat->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
repeat->setRadius(Style::radiusLg * scale);
repeat->setOnClick([this]() {
if (m_mpris == nullptr) {
return;
}
const auto current = m_mpris->loopStatusActive().value_or("None");
const std::string next = current == "None" ? "Playlist" : (current == "Playlist" ? "Track" : "None");
m_mpris->setLoopStatusActive(next);
PanelManager::instance().refresh();
DeferredCall::callLater([this]() {
if (m_mpris == nullptr) {
return;
}
const auto current = m_mpris->loopStatusActive().value_or("None");
const std::string next = current == "None" ? "Playlist" : (current == "Playlist" ? "Track" : "None");
(void)m_mpris->setLoopStatusActive(next);
PanelManager::instance().refresh();
});
});
m_repeatButton = repeat.get();
controls->addChild(std::move(repeat));
@@ -324,10 +328,12 @@ std::unique_ptr<Flex> MediaTab::create() {
previous->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
previous->setRadius(Style::radiusLg * scale);
previous->setOnClick([this]() {
if (m_mpris != nullptr) {
m_mpris->previousActive();
PanelManager::instance().refresh();
}
DeferredCall::callLater([this]() {
if (m_mpris != nullptr) {
(void)m_mpris->previousActive();
PanelManager::instance().refresh();
}
});
});
m_prevButton = previous.get();
controls->addChild(std::move(previous));
@@ -340,10 +346,12 @@ std::unique_ptr<Flex> MediaTab::create() {
playPause->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
playPause->setRadius(Style::radiusLg * scale);
playPause->setOnClick([this]() {
if (m_mpris != nullptr) {
m_mpris->playPauseActive();
PanelManager::instance().refresh();
}
DeferredCall::callLater([this]() {
if (m_mpris != nullptr) {
(void)m_mpris->playPauseActive();
PanelManager::instance().refresh();
}
});
});
m_playPauseButton = playPause.get();
controls->addChild(std::move(playPause));
@@ -356,10 +364,12 @@ std::unique_ptr<Flex> MediaTab::create() {
next->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
next->setRadius(Style::radiusLg * scale);
next->setOnClick([this]() {
if (m_mpris != nullptr) {
m_mpris->nextActive();
PanelManager::instance().refresh();
}
DeferredCall::callLater([this]() {
if (m_mpris != nullptr) {
(void)m_mpris->nextActive();
PanelManager::instance().refresh();
}
});
});
m_nextButton = next.get();
controls->addChild(std::move(next));
@@ -372,11 +382,13 @@ std::unique_ptr<Flex> MediaTab::create() {
shuffle->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
shuffle->setRadius(Style::radiusLg * scale);
shuffle->setOnClick([this]() {
if (m_mpris != nullptr) {
const bool enabled = m_mpris->shuffleActive().value_or(false);
m_mpris->setShuffleActive(!enabled);
PanelManager::instance().refresh();
}
DeferredCall::callLater([this]() {
if (m_mpris != nullptr) {
const bool enabled = m_mpris->shuffleActive().value_or(false);
(void)m_mpris->setShuffleActive(!enabled);
PanelManager::instance().refresh();
}
});
});
m_shuffleButton = shuffle.get();
controls->addChild(std::move(shuffle));
@@ -419,17 +431,20 @@ std::unique_ptr<Flex> MediaTab::create() {
if (m_wayland != nullptr && m_renderContext != nullptr) {
m_playerMenuPopup = std::make_unique<ContextMenuPopup>(*m_wayland, *m_renderContext);
m_playerMenuPopup->setOnActivate([this](const ContextMenuControlEntry& entry) {
if (m_mpris == nullptr) {
return;
}
if (entry.id == 0) {
m_mpris->clearPinnedPlayerPreference();
} else {
const std::size_t idx = static_cast<std::size_t>(entry.id - 1);
if (idx < m_playerBusNames.size()) {
m_mpris->setPinnedPlayerPreference(m_playerBusNames[idx]);
DeferredCall::callLater([this, entry]() {
if (m_mpris == nullptr) {
return;
}
}
if (entry.id == 0) {
m_mpris->clearPinnedPlayerPreference();
} else {
const std::size_t idx = static_cast<std::size_t>(entry.id - 1);
if (idx < m_playerBusNames.size()) {
m_mpris->setPinnedPlayerPreference(m_playerBusNames[idx]);
}
}
PanelManager::instance().refresh();
});
});
}
@@ -603,7 +618,14 @@ void MediaTab::setActive(bool active) {
// Pull a fresh snapshot (including Position) when the tab opens so the
// progress slider starts at the current playback position.
m_positionSampleAt = {};
m_mpris->refreshPlayers();
DeferredCall::callLater([this]() {
if (m_mpris == nullptr) {
return;
}
m_mpris->refreshPlayers();
PanelManager::instance().requestUpdateOnly();
PanelManager::instance().requestRedraw();
});
m_lastMprisRefreshAttempt = std::chrono::steady_clock::now();
}
}
@@ -676,11 +698,14 @@ void MediaTab::refresh(Renderer& renderer) {
if (shouldRetryMpris) {
m_lastMprisRefreshAttempt = now;
kLog.debug("media tab retrying mpris discovery players={} active={}", players.size(), active.has_value());
m_mpris->refreshPlayers();
players = m_mpris->listPlayers();
active = m_mpris->activePlayer();
kLog.debug("media tab refresh after retry players={} active={} active_bus=\"{}\"", players.size(),
active.has_value(), active.has_value() ? active->busName : std::string{});
DeferredCall::callLater([this]() {
if (m_mpris == nullptr) {
return;
}
m_mpris->refreshPlayers();
PanelManager::instance().requestUpdateOnly();
PanelManager::instance().requestRedraw();
});
}
}