在Android中通过蓝牙接收音频

时间:2013-03-21 20:56:46

标签: android bluetooth streaming audio-streaming rfcomm

我想创建一个能够接收音频流的Android应用程序。我想过使用A2DP配置文件,但似乎Android不支持A2DP接收器。看起来有很多人在寻找这个问题的解决方案。但接收普通比特流,然后将数据转换为应用程序中的音频呢?我想通过RFCOMM(SPP蓝牙配置文件)接收PCM或Mp3数据流,然后使用AudioTrack播放它。

首先,如何通过RFCOMM在我的Android手机上收到比特流?是否可以通过RFCOMM接收比特流作为PCM或Mp3流?

其次,如果无法通过RFCOMM接收比特流作为PCM或Mp3流,如何将接收的比特流转换为音频?

第三,如何将接收的数据转换为音频并同时“实时”播放音频?我可以使用onDataReceived吗?

要明确,我对使用A2DP配置文件不感兴趣!我想通过RFCOMM(SPP蓝牙配置文件)传输数据。接收的数据流将采用PCM或Mp3。我想写自己的应用程序,但如果有人知道一个应用程序来解决这个问题,我很高兴听到它!我正在使用Android 2.3 Gingerbread。

/约翰尼

5 个答案:

答案 0 :(得分:41)

否。 尝试编写处理此问题的Android应用程序将不是解决方案。至少如果你想使用A2DP Sink角色。

事实上,正如你所提到的,Android并没有实现对A2DP sink功能的BlueZ(Android使用直到Jelly Bean 4.1的蓝牙堆栈)的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

这将为您提供Devices数组字段中配对设备的列表。

获得与蓝牙适配器配对的设备列表后,您就可以知道它是否已连接到AudioSource界面。

获取连接到AudioSource界面的设备:

  

dbus-send --system --print-reply --dest = org.bluez   /组织/的bluez / {PID} / hci0 / dev_XX_XX_XX_XX_XX_XX   org.bluez.AudioSource.GetProperties   org.bluez.Manager.GetProperties

希望这有帮助。

答案 1 :(得分:2)

另一种解决方法是使用HandsFreeProfile。

在Android中,BluetoothHeadset正在研究这个问题。 等到状态变为BluetoothHeadset.STATE_AUDIO_CONNECTED。

然后你可以录制蓝牙耳机的音频。

    mMediaRecorder = new MediaRecorder();
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mMediaRecorder.setOutputFile(mFilename);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    try {
        mMediaRecorder.prepare();
    } catch (IllegalStateException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    mMediaRecorder.start();

答案 2 :(得分:1)

[不相关但有效] 这个黑客只通过WIFI热点提供mp3流媒体(我在我的车中使用它只有AUX输入):

  1. 安装应用AirSong
  2. 开启wifi热点,
  3. 将其他设备连接到该热点,
  4. 从设备的浏览器访问192.168.43.1:8088,然后您就可以了。
  5. (想知道为什么" 192.168.43.1"只有?因为这是连接到Android Hotspot的任何设备的默认网关)

答案 3 :(得分:0)

Android 4.2.2中似乎缺少

audio.conf吗?

答案 4 :(得分:0)

要通过rfcomm接收pcm音频流,您可以使用代码流作为解释(Reading Audio file in C and forwarding over bluetooth to play in Android Audio track)的提示,并进行更改。更改从44100到22050初始化时使用的频率

AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,22050,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_8BIT,10000, AudioTrack.MODE_STREAM);

注意:此流媒体仍包含一些噪音,但您的

  

“通过RFCOMM(SPP蓝牙配置文件)接收PCM数据流,然后使用AudioTrack播放。”

会奏效。