否。 尝试编写处理此问题的 Android 应用程序将不是解决方案。至少如果你想使用A2DP Sink 角色。
事实上,正如您所提到的,Android 并没有实现对BlueZ(Android 使用到 Jelly Bean 4.1 的蓝牙堆栈)关于 A2DP sink 功能的 API 调用。你必须自己实现它们。我会尽力指导你,因为我最近也有兴趣自己做这件事。
默认情况下,您支持蓝牙的 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 可用here。如果你这样做,你将不得不构建一个本地应用程序 (C/C++) 并为你的平台编译它。您必须能够使用Android NDK 执行此操作。
如果您发现使用D-BUS 有困难,您可以试试我刚刚发现的这个Java 库,它可以为您处理与D-BUS 的通信:http://jbluez.sourceforge.net/。我从未使用过它,但我认为值得一试。
您真正需要做的是找出 A2DP 源设备何时与您的手机配对,以及他何时开始播放音乐。您可以通过 D-BUS 检索这些事件。一旦有人尝试流式传输音乐,您需要告诉 BlueZ 您的本机应用程序将处理它。有一个很好的文档解释了你应该处理的事件流。此文档可通过here 访问。您感兴趣的部分在第 7 页。给定示例中的接收器应用程序是 PulseAudio,但它也可能是您的应用程序。
当您调用org.bluez.MediaTransport.Acquire 方法时,BlueZ 将向您转发一个 UNIX 套接字。读取此套接字将为您提供当前由远程设备流式传输的数据。但我记得有一个在 BlueZ 堆栈上工作的人告诉我,在这个套接字上读取的数据不是 PCM 纯音频,而是编码的音频内容。数据通常以称为SBC(低复杂度子带编码)的格式编码。
解码SBC并不难,可以找解码器 right here。
最后一步是将 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
这会在设备数组字段中为您提供已配对设备的列表。
一旦您获得了与您的蓝牙适配器配对的设备列表,您就可以知道它是否已连接到 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
希望这会有所帮助。