使用 d-bus 在 C.H.I.P 上使用 bluez 5.43 更改音量

Posted

技术标签:

【中文标题】使用 d-bus 在 C.H.I.P 上使用 bluez 5.43 更改音量【英文标题】:Using d-bus to change volume with bluez 5.43 on C.H.I.P 【发布时间】:2017-05-29 09:44:53 【问题描述】:

我是 d-bus 和 bluez 的新手。我有一个芯片模块,作为 BT 扬声器运行。我跟着这个:

https://github.com/hadess/CHIP-bluetooth-speaker

以及以下链接中的说明以使 iPhone 音量正常工作:

https://github.com/hadess/CHIP-bluetooth-speaker/issues/8

我希望能够通过我的 iphone 和模块更改扬声器的音量 - 所以我猜 dbus 命令是可行的方法。

我已使用以下方法成功连接和断开 iPhone:

dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_A0_D7_95_A9_88_91 org.bluez.Device1.Disconnect

d-feet 向我展示了如何做到这一点很有用。但是,我不清楚如何播放/暂停/volumeUp/volumeDown。这里的文档:

https://kernel.googlesource.com/pub/scm/bluetooth/bluez/+/5.43/doc/media-api.txt

解释了如何播放/暂停,但我无法让它工作。我试过了:

dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_A0_D7_95_A9_88_91 org.bluez.MediaPlayer1.Pause

和:

dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_A0_D7_95_A9_88_91/Player1 org.bluez.MediaPlayer1.Pause

同样的错误:

Error org.freedesktop.DBus.Error.UnknownMethod: Method "Pause" with signature "" on interface "org.bluez.MediaPlayer1" doesn't exist

而且我完全不清楚如何更改音量(mediacontrol1 中的 VolumeUp 和 VolumeDown 命令已弃用)。

谁能帮忙?

更新

在下面的康斯坦丁 (Constantin) 出色的 cmets 之后(谢谢),我想进一步澄清一下。

使用 d-feet,我得到以下设备信息:

我应该能够在列表中看到“MediaTransport1”和/或“MediaControl1”接口条目吗?

当我调用 device1 的内省时,我得到:

'<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"\n"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">\n<node><interface name="org.freedesktop.DBus.Introspectable"><method name="Introspect"><arg name="xml" type="s" direction="out"/>\n</method></interface><interface name="org.bluez.Device1"><method name="Disconnect"></method><method name="Connect"></method><method name="ConnectProfile"><arg name="UUID" type="s" direction="in"/>\n</method><method name="DisconnectProfile"><arg name="UUID" type="s" direction="in"/>\n</method><method name="Pair"></method><method name="CancelPairing"></method><property name="Address" type="s" access="read"></property><property name="Name" type="s" access="read"></property><property name="Alias" type="s" access="readwrite"></property><property name="Class" type="u" access="read"></property><property name="Appearance" type="q" access="read"></property><property name="Icon" type="s" access="read"></property><property name="Paired" type="b" access="read"></property><property name="Trusted" type="b" access="readwrite"></property><property name="Blocked" type="b" access="readwrite"></property><property name="LegacyPairing" type="b" access="read"></property><property name="RSSI" type="n" access="read"></property><property name="Connected" type="b" access="read"></property><property name="UUIDs" type="as" access="read"></property><property name="Modalias" type="s" access="read"></property><property name="Adapter" type="o" access="read"></property></interface><interface name="org.freedesktop.DBus.Properties"><method name="Get"><arg name="interface" type="s" direction="in"/>\n<arg name="name" type="s" direction="in"/>\n<arg name="value" type="v" direction="out"/>\n</method><method name="Set"><arg name="interface" type="s" direction="in"/>\n<arg name="name" type="s" direction="in"/>\n<arg name="value" type="v" direction="in"/>\n</method><method name="GetAll"><arg name="interface" type="s" direction="in"/>\n<arg name="properties" type="asv" direction="out"/>\n</method><signal name="PropertiesChanged"><arg name="interface" type="s"/>\n<arg name="changed_properties" type="asv"/>\n<arg name="invalidated_properties" type="as"/>\n</signal>\n</interface></node>'

