Course 1 / Lecture 7

How to develop a softphone in C#

How to handle simultaneous calls effectively

Here you can learn how to managing simultaneous calls. This example requires the knowledge of SIP registering and the receiving of phone calls with the softphone. To learn these, you can visit the previous examples:

Making and accepting calls

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.


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.


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.


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;
    mediaConnector = new MediaConnector();
    mediaConnector.Connect(mp3Player, phoneCallAudioSender);


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;

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)
        else if(e.State.IsCallEnded())

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)

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

void OnCompleted()
    var handler = Completed;
    if (handler != null)
    	handler(this, EventArgs.Empty);


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)


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.


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