主叫基本呼叫流程分析

来源:互联网 发布:参加淘宝客有效果吗 编辑:程序博客网 时间:2024/04/29 08:12
1、摘机dsp driver线程//上报摘机事件SipDrv_EventRecvCbDrv_Event.CnxId = cnxId;Drv_Event.Data = data;Drv_Event.Event = event;Drv_Event.Length = length;Drv_Event.pData = pData;Drv_Event.pEndptState = pEndptState;//将底层事件投入驱动事件队列,并激活事件处理信号量SipDrv_EventPost(&Drv_Event);bosSemGive(&gstSipDrvDC.DrvSemId);2、摘机用户sip main线程//处理事件队列中的事件SipUCC_ProcessEvent()//转化为rv事件//eRvEvent = RV_CCTERMEVENT_OFFHOOKSipUCC_DrvEventToMtfEvent(pstSipDriverEvent,&eRvEvent,&stMtfEventInfo);//检索线路终端idtermIdx = pstSipDriverEvent->pEndptState->lineId;//向MTF上报用户事件//gstIppTerm[termIdx]存储了MTF模拟终端对象的句柄,该句柄是在//用户层向MTF注册模拟终端时创建的。rvMtfSendKeyEvent(gstIppTerm[termIdx],eRvEvent,&stMtfEventInfo);//从终端基类中提取mdm终端对象mdmTerm = rvIppMdmTerminalGetMdmTerm(hTerm);//构造参数列表rvMdmParameterListConstruct(¶msList);//处理摘机事件switch (event)case RV_CCTERMEVENT_OFFHOOK://为当前事件构造keyed=kh参数addParam(¶msList, "keyid", "kh");//处理kf/kd事件rvMdmTermProcessEvent(mdmTerm, "kf", "kd", NULL, ¶msList);rvMdmTermQueueObsEvent(term, pkg, id, media, args);//如果该终端没有激活,则忽略该终端所有事件//该标记在用户层注册物理终端时设置为false来激活if(term->inactive)return//构造请求事件对象,将该请求事件放置到终端blockedEventBuffer//中。queueBlockedObsEvent(term, &item, media, args);//递送请求事件rvMdmTermPostEvent(t);//如果终端未注册,则忽略该终端所有事件if (rvCCTerminalMdmBlockedEventIsUnregOn(term) == RV_TRUE)return//向MTF发送消息,触发MTF处理终端事件,这里与MTF事件//处理线程的关键也能过终端对象句柄指针。sendEventToMsgSocket(x);//资源释放rvMdmParameterListDestruct(¶msList);3、摘机MTF主线程//mdm管理处理终端事件rvCCProviderMdmProcessTerminationEvent(data)rvMdmTermProcessBlockedEvent(term);//判断当前终端是否激活处理事件上报的标记,该标记在注册模拟线路时开启,//如果开启,则进行上报事件的处理if (rvCCTerminalMdmBlockedEventIsObsOn(term))processBlockedEventObserved(x);//当前终端如果有待处理事件,则进行处理while (rvListSize(&term->blockedEventBuffer))//获取第一个待处理事件对象event = rvListFront(&term->blockedEventBuffer);//从事件对象中分别提取媒体描述符、包对象名、包对象子分类名//和当前事件参数media=  (RvMdmMediaStream*)rvCCTerminalMdmGetMediaEventData(term);pkg = rvMdmPackageItemGetPackage(rvMdmEventGetName(event));id  =rvMdmPackageItemGetItem(rvMdmEventGetName(event));args = (RvMdmParameterList*)rvMdmEventGetParameterList(event);//事件处理rvMdmTermProcessObsEvent(rvCCTerminalMdmGetMdmTerm(term),pkg,id,media,args);//如果是数图事件,则进行单独处理if(isInDigitMapPkg(&item) )//当前事件为摘机流程,暂不关心//处理其它事件rvCCTerminalMdmProcessEvent(t, pkg, id, media, args);//将事件包映射为事件枚举RV_CCTERMEVENT_OFFHOOKevent = rvCCTerminalMapEvent(x, pkg, id, args, keyId);//如果上报拨号完成事件,则将最终的号码串存入终端//dialString中if (event == RV_CCTERMEVENT_DIALCOMPLETED)//当前摘机处理暂不关心//存储最后事件处理到终端的lastEvent中setLastEvent(term, pkg, id, args);//事件处理rvCCTerminalProcessEventId(x, event, keyId, callMgr, media);//获取该终端当前活动的连接对象c = rvCCTerminalGetActiveConnection(t);switch(eventId)case RV_CCTERMEVENT_OFFHOOK:if (eventId==RV_CCTERMEVENT_OFFHOOK)//标记音频终端状态为已经激活话柄t->audioTermState |= RV_CCAUDIOTERM_HS_ACTIVE;//对音频终端对象进行事件处理eventId = rvProcessAudioTermEvent(t, c, eventId);//保存音频终端对象,如果是模拟线路类型则音频//终端对象为模拟终端对象自身。oldAt = rvCCTerminalMdmGetActiveAudioTerm(t);//获取当前活动连接的状态activeConnState =rvCCConnectionGetState(rvCCTerminalGetActiveConnection(t));//如果当前终端所有连接都是空闲,或者当前活动//连接是在振铃,则进行处理。if ((rvCCTerminalGetNumActiveConnections(t) == 0)||(activeConnState== RV_CCCONNSTATE_ALERTING)||(activeConnState==RV_CCCONNSTATE_TRANSFER_ALERTING))//设置模拟终端对象的音频终端对象为自身//term.activeAudioTerm = termTerm_evn = setActiveAudioTerminal(t, event);returnterm_evn;//基本呼叫摘机时连接都是空闲,因此不走后继//流程代码。//获取当前线路终端连接是否存在呼叫控制对象,如果//不存在呼叫控制对象,则构造一个新的呼叫对象call = rvCCConnectionGetCall(c);if (call == NULL)rvInitNewCall(callMgr, c);//创建一个呼叫对象,放入callMgr列表中//callMgr. Calls call//call.callMgr = callMgrcall = rvCCCallMgrCreateCall(callMgr);//进行呼叫控制对象与连接对象的关链//conn.call = call//call->connections conn//call->connNum++rvCCCallAddParty(call, conn);break;//继续处理摘机事件rvProcessEvent(c, eventId, reason);//处理终端连接事件,这里调用回调函数为//rvCCConnMdmProcessEvent,下面单独分析rvCCConnectionProcessTermEvent(c, eventId,&callStillAlive, reason);x->funcs->processTermEventF(x, eventId, callStillAlive, reason);//在挂机事件处理中,如果该线路还存在其它呼叫,则进行//其它呼叫的挂机判断处理。当前是摘机事件,暂不关心。if ((origEventId == RV_CCTERMEVENT_LINE)    || (origEventId == RV_CCTERMEVENT_ONHOOK)  ||(origEventId == RV_CCTERMEVENT_REJECT_KEY))xxx//事件处理完成后从列表中消除rvListPopFront(RvMdmEvent)(&term->blockedEventBuffer);------------------------------------------------------------------------------------------------------------------------------//MDM连接对象处理终端事件(这个函数在下文分析时省略了do while的循环处理,这里根据返回下一个事件的值进行循环处理,比如当前摘机事件在处理,摘机事件处理完成后,设置下一个事件为RV_CCTERMEVENT_DIALTONE,则继续调用rvCCConnMdmProcessEvent函数进行处理)rvCCConnMdmProcessEvent//终端连接对象进行事件处理,当前摘机事件不做任何处理eventId =  rvCCTermConnProcessEvents(conn, eventId, &eventReason);//调用回调mdmExtClbksDeprecated.preProcessEvent或//mdmExtClbks.preProcessEventCB通知用户,在事件处理之前是否需要进行其它操作rvIppMdmExtPreProcessEventCB(conn, eventId, &eventReason);//进行call ctrl状态机处理。rvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);switch (event)case RV_CCTERMEVENT_OFFHOOK://获取当前连接状态,当前在IDLE状态switch (rvCCConnectionGetState(conn))case RV_CCCONNSTATE_IDLE://conn. State = RV_CCCONNSTATE_INITIATEDrvCCConnectionSetState(conn, RV_CCCONNSTATE_INITIATED);//调用rvCCConnMdmInitiatedCB回调进行mdm连接对象的//初始化,rvCCConnMdmInitiatedCB回调在下面单独分析。//播号音的播放及数图的激活则在此回调进行。rvCCConnectionInitiatedCB(conn);x->clbks->initiatedCB(x);//调用mdmExtClbksDeprecated.connectionCreated回调通知用户层//一个新的MDM连接已经建立rvIppMdmExtConnectionCreatedCB(conn);//清除终端的数图收集池,为数图收号做准备//term.dialString = 清空rvCCTerminalMdmResetDialString(t);//返回放播号音事件,继续调用rvCCConnMdmProcessEvent函数进行处理return RV_CCTERMEVENT_DIALTONE;//调用用户回调显示待处理显示rvCCConnectionDisplay(conn, t, eventId, eventReason, rvCCProviderMdmGetDisplayData(p));//调用回调通知用户,在事件处理之后是否需要进行其它操作。rvIppMdmExtPostProcessEventCB(conn, eventId,eventReason);-------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmInitiatedCB//这里rvCCConnectionGetLineId获取conn对象中的lineId标识,在终端对象注册时//和终端关联的3个conn对象都进行顺序赋值lineId标识,从1到3。rvCCTerminalMdmSetLineInd(t, rvCCConnectionGetLineId(x), RV_INDSTATE_ON);//构造包Indid参数rvMdmParameterListConstruct(¶ms);RvSnprintf(strLineId, sizeof(strLineId), "l%03d", lineId);addSignalParam(¶ms, "Indid", strLineId);switch (state)case RV_INDSTATE_ON://添加state参数addSignalParam(¶ms, "state", "on");//触发线路连接指示包ind/is,该包中协带两个参数Indid=l00x,//state=onrvCCTerminalMdmStartSignalUI(x, "ind", "is", ¶ms);//给终端触发信号startSignal(term, pkg, id, args, RV_MDMSIGNAL_BRIEF);//构建信号描述符对象buildSignalDescr(x, &signalDesc, pkg, id, args, type);//处理信号描述符rvMdmTermProcessNewSignals(x, &signalDesc);//遍历信号描述符中所有信号for(i=0;i<rvMdmSignalsDescriptorGetNumSignals(signalsDescr);i++)signal = rvMdmSignalsDescriptorGetSignal(signalsDescr,i);//如果信号类别不是短暂类型,则检查当前信号列表中是否有相//同的信号正在处理,如果是,则忽略此次信号触发。if (rvMdmSignalExGetType(signal) != RV_MDMSIGNAL_BRIEF)for(iter=rvListBegin(&x->curSignals);iter!=rvListEnd(&x->curSignals);iter = rvListIterNext(iter))curSignal = rvListIterData(iter);if (signalMatch(signal,&curSignal->signal))startTheSignal = RV_FALSE;//如果上面条件没有触发,则继续进行信号处理if (startTheSignal)//信号启动rvMdmTermStartSignal(x,signal,&type,&timeout)//判断当前终端类是否支持此包对象,如果支持才进//行处理。终端类对包的支持在rvInitIppClasses函数中//设置。if (rvMdmTermIsPkgSupported_(rvCCTerminalMdmGetMdmTerm(x),rvMdmPackageItemGetPackage(name)))//检查当前ind包中是否存在is信号对象//如果不存在则取当前signal自身,如果包中含有//该信号注册,则取包中的信号对象做为默认参考//对象,后面进行信号处理时,如果signal对象的//参数值没有协带,则从info中的信号对象中获取。info = rvMdmTermMgrGetSignalInfo_(mdmMgr,&name->package,&name->item);//映射信号参数到临时变量中//signal->id = id;//signal->pkg = pkg;//signal->params = args;buildMdmSignal(x,&mdmSignal,signal);//当前播号音信号属于brief类型,则//调用term->termClass->playSignalF回调进行//处理。if (*type==RV_MDMSIGNAL_BRIEF)//term->termClass->playSignalF = //rvStartSignalIntCB,该回调函数最终根据上//面传来的信号确定为//RV_MTF_SIGNAL_IND_LINE指示类型信号。//之后再次调用应用层注册的终端管理回调//SipStack_MtfStartSignalCB进行最终的信号//处理。当前代码不处理//RV_MTF_SIGNAL_IND_LINE类型信号,暂不//关心。rvMdmTermPlaySignal_(&x->mdmTerm,&mdmSignal,reportCompletion,&error))else//no thing//如果信号不是短暂类形,则将此信号加入到mdm终端//当前信号处理列表中mdmterm.curSignalsif( type!=RV_MDMSIGNAL_BRIEF )addCurSignal(x,signal,timeout);//设置终端指示线路激活(参照上面线路指示rvCCTerminalMdmSetLineInd信号处理,//最后跟到rvStartSignalIntCB中,没有对该信号的处理)。rvCCTerminalMdmSendLineActive(t, rvCCConnectionGetLineId(x), RV_TRUE);//指示终端放播号音,这里不进行分析了,进行几次回调,最终触发应用层执行放//播号音。首先调用终端类的回调rvStartSignalIntCB,之后该函数调用了用户注册到//终端管理的回调SipStack_MtfStartSignalCB。rvCCTerminalMdmStartDialToneSignal(t);//启动播号音启始定时器,该定时器的超时回调函数是在模拟终端注册时在//rvCCTerminalMdmConstruct函数中创建的,回调函数为//rvCCTerminalMdmDialToneTimerExpired。IppTimerStart(rvCCTerminalMdmGetDialToneTimer(t),IPP_TIMER_RESTART_IF_STARTED,rvCCProviderMdmGetDialToneDuration(p));//启动了digitMapCurTimer定时器,并设置digitMapActive = RV_TRUE数图激动标记。//该定时器是在终端注册时,rvMdmTermDigitMapTimerConstruct函数中创建,回调函//数为digitMapTimerProcess0,该函数用于数图处理时,数图模块在该时间超时之后,//自动触发数图完成事件。注意上面还有一个播号音放音超时事件,两个不同配置项。rvCCTerminalMdmSetWaitForDigits(t);4、MTF主线程继续使用rvCCConnMdmProcessEvent函数处理内部RV_CCTERMEVENT_DIALTONE事件。rvCCConnMdmProcessEvent//term连接对象处理事件,当前该函数没有对RV_CCTERMEVENT_DIALTONE事件处理rvCCTermConnProcessEvents(conn, eventId, &eventReason);//call控制主状态机处理rvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);switch (event)case RV_CCTERMEVENT_DIALTONE://仅仅将term连接对象的连接状态迁为DIALING//conn.state =RV_CCCONNSTATE_DIALINGif (rvCCConnectionGetState(conn) == RV_CCCONNSTATE_INITIATED)rvCCConnectionSetState(conn, RV_CCCONNSTATE_DIALING);returnRV_CCTERMEVENT_NONE;5、按键dsp driver线程SipDrv_EventRecvCb//发送按键事件到gstSipDrvDC.DrvEventQ队列中SipDrv_EventPost(&Drv_Event);6、按键用户sip main线程SipUCC_ProcessEvent//将DSP事件映射到MTF事件参数对象//eMtfEventId=RV_CCTERMEVENT_DIGIT_END;//info->digit = RV_MTF_DIGIT_x;SipUCC_DrvEventToMtfEvent(pstSipDriverEvent,&eRvEvent,&stMtfEventInfo);//向MTF发送事件rvMtfSendKeyEvent(gstIppTerm[termIdx],eRvEvent,&stMtfEventInfo);switch (event)case RV_CCTERMEVENT_DIGIT_END://将info->digit转换转换为包的参数对象keyid= xxxxxxmapDigitToEvent(info->digit, strParam)addParam(¶msList, "keyid", strParam);//构成kp/ku包请求事件,给MTF发送消息,触使MTF线程处理。rvMdmTermProcessEvent(mdmTerm, "kp", "ku", NULL, ¶msList);7、按键MTF主线程处理//mdm管理处理终端事件rvCCProviderMdmProcessTerminationEventrvMdmTermProcessBlockedEvent(x);processBlockedEventObserved(x);rvMdmTermProcessObsEvent(rvCCTerminalMdmGetMdmTerm(term),pkg,id,media,args);//当前是数据事件包,该判断条件成立if(isInDigitMapPkg(&item) )//上面摘机流程已经激活数图处理if(term->digitMapActive )//进行数图算法处理,该函数在单个文件中进行分析。processDigitMapEvent(term,&item,media,args);//mdm终端对象进行事件处理rvCCTerminalMdmProcessEvent(t, pkg, id, media, args);//映射为RV_CCTERMEVENT_DIGIT_END事件event = rvCCTerminalMapEvent(x, pkg, id, args, keyId);//将最后处理事件存储在term.lastEvent中setLastEvent(term, pkg, id, args);rvCCTerminalProcessEventId(x, event, keyId, callMgr, media);//获取当前终端的活动连接对象c = rvCCTerminalGetActiveConnection(t);//进行事件处理rvProcessEvent(c, eventId, reason);//呼叫控制连接进行终端事件处理//调用x->funcs->processTermEventF回调进行事件处理,//该回调函数为rvCCConnMdmProcessEvent,最终进行//mdm的连接对象进行事件处理。该函数下面单独分析。rvCCConnectionProcessTermEvent(c, eventId, &callStillAlive,reason);--------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmProcessEvent//term连接对象处理事件rvCCTermConnProcessEvents(conn, eventId, &eventReason);switch(eventId)case RV_CCTERMEVENT_DIGIT_END://收到按键事件,在连接为通话状态,且非忙转时,处理outbanddtmf,当前//普通呼叫流程不会进入。if ((rvCCConnectionGetTermState(conn) == RV_CCTERMCONSTATE_TALKING) &&(rvCCCallGetTransferType(rvCCConnectionGetCall(conn)) != RV_CCCALL_TRANSFER_BLIND))//out band dtmf处理//调用mdmExtClbksDeprecated.preProcessEvent或mdmExtClbks.preProcessEventCB回调//通知用户进行事件处理之前是否执行其它操作。rvIppMdmExtPreProcessEventCB(conn, eventId, &eventReason);//呼叫控制状态机处理rvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);switch (event)case RV_CCTERMEVENT_DIGIT_END://当前连接状态正在拨号状态if (rvCCConnectionGetState(conn) == RV_CCCONNSTATE_DIALING)//执行新的按键处理,一个按键会触发on/off两个按键事件上报,这里在//分析时只列举了off。最终调用x->clbks->newDigitCB回调进行处理。//该回调函数为rvCCConnMdmNewDigitCB,在下面单独分析。rvCCConnectionNewDigitCB(conn, RV_CCCAUSE_EVENT_END);return RV_CCTERMEVENT_NONE;//调用回调通知用户进行状态显示rvCCConnectionDisplay(……);//调用回调mdmExtClbks.postProcessEventCB通知用户进行事件处理之后是否执行其它//操作。rvIppMdmExtPostProcessEventCB(conn, eventId,eventReason);-------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmNewDigitCB//如果当前是第一次按键,并且是按键on事件,则停止MDM终端对象的dialToneTimer//定时器,及播号音。if ((rvCCTerminalMdmIsFirstDigit(t)) && (reason == RV_CCCAUSE_EVENT_BEGIN))//停止dialToneTimer定时器IppTimerStop(rvCCTerminalMdmGetDialToneTimer(t));//给用户层发送信号停止rvCCTerminalMdmStopSignals(t);//获取当前终端关联的音频处理终端,当前终端为模拟终端,则音频处理终端//为自身。at = rvCCTerminalMdmGetActiveAudioTerm(x);term = rvCCTerminalMdmGetImpl(at);rvMdmTermEventStopSignals(term);//停止终端对象的curSignals中当前所有正在执行的信号stopActiveSignals(x,NULL,RV_MDMSIGNAL_GOTEVENT);for (i=rvListBegin(&x->curSignals);i!=rvListEnd(&x->curSignals);i=next)next=rvListIterNext(i);//这里最终调用了用户在终端管理中设置的回调函数// SipStack_MtfStopSignalCB来停止放音。stopCurSignal(x,&i,reason);//简单跟了一下代码,curSignalLists好像不会触发。processNewSignalLists(x,NULL,RV_MDMSIGNAL_GOTEVENT);//如果当前终端设置playDtmfEnabled参数,则需要触发用户放播号音信号,当前该标//记没有开启。if (rvCCTerminalMdmIsDtmfPlayEnabled(t))//让终端自己放播号音8、后续按键在数图匹配成功后,给MTF上报“dd/ce”事件处理包。其中协带参数,“ds=最终用户按键号码”,“Meth=PM或FM或UM,匹配结果,如果匹配失败,则不协带此参数”rvMdmTermProcessObsEvent//当前虽然是dd数图包,但包id是“ce”,不符合按当前键处理事件,所以这不执//行这里函数if(isInDigitMapPkg(&item) )//xxxrvCCTerminalMdmProcessEvent(t, pkg, id, media, args);//映射为 RV_CCTERMEVENT_DIALCOMPLETED 事件event = rvCCTerminalMapEvent(x, pkg, id, args, keyId);if (event == RV_CCTERMEVENT_DIALCOMPLETED)//如果是数图完成事件,则从ds参数中提取最终按键字符串存入终端对象//的dialString中。//将事件及参数存入终端对象的lastEvent中,这里数图事件参数比较关键,后面//进行数图结果处理时,则从这里提出结果参数。setLastEvent(term, pkg, id, args);//调用x->funcs->processTermEventF回调进行事件处理,该回调函数为// rvCCConnMdmProcessEvent,在后面单独分析。rvCCTerminalProcessEventId(x, event, keyId, callMgr, media);rvProcessEvent(c, eventId, reason);rvCCConnectionProcessTermEvent(c, eventId, &callStillAlive, reason);x->funcs->processTermEventF(x, eventId, callStillAlive, reason);------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmProcessEvent//进行呼叫控制状态机处理rvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);switch (event)case RV_CCTERMEVENT_DIALCOMPLETED://当前MDM连接状态为 DIALINGswitch(rvCCConnectionGetState(conn))case RV_CCCONNSTATE_DIALING://调用x->funcs->addressAnalyzeF回调进行用户地址解析,并构造sip连接//对象,该回调函数为rvCCConnMdmAddressAnalyze,下面单独分析。otherParty = rvCCConnectionAddressAnalyze(conn, cause);//获取当前mdm连接对象是否有transferLine,当前普通呼叫没有此值transferLineConnection = rvCCConnectionGetTransferLine(conn);//当前数图匹配成功,已经成功构建了sip连接对象if (otherParty != NULL)if (rvCCTerminalGetState(t) ==RV_CCTERMINAL_CFW_ACTIVATING_STATE)//当前普通呼叫不进此流程elseif ((transferLineConnection != NULL)…)//不走此流程else//conn->curParty = party;//将sip连接对象关联到mdm连接对象上。rvCCConnectionSetConnectParty(conn, otherParty);//更新当前mdm连接对象协商状态//conn. offerAnswerState = //RV_MTF_OFFERANSWER_OFFER_BUILDINGoldOfferAnswerState = rvCCConnSipGetOfferAnswerState(otherParty);rvCCConnSipSetOfferAnswerState(otherParty, RV_MTF_OFFERANSWER_OFFER_BUILDING);//调用x->funcs->createMediaF回调创建媒体//该回调函数为rvCCConnMdmCreateMedia,该函数在下面//单独分析。mediaState = rvCCConnectionCreateMedia(conn, NULL);//更新媒体状态//conn. mediaState = RV_CCTERMEVENT_MEDIAOKrvCCConnectionSetMediaState(conn, mediaState);//更新连接状态,conn.state = //RV_CCCONNSTATE_ADDRESS_ANALYZErvCCConnectionSetState(conn, RV_CCCONNSTATE_ADDRESS_ANALYZE);//返回媒体OK,循环调用rvCCConnMdmProcessEvent//进行内部事件MEDIAOK处理。return RV_CCTERMEVENT_MEDIAOK;-------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmAddressAnalyze//将用户播的号码存储在连接对象的dialString中rvStringCopy(&conn->dialString, &term->dialString);//获取数图匹配结果,如果数图匹配失败,则返回空连接对象。这里取数图匹配结果//的流程为,从终端lastEvent中取出最后事件参数列表,并找出“Meth”参数,如果//没有找到,则表示数图不匹配,否则如果找到了,则结果为“UM或FM表示”//匹配成功,其它表示匹配失败,也就是“不匹配”和“部分匹配”都认为是失败。if (isDialStringMatching(term) == RV_FALSE)return NULL;//调用呼叫控制的回调x->clbks->addressAnalyzeCB进行地址解析处理。该回调函数为// addressAnalyzeCB,该回调下面单独分析。rvCCConnectionAddressAnalyzeCB(x, rvStringGetData(&conn->dialString), RV_CCCAUSE_OUTGOING_CALL, reason);//存储用户按键到“redialString”中,并复位用户按键rvStringCopy(&term->redialString, &term->dialString);rvStringAssign(&term->dialString, "");-------------------------------------------------------------------------------------------------------------------------------addressAnalyzeCBif (inReason == RV_CCCAUSE_OUTGOING_CALL)//调用x->termClass->mapDialStringToAddressF回调进行数图字符到SIP地址的映//射,最终会调用用户层注册的SipStack_MtfMapDialStringToAddressCB函数进行//地址映射处理。rvMdmTermMapDialStringToAddress_(mdmTerm, address, destAddress);//根据用户层处理的地址结果,判断当前地址类型switch(getProviderType(destAddress))case RV_MTF_PROTOCOL_SIP://创建sip连接对象createNewSipConnection(x, destAddress, outReason);//设置一些业务转移地址findDestinationAddress(c, address, destAddress, sizeof(destAddress)if (((strchr(address, '@') != NULL)…)strncpy(foundDestAddress, address, sizeof(foundDestAddress)-1);//转移业务地址的设置,暂不关心//检测当前是否呼叫自己,如果是则返回错误if (rvCCSipPhoneIsCallingMyself(c, destAddress) == rvTrue)*reason = RV_CCCAUSE_BUSY;return NULL//创建sip连接对象rvCCProviderSipCreateConnection(p, ts)//构建sip连接对象,初始化一些连接对象参数,并构造了三个定时器// referTimer、ringingTimer、updateResendTimer,分别对应的超时函数为// rvCCConnSipReferTimerExpires、rvTimerSendRinging、// rvCCConnSipResendUpdatervCCConnSipConstruct(c, p, t, provider->alloc);//conn. State = RV_CCCONNSTATE_IDLErvCCConnectionSetState(c, RV_CCCONNSTATE_IDLE);//将sip连接对象加入到呼叫控制对象中rvCCCallAddParty(call, newConn);rvCCConnectionSetCall(party, call);rvPtrListPushBack(&call->connections, party);call->connNum++;//将目标地址存储到sip连接对象的remoteAddress中。rvCCConnSipSetRemoteAddress(newConn, destAddress);//如果用户帐号不为空,则存储到sip连接对象的localAddress中。if ((termId != NULL) && (strcmp(termId, "")))RvSnprintf(localAddress,RV_SIPCTRL_ADDRESS_SIZE, "%s@%s", termId, tmpIp);rvCCConnSipSetLocalAddress(newConn, localAddress);--------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmCreateMedia//创建线路媒体rvCCTerminalMdmCreateLineMedia(t, at);//term. streamList向量为空if (rvCCTerminalMdmGetNumOfStreams(term) == 0)//构造一个媒体流信息对象,并分配一个新的id,该值从1开始id = (int)rvCCTerminalMdmAddEmptyMediaStream(term);//设置媒体流信息对象的本地编码能力media = rvCCTerminalMdmSetDefaultMedia(activeTerm, id, rvCCTerminalMdmGetTermId(t));//从终端对象中获取本地存储的编码能力sdp = rvCCTerminalMdmGetMediaCaps(term);x->mediaCaps;descr = rvMdmMediaDescriptorGetStream(mediaCaps, 0);rvMdmStreamDescriptorGetLocalDescriptor(descr, 0);//设置本地SDP一些默认字段,如“o”、“v”等。rvCCTerminalMdmFillSdpDefaultInfo(t, sdp, username);//将本地sdp对象加入到媒体流描述符对象的本地描述符中media = rvCCTerminalMdmGetMediaStream(term, (RvUint32)streamId);rvMdmMediaStreamInfoAddLocalDescriptor(media, (RvSdpMsg*)sdp);//设置媒体流描述符对象模式为 RV_MDMSTREAMMODE_SENDRECVrvMdmStreamDescriptorSetMode(&media->streamDescr, RV_MDMSTREAMMODE_SENDRECV);//创建媒体rvCCTerminalMdmCreateMedia(term, media, NULL)rvMdmMediaStreamInfoCreateMdmMedia(media, term, rspMedia);//构造临时媒体描述符变量对象mdmMediaInfofillMdmInfo(x, &mdmMediaInfo);//设置媒体描述符信息对象参数param = &mdmMediaInfo.param;param->cmd = RVMDM_CMD_CREATE;param->normal.localSdp =rvSdpMsgListGetElement(mdmMediaInfo.localDescr, 0);param->normal.remoteSdp = NULL;param->normal.localCapsSdp = NULL;//调用term->termClass->createMediaF回调进行媒体流创建//该回调函数为rvPhysCreateMediaIntCB,该函数最终内部又//调用mtfMgr->mediaClbks.startPhysicalDeviceCB,当前用户//层没有设置此回调,暂不关心。rvMdmTermCreateMediaStream_(mdmTerm, mediaObsolete, &mdmMediaInfo, &mdmError)//获取当前已经构造的媒体流描述符并返回该对象mediaStream=rvCCTerminalMdmGetMediaStream(term, PHYS_TERM_STREAM_ID);returnmediaStream//创建RTP对象mediaState = createRtpMedia(x, t);//创建临时终端对象initRtpMedia(x, conn, term, &eph)if (conn->streamId == RV_MDM_STREAMID_NONE)//构造一个临时终端对象,关联到当前mdm连接对象中eph = rvCCTerminalMdmSelectRtpTerm(term, x)//创建一个EPHEMERAL类型的终端对象,id为“rtp”,并加入到//终端管理列表。这里创建的终端对象在代码中没有用,因为下面//流程因为mgr->selectF回调为空,不走处理该对象的流程,在下面//该对象最终又删除。rvCCProviderMdmCreateTerminal(p, RV_CCTERMINALTYPE_EPHEMERAL, "rtp", 0, &termPropertiesTmp);//创建mdmterm对象,基类就是上面创建的,该对象下面被删除,//没有用到该对象。rvMdmTermConstruct_(mdmEphTerm, NULL, tempT);//调用回调函数mgr->xTermMgrClbks->registerEphTermF注册临时//终端对象,id为“rtp/xxx”,该回调函数为//mdmProviderRegisterEphTerm,该回调函数在下面单独分析。sprintf(termName, "rtp/%d", termNum++);rtpTerm = rvMdmTermMgrRegisterEphemeralTermination(mgr, mtfMgr->rtpClass, termName, NULL);//取物理终端对象的用户数据做为临时终端对象的数据。rvMdmTermSetUserData(rtpTerm, userData);//删除上面创建的id为“rtp”的无用终端对象。rvCCProviderMdmRemoveTerminal(p, tempT);rvCCProviderMdmReleaseTerminal(tempT);//将新建的rtpTerm对象关联到当前mdm连接对象的ephTerm中rvCCConnMdmSetEphTerm(c, rtpTerm);//关联mdm连接对象到rtpterm对象中//x->activeConnection = 0;//x->connections[0] = conn;ephT = rvCCConnMdmGetEphXTerm(c);rvCCTerminalSetEphemeralActiveConnection(ephT, c);//给当前临时终端对象分配一个媒体描述符对象,并将分配得到的ID存//入到当前mdm连接对象的streamId中。ephTerm = rvCCTerminalMdmGetImpl((*eph));conn->streamId = rvCCTerminalMdmAddEmptyMediaStream(ephTerm);//存储本地地址到临时终端对象中ephTerm = rvCCTerminalMdmGetImpl(eph);ephTerm->localAddress = rvCCTerminalMdmGetLocalAddress(mdmterm)///将本地sdp对象加入到媒体流描述符对象的本地描述符中rvCCTerminalMdmSetDefaultMedia(eph, (int)conn->streamId,rvCCTerminalMdmGetTermId(t));//构造命令处理参数param = &mdmMediaInfo.param;param->cmd = RVMDM_CMD_CREATE;param->normal.localSdp  = rvSdpMsgListGetElement( &media->streamDescr.localDescriptors, 0);param->normal.remoteSdp = rvSdpMsgListGetElement( &media->streamDescr.remoteDescriptors, 0);param->normal.localCapsSdp = rvCCConnMdmGetMediaCaps(x);fillMdmInfo( media,  &mdmMediaInfo);//通过用户层注册的回调处理媒体创建处理rvRtpCreateMediaIntCB(x, &ephTerm->mdmTerm, &mdmMediaInfo)params.action = RVMTF_MEDIA_NEW;params.localSdp = streamDescr->param.normal.localSdp;params.remoteSdp = streamDescr->param.normal.remoteSdp;params.localCapsSdp = streamDescr->param.normal.localCapsSdp;//当前回调函数为SipStack_MtfCreateMediaCB,该函数下面单独分析mtfMgr->connMediaClbks.connCreateMediaStreamCB(…)//如果当前连接对象设置getRemoteVendorInfoF回调才进行处理,该处理应该//是和H323协商的媒体能力有关系,这里不关心。rvCCConnectionGetRemoteVendorInfo(……)returnRV_CCMEDIASTATE_CREATED//记载连接对象媒体处理状态,x.mediaState = RV_CCMEDIASTATE_CREATEDrvCCConnectionSetMediaState(x, mediaState);---------------------------------------------------------------------------------------------------------------------------------SipStack_MtfCreateMediaCB//获取当前终端对应的用户终端IDRvCCTerminal       *pCCTerminal = (RvCCTerminal*)hTerm;RvCCTerminalMdm    *pCCTerminalMdm = rvCCTerminalMdmGetImpl(pCCTerminal);RvMdmTerm          *pMdmTerm       =rvCCTerminalMdmGetMdmTerm(pCCTerminalMdm);SIP_TERM_DC_T      *pTermDc        = (SIP_TERM_DC_T*)pMdmTerm->userData;termIdx = pTermDc->ulTermIndex;//创建RTP会话SipUCC_RtpOpen(&cnxId,&rtpPort);SipDrv_RtpOpen(pCnxId,pRtpPort);//获取一个资源ID,当前总共有总线路数 * 2个资源对象SipDrv_GetIdleCnx(&cnxId);pCnx = &gstSipDrvCnx[cnxId];//这里每次都取本地端口号,是不是问题?pCnx = &gstSipDrvCnx[cnxId];pCnx->localPortNum = gstSipUserConfig.localRtpPort;pPort = &pCnx->localPortNum;ip = pCnx->sourceIpaddr;//调用rv rtp stack创建RTP会话pCnx->rtpHandle = SipStack_RtpOpenWithIp(ip, *pPort,  "Sender");//端口基数增2,但如上面注释,是不是这里的递增基乎没有用处。*pPort+=2;pCnx->localPortNum = *pPort;////调用rv rtp stack创建RTCP会话pCnx->rtcpHandle = SipStack_RtpOpenWithIp(ip, *pPort+1,  "SenderRtcp");//关联gstSipDrvCnx到gstRtpCnxPort中gstRtpCnxPort[cnxId].rtpPort = rtpPort;gstRtpCnxPort[cnxId].cnxId = cnxId;//媒体处理SipStack_ProcessMedia(params, termIdx, cnxId)switch(param->action)case RVMTF_MEDIA_NEW:pSdpParamRemote = &gstSipCallRtpInfo[cnxId].stRemoteRtp;pSdpParamLocal = &gstSipCallRtpInfo[cnxId].stLocalRtp;//转换SDP信息到pSdpParamLocal中SipStack_GetSdpMediaInfo(localSdp, pSdpParamLocal);//调用DSP创建连接SipUCC_CreateConnection(&gstSipCallRtpInfo[cnxId],termIndex,cnxId);//更新最后媒体流处理类型pSdpParamLocal->CallType = SIP_CALL_TYPE_AUDIO;pSdpParamRemote->CallType = SIP_CALL_TYPE_AUDIO;//将当前资源ID关联到终端对象中pTermDc->CurrentCnxId = cnxId;--------------------------------------------------------------------------------------------------------------------------------//注册临时终端对象mdmProviderRegisterEphTerm//创建临时终端对象,并加入到终端管理列表中rvCCProviderMdmCreateTerminal(p, RV_CCTERMINALTYPE_EPHEMERAL, id, 0,&termPropertiesTmp);//构造mdm终端对象,其它终端类为rtpClassrvMdmTermConstruct_(&term->mdmTerm, c, t);//设置终端类型rvCCTerminalMdmSetType(term, RV_MDMTERMTYPE_EPHEMERAL);//从终端类中获取本地媒体能力term->mediaCaps = rvMdmTermClassGetMediaCapabilites_(c);term->inactive = RV_FALSE;//激活标记9、rvCCConnMdmProcessEvent处理内部事件RV_CCTERMEVENT_MEDIAOKrvCCConnMdmProcessEventrvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);switch (event)//媒体创建成功case RV_CCTERMEVENT_MEDIAOK:switch (rvCCConnectionGetState(conn))//数图处理完成case RV_CCCONNSTATE_ADDRESS_ANALYZE://更新连接状态为state = RV_CCCONNSTATE_INPROCESSrvCCConnectionSetState(conn, RV_CCCONNSTATE_INPROCESS);//调用mdm连接对象的x->clbks->inProcessCB回调进行处理//该回调函数为sipphone.c文件里的inProcessCB,下面单独//分析。rvCCConnectionInProcessCB(conn, RV_CCCAUSE_NEW_CALL);return RV_CCTERMEVENT_NONE;------------------------------------------------------------------------------------------------------------------------------inProcessCB//进行呼叫连接,这里的curParty是sip连接对象rvCCCallConnect(x, x->curParty);//将mdm连接对象关联到sip连接对象destConn. curParty中。rvCCConnectionSetConnectParty(destConn, origConn);destConn->userData = origConn->userData;//复制两个连接对象的用户句柄//调用x->funcs->getMediaF回调,从mdm连接对象中获取媒体能力,该回调函数//为rvCCConnMdmGetMedia,该函数仅仅从mdm终端对象媒体流列表中获取本地//媒体能力。origMedia = (RvSdpMsg*)rvCCConnectionGetMedia(origConn);//调用sip连接对象中的回调x->funcs->makeCallF进行呼叫创建,该回调函数为// rvCCConnSipMakeCallrvCCConnectionMakeCall(destConn, origMedia);-------------------------------------------------------------------------------------------------------------------------------rvCCConnSipMakeCall//设置远端能力集,这里能力集的值当前是从本端能力中取出的。rvCCConnSipSetRemoteMedia(x, inMedia, RV_TRUE);//sip连接对象构造媒体流描述符对象,并关联到sip连接对象中。这里关联id//也是从1开始分配,注意这里一个呼叫有两个连接对象,两个连接对象分别有//各自的媒体关联ID。conn->streamId = rvCCProviderSipAddEmptyMediaStream(provider);//在媒体流描述符对象中设置远端媒体能力。media = rvCCProviderSipGetMediaStream(provider, conn->streamId);rvMdmMediaStreamInfoClearRemote(media);rvMdmMediaStreamInfoAddRemoteDescriptor(media, inMedia);//发起一个SIP呼叫事件rvCCConnSipProcessEvent(x, RV_CCTERMEVENT_MAKECALL, NULL, RV_CCCAUSE_NEW_CALL);//SIP连接状态机处理connStateMachine(conn, event, reason, callStillAlive);switch(event)case RV_CCTERMEVENT_MAKECALL:if (conn->state == RV_CCCONNSTATE_IDLE)//将sip连接状态迁为RV_CCCONNSTATE_OFFEREDrvCCConnectionSetState(conn, RV_CCCONNSTATE_OFFERED);//创建呼叫makeCall(conn);//使用SIP管理模块创建呼叫rvSipControlCallMake(&provider->sipMgr,(RvSipAppCallLegHandle)x, conn->remoteAddress,conn->localAddress);//取出sip stack的对话管理句柄RvSipStackGetCallLegMgrHandle( rvSipControlGetStackHandle(x),      &hCallLegMgr);//创建一个sip呼叫对话框对象,将sip连接对象做为用户//数据。RvSipCallLegMgrCreateCallLeg( hCallLegMgr, call,&hCallLeg);//将创建的sip呼叫对话框对象关联到sip连接对象中// conn->callLegHndl = hCallLegrvCCConnSipSetCallLegHandle(c, hCallLeg);//调用sipExtClbks.preCallLegCreatedOutgoingCB回调通知//用户是否在创建sip对话过程前阶段中进行其它处理。rvIppSipExtPreCallLegCreatedOutgoingCB((RvIppSipControlHandle)x, (RvIppConnectionHandle)c,hCallLeg, to, from);//设置sip对话框本端contact,远端contact//调用sipExtClbks.postCallLegCreatedOutgoingCB回调通知//用户是否在创建sip对话过程后阶段中进行其它处理rvIppSipExtPostCallLegCreatedOutgoingCB((RvIppSipControlHandle)x, (RvIppConnectionHandle)c,hCallLeg);//route头域设置RvSipCallLegGetOutboundMsg(hCallLeg, &hMsg);rvSipControlSetRouteHeaderInMsg(hCallLeg, c, hMsg);//设置远端信息保存到sip连接对象中//conn->remoteUserName = toUser//conn->remotePartyUri = to//conn->remotePartyAddress = addrrvCCConnSipSetRemoteData(c,to);//调用RV Stack发送呼叫RvSipCallLegMake(hCallLeg, longfromOut, longTo);//保存呼叫发起方到呼叫对话中。rvCCSipPhoneSetFromAddress(call, longFrom);10、INVITE消息发送处理sip stack对话状态改变回调AppCallLegStateChangedEvHandler//更改mdm连接对象呼叫状态改变原因callLegStateChangedToCallStateChangedReason(c, eReason);//获取mdm连接对象party = rvCCConnectionGetConnectParty(c);//更新mdm连接对象的lastReceivedCallStateReasonswitch(callLegReason)case RVSIP_CALL_LEG_REASON_LOCAL_INVITING:reason = RV_MTF_CALL_STATE_REASON_LOCAL_INVITING;rvCCConnectionSetLastReceivedCallStateReason(party, reason);//调用sipExtClbksDeprecated.preStateChangedF或sipExtClbks.preStateChangedCB回调//通知用户在状态改变处理过程中是否进行其它处理。rvIppSipExtPreStateChangedCB(……)//SIP管理对象进行事件处理rvCCProviderSipProcessEvent(hAppCallLeg, hCallLeg, eState, eReason);event           = RV_CCTERMEVENT_NONE;//仅进行接收到远端的处理进行事件映射if (RvSipCallLegGetReceivedMsg(hCallLeg, &phMsg) == RV_OK)processMessageCode(phMsg, c, &event, &cause);//当前RVSIP_CALL_LEG_STATE_IDLE状态没有要触发的动作。processCallState(hCallLeg, c, state, reason, &event, &cause);//调用sipExtClbksDeprecated.postStateChangedF回调通知用户在状态改变处理过程中是//否进行其它处理。rvIppSipExtPostStateChangedCB(……);11、INVITE消息发送处理sip stack对话框中消息发送回调AppCallLegMsgToSendEvHandler//调用sipExtClbksDeprecated.preMsgToSendF回调通知用户在消息发送之前是否进行其//它处理。rvIppSipExtPreMsgToSendCB//构造Allow头域字段setAllowHeader(hMsg);//构造UserAgent头域字段rvSipMgrSetUserAgentHeader(hMsg);//获取sip对话框对象状态RvSipCallLegGetCurrentState (hCallLeg, &state);switch (state)case RVSIP_CALL_LEG_STATE_IDLE://提取远端编码集力设置到消息的body中。rvCCProviderSipSetMedia(hMsg, hAppCallLeg);//将协商协商状态迁为RV_MTF_OFFERANSWER_OFFER_SENT//con.offerAnswerState = RV_MTF_OFFERANSWER_OFFER_SENTrvCCConnSipChangeOfferAnswerState(c, RV_TRUE, RV_FALSE)//调用sipExtClbks.postMsgToSendCB回调通知用户在消息发送之前是否进行其它处理rvIppSipExtPostMsgToSendCB(……);12、18X应答接收处理sip stack 对话消息接收回调AppCallLegMsgReceivedEvHandler//调用回调通知用户层在处理消息接收时是否进行其它处理rvIppSipExtPreMsgReceivedCB//根据远端Allow字段,确认远端是否允许UPDATE更新媒体,并记录在当前SIP连接对//象中。conn. updateAllowedByRemoteParty = TRUE 或 FALSERvSipMsgGetHeaderByType(hMsg,RVSIP_HEADERTYPE_ALLOW,RVSIP_FIRST_HEADER,&listElem);if (isItemInAllowHeader(hMsg, RVSIP_METHOD_OTHER, "UPDATE"))rvCCConnSipSetUpdateAllowedByRemoteParty(c, RV_TRUE);elservCCConnSipSetUpdateAllowedByRemoteParty(c, RV_FALSE);//判断远端是否协带SDP,这里假设18X不含SDP信息。sdpInMsg = rvSipControlIsMediaBody(hMsg);switch (msgType)//应答的消息类型统一为UNDEFINEDcase RVSIP_METHOD_UNDEFINED://获取应答码code = RvSipMsgGetStatusCode(hMsg);//如果应答码为180,则进行alert-info头域的处理,来实现区别振铃,当前假设//远端不含有该字段,则conn.distinctiveRingback = “”if (code == RV_SIPCTRL_STATUS_RINGING)storeDistinctiveRingFromMsg(hAppCallLeg, hMsg, RvDistinctiveRingback);//当前假设18X不含有SDP,则不进行媒体处理if ((sdpInMsg == RV_TRUE) && (code < 300))//no thing//SIP管理处理接收消息rvCCProviderSipMsgReceived(hMsg, hAppCallLeg);//根据接收消息转换为MTF终端对象事件processMessageCode(hMsg, c, &event, &cause);switch (statusCode)case RV_SIPCTRL_STATUS_RINGING:*cause = RV_CCCAUSE_NORMAL;//将当前消息映射为RV_CCTERMEVENT_RINGING事件//当前判断条件为大体为正在进行媒体创建过程时,不//能再触发振铃信号。mediaState = rvCCConnectionGetMediaState(c);if  (!(((mediaState == RV_CCMEDIASTATE_CREATING) ||(mediaState == RV_CCMEDIASTATE_CREATED)  ||(mediaState == RV_CCMEDIASTATE_CONNECTED))&&((statusCode == RV_SIPCTRL_STATUS_SESSIONPROGRESS)||((statusCode == RV_SIPCTRL_STATUS_RINGING) &&(g_sipControl->connectMediaOn180 == RV_TRUE)))))*event = RV_CCTERMEVENT_RINGING;//sip连接对象处理事件rvCCConnSipProcessEvent(c, event, &callStillAlive, cause);connStateMachine(conn, event, reason, callStillAlive);switch(event)case RV_CCTERMEVENT_RINGING://更新sip连接对象状态//conn. State = RV_CCCONNSTATE_ALERTINGrvCCConnectionSetState(conn, RV_CCCONNSTATE_ALERTING);//触发回铃rvCCCallAlerting(conn, reason);//获取mdm连接对象origin = rvCCConnectionGetConnectParty(x);//调用mdm连接对象回调x->funcs->ringbackF进行放回铃操作//该回调函数为rvCCConnMdmRingback,在下面单独分析rvCCConnectionRingback(origin, reason);//调用回调通知用户层在处理消息接收时是否进行其它处理rvIppSipExtPostMsgReceivedCB(……)------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmRingback//发送RINGBACK事件处理rvCCConnMdmProcessEvent(x, RV_CCTERMEVENT_RINGBACK, NULL, reason);//当前term连接没有该事件处理rvCCTermConnProcessEvents(conn, eventId, &eventReason);//呼叫控制状态机处理rvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);switch (event)case RV_CCTERMEVENT_RINGBACK://变迁mdm连接状态//conn.state = RV_CCCONNSTATE_CALL_DELIVEREDrvCCConnectionSetState(conn, RV_CCCONNSTATE_CALL_DELIVERED);//调用x->clbks->callDeliveredCB回调进行区别振铃处理,该回调函数为//rvCCConnMdmCallDeliveredCBrvCCConnectionCallDeliveredCB(conn, *cause);--------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmCallDeliveredCBrvCCTerminalMdmStartRingbackSignal(t);if (term->termType == RV_CCTERMINALTYPE_ANALOG)//给MTF发送“cg/rt”事件包,触使MTF调用用户回调进行放音,该流程后//面不细分析。startSignal(term, "cg", "rt", NULL, RV_MDMSIGNAL_TIMEOUT);13、18X应答接收处理sip stack对话状态改变回调AppCallLegStateChangedEvHandler//更新mdm连接对象lastReceivedCallStateReason为//RV_MTF_CALL_STATE_REASON_PROVISIONAL_RESP_RECEIVEDcallLegStateChangedToCallStateChangedReason(c, eReason);//sip管理事件处理rvCCProviderSipProcessEvent(hAppCallLeg, hCallLeg, eState, eReason);//关联SIP对话框对象到sip连接对象中rvCCConnSipSetCallLegHandle(c, hCallLeg);//根据接收消息转换为MTF终端对象事件,当前转换为//RV_CCTERMEVENT_RINGINGprocessMessageCode(phMsg, c, &event, &cause);//sip连接事件处理,这里的过程调用在上面消息接收回调中已经处理过一次了,//不再进行分析。rvCCConnSipProcessEvent(c, event, &callStillAlive, cause);connStateMachine(conn, event, reason, callStillAlive);switch(event)case RV_CCTERMEVENT_RINGING:rvCCConnectionSetState(conn, RV_CCCONNSTATE_ALERTING);rvCCCallAlerting(conn, reason);//sip状态处理,当前没有RVSIP_CALL_LEG_STATE_PROCEEDING状态处理processCallState(hCallLeg, c, state, reason, &event, &cause);14、200应答接收处理sip stack 对话消息接收回调AppCallLegMsgReceivedEvHandlerswitch (msgType)case RVSIP_METHOD_UNDEFINED://获取应答码code = RvSipMsgGetStatusCode(hMsg);//假设200应答中含有SDPif ((sdpInMsg == RV_TRUE) && (code < 300))//变迁sip连接对象中的媒体协商状态//conn->offerAnswerState =RV_MTF_OFFERANSWER_OFFER_ANSWEREDrvCCConnSipChangeOfferAnswerState(c, RV_FALSE, RV_FALSE);//处理sdprvCCProviderSipProcessIncomingSdp(hMsg, hAppCallLeg);//SDP解析RvSipMsgGetBody(hMsg, buf, (RvUint)strLen, &actlen);rvSdpMsgConstructParseA(&sdp, buf, (int *)&actlen, &stat, conn->alloc)//sip连接创建媒体rvCCConnSipCreateMedia(c, &sdp)//获取sip连接对象中的媒体描述符对象media = rvCCProviderSipGetMediaStream(provider, conn->streamId);//如果本地能力存在,则清除。if (rvMdmMediaStreamInfoIsLocalDescriptorSet(media) == rvTrue)rvMdmMediaStreamInfoClearLocal(media);//将远端的SDP设置到媒体描述符的本地能力中。rvMdmMediaStreamInfoAddLocalDescriptor(media, inMedia);//调用sip连接的x->clbks->mediaUpdatedCB回调触发媒体更新,该//回调函数为rvCCCallMediaUpdatedCB,下面单独分析rvCCConnectionMediaUpdatedCB(x, inMedia)//更新sip连接对象的媒体状态//conn.mediaState = RV_CCMEDIASTATE_CREATINGmediaState = rvCCConnectionGetMediaState(x);if (mediaState == RV_CCMEDIASTATE_NONE)mediaState = RV_CCMEDIASTATE_CREATING;rvCCConnectionSetMediaState(x, mediaState);//复位sip连接对象的拒绝呼叫标记//conn.rejectCall = FALSErvCCConnSipSetRejectCall(c, RV_FALSE)//sip管理处理消息接收,该函数当前仅处理200以下的应答码,当前不会进行任何处//理。200以上应答码处理在对话状态改变回调中。rvCCProviderSipMsgReceived(hMsg, hAppCallLeg);--------------------------------------------------------------------------------------------------------------------------------rvCCCallMediaUpdatedCB//获取mdm连接对象party = rvCCConnectionGetConnectParty(conn);//调用mdm连接对象的x->funcs->setRemoteMediaF回调更新媒体,该回调函数为// rvCCConnMdmSetRemoteMediarvCCConnectionSetRemoteMedia(party, inMedia);--------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmSetRemoteMedia//获取临时终端对象,就是RTP终端对象eph = rvCCConnMdmGetEphXTerm(x);ephTerm = rvCCTerminalMdmGetImpl(eph);//从临时终端对象中提取媒体描述符media = rvCCTerminalMdmGetMediaStream(ephTerm, conn->streamId);//标记下面需要进行媒体更新if (modify)needModifyMedia = RV_TRUE;//将媒体描述符对象中的远端能力清除if (rvMdmMediaStreamInfoIsRemoteDescriptorSet(media) == RV_TRUE)rvMdmMediaStreamInfoClearRemote(media);//将远端SDP设置到媒体描述符对象的远端能力中rvMdmMediaStreamInfoAddRemoteDescriptor(media, inMedia);//更新收发模式rvMdmStreamDescriptorSetMode(&media->streamDescr,RV_MDMSTREAMMODE_SENDRECV);if (needModifyMedia)//媒体更改,rvCCConnMdmGetMediaCaps函数从音频终端中获取本地媒体能力,//当前模拟终端的音频终端就是自身。modifyMedia(x, RVMDM_CMD_NORMAL,ephTerm,media,rvCCConnMdmGetMediaCaps(x))//更新收发模式,将媒体描述符模式设置为 SENDRECVsetStreamMode(x, media);switch (rvCCConnectionGetTermState(x))default:streamMode = RV_MDMSTREAMMODE_SENDRECV;rvMdmStreamDescriptorSetMode(streamDescr, streamMode);//将远端媒体信息设置到临时变量mdmMediaInfo中,mdmMediaInfo在下面//做为传参进行媒体处理。fillMdmInfo( media,  &mdmMediaInfo);param = &mdmMediaInfo.param;param->cmd = cmd;//RVMDM_CMD_NORMALparam->normal.localSdp = localSdp;param->normal.remoteSdp= remoteSdp;param->normal.localCapsSdp = sdpMediaCaps;//本地DSP能力集//媒体更改rvRtpModifyMediaIntCB(x, &ephTerm->mdmTerm, &mdmMediaInfo)switch (streamDescr->param.cmd)case RVMDM_CMD_NORMAL:params.action = RVMTF_MEDIA_MODIFY_SESSION;switch (streamDescr->param.cmd)case RVMDM_CMD_NORMAL:params.action = RVMTF_MEDIA_MODIFY_SESSION;params.localSdp = streamDescr->param.normal.localSdp;params.remoteSdp = streamDescr->param.normal.remoteSdp;params.localCapsSdp = streamDescr->param.normal.localCapsSdp;//调用回调进行媒体更新,当前回调在用户层注册为//SipStack_MtfModifyMediaCBmtfMgr->connMediaClbks.connModifyMediaStreamCB(……)-------------------------------------------------------------------------------------------------------------------------------SipStack_MtfModifyMediaCB//从应用层数据关联中提取当前终端索引termIdx = pTermDc->ulTermIndex;//提取资源索引cnxId = pTermDc->CurrentCnxId;//处理媒体SipStack_ProcessMedia(params, termIdx, cnxId)//当前在用户侧保存的媒体资源参数pSdpParamRemote = &gstSipCallRtpInfo[cnxId].stRemoteRtp;pSdpParamLocal = &gstSipCallRtpInfo[cnxId].stLocalRtp;switch(param->action)case RVMTF_MEDIA_MODIFY_SESSION://将远端SDP信息转换为本地DSP格式参数SipStack_GetSdpMediaInfo(remoteSdp, pSdpParamRemote);pDescr = rvSdpMsgGetMediaDescr(pSdpMsg, i);//获取SDP中payload列表数ulFormateNum = rvSdpMediaDescrGetNumOfPayloads(pDescr);//获取媒体类型,并标记启用mediaType = rvSdpMediaDescrGetMediaType(pDescr);pSdpParam->bMediaFlag[mediaType] = 1;//从SDP中提取如下参数// pSdpParam->stSdpMedia[mediaType].Port// pSdpParam->ConnMode// pSdpParam->stSdpMedia[mediaType].NetType// pSdpParam->stSdpMedia[mediaType].AddrType// pSdpParam->ConnAddress// pSdpParam->stSdpMedia[mediaType].strConnAddrSipStack_FillConnectionInfoByMedia(pDescr, mediaType, pSdpParam)//获取端口号,payload列表数pSdpParam->ConnPort = pSdpParam->stSdpMedia[mediaType].Port = rvSdpMediaDescrGetPort(pDescr);pSdpParam->stSdpMedia[mediaType].FormatsNum = ulFormateNum;//从SDP的payload列表中 获取编码pt值和编码名 for(j = 0;j < ulFormateNum; j++)if(mediaType != RV_SDPMEDIATYPE_IMAGE)int pt = rvSdpMediaDescrGetPayload(pDescr, j);pSdpParam->stSdpMedia[mediaType].sFormat[j].strFormateName=gstSipStackencodingMap[i].encodingNamepSdpParam->stSdpMedia[mediaType].sFormat[j].Payload = pt;//获取SDP中rtpmap条目数ulRtpMapNum = rvSdpMediaDescrGetNumOfRtpMap(pDescr);pSdpParam->stSdpMedia[mediaType].RtpMapNum = ulRtpMapNum;//获取rtpmap列表的编码名和pt值for(j=0;j< ulRtpMapNum; j++)pRtpMap = rvSdpMediaDescrGetRtpMap(pDescr, j);pSdpParam->stSdpMedia[mediaType].stRtpMap[j].PayloadValue =rvSdpRtpMapGetPayload(pRtpMap);pSdpParam->stSdpMedia[mediaType].stRtpMap[j].strPayloadName =rvSdpRtpMapGetEncodingName(pRtpMap)//获取SDP属性个数pSdpParam->stSdpMedia[mediaType].AttributeNum =rvSdpMsgGetNumOfAttr2(pSdpMsg);//遍历所有SDP属性字段for(j = 0; j< pSdpParam->stSdpMedia[mediaType].AttributeNum && j< SIP_ATTRIBUTE_NUM_MAX;j++)pAttr = rvSdpMsgGetAttribute(pSdpMsg, j);//这个代码逻辑可能有问题,本意应该是跳过rtpmap,但现在代码//逻辑是跳过非rtpamp字段if(strcasecmp(pAttr->iAttrName,"rtpmap"))continue;//处理“ptime”、“fax”、“telephone-event”、“sendonly”等SDP属性//字段。//更新呼叫类型rvSdpMsgGetMediaDescr(remoteSdp, i);mediaType = rvSdpMediaDescrGetMediaType(pMedia);if(mediaType == RV_SDPMEDIATYPE_IMAGE)……else if(mediaType == RV_SDPMEDIATYPE_DATA)…..elsepSdpParamRemote->CallType = SIP_CALL_TYPE_AUDIO;//媒体协商处理,以远端优先进行媒体协商,最后存储到pSdpParamLocal中SipStack_ProcessMediaNegotiate(pSdpParamLocal, pSdpParamRemote);//修改媒体连接SipUCC_ModifyConnection(&gstSipCallRtpInfo[cnxId],termIndex,cnxId);//填充DSP设置参数//更新RTP进行收发包处理SipDrv_RtpUpdate(&drvCNX, cnxId);//在之前媒体创建时,已经开启,所以条件无效if(!pCnx->cnxOn)//no thingelse//更新RTP会话,设置对端媒体地址,此时DSP发送媒体的//回调函数SipDrv_PktSendCb中就可以使用当前RTP会话句柄//向远端发送媒体。SipDrv_SetRemoteAddr(pCnxParam->destIPaddr,pCnxParam->destPortNum,cnxId);//设置媒体接收回调函数,当收到远端媒体时,调用// SipDrv_RtpRecv函数中的vrgEndptPacket接口,交接收到的//媒体数据交给DSP处理。RvRtpSetEventHandler (pCnx->rtpHandle,SipDrv_RtpRecv,pCnx);RvRtpSetEventHandler (pCnx->rtcpHandle,SipDrv_RtcpRecv,pCnx);//调用DSP接口进行通道更新SipDrv_ModifyConnection(&drvCNX, eptId,cnxId);15、200应答接收处理sip stack对话状态改变回调AppCallLegStateChangedEvHandler//更新mdm连接对象的lastReceivedCallStateReason为//RV_MTF_CALL_STATE_REASON_CALL_ACCEPTEDcallLegStateChangedToCallStateChangedReason(c, eReason);//sip管理进行事件处理rvCCProviderSipProcessEvent(hAppCallLeg, hCallLeg, eState, eReason);//根据应答码映射事件,当前200应答映射为RV_CCTERMEVENT_NONEprocessMessageCode(phMsg, c, &event, &cause);//忽略处理if (event != RV_CCTERMEVENT_NONE)rvCCConnSipProcessEvent(c, event, &callStillAlive, cause);//sip对话状态处理processCallState(hCallLeg, c, state, reason, &event, &cause);switch (state)case RVSIP_CALL_LEG_STATE_CONNECTED://当前协议栈配置为自动发送ACK,所以收到200应答后对话框的状//态是变迁为CONNECTED。//这里处理仅将事件映射为 RV_CCTERMEVENT_CALLANSWEREDhandleConnectedState(c, hCallLeg, event, cause);*event = RV_CCTERMEVENT_CALLANSWERED;        *cause = RV_CCCAUSE_OUTGOING_CALL;if (event != RV_CCTERMEVENT_NONE)//处理RV_CCTERMEVENT_CALLANSWERED事件rvCCConnSipProcessEvent(c, event, &callStillAlive, cause);connStateMachine(conn, event, reason, callStillAlive);switch(event)case RV_CCTERMEVENT_CALLANSWERED:switch (conn->state)case RV_CCCONNSTATE_ALERTING://更新sip连接对象状态为 RV_CCCONNSTATE_CONNECTEDrvCCConnectionSetState(conn, RV_CCCONNSTATE_CONNECTED);//处理连接rvCCCallConnected(conn, RV_CCCAUSE_INCOMING_CALL);//获取mdm连接对象origin = rvCCConnectionGetConnectParty(x);//调用x->funcs->callAnsweredF回调处理mdm侧应答//该回调函数为rvCCConnMdmCallAnswered,下面分析rvCCConnectionCallAnswered(origin, NULL);//标记后面可以处理forked对话应答connSip->forkedCallAnswered = RV_TRUE;------------------------------------------------------------------------------------------------------------------------------rvCCConnMdmCallAnswered//触发所有信号音停止,之前分析过,后面不详细分析。rvCCTerminalMdmStopSignals(t);rvCCTerminalMdmStopRingingSignal(t);//媒体连接rvCCConnMdmConnectMedia(x);//获取RTP临时终端,以及媒体描述符对象 getRtpMediaObjects(x, &ephTerm, &rtpTerm, &rtpMedia)//判断当前本地支持该媒体类型时才处理。if ((RvMdmMediaStreamInfoDoesMediaTypeExist(rtpMedia, RV_SDPMEDIATYPE_AUDIO)) == RV_TRUE)//连接线路终端与RTP终端rvCCConnMdmConnectLineAndRtpTerms(x, at, ephTerm, rtpTerm, rtpMedia)//获取线路终端的媒体描述符对象getLineMediaObjects(x, at, &atTerm, &mdmTerm, &lineMedia)//调用mtfMgr->mediaClbks.connectMediaCB回调进行线路与RTP对象的//连接处理,当前用户层注册了该回调,但没有做实际处理。rvRtpConnectIntCB(x, rvCCTerminalMdmGetTermMgr(ephTerm), mdmTerm,            lineMedia, rtpTerm, rtpMedia, RV_MDMSTREAMDIRECTION_BOTHWAYS)//更新线路终端媒体描述符对象 status=RV_MDMSTREAM_CONNECTEDrvMdmMediaStreamInfoSetStatusConnected(lineMedia);//更新RTP终端媒体描述符对象 status=RV_MDMSTREAM_CONNECTEDrvMdmMediaStreamInfoSetStatusConnected(rtpMedia);//更新mdm连接对象的mediaState =RV_CCMEDIASTATE_CONNECTEDrvCCConnectionSetMediaState(x, RV_CCMEDIASTATE_CONNECTED);//发送线路指示,不详细分析rvCCTerminalMdmSetLineInd(t, rvCCConnectionGetLineId(x), RV_INDSTATE_ON);//模拟线路不做处理。audioType = rvCCTerminalMdmGetActiveAudio(t);switch (audioType)case RV_CCTERMAUDIO_NONE:break;//发送保持指示,不详细分析rvCCConnectionTermSetHoldIndicator(x, RV_FALSE);//mdm连接处理事件rvCCConnMdmProcessEvent(x, RV_CCTERMEVENT_CALLANSWERED, &callStillAlive, reason);//没有RV_CCTERMEVENT_CALLANSWERED事件处理rvCCTermConnProcessEvents(conn, eventId, &eventReason);rvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);switch (event)case RV_CCTERMEVENT_CALLANSWERED:switch (rvCCConnectionGetState(conn))case RV_CCCONNSTATE_CALL_DELIVERED://设置mdm连接对象状态为state= RV_CCCONNSTATE_CONNECTEDrvCCConnectionSetState(conn, RV_CCCONNSTATE_CONNECTED);//设置mdm连接对象终端状态为//termState= RV_CCTERMCONSTATE_TALKINGrvCCConnectionSetTermState(conn, RV_CCTERMCONSTATE_TALKING);//进行呼叫连接处理,当前cause值为RV_CCCAUSE_OUTGOING_CALLrvCCCallConnected(conn, *cause);//调用x->clbks->callAnsweredCB回调进行呼叫应答处理,该回调//函数为rvCCConnMdmCallAnsweredCBrvCCConnectionCallAnsweredCB(x);-------------------------------------------------------------------------------------------------------------------------rvCCConnMdmCallAnsweredCB//停止当前所有信号,不详细分析rvCCTerminalMdmStopRingingSignal(t);    rvCCTerminalMdmStopSignals(t);//发送线路指示,不详细分析rvCCTerminalMdmSetLineInd(t, rvCCConnectionGetLineId(x), RV_INDSTATE_ON);//当前mdm连接对象的连接状态已经为RV_CCCONNSTATE_CONNECTED,不进行//此流程处理。if (rvCCConnectionGetState(x) != RV_CCCONNSTATE_CONNECTED)//no thing

原创粉丝点击