High performance VoIP SDK for .Net developers

VoIP SIP SDK

WinForms DTMF IVR

Download: 13_DTMF_IVR_WinForm.zip

This article is a guide about Ozeki WinForms DTMF IVR Example program in relation with Ozeki VoIP SIP SDK. After reading through this page you will be fully familiar with all the essential terms concerning this DTMF IVR program and what you will need for creating your own solution using Ozeki VoIP SIP SDK.

Introduction

The Interactive Voice Response (IVR) systems are programs that simply play audio streams into the call after answering it and navigate the caller customer in a so-called IVR tree structure until the customer gets to the answer they seek or the tree gets to a dead end. The customer can navigate in the IVR tree using different methods but the simplest way is using the numeric keypad and sending DTMF signals.

DTMF is a signaling system that is used in telephoning for sending simple information from one end to another. Every keypad button on a telephone has a special frequency signal that is transferred into the call when the person presses the button. The signal of the given buttons is standard, so it can be perfectly used for getting information from the other end.

When you want to build a DTMF navigation IVR system, you will need to capture audio files like: "If you want to get information about our newest products, please press 9." When a customer presses 9, the IVR tree will recognize the DTMF signal of 9 and navigates to the proper tree branch. The whole concept is based on this simple idea.

The following example source code uses the background support of Ozeki VoIP SIP SDK so you need to download and install it on your computer before you can work with the example program. The program was written in Visual Studio 2010 and using C# programming language, therefore you also need to have those.

The Source Code

This sample program uses more methods for presenting the IVR tree information. It play a welcome.wav file when it answers the call but after that the program uses text to speech conversion that is provided by Ozeki VoIP SIP SDK for the tree navigation.

In Figure 1 you can see a snippet from IVRSystemSample.csv file that shows the navigation tree information.


Figure 1 - The IVR navigation tree concept

The most important part of the example program is the IVREngine class that is the basis of the whole system. In this case the Windows Forms GUI is only a window that basically only shows the IVR tree system.

Code 1 shows the constructor of the IVREngine class. This method realizes the softphone function, initializes a softphone and a phone line and registers it to the PBX using the SIP account that comes as a parameter.

public IVREngine(SIPAccount account)
{
    activeCalls = new List<CustomerCall>();
    menuBuilder=new IVRMenuBuilder();
    Logger.Open(LogLevel.Notice);
    softPhone = SoftPhoneFactory.CreateSoftPhone(SoftPhoneFactory.GetLocalIP(), 5060, 8000, 5060, Path.Combine(Environment.CurrentDirectory,"log.txt"));

    softPhone.IncomingCall += new EventHandler<VoIPEventArgs<IPhoneCall>>(softPhone_IncomingCall);
    line = softPhone.CreatePhoneLine(account,
                              new NatConfiguration(NatTraversalMethod.None),
                              TransportType.Udp);
    line.PhoneLineStateChanged += new EventHandler<VoIPEventArgs<PhoneLineState>>(line_PhoneLineStateChanged);
    softPhone.RegisterPhoneLine(line);

}

Code 1 - The basic initialization

The basic softphone functions are the same as in the case of any softphone applications. There are some standard events to be handled, like the incoming call, the phone line information etc. Basically these work the same way as in a simple softphone.

The significant difference from a softphone can be seen in the call's events, that are not the standard ones, but two other, the closing and the action notification events.

The IVR menu is built up in the IVRMenuBuilder class. This class creates a tree structure that will be used for navigation when an incoming call arrives. Code 2 shows how the tree is built up.

IVRMenuBase BuildTreeAndGetRoots(List<IVRMenuElement> actualObjects)
{
    Dictionary<int, IVRMenuBase> lookup = new Dictionary<int, IVRMenuBase>();
    actualObjects.ForEach(x => lookup.Add(x.id, createMenuItem(x)));
    foreach (var item in lookup.Values)
    {
        IVRMenuBase proposedParent;
        if (lookup.TryGetValue(item.ParentId, out proposedParent))
        {
            item.Parent = proposedParent;
            proposedParent.ChildMenus.Add(item);
        }
    }

    foreach (var item in lookup.Values)
    {
        if (item.ParentId==-1)
        {
            Debug.WriteLine(item.Introduction);
            return item;
        }
    }
    return null;
}

Code 2 - Building up the IVR menu

The tree structure is built up in a standard way. The building method calls the createMenuItem method that generates the menu items from the actual menu information (Code 3). The menu item type can be wav file playing, text to speech conversion or voice recording.

