0

I'm try to build a C++ application in Qt to capture audio streams from Bluetooth devices and play them to an ALSA playback device. This application runs in a Linux-embedded system and communicates with bluez (http://www.bluez.org/) and bluealsa (https://github.com/Arkq/bluez-alsa) via DBus.

What I need to do is being able to listen to the PCMAdded and PCMRemoved signals sent by the org.bluealsa.Manager1 interface of the bluealsa service (org.bluealsa) through the DBus. For some unknown reason, the connect method fails.

Here is how I do it:

manager1 = new QDBusInterface("org.bluealsa",
                              "/org/bluealsa",
                              "org.bluealsa.Manager1",
                              QDBusConnection::systemBus(),
                              this);

qDebug() << "manager1->isValid:" << manager1->isValid(); // YES

if(!manager1->connection().connect(manager1->service(),   //"org.bluealsa",
                                   manager1->path(),      //"/org/bluealsa",
                                   manager1->interface(), //"org.bluealsa.Manager1",
                                   "PCMAdded",
                                   this,
                                   SLOT(PCMAddedSlot(QDBusObjectPath, QVariantMap))),
                                   Qt::QueuedConnection){

    qDebug() << "Failed to connect PCMAdded signal"; // <- FAILS!!!
    qDebug() << "lastError:" << QDBusConnection::systemBus().lastError().message();
}

if(!manager1->connection().connect(manager1->service(),   //"org.bluealsa",
                                   manager1->path(),      //"/org/bluealsa",
                                   manager1->interface(), //"org.bluealsa.Manager1",
                                   "PCMRemoved",
                                   this,
                                   SLOT(PCMRemovedSlot(QDBusObjectPath))),
                                   Qt::QueuedConnection){

    qDebug() << "Failed to connect PCMRemoved signal"; // <- FAILS!!!
    qDebug() << "lastError:" << QDBusConnection::systemBus().lastError().message();
}

In the .h file, the definition of the slots are:

public Q_SLOTS:
    void PCMAddedSlot(QDBusObjectPath path, QVariantMap props);
    void PCMRemovedSlot(QDBusObjectPath path);

I don't know what is wrong, other connections from other services work just fine.

These is a way to know why the connection fails? There is this question, but didn't help (How to get QDBusConnection::connect() failure reason).

Here is the output of the Instrospect command on bluealsa:

dbus-send --system --dest=org.bluealsa --type=method_call --print-reply /org/bluealsa org.freedesktop.DBus.Introspectable.Introspect

method return time=1652969572.610729 sender=:1.3 -> destination=:1.11 serial=14 reply_serial=2
   string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
                      "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.62.6 -->
<node>
  <interface name="org.freedesktop.DBus.Properties">
    <method name="Get">
      <arg type="s" name="interface_name" direction="in"/>
      <arg type="s" name="property_name" direction="in"/>
      <arg type="v" name="value" direction="out"/>
    </method>
    <method name="GetAll">
      <arg type="s" name="interface_name" direction="in"/>
      <arg type="a{sv}" name="properties" direction="out"/>
    </method>
    <method name="Set">
      <arg type="s" name="interface_name" direction="in"/>
      <arg type="s" name="property_name" direction="in"/>
      <arg type="v" name="value" direction="in"/>
    </method>
    <signal name="PropertiesChanged">
      <arg type="s" name="interface_name"/>
      <arg type="a{sv}" name="changed_properties"/>
      <arg type="as" name="invalidated_properties"/>
    </signal>
  </interface>
  <interface name="org.freedesktop.DBus.Introspectable">
    <method name="Introspect">
      <arg type="s" name="xml_data" direction="out"/>
    </method>
  </interface>
  <interface name="org.freedesktop.DBus.Peer">
    <method name="Ping"/>
    <method name="GetMachineId">
      <arg type="s" name="machine_uuid" direction="out"/>
    </method>
  </interface>
  <interface name="org.bluealsa.Manager1">
    <method name="GetPCMs">
      <arg type="a{oa{sv}}" name="PCMs" direction="out"/>
    </method>
    <signal name="PCMAdded">
      <arg type="o" name="path"/>
      <arg type="a{sv}" name="props"/>
    </signal>
    <signal name="PCMRemoved">
      <arg type="o" name="path"/>
    </signal>
  </interface>
</node>
"

Additional info:

  • setting QDBUS_DEBUG=1 showed no helpful information.
  • QDBusConnection::systemBus().lastError().message() shows no errors.
  • system bus is connected and working.
  • cannot use PulseAudio, must stick with bluealsa.
  • signals from bluez (org.bluez) are recieved correctly (the connect methods work).
  • I can use without issues the GetPCMs method of the bluealsa org.bluealsa.Manager1 interface.
  • I cannot use graphical tools (such as d-feet or qdbusviewer) to inspect the DBus, I have only the dbus-* commands.
  • Maybe the problem is somehow connected to the configuration files? I tried to disable all security but still doesn't work (https://lists.freedesktop.org/archives/dbus/2010-October/013654.html).
  • Cannot connect to the PropertiesChanged signal neither. I use the same code that I wrote for other interfaces (and there it works).

Follows the output of the Qt Creator console:

QDBusConnectionPrivate(0x66300920) Adding rule: "type='signal',sender='org.bluealsa',path='/org/bluealsa',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
QDBusConnectionPrivate(0x66300920) sending message: QDBusMessage(type=MethodCall, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="GetNameOwner", signature="", contents=("org.bluealsa") )
QDBusConnectionPrivate(0x66300920) got message reply: QDBusMessage(type=MethodReturn, service="org.freedesktop.DBus", signature="s", contents=(":1.3") )
QDBusConnectionPrivate(0x66300920) Watching service "org.bluealsa" for owner changes (current owner: ":1.3" )
Failed to connect PropertiesChangedSlot signal
lastError: ""  

