基于SIP的嵌入式UA语音终端设计

2013-09-12 04:24沙爱军沈卫康毛其林
电子测试 2013年20期
关键词:主程序开发板通话

沙爱军,沈卫康,毛其林

(南京工程学院通信工程学院,江苏南京,211167)

0 引言

SIP(Session Initiation Protocol)会话初始协议,最新的SIP 规范为RFC 3261。作为应用层控制信令协议,SIP具有简单、灵活的特点,正逐步取代H.323 协议成为 VoIP 的标准协议。

SIP 基于客户机/服务器结构。用户代理(User Agent ),即SIP 终端,是SIP 系统中的最终用户,可分为:用户代理客户端UAC,用于发起呼叫请求;用户代理服务器UAS,用于响应呼叫请求,一个终端往往既可以充当UAC,也可以充当UAS。

在一个VoIP网络中,UA作为终端设备,需求大,而且对移动便携和价格也有要求。嵌入式设备具有便携、专用、可裁剪、性价比等优点,本文将在嵌入式平台上实现一个基于SIP的的语音电话终端,并对系统实现中所需的关键技术和工作过程进行介绍。

1 UA实现框架

需求分析可知,作为一个语音电话终端,需要如下几个方面的功能:(1)要有音频采集/播放设备以及相关的编解码算法;(2)要有网卡处理设备,传输双方的信令和音频数据;(3)要采用实时传输协议保证语音传输质量。基于上述分析,系统的实现框架可设计如图1,后面将具体阐述。

图1 UA 实现框架

2 终端的硬件设备和操作系统

硬件平台采用一款ARM开发板:CPU为三星公司生产的主频可达400MHz的S3C2440A;音频处理设备采用Philips公司生产的UDA1341TS,可实现A/D的相互转换, S3C2440A 通过 L3接口可以控制和配置 UDA1341TS,L3 接口有 L3MODE、L3DATA和 L3CLOCK 三根信号线,音频的驱动采用OSS架构,类似其他驱动,音频驱动的实现分为初始化、打开设备、读写操作、设备查询/控制、释放设备和注销设备等部分;开发板带有网络芯片DM9000,满足联网的要求;系统还带有串口等其他设备。本次使用的内核Linux-2.6.32.2 已经能支持UDA1341 音频芯片的驱动,但提供的是针对SMDK2440,SMDK2440的录音通道,使用的是VIN1,而在本开发板使用的则是VIN2,因此需修改内核驱动linux-2.6.32.2/sound/soc/codecs/ uda134x.c中添加uda134x_write(codec, 2, 2|(5U<<2)),把录音通道改为VIN2。

软件平台采用linux-2.6.32.2,Linux作为一种开源操作系统,具有较高的稳定和可移植性,可以根据需要进行内核、驱动的裁剪配置,这里将TCP、UDP协议以及声卡,网卡、串口等相关的驱动配置进去。

3 信令协议SIP及其协议栈

SIP协议作为会话控制协议,用来建立、修改和终止多媒体会话,其重要性不言而喻。这里对SIP再做点介绍。

