系统未建立
分类: LINUX
2016-02-16 09:32:35
以前我的QSPhone一直在用G729A编码,最近遇到一个问题,有用户在使用的时候出现类似破音的情况,我测试也发现这样很不爽,(奇怪的是在XP下没问题,但在Win7下就出现)。经过多次测试发现在说话时质量很好,当有空闲时出现破音。到时就考虑静音检测问题,于是查了一下G729与静音检测,找到了问题所在,是双方编码有偏差,G729ab <->G729A 间通信,本来是可以兼容的,只怪判断编码是加了一default的,而舒适噪音生成(comfort noise generator,CNG)的RTP Payload是13,走到了default里面播放出现破音。
关于最近学习G729ab资料总结一下:
1.G729编码系列:
G729: 最基本的G.729 标准协议,原始版
G729A: 精简版的G729,兼容原始版G729,对G.729 codec 一些算法进行简单处理,相当于降低了算法的复杂度
G729B: 加入了语音端点检测模块,在编码前对语音进行语音和静默音进行检测,然后分别对不同情况进行编码
G729AB: 這是有靜音检测的G729A版本,而且相容 G729B。
2.一些缩略语
VAD: Voice Activity Detection 语音行为检测,是一种当被在语音端口或拨号对等体上被开启时,只有可以听见的语音能够被传输的功能。当 VAD 被开启时,语音的质量的级别会被稍微降低,但此种连接占用的宽带相对要少一些。
CNG: comfort noise generator舒适噪音生成,在静音的时候产生一定的语音,一直静音下,人的感官觉得不适,为电话通信产生背景噪声。
DTX: 不连续发射(Discontinuous Transmission ),在语音间歇期关闭发射,仅发射静音指示帧,接收端码变换器产生舒适噪声。
BFI:Bad Frame Idicator,坏帧指示,静音帧标识。
SID: Silence Insertion Descriptor,2个字节表示。
3. G.729AB编码帧解析:(Coder_ld8a、prm2bits_ld8k函数处理)
编码后的short串为serial,第二个short字符标识帧的有效长度,同时表示帧的类型:
如果为80,普通帧。
如果为15 or 16, 指的G.729B中的SID帧,这个长度依据传输类型,如果定义OCTET_TX_MODE则为15;
如果为0,表示该帧不传输。
如果serial[1]不为0,每两个字节编码成为BIT_0或者BIT_1。
如此解析是符合ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0′,用0×0081表示1个比特’1′,每个帧头会有同步字和包的长度。对于同步 字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧,这样会导致了编码后数据的增大。需要重新编写prm2bits_ld8k函数.
具体如下:
因为G729是参数编码器,编码后得到的数据是参数,而不同参数得到的bit数是不一样的,查看一下tab_ld8a.c文件中的bitsno[]数组,这里面声明了每一个参数所用的bit数,G729ab中多出一bitsno2[]数组,这是SID帧准备的。
Word16 bitsno[PRM_SIZE] = {1+NC0_B, /* MA + 1st stage */
NC1_B*2, /* 2nd stage */
8, 1, 13, 4, 7, /* first subframe */
5, 13, 4, 7}; /* second subframe */
Word16 bitsno2[4] = {1, /* SID Lsp : MA */
5, /* SID Lsp : 1st stage */
4, /* SID Lsp : 2nd stage */
5 }; /* SID gain */
代码中
Word16 prm[PRM_SIZE+1]; /* Analysis parameters + frame type */
较G729多1,用来存储帧类型prm[0],为0:not transmitted ;1:G729A帧; 2:SID帧。
对此需要分类压缩:
void prm2bits_ld8k_tmp(Word16 *prm,unsigned char *bits)
{
int i;
switch(prm[0]){
/* not transmitted */
case 0 : {
// *bits = RATE_0;
break;
}
case 1 : { //压缩后bits长度为10字节//G729A帧
bits[0] = (unsigned char)(prm[1] & (Word16)0xff);
bits[1] = (unsigned char)((prm[2] & (Word16)0x03fc) >> 2);
bits[2] = (unsigned char)((prm[2] & (Word16)0x0003) << 6);
bits[2] |= (unsigned char)((prm[3] & (Word16)0x00fc) >> 2);
bits[3] = (unsigned char)((prm[3] & (Word16)0x0003) << 6);
bits[3] |= (unsigned char)((prm[4] & (Word16)0x0001) << 5);
bits[3] |= (unsigned char)((prm[5] & (Word16)0x1f00) >> 8);
bits[4] = (unsigned char)(prm[5] & (Word16)0x00ff);
bits[5] = (unsigned char)((prm[6] & (Word16)0x000f) << 4);
bits[5] |= (unsigned char)((prm[7] & (Word16)0x0078) >> 3);
bits[6] = (unsigned char)((prm[7] & (Word16)0x0007) << 5);
bits[6] |= (unsigned char)(prm[8] & (Word16)0x001f);
bits[7] = (unsigned char)((prm[9] & (Word16)0x1fe0) >> 5);
bits[8] = (unsigned char)((prm[9] & (Word16)0x001f) << 3);
bits[8] |= (unsigned char)((prm[10] & (Word16)0x000e) >> 1);
bits[9] = (unsigned char)((prm[10] & (Word16)0x0001) << 7);
bits[9] |= (unsigned char)(prm[11] & (Word16)0x007f);
break;
}
case 2 : {//压缩后bits长度为2字节//SID帧
bits[0] = (unsigned char)((prm[1] & (Word16)0x0001)<<7);
bits[0] |= (unsigned char)((prm[2] & (Word16)0x001f) << 2);
bits[0] |= (unsigned char)((prm[3] & (Word16)0x000c));
bits[1] = (unsigned char)((prm[3] & (Word16)0x0003) <<6);
bits[1] |= (unsigned char)((prm[4] & (Word16)0x001f) <<1);
bits[1] |= (unsigned char)(0);
break;
}
default : {
printf("Unrecognized frame type\n");
exit(-1);
}
}
return
}