基于VoIP的电话终端设备的设计与实现Read.docx
《基于VoIP的电话终端设备的设计与实现Read.docx》由会员分享,可在线阅读,更多相关《基于VoIP的电话终端设备的设计与实现Read.docx(18页珍藏版)》请在冰豆网上搜索。
基于VoIP的电话终端设备的设计与实现Read
IP电话的设计与实现
前言
本文从VoIP相关知识入手,介绍了IP电话的软硬件结构设计及实现方案,并描述了IP电话基于SIP的呼叫流程,并通过设计杂项的方式详细描述了系统中的几个关键点。
内容仅供大家参考,更详细内容可参见源代码,源代码是最好的老师。
VoIP相关知识介绍
什么是VoIP
VoIP是VoiceoverInternetProtocol的缩写,指的是将模拟的声音讯号经过压缩与封包之后,以数据封包的形式在IP网络的环境进行语音讯号的传输。
VoIP技术是目前互联网应用领域的一个热门话题,已经成为下一代网络发展的必然趋势。
IP电话为广大电信用户和运营提供了一个成熟的、可实现广泛多媒体业务的终端载体,是下一代网络技术先进性的重要体现,它为基础语音的业务拓展提供了美好灿烂的应用前景。
VoIP的基本原理
通过语音的压缩算法对语音数据编码进行压缩处理,然后把这些语音数据按TCP/IP标准进行打包,经过IP网络把数据包送至接收地,再把这些语音数据包串起来,经过解压处理后,恢复成原来的语音信号,从而达到由互联网传送语音的目的。
IP电话系统把普通电话的模拟信号转换成计算机可联入因特网传送的IP数据包,同时也将收到的IP数据包转换成声音的模拟电信号。
经过IP电话系统的转换及压缩处理,每路IP电话传输速率可低达8~11kbps带宽,因此在与普通电信网的传输速率为64kbps带宽相比,IP电话数是原来的5~8倍。
VoIP的核心与关键设备是IP网关,它把各地区电话区号映射为相应的地区网关IP地址。
这些信息存放在一个数据库中,数据接续处理软件将完成呼叫处理、数字语音打包、路由管理等功能。
在用户拨打长途电话时,网关根据电话区号数据库资料,确定相应网关的IP地址,并将此IP地址加入IP数据包中,同时选择最佳路由,以减少传输时延,IP数据包经Internet到达目的地的网关。
在一些Internet尚未延伸到或暂时未设立网关的地区,可设置路由,由最近的网关通过长途电话网转接,实现通信业务。
VoIP的主要关键技术
实现VoIP的主要关键技术如下:
1)语音压缩技术:
IP电话的技术基础是语音压缩技术。
目前用于IP电话的标准是G.723.1,G.711alaw/ulaw和G.729a。
2)静噪抑制技术:
又称语音激活技术,是指检测到通话过程中的安静时段即停止发送语音包的技术。
通过静噪抑制技术,可大大节省带宽。
3)回声抵消技术:
在PBX或局用交换机侧,有少量电能未被充分转换而沿原路返回,形成回声。
4)语音抖动处理技术:
IP网络的一个特征就是网络延时与网络抖动,它们可以导致IP通话质量明显下降。
网络延时是指IP包在网络上平均的传输时间,网络抖动是指IP包传输时间的长短变化。
为了防止这种抖动,人们采用抖动缓冲技术,即在接收端设置一个缓冲池,语音包到达时首先进行缓存,然后系统以稳定平滑的速率将语音包从缓冲池中取出并处理,再播放给受话者。
5)语音优先技术:
语音通信对实时性要求较高,在带宽不足的IP网络中,一般需要语音优先技术,即在IP网络路由器中必须设置语音包的优先级最高。
这样,网络延时和网络抖动对语音的影响均将得到明显改善。
6)IP包分割技术:
有时网络上有长数据包,一个包上千字节,这样的长包如不加以限制,在某些情况下也会影响语音质量。
为了保证IP电话的通话质量,应将IP包的大小限制为不超过2556字节。
7)VoIP前向纠错技术:
为了保证语音质量,有些先进的VoIP网关采用信道编码以及交织等技术。
VoIP信令协议
目前构建IP电话系统结构的信令协议主要有H.323、SIP和MGCP(H.248)。
H.323协议是为多媒体会议系统而提出的,由国际电联ITU制定,该协议采用传统电信网络繁琐的信令概念,非常庞大,无论从实现技术手段,还是使用和管理方法上都十分复杂。
MGCP是互联网工程任务组(IETF)定义发布的,基本思想就是网关分离。
将H.323协议的IP网关分为媒体网关(MG)、信令网关(SG)和媒体网关控制器(MGC,又称CA)。
其中MG仅负责媒体格式的变换;SG负责信令的转换;MGC才是真正的智能部分,根据收到的信令控制MG的连接建立和释放。
这样的分离结构不仅可以大幅度提高中继MG的容量,而且可以提供7号信令的支持,并提高了系统的可用性和鲁棒性。
SIP(SessionInitiationProtocol)会话初始协议是IETF制订的,用于多方多媒体通信。
按照协议定义,SIP是一个基于文本的应用层控制协议,独立于底层传输协议TCP/UDP/SCTP,用于建立、修改和终止IP网上的双方或多方多媒体会话。
SIP协议借鉴了HTTP、SMTP等协议,它尽可能的大量采用现有的协议,而不是重建标准,如HTTP、LDAP、RADIUS等,都是技术成熟、应用广泛的协议标准。
SIP协议发展前景较好,正逐渐进入商业应用,而且相关的开源项目也比较多,如VOCAL、OSIP都是比较成熟的、可商业化的SIP协议栈。
SIP应用崭新的业务模式不断呈现,相关研发和项目投资增长迅速,终端产品价格不断下降,SIP协议正得到越来越广泛的支持,SIP协议以其更加开放、更易扩展、与Internet紧密结合等特性,战胜H.323、MGCP等协议成为VoIP的主流协议。
SIP产品将主导未来VoIP通信市场已成为业界人士的共识,基于SIP的IP通信正在成为一个巨大的产业。
因此我们采用了SIP协议。
IPPhone设计方案
我们的IP电话方案是一款低成本,高性能的解决方案,该方案采用简约设计,主芯片采用Infelion的INCA-IP芯片,此芯片是为IPPhone应用设计的一款SOC解决方案,内部集成32-BITMIPSCPU、高性能dsp,SLIC,LCD控制器,MAC,PHY单元,CPU主频达到150MHz的主频,DSP达100MHz,在网络处理和语音方面可以达到很高的性能,是现有市场上比较先进的IPPhoneSoc解决方案。
软件平台采用vxWorks嵌入式操作系统,vxWorks是世界上领先的嵌入式操作系统,因其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空和航天等高精尖技术及实时性要求极高的领域。
信令协议采用SIP协议,主要是由于SIP协议正得到越来越广泛的支持,SIP协议以其更加开放、更易扩展、与Internet紧密结合等特性,战胜H.323、MGCP等协议成为VoIP的主流协议,我们的SIP协议栈是移植的libosip2-2.2.2版本;另外根据国外的需求,后续将要支持IAX2协议。
硬件架构
方案主芯片采用Infelion的INCA-IP芯片,内部集成了32-BITMIPSCPU、高性能dsp,SLIC,LCD控制器,MAC,PHY单元,因此硬件则通过外接flash、SDRAM、手柄、耳机、LCD、键盘和以太变压器来实现。
硬件系统构架见下面框图:
软件架构
我们的软件是在vxWorks操作系统的基础上自主开发完成,主要包括:
驱动模块(DSP驱动、LCD驱动、以太驱动、键盘驱动等)、OSIP协议栈、ORTP协议栈、呼叫控制模块、用户接口模块(menu、CLI、WEB)、扩展业务模块等。
软件系统构架见下面框图:
其中:
●DSP驱动:
Dsp驱动模块是语音、信号处理的核心,完成对语音,数据,信号的采集和发送,同时它还完成对dsp控制、管理的功能。
在系统启动时,完成dsp初始化工作。
●SLIC驱动:
SLIC驱动主要实现对端口摘挂机状态的检测,同时通知上层对摘挂机事件进行相应的处理。
●键盘驱动
主要负责对键盘事件的检测,并将所检测的事件送到上层。
键盘驱动层不负责解析键盘事件的具体含义,而是由上层根据当前话机类型找到相应的键盘布局表,将其转化为对应的按键,并进行处理。
●LCD驱动:
LCD驱动主要负责对LCD显示屏的操作,并为上层提供统一的LCD操作函数,由上层完成LCD显示。
●Ethernet驱动:
以太驱动模块负责CPU上以太网控制器的初始化,PHY的初始化,状态检测,数据处理,访问控制。
接受物理层的数据,并交给链路层进行处理;同时发送链路层数据到物理介质。
●硬件接口层:
主要负责本地端点的资源管理控制,将物理接口的事件转化为系统能够识别的事件,为核心控制层屏蔽具体的物理设备细节,保证除驱动层之外其它层的可移植性、硬件无关性。
●呼叫控制层
呼叫控制层维护端点状态转换关系,根据收到的SIP信令或硬件产生的事件来完成端点状态的转换及呼叫的处理。
●SIP协议栈:
SIP协议栈是SIP协议的具体实现,包括两部分,分别由开源项目libosip2-2.2.2及libeXosip2-2.2.3移植而来。
话机工作流程
话机的工作流程要结合SIP协议,SIP协议规定了用来建立,改变和终止基于IP网络的用户间的呼叫。
其中主叫端点表示主叫用户,UA1状态机表明了主叫侧呼叫状态的处理;被叫端点表示被叫用户,UA2状态机表明了被叫侧呼叫状态的处理;
假设主被叫用户均是我们的话机,则结合代码实现呼叫流程如下:
(1)主叫键盘检测驱动检测到用户按键,通过回调函数kbdEventCallback()上交,在kbdEventCallback()根据当前话机类型找到相应的键盘布局表,将按键事件转化为对应的按键,并最终调用kbdkey_job_add()函数将事件加入到键盘事件处理任务队列中。
任务tKbdTask的主处理函数kbdkey_task()被触发,将摘机事件通过函数endpoint_event_notify()通知到呼叫控制层,呼叫控制层判断出是摘机事件EV_OFFHOOK,则先打开DSP通道,然后在offhook_handler()处理函数中放拨号音,将端点状态由IDLE转换为等待拨号状态。
(2)用户拨号,在拨号处理函数dialup_handler()中收集用户号码(注:
检测到第一个拨号时要关闭拨号音),并根据拨号规则判断用户是否拨号完毕,一旦检测到拨号完毕,则调用call_originate()发起SIP呼叫。
(3)call_originate()中会判断是IP地址拨号还是电话号码拨号,并根据dial-peer配置变换被叫号码,根据SIP配置获得SIP服务器信息,最后调用sip_invite()通过SIP协议栈提供的函数发出invite消息,并将端点状态由等待拨号状态转换为连接中状态。
(4)tExosip任务负责处理从SIP获取到的消息事件,被叫先发送100trying消息(1xx消息是临时消息,表明收到了SIP消息,正进行处理或已放到处理队列中,以告诉对端不必再重传此消息),然后通过call_new()函数通知被叫呼叫状态机进行处理,被叫振铃,发送180或183消息,并将端点状态由IDLE转换到等待摘机状态。
(5)主叫呼叫控制层收到180或183消息,则调用call_ringing()进行处理,通知主叫回铃。
(6)被叫摘机,则调用offhook_handler()进行处理,由于被叫处于等待摘机状态,因此进入到相应的处理流程中,调用sip_200ok()发送200OK消息;
(7)主叫呼叫控制层收到200OK消息,则调用call_answered()处理,根据SIP消息进行ACK,并将端点状态由连接中转换为已连接状态。
(8)被叫收到ACK消息,通过函数call_ack()处理,并将端点状态由等待摘机状态转换为已连接状态。
至此,双向的媒体连接已建立,主被叫双方可进行正常的语音通话。
(9)被叫挂机,则呼叫控制层调用onhook_handler(),根据当前端点状态调用sip_bye()发送BYE消息,关闭DSP通道,并将端点状态恢复成IDLE状态。
(10)主叫收到BYE消息,SIP协议栈会自动发送200OK消息,并通过呼叫控制层的call_closed()函数进行处理,关闭DSP,端点状态转换为等待挂机,并释放催挂音。
(11)主叫挂机,则onhook_handler()根据当前端点状态进行处理,并将端点状态恢复成IDLE状态。
端点及状态转换图
端点是对物理端口的一种抽象,由于话机只有一个语音端口,因此系统中ENDPOINT_NUM为1,但可以很容易地扩展从而支持更多端口的设备(如网关)。
typedefstructendpoint_t
{
//端点标识部分
charindex;/*index,from0toENDPOINT_NUM*/
chartype;/*endpointtype*/
charname[ZCOS_EPNAME_LEN];/*endpointname*/
//端点信息记录部分
charstate;/*endpointstate,justsimple*/
charcallee;/*calleeorcalledparty*/
charoffhook;/*FLASE:
onhookorTRUE:
offhook*/
charmute;
charholded;/*holdbypeer*/
characked;/*receivedACKforthisdialog*/
charfirstkey;/*iffirstkey,thenstopthedialtone*/
WDOG_IDinterKeyTmr;/*timerbetweentwokeys*///不用了
intinterkeyTmrVal;/*timervalue,seconds*/
chardialstr[ZCOS_PHONENUM_LEN];/*currentdialstring*/
/*
callinfo
*/
//呼叫信息记录,主要是保存与一次会话呼叫有关的信息,这样当进行hold、transfer等时可以找到原来的信息
CALLINFOcallinfo;
/*
//定时器信息,端点使用了一个统一的定时器,用来支持等待摘机、等待按键、等待对端应答的定时、
#defineWDOGEVT_WAIT_NONE0/*无*/
#defineWDOGEVT_WAIT_OFFHOOK1/*等待摘机定时器*/
#defineWDOGEVT_WAIT_KEY2/*等待按键定时器*/
#defineWDOGEVT_WAIT_ANSWER3/*等待对端应答定时器*/
*/
WDOG_IDwdog;
intwdogVal;
intwdogEnv;
/*
reserveinformation
保存的一些端点信息
*/
chardisplayname[ZCOS_USERNAME_LEN];/*对端可显示的用户名,nousenow*/
charcalledstr[ZCOS_PHONENUM_LEN];/*主叫时表示被叫信息,被叫时是主叫号码*/
charcallerstr[ZCOS_PHONENUM_LEN];/*主叫时表示本端号码,被叫时是被叫号码*/
chardtmfstr[ZCOS_PHONENUM_LEN];/*连接后拨的分机号码*/
HOLDCBholdq[HOLDQ_SIZE];
intmic;/*mictype*/
RECENT_CALLS*pRecentCalls;
unsignedlongcallStartTick;
/*
forconfiguration
配置信息部分
*/
//SIP_USER*user;
SIP_PHONENUM*phonenum[SIP_REGISTRAR_MAX];
charhotline[ZCOS_PHONENUM_LEN];
charprefix[ZCOS_PHONENUM_LEN];
chartonetype;
u_charcodec;
u_charg729payload;/*payloadlenforG729*/
u_charg723payload;/*6.3kor5.3k*/
u_charsilencecompress;/*silencecompress*/
u_charvolume;/*DSPvolume,defaultis0,maxis7*/
charbaningoing;/*TRUE:
nodisturb*/
charbanoutgoing;/*TRUE:
banoutgoing*/
BOOLcallwaiting;
BOOLcalltransfer;
BOOLconference;
CALLFORWARDcallforward;
intnoanswertime;/*noanswertime*/
}ENDPOINT;
话机工作流程一节中也描述了端点状态转换,下图则更详细地描述了端点状态下收到的事件及状态转换关系。
设计杂项
MENU工作机制
系统中的menu部分是我们自己设计的,数据结构为:
typedefstructmenuNode{
char*pPrompt;// 此节点的提示信息
intnumChildren;// 子节点的个数
structmenuNode*pChildren;// 子节点的入口
FUNCPTRpHandlers;// 此节点对应的处理函数
}menuNode;
通过静态方式组织系统menu节点成员,并通过一个递归方式实现了菜单功能:
voidmenu_main(void)
{
menuExitFlag=FALSE;
if(mRootMenuNode.pHandlers){
if((*(mRootMenuNode.pHandlers))(mRootMenuNode.pPrompt)==OK){
menu_sub(mRootMenuNode.pChildren,mRootMenuNode.numChildren);
}
}else{
menu_sub(mRootMenuNode.pChildren,mRootMenuNode.numChildren);
}
menuExitFlag=FALSE;
kbdkey_mode_enter(KBDKEYMODE_NONE);
}
多语言支持
系统可很容易地支持更多语言,这要归功于rcc_language.c提供的多语言支持功能。
RCC_Language_Id_add():
增加要支持的语言及其前缀标识,如要增加对中文的支持,则可调用RCC_Language_Id_add(RCC_LANGUAGE_CN,RCC_LANGUAGE_ID_CN),这样rcc_language.c在根据相应的提示信息中查找中文就以前缀”|CN”查找,至到遇到分隔符”|”。
RCC_Language_Id_show():
查看系统支持的语言及前缀标识。
RCC_Language_Default_Set():
设置默认的语言,即在查找相应的语言帮助信息未成功的情况下使用默认语言显示。
RCC_Language_Set():
设置当前语言。
RCC_Language_Get():
获取当前语言。
举一个例子:
在web的登录页面中有一个login(登录)按钮,如果当前语言是英文则显示login,是中文则显示登录,那么代码可这样实现:
#defineloginPrompt_EN"Login"
#defineloginPrompt_CN"登录"
#defineloginPromptEN(loginPrompt_EN)CN(loginPrompt_CN),其实loginPrompt的全部信息是:
|EN:
Login|CN:
登录
在read_login()中通过RCC_Language_Help_String_Get(loginPrompt,pDest);函数调用,根据当前语言如果是英文,则会从|EN:
Login|CN:
根据英文的前缀标识EN找到Login,然后传给pDest,这样就获取到了相应的语言,从而可以很容易地支持多种语言。
对于menu、CLI支持多种语言,同上。
但需要说明的是如果真正要支持某一语言,则要有相应的字库支持,对于如何支持字库,则可以由牛ben同学进行补充。
快速转发实现
我们的系统语音质量好也与我们实现了快速转发有一定的关系(呵呵)。
根据软件系统架构图,我们可以看出,当从以太收到语音数据时,会先送到以太的链路层处理,这层有一个主要的工作是去除链路层头部,并将剩下的IP数据交给IP层处理,然后IP层做必要的处理,并剥去IP头部,再将语音数据送到UDP层处理,UDP处理完后再交给RTP层处理,RTP剥离出真正的语音数据,才将其送到DSP,并最终给用户播放出声音来。
先不说层层检查会浪费CPU时间,单就各层的任务间切换就会消耗大量的CPU时间,从而导倒语音处理的滞后,因此我们设计了快速转发功能。
快速转发的主要思想是每建立一个会话,就同时建立一个会话地址表(又称快速转发表),其实就是本地(IP+port)与远端(IP+port)的一个对应关系,这样,当以太收到语音数据时,先定位出IP及UDP信息,查找是否在快速转发表项中,如果在,则说明数据是到本地的语音数据,则直接定位到RTP处,取出语音数据,交由DSP处理;而对于DSP打包完成后的语音数据,则根据此表项,直接打包成以太数据,通过调用相应的以太接口处理函数将数据发送出去。
相对正常流程,快速转发直接在一个任务中处理了语音数据,并采用了简化方式,从而提高了处理效率。
主要数据结构:
typedefstruct{
unsignedlongsrcip;
unsignedlongdstip;
unsignedshortsport;
unsignedshortdport;
}sessionQTKey;
如何增加配置命令
我们的设备有四种配置方式:
CLI命令行、WEB、MENU及auto-provisioning方式,auto-provisioning方式是为客户定制的自动方式。
CLI命令行:
这种方式就是通过终端或telnet进行的交互式配置方式,通过showrunning-config可以看到当前的配置内容,而showstartup-config则可以看到保存到flash中的配置,系统启动时读取flash中的startup文件,并设置话机。
对话机的每条配置都必须增加相应的CLI命令,这是由于信息保存就是以命令行的方式保存到flash中。
可以没有其它配置方式,但要支持配置可保存,目前就必须支持CLI命令方式。
WEB配置:
则为用户提供了一种方便、直观的配置方式;
MENU配置:
为用户提供