QDBusConnectionPrivate(0x66300920) Adding rule: "type='signal',sender='org.bluealsa',path='/org/bluealsa',interface='org.bluealsa.Manager1',member='PCMAdded'"
Failed to connect PCMAdded signal
lastError: ""

QDBusConnectionPrivate(0x66300920) Adding rule: "type='signal',sender='org.bluealsa',path='/org/bluealsa',interface='org.bluealsa.Manager1',member='PCMRemoved'"Failed to connect PCMRemoved signal
lastError: ""

and the output of dbus-monitor --system:

method call time=1652974083.935035 sender=:1.11 -> destination=org.freedesktop.DBus serial=20 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='signal',sender='org.bluealsa',path='/org/bluealsa',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
method call time=1652974083.935120 sender=:1.11 -> destination=org.freedesktop.DBus serial=21 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='org.bluealsa'"
method call time=1652974083.935888 sender=:1.11 -> destination=org.freedesktop.DBus serial=22 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=GetNameOwner
   string "org.bluealsa"
method return time=1652974083.935953 sender=org.freedesktop.DBus -> destination=:1.11 serial=12 reply_serial=22
   string ":1.3"

method call time=1652974125.821756 sender=:1.11 -> destination=org.freedesktop.DBus serial=23 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='signal',sender='org.bluealsa',path='/org/bluealsa',interface='org.bluealsa.Manager1',member='PCMAdded'"

method call time=1652974160.661667 sender=:1.11 -> destination=org.freedesktop.DBus serial=24 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='signal',sender='org.bluealsa',path='/org/bluealsa',interface='org.bluealsa.Manager1',member='PCMRemoved'"

EDIT

I can easily see that the signals are sent via dbus-monitor:

signal time=1653039761.040063 sender=:1.3 -> destination=(null destination) serial=60 path=/org/bluealsa; interface=org.bluealsa.Manager1; member=PCMRemoved
   object path "/org/bluealsa/hci0/dev_EC_7C_B6_05_AD_0D/a2dpsnk/source"    

method return time=1653039769.432723 sender=:1.3 -> destination=:1.2 serial=61 reply_serial=2869
   array of bytes [
      21 15 02 35
   ]
signal time=1653039769.472354 sender=:1.3 -> destination=(null destination) serial=62 path=/org/bluealsa; interface=org.bluealsa.Manager1; member=PCMAdded
   object path "/org/bluealsa/hci0/dev_EC_7C_B6_05_AD_0D/a2dpsnk/source"
   array [
      dict entry(
         string "Device"
         variant             object path "/org/bluez/hci0/dev_EC_7C_B6_05_AD_0D"
      )
      dict entry(
         string "Transport"
         variant             string "A2DP-sink"
      )
      dict entry(
         string "Mode"
         variant             string "source"
      )
      dict entry(
         string "Format"
         variant             uint16 33296
      )
      dict entry(
         string "Channels"
         variant             byte 2
      )
      dict entry(
         string "Sampling"
         variant             uint32 44100
      )
      dict entry(
         string "Codec"
         variant             string "SBC"
      )
      dict entry(
         string "Delay"
         variant             uint16 0
      )
      dict entry(
         string "SoftVolume"
         variant             boolean true
      )
      dict entry(
         string "Volume"
         variant             uint16 32639
      )
   ]
method return time=1653039769.473281 sender=:1.3 -> destination=:1.2 serial=63 reply_serial=2871

Any ideas?

EDIT 2

I've managed to make it work, by calling the AddMatch method on the org.freedesktop.DBus interface. Now the slots are called correcly when the signals PCMAdded and PCMRemoved are emitted by bluealsa, BUT the connect() method still returns false.

An even stranger thing, the dbus interface is not valid, even if it works perfectly.

Here is how I did:

dbus = new QDBusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", QDBusConnection::systemBus(), this);

qDebug() << "dbus->isValid:" << dbus->isValid(); // <- FALSE!

AddMatch("type='signal', sender='org.bluealsa', path='/org/bluealsa', interface='org.bluealsa.Manager1', member='PCMRemoved', arg0='org.myapp', arg2=''");
AddMatch("type='signal', sender='org.bluealsa', path='/org/bluealsa', interface='org.bluealsa.Manager1', member='PCMAdded', arg0='org.myapp', arg2=''");

where:

bool AddMatch(QString str) {

    if (dbus != NULL) {

        QDBusReply<void> reply = dbus->call("AddMatch", str);

        if (reply.isValid()) {
            return true;
        } else {
            qDebug() << reply.error().message() << reply.error().name();
            return false;
        }
    }
    return false;
}
NoobNoob
  • 80
  • 1
  • 9

1 Answers1

0

I can't say what is wrong, but you can try couple of things:

  • Maybe you can check what happens if you connect to the signal over QDBusConnecion rather over QDBusInterface.
QDBusConnection::systemBus().connect("org.bluealsa", "/org/bluealsa", "org.bluealsa.Manager1", "PCMAdded", this, SLOT(PCMAddedSlot(QDBusObjectPath, QVariantMap));
  • Maybe QtDBus has issues with QDBusObjectPath, use QDBusMessage as your slot signature.
public Q_SLOTS:
    void PCMAddedSlot(const QDBusMessage& message);

and parse the required arguments out of QDBusMessage manually.

  • Tried both suggestions, but nothing changed. I somehow made it working by calling the `AddMatch` method on the `org.freedesktop.DBus` interface. Strange thing: the `connect()` still returns false. – NoobNoob May 23 '22 at 06:50