SBC也就是Sub band codec,俗称子带编码,是蓝牙A2DP必须支持的唯一编码。下面结合实例看看SBC编码数据在蓝牙传输中帧结构以及SBC的编解码算法流程:
AVDTP Frame
首先AVDTP Frame是基于L2CAP协议,所以会包含有4个字节的L2CAP头部,如上图看到2个字节的length = 650 bytes,两个字节的Destination CID = 0xA040 (AVDTP)。
接下来看看12个字节的AVDTP的头部:
这12个字节分成了三部分:
- Padding ,Extension, Maker 和 Payload Type组成了2个字节,也就是0x8060;
- Sequence Number 也就是0x0019, 占用2个字节,就是给AVDTP Frame一个序号,方便接收方能检查发送的数据包是不是连续的,有没有丢包。
- Time Stamp 也就是0x00005400,占用4个字节,这个就是计算数据包播放的时间戳,接收方Audio DSP会根据时间戳来做音频播放同步以及丢包错包检查。
- SSRC 也就是0x00000000,占用4个字节。
SBC Frame
从上图可以看到一个2-DH5数据包的Media Payload包含一个字节SBC头部(其中4个bit用来表示包含几个子frame),和7个frame。
根据A2DP_SPEC_V1.3,立体声和联合立体声的Frame_length计算方法:
frame_length = 4 + (4 * nrof_subbands * nrof_channels ) / 8 + (join * nrof_subbands + nrof_blocks * bitpool ) / 8.;联合立体声时,join == 1;
MONO和DUAL CHANNEL mode 的frame_length计算方法:
frame_length = 4 + (4 * nrof_subbands * nrof_channels ) / 8 + nrof_blocks * nrof_channels * bitpool / 8 .
本实例我们得到的nrof_subbands 等于8, nrof_channels 等于2,join 等于1,bitpool等于39,nrof_blocks等于16,所以:
frame_length = 4 +(4* 8 * 2) /8 + (1 * 8 + 16 * 39)/8 = 4 + 8 + 1 +78 = 91 byte
这样我们挑一个frame 1来看看:
从上图可以看出一个SBC子帧是由13个字节的Frame Header + 78个字节的audio samples组成:
第n字节 | 参数 | 值 | 描述 |
---|---|---|---|
1 | syncword | 0x9C | 占用一个字节,这是个固定的值,标志着一个子帧的开始 |
2 | Sampling Frequency | 10(44.1 kHz) | 占用两个bit: 00表示16kHZ; 01表示32KHZ; 10表示44.1KHZ; 11表示48KHZ |
2 | Blocks | (11)16 | 占用2个bit: 00表示4个block; 01表示8个block; 10表示12个block; 11表示16个block |
2 | Channel Mode | Joint Stereo | 占用2个bit: 00表示MONO; 01表示DUAL_CHANNEL; 10表示STEREO; 11表示JOINT STEREO |
2 | Allocation Method | Loudness | 占用1个bit: 0表示LOUDNESS; 1表示SNR; |
2 | Subbands | 1(8) | 占用1个bit: 0表示4个subbands; 1表示8个subbands; |
3 | Bitpool | 39 | 占用一个字节,表示bitpool大小 |
4 | crc_check | 0x5E | 占用一个字节,用作CRC校验 |
5 | join | 0xFE | 占用一个字节,一个bit为1表示一个subband编码为联合立体声,否则为立体声编码。 |
6-13 | Scale Factors | 比例因子,占用8个字节,4个bit表示一个通道,一个子带;此实例有2个通道,8个子带,所以需要4x2x8/8 = 8字节表示; | |
14-91 | Audio Samples | 78 bytes | 占用78个字节,量化编码后的音频数据,16x39/8 = 78,大小也就是nrf_blocks x bitpool / 8 |
SBC解码
- 音频接收端收到SBC帧数据会检查frame_header,然后做CRC的校验:G(X) = X8 + X4 + X3 + X2 + 1 (CRC-8).
- 计算真实的比例因子scalefactors :
scalefactor[ch][sb] = pow(2.0, (scale _ factor[ch][sb] + 1)).
这里的scale_factor[ch][sb]就是上一节我们在帧头部的4个bit,而所谓的scale factor就是每个子段的最大幅值。 - Bit Allocation:这个是跟scalefactors关联的,每个子频段的幅值不一样,需要用到的bit数也不一样,但同一个子频段的幅值所用的bit数是一样的。
- Reconstruction of the Subband Samples:就是把每个子频段的78个字节的audio_sample和真实的比例因子scalefactor做一个乘法运算,进行采样数据的还原:
sb_sample[blk][ch][sb] = scalefactor[ch][sb] * ((audio_sample[blk][ch][sb]*2.0+1.0) /levels[ch][sb]-1.0);
。 - Joint Processing :
for (blk=0;blk< nrof_blocks;blk++)
{
for (sb=0;sb<nrof_subbands;sb++)
{
if ((channel_mode==JOINT_STEREO) && (join[sb]==1))
{
sb_sample[blk][0][sb] = sb_sample[blk][0][sb] + sb_sample[blk][1][sb];
sb_sample[blk][1][sb] = sb_sample[blk][0][sb] – 2 * sb_sample[blk][1][sb];
}
}
}
- Synthesis Filter:多项滤波器组把每个子频带采样数据进行滤波器的合成为PCM数据输出给音频codec。
SBC编码
SBC编码过程跟解码是反过来的:
- Analysis Filter :把输入的PCM数据通过多项滤波器组转化为4或者8个子频带的频域数据;
- Scale Factors :计算每个子频段的比例因子,用4个比特表示,实际值是2的n次方,表示这个子频段的最高幅值 ;
- Bit Allocation:跟解码过程是一样的,跟scalefactors关联 , 每个子频段的幅值不一样,需要用到的bit数也不一样,为每个子频段分配幅值bit数的过程就是bit allocation;
- Quantization:量化,通过如下公式进行:
quantized_sb_sample[blk][ch][sb] = ((sb_sample[blk][ch][sb] / scalefactor[ch][sb] + 1.0) * levels[ch][sb]) / 2.0
- BitStream packing,把每个子频段的frame_header和audio_sample打包到AVDTP数据包中。
SBC的压缩比
首先看一下SBC的比特率的计算:
bit_rate = 8 * frame_length* fs / nrof_subbands / nrof_blocks
如果不进行SBC编码,我们的bit_rate = 44100 x 16 = 705600 bit/s.
进行了SBC编码的bit_rate = 8 * 91 *44100/16/8 = 250818 bit/s
那么压缩比为:705600/250818 = 2.81