编号 尝试编写一个处理此问题的 Android 应用程序不是解决方案。至少如果您想使用 A2DP Sink
角色。
事实是,Android,正如您所提到的,没有实现有关 A2DP sink
功能的 BlueZ
API 调用(Android 使用 Jelly Bean 4.1 之前的蓝牙堆栈)。您必须自己实现它们。我会尝试指导您,因为我也对在不久的将来自己做这件事感兴趣。
您的启用蓝牙的 Android 设备默认情况下会将自己广告为 A2DP source
设备。您必须首先更改此设置,以便附近的设备可以将您的设备识别为 sink。要执行此操作,您必须修改audio.conf文件(通常位于/etc/bluetooth/),并确保存在 Enable
键,并且将值 Source
附加到此键,以便您将获得以下内容:
Enable=Source
重新启动后,附近的设备现在应该将您的设备识别为 A2DP 接收器。
现在,您需要与 BlueZ 交互,以在 A2DP 源设备开始向您的手机流式传输音频时做出适当反应。
Android 和 BlueZ 通过 D-BUS 进行通信。实际上,Android 连接到 DBUS_SYSTEM 通道并侦听每个 BlueZ 广告,例如事件、文件描述符等等。
我记得曾经成功地使用本机应用程序将自己绑定到这个 d-bus 通道,并获得了许多 BlueZ 发布的事件。使用 BlueZ API 可以相对容易地实现此目标,
此处提供了参考。如果您选择这种方法,您需要构建一个本机应用程序(C/C++)并将其编译为您的平台。您可以使用 Android NDK 完成此操作。
如果您发现使用D-BUS很困难,您可以尝试我刚刚发现的这个Java库,它可以为您处理与D-BUS的通信:
http://jbluez.sourceforge.net/。我从未使用过它,但在我看来值得一试。
您真正需要做的是找出何时将A2DP源设备配对到您的手机以及何时开始流式传输音乐。您可以通过D-BUS检索这些事件。一旦有人尝试流式传输音乐,您需要告诉BlueZ您的本机应用程序将处理它。有一份非常好的文件解释了您应该处理的事件流程。此文件可在
here中访问。您感兴趣的部分位于第7页。在给定示例中,接收器应用程序是
PulseAudio
,但也可以是您的应用程序。
BlueZ会在调用
org.bluez.MediaTransport.Acquire
方法时向您转发一个UNIX套接字。在此套接字上读取将提供当前由远程设备流式传输的数据。但我记得有个人在BlueZ堆栈上工作告诉我,在此套接字上读取的数据不是纯PCM音频,而是编码的音频内容。这些数据通常以称为
SBC
(低复杂度子带编码)的格式进行编码。
解码SBC并不是很困难,您可以在这里找到解码器。
最终步骤是将PCM音频转发到扬声器。
为了防止您陷入困境并以更轻松的方式测试应用程序,您可以使用Android系统上应该可用的d-bus
二进制文件。它位于/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
这将在Devices数组字段中给出已配对设备的列表。
一旦您拥有了与蓝牙适配器配对的设备列表,您可以知道它是否连接到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
希望这能帮到您。