Speech Control Editor Tips
This topic contains tips to consider when using the Speech Control Editor. For more tips, see issues of the Microsoft Speech Technologies Newsletter on the Microsoft Speech web site.
Reusing a Command Object Across Pages
One of the best ways to create a reusable Command object across pages is to create a User Control.
There is one trick though: remember to set the scope for the commands. The scope doesn't default to “every QA”, which means that it is necessary to specify the name of the parent container. Use a bit of server-side code to get the name of the container object, and if desired also add properties to the User Control.
Using the Prompt and Listen Controls
The Basic Speech Controls used in the Speech Application SDK (SASDK) are an ASP.NET representation of the two fundamental Speech Application Language Tags (SALT) elements: prompt and listen. These controls are designed especially for applications running on tap-and-talk client devices, and are used primarily for managing application flow through a graphical user interface (GUI). In order to use speech recognition on handheld devices running Pocket Internet Explorer, a separate speech server running Speech Engine Services (SES) must be available. The URL of SES must be specified for each Listen and Prompt control.
Although the Property Builder included in the SASDK makes it easy to enter the URL for an individual control, it can be impractical to enter this information over and over, and to keep it up to date. Because in most cases the same server will be used for all controls in an application, and because the name of the server might change during development, testing, and deployment, it makes sense to store this URL in just one location in the application. One solution to this might be to store the URL of the speech server in the application's web.config file, in the appSettings area. For example, the web.config file might include a section like this:
<appSettings>
<add key=“speechserver” value=“http://MyServer/ses/lobby.asmx” />
</appSettings>
The author can then read the URL from the web.config file at render-time. The URL could then be stored in a string, and ASP.NET data binding could be used to link this value to the Prompt and Listen elements. The author would still need, however, to manually add the necessary text to each .aspx page to specify the information that will be databound.
A more advanced but convenient approach is to add the required information to each control dynamically, at render-time. In essence, code is added that finds each Prompt and Listen control on the page, and dynamically inserts a Param tag specifying the speech server. The code to do this can be added using a Page_PreRender method. In order to employ this method, when in Design mode, select the current page and enter “Page_PreRender” in the Properties window. This will cause Microsoft Visual Studio to insert the code to attach a new handler, as shown in the following example.
private void InitializeComponent()
{
...
this.PreRender += new System.EventHandler(this.Page_PreRender);
...
}
Visual Studio will automatically jump to the code-behind for the page, and will create and select the new Page_PreRender event. The code to add the necessary Param tags looks like this:
private void Page_PreRender(object sender, System.EventArgs e)
{
// Check if the web.config lists a server to user
if (ConfigurationSettings.AppSettings[“speechserver”] == null)
return;
string server =
ConfigurationSettings.AppSettings[“speechserver”].ToString();
// Find all the controls of type Prompt
ArrayList a = FindAllControlsOfType(Page.Controls, typeof(Prompt));
// Loop over them
for (int i=0;i<a.Count;i++)
{
Prompt p = a[i] as Prompt;
// If it already contains a server param, skip it
if (p.Params.ContainsName(“server”)) continue;
// Otherwise create and add a new param setting the server
Param sp = new Param();
sp.Name = “server”;
sp.Value = server;
p.Params.Add(sp);
}
// And do the same for the Listen controls
a = FindAllControlsOfType(Page.Controls, typeof(Listen));
for (int i=0;i<a.Count;i++)
{
Listen l = a[i] as Listen;
if (l.Params.ContainsName(“server”)) continue;
Param sp = new Param();
sp.Name = “server”;
sp.Value = server;
l.Params.Add(sp);
}
}
One additional method is required, to build an ArrayList of all controls on the page of a particular type:
private ArrayList FindAllControlsOfType(ControlCollection theList,
System.Type theType)
{
// Loop over all the controls in the control collection that is
// passed in. Keep an ArrayList of those matching the requested
// type. Recursively check the children of all controls.
ArrayList toRet = new ArrayList();
for(int i=0;i<theList.Count;i++)
{
if (theList[i].GetType() == theType)
toRet.Add(theList[i]);
toRet.AddRange(
FindAllControlsOfType(theList[i].Controls,
theType));
}
return(toRet);
}
Using this mechanism, the author need only specify the URL of the Speech Server in one place (the web.config file), and the URL in the Speech Controls property builder in every instance can be left blank, unless the author wishes to override the global setting.
A more advanced author might wish to move this code to a separate helper class or to implement a new class derived from System.Web.UI.Page, so that it would not be necessary to duplicate this work on each page.
Determining Whether Input is Speech or DTMF (Touch-Tone)
QA controls support both speech and DTMF (dual-tone multi-frequency) input modes simultaneously. It is often important to know which mode the user is using when there is a noreco event (when the speech input is not recognized). When the noreco event is from DTMF input, it is also useful to retrieve the digits and render the prompts accordingly. There is a significant difference in the way the prompt should be rendered, depending on whether the noreco event was related to speech input or DTMF input. For example, in the case of a speech-related noreco event, the prompt can say something like: “sorry, I did not understand you.” However, this prompt does not make sense if it is a DTMF noreco because in DTMF mode the digits are always understood, while they may be incorrect or unexpected.
QA controls provide two client-side OnClientNoReco properties: one for speech and one for DTMF. It is possible to provide a different event handler for each one of them. For example, in the property builder for the QA control, under DTMF properties, the author can provide an event handler for the OnClientNoReco property. In the following example, assume there is a QA control called QA1, and the function name for the DTMF OnClientNoReco is “DTMFNoReco” in the property builder. The following code will appear in the HTML view of the Web form.
<Dtmf OnClientNoReco=“DTMFNoReco” ID=“QA1_Dtmf”>
After the DTMFNoReco function is added, if there is a DTMF noreco event, the function DTMFNoReco will be called, and it will be apparent that this is a DTMF noreco event.
According to the SALT (Speech Application Language Tags) specification version 1.0, section 2.3.2.2, the DTMF object has a text property which is updated on every onkeypress, onreco, and onnoreco event. This makes it possible to retrieve the digits that the user enters all the way to the first key that goes wrong. For example, the user enters 12354 as a PIN number, and the correct PIN is 12345. Here the fourth digit went wrong, and the DTMF text property will capture the digits 1235.
Using the code given previously, the DTMF object ID is 'QA1_Dtmf', see the following implementation:
</form&rt;
<script>
function DTMFNoReco()
{
LogMessage(“DTMF NoReco”, QA1_Dtmf.text);
}
</script>
Detecting User-Initiated Hang-Ups
How is it possible to detect a user-initiated hang-up in a speech application? If an application is actively running (that is, a QA control is running as part of a dialog), and the end user initiates a disconnect — for example, clicking the hang up button on the Telephony Application Simulator — is there any way to detect the user-initiated disconnect in client-side script?
When an end user initiates a hang-up while the application is still running, you can use RunSpeech APIs to detect it. Specifically, you can use the RunSpeech.OnUserDisconnected event as described below.
When a user initiates the hang-up, the SMEX ConnectionClearedEvent is activated, which causes RunSpeech.OnUserDisconnected to be called.
You can register the RunSpeech.OnUserDisconnected event in your script in any function. One approach is to use the AnswerCall control's OnClientConnected event to register the disconnect event. If you have a DisconnectCall control in your application that initiates the disconnect, then the OnClientDisconnected event is activated. However, if the user initiates the disconnect before the DisconnectCall control gets activated, then the RunSpeech.OnUserDisconnected event is activated.
Following is an example of this approach to detecting disconnects.
function AnswerCal1_OnClientConnected( sender, callId, callingDevice, calledDevice )
{
// Call accepted successfully, register for user-initiated disconnects
RunSpeech.OnUserDisconnected = OnUserDisconnected;
}
function OnUserDisconnected( activeObject )
{
// Handle user-initiated disconnects here
}
function DisconnectCall1_OnClientDisconnected( sender )
{
// Handle application-initiated disconnects here
}
Copying and Pasting Speech Controls Between Pages
When a Speech Control is copied from one .aspx page to another that does not already have a Speech Control on it, the Speech Control displays the message Error Creating Control. This is because the required @ Register directive is not added when manually copying and pasting Speech Controls. To avoid the error, use the Toolbox to add the first Speech Control to an .aspx page, before copying and pasting additional Speech Controls from other pages.
Copying Code-Behind Files Between Projects
When copying an .aspx file from one project to another, the code-behind file for the page will compile and run in the new project, provided the project type for the source and target projects is the same. It is possible to copy .aspx and .vb code-behind files between Visual Basic speech Web application projects; and .aspx and .cs code-behind files between C# speech Web application projects. However, if the project types are mixed and Visual Basic files are copied to a C# project or vice versa, the code in the code-behind file in the target project must be re-written in the appropriate language before it will compile.