Course 1 / Lecture 7

VoIP softphone: How to handle more than one call in the same time

Download: parallel-calls.zip

Handling simultaneous calls poster image

Why do we need to handle simultaneous calls?

A softphone that can only manage one call at a time falls over the moment a second caller reaches it while the first call is still active, either dropping the new call or blocking it entirely. Real deployments such as IVR lines, call queues, or shared extensions routinely receive several inbound calls within the same short window, so each one needs its own independent state, media stream, and lifecycle. Without a per-call handling model, one caller's actions (going on hold, hanging up) could accidentally interfere with a completely unrelated call happening at the same time.

Why do we need to handle simultaneous calls
Why do we need to handle simultaneous calls

What is concurrent call handling?

Concurrent call handling means the softphone can accept and manage several calls at once, with each call's state tracked independently of the others. In this example, every incoming call is wrapped in its own CallHandler instance, which owns that call's media objects and event subscriptions, so hanging up or finishing one caller's audio has no effect on any other active call. The calls are kept in a shared list purely so the application can track and clean them up, not to coordinate their behavior.

What is concurrent call handling
What is concurrent call handling

How does it work?

Each time the softphone raises its IncomingCall event, the program wraps that call in a new CallHandler and adds it to a shared list. The handler answers the call, attaches its own MP3StreamPlayback and PhoneCallAudioSender, and starts playing audio the moment the call is answered. When the mp3 finishes or the call ends, the handler hangs up, disposes its own media objects, and removes itself from the list, leaving every other active call completely untouched.

How simultaneous call handling works
How does it work

In this tutorial example we will learn the followings:

  • How to manage simultaneous calls

What knowledges would you need?

To fully understand this guide, you might need to study the following chapters first:

  • SIP registration: you can learn how to begin softphone developing and how to be able to register to a pbx with a sip account.
    Learn more...
  • Managing media handlers: you can find here examples and a simple guide about how to be able to use, connect and manage different media handlers, and how can you attach them to calls.
    Learn more...
  • Making and accepting calls: from this guide you can learn how can your softphone make and accept calls, and handle the calls' states.
    Learn more...
  • Controlling the call: you can learn how to control calls, for example: how to transfer them to another party.
    Learn more...

Please note that, only the softphone's new elements will be introduced here. You can find the registration's process and the needed elements for that at the first example, called "SIP Registration". You can find how to make and accept calls, how to begin to handle the call's states in the second example, called "Making and accepting calls".

This example using three classes:

  • Softphone.cs
    The softphone's implementation goes here, all of it's events, methods, functions, variables.
  • CallHandler.cs
    This class is for handling the incoming calls.
  • Program.cs
    This is a class with the Main() method, this class controls the console window, interacts with the user, by using softphone and callhandler objects.

Softphone.cs

This class is used to introduce how to declare, define and initialize a softphone, how to handle some of the Ozeki VoIP SIP SDK's events and how to use some of that's functions. In other words, we would like to create a "telephone software", which has the same functions (or much more), as an ordinary mobile (or any other) phone. In the Program.cs class we will use this class to create a new softphone, so we can use the functions, we can listen to the events placed here.

CallHandler.cs

This class is used to managing the incoming calls. If there is an inbound call, then the caller will hear a sample mp3 song through the speaker. If there is another incoming call while the previous caller is still in call, the person initiating the incoming call will listen to the sample mp3 file. If multiple calls come in, these callers will listen to the same mp3 song. At what point they are in the mp3 file depends on when a given caller called. This means that each and every call is handled by a separate CallHandler class and to every call such a class will be assigned locally. This way, the states of all simultaneous calls can be determined separately, thus easily.

Objects

You need to create some objects to manage the incoming calls and the MP3 player. These are the call, mediaConnector, mp3Player and phoneCallAudioSender objects from the ICall interface and the MediaConnector, MP3StreamPlayback and PhoneCallAudioSender classes. You can find more details about these features of the Ozeki VoIP SDK here.

ICall call;
MediaConnector mediaConnector;
MP3StreamPlayback mp3Player;
PhoneCallAudioSender phoneCallAudioSender;

public event EventHandler Completed;

The constructor of the class gets an ICall type parameter and it makes the basic setups for the class. Initializes the necessary objects and attaches the phoneCallAudioSender to the call. Besides this creates an MP3StreamPlayback object with file path parameter and connects it to the PhoneCallAudioSender via the mediaConnector.

public CallHandler(ICall call)
{
	this.call = call;
    phoneCallAudioSender = new PhoneCallAudioSender();
    mp3Player = new MP3StreamPlayback(@"..\..\test.mp3");
    mp3Player.Stopped += mp3Player_Stopped;
    phoneCallAudioSender.AttachToCall(call);
    mediaConnector = new MediaConnector();
    mediaConnector.Connect(mp3Player, phoneCallAudioSender);
}

Methods

A method is a code block that contains a series of statements. One of the most important methods of this class is the Start() method because that will be called by the main method of the program. In this method you can subscribe on the CallStateChanged event and accept the call. The call state change event is one of the most important events to notice. This informs both the server and the client about a change in the call state.

public void Start()
{
    call.CallStateChanged += call_CallStateChanged;
    call.Answer();
}

The call_CallStateChanged method examines whether the call is in Answered state or not. If it is, the streaming of the sample mp3 song starts. (Start() method)
Otherwise, when the call is over,the OnCompleted() method will be called.

void call_CallStateChanged(object sender, CallStateChangedArgs e)
{
	if (e.State == CallState.Answered)
    {
    	mp3Player.Start();
    }
        else if(e.State.IsCallEnded())
        	OnCompleted();
}

As soon as the sample mp3 song is over, the mp3Player_Stopped method is called. This method will hang up the call and calls the OnCompleted() method.

        
void mp3Player_Stopped(object sender, EventArgs e)
{
	call.HangUp();
    OnCompleted();
}

The OnCompleted() method terminates all connections and the mp3Player using the Dispose() method.

void OnCompleted()
{
	mediaConnector.Dispose();
    mp3Player.Dispose();
    
    var handler = Completed;
    if (handler != null)
    	handler(this, EventArgs.Empty);
}

Program.cs

This class will introduce the usage of softphone and callHandler objects and handles the console.

The softphone_IncomingCall method

If we would like to be notified when there is an incoming call, we need to set an event for this purpose. This is the IncomingCall event. When the event notifies that there is a call waiting to be accepted, in this case the call has to be accepted by the IVR system. In this method there is a callHandler object for managing the methods of the CallHandler class. If there is an incoming call, then call Start() method of the CallHandler.

static void softphone_IncomigCall(object sender, Ozeki.VoIP.VoIPEventArgs<Ozeki.VoIP.IPhoneCall> e)
{
     Console.WriteLine("Incoming call!");
     var callHandler = new CallHandler(e.Item);
     callHandler.Completed += callHandler_Completed;

     lock (callHandlers)
           callHandlers.Add(callHandler);

     callHandler.Start();
}

We add the callHandlers to a list. Thus, they will be stored in a stack. This way, the termination of the callHandlers by the garbage collector while they are still in use can be avoided.

Conclusion

After reading this documentation and studying the source code, you must be familiar about how to managing simultaneous calls.

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

Related Pages


More information