Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to create a multi-level IVR (Interactive Voice Response) menu system in C#

0.00/5 (No votes)
31 Mar 2014 1  
It presents step-by-step how to create an advanced multi-level VoIP IVR in C# in order to extend your basic menu system and to improve your whole customer service.

Introduction

An IVR (Interactive Voice Response) menu system offers the flexibility to automate the business processes on the phone. Due to the customizable menus and the variety of call routing options, customer queries can be managed effectively and easily. Customers can access various services over the IVR without speaking with the call center agents. As it helps in improving the agent’s productivity, an IVR menu system can help in improving the whole call center as well.

Background

A couple of weeks ago I have created a basic IVR menu system that can receive and manage the incoming calls without any human intervention. It has been extended with blind transfer functionality. Concerning to the fact, that in today’s business world the more advanced multi-level IVRs are commonly used, I improved my IVR solution.

’Multi-level’ means that the caller can be navigated through more menu levels by using DTMF signalling – as it can be seen in Figure 1. In this brief article I am going to explain how to develop an advanced multi-level IVR.

Figure 1: A simple example on how a multi-level IVR works

Prerequisites

My solution is based on my previously created IVR project. The first steps (such as settings in your IDE or the implementation the necessary classes) have not been described in this tip, because all the required initial tasks have been explained in details in my previous tutorial. It can be found at the following link:

How to build a basic IVR (Interactive Voice Response) menu system in C# to improve your call center: http://www.codeproject.com/Articles/746512/How-to-build-a-basic-IVR-Interactive-Voice-Respons

  • I have built my IVR application in C#, so you need an IDE (Integrated Development Environment) supporting this programming language, such as Microsoft Visual Studio.
  • .NET Framework installed on your PC is also needed.
  • As my IVR system is based on VoIP technology, you need to add some VoIP components to the references in your IDE in order to define the default behaviour of the IVR in the simplest way. Since I have been using Ozeki VoIP SIP SDK for VoIP developments, I used the prewritten VoIP components of this SDK. So it also need to be installed on your PC.

Writing the code

In my project 4 classes have been used: Softphone.cs, CallHandler.cs, Program.cs, NewCallHandler.cs. To implement the multi-level IVR solution first you need to conduct some modifications in the CallHandler class. Let’s see step-by-step what you need to do.

Modifications in the CallHandler.cs class

In my basic IVR system I have built only one menu level in which the customer can be transferred to a live agent after pressing 3. Since I am going to develop a multi-level system, now it is not required to implement this last section ('The implementation of the blind transfer'), because you will need this feature later (in the last menu level). If you have already created that blind transfer functionality, open the CallHandler.cs class and delete the Blind transfer section of the call_DtmfReceived() method.

To create a multi-level system, your IVR has to be able to navigate the caller to the next menu level. For this purpose you need to create a method – it is called LowerMenu(). It will manage the navigation through the menu levels (Code example 1).

void call_DtmfReceived(object sender, VoIPEventArgs<DtmfInfo> e)  
{  
     DisposeCurrentHandler();  
     switch (e.Item.Signal.Signal)  
     {  
           case 0: break;  
           case 1: TextToSpeech("Product XY has been designed for those software developers who especially interested in VoIP developments. If you prefer .NET programming languages, you might be interested in Product XY."); break;  
           case 2: MP3ToSpeaker(); break;  
           case 3: LowerMenu(); break;  
     }  
}   

Code example 1: LowerMenu() method in the call_DfmfReceived() method

In the LowerMenu() method, first you need to unsubscribe from all of your actual events (CallStateChanged and DtmfReceived events of the call; Elapsed event of the greetingMessageTimer).

Now you need to create a new class that is called NewCallHandler. It will manage the calls in the lower menu level.

Having done this step, go back to the LowerManu() method and create an object from the new class. Call two methods (BlindTransferNumber(), Start()) with this object and subscribe on the Completed event of that. (You can read about the implementation of these methods below in the ’Implementing the NewCallHandler.cs class’ section (Code example 2)).

private void LowerMenu()  
{  
      call.CallStateChanged -= call_CallStateChanged;  
      call.DtmfReceived -= call_DtmfReceived;  
      greetingMessageTimer.Elapsed -= greetingMessageTimer_Elapsed;  
  
      NewCallHandler newCallHandler = new NewCallHandler(call);  
      newCallHandler.BlindTransferNumber(blindTransferNumber);  
      newCallHandler.Completed += newCallHandler_Completed;  
      newCallHandler.Start();  
}  

Code example 2: The implementation of the LowerMenu() method

The newCallHandler_Completed() method can be used to subscribe back to the events and start the greeting message when the caller press a DTMF button to finish and complete the lower menu and return to the main level (Code example 3).

void newCallHandler_Completed(object sender, EventArgs e)  
{  
     call.CallStateChanged +=call_CallStateChanged;  
     call.DtmfReceived +=call_DtmfReceived;  
     StartGreetingMessage();  
     greetingMessageTimer.Start();  
}  

Code example 3: The newCallHandler_Completed() method

Implementing the NewCallHandler.cs class

Let’s see how to complete the NewCallHandler.cs class.

If the caller enters into this submenu – in my example by pressing 3 – he/she will hear a greeting message and the selectable menu items through the speaker. In my example the caller can choose from two options: transferring to a specified phone number or returning to the main menu.

The call_DtmfReceived() method (Code example 4) can be used to handle the caller’s choice in the second menu level. If the caller presses 1, the system will transfer the call to a predefined phone number. In order to be able to navigate the caller back to the main manu, you need to create and also call a method a method. It is called Return().

void call_DtmfReceived(object sender, VoIPEventArgs<DtmfInfo> e)  
{  
      DisposeCurrentHandler();  
      switch (e.Item.Signal.Signal)  
      {  
          case 1:  
             {  
                 if (blindTransferNumber == "0")  
                 {  
                      TextToSpeech("You did not add any number for blind transferring!");  
                      break;  
                 }  
                 else  
                 {  
                      call.BlindTransfer(blindTransferNumber);  
                      break;  
                 }  
             }  
          case 2: Return(); break;  
      }  
} 

Code example 4: The call_DtmfReceived() method

In this project, the Return() menthod can be used when the caller presses 2. This action indicates that he/she would like to return to the main menu. In this case it is necessary to unsubscribe from the call_DtmfReceived() method, dispose the current handler, close the greetingMessageTimer and invoke the Completed event (Code example 5).

private void Return()  
{  
     call.DtmfReceived -= call_DtmfReceived;  
     DisposeCurrentHandler();  
     greetingMessageTimer.Close();  
  
     var Handler = Completed;  
     if (Handler != null)  
        Handler(this, EventArgs.Empty);  
}   

Code example 5: The Return() method

To handle the changes of the call, the call_CallStateChanged() method can be used. If the caller presses 1 – that is selects the blind transferring option – the call state changes to ’Transferring’ and the system need to dispose the current handler and stop the greetingMessageNumber. When the call state will be ’InCall’ again, the IVR restarts this timer (Code example 6).

void call_CallStateChanged(object sender, VoIPEventArgs<CallState> e)  
{  
     if (e.Item == CallState.InCall) greetingMessageTimer.Start();  
     if (e.Item == CallState.Transferring) DisposeCurrentHandler(); greetingMessageTimer.Stop();  
}  

Code example 6: The call_CallStateChanged() method

Summary

To sum it up, building and improving an IVR can be quite easy and fast if you use previously written VoIP components. Handling a huge amount of simultaneous calls – especially among large companies – can be crucial in order to be able to serve your customers’ needs in the highest possible level. A multi-level IVR menu system can manage numerous simultaneous calls while automating many call center tasks. Due to the blind transferring functionality the customer can be transferred to a live agent easily and automatically.

References

Useful source (initial development tasks):

Theoretical background:

Download the necessary software:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here