在Vovida的基础上实现自己的SIP协议栈(六)

本文是系列博客的第六篇,作者卢政在Vovida项目的基础上详细阐述如何实现自己的SIP协议栈。文章中可能涉及了协议头处理、通信流程、codec编解码以及iterator和vector在协议解析中的应用。
摘要由CSDN通过智能技术生成

在Vovida的基础上实现自己的SIP协议栈(六)

卢政 2003/08/08

3.3 等待对方的呼叫:

  上面花了那么长的时间叙述了如何发起一个呼叫,我们再来介绍一下如何接收一个呼叫:

  当用户进入Idle状态以后,如果系统接收到一个INVITE消息,系统将进入Ring状态,并且进入Opring操作中,这个时候硬件设备将播放振铃声,这个时候如果用户决定摘机通话,那么offhook事件就会产生,同时OpAnswerCall将使状态机进入InCall状态,向主叫发送200响应消息,同样RTP/RTCP通道打开,开始通话,如果通话完毕,双方挂机,那么互相发送SIP Bye消息,OpEndCall将使系统重新回到Idle状态。

  下图表示了从接收到INVITE消息通话完毕的各个状态之间程序各种类之间的迁移过程,和主动呼叫的情况一样,如果协议栈软件应用于Marshal或者是Redirection Server的话,那么采用的协议流程和下面又有一些不一样了,在后续章节会对这些做详细介绍。

  在本图中粗体的部分表示加入MyEntryOperator队列中的操作符
正体的部分表示加入MyOperator队列中的操作符
斜体的部分表示加入MyExitOperator队列中的操作符


(点击放大)


下面我们来详细地介绍每个操作:

3.3.1 OpRing等待对方的振铃消息

OpRing:获取对端向本地发送的INVITE消息
const Sptr < State >
OpRing::process( const Sptr < SipProxyEvent > event )
{
Sptr < SipEvent > sipEvent;
sipEvent.dynamicCast( event );
if ( sipEvent == 0 )
{
return 0;
}
Sptr < SipMsg > sipMsg = sipEvent->getSipMsg();
assert( sipMsg != 0 );
//接收INVITE消息;
Sptr < InviteMsg > msg;
msg.dynamicCast( sipMsg );
… …

Sptr < UaCallInfo > call;
call.dynamicCast( event->getCallInfo() );
assert( call != 0 );
//在UaCallInfo中存储当前的INVITE消息;
call->setRingInvite( new InviteMsg( *msg ) );
call->setContactMsg(*msg);
//保存当前的路由消息;
call->setCalleeRoute1List( msg->getrecordrouteList() );
int numContact = msg->getNumContact();
if ( numContact )
{//保存连接
SipContact contact = msg->getContact( numContact - 1 );
Sptr < SipRoute > route = new SipRoute;
route->setUrl( contact.getUrl() );
call->addRoute1( route );
}
… …
Sptr< BaseUrl > baseUrl = msg->getFrom().getUrl();
assert( baseUrl != 0 );
// Assume we have a SIP_URL
Sptr< SipUrl > sipUrl;
sipUrl.dynamicCast( baseUrl );
assert( sipUrl != 0 );
//获取主叫的Sip URL
Data callingNum = sipUrl->getUserValue();
callingNum += "@";
callingNum += sipUrl->getHost();
signal->dataList.push_back( callingNum.getData(lo) );
//把主叫和被叫的地址(URL)都装入设备的信号队列中,为媒体流和铃声回放的RTP信道做准备
SipRequestLine reqLine = msg->getRequestLine();
baseUrl = reqLine.getUrl();
assert( baseUrl != 0 );

sipUrl.dynamicCast( baseUrl );
assert( sipUrl != 0 );
string calledNum = sipUrl->getUserValue().getData(lo);
signal->dataList.push_back( calledNum );
UaDevice::getDeviceQueue()->add( signal );
//获取主叫的SDP
Sptr remoteSdp;
remoteSdp.dynamicCast (msg->getContentData(0));
bool ringbackTone = false;
//创建本地的SDP
SipSdp localSdp;
if ( remoteSdp != 0 )
{
localSdp = *remoteSdp;
Data host = theSystem.gethostAddress();
if(UaConfiguration::instance()->getNATAddress() != "")
{
host = UaConfiguration::instance()->getNATAddress();
}
//设定本地的SDP
setStandardSdp(localSdp, host,UaDevice::instance()->getRtpPort());
}
//获取本地状态是否当前的硬件状态支持Call Waiting
HardwareStatusType hdwStatus = UaDevice::instance()->getHardwareStatus();
//检验本地是否支持零声回放(回放的话要在零声消息里增加本地的SDP)
StatusMsg statusMsg;
if (UaC
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值