CCXML Voxeo 1.0 Development GuideHome  |  Frameset Home

  tutorial Basic Event Handling  |  TOC  |  Intro to Error Handling  
This documentation is for CCXML 1.0-Voxeo, which has been superceded by CCXML 1.0-W3C. The CCXML-Voxeo platform is not being updated any longer. The CCXML 1.0-W3C version, however, has many new features and is actively being enhanced. If you're writing a new CCXML application, you should use CCXML 1.0-W3C. Click here for the CCXML 1.0-W3C documentation.

Tutorial: Advanced Event Handling

This Lesson will delve deeper into the "state machine" nature of CCXML. If you have not mastered Lesson 2, it is highly recommend you do so before beginning this Lesson.

In this Lesson, we will:

Step 1: creating our initial CCXML structure

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


<?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">
</ccxml>


Step 2: State machines

One of the over-arching concepts in CCXML is the usage of state machines: a certain event changes the current state of an application. A "state variable" is identical syntactically to a "common variable," but the usage characterizes its special nature. While an application can have multiple state variables, each <eventhandler> can only be scoped to a single state variable. Let's take a look:


<?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">
  <var name="app_state" expr="'initial'"/>
  <eventhandler statevariable="app_state">
  </eventhandler>

</ccxml>


Each event capturable by our <eventhandler> will use "app_state" for the state variable. This does not mean that we must use state information as part of our specific event check; instead, it forces us to use the specified state variable if we choose to check for state.

Step 2: answering a call using state

Now that we have a rock-solid foundation to our struktur, we will again answer an incoming phone call:


  <eventhandler statevariable="app_state">
    <transition state="'initial'" event="connection.CONNECTION_ALERTING" name="evt">
      <assign name="app_state" expr="'accepting'"/>
      <accept/>
      <var name="in_callid" expr="evt.callid"/>
     
    </transition> 

    <transition state="'accepting'" event="connection.CONNECTION_CONNECTED">
      <assign name="app_state" expr="'incall_0'"/>
      <send event="'continue'" target="session.id" delay="'3000'"/>

    </transition>
  </eventhandler>


Here we see that a <transition> tag handles more than one conditional requirement: for our first example, the state (as defined within the "app_state" variable) must be equal to "initial" as well as the raw event itself being "connection.CONNECTION_ALERTING". If either of these is not the case, then there is no match. Case in point: we are changing the value (via the <assign> tag) to a new value -- should our state variable never be reset to "initial", then this <transition> will never be visited again. We are also storing the value of the call leg's ID. This will become important later in our application.

Our second transition requires that the state information be set to "accepting". Don't be thrown off by the idea that we just set the value of the state variable to "accepting" -- remember the wisdom taught by your tubby, C++ coding neighbor regarding asynchronous events; nevertheless, the inbound call is accepted, the state information is changed again, and now we <send> an event.

With <send> we are able to post an event to any session we have the identifier of. In this example, we send one simple event to ourselves. Additionally, we will delay the sending for three seconds (yes, the delay value is expressed in milliseconds), allowing us to implement timer functionality or just pause our application briefly.

Step 3: more events

Up until now, we have only tossed and caught CCXML defined events; however, our <send> element requires us to catch a user-defined event.


  <eventhandler statevariable="app_state">
    <transition state="'incall_0'" event="user.continue">
      <assign name="app_state" expr="'incall_1'"/>
      <send event="'continue'" target="session.id" delay="'1000'"/>
    </transition>

    <transition state="'incall_1'" event="user.continue">
      <disconnect callid="in_callid"/>
      <assign name="app_state" expr="'disconnecting'"/>
    </transition>
  </eventhandler>


The most obvious difference between these transitions and our earlier examples is the event attribute itself. Notice that we have to list both the event name ("continue") as well as an object prefix called "user.". This prevents you from creating artificial system events (this is a Voxeo specific addition to CCXML -- remember, we know how you think, even if the W3C doesn't, so don't even try it).

Examining our second transition from above, we can see that after just four seconds of "activity," we choose to disconnect the call. That's right, our application is advanced enough to answer the phone and do absolutely nothing, in a substantially structured sense, before hanging up. Notice that we have to specify a "callid" this time around (unlike Lesson 2). User events do not carry with them any information relating to call ID, so we have to supply the data (remember when we created a variable expressly for this purpose?

Step 4: handling multiple types of disconnects

Our last transition fired the <disconnect> event, but what if we want to detect an earlier event (say, for example, your impatient little sister called and the four seconds of silence overwhelmed her)? Clearly, you might want to know when this situation occurs...


  <eventhandler statevariable="app_state">
    <transition event="call.CALL_INVALID"
                cond="('incall_0' == app_state) || ('incall_1' == app_state)">
      <log expr="'premature disconnection detected in state [' + app_state + ']'"/>
      <exit/>
    </transition>

    <transition event="call.CALL_INVALID">
      <log expr="'not premature...  wise, learned, mature disconnection'"/>
      <exit/>
    </transition>
 
    <transition event="call.*">
      <log expr="'unhandled call.* event detected'"/>
    </transition> 

  </eventhandler>


First of all, it is entirely possible this tutorial will never end. Just wanted to get that out there. Secondly, we now see that in addition to specifying "state" and "event" criteria, a transition can also take explicit conditional statements. Our first transition can now spit out a debug line containing the state we were in when your little sister hung up the phone.

