How to develop a VoIP softphone in C# by using OZEKI VoIP SIP SDK This presentation describes what you should do – having done the SIP registration – to develop a fully-functional softphone in C# in the most simplest way - by using the previously written components of Ozeki VoIP SIP SDK. Part 2 Part 1: SIP registration Part 2: Making and receiving calls Part 3: Controlling the calls 1/19
Previously on this series Windows PC.NET compatible development kit (e.g. MS Visual Studio) installed on your PC.NET Framework installed on your PC Ozeki VoIP SIP SDK installed on your PC In order to build a VoIP softphone application in C# you will need the followings: 2/19 Download free example source code for this project (Part 1) from ! After studying the previous tutorial, you need be familiar with adding VoIP components to your references and creating a Softphone class that provides a softphone object to the user using the input setups. Now you have a console window which interacts with the user and handles your softphone with the provided opportunities. Download free example source code for this project (Part 2) from !
In the ‘using section’ you need to add some extra lines, as well as: Without these lines you would have to use the namespace information as a label for all tools of the SDK. Source code analysis using Ozeki.Media; using Ozeki.Media.MediaHandlers; using Ozeki.Network.Nat; using Ozeki.VoIP; using Ozeki.VoIP.SDK; 3/19 Classes: Softphone.cs 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 features. So the aim is creating a ‘telephone software’, which has the same functionalities (or much more), as an ordinary phone’s. You will use the Program.cs class to create a new softphone, so you can use the functions and listen to the events placed here.
The microphone will be connected to the mediaSender, and the speaker will be connected to themediaReceiver with the help of the connector object. The mediaSender and the mediaReceiver media handlers will be attached to the call object, this step is necessary if you would like to send and receive media data (for example: voice) during the communication. This sender and receiver object can be connected to different devices, media handlers as well. You also need a variable to indicate the incoming call: Objects (1) IPhoneCall call; Microphone microphone; Speaker speaker; MediaConnector connector; PhoneCallAudioSender mediaSender; PhoneCallAudioReceiver mediaReceiver; bool incomingCall; In the guide you have created a softphone and a phone line object from the ISoftPhone and the IPhoneLine interfaces. Now, you need to create some new objects: 4/19
In a constructor, you need to initialize the following new objects, variables: Since your softphone has no any incoming call yet, you need to set the variable to ‘false’. Objects (2) microphone = Microphone.GetDefaultDevice(); speaker = Speaker.GetDefaultDevice(); connector = new MediaConnector(); mediaSender = new PhoneCallAudioSender(); mediaReceiver = new PhoneCallAudioReceiver(); incomingCall = false; 5/19
There are some methods to help your later work, for example the methods designed to start and stop the devices, to connect them with the other media handlers, etc. Let's start with the device starter/stopper ones. In this example microphone and a speaker were used, but you can also use many other devices as objects, e.g. a webCamera. As you can see, this method checks first if there is a device to be started or not. After that, it starts the existing device with a single command. The method which stops them works on a similar way, with the Stop() command of the device's object. Starting and stopping the devices if (microphone != null) { microphone.Start(); } 6/19
Connecting the media handlers (1) if (microphone != null) { connector.Connect(microphone, mediaSender); } In order to send voice through the microphone to the other client's speaker, you need to connect the correct devices. Please note that it is possible to use several different kind of media handlers with the Ozeki VoIP SIP SDK, for example there is a similar way to connect a WaveStreamPlayback or anMP3Playback object to the mediaSender object, to play a.wav or an.mp3 file into the call, as voice (and you can receive and record voices, videos as well, and there is much more). To connect the microphone object to the mediaSender object with the help of the connector object, use the following lines: 7/19
The first parameter of the connector is the source, and the second is the destination of the data stream. So, in case of speaker, it looks like: As it shows, the mediaReceiver sends the voice to the speaker. (There is method called ‘disconnector’, which closes the connection between the two media handlers with the Disconnect() method.) There is a way to close all of the connections with only one command: This line closes every connection. Connecting the media handlers (2) if (speaker != null) { connector.Connect(mediaReceiver, speaker); } 8/19 connector.Dispose();
In the source code, you can find two methods to help in subscribtion and unsubscribtion. Subscribe to the events: The first line: if the call state changes The second line: if an error occurs during the call. The method to unsubscribe from the events works similar to the subscriber (with the ‘-=‘ operator). Subscribing for the call events call.CallStateChanged += (call_CallStateChanged); call.CallErrorOccured += (call_CallErrorOccured); 9/19
If you would like to be notified when there is an incoming call, you need to set an event at the initialization of the softphone: When the event notifies that there is a call waiting to be accepted, it sets the call object, and subscribes to the events of the call with the help of the previously written method. It also sets the value of the incomingCall variable to ‘false’ to indicate: there is no other call waiting. Listening to the incoming calls softphone.IncomingCall += softphone_IncomingCall; 10/19
Maybe this is the main part of your softphone within the Softphone class. If the call state changes, an event occurs. You can handle these events within the Softphone.cs and the Program.cs file as well. In this example two states has been used by their name: Handling the call states (1) CallState.Answered CallState.InCall 11/19
The ‘Answered’ state occurs, when the call is being answered, and the ‘InCall’ state occurs during the call, so if there is an active communication. To understand the difference between the two cases: the ‘Answered’ state can occur only once per call, but we can enter into the same call again and again (for example if we put the call on hold, and then take the call off hold). In the ‘Answered’ state, we need to: Start the devices, with the help of the previously written method Attach the media handlers to the call Please note that we need the devices to be connected to the media sender and receiver objects, but it's already done at the initializationof the softphone. In this example you need these lines in order to attach the media handlers to the call: Handling the call states (2) 12/19 mediaReceiver.AttachToCall(call); mediaSender.AttachToCall(call);
In the ‘InCall’ state, you need to: Start the devices with the help of the previously written method Please note that the media handlers are already set to the call In both cases, you subscribes to the call events when the call is made or received. More states can be used when the call ends: If the call ends, you can be notified about it as the IsCallEnded() method returns with a true value. For example it can occur, when an error occurs or the call enters into ‘Completed’ state, but we can handle them all in once. When the call ends, you need to: Stop the devices with the help of the previously written method. Detach the media handlers from the call Unsubscribe from the call events Finally, set the call objects to ‘null’ Handling the call states (3) 13/19
Making a call means creating a call object, subscribing to the call events and then call the Start() method of the call object. In the example the softphone checks first, if there is an already active call or not. If there is no active call, the you need to call the correct methods, illustrated above. To hang up the call, you can use the call object's HangUp() method. Making a call if (call == null) { call = softphone.CreateCallObject(phoneLine, numberToDial) ; WireUpCallEvents(); call.Start(); } 14/19
As you could see, when the variable, which indicates the incoming call, has been set to ‘true’, then there is a call to accept (so, your phone is ‘ringing’). In this example there is only text to notify if the phone is ringing. In order to let it ring with voice, you have a lot of options provided by the SDK or just by most of the programming languages. When you would like to accept a call, you need to set the value of the variable to ‘false’. In order to indicate that there are no incoming calls anymore, you need to accept the call with the Accept() method of the call object: To hang up the call, You can use the call object's HangUp() method. Accepting a call if (incomingCall == true) { incomingCall = false; call.Accept(); } 15/19
You can find a method, called ‘DispatchAsync(Action action)’ in the source file. This method is used to solve the thread blockings, because the ReadLine() methods would block the thread. Program.cs 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 can accept calls automatically, and can call the number, given by the user. You can handle everything with separated methods. These methods are communicating with each other, and making the source code more understandable and reusable. Solving the Thread blockings 16/19
The first step is the initialization the softphone you have created. To do this, you need to call an initializer method. You also need to subscribe to the call events. For this purpose you need the following lines: Now you are listening to the phone line and the call states or errors and to the incoming calls. This method will be called in the Main() method. Initialization (1) mySoftphone = new Softphone(); mySoftphone.PhoneLineStateChanged += mySoftphone_PhoneLineStateChanged; mySoftphone.CallStateChanged += mySoftphone_CallStateChanged; mySoftphone.IncomingCall += mySoftphone_IncomingCall; mySoftphone.CallErrorOccurred += mySoftphone_CallErrorOccurred; 17/19
Handling an error, occurred during the call By subscribing to listening to the call errors, you can notify the user about the occurred errors with a simple message in this example. Handling if there is an incoming call If there is an incoming call, your softphone notifies the user about that and automatically accepts the call with the help of the previously written method of the softphone. Handling the call's states You can reach the call states, since you are listening them. When the call ends, you calls the method that is asking the user about a number to be dialled. There are more call states, but in this tutorial you will need only this one. Handling if the registration succeeded In the previous example (that introduces how to register to a PBX with a SIP account), you could learn how to handle the states of the phone line. You've notified the user about the success, and now you are telling the user to dial a number by calling a method to ask about it. Asking the user about a number to be dialled In this example, the phone asks the user about a number to be dialled and then stores that number as a string. You need to store the number as a string value, since it can contain special characters as well. Initialization (2) 18/19
Check the 3. part of the ‘How to develop a VoIP softphone in C# by using OZEKI VoIP SIP SDK’ tutorial series and get to know how to control the calls using such useful features as call holding, redialing, call transferring, etc.! After studying this tutorial, you need be familiar with reaching the media handlers, handling the devices and attachning them to the call object. Now you also know how to make and accept calls, and how to handle the call states and events. Part 2 Thank you for your attention! For more information please visit or send an to 19/19