IRAPI applications are event driven. This means that the application must respond properly to completion events that result from commands initiated by the IRAPI application (such as a speech play request) or miscellaneous externally induced events (such as an incoming telephone call).
By default, the library notifies the application of most events. The application may request that it be notified of all the events. Some events can be masked meaning that an application may ask not to be informed of the event (that is, the event is to be ignored). Some of the more important events are non-maskable meaning that the application must be informed about the event. Generally an event is non-maskable if the application would likely encounter state transition errors by trying to ignore the event.
By properly responding to the events as they occur, an application seldom needs to check the library or service states that are maintained by the IRAPI library. Applications may occasionally need to maintain a small amount of application state information in order to properly handle the events that occur.
The IRAPI library allows an application to interrupt activities with events. Interrupts see the premature stopping of some IRAPI activity such as playing of speech. For example, an application may want to interrupt speech after receiving a touch tone so the caller does not have to listen to the entire prompt.
Controlling events
The action taken by the library in response to an event may be modified by the routines described in irEvent(3IRAPI).
The action argument to irSetEvent is an ORed result of some of the following values:
irGetEvent(3IRAPI) can be used to return the current control action for an event.
Detecting library events
The following routines are used to detect library events:
Note:
A few applications may need to call irCheck() directly if they need to be able to detect that there are no pending events and then take some action other than calling irWait() to wait for the next event.
The following code fragment shows an example of irWCheck():
while (irWCheck(&ev) != IRR_FAIL) {
cid = ev.cid;
chan = irCid2Chan(cid);
switch(ev.event_id) {
case IRE_EXEC:
.
.
.
case IRE_PLAY_DONE:
.
.
.
}
}
Handling events in a timely manner
An IRAPI application must handle events in a timely manner to prevent problems from occurring. Network interface timing errors may occur, or callers may hear speech breaks or other undesirable behavior.
An IRAPI application must call irWCheck (or irWait and irCheck) frequently to avoid these problems. This is especially true for permanent IRAPI applications that are handling multiple channels simultaneously. A permanent IRAPI application must not allow itself to be blocked while waiting for an input/output (I/O) or other request that could take more than a few milliseconds to complete. For example, it is unwise to write an IRAPI application that is blocked while waiting for the response to a complex database query that might take seconds to complete. A separate data interface process (DIP) may be necessary in this case.
Preferably, IRAPI applications should be written so that the only blocking occurs within irWait or irWCheck.
Polling with stream-oriented devices
irWait is compatible with signals in that irPoll(3IRAPI) functions can be used on stream-oriented devices. These functions may be used to multiplex input from irWait(3IRAPI) and other file descriptors.
int handle_poll(int fd, short revents)
{
/* handle your input here */
}
main()
{
...
irAddPoll(fd, POLLRDNORM|POLLHUP, handle_poll);
while(1)
{
while( irWCheck(&ev) != IRE_NULL)
{
switch(ev.event_id)
{
.
.
.
}
}
}
}
Polling for other input using IRAPI timers
If an application simply needs a frequent stimulus to poll for the handling of non-IRAPI activity, the application can set a process-oriented timer to generate an IRE_CLOCK event at regular intervals with ten millisecond granularity. See the following code fragment for an implementation example:
main ()
{
int tag=0xfeed;
/* set a repeating timer for 2 seconds */
irStartPTimer (2000, 1, tag);
while (1) {
while (irWCheck(&ev) != IRE_NULL) {
switch (ev.event_id) {
case IRE_CLOCK:
/* handle your other activity here,
* taking care not to sleep */
.
.
.
}
}
}
}
Polling for other input with SIGALRM
The alarm system call can be used to interrupt irWait at fairly regular intervals to handle other activity input. The use of alarm allows less control on the accuracy of the polling rate than using IRE_CLOCK in the previous example because alarm generates an interrupt at the given time with one second granularity.
void
handle_alarm (int signal_no)
{
/* handle your input here, taking care not to sleep */
alarm (2);
}
main ()
{
sigset (SIGALRM, handle_alarm);
/* set a repeating timer for 2 seconds */
alarm (2);
while (1) {
while (irWCheck(&ev) != IRE_NULL) {
switch (ev.event_id) {
.
.
.
}
}
}
}
Polling for IRAPI activity
As a last resort, an IRAPI application can block on other activity (only when necessary) and poll the IRAPI library as frequently as possible.
main ()
{
while (1) {
/* wait on and handle your input here,
* making sure to enter this loop frequently. */
while (irCheck(&ev) != IRE_NULL) {
switch (ev.event_id) {
.
.
.
}
}
}
}
IRAPI event tags
IRAPI functions that initiate speech or telephony activity which result in a subsequent completion event have a tag argument. This tag can be used for whatever purpose the application chooses. The same tag value is returned in the tag field of the resulting completion event.
The tag value is not used internally by the IRAPI library and may contain any integer value that the application chooses. The tag can be used to resolve any ambiguity on event handling. The application may choose to use the tag for any of the following: