2013-03-21 84 views
23

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

首先,我如何通过RFCOMM在我的Android手机上接收比特流?是否有可能通过RFCOMM接收比特流作为PCM或Mp3流?其次,如果无法通过RFCOMM接收比特流作为PCM或Mp3流,我如何将接收到的比特流转换为音频?

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

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

/约翰尼

+0

嘿约翰尼,到目前为止没有什么进展? ;) – Nippey 2013-12-13 09:44:34

+0

嘿!任何进展? – dpaksoni 2017-05-11 05:45:34

回答

37

试图写入一个Android应用程序来处理,这将不会是溶液。至少如果你想使用A2DP Sink角色。

事实上,正如你所提到的,Android并没有实现对BlueZ(Android使用的蓝牙堆栈直到Jelly Bean 4.1)关于A2DP sink功能的API调用。你必须自己实现它们。我会尽力引导你,因为我也有兴趣在过去做我的自我。

默认情况下,支持蓝牙的Android设备将自己宣传为A2DP source设备。您必须首先更改此设置,以便附近的设备可以将您的设备识别为接收器。要做到这一点,你必须修改audio.conf文件(usally位于的/ etc /蓝牙/),并确保Enable键存在和价值Source连接到这个键,所以你会得到的东西,如:

Enable=Source 

重启,附近的设备现在应该认识到您的设备作为A2DP sink

现在当一个A2DP信号源设备开始向您的手机传输音频时,您将不得不与BlueZ进行互动以做出适当反应。

Android和BlueZ正在通过D-BUS互相交谈。事实上,Android连接到DBUS_SYSTEM通道,并收听每个BlueZ广告,如事件,文件描述符...

我记得我已经成功地使用原生应用程序绑定到这个d总线通道并获得访问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-发送--system --dest = org.bluez --print -reply/ org.bluez.Manager.GetProperties

这将返回适配器数组及其路径。一旦你有了这些路径,你可以检索与你的适配器配对的所有蓝牙设备的列表。

获得配对的设备:

DBUS-发送--system --print回复--dest = org.bluez /组织/的bluez/{PID}/hci0 org.bluez.Adapter .GProProperties

这给出了设备阵列字段中配对设备的列表。

一旦你有蓝牙适配器配对的设备列表,你可以知道它是否连接到AudioSource接口。

获取连接到接口的AudioSource设备:

DBUS-发送--system --print回复--dest = org.bluez /组织/的bluez/{PID}/hci0/dev_XX_XX_XX_XX_XX_XX org.bluez.AudioSource.GetProperties org.bluez.Manager.GetProperties

希望这有助于。

+0

太棒了!我会尽快尝试。 但我认为应该可以忽略A2DP并使用RFCOMM。我意识到,我最终可能只是单声道音频,但音频流实际上是一个比特流,不是吗?那么为什么不使用RFCOMM接收它,然后在我的应用程序中将比特流转换为PCM音频流? – Johnny 2013-03-22 08:02:22

+1

由于A2DP是一种标准,每个手机都默认使用它(即不需要任何应用程序在客户端工作)。如果您决定使用RFCOMM,我想,您可以提供一个客户端应用程序,以便从远程设备传输音频。如果你决定这样做,你也可以使用wifi通过普通的套接字流式传输音频。Play商店中的许多应用程序都提供了这样的功能。 – 2013-03-22 08:08:27

+0

这就是说,如果您应用我上面提到的更改,您的接收设备将是唯一的,因为更改不会在每个Android手机上都可用(除非您使用JNI将另一个BlueZ堆栈封装在应用程序中,并且仍然是非常困难)。但另一方面,每个设备都可以将音频流式传输到您的接收器。 – 2013-03-22 08:12:27

0

audio.conf似乎在Android 4.2.2中缺失?

+1

从Jellybean开始,bluez堆栈被google替换为broadcomm蓝牙堆栈 – ashish 2013-05-28 10:46:09

+0

在4.1.2中,我提到了上面提到的audio.conf文件。安装AOKP 4.2.2后,audio.config丢失。 – WoodsLink 2013-06-15 01:03:03

+0

4.2.2包含来自Broadcom的蓝牙协议栈,audio.conf是bluez协议栈的一部分[这里](https://source.android.com/devices/bluetooth.html) – ashish 2013-06-17 04:20:45

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接收的PCM数据流(SPP蓝牙配置文件),然后播放它使用AudioTrack“。

将工作。

1

另一个解决方法是使用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(); 
+0

你有完整的代码来连接和设置Android免提?感谢 – user8264 2014-12-11 15:03:21

+0

@ user8264“半满” - https://developer.sony.com/develop/wearables/smarteyeglass-sdk/guides/use-bluetooth-for-audio-io/ – Nativ 2016-12-16 16:52:36

1

[无关,但工程]这个黑客仅用通过WIFI热点的流媒体MP3(我用它在我的车只具有AUX输入):

  1. 安装应用AirSong
  2. 打开wifi热点,
  3. 将其他设备连接到该热点,
  4. 从设备的浏览器访问192.168.43.1:8088,并哟你在开。

(不知道为什么“192.168.43.1”而已?因为那是连接到Android热点任何设备的默认网关)