private IVRMenuBase createMenuItem(IVRMenuElement element)
{
    IVRMenuBase currentmenu=null;

    switch ((IVRMenuType)element.menutype)
    {
        case IVRMenuType.Playback:
            currentmenu = new IVRMenuFilePlayback(element);
            break;
        case IVRMenuType.TextToSpeech:
            currentmenu = new IVRMenuTextToSpeech(element);
            break;
        case IVRMenuType.VoicRecording:
            currentmenu = new IVRMenuVoiceMessageRecorder(element);
            break;
        default: throw new Exception(string.Format("'{0}'is unknown menu type.", element.menutype));
    }
    return currentmenu;
}

Code 3 - Creating IVR menu items

If you want to use the csv file for creating the IVR menu, you need to call the method shown in Code 4. This code actually uses the .csv file that was shown above.

private List<IVRMenuElement> GetIVRSystemFromCVSFile()
{
    try
    {
        List<IVRMenuElement> elements=new List<IVRMenuElement>();
        using (StreamReader sr = new StreamReader(Path.Combine(Environment.CurrentDirectory,  "DataBase\\IVRSystemSample.csv")))
        {
            String line;
            while ((line = sr.ReadLine()) != null)
            {
             // MessageBox.Show(line);
                IVRMenuElement cur = GetMenuElementFromString(line);
                if (cur !=null)
                {
                    elements.Add(GetMenuElementFromString(line));
                }

            }
        }
        return elements;
    }
    catch (Exception e)
    {

        MessageBox.Show("The file could not be read: IVRSystemSample.csv.");
        return null;
    }
}

Code 4 - Creating IVR menu from a .csv file

The other classes of the project define the actual working methods of the IVR system, like the text to speech functionality or the .wav playback. These classes simply use the Ozeki provided tools to perform these functions when the IVR navigation gets to a point when a decision is made upon the DTMF signals.

The CustomerCall class handles the actual incoming calls and the DTMF signals that comes from the customer's phone. The customer's call need to be subscribed for the DTMFReceived event that will be handled in the method shown in Code 5. The event handler calls the actual menu element's CommandReceived method. This method is implemented in every menu element types' classes. The navigation is made according to the DTMF signal that was received.

void PhoneCall_DtmfReceived(object sender, VoIPEventArgs<DtmfInfo> e)
{
    DtmfInfo dtmfInfo = e.Item;

    OnNotifyAction(string.Format("{0} sent the following DTMF sign: {1}", PhoneCall.DialInfo, dtmfInfo.Signal.Signal));
    currentMenu.CommandReceived(dtmfInfo.Signal.Signal);
}

Code 5 - Receiving a DTMF signal

The CustomerCall class also defines the call state change event handler for the incoming call (Code 6). This method only defines special action for the established call (InCall) and the completed call states. In any other cases it closes the call.

In case of the InCall state the IVR menu starts to be played and the navigation process can be started. The call completion, of course, ends all kind of communication a closes the lines.

void PhoneCall_CallStateChanged(object sender, VoIPEventArgs<CallState> e)
{
    switch (e.Item)
    {
        case CallState.InCall:
            OnNotifyAction(string.Format("Caller '{0}' is in welcome menu.", PhoneCall.DialInfo));
            currentMenu.StartIntroduction();

            break;
        case CallState.Completed:
            OnNotifyAction(string.Format("{0} hanged up the call.",PhoneCall.DialInfo));
            currentMenu.StopIntroduction();
            Close();
            break;
        case CallState.Error:
        case CallState.Rejected:
        case CallState.Cancelled:
        case CallState.Busy:
            Close();
            break;
    }
}

Code 6 - Handling the call states

You can see that building an IVR tree has a very simple concept that can be easily done by using the background support of Ozeki VoIP SIP SDK. In this case the IVR tree used more methods for informing the customers, so you could see that you can play audio files or simply use, for example, text to speech conversion for this purpose. Now, you are familiar with the basic concepts and can try the IVR system and create your own solution according to your needs.

This article introduced you the basic knowledge about Ozeki Winforms DTMF IVR program and showed how Ozeki VoIP SIP SDK can help you to fulfill your wishes about this topic. If you have read through this page carefully, you already have all the knowledge you need to start on your own solution.

As you are now familiar with all the terms concerning this topic, now it is time to take a step further and explore what other extraordinary solution Ozeki VoIP SIP SDK can provide to you.

If you have any questions or need assistance, please contact us at info@voip-sip-sdk.com

You can select a suitable Ozeki VoIP SIP SDK license for your project on licensing page

Related Pages