CCXML 1.0-W3C Development GuideHome  |  Frameset Home

  tutorial Advanced VoiceXML Dialogs  |  TOC  |  tutorial Outbound CCXML Token Dialing  

Tutorial: Connecting Call Legs

This Lesson will revisit how CCXML is able to interact with VoiceXML 2.0 dialogs and delve into the world of connecting two call legs together in a conference-style application. This tutorial is considerably more complicated than our previous ones, and is not recommended as a starting point.

Note: The code presented within this tutorial is intended for the "Prophecy - CCXML 1.0" application type only. Attempts to utilize this code on the "CCXML - Voxeo" application type will not function, as the latter platform is based on the W3C specification from 2002.  Prophecy CCXML 1.0 is compliant to the most recent specification from 2006.


In this tutorial, we will:

Note: this tutorial requires the enabling of outdial priveleges on the Voxeo network, and the provisioning of a alphanumeric token string to your application. In order to get hooked up with all these neat features, check our Support Guide for all the juicy details.

Step 1: creating our initial CCXML structure

By now, we are used to setting up the basic framework of a CCXML 1.0 application. We will do so here as our starting point, and will also pre-declare some application variables that we will need as we flesh out our application:


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">
  <var name="state0" expr="'init'"/>
  <var name="callid_in"/>
  <var name="callid_out"/>
  <var name="pin"/>
  <var name="holdMusicDlg"/>

</ccxml>


The variables that we will be using are explained as follows:



These variables and what they do might not make too much sense right now, but as we add more content to the CCXML 1.0 application, it will all be clear as a bell.

Step 2: setting up our basic handlers

We should be pretty hip with state machines and handlers, both "event" and "error", so let's go ahead and define those first. After all, putting in place error handlers especially is the most important thing that we can define right out of the gate to ensure that any goofs won't cause an application loop:


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

  <var name="state0" expr="'init'"/>
  <var name="callid_in"/>
  <var name="callid_out"/>
  <var name="pin"/>
  <var name="holdMusicDlg"/>

<eventprocessor statevariable="state0">

    <transition state="init" event="connection.alerting">
      <accept/>     
    </transition>

    <transition state="init" event="connection.connected">
      <assign name="callid_in" expr="event$.connectionid"/>
    </transition>

    <transition event="error.*">
      <log expr="'an error has occured (' + event$.error + ')'"/>
              <voxeo:sendemail to="'yourEmail@there.com'"
                        from="'myApp@here.com'"
                        type="'debug'"
                        body=" 'generic error detected ! ' "/>
      <exit/>
    </transition>


A few items to note so far:

Step 3: introducing VoiceXML dialogs into the fray

CCXML 1.0 is designed as a powerful call control structure, but often phone applications expect pesky items, like audio files, to be played or even voice recognition inputs to gather information. These are accomplished through "dialogs" to VoiceXML applications. As we are planning on just prompting for, and then receiving a PIN code from our inbound caller, we will utilize the Voxeo 'application/x-fetchdigits' dialog extension just as soon as the call is accepted, while within the "connection.connected" transition:


    <transition state="init" event="connection.connected">
      <assign name="callid_in" expr="event$.connectionid"/>
      <assign name="state0" expr="'enterpin'"/> 
      <dialogstart src="'null://?termdigits=#&amp;text=enter your conference pin code followed by the pound key'"
                  type="'application/x-fetchdigits'"/>


    </transition>


You will doubtlessly notice that we change the state and launch the dialog contained in our dialog extension. This dialog is very basic, gathering up a PIN code with voice recognition so that we can allow, or disallow specific PIN codes: In this case, "1234" will allow callers to connect to the outbound party; all others will be disconnected.

Now what? Our dialog will end naturally when the caller enters their PIN code and presses the terminating character, (dtmf-pound, as defined in the "termdigits" parameter), and this variable is now available to us within the CCXML 1.0 context via  "event$.values.digits", which is yet another Voxeo extension that allows us to access the values from any "application/x-fetchdigits" dialog. As we changed the state to "enterpin" above, this is where we code in the logic allowing us to access the value when the dialog has exited:


    <transition state="enterpin" event="dialog.exit">
      <log expr="'*** PIN = [' + event$.values.digits + ']'"/>
    </transition>


