Lesson 2 -- Adding DTMF Input

The version of app-root.vxml developed in Lesson 1 responds only to voice input from the caller. DTMF (Dual-Tone Multi-Frequency, the familiar "touch tone") input can be used as an alternative to voice input. In this lesson, we will add DTMF capability so that the caller can choose to respond to prompts either by speaking or by using the touch-tone phone keys.

A caller's DTMF input can be obtained either via a form dialog or a menu dialog. This lesson addresses how to use a <form> element to get DTMF input and adds DTMF capability to app-root.vxml. Lesson 3 will demonstrate how we can get DTMF input via the <menu> element.

DTMF grammars in forms

Let us add DTMF input as an alternative to voice input in our main form.

You can choose to make a form respond to both voice and DTMF by using two grammars: a DTMF grammar and a voice grammar. The two must be different grammars, however-you cannot mix voice and DTMF in the same grammar.

Note

You can also make a form respond only to DTMF by including only a DTMF grammar.

DTMF grammar headers

A DTMF grammar must have mode="dtmf" as an attribute of the <grammar> element. A language attribute should not be used. Other attributes are the same as for a voice grammar. For example,

<grammar mode="dtmf" version="1.0" root="topRule">

Structure of DTMF grammars

The permitted values for DTMF grammars are 0 1 2 3 4 5 6 7 8 9 (digits, not words) and * #.

DTMF grammars are constructed with the same elements that are used for voice grammars. For example:

  1. <grammar> elements contain one or more <rule> elements. The Tellme platform requires that the <grammar> element must have an attribute named root that identifies the top-level <rule> element.

  2. <item> elements enclose expected input tones or groups of tones.

  3. <one-of> elements enclose lists of alternative <item> elements.

An example

In the app-root.vxml application that we developed in Lesson 1, the main dialog looked like this:

<form id="main">
      <field name="main_selection">
         <prompt>
            Welcome to Contoso Travel. Say new reservation, change
                             reservation, or restaurant recommendation.
         </prompt>
         <grammar version="1.0" root="top">
            <rule id="top">
               <one-of>
                  <item>new reservation</item>
                  <item>change reservation</item>
                  <item>restaurant recommendation</item>
               </one-of>
            </rule>
         </grammar>
         <filled>
            <!-- logic to transition to next form -->
         </filled>
      </field>
   </form>

To include DTMF, we modify the prompt and add a DTMF grammar just after the voice grammar. The changes are shown in bold font:

<form id="main">
      <field name="main_selection">
         <prompt>
            Welcome to Contoso Travel.
            Say new reservation or press 1.
            Say change reservation or press 2.
            Say restaurant recommendation or press 3.
         </prompt>
         <grammar version="1.0" root="top">
            <rule id="top">
               <one-of>
                  <item>new reservation</item>
                  <item>change reservation</item>
                  <item>restaurant recommendation</item>
               </one-of>
            </rule>
         </grammar>
         <grammar mode="dtmf" version="1.0" root="top"><rule id="top"><one-of><item>1</item><item>2</item><item>3</item></one-of></rule></grammar>

         <filled>
            <!-- logic to transition to next form -->
         </filled>
      </field>
   </form>

The <filled> logic

Since we are now permitting DTMF input, we must change the logic in the main_selection field's <filled> element.

If there is a grammar match to the DTMF grammar (that is, the caller has pressed 1, 2, or 3), the VoiceXML interpreter assigns the match value to the main_selection variable, just as it would for a voice match.

With voice input only, we had:

         <filled>
            <script>
               <![CDATA[
                  var next_destination = "";
                  switch (main_selection){

                  case "new reservation" :
                    next_destination = "#new_reservation";
                    break;
                    
                  case "change reservation" :
                    next_destination = "change-reservation.vxml";
                    break;
                    
                  case "restaurant recommendation" :
                    next_destination = "restaurant.vxml";
                    break;
                    
                  default:
                   next_destinaton ="error.vxml";
                   break;
                 }
               ]]>
            </script>
            <goto expr="next_destination"/>
         </filled>

To accommodate DTMF input, we need only add three more switch cases (1, 2, and 3). The changes are shown in bold font:

         <filled>
            <script>
               <![CDATA[
                  var next_destination = "";
                  switch (main_selection){

                  case "new reservation" :
                    next_destination = "#new_reservation";
                    break;

                  case "1" :next_destination = "#new_reservation";break;
                    

                  case "change reservation" :
                    next_destination = "change-reservation.vxml";
                    break;
                    
                  case "2" :next_destination = "change-reservation.vxml";break;
                    

                  case restaurant recommendation" :
                    next_destination = "restaurant.vxml";
                    break;
                    
                  case "3" :next_destination = "restaurant.vxml";break;
                    

                  default: 
                    next_destination = "error.vxml"
                    break;
                 }
               ]]>
            </script>
            <goto expr="next_destination"/>
         </filled>

The main form with DTMF

Combining the code above, we have the complete main dialog. The changes are shown in bold font:

