Professional Documents
Culture Documents
Monica McArthur
Adapted from my presentation at AstriCon 2007
Record both legs of the call Play prerecorded prompts separately to inbound and outbound legs Provide call routing through IVR trees, overflow on busy/no answer, and voicemail Save the call detail record to a database for access by applications to do reporting and further data processing All features can be provisioned in real-time System must be highly-available and scalable
Initial capacity 1250 simultaneous calls 99.99% availability requirement Scheduled maintenance can be performed with no downtime
General solution
Write a routing application in Java to handle routing rules, provisioning changes, and interface with the database and other applications Have the Java application direct a third-party host media processing system that provides the actual SIP signaling, RTP media handling, prompt playing, call recording, and DTMF input The application servers running the Java routing application are loadbalanced by hardware and can be scaled as needed The host media processing servers are load-balanced by a SIP proxy server and can be scaled as needed
Particular issues
Inbound leg must be able to continue even if outbound leg fails
To provide voicemail and overflow routing
Outbound leg must be able to continue after inbound leg hangs up on a connected call
To provide post-call input and play index number for recorded calls
Outbound calls may play a whisper heard only by the target while the inbound still hears ringback If there is no whisper, the call must support early media
Media begins streaming (initially ringback) before outbound connect and must be played to inbound If early media is not streamed to inbound leg, the initial few syllables of the outbound call may be lost (media clipping) Ringback must not be included in call recordings
100 TRYING
183 SESSION PROGRESS Early media 200 OK Normal media Media that can be lost to clipping
More port density per server (can easily achieve 150 vs. 125)
Open source allows us to either find bug fixes in the Asterisk community or write our own
FastAGI and AMI provide means for existing Java software to communicate with Asterisk in ways similar to the previous HMP
Only need to replace the vendor-specific code
Could write our own software to interface with FastAGI and AMI
Asterisk-Java
Open source, free library for Asterisk integration Hosted in SourceForge Current version is 0.3 Handles the low-level details of FastAGI and AMI communication Java code for accessing AGI using Asterisk-Java is structured similarly to servlets AMI communication is handled through ManagerActions (to send AMI actions) and ManagerEvents (to receive AMI events)
AgiRequest contains information about the call (caller ID, dialed digits, etc.)
AgiChannel handles the details of the convenience methods
Subclasses of ManagerEventListener are registered to listen on a ManagerConnection Can also create custom events that are subclasses of ManagerEvent and register them with the ManagerConnection
Custom ManagerEvent
public class ConnectedEvent extends ManagerEvent { private String channelName; private String channelID; private String userData;
Remaining issues
With this architecture and a plain version of Asterisk, we can provide all of the required features of the softswitch EXCEPT
Early media
app_dial does provide support for early media, but only with the channel it is running on
Problem 1: having the outbound leg survive after the inbound disconnects
The straightforward way to handle connecting an inbound leg to another number is to dial the number using app_dial
Unfortunately, in that case the outbound leg does not survive the hangup of the inbound leg Need to have each leg living independently (in its own channel) but still joined together
Solution
To get the outbound leg in its own channel: use AMI Originate to get a local channel, connect to AGI, then use app_dial to make the outbound call To join the two channels together: use a patch for bridging independent legs
Was bug 5841; in trunk for 1.6
In AGI script, use app_dial to make actual call for outbound leg
Check result of app_dial in start context to handle busy/no answer Perform additional functions on connected leg in context specified for connection This is a well-known pattern; see http://blogs.reucon.com/asteriskjava/2007/04/18/originate_using_asterisk_local_channels.html
Bridge patch
Bridge patch was originally submitted with bug 5841: Bridge two channels via a Dialplan App or an AMI event Provides a Bridge() application for dialplan/AGI and an AMI Bridge action that will bridge the current channel with another specified channel that already exists Used to bridge the inbound leg with the connected outbound leg obtained by app_dial Patch we used was bridge-trunk-rev48286.patch Code is now included in 1.6 trunk
See http://bugs.digium.com/view.php?id=5841 for details
In order to provide early media to the inbound leg, app_dial needs to return if SIP 183 (session progress) is received
Since calls with whisper cannot use early media, whether app_dial returns on SIP 183 needs to be configurable In order to avoid recording the ringback when early media is used, the Java application needs to know when the SIP 200 (OK) is received after app_dial connects on SIP 183
Execute bridge
exec("Bridge", astCall.getObAstChannel());
app_dial.c changed to have new argument which specifies whether to connect on SIP 183 if received
Summary of changes
Asterisk
Include bridge patch bridge-trunk-rev48286.patch (already included in 1.6 trunk) Patch app_dial to optionally consider a progress as answer and to set a channel variable with which signal resulted in connect; patch channel.c to send an AMI event when a connect is received
Asterisk-Java: no changes
Custom Java code:
New Java code for AGI scripts and explicit state machine handling One new subclass of Asterisk-Javas ManagerEvent to handle channel.cs new event