CCXML 1.0-W3C Development Guide Home  |  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 dialogs and describe how to connect two call legs in an application.

Note: This tutorial is considerably more complicated than the previous tutorials and is therefore not recommended as a starting point for leaning CCXML.

In this tutorial, you will:
Note: This tutorial requires that you have outbound dialing privileges enabled on the Voxeo network and the provisioning of a alphanumeric token string for your application. Create a support ticket to request the upgrade to your Evolution account and your application. For more information, see the Voxeo Support Guide.

Step 1: Creating an initial CCXML structure

From the previous tutorials, create the following CCXML structure as a starting point:

<?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="pinCode"/>
  <var name="holdMusicDlg"/>

</ccxml>

The variables in the following list describe the application variables:

Step 2: Setting up basic handlers

From earlier tutorials, you understand state machines and event handlers. In this step, we will define the event handlers, including error handling.

<?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="pinCode"/>
  <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=" 'A generic error was detected ! ' "/>
      <exit/>
    </transition>


A few items to note so far:

Step 3: Introducing VoiceXML dialogs

While CCXML is designed as a powerful call control structure, a telephone application is needed to play audio files and use voice recognition inputs to gather information. Using a VoiceXML application, we will ask for an access code, or pin, from the inbound caller, and then use the Voxeo application/x-fetchdigits dialog extension within the  connection.connected transition when the call is accepted as shown in the following code example.

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

In the preceding code example, the application state is changed to enterpin and the dialog contained in dialog extension is started. The basic dialog collects an access code by using voice recognition to determine if the inbound caller is permitted to join the call.

The VoiceXML application dialog ends when the inbound caller enters the access code. The access code is the value of the of the event$.values.digits extension to allow you to access the values from any "application/x-fetchdigits" dialog. After the application state is changed to enterpin in the preceding code example, you can access the value when the dialog closes as shown in the following code example.

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

Next, the dialog.exit event is captured and the PIN variable is contained within the event Object. We will use the enterpin variable in the following code example.

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

In the preceding code example, the first conditional block will disconnect the inbound caller if the access code is not 1 2 3 4. If the correct access code is entered, the value is assigned to pinCode variable that you declared in Step 1.
Next, the holdMusicDlg is started, and the application state is updated to calling. By specifying a different CCXML application state for each dialog and using the dialogid attribute, you can ensure the correct dialog is started at the correct time.

The hold music plays while the state machine is processing the outbound call. While the inbound caller is listening to music, the CCXML application is busy trying to connect the call outbound call portion to join the two calls.

In the next section, you need to handle the possibilities that the outbound call can run into.

Step 4: Handing the outbound call possibilities

If the outbound connection fails, you must have code to capture and handle the call failure as shown in the following code example.

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

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

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

Handling a call failure is a three-step process. First, capture the connection.failed event, update the application state to callfailed, and then terminate the dialog playing the music for the inbound caller. Next, with the playingCallFailed state, you can initiate a dialog.exit event to end the correct dialog, and then begin the VoiceXML call failure dialog to tell the inbound caller that the outbound call failed. After the call failure dialog is played, you change the CCXML state and exit the dialog, and follow up with an exit event.

If the outbound call is successful, you need to handle the connection events as shown in the following code example.

<transition state="calling" event="connection.connected">
    <var name="callid_out" expr="event$.callid"/>
    <assign name="state0" expr="'playDialog'"/>
    <send name="'playNewCallerDialog'" target="session.id"/>
</transition>

<transition state="playDialog" event="playNewCallerDialog">
    <assign name="state0" expr="'dialogActive'"/>
    <dialogstart src="'myNewCall.xml'" namelist="pinCode" type="'application/voicexml+xml'" connectionid="callid_out"/>
</transition>

<transition state="dialogActive" event="dialog.exit">
    <if cond="event$.connectionid == callid_in">
        <exit/>
        <else/>
            <dialogterminate dialogid="holdMusicDlg"/>
            <assign name="state0" expr="'beforeBridging'"/>
            <send name="'joining'" target="session.id"/>
        </if>
</transition>

<transition state="beforeBridging" event="dialog.exit">
        <assign name="state0" expr="'bridged'"/>
        <send name="'user.joinLegs'" target="session.id" targettype="'ccxml'" delay="'150ms'"/>
</transition>

<transition event="user.joinLegs">
        <join id1="callid_in" id2="callid_out"/>
</transition>

Just like a call failure, a call success is handled in three parts. First, the call ID out the outbound call is captured in the callid_out variable, the application state is updated to calling, and the event named playNewcallerDialog is passed to the application.

The pinCode variable is passed to the VoiceXML application and used in the myNewCall.xml dialog to read the access code to the person who answered the outbound call. The CCXML state is updated to dialogActive.

In the next transition, there is a check to ensure that the music dialog did not end prior to the start of the call join. If the "hold music" is already terminated, it means that the inbound caller either hung up or was disconnected. In this case, the join is terminated.

If the check confirms the inbound call is still in progress, the "hold music" dialog is terminated and a dialog.exit event is triggered.