<form id="main">
      <field name="main_selection">
         <prompt>
            Welcome to Contoso Travel.
            Say new reservation or press 1.
            Say change reservation or press 2.
            Say restaurant recommendation or press 3.
         </prompt>
         <grammar version="1.0" root="top">
            <rule id="top">
               <one-of>
                  <item>new reservation</item>
                  <item>change reservation</item>
                  <item>restaurant recommendation</item>
               </one-of>
            </rule>
         </grammar>

         <grammar mode="dtmf" version="1.0" root="top"><rule id="top"><one-of><item>1</item><item>2</item><item>3</item></one-of></rule></grammar>

         <catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

         <filled>
            <script>
               <![CDATA[
                  var next_destination = "";
                  switch (main_selection){

                  case "new reservation" :
                    next_destination = "#new_reservation";
                    break;

                  case "1" :next_destination = "#new_reservation";break;
                    

                  case "change reservation" :
                    next_destination = "change-reservation.vxml";
                    break;
                    
                  case "2" :next_destination = "change-reservation.vxml";break;
                    

                  case "restaurant recommendation" :
                    next_destination = "restaurant.vxml";
                    break;
                    
                  case "3" :next_destination = "restaurant.vxml";break;
                    

                  default:
                   next_destination = "error.vxml";
                   break;
                 }
               ]]>
            </script>
            <goto expr="next_destination"/>
         </filled>
      </field>
   </form>

A new version of app-root.vxml

To change app-root.vxml so that it will also accept DTMF input in the main form, do the following:

  1. Copy the app-root.vxml code at the end of Lesson 1.

  2. Replace the main form with the main code in the preceding section.

Following the above steps, we have a new version of app-root.vxml. The new code is shown in bold font.

<?xml version="1.0" encoding="UTF-8"?>
<vxml xmlns="http://www.w3.org/2001/vxml"
      version="2.1"
      xml:lang="en-US"
      xml:base="https://studio.tellme.com/vxml-tutorial/">
      
   <script>
      <![CDATA[
         var doNewPlaneRes = false;
         var doNewHotelRes = false;
         var doNewCarRes = false;
         var doChangePlaneRes = false;
         var doChangeHotelRes = false;
         var doChangeCarRes = false;
         var doRestaurantRec = false;
      ]]>
   </script>

<form id="main">
      <field name="main_selection">
         <prompt>
            Welcome to Contoso Travel.
            Say new reservation or press 1.
            Say change reservation or press 2.
            Say restaurant recommendation or press 3.
         </prompt>
         <grammar version="1.0" root="top">
            <rule id="top">
               <one-of>
                  <item>new reservation</item>
                  <item>change reservation</item>
                  <item>restaurant recommendation</item>
               </one-of>
            </rule>
         </grammar>
         <grammar mode="dtmf" version="1.0" root="top"><rule id="top"><one-of><item>1</item><item>2</item><item>3</item></one-of></rule></grammar>

         <catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

         <filled>
            <script>
               <![CDATA[
                  var next_destination = "";
                  switch (main_selection){

                  case "new reservation" :
                    next_destination = "#new_reservation";
                    break;

                  case "1" :next_destination = "#new_reservation";break;
                    

                  case "change reservation" :
                    next_destination = "change-reservation.vxml";
                    break;
                    
                  case "2" :next_destination = "change-reservation.vxml";break;
                    

                  case "restaurant recommendation" :
                    next_destination = "restaurant.vxml";
                    break;
                    
                  case "3" :next_destination = "restaurant.vxml";break;
                    

                  default:
                    next_destination = "error.vxml";
                   break;
                 }
               ]]>
            </script>
            <goto expr="next_destination"/>
         </filled>
      </field>
   </form>
   <form id ="new_reservation">
      <field name="new_reservation_type">
         <prompt>
            What type of reservation do you want to make? Say plane, hotel,
            or car. You can combine types by saying plane and hotel for example.
         </prompt>
         <grammar version="1.0" root="top">
            <rule id="top">
               <one-of>
                  <item>plane</item>
                  <item>hotel</item>
                  <item>car</item>
                  <item>plane and hotel</item>
                  <item>hotel and car</item>
                  <item>plane and car</item>
                  <item>plane and hotel and car</item>
               </one-of>
            </rule>
         </grammar>

         <catch event="noinput nomatch">
            Sorry. Didn't get that. Please try again.
            <reprompt/>
         </catch>

         <filled>
            <script>
              <![CDATA[
                  var next_destination = "";
                  switch (new_reservation_type){

                  case "plane" :
                    next_destination = "new-plane.vxml";
                    break;

                  case "hotel" :
                    next_destination = "new-hotel.vxml";
                    break;

                  case "car" :
                    next_destination = "new-car.vxml";
                    break;
                    
                  case "plane and hotel" :
                    next_destination = "new-plane.vxml";
                    doNewHotelRes = true;
                    break;

                  case "plane and car" :
                    next_destination = "new-plane.vxml";
                    doNewCarRes = true;
                    break;

                  case "hotel and car" :
                    next_destination = "new-hotel.vxml";
                    doNewCarRes = true;
                    break;
                    
                  case "plane and hotel and car" :
                    next_destination = "new-plane.vxml";
                    doNewHotelRes = true;
                    doNewCarRes = true;
                    break;

                  default: break;
                 }
               ]]>
            </script>

            <goto expr="next_destination"/>
         </filled>
      </field>
   </form>
</vxml>

You should paste this code into the Tellme Studio Scratchpad and run it.

What's next?

In the first two lessons, we have developed an entry-point document for Contoso Travel. In lesson 1, we developed the document with voice response only. In this lesson, Lesson 2, we added DTMF capability so that the caller can respond either with voice or by pressing the touch-tone phone keys.

There are two types of dialogs: <form> elements and <menu> elements. The VoiceXML document we have developed in Lessons 1 and 2 uses only <form> elements as dialogs. We will continue to use this type of dialog throughout this tutorial because <form> elements are more versatile than <menu> elements.

We feel that you should know about menus, the other type of dialog, however, so Lesson 3 shows how we could replace the main <form> element with a <menu> element with the same functionality.