Course 1 / Lecture 4

How to develop a softphone in C#

How to control calls using SIP messages


You can learn here how to control the call, such as putting the call on hold, taking the call off hold, transfering the call etc.
This example requires the knowledge of SIP registering and the making of phone calles with the softphone. To learn these, you can visit the previous examples:

In this tutorial example we will learn the followings:

  • How to put the call on hold
  • How to take the call off from hold
  • How to hang up the call
  • How to redial a number
  • How to transfer the call

What knowledge 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...

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".

Source code analysis

To understand the source code, the softphone's functions and their usage, we need to discuss the details.

What is Softphone.cs used for?

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.
Please note that, this softphone is not able to accept calls. That function is removed in purpose to reduce the code's size, and to be more understandable.
We have no new objects or variables to introduce in this example.

How to handle the call's states?

There are some changes in the method which handles the call's states. We are attaching the media handlers to the call object only once, so the ideal state to do this is the "Answered" state, since it occurs only once per a call.


When the call's state is "LocalHeld", we are stopping the devices. Please note that, if the call is being taken off from hold, then we'll enter into the "InCall" state (again), so we need to start the devices there as well. Since the call can enter into the InCall state several times during a call, this is the reason why we are attaching the media handlers at the "Answered" state.

Please also note that, the hold function notifies the other client to do not send data (in our case: do not talk into the microphone). In the most of the cases we do not want our voice to be heard either by to other party, while we are holding the call, so we don't need the microphone or the speaker either, this is the reason why did we stop them.

Hot to putt the call on hold, and take off from hold?

In this method, we are checking first, if we have an active communication or not (is the call object "null" or not), then we can start to handle the "holding"/"unholding" process. If there is an active call and we call this method, there can be two cases: if the call is in not in "LocalHeld" state, that means we haven't put the call on hold yet, then we put the call on hold. If the call is in the "LocalHeld" state, then it indicates that we are already holding the call, so we take the call off hold. We can do it with checking the call's state and using the commands , introduced below:


But the simplest way to do this:

if (call != null)

As we can see, with the ToggleHold() method we do not even need to check the call's state, or store/check if the call is held or not. This method does the work for us.

How to hang up the call?

We are talking about a really simple function.

if (call != null)
	call = null;

If the call exists, we just need to use the call object's HangUp() method, and then to set the call object to "null".

How to transfer the call?

Another very simple function, when we would like to transfer the call to an other destination, to an other client, there are several ways to do this, for example we can transfer the call with one of the BlindTransfer() or the AttendedTransfer() methods, or we can forward the call with the ForwardCall() one.

  • BlindTransfer(): using this during a call, the third party's phone starts to ring, like it would be dialled first, and not ours. When the third party answers the call, we are stepping out from that.
  • AttendedTransfer(): using this during a call, we can notify the third party about the incoming call by calling it, and then redirect the call.
  • ForwardCall(): without answering the call, we can set the softphone to redirect the incoming call to an other destination. (For example: if we leave our office, we can forward the office's phone's incoming calls to our mobile phone.)

This example uses the BlindTransfer() method for this purpose.

if (call != null && !string.IsNullOrEmpty(destination))

This example uses the BlindTransfer() method for this purpose. As we can see, we are checking first, if the destination has been set, and of course we can only transfer an existing call. After that, we are using the call object's BlindTransfer() method with the other client's number as a string parameter.

What is Program.cs used for?

This class will introduce the usage of a softphone object, handles the console events, interacts with the user, and uses the opportunities provided by the Softphone class. In this example, the softphone asks the user for a number to dial, and for a number to transfer the call to. The application guides us through the following steps:

  • Asks the user for two numbers (to call, and to transfer to)
  • Waits for a key to be pressed to take the call on hold
  • Waits for a key to be pressed to take the call off hold
  • Takes the call off hold, than hangs up the call when press any key
  • Waits for a key to be pressed, than it redials the last called number
  • When the call is being answered, press a key and it's being transferred to the other number, given by the user.

We are handling everything with separated methods. These methods are communicating with each other, and making the source code more understandable and reusable.

How to initialize the softphone?

This example is using three new string variables, we need to initialize them to empty:

numberToTransfer = string.Empty;
numberToCall = string.Empty;
exampleSteps = string.Empty;

The numberToCall is the phone number to dial first, and then, to redial when we need to. The call will be transferred to the numberToTransfer phone number. The exampleSteps variable will guide us through the call events. We need this variable, since we would enter into the same states several times and that would cause troubles in the guiding. We can also follow the user interacts (it is mostly automatized this time) with the help of this variable by writing the user events to the console.

How to ask the user about phone numbers?

This method asks the user about two phone numbers (as strings). By storing the last called number (and the last incoming one) and then using that number again to dial without setting the called number manually, we've just created a function which is functioning just like the traditional telephone's redial button.

We need to call this method after the welcoming messages. When both numbers are given, the numberToCall is being dialled immediately, and the exampleSteps variable is being set to "Calling", so in the console window we can see; the user is calling the number, and the call's state is changing too.

How to handle the call's and the guide's states?

The user is being guided through states by only pressing a few keys. For the guide we need to handle the call's actual state and the exampleSteps variable's value:

  • The first case, when the call is in "Answered" state and the variable's value is "Calling". In this case, the softphone puts the call on hold, and sets the variable to "Held".
  • The call enters to "LocalHeld" state, sets the variable to "Unheld" and takes the call off hold, when the user presses a button.
  • The call enters to "InCall" state (again), and if the variable is "Unheld", changes that to "HangedUp" and hangs up the call.
  • The call enters to "Completed" state, and if the variable is "HangedUp", changes that to "Redialed", and waits for a key to be pressed. If that happens, it redials the last called number.
  • When the other phone answers the call, it enters into "Answered" state, and if the variable is "Redialed", the call is being transferred to the other phone number immediately. The variable's value is also changed to "Transfering".

By writing the exampleSteps variable's value to the console, we can see what would happen, if a real user would use these functions, actions.


With understanding these examples, it's easy to learn how to control the calls. Please note that, these are only basic functions, You can write your own ones. You can handle more calls simultaneously, play audio files into the call as voice (like the hold function does it), you can create message recorder, IVR (Interactive Voice Response) etc.

You can also learn how to send Instant Messages, by continuing to develop the "SIP Registration" example:

If you have any questions or need assistance, please contact us at

Related Pages

Copyright © 2000- - Ozeki Ltd |
Legal | Privacy | Terms of use | 7539 | | Login