To make or receive a VOIP call a Virtual Media Processing channel needs to be created on a DSP module connected to the board which has the VOIP capability (Using SMcreateVMP()). The supported codecs can then be specified for that VMP channel using the SMsetcodec() function.
The usual call control functions can then be used to receive an inbound VOIP call, but before accepting the call the call accept parameters must be setup with the VMP channel so that the media stream (codec) can be processed. This is done using the CCsetparm() functions.
In the example below, once the VOIP call has been received we then make an outbound call over the E1 port and when this answers we create a TDM endpoint so that the E1 stream can be connected to the VMP port in a full duplex connection so that the two parties can talk to each other. This is done through the CCcreateTDM() functions and the SMfeedlisten() function.
Here is a small program showing this functionality:
$include "aculab.inc"
int vox_chan, port, chan, vmp_chan, module_id;
int call_state;
main
vox_chan=1;
module_id=0;
e1port=0;
e1chan=1;
ipport=8;
ipchan=1;
vmp_chan=SMcreateVMP(module_id); // Create a VMP channel
// specify a codec on the vmp channel
SMsetcodec(vmp_chan,0,G711_ALAW);
// Keep a track of where we are so that we know how to clear down the call in onsignal
call_state=0;
// Wait for an inbound call on IP channel(using the newly created VMP when we accept)
CCenablein(ipport,ipchan);
CCuse(ipport,ipchan); // Hangup will cause jump to onsignal
while(1)
x=CCwait(ipport,ipchan,WAIT_FOREVER,&state);
if(state eq CS_INCOMING_CALL_DET)
call_state=1; // need to clear down ip call
CCalerting(ipport,ipchan); // send INCOMING_RINGING event
else if(state eq CS_WAIT_FOR_ACCEPT)
// specify a codec on the vmp channel
SMsetcodec(vmp_chan,0,G711_ALAW);
// Set the VMP and CODEC array into the call accept parameters..
CCclrparms(ipport,ipchan,PARM_TYPE_ACCEPT);
CCsetparm(ipport,ipchan,PARM_TYPE_ACCEPT,CP_IPTEL_VMPRXID,vmp_chan);
CCsetparm(ipport,ipchan,PARM_TYPE_ACCEPT,CP_IPTEL_VMPTXID,vmp_chan);
CCsetparm(ipport,ipchan,PARM_TYPE_ACCEPT,CP_IPTEL_CODECS,vmp_chan);
CCaccept(ipport,ipchan);
break;
endif endif
endwhile
task_sigctl("("); // Temporarily prevent hangup from causing jump to onsignal
// Create the TDM endpoint for the E1 port
tdm_chan=CCcreateTDM(e1port,e1chan); // Get a TDM endpoint for an E1 channel
// ** Now connect the feeds from the VMP and TDM endpoint to make
// ** a full duplex connection to connect the conversations from the IP to E1 calls
// ** we do this here so that VOIP call will hear call progress tones..
// The vmp_chan will now listen to the tdm_chan datafeed
SMfeedlisten(vmp_chan,TYPE_VMP,tdm_chan,TYPE_TDM);
// The tdm_chan will now listen to the vpm_chan datafeed
SMfeedlisten(tdm_chan,TYPE_TDM,vpm_chan,TYPE_VPM);
call_state=2; // need to clear down ip call and destroy TDM
task_sigctl(")"); // Allow hangup to cause jump to onsignal again..
// hangup on E1 port will cause jump to onsignal
CCuse(e1port,e1chan);
call_state=3; // need to clear down both IP and E1 calls
// Now make outbound call on E1 port/channel
x=CCmkcall(e1port,e1chan,"123456"."987654");
while(1)
x=CCwait(e1port,e1chan,WAIT_FOREVER,&state);
if(state eq CS_OUTGOING_RINGING)
applog("Outgoing ringing") // send INCOMING_RINGING event
else if(state eq CS_CALL_CONNECTED)
break;
endif endif
endwhile
// We just loop here waiting for a hangup from either side which will cause jump to onsignal
while(1)
sleep(40); // four second sleep
endwhile
endmain
onsignal
applog("We are in ONSIGNAL!!!!");
// Release the VMP channel
SMdestroyVMP(vmp_chan,VMP_TYPE);
// do we need to clear down the inbound IP call?
if(call_state)
CCdisconnect(ipport,ipchan,LC_NORMAL);
if(call_state >=2)
SMdestroyTDM(tdm_chan);
endif
last_state=-1;
while(1)
# wait for idle
applog("CCIN: in onsig CCwaiting for CS_IDLE");
x=CCwait(ipport,ipchan,10,&state,last_state);
applog("CCIN: CCwait returned x=",x," state=",state);
if(state eq 0)
applog("ipport=",ipport," ipchan=",ipchan," Incoming went to IDLE");
CCrelease(ipport,ipchan);
break;
endif
task_sleep(1);
endwhile
endif
// do we need to clear down the outbound E1 call?
if(call_state >=3)
CCdisconnect(e1port,e1chan,LC_NORMAL);
last_state=-1;
while(1)
# wait for idle
applog("CCIN: in onsig CCwaiting for CS_IDLE");
x=CCwait(e1port,e1chan,10,&state,last_state);
applog("CCIN: CCwait returned x=",x," state=",state);
if(state eq 0)
applog("e1port=",e1port," ipchan=",e1chan," Incoming went to IDLE");
CCrelease(e1port,e1chan);
break;
endif
task_sleep(1);
endwhile
endif
restart;
endonsignal