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 bluealsaorg.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;
}