不。尝试编写处理此问题的 Android 应用程序不是解决方案。至少如果你想使用A2DP Sink
角色。
事实是,正如您所提到的,Android 没有实现BlueZ
关于功能的 API 调用(Android 使用的蓝牙堆栈直到 Jelly Bean 4.1)A2DP sink
。你必须自己实现它们。我会尽力指导你,因为我在不久的过去也有兴趣自己做这件事。
默认情况下,您启用蓝牙的 Android 设备将自己宣传为A2DP source
设备。您必须先更改此设置,以便附近的设备可能会将您的设备识别为接收器。为此,您必须修改audio.conf文件(通常位于/etc/bluetooth/中)并确保Enable
密钥存在并且值Source
已附加到此密钥,因此您将获得如下内容:
Enable=Source
重新启动,附近的设备现在应该将您的设备识别为A2DP sink
.
现在,当 A2DP 源设备开始将音频流式传输到您的手机时,您必须与 BlueZ 进行交互以做出适当的反应。
Android 和 BlueZ 正在通过D-BUS
. 实际上,Android 连接到 DBUS_SYSTEM 通道并监听每个 BlueZ 广告,例如事件、文件描述符......
我记得我使用本机应用程序成功地将自己绑定到这个 d-bus 通道,并访问了 BlueZ 发布的各种事件。使用 BlueZ API 作为参考,这是相对容易实现的,此处提供了 BlueZ API 。如果你这样做,你将不得不构建一个本地应用程序 (C/C++) 并为你的平台编译它。您必须能够使用Android NDK
.
如果你觉得它很难使用D-BUS
,你可以试试我刚刚发现的这个 Java 库,它可以为你处理与 D-BUS 的通信:http: //jbluez.sourceforge.net/。我从未使用过它,但我认为值得一试。
您真正需要做的是找出 A2DP 源设备何时与您的手机配对,以及他何时开始流式传输音乐。您可以通过 D-BUS 检索这些事件。一旦有人尝试流式传输音乐,您需要告诉 BlueZ 您的本机应用程序将处理它。有一个很好的文档解释了你应该处理的事件流。该文档可在此处访问。您感兴趣的部分在第 7 页。给定示例中的接收器应用程序是,PulseAudio
但它也可能是您的应用程序。
当您调用该org.bluez.MediaTransport.Acquire
方法时,BlueZ 将向您转发一个 UNIX 套接字。读取此套接字将为您提供当前由远程设备流式传输的数据。但我记得有一个在 BlueZ 堆栈上工作的人告诉我,在这个套接字上读取的数据不是 PCM 纯音频,而是编码的音频内容。数据通常以称为SBC
(低复杂度子带编码)的格式编码。
解码 SBC 并不难,你可以在这里找到解码器。
最终步骤是将 PCM 音频转发到您的扬声器。
为了防止您卡住并以更简单的方式测试您的应用程序,您可以使用d-bus
应该在您的 Android 系统上可用的二进制文件。他位于/system/bin。
在执行上述任何操作之前可以进行的快速测试可能是:
获取设备列表:
dbus-send --system --dest=org.bluez --print-reply / org.bluez.Manager.GetProperties
这将返回一个适配器数组及其路径。获得这些路径后,您可以检索与您的适配器配对的所有蓝牙设备的列表。
获取配对设备:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/{pid}/hci0 org.bluez.Adapter.GetProperties
这将为您提供设备数组字段中的配对设备列表。
获得与蓝牙适配器配对的设备列表后,您就可以知道它是否已连接到 AudioSource 接口。
获取连接到 AudioSource 接口的设备:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/{pid}/hci0/dev_XX_XX_XX_XX_XX_XX org.bluez.AudioSource.GetProperties org.bluez.Manager.GetProperties
希望这可以帮助。