主叫基本呼叫流程分析

1、摘机dsp driver线程
//上报摘机事件
SipDrv_EventRecvCb
	Drv_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_OFFHOOK
	SipUCC_DrvEventToMtfEvent(pstSipDriverEvent,&eRvEvent,&stMtfEventInfo);
	
	//检索线路终端id
	termIdx = 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_OFFHOOK
							event = 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 = term
										Term_evn = setActiveAudioTerminal(t, event);
										returnterm_evn;
									
									//基本呼叫摘机时连接都是空闲,因此不走后继
									//流程代码。
								
								//获取当前线路终端连接是否存在呼叫控制对象,如果
								//不存在呼叫控制对象,则构造一个新的呼叫对象
								call = rvCCConnectionGetCall(c);
								if (call == NULL)
									rvInitNewCall(callMgr, c);
										//创建一个呼叫对象,放入callMgr列表中
										//callMgr. Calls call
										//call.callMgr = callMgr
										call = 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_INITIATED
				rvCCConnectionSetState(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=on
		rvCCTerminalMdmStartSignalUI(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.curSignals
							if( 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_DIALING
			if (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= xxxxxx
				mapDigitToEvent(info->digit, strParam)
				addParam(¶msList, "keyid", strParam);
				
				//构成kp/ku包请求事件,给MTF发送消息,触使MTF线程处理。
				rvMdmTermProcessEvent(mdmTerm, "kp", "ku", NULL, ¶msList);
7、按键MTF主线程处理
//mdm管理处理终端事件
rvCCProviderMdmProcessTerminationEvent
	rvMdmTermProcessBlockedEvent(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) )
		//xxx
	
	rvCCTerminalMdmProcessEvent(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连接状态为 DIALING
			switch(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)
	//当前普通呼叫不进此流程
					else
						if ((transferLineConnection != NULL)…)
							//不走此流程
						else
							//conn->curParty = party;
							//将sip连接对象关联到mdm连接对象上。
							rvCCConnectionSetConnectParty(conn, otherParty);
							
//更新当前mdm连接对象协商状态
							//conn. offerAnswerState = 
							//RV_MTF_OFFERANSWER_OFFER_BUILDING
							oldOfferAnswerState = 
								rvCCConnSipGetOfferAnswerState(otherParty);
							rvCCConnSipSetOfferAnswerState(otherParty, 
								RV_MTF_OFFERANSWER_OFFER_BUILDING);
							
							//调用x->funcs->createMediaF回调创建媒体
							//该回调函数为rvCCConnMdmCreateMedia,该函数在下面
							//单独分析。
							mediaState = rvCCConnectionCreateMedia(conn, NULL);
							
							//更新媒体状态
							//conn. mediaState = RV_CCTERMEVENT_MEDIAOK
							rvCCConnectionSetMediaState(conn, mediaState);
							
							//更新连接状态,conn.state = 
							//RV_CCCONNSTATE_ADDRESS_ANALYZE
							rvCCConnectionSetState(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, "");

-------------------------------------------------------------------------------------------------------------------------------
addressAnalyzeCB
	if (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、
				// rvCCConnSipResendUpdate
				rvCCConnSipConstruct(c, p, t, provider->alloc);
				
				//conn. State = RV_CCCONNSTATE_IDLE
				rvCCConnectionSetState(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_SENDRECV
			rvMdmStreamDescriptorSetMode(&media->streamDescr, 
			RV_MDMSTREAMMODE_SENDRECV);
			
			//创建媒体
			rvCCTerminalMdmCreateMedia(term, media, NULL)
				rvMdmMediaStreamInfoCreateMdmMedia(media, term, rspMedia);
					//构造临时媒体描述符变量对象mdmMediaInfo
					fillMdmInfo(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_CREATED
	rvCCConnectionSetMediaState(x, mediaState);

---------------------------------------------------------------------------------------------------------------------------------
SipStack_MtfCreateMediaCB
	//获取当前终端对应的用户终端ID
	RvCCTerminal       *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终端对象,其它终端类为rtpClass
rvMdmTermConstruct_(&term->mdmTerm, c, t);

//设置终端类型
rvCCTerminalMdmSetType(term, RV_MDMTERMTYPE_EPHEMERAL);

//从终端类中获取本地媒体能力
term->mediaCaps = rvMdmTermClassGetMediaCapabilites_(c);

term->inactive = RV_FALSE;	//激活标记
9、rvCCConnMdmProcessEvent处理内部事件RV_CCTERMEVENT_MEDIAOK
rvCCConnMdmProcessEvent
	rvCCConnectionStateMachine(conn, eventId, &eventReason,callStillAlive);	
		switch (event)
		//媒体创建成功
		case RV_CCTERMEVENT_MEDIAOK:
			switch (rvCCConnectionGetState(conn))
			//数图处理完成
			case RV_CCCONNSTATE_ADDRESS_ANALYZE:
				//更新连接状态为state = RV_CCCONNSTATE_INPROCESS
				rvCCConnectionSetState(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进行呼叫创建,该回调函数为
		// rvCCConnSipMakeCall
		rvCCConnectionMakeCall(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_OFFERED
					rvCCConnectionSetState(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 = hCallLeg
	rvCCConnSipSetCallLegHandle(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 = addr
rvCCConnSipSetRemoteData(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连接对象的lastReceivedCallStateReason
		switch(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_SENT
	rvCCConnSipChangeOfferAnswerState(c, RV_TRUE, RV_FALSE)

//调用sipExtClbks.postMsgToSendCB回调通知用户在消息发送之前是否进行其它处理
rvIppSipExtPostMsgToSendCB(……);
12、18X应答接收处理sip stack 对话消息接收回调
AppCallLegMsgReceivedEvHandler
	//调用回调通知用户层在处理消息接收时是否进行其它处理
	rvIppSipExtPreMsgReceivedCB
	
	//根据远端Allow字段,确认远端是否允许UPDATE更新媒体,并记录在当前SIP连接对
	//象中。conn. updateAllowedByRemoteParty = TRUE 或 FALSE
	RvSipMsgGetHeaderByType(hMsg,RVSIP_HEADERTYPE_ALLOW,RVSIP_FIRST_HEADER,
&listElem);
	if (isItemInAllowHeader(hMsg, RVSIP_METHOD_OTHER, "UPDATE"))
		rvCCConnSipSetUpdateAllowedByRemoteParty(c, RV_TRUE);
	else
		rvCCConnSipSetUpdateAllowedByRemoteParty(c, RV_FALSE);
	
	//判断远端是否协带SDP,这里假设18X不含SDP信息。
	sdpInMsg = rvSipControlIsMediaBody(hMsg);
	
	switch (msgType)
	//应答的消息类型统一为UNDEFINED
	case 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_ALERTING
					rvCCConnectionSetState(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_DELIVERED
				rvCCConnectionSetState(conn, RV_CCCONNSTATE_CALL_DELIVERED);
				
				//调用x->clbks->callDeliveredCB回调进行区别振铃处理,该回调函数为
				//rvCCConnMdmCallDeliveredCB
				rvCCConnectionCallDeliveredCB(conn, *cause);
--------------------------------------------------------------------------------------------------------------------------------
rvCCConnMdmCallDeliveredCB
	rvCCTerminalMdmStartRingbackSignal(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_RECEIVED
	callLegStateChangedToCallStateChangedReason(c, eReason);
	
	//sip管理事件处理
	rvCCProviderSipProcessEvent(hAppCallLeg, hCallLeg, eState, eReason);
		//关联SIP对话框对象到sip连接对象中
		rvCCConnSipSetCallLegHandle(c, hCallLeg);
		
		//根据接收消息转换为MTF终端对象事件,当前转换为
		//RV_CCTERMEVENT_RINGING
		processMessageCode(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 对话消息接收回调
AppCallLegMsgReceivedEvHandler
	switch (msgType)
	case RVSIP_METHOD_UNDEFINED:
		//获取应答码
		code = RvSipMsgGetStatusCode(hMsg);
		
		//假设200应答中含有SDP
		if ((sdpInMsg == RV_TRUE) && (code < 300))
			//变迁sip连接对象中的媒体协商状态
			//conn->offerAnswerState =RV_MTF_OFFERANSWER_OFFER_ANSWERED
			rvCCConnSipChangeOfferAnswerState(c, RV_FALSE, RV_FALSE);
			
			//处理sdp
			rvCCProviderSipProcessIncomingSdp(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_CREATING
					mediaState = rvCCConnectionGetMediaState(x);
					if (mediaState == RV_CCMEDIASTATE_NONE)
						mediaState = RV_CCMEDIASTATE_CREATING;
					rvCCConnectionSetMediaState(x, mediaState);
				
				//复位sip连接对象的拒绝呼叫标记
				//conn.rejectCall = FALSE
				rvCCConnSipSetRejectCall(c, RV_FALSE)
	
	//sip管理处理消息接收,该函数当前仅处理200以下的应答码,当前不会进行任何处
	//理。200以上应答码处理在对话状态改变回调中。
	rvCCProviderSipMsgReceived(hMsg, hAppCallLeg);

--------------------------------------------------------------------------------------------------------------------------------
rvCCCallMediaUpdatedCB
	//获取mdm连接对象
	party = rvCCConnectionGetConnectParty(conn);
	
	//调用mdm连接对象的x->funcs->setRemoteMediaF回调更新媒体,该回调函数为
	// rvCCConnMdmSetRemoteMedia
	rvCCConnectionSetRemoteMedia(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))
			//更新收发模式,将媒体描述符模式设置为 SENDRECV
			setStreamMode(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_NORMAL
			param->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_MtfModifyMediaCB
				mtfMgr->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].strConnAddr
				SipStack_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].encodingName
						
						pSdpParam->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)
				…..
			else
				pSdpParamRemote->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 thing
					else
						//更新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_ACCEPTED
	callLegStateChangedToCallStateChangedReason(c, eReason);
	
	//sip管理进行事件处理
	rvCCProviderSipProcessEvent(hAppCallLeg, hCallLeg, eState, eReason);
		//根据应答码映射事件,当前200应答映射为RV_CCTERMEVENT_NONE
		processMessageCode(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_CALLANSWERED
				handleConnectedState(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_CONNECTED
							rvCCConnectionSetState(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_CONNECTED
				rvMdmMediaStreamInfoSetStatusConnected(lineMedia);
		
		//更新RTP终端媒体描述符对象 status=RV_MDMSTREAM_CONNECTED
		rvMdmMediaStreamInfoSetStatusConnected(rtpMedia);
		
		//更新mdm连接对象的mediaState =RV_CCMEDIASTATE_CONNECTED
		rvCCConnectionSetMediaState(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_CONNECTED
					rvCCConnectionSetState(conn, RV_CCCONNSTATE_CONNECTED);
					
					//设置mdm连接对象终端状态为
//termState= RV_CCTERMCONSTATE_TALKING
					rvCCConnectionSetTermState(conn, RV_CCTERMCONSTATE_TALKING);
					
					//进行呼叫连接处理,当前cause值为RV_CCCAUSE_OUTGOING_CALL
					rvCCCallConnected(conn, *cause);
						//调用x->clbks->callAnsweredCB回调进行呼叫应答处理,该回调
						//函数为rvCCConnMdmCallAnsweredCB
						rvCCConnectionCallAnsweredCB(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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值