mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-01-28 22:01:50 +00:00
[Linux] DBus fixes
This commit is contained in:
committed by
Tim Gromeyer
parent
48ae249405
commit
91ffaaa972
@@ -44,7 +44,7 @@ void MediaController::handleEarDetection(EarDetection *earDetection)
|
||||
|
||||
if (shouldPause && isActiveOutputDeviceAirPods())
|
||||
{
|
||||
if (m_mediaState == Playing)
|
||||
if (getCurrentMediaState() == Playing)
|
||||
{
|
||||
pause();
|
||||
}
|
||||
@@ -172,7 +172,7 @@ void MediaController::setConnectedDeviceMacAddress(const QString &macAddress) {
|
||||
}
|
||||
|
||||
MediaController::MediaState MediaController::mediaStateFromPlayerctlOutput(
|
||||
const QString &output) {
|
||||
const QString &output) const {
|
||||
if (output == "Playing") {
|
||||
return MediaState::Playing;
|
||||
} else if (output == "Paused") {
|
||||
@@ -182,71 +182,77 @@ MediaController::MediaState MediaController::mediaStateFromPlayerctlOutput(
|
||||
}
|
||||
}
|
||||
|
||||
QDBusInterface *MediaController::getMediaPlayerInterface()
|
||||
MediaController::MediaState MediaController::getCurrentMediaState() const
|
||||
{
|
||||
// List all media player services
|
||||
QDBusConnection sessionBus = QDBusConnection::sessionBus();
|
||||
QDBusInterface dbusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus", sessionBus);
|
||||
QDBusReply<QStringList> reply = dbusInterface.call("ListNames");
|
||||
|
||||
if (!reply.isValid())
|
||||
{
|
||||
LOG_ERROR("Failed to list DBus services: " << reply.error().message());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QStringList services = reply.value();
|
||||
QString mediaPlayerService;
|
||||
|
||||
for (const QString &service : services)
|
||||
{
|
||||
if (service.startsWith("org.mpris.MediaPlayer2."))
|
||||
{
|
||||
mediaPlayerService = service;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mediaPlayerService.isEmpty())
|
||||
{
|
||||
LOG_DEBUG("No active media player found on DBus");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Found media player service: " << mediaPlayerService);
|
||||
return new QDBusInterface(mediaPlayerService, "/org/mpris/MediaPlayer2",
|
||||
"org.mpris.MediaPlayer2.Player", sessionBus, this);
|
||||
return mediaStateFromPlayerctlOutput(PlayerStatusWatcher::getCurrentPlaybackStatus(""));
|
||||
}
|
||||
|
||||
bool MediaController::sendMediaPlayerCommand(const QString &method)
|
||||
{
|
||||
QDBusInterface *iface = getMediaPlayerInterface();
|
||||
if (!iface)
|
||||
// Connect to the session bus
|
||||
QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
|
||||
// Find available MPRIS-compatible media players
|
||||
QStringList services = bus.interface()->registeredServiceNames().value();
|
||||
QStringList mprisServices;
|
||||
for (const QString &service : services)
|
||||
{
|
||||
LOG_ERROR("No media player interface available for " << method);
|
||||
if (service.startsWith("org.mpris.MediaPlayer2."))
|
||||
{
|
||||
mprisServices << service;
|
||||
}
|
||||
}
|
||||
|
||||
if (mprisServices.isEmpty())
|
||||
{
|
||||
LOG_ERROR("No MPRIS-compatible media players found on DBus");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use QDBusMessage for more control and error handling
|
||||
QDBusMessage message = QDBusMessage::createMethodCall(
|
||||
iface->service(),
|
||||
iface->path(),
|
||||
iface->interface(),
|
||||
method);
|
||||
|
||||
QDBusPendingCall call = iface->connection().asyncCall(message);
|
||||
call.waitForFinished();
|
||||
|
||||
if (call.isError())
|
||||
bool success = false;
|
||||
// Try each MPRIS service until one succeeds
|
||||
for (const QString &service : mprisServices)
|
||||
{
|
||||
LOG_ERROR("Failed to execute " << method << ": " << call.error().message());
|
||||
delete iface;
|
||||
return false;
|
||||
QDBusInterface playerInterface(
|
||||
service,
|
||||
"/org/mpris/MediaPlayer2",
|
||||
"org.mpris.MediaPlayer2.Player",
|
||||
bus);
|
||||
|
||||
if (!playerInterface.isValid())
|
||||
{
|
||||
LOG_ERROR("Invalid DBus interface for service: " << service);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Send the Play or Pause command
|
||||
if (method == "Play" || method == "Pause")
|
||||
{
|
||||
QDBusReply<void> reply = playerInterface.call(method);
|
||||
if (reply.isValid())
|
||||
{
|
||||
LOG_INFO("Successfully sent " << method << " to " << service);
|
||||
success = true;
|
||||
break; // Exit after the first successful command
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Failed to send " << method << " to " << service
|
||||
<< ": " << reply.error().message());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Unsupported method: " << method);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
delete iface;
|
||||
return true;
|
||||
if (!success)
|
||||
{
|
||||
LOG_ERROR("No media player responded successfully to " << method);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void MediaController::play()
|
||||
|
||||
@@ -43,16 +43,15 @@ public:
|
||||
|
||||
void play();
|
||||
void pause();
|
||||
MediaState getCurrentMediaState() const { return m_mediaState; };
|
||||
MediaState getCurrentMediaState() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void mediaStateChanged(MediaState state);
|
||||
|
||||
private:
|
||||
MediaState mediaStateFromPlayerctlOutput(const QString &output);
|
||||
MediaState mediaStateFromPlayerctlOutput(const QString &output) const;
|
||||
QString getAudioDeviceName();
|
||||
bool sendMediaPlayerCommand(const QString &method);
|
||||
QDBusInterface *getMediaPlayerInterface();
|
||||
|
||||
bool wasPausedByApp = false;
|
||||
int initialVolume = -1;
|
||||
@@ -60,7 +59,6 @@ private:
|
||||
EarDetectionBehavior earDetectionBehavior = PauseWhenOneRemoved;
|
||||
QString m_deviceOutputName;
|
||||
PlayerStatusWatcher *playerStatusWatcher = nullptr;
|
||||
MediaState m_mediaState = Stopped;
|
||||
};
|
||||
|
||||
#endif // MEDIACONTROLLER_H
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <QDBusPendingReply>
|
||||
#include <QVariantMap>
|
||||
#include <QDBusReply>
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
PlayerStatusWatcher::PlayerStatusWatcher(const QString &playerService, QObject *parent)
|
||||
: QObject(parent),
|
||||
@@ -44,4 +45,26 @@ void PlayerStatusWatcher::onServiceOwnerChanged(const QString &name, const QStri
|
||||
} else if (name == m_playerService && !newOwner.isEmpty()) {
|
||||
updateStatus(); // player appeared/reappeared
|
||||
}
|
||||
}
|
||||
|
||||
QString PlayerStatusWatcher::getCurrentPlaybackStatus(const QString &playerService)
|
||||
{
|
||||
QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
QStringList services = bus.interface()->registeredServiceNames().value();
|
||||
|
||||
for (const QString &service : services) {
|
||||
if (service.startsWith("org.mpris.MediaPlayer2.")) {
|
||||
QDBusInterface iface(service, "/org/mpris/MediaPlayer2",
|
||||
"org.mpris.MediaPlayer2.Player", bus);
|
||||
|
||||
if (iface.isValid()) {
|
||||
QVariant status = iface.property("PlaybackStatus");
|
||||
if (status.isValid() && status.toString() == "Playing") {
|
||||
return status.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
@@ -8,6 +8,7 @@ class PlayerStatusWatcher : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlayerStatusWatcher(const QString &playerService, QObject *parent = nullptr);
|
||||
static QString getCurrentPlaybackStatus(const QString &playerService);
|
||||
|
||||
signals:
|
||||
void playbackStatusChanged(const QString &status);
|
||||
|
||||
77
linux/playerstatuswatcher.cpp
Normal file
77
linux/playerstatuswatcher.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "media/playerstatuswatcher.h"
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QVariantMap>
|
||||
#include <QDBusReply>
|
||||
|
||||
PlayerStatusWatcher::PlayerStatusWatcher(const QString &playerService, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_playerService(playerService),
|
||||
m_iface(new QDBusInterface(playerService, "/org/mpris/MediaPlayer2",
|
||||
"org.mpris.MediaPlayer2.Player", QDBusConnection::sessionBus(), this)),
|
||||
m_serviceWatcher(new QDBusServiceWatcher(playerService, QDBusConnection::sessionBus(),
|
||||
QDBusServiceWatcher::WatchForOwnerChange, this))
|
||||
{
|
||||
// Register this object on the session bus to receive D-Bus messages
|
||||
QDBusConnection::sessionBus().registerObject("/PlayerStatusWatcher", this,
|
||||
QDBusConnection::ExportAllSlots);
|
||||
|
||||
QDBusConnection::sessionBus().connect(
|
||||
playerService, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged", this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))
|
||||
);
|
||||
connect(m_serviceWatcher, &QDBusServiceWatcher::serviceOwnerChanged,
|
||||
this, &PlayerStatusWatcher::onServiceOwnerChanged);
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
void PlayerStatusWatcher::onPropertiesChanged(const QString &interface,
|
||||
const QVariantMap &changed,
|
||||
const QStringList &)
|
||||
{
|
||||
// Get the service name of the sender
|
||||
QString sender = message().service();
|
||||
|
||||
// Skip if it's a KDE Connect player
|
||||
if (sender.contains("kdeconnect", Qt::CaseInsensitive)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (interface == "org.mpris.MediaPlayer2.Player" && changed.contains("PlaybackStatus")) {
|
||||
emit playbackStatusChanged(changed.value("PlaybackStatus").toString());
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerStatusWatcher::updateStatus() {
|
||||
QVariant reply = m_iface->property("PlaybackStatus");
|
||||
if (reply.isValid()) {
|
||||
emit playbackStatusChanged(reply.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerStatusWatcher::onServiceOwnerChanged(const QString &name, const QString &, const QString &newOwner)
|
||||
{
|
||||
if (name == m_playerService && newOwner.isEmpty()) {
|
||||
emit playbackStatusChanged(""); // player disappeared
|
||||
} else if (name == m_playerService && !newOwner.isEmpty()) {
|
||||
updateStatus(); // player appeared/reappeared
|
||||
}
|
||||
}
|
||||
|
||||
QString PlayerStatusWatcher::getCurrentPlaybackStatus(const QString &playerService)
|
||||
{
|
||||
QDBusInterface iface(
|
||||
playerService,
|
||||
"/org/mpris/MediaPlayer2",
|
||||
"org.mpris.MediaPlayer2.Player",
|
||||
QDBusConnection::sessionBus());
|
||||
QVariant reply = iface.property("PlaybackStatus");
|
||||
if (reply.isValid())
|
||||
{
|
||||
return reply.toString(); // "Playing", "Paused", "Stopped"
|
||||
}
|
||||
else
|
||||
{
|
||||
return QString(); // or handle error as needed
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user