SMS Gateway software
Ozeki brings you outstanding
SMS Gateway technology. Use our SMS Server products on Windows,Linux, or Android

Developers can use our C# SMS API to send SMS from C#.Net. The C# SMS API comes with full source code

The ozeki PHP SMS gateway software can be used to send SMS from PHP and to receive SMS usig PHP on your website

SMPP SMS Gateway
SMS service providers use our SMPP gateway solution, that offers a high performance SMPP server and SMPP client gateway with amazing routing capabilities

  Course 2 / Lecture 8

How to build a VoIP PBX in C#

How to create call queue in your VoIP PBX

Ozeki VoIP SIP SDK provides professional technology to create a virtual PBX extension for call queues. Call queues can be used for such scenarios in which you have more incoming calls than agents and as a result you can have further callers on hold listening to music while your agents handle the calls they are in. Read this article and use the source codes to start implementing this solution efficiently.

Download: call-queue.zip

At corporations, it is a quite frequent issue that the number of incoming calls is more than the number of available agents. The example below illustrates how the incoming calls can be put on a call queue and how you can have the waiting callers listen to the music of your choice until their calls are transferred to agents.

What knowledges would you need?

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

  • Simple VoIP PBX: you can learn how to start to develop your own PBX with Ozeki SIP SDK.
    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...


Please be informed that PBX development support is available in Ozeki VoIP SIP SDK from version 10.0. You can download the latest Ozeki SIP SDK version from the download page.

Private Branch Exchange (PBX) systems are used for phone line establishment between communicating end points, regardless of wired, mobile or VoIP technology they use. The end points are registered to the PBX through a SIP account and are called extensions. The PBX can also have virtual extensions that are not attached to physical or software communication solutions but used for some special purposes.

The following program code uses the unique background support of Ozeki VoIP SIP SDK, therefore you will need to download and install Ozeki SIP SDK on your computer before starting to use the program code. You will also need to have Visual Studio 2010 or compatible IDE and .NET Framework installed on your system, as the program code below is written in C# language.

Ozeki VoIP SIP SDK provides professional technology to create a virtual PBX extension for call queues. Call queues can be used for such scenarios in which you have more incoming calls than agents and as a result you can have further callers on hold listening to music while your agents handle the calls they are in.

Call queue source code analysis in C#

For simplicity's sake, let's just say that there is only one agent taking calls. In this case, if more than one call, for instance two calls, come in, the agent will not be able to answer both calls at the same time. As a result, the other caller would receive a Busy tone from the system. This issue can be resolved by using call queue. This way, when there is a second incoming call yet still one agent, this second call can be received with the help of call queue. While the second caller waits for the call to be transferred to the agent, the caller can either listen to a previously created mp3 file or can be notified that the call will be answered soon.

The virtual call queue extension contains 2 classes: The CallQueueExtension and the CallQueueCallHandler class.

In the CallQueueExtension class you need the following objects:

IExtensionContainer extensionContainer;
List<CallQueueCallHandler> callHandlers;
ICallManager callManager;
List<string> members;
object sync;

The constructor has a list parameter. In this list, you should provide the phone numbers of those agents who will take the calls.

public CallQueueExtension(string id, IExtensionContainer extensionContainer, ICallManager callManager, List members)
	sync = new object();
	callHandlers = new List<CallQueueCallHandler>();
	ExtensionID = id;
	this.extensionContainer = extensionContainer;
	this.callManager = callManager;
	this.members = members;

The calls can be handled with the help of the CallQueueCallHandler class. This class works with call queues just like it deals with simultaneous calls, since these calls are similar to each other. This means that each and every call will be a separate CallQueueCallHandler object.

The OnCalled method handles the incoming calls. For these calls, you should create a call object using the createIncomingPBXCall method of callfactory.

The CallQueueCallHandler objects are stored in the callQueueHandler variable, then these will be collected in the callHandlers list.

If there is only one element in this list, i.e. there is only one incoming call in the queue, you can call the Start() method, which starts a timer.

public void OnCalled(IPBXCall call, IncomingCallParams callParams)
	var callQueueHandler = new CallQueueCallHandler(call, callManager, extensionContainer, members);
	callQueueHandler.Completed += CallHandlerCompleted;

	if (callHandlers.Count == 1)

If the call state is Completed, then the CallHandlerCompleted method is called. If that was the first call on the callHandlers list, it will be removed. After that if there is more than one call, the Start() method should be called for the next call.

void CallHandlerCompleted(object sender, System.EventArgs e)
	lock (sync)
		var callHandler = (CallQueueCallHandler)sender;

		if (callHandlers[0] == callHandler)

			if (callHandlers.Count >= 1)
				var nextCallHandler = callHandlers[0];

The Start() method is in the CallQueueCallHandler class. This starts the timer under the calls.

public void Start()
	if (call.CallState.IsCallEnded())


When this timer elapsed (in this example it is one second) the timer_Elapsed method will be called. This method examines the state of the given call and if that state is not InCall, the method will use the ActiveSession method of the callManager to check which agents are in call. The names/extension numbers of the available agents will be stored on a list. The next step is to select from this list who have logged into the system. You can look into this with the help of the extension container (extensionContainer.GetExtension()).

If one of the agents is not in a call yet logged into the system, i.e. can be found in the PBX, the incoming call can be transferred to that agent. You can do so by using the BlindTransfer method.

void timer_Elapsed(object sender, ElapsedEventArgs e)
	if (!call.CallState.IsInCall())

	var memb = new List<string>(members);

	foreach (var activeSession in callManager.ActiveSessions)
		var callee = activeSession.CalleeInfo.Owner.ExtensionID;
		var caller = activeSession.CallerInfo.Owner.ExtensionID;


	foreach (var member in memb)
		if (extensionContainer.GetExtension(member) != null)

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 PBX development on Pricing and licensing information page

Related Pages

More information