complete workshop
Filetype:

pdf
Filesize: 1566311
Stop Rude Calls:
A CCXML Workshop for VoiceXML Veterans
Moshe Yudkowsky
Disaggregate
speech@pobox.com
1
2
Stop Rude Calls
But this could be much more useful...
Ask a user a question, e.g., “how
much is two plus two?”
User responds; transfer/drop call
3
Making app more useful...
White list and black list
Listen to messages live
Forward to multiple phones
?
?
1
2
3
Basic Concepts
4
5
CCXML provides a wide range of
call control, dialog control, sending
& receiving outside information
6
CCXML:
Movie
actions
and plot
VoiceXML:
Form
fill in the
blanks
Contrasts
4
5
6
7
Typical Plot
Start
Boy
Meets
Girl
Boy
Gets
Girl
Boy
Loses
Girl
Boy
Chases
Girl
8
Start
Boy
Meets
Girl
Boy
Gets
Girl
Boy
Loses
Girl
Boy
Chases
Girl
Coffee Cup Spill
Handsome Bank
Robber
Detective
Secret Uncovered
Technical Name:
State Machine
State
Event
CCXML:
Define states and
move between
them
9
Example:
Telephony
Application
DECIDE
TRANSFER/
DROP
START
VALIDATE
ALIVENESS
7
8
9
10
CCXML:
lazy
calmly
waits
forever
VoiceXML:
activist
always
talks or
listens
11
CCXML Only Moves If You
Push It -- via “Events”
Telephony Events
Ring, connect, hangup,...
Data Events
Data sent, data arrives,...
Error Events
Programming, platform...
DECIDE
TRANSFER/
DROP
START
VALIDATE
ALIVENESS
12
CCXML Only Moves If You
Push It -- via “Events”
Telephony Events
Ring, connect,
disconnect
Create call
Create conference,
join, unjoin
DECIDE
TRANSFER/
DROP
START
VALIDATE
ALIVENESS
10
11
12
13
CCXML Only Moves If You
Push It -- via “Events”
Data Events
Data send, data arrive
DECIDE
TRANSFER/
DROP
START
VALIDATE
ALIVENESS
14
CCXML Only Moves If You
Push It -- via “Events”
Interpreter Events
System startup
Handoff
Error, “kill”
DECIDE
TRANSFER/
DROP
START
VALIDATE
ALIVENESS
15
Switch
VoiceXML
Server
XML
Server
VoiceXML Architecture
13
14
15
16
CCXML Architecture
Switch
VoiceXML
Server
XML
Server
CCXML
Server
17
Same VoiceXML Limitations...
Switch
VoiceXML
Server
XML
Server
CCXML
Server
1,000 Users ?
1,000 Servers
Explicit
management of
User Interface
Limited intelligence
Starting a CCXML Call
18
16
17
18
19
Review:
Overview of
complete
interaction
DECIDE
TRANSFER/
DROP
START
VALIDATE
ALIVENESS
20
Stage 1:
Start the
CCXML
START
VALIDATE
21
Stage 1:
Not just a
single state.
Initialize
Script
START
VALIDATE
Ringing
Accept
19
20
21
22
Interpreter
events:
CCXML.loaded
CCXML.exit
CCXML.kill
Initialize
Script
START
VALIDATE
Ringing
Accepting
CCXML.
loaded
connection.
connected
connection.
alerting
23
24
But ringing started
immediately...
So why didn’t we
move to “Ringing”
immediately?
Initialize
Script
START
VALIDATE
Ringing
Accepting
CCXML.
loaded
connection.
connected
connection.
alerting
But doesn’t this seem
wrong?
22
23
24
25
CCXML:
queue
program
control of
state
VoiceXML:
immediate
auto-
move to
states
26
CCXML Infrastructure
27
Baseline
infrastructure.
Initialize
Script
START
VALIDATE
Ringing
Accept
25
26
27
28
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!
DOCTYPE
ccxml
PUBLIC
"-//W3C//DTD CCXML 1.0//EN"
"http://www.w3.org/TR/ccxml/ccxml.dtd"
>
<
ccxml
version
=
"1.0"
>
<
log
expr
=
”’Starting...’”
/>
</
ccxml
>
29
CCXML:
Strict
all defs
strict
ECMA
VoiceXML:
Hybrid
some
ECMA,
some not
30
CCXML:
Prog. States
state set
by app
VoiceXML:
Auto States
state set
by interp.
28
29
30
31
To
manage
current state, modify
the state-tracking variable.
To
create
a state, define a string
with the name of the state.
32
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!
DOCTYPE
ccxml
PUBLIC
"-//W3C//DTD CCXML 1.0//EN"
"http://www.w3.org/
TR/ccxml/ccxml.dtd"
>
<
ccxml
version
=
"1.0"
>
<!-- State Names -->
<
var
name
=
"src_init"
expr
=
"'src_init'"
/>
<
var
name
=
"src_connected"
expr
=
"'src_connected'"
/>
<
var
name
=
"src_authorized"
expr
=
"'src_authorized'"
/>
<
var
name
=
"src_refused"
expr
=
"'src_refused'"
/>
<
var
name
=
"src_exiting"
expr
=
"'src_exiting'"
/>
<!-- state variable, initialized -->
<
var
name
=
"src_currentState"
expr
=
"src_init"
/>
<
log
expr
=
”’Starting...’”
/>
<
eventprocessor
statevariable
=
"src_currentState"
>
</
eventprocessor
>
</
ccxml
>
33
Describe State and how to
handle Events
<transition>
Algorithm:
Look for first transition that
matches “conditions”
No transition? do something
logical
Event
START
VALIDATE
31
32
33
34
<transition
state
="state_name"
event
="event_name">
Name we
give state
Event this
transition handles
Attribute
35
<
eventprocessor
statevariable
=
"src_currentState"
>
<!-- loaded -->
<
transition
state
=
"src_init"
event
=
"ccxml.loaded"
/>
36
<
eventprocessor
statevariable
=
"src_currentState"
>
<!-- loaded -->
<
transition
state
=
"src_init"
event
=
"ccxml.loaded"
/>
<
transition
state
=
"src_init"
event
=
"ccxml.loaded"
>
<
log
expr
=
"logdelim + 'in init state'"
/>
</
transition
>
34
35
36
37
Phone Rings
How does that look?
How do we answer?
START
VALIDATE
38
<
transition
state
=
"src_init"
event
=
"ccxml.loaded"
>
<
log
expr
=
"logdelim + 'in init state'"
/>
</
transition
>
<
transition
state
=
"src_init"
event
=
"connection.alerting"
name
=
"evt"
>
<
assign
name
=
"userId"
expr
=
"evt.connection.remote"
/>
<
assign
name
=
"inboundConnection"
expr
=
"evt.connectionid"
/>
<
accept
/>
<
log
expr
=
"logdelim + 'accepted connection'"
/>
</
transition
>
Shortcut to
access infoEvents
contain info
39
37
38
39
40
CCXML:
Prog. States
state set
by app
VoiceXML:
Auto States
state set
by interp.
(Reminder)
41
Move to a different state:
explicitly set the
state variable
to
the
new state name
.
42
<
transition
state
=
"src_init"
event
=
"connection.connected"
name
=
"evt"
>
<
assign
name
=
"src_currentState"
expr
=
"src_connected"
/>
<
send
data
=
"nextstate"
target
=
"session.id"
/>
<
log
expr
=
"logdelim + 'ready to query'"
/>
</
transition
>
<
transition
state
=
"src_connected"
event
=
"nextstate"
name
=
"evt"
>
<
dialogstart
src
=
"requestPIN"
connectionid
=
"inboundConnection"
/>
</
transition
>
40
41
42
43
QUESTION
Many messages in the queue. How do
they pop off the queue? Or get in?
Which comes first?
44
CCXML:
Queue
we work
thru
queue
VoiceXML:
Single
Events
45
QUESTION
Many messages in the queue. How do
they pop off the queue? Or get in?
ANSWER
They enter queue in whatever order
they arrive.
They come off one after the other,
regardless of current state.
Transition selected in document order.
Which comes first?
43
44
45
46
<
transition
state
=
"src_init"
event
=
"error.connection"
name
=
"evt"
>
<
log
expr
=
"logdelim + 'uh oh'"
/>
</
transition
>
<
transition
event
=
"error.*"
name
=
"evt"
>
<
log
expr
=
"logdelim + 'received error ' +
evt.name + ' because ' + evt.reason"
/>
</
transition
>
47
CCXML: Outside Data
48
<
transition
state
=
"src_init"
event
=
"connection.alerting"
name
=
"evt"
>
<
assign
name
=
"userId"
expr
=
"evt.connection.remote"
/>
<
assign
name
=
"inboundConnection"
expr
=
"evt.connectionid"
/>
<
accept
/>
<
log
expr
=
"logdelim + 'accepted connection'"
/>
</
transition
>
46
47
48
<send>
Send data between CCXML sessions
Send data to other places via HTTP
49
<send> attributes
targettype: ccxml or basichttp
target: session ID or URL
data: event name
namelist: data to send along
50
51
<
transition
state
=
"src_init"
event
=
"connection.connected"
name
=
"evt"
>
<
assign
name
=
"src_currentState"
expr
=
"src_connected"
/>
<
send
data
=
"nextstate"
target
=
"session.id"
targettype
=
"send_ccxml"
/>
<
log
expr
=
"logdelim + 'ready to query'"
/>
</
transition
>
<
transition
state
=
"src_connected"
event
=
"nextstate"
name
=
"evt"
>
<
dialogstart
src
=
"requestPIN"
connectionid
=
"inboundConnection"
/>
</
transition
>
49
50
51
<send> responses
error. send.failed
error.send.targetunavailable
error.send.targettypeinvalid
send.success
52
53
STATE-BASED
Create series of sub-states. Stay in sub-
states until <send> completes.
Disadvantages
Little/nothing else happens meantimes
Reliable <send> ?
How?
54
STATELESS
Handle each individual <send>-related
signal regardless of current state
Disadvantages
Creates private state machine
Requires multiple tracking variables
Reliable <send> (cont.)
52
53
54
55
<
transition
event
=
"error.send.*"
>
<
log
expr
=
"logdelim + 'send error'"
/>
</
transition
>
56
CCXML:
Multi
thread
can pass
data
VoiceXML:
Single
Thread
sub-prog
must term
57
SEPARATE THREAD
Create separate process to interact, report
results to main thread
Disadvantages
Thread => CPU overhead, license
Reliable <send> (best)
55
56
57
58
<
transition
state
=
"src_init"
event
=
"connection.connected"
name
=
"evt"
>
<
createccxml
next
=
"checkId"
sessionid
=
"sendDataId"
namelist
=
"userId parentId"
method
=
"post"
/>
<
log
expr
=
"logdelim + 'start reliable send'"
/>
</
transition
>
<
transition
state
=
"src_init"
event
=
"ccxml.created"
name
=
"evt"
>
<
assign
name
=
"src_currentState"
expr
=
"src_connected"
/>
<
send
data
=
"nextstate"
target
=
"session.id"
targettype
=
"send_ccxml"
/>
<
log
expr
=
"logdelim + 'send started, ready to talk'"
/>
</
transition
>
<
transition
state
=
"src_init"
event
=
"error.createccxml"
name
=
"evt"
>
<
log
expr
=
"logdelim + 'uh oh'"
/>
</
transition
>
59
The absolute most powerful tool
in the CCXML toolbox:
Write a script to handle a single
call, then run as many copies as
needed.
60
How does outside
server send to us?
No standard! Ask your CCXML vendor.
58
59
60
61
IMMEDIATE:
server responds to <send> with
text/plain that includes:
report
item1=value1
item2=value2
Appears as event “report” with
evt.item1, evt.item2
Voxeo method (1)
Voxeo method (2)
62
DEFERRED:
http request from server to CCXML
platform:
http://ccxml.example.com/
CCXML.send?
sessionid=xyz&eventname=abc&it
em1=value1
Appears as event “abc” with evt.item1
63
VoiceXML Integration
61
62
63
VoiceXML-specific elements
dialogprepare, dialogstart
dialogterminate
dialog.exit
dialog.transfer, etc.
error.dialog.*
64
65
<
transition
state
=
"src_connected"
event
=
"nextstate"
name
=
"evt"
>
<
dialogstart
src
=
"detectHuman"
connectionid
=
"inboundConnection"
/>
</
transition
>
<!-- dialog error -->
<
transition
state
=
"src_connected"
event
=
"error.dialog*"
name
=
"evt"
>
<
log
expr
=
"logdelim + 'uh, oh'"
/>
</
transition
>
66
<
filled
>
<
log
expr
=
"logdelim + 'field filled'"
/>
<
prompt
>
Thank you, one moment please.
</
prompt
>
<
assign
name
=
"human"
expr
=
"request$.interpretation.human"
/>
<
exit
namelist
=
"human"
/>
</
filled
>
And on the VXML side...
64
65
66
67
<
transition
state
=
"src_connected"
event
=
"nextstate"
name
=
"evt"
>
<
dialogstart
src
=
"detectHuman"
connectionid
=
"inboundConnection"
/>
</
transition
>
<!-- dialog error -->
<
transition
state
=
"src_connected"
event
=
"error.dialog*"
name
=
"evt"
>
<
log
expr
=
"logdelim + 'uh, oh'"
/>
</
transition
>
<!-- is human? -->
<
transition
state
=
"src_connected"
event
=
"dialog.exit"
name
=
"evt"
>
<
assign
name
=
"isHuman"
expr
=
"evt.values.human"
/>
</
transition
>
68
Call Manipulation
69
QUESTION
How do I connect incoming caller to me?
ANSWER
Make outgoing call
Create conference
Connect together
67
68
69
Basic Elements (“Tags”)
createcall
createconference, join, unjoin
70
71
<!-- authorized call. make outbound connection. -->
<
transition
state
=
"src_authorized"
event
=
"nextstate"
name
=
"evt"
>
<
createcall
dest
=
"clientTn"
connectionid
=
"clientConnId"
/
>
</
transition
>
72
<!-- connection failed. Which one failed? -->
<
transition
state
=
"src_authorized"
event
=
"connection.failed"
name
=
"evt"
>
<
if
cond
=
"evt.connectionid == clientConnId"
>
<!-- do one thing -->
<
elseif
cond
=
"evt.connectionid == inboundConnection"
/>
<!-- do something else -->
</
if
>
</
transition
>
We have two calls. On failure, check to see
which one failed.
70
71
72
73
QUESTION
How do I connect incoming caller to me?
ANSWER
Make outgoing call
Create conference
Connect together
74
<!-- conference info -->
<
var
name
=
"srcConferenceId"
/>
<
var
name
=
"srcConfName"
expr
=
"'src_conf_' + session.id"
/>
<
transition
state
=
"src_conferenced"
event
=
"nextstate"
name
=
"evt"
>
<
createconference
conferenceid
=
"srcConferenceId"
confname
=
"srcConfName"
/>
</
transition
>
<
transition
state
=
"src_conferenced"
event
=
"conference.error.create"
name
=
"evt"
>
<
log
expr
=
"logdelim + 'uh oh'"
/>
</
transition
>
75
<
transition
state
=
"src_conferenced"
event
=
"conference.created"
name
=
"evt"
>
<
join
id1
=
"srcConferenceId"
id2
=
"inboundConnection"
entertone
=
"false"
exittone
=
"false"
/>
<
join
id1
=
"srcConferenceId"
id2
=
"clientConnId"
entertone
=
"false"
exittone
=
"false"
/>
</
transition
>
73
74
75
76
QUESTION
How do I detect failure to join?
QUESTION
Can I use separate CCXML instance
devoted to task of joining calls?
ASSERTION
Previous code segment is bad example.
77
CCXML:
Call in
Session
in original
thread
VoiceXML:
Call in
Thread
active
thread
78
POSSIBLE
PROCEDURE:
Add more states
Join 1, validate
Join 2, validate
Go to
“nominal” and
wait for
hangups.
Join 1
START_
CONFERENCE
NOMINAL
Join 2
76
77
78
79
REAL QUESTION
Does it actually make a difference which
call fails? If not, play announcement to
survivor and just hang up.
80
<
transition
state
=
"src_conferenced"
event
=
"pleaseDisconnect"
name
=
"evt"
>
<
disconnect
connectionid
=
"inboundConnection"
/>
</
transition
>
About hanging up...
Adding script to track different calls
works for a couple of calls,
but rapidly gets out of control.
Scaling Up:
Problems and Solutions
81
79
80
81
82
Master
Master
Leg
Leg
Call
Call
Leg (1)
Leg (1)
Conference
Conference
Call
Call
Leg (n)
Leg (n)
Conference Call Scenario
Master Call Leg
Conference Object
Twelve Call Legs
Make outbound calls
Retry each call if necessary
Track individual data
83
Outbound Legs
Possible Architecture:
Create array of “outbound”
objects
Use array to track status of each
call
As call status changes, take
action & update status
84
82
83
84
Outbound Legs
Possible Architecture:
Write CCXML instance to handle
single call leg
Use multiple instances
85
86
The absolute most powerful tool
in the CCXML toolbox:
Write a script to handle a single
call, then run as many copies as
needed.
87
Main
Main
Loop
Loop
Call
Call
Leg (1)
Leg (1)
Conference
Conference
Call
Call
Leg (n)
Leg (n)
Voice Conference
Manager
Multiple Instances
85
86
87
88
Each call leg
instance handles
the simple tasks
associated with a
single leg
Main
Main
Loop
Loop
Call
Call
Leg (1)
Leg (1)
Conference
Conference
Call
Call
Leg (n)
Leg (n)
Start
Status
Action
Best Practices &
Debugging
89
90
Conference
Conference
Conference
Conference
Problem: Connect
Conferences
88
89
90
Wrong!
91
Conference
Conference
Conference
Conference
Call Leg
Call Leg
92
Remember:
CCXML has
only one end
of a call.
93
Conference
Conference
Conference
Conference
Call Leg
Call Leg
Call Leg
Call Leg
91
92
93
Avoid Confusing State
Names
94
CONNECTED
START
Potential human
confusion between
state name and
canonical state
name
95
<dialogstart type=”’application/voicxml+xml’”
src=”’../vxml/askAccountNumber.vxml’”/>
Never, ever use a string
if you can avoid it
96
<transition event=”connection.connected”
state=”’s_init_endOfInitialzation’”/>
Never, ever use a string
if you can avoid it
94
95
96
97
<assign name=”item1”
expr=”’statusSucceess’”/>
Never, ever use a string
if you can avoid it
98
Best Practices (1)
Use separate CCXML module when
tasks are asynchronous and mixed
99
Main
Main
Module
Module
Send
Send
Instance
Instance
Send
Send
Manager
Manager
97
98
99
100
Best Practices (1)
Use separate CCXML module when
tasks are asynchronous and mixed
Use separate CCXML instances
when you start imitating state
machine
Consider separate CCXML modules
for logically separate tasks
101
Best Practices (2)
Use variables, not strings
Don’t neglect standard
programming practices
Use unique conference names if
you want them to be unique!
Use unique “statevariable” names
for each CCXML module
102
Best Practices (3)
The kindergarten rules:
Play nicely with others
(use comments)
Clean up after yourself
(use destroyconference, etc.)
100
101
102
What I Really Prefer
A separate instance for each
outgoing call
A separate instance to manage
conference
Send messages from master
instance to call instances to tell
them to join conference
103
104
The only real source of debugging
information is your log files.
105
Create your own standard delimiter
<var name=”logdelim
expr=”’ ::::::LOG:::::: ‘”/>
103
104
105
106
<log expr=”
logdelim
+ ‘var is
’ +
varValue
+ ‘from
inside object: ’ +
JSON.stringify
(object)”/>
Log statements can contain
strings, ECMAScript values, and
ECMAScript functions
About Disaggregate
Moshe Yudkowsky
Disaggregate
2952 W. Fargo
Chicago, IL 60645
+1 773 764 8727
www.Disaggregate.com
106
107