Some Simple Examples
Previous Topic  Next Topic 

Probably the best way to show the basic library functions and the library calling conventions is to provide a simple example.       The example below simply waits for an incoming call on the first channel of the first E1 port,  plays a message and then hangs up.            It is assumed that the reader is familiar with the Telecom Engine standard library set and the Aculab Speech module library (CXACUDSP.DLL).



$include "aculab.inc"

 

int port, chan, vox_chan, x, event;

var filename:64;

 

main

    port=0

    chan=1;

    vox_chan=1;

    filename="hello.vox";

 

    // Make full duplex H.100 bus routing between voice channel and network port/channel

    CClisten(port,chan,SMgetslot(vox_chan));

    SMlisten(vox_chan, CCgetslot(port, chan));

 

    // Enable inbound calls on this port/channel

    CCenablein(port,chan);

    

    // loop waiting for incoming call

    while(1)

          x=CCwait(port,chan,CC_WAIT_FOREVER,&event);

          if(x > 0 and event eq CS_INCOMING_CALL_DETECTED)

               break;

          endif

    endwhile

 

    // Answer the call

    CCaccept(port,chan);

 

    // Play a vox file to caller

    SMplay(vox_chan,filename);

   

    // Hangup the call 

    CCdisconnect(port,chan,CAUSE_NORMAL);

 

   // Wait for state to return to IDLE the release call

   while(1)

       x=CCwait(port,chan,CC_WAIT_FOREVER,&event);

       if(x eq CS_IDLE)

             break;

       endif

    endwhile

 

    // release the call

    CCrelease(port,chan);

    

    // restart the application to wait for another call..   

    restart;

 

endmain



The program should be fairly self explanatory but I will describe the key parts of the program below.


The “aculab.inc” file is provided with the library and defines all the constants that are used with the library such as CC_WAIT_FOREVER, CAUSE_NORMAL, CS_INCOMING_CALL_DETECTED etc.       These are be described in more detail in the call control library function library reference (CXACULAB).  


The first call:  CClisten() simply makes the receiving stream/channel of the call control channel Listen to the transmit stream/channel of the Voice channel, so that anything that is output by the voice channel will be heard by the caller.       


The second call:   SMlisten() makes the receiving stream/channel voice channel listen to the transmit stream/channel of the Call control channel, so that any DTMF digits or other audio transmitted by the caller will be heard by the voice channel.   


As mentioned above all this is done by switching from and to the extern H.100 or SCBUS.


The CCenablein(port,channel) allows inbound calls to be received on the channel,  and then the application goes into a loop waiting for calls.


The CCwait(port,channel,timeout_100ms,&event) function call will wait for the specified timeout (in 10ths of a second) for an event.    If the timeout is defined as -1 (CC_WAIT_FOREVER) then the call will not return until an event is found or it is aborted by a CCabort() call.       Really the only event that should be received here is CS_INCOMING_CALL_DETECTED but we do a specific check for it anyway in case the channel was in a unknown state when the program started (probably some error handling should be carried out if we found an unexpected event).


Once a CS_INCOMING_CALL_DETECTED event has been received then the call is answered immediately with CCaccept(port,channel)  and the voice prompt is played to the caller using the SMplay(vox_chan,filename) function from the CXACUDSP.DLL library.         


The call is then disconnected using the CCdisconnect(port,channel) call and the application goes into a loop waiting for the channel to return to the CS_IDLE state before releasing the call with CCrelease(port,channel) and restarting the program to wait for the next call.


There are obviously a number of improvements that can be made to this application to make it more useful.      Currently it only waits for and accepts a call on one channel, whereas in a real life situation there would be 30 or more channels on an E1.        



Usually, one would have a master program which would spawn a task to take control of a single channel on a port.     In the application below there are 4 E1 ports and so we spawn a channel control task for each channel on each E1, something like this:


int port, channel;

const MAX_PORTS=4

const MAX_CHANNELS=32;


main


     for(port=1;port <= MAX_PORTS)

          for(channel=1;channel <= MAX_CHANNELS;channel++)

            // Skip the signalling channel

            if(channel <> 16)

                // spawn the task called chantask.tex

                // and pass the port and channel as arguments

                task_spawn("chantask",port,channel);

            endif

        endfor

    endfor

endmain



The chantask.tex application would then be similar to the first example but instead of the port and chan variables being hard-coded, we would instead take these from the arguments passed to the task through the task_spawn() function call:


$include "aculab.inc"

 

int port, chan, vox_chan, x, event;

var filename:64;

 

main

    port=arg(1);

    chan=arg(2);


    // Use voice channels sequentially 1..x

    vox_chan=1+(port*32+chan);

    filename="hello.vox";

 

    // Make full duplex H.100 bus routing between

    // voice channel and network port/channel

    CClisten(port,chan,SMgetslot(vox_chan));

    SMlisten(vox_chan, CCgetslot(port, chan));

 

    // Enable inbound calls on this port/channel

    CCenablein(port,chan);

    

    // loop waiting for incoming call

    while(1)

          x=CCwait(port,chan,CC_WAIT_FOREVER,&event);

          if(x > 0 and event eq CS_INCOMING_CALL_DETECTED)

               break;

          endif

    endwhile

 

  ... etc


endmain



Also it is likely that rather than playing a fixed prompt, as in the program above, a more usual way of handling incoming calls is to inspect the DID or ANI and make a decision based on these about how to handle the call (usually a table lookup).        Typically this would result in the chantask.tex program chaining on to another application which then takes control of playing messages and receiving DTMF etc.    When the caller hangs up or the application disconnects the call then the application would then chain back to the chantask.tex program  to wait for another call.      The CCgetparm(port,channel,ParmID) function is used to extract call specific parameters such as the DID and ANI.


$include "aculab.inc"

 

int port, chan, vox_chan, x, event;

var filename:64, did:64,ani:64, service_name:64;


main

    port=arg(1);

    chan=arg(2);


    // Use voice channels sequentially based on the port/channel

    vox_chan=1+(port*32+chan);

    filename="hello.vox";

 

    // Make full duplex H.100 bus routing between

    // voice channel and network port/channel

    CClisten(port,chan,SMgetslot(vox_chan));

    SMlisten(vox_chan, CCgetslot(port, chan));

 

    // Enable inbound calls on this port/channel

    CCenablein(port,chan);

    

    // loop waiting for incoming call

    while(1)

          x=CCwait(port,chan,CC_WAIT_FOREVER,&event);

          if(x > 0 and event eq CS_INCOMING_CALL_DETECTED) break; endif

    endwhile


    // Get the CLID and DID

    did=CCgetparm(port,chan,CP_DESTINATION_ADDR);

    ani=CCgetparm(port,chan,CP_ORIGINATING_ADDR);


    // Use the DID to decide which application to chain

    // This usually will be a database lookup based on the DID

    service_name=DID_LOOKUP(did);


    //  A blank service_name indicates unknown DID number

    if(service_name strneq "")

         // Answer the call

         CCaccept(port,chan);

    

         // Chain on to the IVR service task

         task_chain(service_name,port,channel);


         // If we get here then the chain call failed (ie. Invalid TEX file)

    endif


 

    // Hangup the call 

    CCdisconnect(port,chan,CAUSE_NORMAL);

 

   // Wait for state to return to IDLE the release call

    while(1)

       x=CCwait(port,chan,CC_WAIT_FOREVER,&event);

       if(x eq CS_IDLE) break; endif

    endwhile

 

    // release the call

    CCrelease(port,chan);

    

    // restart the application to wait for another call..   

    restart;

 

endmain