Ubuntu上Bluetooth A2DP receiver实现分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Wendell_Gong/article/details/20557707

A2DP相关部分的简介

    A2DP——Advanced Audio Distribution Profile,是蓝牙音频数据传输的profile。A2DP中定义了两种role: Source and Sink。发送音频流的设备是source,接收音频流的设备是sink,比如手机是source,蓝牙耳机是sink。A2DP依赖与传输层协议AVDTP——Audio/Video Distribution Transport Protocol。A2DP还规定了音频的编码格式,其中SBC是必须支持的,可选的格式有MPEG-1, MPEG-2, MPEG-4, AAC and ATRC, 另外也支持厂商扩展的格式,比如高质量的音频编码格式apt-X。

BlueZ相关部分简介

    BlueZ是Linux的官方标准蓝牙协议栈,目前的最新版本是5.x。在4.46上,BlueZ实现了对A2DP Sink的支持,而之前的版本只支持A2DP Source。以下的讨论是基于BlueZ 4.46之后的4.x版本。5.x因为在D-Bus接口方面有较大改动,会影响A2DP Sink和上层Audio server的接口,不在本讨论覆盖范围之内。

PulseAudio相关部分的简介

    PulseAudio是一个开源的、跨平台的、支持网络的sound server。它可以支持从一个或多个source(进程或音频采集设备)输入声音并重定向它到一个或多个sink(声卡,远程网络PulseAudio server或其他进程)。PulseAudio的目的之一就是通过它来reroute所有的音频流,如下图


为了支持Bluetooth audio source,PulseAuido还实现了动态检测蓝牙音频设备的功能。这个功能和BlueZ A2DP Sink都是由João Paulo实现的,可以在它的blog《BlueZ now has A2DP Sink support》中找到相关信息(需要翻墙,责任自负)。

系统架构


开启A2DP Receiver功能

    按照这篇《Can I use my computer as an A2DP receiver?》的说明,即可在Ubuntu系统上开启A2DP receiver的功能。有一点需要解释的是为什么要打开的是A2DP Sink,而/etc/bluetooth/audio.conf中增加的却是Enable=Source。这个‘source’是针对PulseAudio的来说的,而不是指A2DP中的source role。一个Bluetooth A2DP sink device,在PulseAudio看来就是一个音频输入的source。另,在某些Ubuntu版本上有PulseAudio不能reroute A2DP audio stream的情况。我的PC系统信息如下:Ubuntu 12.04, BlueZ 4.98, pulseAudio 1.1。

    在bluez.org和pulseaudio.org可下载到源码,然后进行分析。

BlueZ中A2DP Sink的实现

    在阅读代码之前,最好先熟悉以下这两份spec: A2DP and AVDTP,这将有助于理解代码。从bluetooth.org上可以下载到这两份spec。

    bluez/audio目录集中了audio相关的protocol和profile(但是并未给每个audio相关的profile建立子目录,BlueZ 5.x对此上做了改进,在bluez/profiles目录下给每个profile建立了子目录)。audio相关的模块以BlueZ plugin的形式加载,其plugin接口实现在bluez/audio/main.c中。audio_init()载入了audio.conf文件,并调用bluez/audio/manager.c中的audio_manager_init()对这个文件的内容进行解析。前面提到的‘Enable=Source’就是被这个函数解析的,并设置了‘enabled.source = TRUE’。在manager.c中,audio的一系列server都被注册了,包括headset server, gateway server, a2dp server, avrcp server, media server。如果想了解每个server的注册,初始化过程,可以从manager.c入手。

    A2DP Sink实现的源文件是source.c(注意:source.c实现了A2DP Sink而不是sink.c)。a2dp.c也做了一些支持A2DP sink的相应改进,比如增加了对AVDTP_SEP_TYPE_SOURCE的判断,然后调用相应的source或sink函数。结合文档和protocol analyzer tool可以比较容易追踪音频数据流的处理过程。

PulseAudio如何从BlueZ得到音频数据

    虽然BlueZ内部对A2DP Sink的实现较为复杂,但是暴露给外部的数据接口确非常简单。在bluez/audio/ipc.c中实现了三个bt_audio_service函数。PulseAudio使用bt_audio_service_open()打开一个socket,然后调用bt_audio_service_get_data_fd()得到音频数据文件描述符fd。这个fd是通过那个socket从BlueZ的进程传递到PulseAudio的进程的。最后,使用完毕,调用bt_audio_service_close()来关闭socket。PulseAudio通过D-bus和BlueZ进行通信,进行参数的读取和设置,决定合适的读取时机,发送读取的状态。

     PulseAudio从fd读出的音频数据流是经过SBC压缩编码的(对于采用其他编码,如MPEG-1,的情况,本文不做讨论),PulseAudio还需要对这些音频数据流进行解码。在BlueZ中已经实现了SBC编解码,源文件位于bluez/sbc。PluseAudio直接使用了这些源代码,把它们放在pulseadio/src/modules/bluetooth/sbc中。


展开阅读全文

没有更多推荐了,返回首页