CCXML 1.0-W3C Development GuideHome  |  Frameset Home

  Answering Machine Detection  |  TOC  |  Conferencing with Whisper   

Answering Machine Detection

So after your first go-round with CPA, you have noticed a couple of things:
  1.  CPA is really cool!
  2.  Your CPA settings are not perfect.



Call Progress Analyzer Parameters


voxeo-cpa-version
This parameter is optional.  The current CPA version is "2.0."

voxeo-cpa-maxsilence
The 'cpa-maxsilence' parameter is used to identify the end of voice activity.  When activity begins, CPA will measure the duration until a period of silence greater than the value of 'cpa-maxsilence' is detected.  Armed with start and end timestamps, CPA can then calculate the total duration of voice activity.  A value of 800 to 1200ms is suggested for this parameter.

voxeo-cpa-maxtime
The 'cpa-maxtime' parameter is the "measuring stick" used to determine 'human' or 'machine' events.  If the duration of voice activity is less than the value of 'cpa-maxtime', the called party is considered to be 'human.'  If voice activity exceeds the 'cpa-maxtime' value, your application has likely called a 'machine.'  The recommended value for this parameter is between 4000 and 6000ms.

voxeo-cpa-runtime
The 'cpa-runtime' parameter specifies the maximum amount of time CPA should listen for events.  If the 'runtime' exprires, CPA will return an "unknown" result.  Therefore, 'cpa-runtime' should always be longer than the average answering machine outgoing message.  We recommend a value of at least 15000-20000ms.

voxeo-cpa-maskevent
The 'cpa-maskevent' parameter lists the CPA results that should throw an event.  This assures that only desired results, important to your specific application, will be acknowledged.  The value for this parameter should be a comma-separated list, any combination of the following:

* For those who are aspiring telephony geeks, SIT stands for "Special Information Tones."  These are the tones you might hear when calling a disconnected or not in-service number.

voxeo-cpa-maskstop
The 'cpa-maskstop' parameter lists the CPA results that, when received, will simply stop CPA from listening for further events. The value for this parameter should be a comma-separated list, any combination of the following:


Call Progress Analyzer Results


human
A 'human' result is determined when the duration of initial voice activity is less than the 'cpa-maxtime' value. 

machine
A 'machine' result is determined when the duration of initial voice activity is greater than the 'cpa-maxtime' value. 

beep
A 'beep' result indicates that CPA's Digital Signal Processing (DSP) has encountered a pure tone.

modem
CPA has detected a modem.

faxtone
CPA has detected a fax machine.

SIT
A 'SIT' result indicates that CPA detected Special Information Tones - SIT tones.  This generally means that the called number has been disconnected or is no longer in service.

unknown
An 'unknown' result is returned when the 'cpa-runtime' expires.



Simple CPA Example Code

The below example illustrates basic usage of CPA at its most simplistic.  The application will be initiated using a tokenID, create an outbound call, and simply log the CPA result value.  Use this application to familiarize yourself with CPA's detection algorithm as described above.

<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns="http://www.w3.org/2002/09/ccxml" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<meta name="author" content="Jeff Menkel"/>
<meta name="copyright" content="2007 Voxeo Corporation"/>
<meta name="maintainer" content="YOUR_EMAIL@HERE.COM"/>

<var name="state0" expr="'init'"/>

  <eventprocessor statevariable="state0">
 
    <transition state="init" event="ccxml.loaded">
      <createcall dest="'tel:+14071112233'"
                  timeout="'60s'"
                voxeo-cpa-maxsilence="'100'"
                  voxeo-cpa-maxtime="'400'"
                  voxeo-cpa-runtime="'2000'"
                  voxeo-cpa-maskstop="'beep, faxtone, modem, ring, sit, human, machine'"
                  voxeo-cpa-maskevent="'beep, faxtone, modem, ring, sit, human, machine'"/>
    </transition>

  <transition event="voxeo.cpa.result">
      <log expr="'*** CPA says [' + event$.type + '] ***'"/>
      <exit/>
    </transition>

    <transition state="calling" event="connection.failed">
      <log expr="'*** CALL FAILED ***'"/>
      <exit/>
    </transition>

    <transition event="connection.disconnected">
        <exit/>
    </transition>

    <transition event="error.*">
      <log expr="'*** AN ERROR HAS OCCURRED (' + event$.reason + ') ***'"/>
      <exit/>
    </transition>
  </eventprocessor>
</ccxml>


Advanced CPA Example Code

Most real-world applications will likely do a bit more than simply log a CPA event, and exit. More often than not, you will need to play a message or invoke a VoiceXML dialog based on the CPA result.

