背景
SBC是经典蓝牙A2DP强制支持的音频标准配置的codec,通常情况下,在我们的印象中SBC是蓝牙低质量音质的代名词,如果一个耳机或者音响只支持SBC一个codec,那么这个耳机或音响肯定是低端货,一般高端的人耳机都会支持一些其他私有编码器,比如AAC,LDAC,还有各家公司自己开发的编解码器,比如高通的APTX,华为自己开发的L2HC等等。其实不然,蓝牙音频SBC是可以通过一些方法来提升音质,甚至可以提升至APTX HD相当的音效。
记得大概七八年前,我在上一家公司曾经做过一个韩国某司的智能TV项目,因为当时开发调试的时间比较长,所以还有印象就是当时客户就要求我们基于bluedroid蓝牙协议栈架构的A2DP Source端做如下修改:
- 左右音响需要单独建立ACL & A2DP链路,从audio系统那边过来的立体声数据按Left-Right-Left-Right组合,需要在协议栈里做分离,Left Channel的数据只发送Left Speaker,Right Channel的数据发送Right Speaker。
- 左右声道的音频数据都是在协议栈里分别各自进行SBC Encode,各自有独立的编码参数, Channel Mode由原来的Joint stereo 变成了Mono Channel Mode。
- A2DP configuration能够动态配置,比如单独一个音响的时候是aptx Mode,如果有两个音响,则需要切换为SBC,反之亦然。
- 需要给应用层提供一些接口,比如配置左右音响,配置bitpool的值等等。
上面的需求看似不复杂,其实当时一个人还是花了不少时间,尤其是两条数据流同时做SBC encode的时候,SBC的库还有重入的问题(其实就是SBC编码库引入一些全局变量导致),后面又碰到一些两个音响数据流同步等问题,还有两条流变一条流,一条流变两条流做A2DP Configuration动态切换问题等等。
客户为啥需要这么做呢?这么配置会带来哪些好处,接下来探讨:
SBC编码参数
下面看一个具体耳机端实例所支持的SBC编码的参数:
参数 | 值 | 详解 |
---|---|---|
Channel Mode | 联合立体声,立体声,双通道,单通道 | Dual channel:由两个单声道组成,两个声道编码时不考虑相关性,每个声道的码率为音频总码率的一半。 Stereo:由两个或多个相互独立的声道组成,每个声道的码率根据其各自编码信息量大小而定。人耳听到时能对音源位置进行定位。E.G right use 48kbits and left uses 96 kbits in a 128kbits file。不会计算双声道之间的资料相关性,但是会协调分配双声道的资料流量,自动分配较多的 Bit 给复杂的声道使用。 Joint stereo:也是由两个声道组成,但编码时兼顾了这两个声道的共同信息量,比Stereo的压缩率更高。在这个压缩模式下,LAME 会利用双声道之间的资料相关性进行演算。左右声道资料类似时,会利用 M/S (Mid/Side) 编码技术,计算中央声道 (L+R) 和两侧声道差异 (L-R) 的值,并且会分配较多的 Bit 给中央声道,增加资料记录频宽。 |
Sampling Frequency | 48KHZ,44.1KHZ | 音频采样率,可以理解为1秒播放44100个采样点或者48000个采样点 |
Allocation Method | Loudness或SNR | 量化分配方法是响度还是信噪比 |
sub bands | 8或者4 | "Number of frequency bands"指的是频率带的数量。通常用于音频处理、无线通信等领域,表示将整个频率范围分割成的多个区段或通道的数量。每个频带代表一个特定范围内的频率集合。例如,在音频均衡器中,不同的频带可以分别调整不同频率范围的声音强度。在无线通信中,频带则指定了信号传输所使用的具体频率区间。 |
Block Length | 4,8,12,16 | 一个音频帧中的音频块数据 |
Min Bitpool value | 2 | 量化比特池的最小值为2 |
Max Bitpool Value | 39 | 量化比特池的最大值为39 |
下面看一个手机通过AVDTP Set Configuration设置的SBC编码参数的实例:
可以看到手机选择是:联合立体声,采样率44.1kHz ,响度,频带数量为8,帧中块数为16,量化比特池最小值为2,最大值为39。
SBC码率计算
b
i
t
r
a
t
e
=
8
∗
f
r
a
m
e
_
l
e
n
g
t
h
∗
s
a
m
p
l
e
_
r
a
t
e
s
u
b
b
a
n
d
s
∗
b
l
o
c
k
s
bitrate= \frac{8 * frame\_length * sample\_rate}{subbands * blocks}
bitrate=subbands∗blocks8∗frame_length∗sample_rate
其中sample_rate, subbands和blocks这些都是定义好了的,只有frame_length的计算方法参考:
可以计算上面的手机和耳机传输SBC音频数据的frame_length = 4 + (8 * 2)/2 + (8+16 * 39)/8 = 91
可以计算上面的手机和耳机传输SBC数据的码率为8 * 91 * 44100/(8 * 16)=250.8 kbps
这里也有一个现成的计算方法:https://btcodecs.valdikss.org.ru/sbc-bitrate-calculator/ 来验证一下:
上面这个表格的2DH5代表,采用2M PHY,一次传输采用5个slot(0.625ms)+一个slot的间隔,总共是6x0.625ms = 3.75ms;
而3DH5则表示采用3M PHY,一次传输采用5个slot +一个slot的间隔,总共也是3.75ms。
可以看到采用2DH5最多一次可以传输679个字节,一个传输周期可以传输7个frame,有25个字节浪费;
计算方法:679 - 4(L2CAP) - 12(AVDTP) - 1(SBC header) - (91 * 7) = 25。
而采用3DH5一次最多传输1021个字节,可以传输11个frame,只有3个字节浪费。
同理:1021 - 4(L2CAP) - 12(AVDTP) - 1(SBC header) - (91* 11) = 3。
这里列举A2DP SPEC定义的高质量和低质量的一些常用的比特池对应的SBC码率表格:
Dual Split A2dp SBC Streams Benifit
再回到我之前的项目中,假设按照以下的固定配置,每个音频帧包含16块,量化分配方法为响度和频带数为8,比特池为38的设置下,来看看单个A2DP联合立体声音频数据流和两条A2DP MONO音频数据流各自对应的码率为多少:
联合立体声:
- frame_length = 4 + 8* 2/2 + (8+16*38)/8 = 89 ;
- bitrate = 8 * 89* 44100/(8*16)=245.3kbps
MONO:
- frame_length = 4 + 8*2/2 + (16 * 38)/8 = 88
- bitrate = 8 * 88* 44100/(8*16)=242.5kbps
这里需要注意的是采用联合立体声的话,如果两个音响配合,另外一个副音响可以采取监听模式,这样蓝牙的总带宽还是245.3kbps;如果采取MONO,两个音响需要建立两条A2DP音频数据流,那么总带宽就变成了242.5 x 2 = 485 kbps。
带宽翻倍最终带来的也是效果翻倍甚至更好,这是由专业测试的,可以达到Aptx HD的效果,具体参考:http://soundexpert.org/articles/-/blogs/audio-quality-of-sbc-xq-bluetooth-audio-codec