Avaya Logo

Previous Topic

Next Topic

Book Contents

Book Index

Making chantest support outcalling

An IRAPI application placing outbound calls must know what channel to use, what telephone number to call, and what parameter values to use (if not using the defaults). There are many techniques available to initiate outcalling. A transient IRAPI application that is designed to handle a single channel might accept command line arguments such as the telephone number to call. A permanent IRAPI application that is designed to handle multiple channels may receive the equipment group (or specific channel), phone number, and parameter values via an exec buffer or via an IRE_EXTERNAL event. The example that follows uses the IRE_EXTERNAL event to pass the equipment group, phone number, and parameter values.

The code fragments that follow indicate changes to the chantest sample application that allow the new chantest_oc application to initiate a call as well as answer incoming calls. The complete code for the chantest_oc sample application is available on the system in the file /vs/examples/IRAPI/chantest_oc.c. Also, included on the system is the mkcall sample application (in the file /vs/examples/IRAPI/mkcall.c ) that uses irPostEventQ to pass the IRE_EXTERNAL message to chantest_oc.

In this particular example, the mkcall program expects the user to provide the equipment group number that should be used when initiating the call. chantest_oc then uses any available channel in that equipment group to initiate the call. It is a straightforward change to mkcall and chantest_oc to pass either a specific channel number or an equipment group.

The following is the message structure for passing the data from the mkcall transient process to the chantest_oc process. mkcall is a command line program that accepts the data values as command line arguments and passes them to chantest_oc via the following message structure.

struct CALLDATA {
struct mbhdr header;
int groupNo;
int MaxRings;
int CCAType;
char Number[PH_NUM_LEN];
} *msgp;

The chantest_oc program must store the call request parameters for one or more outbound call requests until the channels are granted for placing the call. The following structure is used to store the requests.

struct PENDING_CALL {
int pending_flag;
struct CALLDATA call_request;
} pending_calls[MAX_PENDING];

The following shows new code that can be added to chantest to handle the IRE_EXTERNAL event. Note that the index into the preceding array of structures is used as the identifier for a specific request.

case IRE_EXTERNAL:
/* Save the outcalling request data and soft seize a
* channel from the specified equipment group. */
msgp = (struct CALLDATA *) ev.event_text;
for (i = 0; i < MAX_PENDING; i++) {
if(pending_calls[i].pending_flag == IRD_FALSE) {

pending_calls[i].pending_flag = IRD_TRUE;
pending_calls[i].call_request = *msgp;
(void) seizeGroup(i);
break;
}
}
break;

The seizeGroup() function initializes a channel and possibly starts the application.

int seizeGroup(int req_idx) {

struct CALLDATA *callReqP;
int ret;
channel_id cid;

/* Attempt to become channel owner for a channel in the equipment
* group identified by the request. */
callReqP = &pending_calls[req_idx].call_request;

ret = irInitGroup(callReqP->groupNo, &cid, 10000, req_idx);

if (ret == IRR_FAIL) {
irPError("Error on irInitGroup");
return(-1);
}

if(ret == IRR_OK) {
if ( setEvents(cid) < 0 || setTTParams(cid) < 0 ) {
cleanup("Error setting events or parameters", cid);
return(-1);
}
return(startOutcall(cid, req_idx));
} else {
return(0); /* Chan request is pending */
}
}

In almost all cases, irInitGroup(3IRAPI) returns IRR_PENDING; therefore, the application must wait for either IRE_CHAN_GRANT or IRE_CHAN_DENY. Note that tag passed to irInitGroup is being used to identify a specific request in the array of PENDING_CALL structures.

case IRE_CHAN_GRANT:
if(setEvents(cid) < 0) {
cleanup("Error on setEvents", cid);
break;
}
if(setTTParams(cid) < 0) {
cleanup ("Error on setTTParams", cid);
break;
}

(void) startOutcall(cid, ev.tag);
break;

case IRE_CHAN_DENY:
(void) fprintf(stderr, "Denied ownership of channel");
if ( ev.tag >= 0 && ev.tag <= MAX_PENDING) {
pending_calls[ev.tag].pending_flag = IRD_FALSE;
}
break;

The startOutcall() function initiates the outbound call via irCall(3IRAPI).

int startOutcall(channel_id cid, int req_idx)
{
struct CALLDATA *callReqP;
int chan = irCid2Chan(cid);

if(req_idx < 0 || req_idx > MAX_PENDING) {
cleanup ("Invalid call request index", cid);
return (-1);
}
/* Set parameters for outcalling and call. */
callReqP = &pending_calls[req_idx].call_request;

if ( irSetParam(cid, IRP_OUTCALL_DIALTYPE, IRD_DIALTYPE_TT)
== IRR_FAIL ||
irSetParam(cid, IRP_OUTCALL_MAXRINGS, callReqP->MaxRings)
== IRR_FAIL ||
irSetParam(cid, IRP_OUTCALL_CCALEVEL, callReqP->CCAType)
== IRR_FAIL ||
irCall(cid, 1, callReqP->Number) == IRR_FAIL ) {
cleanup("Failure in startOutcall", cid);
return(-1);
}
/* Release this pending_call entry */
pending_calls[req_idx].pending_flag = IRD_FALSE;

return(0);
}

The IRE_CALL_DONE event indicates call disposition. The IRE_CALL_PROG event may be used by some applications to follow call progress.

case IRE_CALL_DONE:
switch (ev.event_mod1)
{
case IREM_RINGBACK:
case IREM_ANSWER_SUP:
case IREM_ANSWER:
case IREM_BLIND:
startChanTst(cid);
break;
case IREM_NOANSWER:
case IREM_HIDRY:
case IREM_REORDER:
case IREM_BUSY:
case IREM_TIMEOUT:
case IREM_FAST_BUSY:
case IREM_ERROR:
default:
if (irDisconnect(cid, 0) < 0) {
cleanup ("Error on irDisconnect", cid);
}
break;
}
break;

© 2006 Avaya Inc. All Rights Reserved.