The below sample script shows how we can tweak the CPA parameters and add clever application logic to suit our specific needs.  This particular application is designed to leave a full and complete message ('message.wav') with either a human recipient or an answering machine. You will notice that we are now incorporating several bits of logic around our CPA usage to achieve this goal:


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns="http://www.w3.org/2002/09/ccxml" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<meta name="author" content="Jeff Menkel"/>
<meta name="copyright" content="2007 Voxeo Corporation"/>
<meta name="maintainer" content="YOUR_EMAIL@HERE.COM"/>

<var name="state0" expr="'init'"/>
<var name="DlgActive" expr="'no'"/>
<var name="lastCPAEventTime" expr="new Date().getTime()"/>
<var name="DlgExitStatus" expr="'unforced'"/>
<var name="call_0"/>
<var name="playMsg"/>

<eventprocessor statevariable="state0">
  <transition state="init" event="ccxml.loaded">
    <createcall dest="'tel:+14071112233"
                timeout="'60000ms'"
                voxeo-cpa-runtime="'60000'"
                voxeo-cpa-maxtime="'4000'"
                voxeo-cpa-maxsilence="'1000'"
                voxeo-cpa-maskevent="'human,machine,beep'"
                voxeo-cpa-maskstop="''"
                connectionid="call_0"/>
  </transition>

  <transition event="connection.connected">
    <log expr="'*** CALL CONNECTED -- WAITING FOR CPA ***'"/>
  </transition>

  <transition event="connection.failed">
    <log expr="'*** CALL FAILED [' + event$.connectionid + '] ***'"/>
    <log expr="'*** REASON [' + event$.reason + '] ***'"/>
    <exit/>
  </transition>

  <transition event="voxeo.cpa.result">
    <log expr="'*** CPA SAYS [' + event$.type + '] ***'"/>

<!--  If it has been more than 1000ms since the last time we have    -->
<!--  received the 'voxeo.cpa.result' event, we will process this    -->
<!--  code.  This logic will simply prevent multiple CPA events,    -->
<!--  such as a 'machine' and then an immediate 'beep' event, from    -->
<!--  overlapping and causing a state mismatch when trying to        -->
<!--  start and terminate the message dialog. -->

    <if cond="new Date().getTime() - lastCPAEventTime >= 1000">

<!--  Put a new time stamp on the last time we have received the    -->
<!--  'voxeo.cpa.result' event.  -->

      <assign name="lastCPAEventTime" expr="new Date().getTime()"/>

      <if cond="event$.type == 'human'">
        <log expr="'*** HUMAN ANSWERED -- PLAY MESSAGE ***'"/>
        <send name="'playMsg'" target="session.id"/>
        <assign name="state0" expr="playMsg"/>
      <elseif cond="event$.type == 'machine'"/>
        <log expr="'*** MACHINE ANSWERED -- PLAY MESSAGE ***'"/>
        <send name="'playMsg'" target="session.id"/>
        <assign name="state0" expr="playMsg"/>
      <elseif cond="event$.type == 'beep'"/>
        <log expr="'*** BEEP DETECTED -- PLAY MESSAGE ***'"/>
        <send name="'playMsg'" target="session.id"/>
        <assign name="state0" expr="playMsg"/>
      </if>
    </if>
  </transition>

  <transition event="playMsg">

<!--  If the message dialog is not currently playing, -->
<!--  start the message dialog.  -->

    <if cond="DlgActive == 'no'">
      <assign name="DlgActive" expr="'yes'"/>
      <assign name="DlgExitStatus" expr="'unforced'"/>
      <dialogstart src="'audiofile.wav'"
                  type="'audio/wav'"
                  connectionid="call_0"
                  dialogid="Message_Dlg"/>
    <else/>

<!--  If the message dialog is currently playing, -->
<!--  stop the current  dialog  -->

      <assign name="DlgExitStatus" expr="'forced'"/>
      <dialogterminate dialogid="Message_Dlg"/>
    </if>
  </transition>

  <transition event="dialog.exit">

<!--  If the dialog has exited 'unforced', then the message has      -->
<!--  been completely delivered.  -->

    <if cond="DlgExitStatus == 'unforced'">
      <log expr="'*** MESSAGE PLAYED ***'"/>
      <exit/>

