扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
HeartLessProxy::run()
myWorkerThread->run();
mySipThread->run();
通过上面可以看到有两个Run方法的调用,第一个是WorkThread的Run方法,它的主要作用是处理UaBuilder的Process方法,主要用来处理Sptr
现在我们来看一下两个Run方法的实现:
2.5.1 WorkerThread的Run方法:
UaBuilder::process( const Sptr
{
//处理以下的四种事件
/// SipEvent
Sptr
sipEvent.dynamicCast( nextEvent );
if ( sipEvent != 0 )
{
//处理本地的SIP的事件,包括对状态机的设置和命令/状态队列返回的操作在下面将//对它做详细的介绍
if( processSipEvent( sipEvent ) )
{
return;
}
//向消息队列myCallContainer中插入相应的事件信息。
sendEvent( nextEvent );
return;
}
/// UaDeviceEvent
Sptr
uaDeviceEvent.dynamicCast( nextEvent );
if ( uaDeviceEvent != 0 )
{
处理本地的设备事件,最主要的就是处理摘机信号;
if( processUaDeviceEvent( uaDeviceEvent ) )
{
return;
}
sendEvent( nextEvent );
return;
}
/// UaDigitEvent
Sptr
uaDigitEvent.dynamicCast( nextEvent );
if ( uaDigitEvent != 0 )
{
//处理在规定的时间间隔(Kickstart)主动呼叫事件的触发。
if( processUaDigitEvent( uaDigitEvent ) )
{
return;
}
sendEvent( nextEvent );
return;
}
/// UaTimerEvent
Sptr
uaTimerEvent.dynamicCast( nextEvent );
if ( uaTimerEvent != 0 )
{
//在各种SIP命令的回应产生了超时事件后,系统的事件触发。例如:
//在StateTrying()中addEntryOperator( new OpStartTimer )在myEntryOperators队列中加入
//该Operator(指一个操作,例如呼叫或者是进入等待),这里我们这个Operator在时间到达
//以后户会被OpTimeout::process的方法检测到(isTimeout(event)进行检测,对StateTrying
//整个状态进行检测,也就是Trying事件),最后如果UaTimerEvent事件被触发,那么,//就会调用:stateMachine->findState( "StateError" )这个状态,进入错误状态,实施错误的
//处理机制,同时向myEntryOperators队列中加入一个新的Operator--OpStartErrorTone,
//从而被processUaTimerEvent过程扑捉到,最后通过SendEvent发送到执行队列里去。
if( processUaTimerEvent( uaTimerEvent ) )
{
return;
}
sendEvent( nextEvent );
return;
}
assert( 0 );
}
2.5.1.1 processSipEvent
顾名思义,processSipEvent方法是对队列中的SIP消息进行处理,我们来看下面的程序:
bool UaBuilder::processSipEvent( const Sptr
{
Sptr
statusMsg.dynamicCast( sipEvent->getSipMsg() );
// 检验是否为返回的状态码(主要是对Notify,Subscribe,Register三种状态进行单独处理)
//下面做详细介绍
if ( statusMsg != 0 )
{
if( handleStatusMsg( sipEvent ) )
{
return true;
}
}
//在这里表示接收到一个SIP的消息,
//检验是否为一个SIP的消息而不是一个状态(例如是否为Invite命令)
/// Let's check the call info, now
callId = sipEvent->getSipCallLeg()->getCallId();
callInfo = calls->findCall( callId );
if ( callInfo == 0 )
{
//下面分成两种状况进行讨论,一种是接受到Invite的消息,一种是接收到一个普通的
//命令,例如
Sptr
inviteMsg.dynamicCast( sipEvent->getSipMsg() );
if ( inviteMsg == 0 )
{
//如果大家在这里有什么奇怪的话没有必要,为什么除了inviteMsg以外的所有的消
//息都不处理呢?其实这些消息都在SipThread这个程序中处理了,在Ua这个大状态
//机中所有的状态都是以Invite这个消息作为启动的。每一个INVITE启动一个系列的//消息和状态。
return true;
}
else
{
//收到一个Invite消息,这个时候我们就要进入相应的处理机制中了;
callInfo = calls->newCall
( sipEvent->getSipCallLeg()->getCallId() );
callInfo->setFeature( stateMachine );
如果进入的状态是自动呼叫(Auto Call)或者是自动应答(Auto Answer)状态(这
//两种状态的确定要在CFG文件中体现)
if ( UaConfiguration::instance()->getLoadGenOn() )
{
/// Assume this is a new call...
/// Also assume that we are not in use.
callInfo->setState( stateMachine->findState( "StateAutoIdle" ) );
//StateAutoIdle这个状态是一个自动应答和自动呼叫(按照呼叫列表)时候的状态,这里我
//们不做介绍,它本身和手动呼叫是非常相似的。
}
else // LoadGen is off
{
//下面这个程序会进入等待远端SIP事件和本地呼叫事件的状态StateIdle
if( handleCallWaiting( callInfo ) )
{
cpLog( LOG_ERR, "Returned from handleCallWaiting\n" );
return true;
}
}
} // lots of brackets!
}
return false;
} /// UaBuilder::processSipEvent
handleStatusMsg在做什么?
前面我们已经作了简单的介绍,这个函数的主要目的是在处理Rgister,Notify,和Subscribe等几个状态,并且分别调用他们的处理机;
Rgister调用它的处理机:
handleRegistrationResponse他的主要作用是处理返回的各种Rgister状态,例如200,4XX或者是100等状态,另外它还负责在作为Mashal Server的时候转发各种状态时候,重新设定Expire的值;另外要注意的是在Register中增加了一个新的返回--Trying这个是非常合理的,特别是大型网络中,对服务器端的性能判定很有效,所以使用协议栈的同志能好好利用这个机制;另外如果发挥的值是401/407状态(未授权),还需要调用authenticateMessage做相应的处理,以返回的(401/407)状态中所带的密钥加密新的Rgister消息,发送给Register服务器重新进行授权判定;有兴趣的可以看看BaseAuthentication中的addAuthorization函数。在介绍UaMarshal和Redirect Server的时候会着重讨论这个问题。
注明:Subscribe的处理机在Feature Server章节里面在再详细介绍)。
2.5.1.2 processUaDeviceEvent
前面说了,processUaDeviceEvent主要是用来处理本地的设备事件,最主要就是处理摘机信号,在这里程序的流程我就不详细的列出,不过我们从主要的程序主体部分可以看出:
在uaDeviceEvent->type == DeviceEventHookUp也就是检测了摘机以后,程序会采取某些必要的方式取得CallID(主要是通过CFG文件),最后让程序进入状态机的StateIdle状态,这个状态是接收和发送消息的初始状态,我们可以在后面将会重点介绍这个状态;
2.5.1.3 processUaDigitEvent
也是主要通过判定CFG文件中的LoadGen_On的参数是On或者是Off来决定是否进入StateAutoIdle状态,或者是StateAutoRS状态(自动通过Marshal Server进行中转所有的SIP的消息和状态,在Marshal Server的时候会做详细的介绍)。
2.5.1.4 processUaTimerEvent
这个的流程也实在没有什么好说的,前面也有了一定的介绍,如果大家对这些还有不明白的话,可以看一下SIP协议中Trying过程的走势,主要是对超时处理部分的介绍,就会明白(按照前面所说的UaBuilder::Process中关于SIP命令消息超时的介绍部分)。
2.5.2 SipThread的Run方法:
Void SipThread::thread()
{
… …
while ( true )
{
try
{
//接收所发送的消息,并且准备置入相关的队列中;
Sptr
if ( sipRcv != 0 )
{
Sptr
if ( sipMsg != 0 )
{
//根据本地的地址来检查是否发生了路由环路
if ( discardMessage(sipMsg) ) continue;
// 在这里的myOutputFifo就是 myCallProcessingQueue(异地输入消息的队
//列),在Workthread构建的时候会把这个队列带入作为处理参量
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者