Skip to content

Commit 91ffaaa

Browse files
committed
[Linux] DBus fixes
1 parent 48ae249 commit 91ffaaa

5 files changed

Lines changed: 157 additions & 52 deletions

File tree

linux/media/mediacontroller.cpp

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void MediaController::handleEarDetection(EarDetection *earDetection)
4444

4545
if (shouldPause && isActiveOutputDeviceAirPods())
4646
{
47-
if (m_mediaState == Playing)
47+
if (getCurrentMediaState() == Playing)
4848
{
4949
pause();
5050
}
@@ -172,7 +172,7 @@ void MediaController::setConnectedDeviceMacAddress(const QString &macAddress) {
172172
}
173173

174174
MediaController::MediaState MediaController::mediaStateFromPlayerctlOutput(
175-
const QString &output) {
175+
const QString &output) const {
176176
if (output == "Playing") {
177177
return MediaState::Playing;
178178
} else if (output == "Paused") {
@@ -182,71 +182,77 @@ MediaController::MediaState MediaController::mediaStateFromPlayerctlOutput(
182182
}
183183
}
184184

185-
QDBusInterface *MediaController::getMediaPlayerInterface()
185+
MediaController::MediaState MediaController::getCurrentMediaState() const
186186
{
187-
// List all media player services
188-
QDBusConnection sessionBus = QDBusConnection::sessionBus();
189-
QDBusInterface dbusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus",
190-
"org.freedesktop.DBus", sessionBus);
191-
QDBusReply<QStringList> reply = dbusInterface.call("ListNames");
192-
193-
if (!reply.isValid())
194-
{
195-
LOG_ERROR("Failed to list DBus services: " << reply.error().message());
196-
return nullptr;
197-
}
187+
return mediaStateFromPlayerctlOutput(PlayerStatusWatcher::getCurrentPlaybackStatus(""));
188+
}
198189

199-
QStringList services = reply.value();
200-
QString mediaPlayerService;
190+
bool MediaController::sendMediaPlayerCommand(const QString &method)
191+
{
192+
// Connect to the session bus
193+
QDBusConnection bus = QDBusConnection::sessionBus();
201194

195+
// Find available MPRIS-compatible media players
196+
QStringList services = bus.interface()->registeredServiceNames().value();
197+
QStringList mprisServices;
202198
for (const QString &service : services)
203199
{
204200
if (service.startsWith("org.mpris.MediaPlayer2."))
205201
{
206-
mediaPlayerService = service;
207-
break;
202+
mprisServices << service;
208203
}
209204
}
210205

211-
if (mediaPlayerService.isEmpty())
206+
if (mprisServices.isEmpty())
212207
{
213-
LOG_DEBUG("No active media player found on DBus");
214-
return nullptr;
208+
LOG_ERROR("No MPRIS-compatible media players found on DBus");
209+
return false;
215210
}
216211

217-
LOG_DEBUG("Found media player service: " << mediaPlayerService);
218-
return new QDBusInterface(mediaPlayerService, "/org/mpris/MediaPlayer2",
219-
"org.mpris.MediaPlayer2.Player", sessionBus, this);
220-
}
221-
222-
bool MediaController::sendMediaPlayerCommand(const QString &method)
223-
{
224-
QDBusInterface *iface = getMediaPlayerInterface();
225-
if (!iface)
212+
bool success = false;
213+
// Try each MPRIS service until one succeeds
214+
for (const QString &service : mprisServices)
226215
{
227-
LOG_ERROR("No media player interface available for " << method);
228-
return false;
229-
}
216+
QDBusInterface playerInterface(
217+
service,
218+
"/org/mpris/MediaPlayer2",
219+
"org.mpris.MediaPlayer2.Player",
220+
bus);
230221

231-
// Use QDBusMessage for more control and error handling
232-
QDBusMessage message = QDBusMessage::createMethodCall(
233-
iface->service(),
234-
iface->path(),
235-
iface->interface(),
236-
method);
222+
if (!playerInterface.isValid())
223+
{
224+
LOG_ERROR("Invalid DBus interface for service: " << service);
225+
continue;
226+
}
237227

238-
QDBusPendingCall call = iface->connection().asyncCall(message);
239-
call.waitForFinished();
228+
// Send the Play or Pause command
229+
if (method == "Play" || method == "Pause")
230+
{
231+
QDBusReply<void> reply = playerInterface.call(method);
232+
if (reply.isValid())
233+
{
234+
LOG_INFO("Successfully sent " << method << " to " << service);
235+
success = true;
236+
break; // Exit after the first successful command
237+
}
238+
else
239+
{
240+
LOG_ERROR("Failed to send " << method << " to " << service
241+
<< ": " << reply.error().message());
242+
}
243+
}
244+
else
245+
{
246+
LOG_ERROR("Unsupported method: " << method);
247+
return false;
248+
}
249+
}
240250

241-
if (call.isError())
251+
if (!success)
242252
{
243-
LOG_ERROR("Failed to execute " << method << ": " << call.error().message());
244-
delete iface;
245-
return false;
253+
LOG_ERROR("No media player responded successfully to " << method);
246254
}
247-
248-
delete iface;
249-
return true;
255+
return success;
250256
}
251257

252258
void MediaController::play()

linux/media/mediacontroller.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,22 @@ class MediaController : public QObject
4343

4444
void play();
4545
void pause();
46-
MediaState getCurrentMediaState() const { return m_mediaState; };
46+
MediaState getCurrentMediaState() const;
4747

4848
Q_SIGNALS:
4949
void mediaStateChanged(MediaState state);
5050

5151
private:
52-
MediaState mediaStateFromPlayerctlOutput(const QString &output);
52+
MediaState mediaStateFromPlayerctlOutput(const QString &output) const;
5353
QString getAudioDeviceName();
5454
bool sendMediaPlayerCommand(const QString &method);
55-
QDBusInterface *getMediaPlayerInterface();
5655

