Code Repo    |     RSS
MD's Technical Sharing



Tuesday, April 8, 2008

Design an IVR System on Windows Mobile

The architecture of TAPI on Windows CE (which is the core of windows mobile devices), per se, support DTMF sending and detection. However, in reality, it is not possible to rely on TAPI's DTMF capabilities to develop an IVR system for windows mobile devices. This writing explains why.

First, sending DTMF is straight forward. One can use lineGenerateTone to send DTMF and this works on most phones. To detect DTMF, there are 2 approaches:

  1. Approach 1 seems straight forward. Use lineMonitorDigits on the open line to be informed when DTMF is received during an active call. However, on most tested phones, lineMonitorDigits fails, indicating it's not implemented by the OEM. This, however, works on a desktop with a modem attached.

  1. Perform analysis of the call audio stream and use algorithm to detect DTMF. To do this, we must use lineGetID to retrieve a handle to the "wave/out" or "wave/in" device of the active call and work on the audio stream coming from these devices. However, in the first place, lineGetID fails, simply because the device does not make the audio stream available to TAPI. There is possibly a physical separation layer between the phone audio hardware and the telephony logic. Some sites suggest that lineGetID when used to get wave devices require that the line be opened in LINEMEDIAMODE_AUTOMATEDVOICE. However, when tested, lineOpen in automated voice mode fails with LINEERR_INVALMEDIAMODE, suggesting that TSP does not support this.

There is yet, another crude but working approach, which is, to turn on the loudspeaker, to the max. volume, during an active call. The microphone will pick up sounds from the speaker. The code will then be able to record whatever sound coming from the microphone, and detect any DTMF. This is a bit unreliable as it will pick up a lot of noises from the environment and the DTMF algorithm must be designed to work with a wide range of signal-to-noises ratios (SNR). However, in a silent environment, it does work. The attached solution demonstrates this idea. There are 2 projects in the solution
  • IVR_Lib_Dotnet project: The library used by the main projects. It contains functions to record voice from the phone speaker as well as playing back.
    • TAPI.cs: C# wrapper for TAPI
    • Wave folder: supports playing/recording of Wave file from .NET. The classes was taken from .NET Compact Framework Sample: P/Invoke Library
    • DTMF folder: support detecting DTMF from a wave stream using the the Goertzel Algorithm. This contains the following file
      • Goertzel.cs: the pure Goertzel algorithm
      • DTMFDetector.cs: algorithm to detect DTMF from a wave recording.
      • DTMFCapture.cs: this uses a timer to keep on scanning a WaveIn stream for any possible DTMF. It calls DTMFDetector.cs as often as the timer interval
  • DTMF_Detector: this project is only for testing of the DTMFDetector.cs class. Provide it a WAVE file and it will report any DTMF found in the file. Only 1 DTMF per file is supported.
  • TAPI_IVR_Demo: the main project. It contains 2 forms
    • TAPI_Test.cs: for testing of the TAPI.cs class, including making calls and hanging up.
    • IVRDemo.cs: the main IVR system.
To detect DTMF, a new instance of the class must first be initialized:

wi = new WaveIn();
myCapture
= new DTMFCapture(wi);

//raise when a key is pressed
myCapture
.DTMFKeyPressed += new DTMFCapture.DTMFEventHandler(myCapture_DTMFKeyPressedOption2);

//raised when timeout waiting for DTMF
myCapture
.Timeout += new EventHandler(myCapture_Timeout);

//start DTMF monitoring
myCapture
.StartMonitoring();
To play a WAV file:
playWave(getAppDir() + "\\recordings\\voicemail.wav", 2000);
To perform recording:
saveRecord = true;
myCapture
.StopMonitoring();
wi
= new WaveIn();
wi
.Preload(60 * 1000, 1024);

wi
.Start();

Download source code

The attached project is only meant to be used as a proof-of-concept IVR application running on Windows Mobile. The approach that the project takes makes it impossible to use it for any serious purposes other than running a few test calls.


References:

1 comment:

Note: Only a member of this blog may post a comment.