| CCXML 1.0-W3C Development Guide | Home | Frameset Home |
|
<send> element
<?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>
<?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="myState" expr="'init'"/>
<eventprocessor statevariable="myState">
<transition event="connection.alerting" state="init">
<log expr="'***** CONNECTION ALERTING *****'"/>
<accept/>
</transition>
<transition event="connection.connected" state="init">
<log expr="'***** CALL WAS ANSWERED *****'"/>
</transition>
<transition event="error.*">
<log expr="'an error has occured (' + event$.reason + ')'"/>
<log expr="'*** EVENT$.NAME = ' + event$.name"/>
<log expr="'*** EVENT$.REASON = ' + event$.reason"/>
<log expr="'*** EVENT$.TAGNAME = ' + event$.tagname"/>
<log expr="'*** EVENT$.EVENTID = ' + event$.eventid"/>
<log expr="'*** EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
<log expr="'*** EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
<voxeo:sendemail to="'youremail@somewhere.com'"
from="'myApp@here.com'"
type="'debug'"
body="'We had an error! \n Time to panic! \n
Flee the cities, abandon all hope!'"/>
<exit/>
</transition>
</eventprocessor>
</ccxml>
error.* handler, right? Wrong. Try copying this code by typing it out, and the laws of probability suggest that you will make a tpyo, (That last was on purpose. Get it?). When this happens, the <log> statements in this handler will show us in the real-time logger exactly where the goof occurred. And we are going to remember to change the 'sendmail' attribute to, you know, a valid email address at this point. That would be just swell.<dialogstart> element, of course. Later on in this tutorial, we may, (read: will), have need to access a user-defined 'dialogid' value, so let's declare this value at the start of our document. While we are at it, lets also apply what we learned about the connection object, and add the inevitable <log> statements to display some sweet, sweet connection object values in the debugger:
<?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="myState" expr="'init'"/>
<var name="myDialogID"/>
<eventprocessor statevariable="myState">
<transition event="connection.alerting" state="init">
<log expr="'***** CONNECTION ALERTING *****'"/>
<accept/>
</transition>
<transition event="connection.connected" state="init">
<log expr="'***** CALL WAS ANSWERED *****'"/>
<log expr="'***** EVENT$.CONNECTION.CONNECTIONID = ' + event$.connection.connectionid"/>
<log expr="'***** EVENT$.CONNECTION.PROTOCOL.NAME = ' + event$.connection.protocol.name"/>
<log expr="'***** EVENT$.CONNECTION.PROTOCOL.VERSION = ' + event$.connection.protocol.version"/>
<log expr="'***** EVENT$.CONNECTION.STATE = ' + event$.connection.state"/>
<log expr="'***** EVENT$.CONNECTION.LOCAL = ' + event$.connection.local"/>
<log expr="'***** EVENT$.CONNECTION.REMOTE = ' + event$.connection.remote"/>
<log expr="'***** EVENT$.CONNECTION.ORIGINATOR = ' + event$.connection.originator"/>
<dialogstart src="'myDialog.xml'" type="'application/voicexml+xml'" dialogid="myDialogID"/>
</transition>
<transition event="error.*">
<log expr="'an error has occured (' + event.reason + ')'"/>
<log expr="'*** EVENT$.NAME = ' + event$.name"/>
<log expr="'*** EVENT$.REASON = ' + event$.reason"/>
<log expr="'*** EVENT$.TAGNAME = ' + event$.tagname"/>
<log expr="'*** EVENT$.EVENTID = ' + event$.eventid"/>
<log expr="'*** EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
<log expr="'*** EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
<voxeo:sendemail to="'youremail@somewhere.com'"
from="'myApp@here.com'"
type="'debug'"
body="'We had an error! \n Time to panic! \n
Flee the cities, abandon all hope!'"/>
<exit/>
</transition>
</eventprocessor>
</ccxml>
<dialogstart> element is rather straightforward -- we hand it a source URL and a dialog name (the name is for CCXML event purposes only). That script is then executed by a VoiceXML server, running parallel to our CCXML session. Our beautiful, titanic, asynchronous state machine chugs along (la la la), waiting for a reply from the off-loaded dialog.<dialogstart> element:
<?xml version="1.0" encoding="UTF-8" ?>
<vxml version="2.0">
<meta name="maintainer" content="youremail@here.com"/>
<form id="dialogContainer">
<field name="F_1">
<grammar type="text/gsl">[(when its a jar) (what kind of a question is that)]</grammar>
<prompt>
<audio src="question.wav">
Greetings, and welcome to our humble Voice X M L dialog.
The burning question of the day is as follows:
When is a door not a door?
</audio>
</prompt>
<filled>
<log expr="' ***** CALLER SAID ' + F_1 + ' *****'"/>
<exit namelist="F_1"/>
</filled>
</field>
</form>
</vxml>
<field> gathers some caller input to a really simple riddle, and then passes this value back to the CCXML 1.0 layer via the <exit> command. Notice the "namelist" attribute: like all VoiceXML namelists, we can pass multiple variables back to our call control layer, and then access the value there if we desire. Which we do, thank you very much for asking.<send> to fire off an event to the CCXML interpreter, (or other external systems that make use of an Event I/O Processor). For the purposes of illustration, we will setup a call timer that will send a notification to the CCXML interpreter that kicks the user out of the dialog after 15 seconds. This event we will need to have a handler for it, so that we can direct the application to kill the dialog via the <dialogterminate> element, and bring the caller back into the CCXML context before we exit application execution. In order to do so, we will need to make a slight change to our state machine so that we can clearly define when the user is in the VoiceXML dialog, and when he is out of it entirely. To do so, we set the statevariable to 'dialogActive' right after the dialog starts. Let's now switch gears back to our fledgling CCXML 1.0 script, and take a gander at how this would 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="myState" expr="'init'"/>
<var name="myDialogID"/>
<eventprocessor statevariable="myState">
<transition event="connection.alerting" state="init">
<log expr="'***** CONNECTION ALERTING *****'"/>
<accept/>
</transition>
<transition event="connection.connected" state="init">
<log expr="'***** CALL WAS ANSWERED *****'"/>
<log expr="'***** EVENT$.CONNECTION.CONNECTIONID = ' + event$.connection.connectionid"/>
<log expr="'***** EVENT$.CONNECTION.PROTOCOL.NAME = ' + event$.connection.protocol.name"/>
<log expr="'***** EVENT$.CONNECTION.PROTOCOL.VERSION = ' + event$.connection.protocol.version"/>
<log expr="'***** EVENT$.CONNECTION.STATE = ' + event$.connection.state"/>
<log expr="'***** EVENT$.CONNECTION.LOCAL = ' + event$.connection.local"/>
<log expr="'***** EVENT$.CONNECTION.REMOTE = ' + event$.connection.remote"/>
<log expr="'***** EVENT$.CONNECTION.ORIGINATOR = ' + event$.connection.originator"/>
<dialogstart src="'myDialog.xml'" type="'application/voicexml+xml'" dialogid="myDialogID"/>
<assign name="myState" expr="'dialogActive'" />
<send name="'timeout'" target="session.id" delay="'15s'"/>
</transition>
<transition event="timeout" state="dialogActive">
<log expr="'***** TIMEOUT RECEIVED, NOW TERMINATING THE DIALOG *****'"/>
<dialogterminate dialogid="myDialogID" immediate="false"/>
</transition>
<transition event="send.successful" state="dialogActive">
<log expr="'***** SEND IS SUCCESSFUL *****'"/>
</transition>
<transition event="error.*">
<log expr="'an error has occured (' + event$.reason + ')'"/>
<log expr="'*** EVENT$.NAME = ' + event$.name"/>
<log expr="'*** EVENT$.REASON = ' + event$.reason"/>
<log expr="'*** EVENT$.TAGNAME = ' + event$.tagname"/>
<log expr="'*** EVENT$.EVENTID = ' + event$.eventid"/>
<log expr="'*** EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
<log expr="'*** EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
<voxeo:sendemail to="'youremail@somewhere.com'"
from="'myApp@here.com'"
type="'debug'"
body="'We had an error! \n Time to panic! \n
Flee the cities, abandon all hope!'"/>
<exit/>
</transition>
</eventprocessor>
</ccxml>
<transition> in there for the purposes of logging exactly when the <send> command bubbles back up to the CCXML 1.0 interpreter. You'll notice that both of our newly added handlers specifies that the state must have a value of 'dialogACtive' in order for these to be executed, as we indicated previously. We finally make use of the 'dialogID' attribute within the <dialogterminate> element, as this tells the CCXML 1.0 interpreter exactly which dialog we want to shut down in this case.<log> statements, (this time for the dialog object properties), and see the user utterance from the VoiceXML session bubble back up to the CCXML 1.0 layer:
<?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="myDialogID"/>
<var name="myState" expr="'init'"/>
<eventprocessor statevariable="myState">
<transition event="connection.alerting" state="init">
<log expr="'***** CONNECTION ALERTING *****'"/>
<accept/>
</transition>
<transition event="connection.connected" state="init">
<log expr="'***** CALL WAS ANSWERED *****'"/>
<log expr="'***** EVENT$.CONNECTION.CONNECTIONID = ' + event$.connection.connectionid"/>
<log expr="'***** EVENT$.CONNECTION.PROTOCOL.NAME = ' + event$.connection.protocol.name"/>
<log expr="'***** EVENT$.CONNECTION.PROTOCOL.VERSION = ' + event$.connection.protocol.version"/>
<log expr="'***** EVENT$.CONNECTION.STATE = ' + event$.connection.state"/>
<log expr="'***** EVENT$.CONNECTION.LOCAL = ' + event$.connection.local"/>
<log expr="'***** EVENT$.CONNECTION.REMOTE = ' + event$.connection.remote"/>
<log expr="'***** EVENT$.CONNECTION.ORIGINATOR = ' + event$.connection.originator"/>
<dialogstart src="'myDialog.xml'" type="'application/voicexml+xml'" dialogid="myDialogID"/>
<assign name="myState" expr="'dialogActive'" />
<send name="'timeout'" target="session.id" delay="'15s'"/>
</transition>
<transition event="timeout" state="dialogActive">
<log expr="'***** TIMEOUT RECEIVED, NOW TERMINATING THE DIALOG *****'"/>
<dialogterminate dialogid="myDialogID" immediate="false"/>
</transition>
<transition event="send.successful" state="dialogActive">
<log expr="'***** SEND IS SUCCESSFUL *****'"/>
</transition>
<transition event="error.dialog.notstarted">
<log expr="'****** ERROR.DIALOGNOTSTARTED.NAME = ' + event$.name"/>
<log expr="'***** EVENT$.NAME = ' + event$.name"/>
<log expr="'***** EVENT$.DIALOGID = ' + event$.dialogid"/>
<log expr="'***** EVENT$.DIALOG = ' + event$.dialog"/>
<log expr="'***** EVENT$.CONFERENCEID = ' + event$.conferenceid"/>
<log expr="'***** EVENT$.CONNECTIONID = ' + event$.connectionid"/>
<log expr="'***** EVENT$.REASON = ' + event$.reason"/>
<log expr="'***** EVENT$.EVENTID = ' + event$.eventid"/>
<log expr="'***** EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
<log expr="'***** EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
<exit/>
</transition>
<transition event="error.send.targetunavailable">
<log expr="'***** SEND TARGET UNAVAILABLE *****'"/>
<exit/>
</transition>
<transition event="dialog.exit">
<log expr="'***** CALL EXITING *****'"/>
<log expr="'***** event$.VALUES.F_1 =' + event$.values.F_1"/>
<log expr="'***** EVENT$.NAME = ' + event$.name"/>
<log expr="'***** EVENT$.DIALOGID = ' + event$.dialogid"/>
<log expr="'***** EVENT$.CONFERENCEID = ' + event$.conferenceid"/>
<log expr="'***** EVENT$.CONNECTIONID = ' + event$.connectionid"/>
<log expr="'***** EVENT$.EVENTID = ' + event$.eventid"/>
<log expr="'***** EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
<log expr="'***** EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
<!-- DIALOG OBJECT PROPERTIES -->
<log expr="'***** EVENT$.DIALOG.DIALOGID = ' + event$.dialog.dialogid"/>
<log expr="'***** EVENT$.DIALOG.CONNECTIONID = ' + event$.dialog.connectionid"/>
<log expr="'***** EVENT$.DIALOG.CONFERENCEID = ' + event$.dialog.conferenceid"/>
<log expr="'***** EVENT$.DIALOG.TYPE = ' + event$.dialog.type"/>
<log expr="'***** EVENT$.DIALOG.SRC = ' + event$.dialog.src"/>
<log expr="'***** EVENT$.DIALOG.INPUT = ' + event$.dialog.input"/>
<log expr="'***** EVENT$.DIALOG.OUTPUTS = ' + event$.dialog.outputs"/>
<exit/>
</transition>
<transition event="error.*">
<log expr="'an error has occured (' + event$.reason + ')'"/>
<log expr="'*** EVENT$.NAME = ' + event$.name"/>
<log expr="'*** EVENT$.REASON = ' + event$.reason"/>
<log expr="'*** EVENT$.TAGNAME = ' + event$.tagname"/>
<log expr="'*** EVENT$.EVENTID = ' + event$.eventid"/>
<log expr="'*** EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
<log expr="'*** EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
<voxeo:sendemail to="'youremail@somewhere.com'"
from="'myApp@here.com'"
type="'debug'"
body="'We had an error! \n Time to panic! \n
Flee the cities, abandon all hope!'"/>
<exit/>
</transition>
</eventprocessor>
</ccxml>
<log> statements. The real 'guts' of our new additions to the code are the event handlers for 'error.send.targetunavailable', and 'error.dialog.notstarted': In both of these cases, we log the event, and skeedaddle. The other important additions are both kinds of 'dialog.exit' event handlers: you'll notice that one defines that the state must be set to 'dialogActive', which means that this will be kicked off when a 'timeout' event is thrown. The other 'dialog.exit' handler is going to be kicked off when we receive a valid utterance in the VoiceXML, and the <exit namelist> event transfers control back to the CCXML 1.0 context. Within here, we log some event object properties, and some dialog object properties. This is somewhat redundant in this case, as we have a bit of overlapping data. No matter. Looking closely, you'll also see the 'evt.values.F_1' <log> statement: This contains the value returned form the VoiceXML dialog, just like we promised. Since our <field> is christened "F_1" within the VoiceXML dialog, we then reference the value within the CCXML 1.0 as a property of the dialog object, (ie, 'event$.values.F_1'). If we are passing in more than one value back to the CCXML, we can log each one independently of one another, and reassign these values to local CCXML 1.0 variables, if we so desire.<log> statements are really handy, sometimes!<log> statements in your CCXML 1.0 applications<send> element| ANNOTATIONS: EXISTING POSTS |
steve1_rm
|
|
| Hello,
I am just wondering about the following statement: <filled> <log expr="' ***** CALLER SAID ' + F_1 + ' *****'"/> <exit namelist="F_1"/> </filled> Will this return the contents of field F_1? I am currently working on a project that will allow the user to input a 4 digit pin number for call forwarding. So my F_1 will return the 4 digits that will be used for call forward inside the ccxml. <dialogstart src="'myDialog.xml'" type="'application/voicexml+xml'" dialogid="myDialogID"/> The above line will call the dialog, but where will the F_1 field be returned to. Many thanks for any advice, Steve |
|
VoxeoDustin
|
|
| Hey Steve,
That will return the interpretation value of the field to CCXML. You can access in CCXML within your dialog.exit event like so: [code] <transition event="dialog.exit"> <assign name="myVar" expr="event$.values.F_1"/> <log expr="'****** DIALOG EXIT - F_1 = ' + myVar"/> </transition> [/code] Hope this helps. Thanks, Dustin |
|
weichen
|
|
| I am bit confused about the two dialog.exit transition.
When <transition event="dialog.exit"> happens, what is the value of myState variable? If the value is dialogActive, what's the difference between the two dialog.exit transitions? |
|
VoxeoDustin
|
|
| Hey Wei,
CCXML will execute in a top-down manner until it reaches a transition that matches. A dialog.exit without a state variable will match anytime that event is thrown, so the state variable's value is not evaluated. There is no major difference in this particular example, except that one dialog logs a few more things before exiting. It is simply exhibiting how we can handle an event differently depending on the value of our state variable. Let me know if this clarifies. Thanks, Dustin |
|
weichen
|
|
| Hi, Dustin,
When a dialog.exit event occurs while myState == dialogActive, CCXML should go to <transition event="dialog.exit" state="'dialogActive'"> since CCXML is running top-down. Is this right? However, my test shows CCXML goes to <transition event="dialog.exit"> while myState == dialogActive. ----- 00241 3059 00:29:38 AM matched transition (, dialog.exit, ) @ eventhandler (, myState) 00242 3059 00:29:38 AM log: ***** CALL EXITING ***** 00243 3059 00:29:38 AM log: mystate = dialogActive ...!!!!... 00244 3059 00:29:38 AM log: ***** event$.VALUES.F_1 =when its a jar 00245 3059 00:29:38 AM log: ***** EVENT$.NAME = dialog.exit ----- That's where I am confused. |
|
jdyer
|
|
| Hey Wei,
If this is your transition [code] <transition event="dialog.exit" state="'dialogActive'">[/code] then you need to remove the single quotes from the state variable. <transition event="dialog.exit" state="'dialogActive'"> <transition event="dialog.exit" state="dialogActive"> Its hard to see here but this is why it is defaulting to the other dialog.exit handler. Hope that helps! Regards, John Voxeo Supporteon |
|
weichen
|
|
| Hi, John,
I assume sample code in Step 5 in the above document should be fixed. Here is the piece from the Step 5 sample code. [code] ... <transition event="dialog.exit" state="'dialogActive'"> <log expr="'***** DIALOG EXIT IN DIALOG ACTIVE STATE *****'"/> <exit/> </transition> ... [/code] After I change it to [code] ... <transition event="dialog.exit" state="dialogActive"> <log expr="'***** DIALOG EXIT IN DIALOG ACTIVE STATE *****'"/> <exit/> </transition> ... [/code] Things work as expected. The last question is, in what circumstance (or never), this CCXML will transition into <transition event="dialog.exit">, given 1)there is only one dialog in this CCXML 2)myState is always set to dialogActive once the dialog is started? Thanks. |
|
voxeoJeffK
|
|
| Hi,
We apologize if that part of the tutorial was confusing to you. I believe the transition for dialog.exit that specifies state="'dialogActive'" is there for example purposes, and that's why the author included the single quotes to effectively disable the transition. That is to say the author wanted to show examples of dialog.exit transitions. One included a state designation, and one did not. You are correct in the statement that, after removing the single quotes, this particular script will always hit the first dialog.exit transition since it is always in state=dialogActive. Regards, Jeff K. |
|
mtatum111
|
|
| I guess that I am having problems understanding the dialog.exit as well. I understand that if state="dialogActive" then the first <transition> will be executed and then we will exit.
However, since state is not set to "dialogInActive" how does the second <transition> element which does not have state defined ever get executed. It could be something like the vxml dialog setting the state and passing it back to CCXML. However, I don't see this happening. It appears that if nothing is spoken at the prompt (when we go to the vxml dialog), that is when the first transition is executed. If something is actually spoken at the prompt, then the second transition is executed... Thanks for any further clarification. |
|
voxeoJeffK
|
|
| Hello,
>> since state is not set to "dialogInActive" how does the second <transition> element which does not have state defined ever get executed. If a state is not defined then the trigger for that transition is the event, regardless of state. When no state is defined, it is the same as saying *all* states. Remember also, the transition matching moves from the head of the file downward. You want to put specific handlers first followed by generic "catch-all" handlers. >> It could be something like the vxml dialog setting the state and passing it back to CCXML. While you can certainly use a return variable from a dialog to then assign state, that is not happening here. You would have to explicitly do so. >> It appears that if nothing is spoken at the prompt (when we go to the vxml dialog), that is when the first transition is executed. If something is actually spoken at the prompt, then the second transition is executed... First let me make clear: as the code stands the first dialog.exit transition NEVER works. Its a dummy. Notice the single quotes around dialogActive: <transition event="dialog.exit" state="'dialogActive'" It can't have single quotes! It breaks the transition. Try removing the single quotes, and run the code. Now you'll find that the first dialog.exit transition ALWAYS works. Why? because after the dialog starts we are always in the dialogActive state, so that transition is always valid upon dialog.exit. Please let me know if you are still fuzzy on anything. We are more than happy to clarify, and if you like I can whip up a different example. Regards, Jeff Kustermann Voxeo Support |
|
mtatum111
|
|
| Jeff, that makes perfect sense. I didn't catch the fact that the state was enclosed inside single quotes which was causing a problem in its execution. Thanks for the explanation.
|
|
punkin
|
|
| Another single quote problem:
<transition event="error.dialog.notstarted'"> An incorrect ending single quote appears to the event name, error.dialog.notstarted. I wish all the single quote problems can or will be fixed soon including the one pointed out by weichen. In order to keep the generic <transition> for event dialog.exit, the author had to put the single quotes inside the state attribute. It doesn't make sense to me. Looking at what this tutorial covers, I still don't see what the purpose is but confusing. Why not have them fixed (remove the single quotes and remove the generic <transition> for event dialog.exit)? |
|
voxeoJeffK
|
|
| Hello,
Since that single transition has seemed to cause more confusion that assistance, I have removed it entirely from the code. Also, I have corrected the typo whereby a single quote has found its way into the dialog.notstarted transition. These changes will take effect within the next few days on the next Documentation Build. Regards, Jeff Kustermann Voxeo Support |
| login |
|