Our last transition uses the filter feature of CCXML, where whole event groups can be caught by one handler. In this case, we process every "call" message. As stated in our last tutorial, the order of the transitions is critical -- if we put this code piece at the top of the <eventhandler>, neither of our "call.CALL_INVALID" would be executed!

Step 5: the complete script

Our lesson on state machines and structure now comes to a close. Here is the complete script, for your viewing pleasure.


<?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">
  <var name="app_state" expr="'initial'"/>
  <eventhandler statevariable="app_state">

    <transition state="'initial'" event="connection.CONNECTION_ALERTING" name="evt">
      <assign name="app_state" expr="'accepting'"/>
      <accept/>
      <var name="in_callid" expr="evt.callid"/>     
    </transition> 

    <transition state="'accepting'" event="connection.CONNECTION_CONNECTED">
      <assign name="app_state" expr="'incall_0'"/>
      <send event="'continue'" target="session.id" delay="'3000'"/>
    </transition> 
 
    <transition state="'incall_0'" event="user.continue">
      <assign name="app_state" expr="'incall_1'"/>
      <send event="'continue'" target="session.id" delay="'1000'"/>
    </transition>

    <transition state="'incall_1'" event="user.continue">
      <disconnect callid="in_callid"/>
      <assign name="app_state" expr="'disconnecting'"/>
    </transition>

    <transition event="call.CALL_INVALID"
                cond="('incall_0' == app_state) || ('incall_1' == app_state)">
      <log expr="'premature disconnection detected in state [' + app_state + ']'"/>
        <voxeo:sendemail to="'yourEmail@there.com'"
                        from="'myApp@here.com'"
                        type="'debug'"
                        body=" 'premature disconnection detected!' "/>
      <exit/>
    </transition>

    <transition event="call.CALL_INVALID">
      <log expr="'not premature...  wise, learned, mature disconnection'"/>
      <exit/>
    </transition>
 
    <transition event="call.*">
      <log expr="'unhandled call.* event detected'"/>
    <voxeo:sendemail to="'yourEmail@there.com'"
                        from="'myApp@here.com'"
                        type="'debug'"
                        body="'unhandled call event detected!'"/>
    </transition> 
  </eventhandler>
</ccxml>


  Download the CCXML source code!

What we covered:




  ANNOTATIONS: EXISTING POSTS
jason.m.hanna
2/20/2007 12:26 PM (EST)
Hi,

Perhaps a correction for the documentation. In the last sentence before Step 5, the documentation states:

---
As stated in our last tutorial, the order of the transitions is critical -- if we put this code piece at the top of the <eventhandler>, nothing would work at all (we wouldn't get our four seconds of silence!).
---

I don't think that is 100% accurate. If you move the "call.*" transition event to the first position in the transition definitions, the "connection.*" events will still be handled properly, still giving you the 4 seconds of silence.

You won't, however, ever capture the "premature" or "mature" call.CALL_INVALID transition events and exit gracefully from the disconnect. The call.* filter will always catch it first.

Correct?

Regards,
-jmh
MattHenry
2/20/2007 2:47 PM (EST)


Correct you are, sir. I have fixed this in our internal doc build so that other folks won't be mislead by that statement.

Thanks again,

~Matthew Henry
kave
8/31/2007 9:53 PM (EDT)
hi there!

where could i get some information about "call leg id" or "callid"?


best,

kave



voxeojeremy
8/31/2007 10:13 PM (EDT)
Kave,


You may get some information on call legs at this doc post:

http://docs.voxeo.com/ccxml/1.0/introcalllegs_ccxml.htm

And you may wish to do the associated tutorial, at this link:

http://docs.voxeo.com/ccxml/1.0/t_6ccxml.htm


Regards,

Jeremy McCall
Voxeo Extreme Support
kave
9/1/2007 1:31 AM (EDT)
hi Jeremy!

thanks for the links, i'm still a little confused about callid, callerid and calledid...

when i want to disconnect an inbound call ,  would it be with callid right?,, callerid is more like a variable for user recognition, isn't it? also a question about calledid, is it possible that a  phone number that is connected by an application, everytime when i do an inbound call to this  phone number, could the calledid number be different...??? i mean...

example:

phone number: 1-800-123-456

Application numbers (Dnis)
1rst call --> DNIS =3212022485
2nd call --> DNIS = 3212024875...

or is the same DNIS always?

in other words, are callerid and callid  static variables? and is calledid or application number a dinamic variable?

thanks in avance,

best
kave
mikethompson
9/1/2007 10:51 PM (EDT)
Hi Kave,

I'm happy to clarify callerid, callid, and calledid for you.

When calling into an application, the called ID will always be the inbound phone number you are dialing.  This value shouldn't change.

The caller ID (ANI) is just that, the number of the phone trying to reach the application.  This will clearly be dynamic.

You are correct, callid is used to associate certain events with a call leg.  For example, you can use this to do a dialogstart for a specific call leg.

I hope I was able to provide some clarity for you, but do let me know if you have additional questions.

Best,
Mike Thompson
Voxeo Corporation
kave
9/2/2007 2:58 PM (EDT)
Hi Mike!


Thanks a lot Mike, like they song in Jamaica! "I can see clear now and very strong!!!" lol


Best Regards!
kave

login
  tutorial Basic Event Handling  |  TOC  |  Intro to Error Handling  

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