哪个没有音量、传输控制等细节。这是否意味着我的 bluez 设置不允许?

最终,我希望这一切都在 Python 中运行,所以,Constantin,如果您能继续提供大力支持,一些 Python 代码示例也会很棒。

更新 2

好的,所以在带有 Bluez v5.23 的 Rpi V3 上尝试这个,我得到:

pi@raspberrypi:~ $ qdbus --system org.bluez /org/bluez/hci0/dev_A0_D7_95_A9_88_91
method QString org.freedesktop.DBus.Introspectable.Introspect()
property read QDBusObjectPath org.bluez.Device1.Adapter
property read QString org.bluez.Device1.Address
property readwrite QString org.bluez.Device1.Alias
property read ushort org.bluez.Device1.Appearance
property readwrite bool org.bluez.Device1.Blocked
property read uint org.bluez.Device1.Class
property read bool org.bluez.Device1.Connected
property read QString org.bluez.Device1.Icon
property read bool org.bluez.Device1.LegacyPairing
property read QString org.bluez.Device1.Modalias
property read QString org.bluez.Device1.Name
property read bool org.bluez.Device1.Paired
property read short org.bluez.Device1.RSSI
property readwrite bool org.bluez.Device1.Trusted
property read QStringList org.bluez.Device1.UUIDs
method void org.bluez.Device1.CancelPairing()
method void org.bluez.Device1.Connect()
method void org.bluez.Device1.ConnectProfile(QString UUID)
method void org.bluez.Device1.Disconnect()
method void org.bluez.Device1.DisconnectProfile(QString UUID)
method void org.bluez.Device1.Pair()
method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface, QString name)
method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface)
signal void org.freedesktop.DBus.Properties.PropertiesChanged(QString interface, QVariantMap changed_properties
method void org.freedesktop.DBus.Properties.Set(QString interface, QString name, QDBusVariant value)
property read bool org.bluez.MediaControl1.Connected
method void org.bluez.MediaControl1.FastForward()
method void org.bluez.MediaControl1.Next()
method void org.bluez.MediaControl1.Pause()
method void org.bluez.MediaControl1.Play()
method void org.bluez.MediaControl1.Previous()
method void org.bluez.MediaControl1.Rewind()
method void org.bluez.MediaControl1.Stop()
method void org.bluez.MediaControl1.VolumeDown()
method void org.bluez.MediaControl1.VolumeUp()

...所以显示了 MediaControl1。

问题是,是因为 Bluez 版本不同还是平台不同?响应 dbus 命令也有点慢(我没想到)。有时它几乎是立即的,有时可能需要 1-2 秒。这是预期的吗?

【问题讨论】:

【参考方案1】:

首先,将“Player1”添加到对象路径时,您的方式是正确的,文档清楚地指出:

Object path [variable prefix]/hci0,hci1,.../dev_XX_XX_XX_XX_XX_XX/playerX

但是,您是如何找到“Player1”的?这不能是随机数,您将通过内省您的设备(带有 dev_XX_XX 的对象路径...)找到必须附加到 mac 地址的确切字符串,通常在 xml 标签中''


现在关于您的错误,我知道文档指出 Pause 方法不接受参数,尽管文档可能不是最新的? 了解更多关于 dbus 方法的一种简单方法是分析自省: 您可以使用以下命令来检索自省(您应该更新 hci0 之后的路径以匹配您的对象路径):

dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.freedesktop.DBus.Introspectable.Introspect

举个例子,从内省中提取以下内容:

<method name="GetAll"><arg name="interface" type="s" direction="in"/><arg name="properties" type="asv" direction="out"/>

由此我了解到 GetAll 方法将接口名称作为字符串作为参数(方向输入,输入 s),并返回一个字典,其中字符串(键)映射到变量(值)(方向输出,输入 a sv)

您能否检查您的设备并确保您找到“Player1”节点标签?然后反省 Player1 并确保 Pause 方法不接受任何参数。


要更改音量,我想您应该使用 Interface org.bluez.MediaTransport1 中的“音量”属性(查看 media-api.txt 文件的末尾) .


最后,您是否打算将这些操作包含在程序中?如果是,我建议使用适当语言(C、Glib、Python、C#...)的 dbus 绑定。我可以为您提供更多关于如何在程序中与 bluez 交互的文档。

更新

您的 rpi (5.23) 上的版本较旧,并且使用了现在已弃用的 API(请自行查看 org.bluez.MediaControl1 接口在此处随处 [已弃用] https://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/media-api.txt)

通过查看文档,在自省设备时应该看不到任何接口。 org.bluez.Media1 如果您自省 /org/bluez/hci0(指指定的对象路径),应该会出现。

Service     org.bluez
Interface   org.bluez.Media1
Object path [variable prefix]/hci0,hci1,...

自省播放器时应该会出现 org.bluez.MediaPlayer1 :

Service     org.bluez (Controller role)
Interface   org.bluez.MediaPlayer1
Object path [variable prefix]/hci0,hci1,.../dev_XX_XX_XX_XX_XX_XX/playerX

尽管在您的情况下,我在您的反省中没有看到与“playerX”相关的任何内容,这是需要首先解决的问题。

要通过蓝牙传输声音,您需要使用 A2DP 协议,将您的 linux 用作“源”,将扬声器用作“接收器”。此功能(音频流)可能需要 PulseAudio。尝试将最新版本的 pulseaudio 添加到您的系统(您可能希望从源代码编译)。详情见这里:https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Bluetooth/

也许您的 rpi 使用 bluez4 和 pulseaudio 配置为自动连接。这可以解释为什么您可以在 rpi 上看到接口。

还有 Arch Wiki 可以帮助解决问题:https://wiki.archlinux.org/index.php/Bluetooth_headset#Headset_via_Bluez5.2FPulseAudio


在寻找信息时,我发现了这个网站:http://www.lightofdawn.org/wiki/wiki.cgi/BluezA2DP

它描述了如何使用 bluez api 使其适用于 A2DP。本教程是为 bluez4 编写的,作者最后谈到了 bluez5 的兼容性。

我无法确切说明您需要执行哪些操作以及按什么顺序执行,尽管您在谷歌搜索“bluez a2dp python”时会找到大量文档和教程(例如 reddit 上的这个,请仔细阅读他的 cmets,网址为他的代码文件的顶部):https://www.reddit.com/r/Python/comments/1f1xkt/use_python_to_turn_your_bluetooth_laptop_into_a/)

我的猜测是,您需要扫描 (org.bluez.Adapter1),注册端点 (org.bluez.Media1),配对(并且可能连接?使用 org.bluez.Device1)并获取文件描述符写作 (org.bluez.MediaTransport1)

在做任何其他事情之前,您需要使用 d-feet 查看那些界面!一旦你让它与 d-feet 一起工作,你可以参考这个 gist 以获得一个简单的 python 示例来执行扫描:https://gist.github.com/CynaCons/8eb02540f87af5594fac489a9dca32c1

我还在 github gist 上上传了一个高级版本。

【讨论】:

以上是关于使用 d-bus 在 C.H.I.P 上使用 bluez 5.43 更改音量的主要内容,如果未能解决你的问题,请参考以下文章

D-Bus:没有 ObjectManager 的导出对象

如何找到在 D-Bus 接口中公开的方法

使用 gdbus-codegen 骨架时如何验证 D-Bus 属性

使用 GDBus 通过 D-Bus 发送字节数组(类型为 `ay`)

列出来自 Java 的 d-bus 注册对象

Git + libsecret 抛出“没有 X11 $DISPLAY 无法自动启动 D-Bus”