This page is a detailed source code explanation for
a C# open source VoIP softphone application with WPF GUI using Ozeki VoIP SIP SDK.
Check the source code sections and find their details for making your work
Graphical User Interface
The GUI of this sample program has been developed with Microsoft WPF (Windows Presentation Foundation)
technology. The reason for this is that it allows great flexibility regarding the
appearance of the program. This flexibility is only limited by your imagination.
The main goal of this sample program is to demonstrate the simple and convenient use
of Ozeki SDK (I do not enlist the great functions of WPF technology in this article).
That is why I created a simple but representative GUI (Figure 1) with basic telephone functions.
The softphone has all the functions that are required for establishing phone calls
effectively like to make a call, to receive a call, sending and receiving DTMF signals
and display of call events on the interface.
Figure 1 - GUI
The Source Code
If you open the code-Behind of PhoneWindow.xaml describing the GUI you can see the devices of the
SDK that are needed for making phone calls.
public partial class PhoneWindow : Window
Microphone microphone = Microphone.GetDefaultDevice();
Speaker speaker = Speaker.GetDefaultDevice();
MediaConnector connector = new MediaConnector();
PhoneCallAudioSender mediaSender = new PhoneCallAudioSender();
PhoneCallAudioReceiver mediaReceiver = new PhoneCallAudioReceiver();
It represents a telephone, and its telephone line is represented by the
IphoneLine class. There can be more telephone lines which mean that you can develop a
multi line phone.
It represents a telephone line that can be registered to a SIP PBX, for example
Asterisk, 3CX, or maybe to other free PBXs that are offered by SIP providers.
Registration is made via a SIP account.
It is an enum type that represents the status of the phone line with the PBX: e.g.,registered, not registered, successful/unsuccessful registration, etc.
It represents a call: the status of the call, the direction of the call, on
which telephone line it was created, the called person, etc.
Class for capturing audio data with microphone.
Class for playing audio through speakers.
Class for creating connections between 'VoIPMediaHandler' objects.
It can send audio data to the attached 'IPhoneCall' object.
It can receive audio data from the attached 'IPhoneCall' object.
The softphone is initialized after loading the GUI
The program initializes the softphone after loading
private void InitializeSoftPhone()
softPhone = SoftPhoneFactory.CreateSoftPhone(SoftPhoneFactory.GetLocalIP(), 5700, 5750, 5700);
softPhone.IncomingCall += new EventHandler<VoIPEventArgs<IPhoneCall>>(softPhone_IncomingCall);
phoneLine = softPhone.CreatePhoneLine(new SIPAccount(true, "oz875", "oz875", "oz875", "oz875", "192.168.112.100", 5060),new NatConfiguration(NatTraversalMethod.None,""));
phoneLine.PhoneLineStateChanged += new EventHandler<VoIPEventArgs< private void buttonPickUp_Click(object sender, RoutedEventArgs e)
inComingCall = false;
if (call != null)
if (phoneLineInformation != PhoneLineState.RegistrationSucceeded && phoneLineInformation != PhoneLineState.NoRegNeeded)
MessageBox.Show("Phone line state is not valid!");
call = softPhone.CreateCallObject(phoneLine, textBlockDialingNumber.Text);
Since you can make and pick up the call with the very same button first you need to decide if it
is an incoming or an outgoing call with the help of
a simple bool variable truth verification (Incoming calls will be detailed later).
Before initiating a phone call, check if the phoneline
has successfully registered to the server when registration is required. If an
inappropriate result is returned the user is informed about the reason of the failure.
If the phoneline is registered, create a IPhoneCall object representing a call via the ’softPhone.CreateCallObject’ method
and its parameters. The first parameter
is the telephone line on which we would like to initiate calls, the second parameter
is the phone number to be called. In order to make your calls successful, wire up to some Call Events.
Therefore, the audio data arriving from the remote end, the DTMF signal or changes in call status can be processed
effectively. The wire up process is demonstrated in the sample as follows:
private void WireUpCallEvents(IPhoneCall call)
call.CallStateChanged += new EventHandler<VoIPEventArgs<CallState>>(call_CallStateChanged);
call.DtmfReceived += new EventHandler<VoIPEventArgs<OzTuple<VoIPMediaType, DtmfSignal>>>(call_DtmfReceived);
call.CallErrorOccured += new EventHandler<VoIPEventArgs<CallError>>(call_CallErrorOccured);
This event is for displaying the changes in the call status.
This event is responsible for processing DTMF signals arriving from the remote end.
Via the CallErrorOccured event above you can receive information about
the reasons why the call was not created. For example: the called party is
busy, the call is rejected, the called number does not exist or the called
number is not available.
To wire up to these necessary events you only need to actually start a call.
You can do it with the Start() function of the call object. In this example it is
the ’call.Start()’ line.
b. Handling incoming calls
The Ozeki VoIP SIP SDK publishes the incoming calls through the ’ISoftphone’
The code sample above is for handling this. It displays incoming calls on the display
and registers onto the necessary events of the object representing
incoming calls which was mentioned above. The incoming call
variable notifies the Pick Up button if the call is an outgoing or an incoming one.
c. Ending a call in progress
There are three different ways for ending a call that is in progress.
You end the call
The remote end ends the call
There is a break in network connection
You need to take care of ending the call only if you want to end it.
Just like the ’Pick Up’ button the ’Hang Up’ button is also connected to the
If you press the ’Hang Up’ button the following event manager is responsible for ending the call:
Now it needs to be checked if there is an active call. If there is an active call
you need to end it and delete the information related to dialing.
d. Displaying call status
Ozeki VoIP SIP SDK provides the following information about the call status: ringing, InCall, Completed, Rejected, etc.
These call statuses are displayed via the CallStateChange event of the ’call’ object. In this
sample program I only focused on the essential options for being simple but demonstrative.
Based upon these essential option you can easily create further options.
The code above is only for reacting to the changes in the call status. For example:
If the phone is picked up it starts receiving the voice
so we can send our audio data to the other party. Moreover it
initializes the devices that are necessary for playing incoming audio data.
e. Handling audio data arriving from the remote end
Since we wired up to the MediaDataReceived event of the ’call’ object in case of both outgoing and incoming calls,
the incoming PCM audio data only needs to be forwarded to the sound system as it is demonstrated in the method.
f. Forwarding incoming audio from the microphone to the remote end
via the SDK
The PCM audio data originating from the microphone is forwarded to the ’call’
object that represents the actual call via the process of.
Then the audio data is compressed by Ozeki SIP SDK with the right audio codecs and then
sent to the intended person according to the established communication
g. Receiving DTMF signals
DTMF signals can be received similarly to audio data. This
sample program only displays the reference value of the received DTMF signal on the
Further development possibilities
This sample program is only for handling one telephone line. However, Ozeki VoIP SIP
SDK offers the opportunity to develop and handle multiple telephone lines
simultaneously. Moreover further functions can also be implemented effectively like call forwarding
and chat function. If the above mentioned functions have called your attention
contact us at firstname.lastname@example.org!