5756
bool wasPausedByApp = false;
5857
int initialVolume = -1;
5958
QString connectedDeviceMacAddress;
6059
EarDetectionBehavior earDetectionBehavior = PauseWhenOneRemoved;
6160
QString m_deviceOutputName;
6261
PlayerStatusWatcher *playerStatusWatcher = nullptr;
63-
MediaState m_mediaState = Stopped;
6462
};
6563

6664
#endif // MEDIACONTROLLER_H

linux/media/playerstatuswatcher.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <QDBusPendingReply>
44
#include <QVariantMap>
55
#include <QDBusReply>
6+
#include <QDBusConnectionInterface>
67

78
PlayerStatusWatcher::PlayerStatusWatcher(const QString &playerService, QObject *parent)
89
: QObject(parent),
@@ -44,4 +45,26 @@ void PlayerStatusWatcher::onServiceOwnerChanged(const QString &name, const QStri
4445
} else if (name == m_playerService && !newOwner.isEmpty()) {
4546
updateStatus(); // player appeared/reappeared
4647
}
48+
}
49+
50+
QString PlayerStatusWatcher::getCurrentPlaybackStatus(const QString &playerService)
51+
{
52+
QDBusConnection bus = QDBusConnection::sessionBus();
53+
QStringList services = bus.interface()->registeredServiceNames().value();
54+
55+
for (const QString &service : services) {
56+
if (service.startsWith("org.mpris.MediaPlayer2.")) {
57+
QDBusInterface iface(service, "/org/mpris/MediaPlayer2",
58+
"org.mpris.MediaPlayer2.Player", bus);
59+
60+
if (iface.isValid()) {
61+
QVariant status = iface.property("PlaybackStatus");
62+
if (status.isValid() && status.toString() == "Playing") {
63+
return status.toString();
64+
}
65+
}
66+
}
67+
}
68+
69+
return QString();
4770
}

linux/media/playerstatuswatcher.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class PlayerStatusWatcher : public QObject {
88
Q_OBJECT
99
public:
1010
explicit PlayerStatusWatcher(const QString &playerService, QObject *parent = nullptr);
11+
static QString getCurrentPlaybackStatus(const QString &playerService);
1112

1213
signals:
1314
void playbackStatusChanged(const QString &status);

linux/playerstatuswatcher.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#include "media/playerstatuswatcher.h"
2+
#include <QDBusConnection>
3+
#include <QDBusPendingReply>
4+
#include <QVariantMap>
5+
#include <QDBusReply>
6+
7+
PlayerStatusWatcher::PlayerStatusWatcher(const QString &playerService, QObject *parent)
8+
: QObject(parent),
9+
m_playerService(playerService),
10+
m_iface(new QDBusInterface(playerService, "/org/mpris/MediaPlayer2",
11+
"org.mpris.MediaPlayer2.Player", QDBusConnection::sessionBus(), this)),
12+
m_serviceWatcher(new QDBusServiceWatcher(playerService, QDBusConnection::sessionBus(),
13+
QDBusServiceWatcher::WatchForOwnerChange, this))
14+
{
15+
// Register this object on the session bus to receive D-Bus messages
16+
QDBusConnection::sessionBus().registerObject("/PlayerStatusWatcher", this,
17+
QDBusConnection::ExportAllSlots);
18+
19+
QDBusConnection::sessionBus().connect(
20+
playerService, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties",
21+
"PropertiesChanged", this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))
22+
);
23+
connect(m_serviceWatcher, &QDBusServiceWatcher::serviceOwnerChanged,
24+
this, &PlayerStatusWatcher::onServiceOwnerChanged);
25+
updateStatus();
26+
}
27+
28+
void PlayerStatusWatcher::onPropertiesChanged(const QString &interface,
29+
const QVariantMap &changed,
30+
const QStringList &)
31+
{
32+
// Get the service name of the sender
33+
QString sender = message().service();
34+
35+
// Skip if it's a KDE Connect player
36+
if (sender.contains("kdeconnect", Qt::CaseInsensitive)) {
37+
return;
38+
}
39+
40+
if (interface == "org.mpris.MediaPlayer2.Player" && changed.contains("PlaybackStatus")) {
41+
emit playbackStatusChanged(changed.value("PlaybackStatus").toString());
42+
}
43+
}
44+
45+
void PlayerStatusWatcher::updateStatus() {
46+
QVariant reply = m_iface->property("PlaybackStatus");
47+
if (reply.isValid()) {
48+
emit playbackStatusChanged(reply.toString());
49+
}
50+
}
51+
52+
void PlayerStatusWatcher::onServiceOwnerChanged(const QString &name, const QString &, const QString &newOwner)
53+
{
54+
if (name == m_playerService && newOwner.isEmpty()) {
55+
emit playbackStatusChanged(""); // player disappeared
56+
} else if (name == m_playerService && !newOwner.isEmpty()) {
57+
updateStatus(); // player appeared/reappeared
58+
}
59+
}
60+
61+
QString PlayerStatusWatcher::getCurrentPlaybackStatus(const QString &playerService)
62+
{
63+
QDBusInterface iface(
64+
playerService,
65+
"/org/mpris/MediaPlayer2",
66+
"org.mpris.MediaPlayer2.Player",
67+
QDBusConnection::sessionBus());
68+
QVariant reply = iface.property("PlaybackStatus");
69+
if (reply.isValid())
70+
{
71+
return reply.toString(); // "Playing", "Paused", "Stopped"
72+
}
73+
else
74+
{
75+
return QString(); // or handle error as needed
76+
}
77+
}

0 commit comments

Comments
 (0)