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


2.6.1 媒体设备启动
DeviceThread->run(); //调用SoundcardDevice::hardwareMain(0)
第一个是调用Sound Card的处理进程 , 它最主要的用处是返回各种按键的处理信息 , 他的具体的作用可以参看程序 , 和具体的操作手册 , 非常的简单易懂 , 不用具体介绍 , 不过要注重的一点是 , 在程序中 , 启动按键事件的检测是通过RTP/RTCP的事件触发的 , (很明显 , 例如在通话的时候按下z表示挂机 , 必须是在有RTP/RTCP事件) , 说简单了 , 没有设备 , 键盘事件无法触发 。
2.6.2 启动RTP线程 , 用于对RTP/RTCP包的接收和发送治理;
rtpThread->run //调用SoundCardDevice::processRTP()
参看RtpThread实例化的过程可以看出 , 实际上就是调用SoundCardDevice的processRTP过程 。
SoundCardDevice::processRTP ()
{
… …
if (audioStack == 0)
{
… …
return;
}
bool bNothingDo = true;
RtpSessionState sessionState = audioStack->getSessionState();
if ( sessionState == rtp_session_undefined )
{
deviceMutex.unlock();
… …
return;
}
if( sessionState == rtp_session_recvonly
sessionState == rtp_session_sendrecv )
{
// audioStack就是RtpSession , 在这里它是在构建这个声音设备的时候 , 就创建它了 。
//这里表示从一个创建好的RTP会话中接收一帧数据 ,
inRtpPkt = audioStack->receive();
if( inRtpPkt )
{
//这里的声卡目前只能接受一种压缩方式PCM , 所以只能解析这一种最常用的 ,
if( inRtpPkt->getPayloadType() != rtpPayloadPCMU
//RTP的采样频率是否为要求的频率 , 例如为20ms
inRtpPkt->getPayloadUsage() != NETWORK_RTP_RATE )
{
cpLog(LOG_ERR,"Received from RTP stack incorrect payload type");
}
//将数据输出到声卡 ,
writeToSoundCard( (unsigned char*) inRtpPkt->getPayloadLoc(),
inRtpPkt->getPayloadUsage() );
bNothingDo = false;
… …
}
}
// 这里是发送一帧数据;
if( sessionState == rtp_session_sendonly
sessionState == rtp_session_sendrecv )
{
int cc;
if( audioStack->getRtcpTran() )
{ //假如有发送零声的情况 , 例如零声回送被叫端 , 这里在OpRing里通过//sendRemoteRingback过程来实现向远端回送零声(sendRingback=True)
if( sendRingback )
{
cc = getRingbackTone( dataBuffer, RESID_RTP_RATE );
#ifdef WIN32
Sleep(15);
#endif
}
else
{//从声卡中读入一帧数据 , 按照cfg文件中规定的采样标准
cc = readFromSoundCard( dataBuffer, RESID_RTP_RATE );
}
if ((cc > 0) && audioStack)
{//将这帧数据(毛数据 , 未压缩的作成RTP包发送出去);
audioStack->transmitRaw( (char*)dataBuffer, cc );
bNothingDo = false;
}
… …
}
}
… …
deviceMutex.unlock();
return;
}
2.6.3 合法用户列表的获取(Redirection Server专用)
第三个过程是featureThread->run, , 这个过程主要是用在向重定向服务器(Redirection Server)和Provisioning Server中的Feature线程 , 它实质上是调用 subscribe -Manager->subscribeMain,主体程序部分是向Provisioning Server发送Subscribe消息 , 在这个循环中会反复的发送SubScribe消息到Provision Server中去 , 稍后我们要介绍的UaBuilder::handleStatusMsg(UaBuilder::processSipEvent中)过程会将会处理从Provision Server 返回的Notify消息 , 关于Subscribe/Notify消息对的介绍我们可以参看在Vocal中的相关介绍 , 它的作用范围是在一个普通的UA向Marshal Server进行注册或者是证实的时候 , Marshal Server同时向Redirection Server发出Register消息 , 并且由Redirection Server向Provisioning Server发送Subscribe消息 , 对用户列表进行检测;我们可以举一个例子来说明这个过程:

推荐阅读