Writing an IVR
Start an IVR
In Yate an IVR is an application started when an incoming call is routed to that application. This application gets the opportunity of inspecting events generated by the caller and giving commands to Yate - all these by handling or generating Messages. From Yate's point of view the IVR (the application behind it) is just a channel.
What should do an IVR
An IVR application must at least:
- install handlers for messages it wants to process
- read the standard input and parse incoming messages
- identify the messages it needs and process them
- acknowledge all incoming messages
- maintain the call state
- keep the event loop running (reading and acknowledging messages - VERY IMPORTANT)
Since all these are complex it is better to use libraries that can handle at least part of the job.
How to implement an IVR
Usually an IVR is implemented using a script run under the control of the the external module and a library that converts incoming and outgoing messages in objects the programming language can handle. Currently the options are PHP (via libyate.php) or Python (via libyate.py or YAYPM).
The application should install handlers for messages like "chan.dtmf" and "chan.notify" and act as a state machine, processing incoming events, changing the state and attaching voice sources and/or consumers via the "chan.attach" message.
The caller can be transferred to another channel (which can be another IVR) by masquerading a "call.execute" message. As soon as the caller is connected to the transfer target channel the current application (the IVR) is automatically disconnected and terminated.
An application can also disconnect the caller by simply exiting.
Note that the current application is also terminated if the user hangs up. The script gets a chance of cleaning up just after its stdin/stdout get closed. In case of libyate.php this is converted to an "EOF" event.
As a local option an IVR can enable generating its own "chan.disconnected" message. While handling it an IVR can safely perform cleanup operations. However, once "chan.disconnected" is acknowledged the communication channel is closed and the script terminated after a very short delay.
Nothing prevents an IVR from implementing other functionality. A route to a given called number can be obtained by emitting a "call.route" message and looking at the answer. An IVR can even act as a short lived routing module, for example to implement a meeting room.