VOIP:RTP分析和AC490调试记录

本文探讨了AudioCodes公司的VoIP处理器AC490的使用与调试经验,重点介绍了RTP包格式及其在G.729与G.711A编码下的具体实现,针对调试过程中遇到的问题提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/ren911/archive/2010/05/04/5557682.aspx

 

最近在研究VOIP ,媒体网关底层使用ac490 进行语音信号IP( 驱动不由我写) ,碰见一些,总结如下。

.ac490 介 绍:

ac490AudioCodes 公 司的VoIP 处理器,可以运行8/12 通道LBRC ,包括G.723/G.729/iLBC/AMR/GSM FR 。支持24 通道的G.711 算 法或12 通道的G.711/G.723 算法 的语音编码;G.168-2002 回波消除;T.38 传 真;支持RTP/RTCP 的打包/ 解包。

.RTP 包格式

详细定义请见rfc3550
 (RTP
格式的描述) rfc3551
 (RTP
携带的媒体信息格式的描述).

2.1RTP 头格式

12 个字节在每一个RTP packet 中都存在,而一系列的CSRC 标记 只有存在Mixer 时才有。
   version (V): 2 bits
      
标明RTP 版本号。协议初始版本为0RFC3550 中规定的版本号为2
   padding (P): 1 bit
      
如果该位被设置,则在该packet 末尾包含了额外的附加信息,附加信息的 最后一个字节表示额外附加信息的长度(包含该字节本身)。该字段之所以存在是因为一些加密机制需要固定长度的数据块,或者为了在一个底层协议数据单元中传 输多个RTP packets
   extension (X): 1 bit
      
如果该位被设置,则在固定的头部后存在一个扩展头部,格式定义在RFC3550 5.3.1 节。
   CSRC count (CC): 4 bits
      
在固定头部后存在多少个CSRC 标 记。
   marker (M): 1 bit
      
该位的功能依赖于profile 的定义。profile 可以改变该位的 长度,但是要保持markerpayload type 总 长度不变(一共是8 bit )。
   payload type (PT): 7 bits
      
标记着RTP packet 所携带信息的类型,标准类型列出在RFC3551 中。如果接收方不能识 别该类型,必须忽略该packet
   sequence number: 16 bits
      
序列号,每个RTP packet 发送后该序列号加1 ,接收方可以根据该序列号重新排列数据包顺序。
   timestamp: 32 bits
      
时间戳。反映RTP packet 所携带信息包中第一个字节的采样时间。
   SSRC: 32 bits
      
标识数据源。在一个RTP Session 其 间每个数据流都应该有一个不同的SSRC
   CSRC list: 0 to 15 items, 32 bits each
      
标识贡献的数据源。只有存在Mixer 的时候才有效。如一个将多声道的语音流合并成一个单声道的语音流,在这里就列出原来每个声道的 SSRC

   Payload :此部分的格式规定见RFC3551, 随携带的媒体流格式不同而不同。

2.2 RTPpayload 格 式

   2.2.1 G.729 格式

按照RFC3551 4.5.6 规定,一个携带G729 格式的RTP 包的payload 可以由0 或多个G.729 G.729 Annex A 帧组成,后面再有0 或多个G.729 Annex B 帧组成。

G.729 G.729 Annex A 每帧长10 byte ,相互 间完全兼容,主要携带语音信息。G.729 Annex B 帧每帧长4 byte ,主要携带VAD(voice activity detector, 语音行为检测)CNG(comfort noise generator, 舒适噪音生成)

不过根据对sip 电话和软sip 电话的G729RTP 包抓包分析,其payload 一般是由4G.729 G.729 Annex A 组成。因为VAD 不是所有设 备都支持,例如asterisk 不支持。

   2.2.2 G.711A 格式

按照RFC35514.5.14 规定,一个携带G711 格式的RTP 包格式较简单,在G711 中每个声音采样被编码为8 bit56 kb/s48 kb/sRTP 中是不被支持的。

. AC490 调试

本身希望用AC490 直接发送rtp 包,但是控制其直接发送的RTP 包却无法被sip 电话,asteriskwireshark 正确分析。

3.1 G

.729

的问题 
       RTP
头部多了4bit
,一般来时G729RTP
包头2bite80 12
,或者80 92(mark
被置为1
,一般是在第一个RTP
包中)
,而
ac490
发送G729RTP
包中80 12
前面多个4bit
, 修改ac490
的驱动使其去掉头4bit
,可以被wireshark
分析为G729RTP
包,
但仍然无法与sip
电话互通,继续分析发现sip
电话的G729RTPpayload
长度为20 bit
,而ac490
的为12bit
,且在通过
asterisk
的时候,asterisk
报告检测有VAD
帧,查看asterisk
源码发现asteriskframe.c
不支持VAD
       综上和前面对G729
格式的描述,猜测ac490
的默认G729RTP
包由2G.729 G.729 Annex A 
帧和一个G.729 Annex B
帧组成。而sip
电话和软sip
电话的G729RTP
包一般由4G.729 G.729 Annex A 
帧组成。
      修改驱动,改变ac490G729RTP
包为4G.729
帧,与sip
电话和软sip
电话互通成功。
3.2 G

.711A

的问题 
      在前面的调试过程,由于修改ac490G729RTP
包格式的方式需要些时间,尝试修改ac490RTP
格式为G.711A
,也就是pcma
因为其格式较为简单。但开始时仍然无法与sip
电话互通,表现为sip
电话可以听到声音但有很大的杂音,ac490
这面的普通电话静音。分析
为还是两端包格式不符,ac490
丢弃了所有发过来的包。
      继续抓包,sip
电话的G.711ARTPpayload
长度为160bit
,而ac490G.711ARTPpayload
长度为162bit
,多次试验分析后,发
现主要在ac490RTPpayload
最后两个bit
上,在一次通话中,这两个bit
要么是00 00
,要么是固定的两个bit
,所有包后面都是这两种类型。
而不同通话中,00 00 
外的另一种方式的两个bit
不同。而00 00
或两个固定bit
出现方式暂时为发现规律,在静音包和语音包尾部两种都会
出现。
      建议修改ac490
驱动为在发送时去掉尾部两个bit
,接受时补上两个bit 00 00
再次试验互通成功。

. 总结

1. 
较为仔细的学习了RTP
有关RFC
,主要是rfc3550, rfc3551,
还有rfc 2198rfc2833
2. 
基本掌握了sip
电话和软sip
电话的RTP
包结构,了解了常见的RTP
包格式(rfc
中建议的多种方式那种最常用)
3. asterisksip.conf
配置进一步熟悉,尤其是canreinvite
这一段,怎样使其表现的近似于statelesssip
服务器。
4. 
对用wireshark
抓包进一步掌握。
继续编译报这些错误,你看看是不是要包含什么头文件: packages/apps/zorro/neteq/test1.cpp:77:17: error: use of undeclared identifier 'LS_WARNING' RTC_LOG(LS_WARNING) << "Failed to insert packet: " << error; ^ packages/apps/zorro/neteq/test1.cpp:90:17: error: use of undeclared identifier 'LS_ERROR' RTC_LOG(LS_ERROR) << "Failed to get audio: " << error; ^ packages/apps/zorro/neteq/test1.cpp:101:12: error: call to deleted constructor of 'webrtc::AudioFrame' return audio_frame; ^~~~~~~~~~~ packages/apps/zorro/neteq/include/api/audio/audio_frame.h:60:3: note: 'AudioFrame' has been explicitly marked deleted here AudioFrame(const AudioFrame&) = delete; ^ packages/apps/zorro/neteq/test1.cpp:116:5: error: unknown type name 'RtpReceiver' RtpReceiver rtp_receiver(1234); // <BC><E0><CC><FD> 1234 <B6>˿<DA> ^ packages/apps/zorro/neteq/test1.cpp:132:13: error: use of undeclared identifier 'PlayAudio' PlayAudio(audio.data(), ^ packages/apps/zorro/neteq/test1.cpp:139:9: error: use of undeclared identifier 'SleepMs' SleepMs(10); ^ packages/apps/zorro/neteq/test1.cpp:177:26: error: no member named 'Socket' in namespace 'rtc' std::unique_ptr<rtc::Socket> socket_; ~~~~~^ packages/apps/zorro/neteq/test1.cpp:148:24: error: no member named 'Socket' in namespace 'rtc' socket_ = rtc::Socket::Create(rtc::SocketAddress(), rtc::Socket::Type::SOCK_DGRAM); ~~~~~^ packages/apps/zorro/neteq/test1.cpp:148:66: error: no member named 'Socket' in namespace 'rtc' socket_ = rtc::Socket::Create(rtc::SocketAddress(), rtc::Socket::Type::SOCK_DGRAM); ~~~~~^ packages/apps/zorro/neteq/test1.cpp:148:44: error: no member named 'SocketAddress' in namespace 'rtc' socket_ = rtc::Socket::Create(rtc::SocketAddress(), rtc::Socket::Type::SOCK_DGRAM); ~~~~~^ packages/apps/zorro/neteq/test1.cpp:151:27: error: expected ';' after expression rtc::SocketAddress local_address("0.0.0.0", port_); ^ ; packages/apps/zorro/neteq/test1.cpp:151:14: error: no member named 'SocketAddress' in namespace 'rtc' rtc::SocketAddress local_address("0.0.0.0", port_); ~~~~~^ packages/apps/zorro/neteq/test1.cpp:151:28: error: use of undeclared identifier 'local_address' rtc::SocketAddress local_address("0.0.0.0", port_); ^ packages/apps/zorro/neteq/test1.cpp:152:36: error: use of undeclared identifier 'local_address' int result = socket_->Bind(local_address); ^ packages/apps/zorro/neteq/test1.cpp:158:14: error: no type named 'SocketAddress' in namespace 'rtc' rtc::SocketAddress remote_address; ~~~~~^ packages/apps/zorro/neteq/test1.cpp:177:34: warning: private field 'socket_' is not used [-Wunused-private-field] std::unique_ptr<rtc::Socket> socket_; ^ 15 warnings and 15 errors generated.
最新发布
08-02
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值