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 (shouldPause && isActiveOutputDeviceAirPods())
|
||||||
{
|
{
|
||||||
if (m_mediaState == Playing)
|
if (getCurrentMediaState() == Playing)
|
||||||
{
|
{
|
||||||
pause();
|
pause();
|
||||||
}
|
}
|
||||||
@@ -172,7 +172,7 @@ void MediaController::setConnectedDeviceMacAddress(const QString &macAddress) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MediaController::MediaState MediaController::mediaStateFromPlayerctlOutput(
|
MediaController::MediaState MediaController::mediaStateFromPlayerctlOutput(
|
||||||
const QString &output) {
|
const QString &output) const {
|
||||||
if (output == "Playing") {
|
if (output == "Playing") {
|
||||||
return MediaState::Playing;
|
return MediaState::Playing;
|
||||||
} else if (output == "Paused") {
|
} 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
|
return mediaStateFromPlayerctlOutput(PlayerStatusWatcher::getCurrentPlaybackStatus(""));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaController::sendMediaPlayerCommand(const QString &method)
|
bool MediaController::sendMediaPlayerCommand(const QString &method)
|
||||||
{
|
{
|
||||||
QDBusInterface *iface = getMediaPlayerInterface();
|
// Connect to the session bus
|
||||||
if (!iface)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use QDBusMessage for more control and error handling
|
bool success = false;
|
||||||
QDBusMessage message = QDBusMessage::createMethodCall(
|
// Try each MPRIS service until one succeeds
|
||||||
iface->service(),
|
for (const QString &service : mprisServices)
|
||||||
iface->path(),
|
|
||||||
iface->interface(),
|
|
||||||
method);
|
|
||||||
|
|
||||||
QDBusPendingCall call = iface->connection().asyncCall(message);
|
|
||||||
call.waitForFinished();
|
|
||||||
|
|
||||||
if (call.isError())
|
|
||||||
{
|
{
|
||||||
LOG_ERROR("Failed to execute " << method << ": " << call.error().message());
|
QDBusInterface playerInterface(
|
||||||
delete iface;
|
service,
|
||||||
return false;
|
"/org/mpris/MediaPlayer2",
|
||||||
|
"org.mpris.MediaPlayer2.Player",
|
||||||
|
bus);
|
||||||
|
|
||||||
|
if (!playerInterface.isValid())
|
||||||
|
{
|
||||||
|
LOG_ERROR("Invalid DBus interface for service: " << service);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete iface;
|
// Send the Play or Pause command
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
LOG_ERROR("No media player responded successfully to " << method);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaController::play()
|
void MediaController::play()
|
||||||
|
|||||||
@@ -43,16 +43,15 @@ public:
|
|||||||
|
|
||||||
void play();
|
void play();
|
||||||
void pause();
|
void pause();
|
||||||
MediaState getCurrentMediaState() const { return m_mediaState; };
|
MediaState getCurrentMediaState() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void mediaStateChanged(MediaState state);
|
void mediaStateChanged(MediaState state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MediaState mediaStateFromPlayerctlOutput(const QString &output);
|
MediaState mediaStateFromPlayerctlOutput(const QString &output) const;
|
||||||
QString getAudioDeviceName();
|
QString getAudioDeviceName();
|
||||||
bool sendMediaPlayerCommand(const QString &method);
|
bool sendMediaPlayerCommand(const QString &method);
|
||||||
QDBusInterface *getMediaPlayerInterface();
|
|
||||||
|
|
||||||
bool wasPausedByApp = false;
|
bool wasPausedByApp = false;
|
||||||
int initialVolume = -1;
|
int initialVolume = -1;
|
||||||
@@ -60,7 +59,6 @@ private:
|
|||||||
EarDetectionBehavior earDetectionBehavior = PauseWhenOneRemoved;
|
EarDetectionBehavior earDetectionBehavior = PauseWhenOneRemoved;
|
||||||
QString m_deviceOutputName;
|
QString m_deviceOutputName;
|
||||||
PlayerStatusWatcher *playerStatusWatcher = nullptr;
|
PlayerStatusWatcher *playerStatusWatcher = nullptr;
|
||||||
MediaState m_mediaState = Stopped;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MEDIACONTROLLER_H
|
#endif // MEDIACONTROLLER_H
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <QDBusPendingReply>
|
#include <QDBusPendingReply>
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
#include <QDBusReply>
|
#include <QDBusReply>
|
||||||
|
#include <QDBusConnectionInterface>
|
||||||
|
|
||||||
PlayerStatusWatcher::PlayerStatusWatcher(const QString &playerService, QObject *parent)
|
PlayerStatusWatcher::PlayerStatusWatcher(const QString &playerService, QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
@@ -45,3 +46,25 @@ void PlayerStatusWatcher::onServiceOwnerChanged(const QString &name, const QStri
|
|||||||
updateStatus(); // player appeared/reappeared
|
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
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit PlayerStatusWatcher(const QString &playerService, QObject *parent = nullptr);
|
explicit PlayerStatusWatcher(const QString &playerService, QObject *parent = nullptr);
|
||||||
|
static QString getCurrentPlaybackStatus(const QString &playerService);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void playbackStatusChanged(const QString &status);
|
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