Finally, with the <join>, you can link the inbound caller ID to the outbound call ID.

Step 5: The complete script

The following code example is the complete CCXML code to join a call.

<?xml version="1.0" encoding="UTF-8"?>
<ccxml xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml" version="1.0">
  <var name="state0" expr="'init'"/>
  <var name="callid_in"/>
  <var name="callid_out"/>
  <var name="pinCode"/>
  <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 connectionid="callid_in" src="'null://?termdigits=%23&amp;text=Please enter your access code and then press the pound key.'" 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="pinCode" expr="event$.values.digits"/>
        <dialogstart src="'holdingPattern.xml'" type="'application/voicexml+xml'" connectionid="callid_in" dialogid="holdMusicDlg"/>
    </if>
      <assign name="state0" expr="'calling'"/>
      <createcall dest="'14072223333'" callerid="'4075551212'" connectionid="callid_out"/>
    </transition>

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

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

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

    <transition state="calling" event="connection.connected">
      <var name="callid_out" expr="event$.callid"/>
      <assign name="state0" expr="'playDialog'"/>
      <send name="'playNewCallerDialog'" target="session.id"/>
    </transition>

    <transition state="playDialog" event="playNewCallerDialog">
      <assign name="state0" expr="'dialogActive'"/>
      <dialogstart src="'myNewCall.xml'" namelist="pinCode" type="'application/voicexml+xml'" connectionid="callid_out"/>
    </transition>

    <transition state="dialogActive" event="dialog.exit">
    <if cond="event$.connectionid == callid_in">
      <exit/>
    <else/>
      <dialogterminate dialogid="holdMusicDlg"/>
      <assign name="state0" expr="'beforeBridging'"/>
      <send name="'joining'" target="session.id"/>
    </if>
    </transition>

    <transition state="beforeBridging" event="dialog.exit">
      <assign name="state0" expr="'bridged'"/>
      <send name="'user.joinLegs'" target="session.id" targettype="'ccxml'" delay="'150ms'"/>
    </transition>

    <transition event="user.joinLegs">
      <join id1="callid_in" id2="callid_out"/>
    </transition>

    <transition state="bridged" event="joining">
      <log expr="'******* JOINED'"/>
    </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=" 'A generic error was detected ! ' "/>
      <exit/>
    </transition>
  </eventprocessor>
</ccxml>


  Download the CCXML source code!

What was covered:



  ANNOTATIONS: EXISTING POSTS
romilly1
2/2/2010 9:55 PM (EST)
Am I wrong or is there no <exit/> being executed after a call fails (i.e. after 'playingCallFailed' state)?
voxeojeremyr
2/2/2010 11:02 PM (EST)
Hello,

Yes you are correct.  Actually there are a couple of different errors in the code.  Where we have the <disconnect> it should be <exit>.  Also for playing the
[code]
<dialogstart src="'callFailure.vxml'" type="'application/xml+vxml'"/>
[/code]
we need to specify the connectionid of the call to play the VXML dialog to. 

So it should be:
[code]
<dialogstart src="'callFailure.vxml'" type="'application/xml+vxml'" connectionid="callid_in"/>
[/code]

I have made the fixes to the code and will be submitting it to our documentation team so that they can update the text and also the downloadable code.

Thank you for pointing that out.

Regards,
Jeremy Richmond
Voxeo Support
romilly1
2/3/2010 1:30 AM (EST)
There're some more bugs in the downloadable code that are not on the guide. I think the zip file is not up to date.

e.g. there are other <dialogstart>'s without a 'connectionid'.
voxeoJeffK
2/3/2010 1:56 AM (EST)
Hello,

Thank you for the feedback. We've made edits to the documentation, but the build has not been pushed live quite yet.

Regards,
Jeff Kustermann
Voxeo Support
ggtbx
4/6/2010 2:45 PM (EDT)
Can you please give me correct code ?

in the above given code : callid_out is never initialized

and events donot have anything called callid.

jdyer
4/6/2010 4:19 PM (EDT)
Hello,

  You are correct, there actually a few type-o's in the above tutorial, thanks for point that out!  I have gone ahead and corrected the above, as well as the attached source files so please give it another try.  I also went ahead and deployed the entire application to your hosted account, so you should be all set!. I do hope this helps, and if there are any other questions please let us know!

Regards,

John Dyer
Customer Engineer
Voxeo Support
petertv2000
8/16/2010 6:44 PM (EDT)
In the  "dialogstart connectionid="callid_in" src="'null://?termdigits=#&amp;text=enter your conference pin code now'" type="'application/x-fetchdigits'"/>

What am I supposed to modify  "src="'null://"?
Thanks,
jdyer
8/16/2010 8:37 PM (EDT)
Hello Peter,

There is no change needed to use our custom dialog extension in CCXML, you can just 'plug and play' this sample.  I do hope this information is helpful, and if there are any other questions please let us know; Our support team is always standing by to offer any help our developers may require!

Regards,

John Dyer
Customer Engineer
Voxeo Support
czhang86
1/27/2011 6:45 PM (EST)
nice choice of music but.... isn't it copyright infringement ??

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

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