pythonpyqtdbuspyqt6

PyQt6 - DBus signal not being received?


I'm trying to create a system to keep track of the currently-playing media via mpris. Adapted from this question's PyQt6 answer, I have tried the following code:

from PyQt6 import QtCore, QtWidgets, QtDBus
import sys

class MainWindow(QtWidgets.QMainWindow):
    def __init__ (self):
        super().__init__()
        service = 'org.mpris.MediaPlayer2.vlc'
        path = '/org/mpris/MediaPlayer2'
        iface = 'org.mpris.MediaPlayer2'
        conn = QtDBus.QDBusConnection.systemBus()
        conn.registerObject('/', self)
        conn.connect(service, path, iface, 'PropertiesChanged', self.nochangeslot)

    @QtCore.pyqtSlot(QtDBus.QDBusMessage)
    def nochangeslot(self, msg):
        print(f'signature: {msg.signature()!r}, '
              f'arguments: {msg.arguments()!r}')

app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

This should connect any VLC Media Player instance (replace with service of your choice or find it programatically) emitting PropertiesChanged to a simple function that prints the message.

PropertiesChanged should be emitted when doing things like changing the current song. However, nothing is printed when doing so. I also tried changing iface to 'org.mrpis.MediaPlayer2.Player', but it didn't improve matters.

Any idea why this isn't working?


Solution

  • There are two problems:

    1. You won't find MPRIS players (nor any desktop other apps) on the system bus¹. They are all connected to the user's individual session bus i.e. .sessionBus().

      Generally the only services you will find on the system bus are those which are global to the system (e.g. NetworkManager), whereas multiple users on the same system could have their own copies of the same player or app running, so accordingly each user also has a separate "session bus" (which is now more often really a "user bus").

      Use d-spy or d-feet, or qdbusviewer6, or busctl --acquired (with the --user option for the session bus) to see which D-Bus services are active where.

      $ busctl --user --acquired
      NAME
      org.mpris.MediaPlayer2.quodlibet
      

      ¹ (Such apps may still connect to the system bus as clients, though – just not as services.)

    2. Since properties are a generic D-Bus concept, their signals and methods are implemented as part of the generic org.freedesktop.DBus.Properties interface, not as part of the object's custom interfaces. (The "real" interface that each property belongs to is actually provided as an argument to those signals and methods.)

      Use D-Spy/D-Feet/QDBusViewer or gdbus introspect or busctl introspect to see which signals exist under which interfaces.

      $ busctl --user introspect \
           org.mpris.MediaPlayer2.quodlibet /org/mpris/MediaPlayer2
      
      NAME                                TYPE      SIGNATURE RESULT/VALUE
      org.freedesktop.DBus.Properties     interface -         -
      .PropertiesChanged                  signal    sa{sv}as  - 
      
      $ gdbus introspect -e \
           -d org.mpris.MediaPlayer2.quodlibet \
           -o /org/mpris/MediaPlayer2
      
      node /org/mpris/MediaPlayer2 {
        interface org.freedesktop.DBus.Properties {
          signals:
            PropertiesChanged(s interface_name,
                              a{sv} changed_properties,
                              as invalidated_properties);
        };
      };
      

      If in doubt, run dbus-monitor or busctl monitor (or use Bustle, or even Wireshark) to see what is being transferred over each bus.

      dbus-monitor --session "type=signal,member=PropertiesChanged"
      

      Note: With services that use the 'legacy' libdbus, there can sometimes be a mismatch between what the service declares via its .Introspect() and what it actually sends, as is a very low-level library that offers no facilities for managing objects or generating correct introspection data. (It requires the service to have its own implementation of Introspect() which often returns a hand-written XML string – such as this example – which may or may not be 100% accurate to what other parts of the code actually send or accept.) This is always a bug in the service, but it means that you should always double-check with bus monitor tools.