SIP采用分层结构,最低层是语法和编码,第2层是传输层,第3层是事务层。最上层是事务用户。每个有状态的SIP 实体,都是事务用户,当发送请求时,将创建一个客户端事务实例,并将请求与目的IP 地址、端口一起发送。SIP消息分为两大类:请求(Request)和 响应(Response。请求消息分为 6 种:REGISTER、INVITE、ACK、BYE、CANCEL、OPTIONS。响应消息分为6类:1xx,2xx,3xx,4xx,5xx,6xx。其中1xx是临时响应(Provisional Response),其余是最终响应(Final Response)。

目前符合RFC3261规范的开源SIP协议栈有OPAL,VOCAL,sipX ,oSIP[5]等,oSIP 结构简单、功能齐全,可移植性好,因此本次选用了oSIP。

oSIP协议栈主要分为3大部分:状态机模块、解析器模块、工具和对话模块。其核心是状态机模块。状态机有4种类型:ICT、IST、NICT以及 NST,对不同的事务,oSIP用不同的状态机处理,并推动自身状态的改变。解析器模块主要完成对SIP 消息结构剖析、SDP 消息的结构剖析以及URI 结构的剖析。工具模块主要提供一些处理工具用于对话管理和SDP协商。

eXosip是对oSIP的扩展,它对oSIP协议栈进行了部分封装,增加了registration、 call、dialog等过程的解析,使得调用接口更加友好,使用eXosip可以简化开发任务。

4 流媒体处理部分Mediastreamer2和oRTP和语音编解码算法

流媒体处理分为3个部分Mediastreamer2和ORTP以及编解码算法。这3个本来是独立的,由于它们相互协作处理用于处理音频流,因此这里一起介绍。

Mediastreamer2负责媒体流的处理,采用纯C开发,是一个功能强大且小巧的流引擎,最小依赖只需oRTP和LIBC,可根据需要添加其他库,如SPEEX。Mediastreamer2媒体库将语音模块的工作分为几大MSFilter实体:对声卡的读写soundread/soundwrite,调用音频库的encode/decode,接收/发送RTP数据包的rtpsend/rtprecv等,利用函数指针将一系列的FILTER组合起来,多个MSFilter进行连接,形成一个MSFilter chain。

oRTP负责流媒体如何安全可靠的传输,是用C语言编写的RTP的开源协议栈,并且实现了RTCP,RTP在初始化的时候会对全局变量RtpProfile赋值,RtpProfile中的PayloadType数组的每个元素对应一种媒体流,包括了名称,采样率,声音位数,静音格式,占用带宽等媒体流属性。rtp_session_send_with_ts和rtp_session_recv_with_ts分别是oRTP发送和接收的主要函数。

语音压缩编解码算法很多,常见的有G.711PCM、GSM等算法,本次采用的G.711PCM算法,如需要更多算法,还可以使用SPEEX库。

5 UA的程序设计

本次UA部分实现了注册、呼叫、应答、挂断、退出 等电话呼叫的基本功能。UA主程序的流程图如图2示。

图2 UA主流程图

图3 mysip_init()执行流程图

(1)系统首先调用add_port_set(),设置注册时所用的注册服务器地址和端口号,通话时对端的sip url地址及本地sip端口和rtp端口号、用户名和密码等;然后调用mysip_init()。

(2)在mysip_init()中,进行一系列初始化,见图3。首先调用eXosip_init()对eXosip变量、osip库初始化,设置回调函数以及传输方式;mysip_init()接着调用eXosip_listen_addr(),eXosip_listen_addr()则对开始监听sip端口,并执行eXosip_execute ()去读取各种osip事件,并进行处理:对于要发送的message,管理程序会主动调用接口发送,对于接收到的message,可能会创建新的call、新的transaction,生成新的transaction的event,还有exosip的event,其中exosip的event是上报给管理程序的;在mysip_init()中会创建一个新的线程ua_exosip来处理这些eXosip事件,为便于描述,在(3)中再讨论这些事情,该线程创建后,会对UAC和UAS事件分别作出处理,见图4;mysip_init()继续完成初始化的调用ortp()和ms_init(),分别对oRTP协议栈和对Mediastreamer2初始化。

(3)ua_exosip()线程创建后就一直独立运行,在程序初始化完成后,它的运行要和主程序的循环读取用户输入的命令并做出响应的运行结合起来。

在ua_exosip中的exosip事件处理有很多,这里仅仅选取了UAS端收到的EXOSIP_CALL_INVITE, EXOSIP_CALL_ACK以及UAC端收到的EXOSIP_CALL_RINGING,EXOSIP_CALL_ANSWERED在图4中展示。

(4)在主程序中进入一个死循环中,循环中不断读取当前输入的命令,并根据命令的输入,执行相应的处理函数。图2中,列举了一些常见的命令,当输入r时,代表要向注册服务器注册,将执行函数sregister()完成此功能;当输入i时,代表作为UAC,将执行函数sinvite()发起一次呼叫;当输入a时,代表作为UAS,将执行函数sanswer()接听电话;当按下h时,代表挂断电话,将执行shang();当按下q时,代表退出系统,将执行squit()。这里分别以UAC端的sinvite()和UAS端的sanswer()为例,介绍实现过程。

图5为UAC端的sinvite()过程,由于这是一个呼叫发起请求,将主要调用eXosip_call_build_initial_invite(&invite, dest_call, source_call, NULL, "invite")和eXosip_call_send_initial_invite (invite)等,它们将构造一个invite 请求信息,创建一个新的call,并为该invite创建一个新的transaction,创建完call和transaction后,会根据要发送的invite生成一个transaction的event,并将event添加到transaction的event队列中,最后唤醒处理线程对transaction上的event处理。

图6 为UAS端的sanswer()过程。当接收方接听一个电话时,将向发起方发送200OK的信息,此时将建立起来一次dialog。但正式的通话要等到发起方发出ack信息之后。

(5)终端的运行分析

结合图4、图5、图6来分析一次执行的过程。当在主程序中输入i命令时,UAC将调用sinvite()发起一次呼叫,向接收端发送呼叫请求(INVITE),接收端UAS收到了来自EXOSIP层的EXOSIP_CALL_INVITE,则将执行图4中的EXOSIP_CALL_INVITE分支下的处理程序,显示“收到来自xx的呼叫”,本地振铃,发送“180”消息给UAC;当UAC收到来自EXOSIP层的EXOSIP_CALL_RINGING时,会显示“对方已振铃”;UAS端打算接听电话,在主程序中输入a命令,则调用sanswer()接听,这里将进行媒体协商,并发送200OK消息给UAC,表明已应答,一次dialog建立;UAC收到来自EXOSIP报告的EXOSIP_CALL_ANSWERED,将“显示对方已通话”,并构建、发送ACK消息给UAS,获取编码方式,调用start_media()函数进行媒体流的建立,为随时准备利用RTP传输通话语音;UAS收到来自EXOSIP报告的EXOSIP_CALL_ACK,将会显示“通话开始”,同时调用start_media()函数进行媒体流的建立。start_media()中将调用Mediastreamer2和oRTP来进行音频数据的RTP传输。

6 测试及结论

在移植好开发板所用的内核和文件系统后,再交叉编译libosip、libexosip、mediastream、ortp等库和应用程序myua.c等,得到可执行文件myua,将可执行文件和前述生成的动态库拷贝到开发板的相应目录下,就可以运行。

图4 ua_exosip中的exosip事件处理

图5 UAC端的sinvite()过程

图6 UAS端的sanswer()过程

系统的运行环境:在一个局域网内,由一台在ubuntu下运行的brekeke sip sever担任服务器,提供注册员、代理服务、定位等功能;客户端由两个移植了UA的开发板组成,地址和用户名见图7。运行时,假设1002(此时担当UAC)向1001(此时担当UAS)发起呼叫:先将两者分别运行注册;再在1002上输入i,则会发起一次呼叫;1001收到后输入a应答;1002收到发ACK则两者建立语音通话。

图7 系统的运行环境

测试表明,局域网内RTP包的丢包率为0,通话通话质量较为清晰,通话情况良好。进一步的工作可以实现视频通话,增加SPEEX等语音编码,使其能用于更多的场合。

[1]Rosenberg J.SIP: Session Initiation Protocol[S].RFC3261 ,IETF , 2002

[2]张辽.基于ARM 的嵌入式 IP 电话系统设计与实现[D].武汉:华中科技大学,2012.1.

[3]刘刚,赵剑川.Linux系统移植 [M].北京: 清华大学出版社, 2011.1.

[4]友善之臂.Mini2440 之Linux 移植开发实战指南[EB].http://www.arm9.net/.2010.04

[5]潘健等.基于Mediastreamer2的嵌入式语音终端的实现[J],湖北工业大学学报,2012,27(5):48-51

[6]胡斌.VoIP系统中基于RTP/RTCP协议的语音及视频传输的设计与实现[D].厦门:厦门大学,2009.05

猜你喜欢
主程序开发板通话
自动升级程序在船舶监测系统中的应用
微信上小额借款 请务必通话确认
浅谈数控铣削技术代码程序的嵌套方式研究
电控冰箱软件模块化设计
《戊戌元日与友人通话》
时光倒流 换回PotPlayer老图标
浅析单片机开发板的设计与制作
ARM宣布mbed Enabled Freescale FRDM—K64F开发板通过微软认证
Arduino和Atmel发布Arduino Zero开发板
2013年3月通信业主要指标完成情况(一)