CCXML 1.0-W3C Development GuideHome  |  Frameset Home

  tutorial Hello World  |  TOC  |  tutorial Advanced Event Handling  

Tutorial: Basic Event Handling

This lesson will step you through the process of handling events within Prophecy CCXML 1.0. If you have not already completed Lesson 1, we suggest running our Hello World example first before tackling this tutorial.

In this lesson, we will:

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.


Step 1: creating our initial CCXML 1.0 structure

From our previous episode, we now recognize the following structure as a normal starting point:

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


Step 2: handling our 'alerting' events


For most real-world CCXML 1.0 applications, we will want to employ some event handling logic so that we can cleanly address asynchonous telephony events as they happen without having our callers encounter an error. For this purpose, we introduce to you the <eventprocessor> element, which is used to encapsulate a bundle of code pieces that are triggered on a certain event, state, or conditional expression. For the purposes of this tutorial, we only care about events.

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

</ccxml>


The order and "definition" of elements within an <eventprocessor> block is critical -- CCXML 1.0 will search sequentially through your document and trigger on the first match (even if there is a subsequent match that would be more accurate).

<transition> elements contain the code for specific events you are looking to trigger. Our first <transition> takes care of virtually every event signaling an incoming call with the "connection.alerting" value specified. This event value is actually the precursor to the phone actually being answered, and as such, we can perform some operations programmatically when we have an incoming call request. Since many of your CCXML 1.0 applications will actually want to, you know, answer the phone, let's see how this works in practice below:

<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0">
  <eventprocessor>
    <transition event="connection.alerting">
      <log expr="'*** The calledID is ' + event$.connection.local"/>
    </transition>

  </eventprocessor>
</ccxml>


For the above step in our development cycle, we have also employed the <log> element to output the callerID value, which in turn accesses the ".local" property of the connection object that is created when we execute any valid CCXML document. Note that the "event" attribute is not an ECMAScript expression, but a static value. As you can see, the <transition> element is another container -- this means that we can execute any number of elements once we have matched an event. So far, we are only logging the Caller ID, but we will be accessing more of these connection objects later in our tutorials. Our next step in the development process involves adding some conditional logic that will allow us to accept calls from certain callerIDs, and send other folks packing: This is a good way to allow or disallow callers from accessing any given application:

<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0">
  <eventprocessor>
    <transition event="connection.alerting">
      <log expr="'*** The calledID is ' + event$.connection.local"/>

      <if cond="event$.connection.local == '8315551234'">
        <reject/>
      <elseif cond="event$.connection.remote == '8315557890'"/>
        <reject/>
      <else/>
        <accept/>
      </if>


    </transition>
  </eventprocessor>
</ccxml>


Here we see several advanced items: the complete <if/elseif/else> conditional structure is present, as well as the option to "accept" or "reject" the call (i.e., answer or not answer). Note the subtle difference between the first <reject> and second: you are able to specify not only the callerID to reject or accept, but also the called id value. If the event came from the call leg itself, no specifier is needed -- the first <reject> works for this reason. The <accept> element fires an asynchronous event (as do most CCXML 1.0 triggers), and will communicate to us later the result. If you are uncomfortable with the concept of asynchronous events, please poke the fat guy coding C++ in the cube next to you for an explanation.

Step 3: handling our 'answer' events


Answering an inbound phone call is a two-step process, but still easy enough that anyone could understand. As we have already told the CCXML 1.0 document to asynchronously fire an "accept" event, we now need a handler for that event. Appropritately enough since the call is answered, we will now make use of the "connection.connected" event:


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0">
  <eventprocessor>
    <transition event="connection.alerting">
      <log expr="'*** The calledID is ' + event$.connection.local"/>
      <log expr="'*** The caller ID is ' + event$.connection.remote"/>

      <if cond="event$.connection.local == '4072223333'">
        <reject/>
      <elseif cond="event$.connection.remote == '4071112222'"/>
        <reject/>
      <else/>
        <accept/>
      </if>
    </transition>

    <transition event="connection.connected">
      <log expr="'*** Call was answered ***'"/>
      <disconnect/>
    </transition>

  </eventprocessor>
</ccxml>


Our handler for finally answering the incoming call is very straightforward, yes? We answer the call, log a debug message, and then immediately disconnect. Normal applications would hopefully do something snazzy before disconnecting the caller, but all that can be done later.

Step 4: error handling and call cleanup

Just to be safe, our application needs two more things before we can consider it complete: one more event handler, this time capturing an "invalid call" situation, and an event handler for the "disconnect" event. The former will occur whenever an error, or a rejection has been tossed by CCXML 1.0 platform. This will ensure that we properly clean up our session (provided that the session was itself triggered by an inbound call). You'll also note that we have added the Voxeo-proprietary <voxeo:sendemail tag into the mix; also check out the fact that we have specified the voxeo 'xmlns' attribute in the initial ccxml declaration. This is important, as otherwise, we will get a nasty parsing error.. Assuming that we fill in all the blanks so that we have a valid email address, we will then get an email notification whenever the 'call.invalid' event is executed. Tres` cool, eh? Why we need a handler for the "disconnect" event might be confusing to some folks: The call is already disconnected, so what's the big deal? The big deal is this: Just because the call is disconnected doesn't mean that the session is no longer active. Far from it. Good coding practices dictate that we programmatically kill any CCXML 1.0 sessions that are active before we consider the job done, otherwise, we can end up with "zombie" sessions that can run rampant on the network, or end up spiking the CPU on a local installation of the Prophecy software, which isn't really considered "best practices". As such, we need to add a handler for the "connection.disconnected" event, and then programmatically <exit> from the application:


<?xml version="1.0" encoding="UTF-8"?>
<!-- NOTE THAT WE *MUST* DECLARE THE xmlns ATTRIBUTE -->
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">


  <eventprocessor>
    <transition event="connection.alerting">

    <log expr="'*** The calledID is ' + event$.connection.local"/>
    <log expr="'*** The caller ID is ' + event$.connection.remote"/>

      <if cond="event$.connection.local == '4072223333'">
        <reject/>
      <elseif cond="event$.connection.remote == '4071112222'"/>
        <reject/>
      <else/>
        <accept/>
      </if>

    </transition>

    <transition event="connection.connected">
      <log expr="'*** Call was accepted ***'"/>
      <disconnect/>
    </transition>

    <transition event="connection.disconnected">
      <log expr="'*** Call was disconnected ***'"/>
      <exit/>
    </transition>

   
    <transition event="connection.failed">
      <voxeo:sendemail to="'yourEmail@there.com'"
                        from="'myApp@here.com'"
                        type="'debug'"
                        body="'We had an error! \n Time to panic! \n
                            Flee the cities, abandon all hope! \n '"/>
      <exit/>
    </transition>


  </eventprocessor>

  <log expr="'*** Application is starting ***'"/>

</ccxml>


As a final note, the <log> element at the very end of the application is outside the scope of our <eventprocessor>. CCXML will initially execute all code in the application not contained in an eventprocessor (thus, we would always see our "Application is starting..." message). Why you ask? Because events are fired asynchronously, code within an <eventprocessor> block will not be executed until that specific event occurs; however, other CCXML elements are handled, and executed, sequentially. As we move forward, grasping this difference will become easier. For clarity, it is usually best to include your <eventprocessor> block at the end of the document, but it is not a requirement (as shown above).

  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 Hello World  |  TOC  |  tutorial Advanced Event Handling  

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