<!--  If the dialog has been 'forced' to exit, then we send the      -->
<!--  'playMsg' event to start the message dialog over again.        -->

    <else/>
      <log expr="'*** MESSAGE DISRUPTED -- RESTARTING MESSAGE ***'"/>
      <assign name="DlgActive" expr="'no'"/>
      <send name="'playMsg'" target="session.id"/>
    </if>
  </transition>

  <transition event="connection.disconnected">
    <if cond="call_0 == event$.connectionid">
      <log expr="'*** CALL DISCONNECTED -- EXIT ***'"/>
      <exit/>
    </if>
  </transition>

  <transition event="error.*">
    <log expr="'*** AN ERROR HAS OCCURRED [' + event$.reason + '] ***'"/>
    <exit/>
  </transition>
</eventprocessor>
</ccxml>



Tips, Tricks, and Advice

Many users new to CPA often experience problems with long delays or silence when starting their initial VoiceXML dialog.  For the edification of our developers experiencing such delays/silence, here is an explanation of problem, and some useful suggestions on how we can rectify these fetch/loading delays:

First of all, any delays in initial dialog execution most likely has to do with long fetch times on your initial VoiceXML document itself...possibly due to database hits and/or back-end logic.  This, of course, will in turn cause undesirable periods of silence for your end user(s). To explain the execution order of this type of an application, it may help to visualize what is actually happening:

Note:  Let's assume your application has seven individual documents - none of which has an active reco <field>, and each document hits a database. Let's further assume that each fetch of these seven documents takes 2 seconds to load and parse, (a conservative estimate!). In this case, your first <audio> file or TTS prompt would not be played for 14 seconds!  Even if that first <audio> was located in the very first document, the VoiceXML Form Interpretation Algorithm (FIA) as described by the W3C in the VoiceXML2.1 specification would dictate that we would indeed have a 14 second delay, a period of initial silence upon call pickup that most of our callers would find unpalatable.

To address this, we must first understand that if we intend to use CPA, the initial delay encountered when waiting for the 'cpa-maxsilence' to expire is unavoidable anyway we choose to go about this. (We humbly recommend that your 'cpa-maxsilence' be set to 800ms - 1200ms)  But this alone should not be a huge issue for an end user.  The real trick here will be fooling the VoiceXML FIA into stopping execution in order to immediately play an opening audio file, and then loading the "real" application document(s) - containing the databse hits and back-end logic - without causing the end user to sit in uncomfortable silence.  To accomplish this, we suggest that you configure your application with the following suggestions firmly in mind:



An example of how you could code a stub file is presented for your review below. While this sample is written in ASP, the only 'moving parts' to the ASP are catching the querystring value of the CPA result, and importing it to the VoiceXML context. As such, it's a simple matter to change this stub file to suit the server-side language of your choice, (see our VoiceXML documentation on passing querystrings for additional information.


StubFile Example


<?xml version="1.0" encoding="UTF-8"?>
<vxml version = "2.0">
<!-- stubfile.asp -->

<var name="voxeo-cpa-result" expr="'<%
=Request.Querystring("voxeo-cpa-result") %>'"/>

<form>
  <block>
    <log expr="'##########################################'"/>
    <log expr="'### CPA Says: ' + voxeo-cpa-result + ' ###'"/>
    <log expr="'##########################################'"/>
  </block>

  <field name="dummy">
    <property name="timeout" value="100ms"/>
<!-- set the 'noinput' timeout to 0.1 seconds -->

    <audio src="http://myserver.com/helloThere.wav">
      Hello there.  This is a call from Big Bird.
    </audio>

<!-- create a 'garbage' grammar that will NEVER get a match -->
    <grammar> [paris hilton is a boon to the human race] </grammar>

    <filled>
    <!-- this shouldn't ever happen -->
    </filled>

    <catch event="noinput nomatch">
      <submit next="http://myserver.com/myCoolAppWithNaughtyDBHits.asp"
              fetchaudio="myCoolWaitMusic.wav"
              method="post"
              namelist="voxeo-cpa-result" />
    </catch>
  </field>
</form>
</vxml>


Confirmation Dialogs

Another good CPA strategy is to load a 'confirmation' VoiceXML dialog upon detection of a 'human' event, which gives us an additional layer of detection, although this might not fit with all application designs. In short, we assume that the call recipient is *always* a human, regardless of the event  that the CPA returns. We can then invoke a VoiceXML dialog along the lines of "This is a secure message for 555-111-2222. If the callee is available, please press 1". This will squeeze even more accuracy out of the CPA, and ensure that your messge won't have the first few seconds clipped off of it due to event timing....if the dialog receives the correct keypress, we can be 100% certain that the caller is indeed a human. If we receive a <noinput> event, (and be sure to adjust your form-item's 'timeout' value!), then we can be confident that we have encountered a voicemail system.


  ANNOTATIONS: EXISTING POSTS
0 posts - click the button below to add a note to this page

login
  Answering Machine Detection  |  TOC  |  Conferencing with Whisper   

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