This seems straightforward enough -- a "dialog.exit" event is captured, and our "pin" variable is contained within the event Object. Since we went to all the trouble of gathering user input, we should clearly do something with it. Let's extend our transition a bit, and move on.


    <transition state="enterpin" event="dialog.exit">
      <log expr="'PIN = [' + event$.values.digits + ']'"/>
      <if cond="'1234' != event$.values.digits">
        <exit/>
      <else/>
        <assign name="pin" expr="event$.values.digits"/>
      </if>
       
      <assign name="state0" expr="'calling'"/>         
      <dialogstart src="'holdingPattern.vxml'" type="'application/xml+vxml'" dialogid="holdMusicDlg"/>           
      <createcall dest="'4072223333'" connectionid="callid_out"/>
    </transition> 


So we just introduced quite a bit of complexity, but we can break it down. Our first conditional block will simply exit the session if the user input doesn't match "1234". Let's assume, for the moment, the caller entered our super secret code -- we then assign the value to our previously declared "pin" variable, (so that it will not be lost), change the state, start a "hold music" VoiceXML dialog, and actually make an outbound call (to my mom's house). Astute observers will take note of the fact that we reference the "dialogid" attribute, and that we aren't just changing the state just for kicks: We will be launching other dialogs within the CCXML, and specifying a particular state for each dialog is a sure-fire way to ensure that we are launching the right dialog at the right time.

Using hold music creates a nice delay for the state machine to process the outbound call while not leaving the inbound call in limbo. While the caller is listening to annoying, souless pop music from the early 90's, let's explore what might happen with the outbound call.


Step 4: outbound call possibilities

Seeing as my mom often doesn't answer her phone, espcially when the game shows are on, we should make sure we have a provision for this likely possibility:


    <transition state="calling" event="connection.failed">
      <assign name="state0" expr="'callfailed'"/>
      <dialogterminate dialogid="holdMusicDlg"/>
    </transition>

    <transition state="callfailed" event="dialog.exit">
      <assign name="state0" expr="'playingCallFailed'"/>
      <dialogstart src="'callFailure.vxml'" type="'application/xml+vxml'"/>                 
    </transition>

    <transition state="playingCallFailed" event="dialog.exit">
      <disconnect/>
    </transition>


So here we see a three step process (bearing in mind, of course, that this will all occur asynchronously). First, we trap the "connection.failed" event and terminate our cheesy "hold music" dialog. Second, we pounce on the "dialog.exit" event, (again, referencing the previously defined "dialogid" value so that the CCXML 1.0 interpreter knows which dialog to kill), and start a brand new VoiceXML dialog that tells our inbound caller the outbound call to my mom failed. Lastly, after the message has been delivered, we trap the (new) "dialog.exit" event and fire off a <disconnect> event. Now that we have taken care of the worst case scenario, let's now wax optimistic, and add some logic to handle events in the event that our efforts actually succeed, and the call is answered.




    <transition state="calling" event="connection.connected">
      <var name="callid_out" expr="event$.callid"/>
      <assign name="state0" expr="'callAccepted'"/>
      <dialogstart src="'myNewCall.vxml'" namelist="pin" type="'application/xml+vxml'"/>
    </transition>

    <transition state="callAccepted" event="dialog.exit">
      <if cond="event$.connectionid == callid_in">
        <exit/>
      <else/>
        <assign name="state0" expr="'beforeBridging'"/>
        <dialogterminate dialogid="holdMusicDlg"/>
      </if>
    </transition>

    <transition state="beforeBridging" event="dialog.exit">
      <assign name="state0" expr="'bridged'"/>
      <join id1="callid_in" id2="callid_out"/>
    </transition>


Like our state machine branch to handle a call failure situation, our call success scenario has three steps. The first saves off the Call ID of the outbound leg (remember, we already saved off the inbound Call ID) and runs a VoiceXML dialog, where we pass in our "pin" as a querystring variable. Our hold music dialog is going to be pretty basic, but we are throwing in a some new stuff as well: Using older implementations of CCXML, you'd have to pull the 'pin' value from the querystring to import into the VXML context via some dynamic markup. In the Prophecy CCXML 1.0 implementation, we can access one of the cooler features of the Connection Object that allows us to grab this parameter on the client side, thereby allowing us to keep our application 100% static:


  <var name="pinCode" expr="session.connection.ccxml.values.pin"/>



All that this little dialog simply does is simply reads the "pin" information to person who answered the phone as a type of "whisper mode" operation. Slick, eh?

Our second transition has a quick check to ensure that our "hold music" dialog did not end prior to our "new call" dialog. Assuming we are still on track, we now kill the "hold music" dialog. This tosses another "dialog.exit" event, and our long road to conferencing call legs together finally comes to fruition. With <join>, we link our two saved Call IDs together, and the beauty of human-to-human communication is achieved.


Step 5: the complete script

Whew. Possibly pushing the cube on tutorial complexity, I hope you kept up. Here is the complete CCXML script, with links to download all the CCXML 1.0 code, and associated VoiceXML 2.1 dialogs:


<?xml version="1.0" encoding="UTF-8"?>

<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

  <var name="state0" expr="'init'"/>
  <var name="callid_in"/>
  <var name="callid_out"/>
  <var name="pin"/>
  <var name="holdMusicDlg"/>

  <eventprocessor statevariable="state0">

    <transition state="init" event="connection.alerting">
      <accept/>     
    </transition>

    <transition state="init" event="connection.connected">
      <assign name="callid_in" expr="event$.connectionid"/>
      <assign name="state0" expr="'enterpin'"/>
      <dialogstart src="'null://?termdigits=#&amp;text=enter your conference pin code now'"
                  type="'application/x-fetchdigits'"/>
    </transition>

    <transition state="enterpin" event="dialog.exit">
      <log expr="'PIN = [' + event$.values.digits + ']'"/>
      <if cond="'1234' != event$.values.digits">
        <exit/>
      <else/>
        <assign name="pin" expr="event$.values.digits"/>
      </if>
       
      <assign name="state0" expr="'calling'"/>         
      <dialogstart src="'holdingPattern.vxml'" type="'application/xml+vxml'" namelist="pin" dialogid="holdMusicDlg"/>           
      <createcall dest="'4072223333'" connectionid="callid_out"/>
    </transition>   
   
    <transition state="calling" event="connection.failed">
      <assign name="state0" expr="'callfailed'"/>
      <dialogterminate dialogid="holdMusicDlg"/>
    </transition>

    <transition state="callfailed" event="dialog.exit">
      <assign name="state0" expr="'playingCallFailed'"/>
      <dialogstart src="'callFailure.vxml'" type="'application/xml+vxml'"/>                 
    </transition>

    <transition state="playingCallFailed" event="dialog.exit">
      <disconnect/>
    </transition>
 
    <transition state="calling" event="connection.connected">
      <var name="callid_out" expr="event$.callid"/>
      <assign name="state0" expr="'callAccepted'"/>
      <dialogstart src="'myNewCall.vxml'" namelist="pin" type="'application/xml+vxml'"/>
    </transition>

    <transition state="callAccepted" event="dialog.exit">
      <if cond="event$.connectionid == callid_in">
        <exit/>
      <else/>
        <assign name="state0" expr="'beforeBridging'"/>
        <dialogterminate dialogid="holdMusicDlg"/>
      </if>
    </transition>

    <transition state="beforeBridging" event="dialog.exit">
      <assign name="state0" expr="'bridged'"/>
      <join id1="callid_in" id2="callid_out"/>
    </transition>   

    <transition event="error.conference.join">
    <log expr="'*** ERROR DURING JOIN ***'"/>
    <exit/>
    </transition>

    <transition event="error.*">
      <log expr="'an error has occured (' + event$.reason + ')'"/>
              <voxeo:sendemail to="'yourEmail@there.com'"
                        from="'myApp@here.com'"
                        type="'debug'"
                        body=" 'generic error detected ! ' "/>
      <exit/>
    </transition>
  </eventprocessor>   
</ccxml>



  Download the CCXML source code!


What we covered:



  ANNOTATIONS: EXISTING POSTS
0 posts - click the button below to add a note to this page

login
  tutorial Advanced VoiceXML Dialogs  |  TOC  |  tutorial Outbound CCXML Token Dialing  

© 2008 Voxeo Corporation  |  Voxeo IVR  |  VoiceXML & CCXML IVR Developer Site