📄 cmcall.c
字号:
* output : none
* return : none
************************************************************************/
void dequeueCallStates(
IN cmElem* app,
IN callElem* call,
IN cmCallState_e state,
IN cmCallStateMode_e stateMode)
{
int nesting;
call->q_numStates++;
while ((call->q_numStates > 0) && (call->state != cmCallStateIdle)) /* Idle is the "last stop" */
{
/* cmCallStateInit is reserved for the use of the queue as a state that should be
in the queue, but always not-handled. This way, we can for example use cmEvNewCall()
as if it is a queued state to make sure all event callbacks are handled after it */
if (state != cmCallStateInit)
{
/* handle the next state - its a real one */
#if (RV_LOGMASK_COMPILEMASK & RV_LOGLEVEL_ENTER)
static char *stateModes[]=
{(char*)"",
(char*)"cmCallStateModeDisconnectedBusy",
(char*)"cmCallStateModeDisconnectedNormal",
(char*)"cmCallStateModeDisconnectedReject",
(char*)"cmCallStateModeDisconnectedUnreachable",
(char*)"cmCallStateModeDisconnectedUnknown",
(char*)"cmCallStateModeDisconnectedLocal",
(char*)"cmCallStateModeConnectedControl",
(char*)"cmCallStateModeConnectedCallSetup",
(char*)"cmCallStateModeConnectedCall",
(char*)"cmCallStateModeConnectedConference",
(char*)"cmCallStateModeOfferingCreate",
(char*)"cmCallStateModeOfferingInvite",
(char*)"cmCallStateModeOfferingJoin",
(char*)"cmCallStateModeOfferingCapabilityNegotiation",
(char*)"cmCallStateModeOfferingCallIndependentSupplementaryService",
(char*)"cmCallStateModeDisconnectedIncompleteAddress"};
static char *states[]=
{(char*)"cmCallStateDialtone",
(char*)"cmCallStateProceeding",
(char*)"cmCallStateRingBack",
(char*)"cmCallStateConnected",
(char*)"cmCallStateDisconnected",
(char*)"cmCallStateIdle",
(char*)"cmCallStateOffering",
(char*)"cmCallStateTransfering",
(char*)"",(char*)"",
(char*)"cmCallStateIncompleteAddress",
(char*)"cmCallStateWaitAddressAck"};
int use_statemode;
use_statemode = ((state==cmCallStateDisconnected)||(state==cmCallStateConnected)||(state==cmCallStateOffering));
cmiCBEnter((HAPP)app,"cmEvCallStateChanged(haCall=0x%p,hsCall=0x%p,state=%s,stateMode=%s)",
emaGetApplicationHandle((EMAElement)call), call, states[state],
use_statemode ? stateModes[stateMode+1] : "");
#endif
nesting=emaPrepareForCallback((EMAElement)call);
{
call->state=state;
call->stateMode=stateMode;
if (app->cmMyCallEvent.cmEvCallStateChanged)
app->cmMyCallEvent.cmEvCallStateChanged((HAPPCALL)emaGetApplicationHandle((EMAElement)call),(HCALL)call,state,stateMode);
else if (state==cmCallStateIdle)
{
/* If the application has no state-change callback, we should close the call on IDLE state */
cmCallClose((HCALL)call);
}
/* If callback didn't delete the call and it's a connected one, check
if the control has already connected as well */
if ( (!emaWasDeleted((EMAElement)call)) &&
(state == cmCallStateConnected) &&
(stateMode == cmCallStateModeConnectedCallSetup) )
notifyControlState((HCALL)call);
}
#if (RV_LOGMASK_COMPILEMASK & RV_LOGLEVEL_LEAVE)
cmiCBExit((HAPP)app,"cmEvCallStateChanged");
#endif
emaReturnFromCallback((EMAElement)call,nesting);
}
/* reduce state number */
call->q_numStates--;
if(call->q_numStates)
{
/* get next state from the queue */
if (call->q_states[call->q_nextState] != RV_H323CALL_STATE_DUMMY)
{
state = (cmCallState_e) call->q_states[call->q_nextState];
stateMode = (cmCallStateMode_e) call->q_stateModes[call->q_nextState];
}
else
state = cmCallStateInit;
call->q_nextState = (RvUint8) ( (call->q_nextState+1)%RV_H323CALL_STATE_MAX );
}
}
}
/************************************************************************
* notifyState
* purpose: Notify the application about the state of the call
* input : hsCall - Stack handle for the call
* state - State of call
* stateMode - Mode of the state
* output : none
* return : none
************************************************************************/
void notifyState(IN HCALL hsCall, IN cmCallState_e state, IN cmCallStateMode_e stateMode)
{
callElem*call=(callElem*)hsCall;
cmElem* app=(cmElem*)emaGetInstance((EMAElement)call);
/* check if a state is already being handled */
if (call->q_numStates)
{
int newState;
int oldState;
if (call->q_numStates >= RV_H323CALL_STATE_MAX)
{
/* we may be in a state-loop - this shouldn't happen! */
RvLogError(&app->logERR,
(&app->logERR, "notifyState: We have a loop for hsCall=0x%p", hsCall));
return;
}
/* place the new state in the state queue */
newState = (call->q_nextState + call->q_numStates - 1) % RV_H323CALL_STATE_MAX;
oldState = (newState+RV_H323CALL_STATE_MAX-1)%RV_H323CALL_STATE_MAX;
if((call->q_states[oldState] != state) || (call->q_stateModes[oldState] != stateMode))
{
/* Seems like this state is not the same state as its predecessor - add it in */
call->q_states[newState] = (RvUint8) state;
call->q_stateModes[newState] = (RvUint8) stateMode;
call->q_numStates++;
}
return;
}
/* No current states - handle it as is */
/* don't report the same state twice */
if ( (call->state == state) && (call->stateMode == stateMode) )
return;
/* enter state handle */
dequeueCallStates(app, call, state, stateMode);
}
/************************************************************************
* notifyControlState
* purpose: Notify the application about the state of the control
* This function checks the control state and uses the call state
* notification function.
* input : hsCall - Stack handle for the call
* output : none
* return : none
************************************************************************/
void notifyControlState(IN HCALL hsCall)
{
callElem*call=(callElem*)hsCall;
if (m_callget(call,control))
{
switch(controlGetState(cmiGetControl((HCALL)call)))
{
case ctrlConnected:
notifyState((HCALL)call,cmCallStateConnected,cmCallStateModeConnectedCall);
break;
case ctrlConference:
notifyState((HCALL)call,cmCallStateConnected,cmCallStateModeConnectedConference);
break;
default:
/* Do nothing */
break;
}
}
}
/************************************************************************
* callStartOK
* purpose: Deal with an outgoing or incoming call in the Q931 side, after
* RAS was done (or skiped)
* input : call - Stack handle for the call to dial
* output : none
* return : Non-negative value on success
* Negative value on failure
************************************************************************/
int callStartOK(IN callElem* call)
{
cmElem* app=(cmElem*)emaGetInstance((EMAElement)call);
int nodeId;
cmTransportAddress tpkt;
cmTransportAddress annexE;
int ret=0;
catStruct callObj;
/* See what's the direction of the call */
if (m_callget(call,callInitiator))
{
/* Outgoing call - make sure we add it to the CAT */
if ((ret = callObjectCreate(app, (HCALL)call, Outgoing, &callObj))<0)
return ret;
if ((call->hCatCall = catAdd(app->hCat, &callObj, (HCALL)call))==NULL)
return RV_ERROR_OUTOFRESOURCES;
{
cmAnnexEUsageMode annexEBehavior=cmTransNoAnnexE;
cmCallGetParam((HCALL)call,cmParamAnnexE,0,(int *)&annexEBehavior,NULL);
cmTransSetSessionParam(call->hsTransSession, cmTransParam_isAnnexESupported,&annexEBehavior);
}
/* Findout the address of the call's Q931 destination and try to connect to it */
nodeId=((call->routeCallSignalAddress>=0))?
call->routeCallSignalAddress:
call->callSignalAddress;
cmVtToTA(app->hVal,nodeId, &tpkt);
if (call->annexECallSignalAddress>=0)
cmVtToTA(app->hVal,call->annexECallSignalAddress, &annexE);
else
annexE=tpkt;
cmTransSetAddress(call->hsTransSession, NULL, &tpkt, &annexE, NULL, cmTransQ931Conn, RV_FALSE);
ret = cmTransQ931Connect(call->hsTransSession);
}
else
{
/* Incoming call */
RvBool incompleteAddress=0;
{
RVHCATCALL hCatCall;
/* CAT changes */
if ((ret=callObjectCreate(app, (HCALL)call, Incoming, &callObj))<0)
return ret;
/* See if we've already got this call */
if ((hCatCall=catFind(app->hCat, &callObj))!=NULL)
{
callElem*foundCall = (callElem*)catGetCallHandle(app->hCat, hCatCall);
if (foundCall && m_callget(foundCall,callWithoutQ931))
{
catUpdate(app->hCat, hCatCall, &callObj);
*foundCall=*call;
call=foundCall;
}
}
else
{
/* No such call - add it to CAT as a new call */
if ((call->hCatCall = catAdd(app->hCat, &callObj, (HCALL)call))==NULL)
return RV_ERROR_OUTOFRESOURCES;
}
/* Check if we've got a complete address or not */
if (m_callget(call,remoteCanOverlapSend) && m_callget(call,enableOverlapSending))
incompleteAddress=1;
}
if (incompleteAddress)
{
/* Notify the application about the incomplete address */
notifyState((HCALL)call,cmCallStateWaitAddressAck, (cmCallStateMode_e)0);
}
else
{
/* Continue to handle the incoming setup */
enterCallSetupState(call);
}
}
return ret;
}
typedef enum
{
reasonReleaseComplete,
reasonH245ConnectionClosed,
reasonApplicationDrop,
reasonDRQ,
reasonQ931ConnectionClosed,
reasonProtocolError
} dropReasonType;
/************************************************************************
* reportDisconnectedState
* purpose: Notify the application about a disconnected call
* input : call - Stack handle for the call
* dropReason - Reason the call was disconnected
* output : none
* return : none
************************************************************************/
void reportDisconnectedState(callElem*call,dropReasonType dropReason)
{
cmCallState_e state=cmCallStateDisconnected;
cmCallStateMode_e stateMode=cmCallStateModeDisconnectedNormal;
RvBool doNotReport=RV_FALSE;
/* Make sure we notify application about disconnections only if it knowns about this call */
if (m_callget(call,notified))
{
switch(dropReason)
{
case reasonReleaseComplete:
{
int causeValue;
cmReasonType reason;
cmCallGetParam((HCALL)call,cmParamReleaseCompleteCause,0,&causeValue,NULL);
cmCallGetParam((HCALL)call,cmParamReleaseCompleteReason,0,(int *)&reason,NULL);
if (causeValue==17 || reason==cmReasonTypeInConf)
stateMode=cmCallStateModeDisconnectedBusy;
if (causeValue==28)
stateMode=cmCallStateModeDisconnectedIncompleteAddress;
}
break;
case reasonDRQ:
break;
case reasonApplicationDrop:
stateMode=cmCallStateModeDisconnectedLocal;
break;
case reasonQ931ConnectionClosed:
break;
case reasonH245ConnectionClosed:
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -