Sip Soft Switch Astri Con Adapted

download Sip Soft Switch Astri Con Adapted

of 28

Transcript of Sip Soft Switch Astri Con Adapted

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    1/28

    Building a SIP softswitch withAsterisk and Asterisk-Java

    Monica McArthur

    Adapted from my presentation at AstriCon 2007

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    2/28

    The task at hand

    Build a pure SIP softswitch that can perform the following functions:

    Answer an inbound call and redirect it to a specified target phonenumber

    Rules for determining target number can be complex

    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 todo 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

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    3/28

    General solution

    Write a routing application in Java to handle routing rules,provisioning changes, and interface with the database and otherapplications

    Have the Java application direct a third-party host media processingsystem 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 load-balanced 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

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    4/28

    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 ona 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 outboundcall may be lost (media clipping)

    Ringback must not be included in call recordings

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    5/28

    Overview of early media issue

    In many standard SIP signaling exchanges, the answering user agentmay start generating media before the first agent is ready for it(media clipping)

    To avoid media clipping, the answering user agent may send a 183(session progress) and then initiate a one-way media stream at thatpoint

    If the initial user agent ignores the media stream sent with the 183and only accesses it after receiving a 200, media clipping will stilloccur

    This issue is discussed in RFC 3960: Early Media and Ringing ToneGeneration in the Session Initiation Protocol (SIP)

    http://www.rfc-archive.org/getrfc.php?rfc=3960

    http://www.rfc-archive.org/getrfc.php?rfc=3960http://www.rfc-archive.org/getrfc.php?rfc=3960http://www.rfc-archive.org/getrfc.php?rfc=3960http://www.rfc-archive.org/getrfc.php?rfc=3960
  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    6/28

    Diagram of SIP signaling with early media

    Media path established

    Inbound leg Media gateway Outbound leg

    INVITE

    100 TRYING

    183 SESSION PROGRESS

    Early media

    200 OK

    Normal media

    Media that can be lost

    to clipping

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    7/28

    Problems with existing solution

    Ports are expensive!

    Chosen host media platform did not support early media

    Dependent on vendor to implement fixes Could take years

    Often broke workarounds in place to support other features

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    8/28

    New solution: Asterisk

    Port cost now zero

    More port density per server (can easily achieve 150 vs. 125)

    Open source allows us to either find bug fixes in the Asteriskcommunity 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

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    9/28

    Software architecture with Asterisk

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    10/28

    How to interface with Asterisk

    Could write our own software to interface with FastAGI and AMI

    Or could select from a wide variety of existing open source libraries

    After review, selected Asterisk-Java

    http://asterisk-java.org

    http://asterisk-java.org/http://asterisk-java.org/http://asterisk-java.org/http://asterisk-java.org/
  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    11/28

    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 structuredsimilarly to servlets

    AMI communication is handled through ManagerActions (to send AMIactions) and ManagerEvents (to receive AMI events)

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    12/28

    Accessing AGI in Asterisk-Java

    AGI applications are implemented as subclasses of BaseAgiScript

    BaseAgiScript provides convenience methods to send all AGIcommands

    AGI scripts are mapped to correct classes in setup code

    service() method of BaseAgiScript has two arguments, AgiRequestand AgiChannel

    AgiRequest contains information about the call (caller ID, dialeddigits, etc.)

    AgiChannel handles the details of the convenience methods

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    13/28

    Accessing AGI in Asterisk-Java(examples)

    public class AGIInbound extends BaseAgiScript {

    public void service(AgiRequest request, AgiChannel channel)

    throws AgiException {

    callID = new Long(getVariable(APP_CALLID"));this.streamFile(greetingFile);

    this.streamFile("routing/tone");

    this.exec("Record", recordingFilename + ".wav" + "|" + silence

    + "|" + maxduration + "|q");

    this.hangup();

    Agi script to begin handling call

    Code for voicemail

    agiMap.put("AGIInbound.agi", new AGIInbound());

    SimpleMappingStrategy agiMapping = new SimpleMappingStrategy();

    agiMapping.setMappings(agiMap);

    agiServer.setMappingStrategy(agiMapping);

    Setting up the mapping for AGIInbound

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    14/28

    Accessing AMI in Asterisk-Java

    Subclasses of ManagerAction are provided for each AMI action e.g., OriginateAction, HangupAction, SetVarAction

    Instances of actions are sent by using an instance ofManagerConnection

    Subclasses of ManagerEvent are provided for each AMI event e.g., DialEvent, HangupEvent, NewChannelEvent

    Subclasses of ManagerEventListener are registered to listen on aManagerConnection

    Can also create custom events that are subclasses of ManagerEventand register them with the ManagerConnection

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    15/28

    Accessing AMI in Asterisk-Java(examples)

    managerConnection.addEventListener(new

    ManagerEventListenerProxy(amiDispatchers.get(routingNode)));

    managerConnection.registerUserEventClass(Class.forName(

    "astrouting.control.ami.events.ConnectedEvent"));

    public class ConnectedEvent extends ManagerEvent {

    private String channelName;

    private String channelID;

    private String userData;

    Configure event listener and custom event

    Custom ManagerEvent

    OriginateAction originateAction = new OriginateAction();originateAction.setChannel(channel);

    originateAction.setVariable(APP_CALLID", "" + astCall.getCallID());

    originateAction.setAsync(true);

    originateAction.setTimeout(1000L*astCall.getCall().getRNATime()+5000L);

    managerResponse = managerConnection.sendAction(originateAction);

    Create and send OriginateAction

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    16/28

    Software architecture (detailed)

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    17/28

    Remaining issues

    With this architecture and a plain version of Asterisk, we can provide allof the required features of the softswitch EXCEPT

    Having the outbound leg survive after the inbound disconnects Need legs in separate threads

    Early media app_dial does provide support for early media, but only with the channel it is running

    on

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    18/28

    Problem 1: having the outbound legsurvive after the inbound disconnects

    The straightforward way to handle connecting an inbound leg toanother number is to dial the number using app_dial

    Unfortunately, in that case the outbound leg does not survive thehangup of the inbound leg

    Need to have each leg living independently (in its own channel) butstill joined together

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    19/28

    Solution

    To get the outbound leg in its own channel: use AMI Originate to get alocal channel, connect to AGI, then use app_dial to make theoutbound call

    To join the two channels together: use a patch for bridgingindependent legs

    Was bug 5841; in trunk for 1.6

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    20/28

    Originate on a local channel

    First, use AMI OriginateAction to request a local channel that will startin a particular context and go to another context when connected

    Syntax is local/s@

    Then, launch AGI script from context

    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 forconnection

    This is a well-known pattern; see

    http://blogs.reucon.com/asterisk-java/2007/04/18/originate_using_asterisk_local_channels.html

    http://blogs.reucon.com/asterisk-java/2007/04/18/originate_using_asterisk_local_channels.htmlhttp://blogs.reucon.com/asterisk-java/2007/04/18/originate_using_asterisk_local_channels.htmlhttp://blogs.reucon.com/asterisk-java/2007/04/18/originate_using_asterisk_local_channels.htmlhttp://blogs.reucon.com/asterisk-java/2007/04/18/originate_using_asterisk_local_channels.htmlhttp://blogs.reucon.com/asterisk-java/2007/04/18/originate_using_asterisk_local_channels.html
  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    21/28

    Example code for origination

    int dialExecResult = exec(Dial, "SIP/" + target + "@nextone|" +

    dialTimeout);

    String DIALSTATUS = this.getVariable("DIALSTATUS");

    if (dialExecResult == 0) {

    if ("NOANSWER".equals(DIALSTATUS)) {

    astCall.noAnswer();

    } else if ("BUSY".equals(DIALSTATUS)) {

    astCall.busy();}

    // etc. for CONGESTION, CHANUNAVAIL, CANCEL, HANGUP, default

    }

    Configure and send OriginateActionOriginateAction originateAction = new OriginateAction();

    originateAction.setChannel("Local/s@ob-agi-dial");

    originateAction.setApplication("Agi");

    originateAction.setData("agi://" + agiServer+

    ":4573/AGIOutboundConnect.agi");

    managerResponse = managerConnection.sendAction(originateAction);

    Launch app_dial and check result

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    22/28

    Bridge patch

    Bridge patch was originally submitted with bug 5841: Bridge twochannels via a Dialplan App or an AMI event

    Provides a Bridge() application for dialplan/AGI and an AMI Bridgeaction that will bridge the current channel with another specifiedchannel that already exists

    Used to bridge the inbound leg with the connected outbound legobtained 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

    http://bugs.digium.com/view.php?id=5841http://bugs.digium.com/view.php?id=5841
  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    23/28

    Problem 2: early media

    app_dial provides support for early media, but only to its inbound leg

    In this architecture, the inbound leg is a local channel and the actualinbound leg does not receive media from the outbound leg until theyare joined using Bridge()

    In order to provide early media to the inbound leg, app_dial needs toreturn if SIP 183 (session progress) is received

    Since calls with whisper cannot use early media, whether app_dialreturns on SIP 183 needs to be configurable

    In order to avoid recording the ringback when early media is used, theJava application needs to know when the SIP 200 (OK) is receivedafter app_dial connects on SIP 183

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    24/28

    Example code to use bridge patch

    public void onManagerEvent(ManagerEvent event) {

    else if (event instanceof DialEvent) {

    astCall = AstRoutingController.getController().

    getAstCallByChannel(event.getSrc());

    astCall.setObAstChannel(event.getDestination());

    }

    Get outbound channel ID from DialEvent

    exec("Bridge", astCall.getObAstChannel());

    Execute bridge

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    25/28

    Solution: app_dial and channel patch

    This required an original patch

    Not yet submitted to Asterisk; will consider based on demand

    app_dial.c changed to have new argument which specifies whether toconnect on SIP 183 if received

    app_dial.c also stores which signal (PROGRESS/183 or ANSWER/200)it actually connected on SIP spec does not require answering user agent to send 183

    channel.c changed to send custom AMI event on receipt of answer Used to determine time to start recording if app_dial connected on 183

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    26/28

    Example code to use the new patch

    String dialExecString = "SIP/" + target + "@nextone|" + dialTimeout;

    if(astCall.earlyMedia())

    dialExecString += ||1";

    int dialExecResult = exec(Dial, dialExecString);

    public void onManagerEvent(ManagerEvent event) {

    else if (event instanceof ConnectedEvent) {

    astCall = AstRoutingController.getController().

    getAstCallByChannel(event.getChannelName());

    astCall.connectSignaled();

    }

    Call app_dial with new argument

    Receive notice of connect

    String connectedSignal = getVariable("CONNECTED_SIGNAL");if("PROGRESS".equals(connectedSignal)) {

    // handle early media

    } else {

    // handle normal flow

    }

    Check channel variable

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    27/28

  • 7/29/2019 Sip Soft Switch Astri Con Adapted

    28/28

    Summary of best practices learned

    Go into an AGI script in a context immediately

    Use AMI events (hangup events, dial events, new events as needed)to keep track of call state and handle graceful hangups

    To get an outbound leg in its own thread, originate on a local channel

    and then use app_dial (called from an AGI script) to make the actualoutbound call