SIGN UP MEMBER LOGIN:    
ARTICLE

Creating a C# Softphone

Posted by Csilla SZABO KOZELL Articles | Articles C# January 18, 2012
This article is a developers’ guide to softphone development. It covers the basic steps for this development and settings that need to be made when you write a VoIP softphone program. The attached C# project contains a fully operable softphone solution that can be run without code modification.
Reader Level:
Download Files:
 

Introduction

Softphone is the short term for a software telephone and it is an extended model for the traditional telephone device. It works with VoIP technology and it is extended as it can be capable of both voice and video calling.

In this article I try to introduce a simple softphone application that can be used for voice calls. The new version of the Ozeki VoIP SIP SDK I use has just come out, so I had to modify my program in some aspects, therefore I had no time to write the video calling part yet. I will cover that topic in another article soon.

Basic Requirements for an Ozeki Softphone

A softphone application requires a PBX, as I mentioned in my previous article. The Ozeki SDK supports many PBX systems [1] and they also have guides to their configuration. I use a simple FreePBX [2] that is installed onto a virtual machine. This is an Asterisk based PBX system that seemed to be easy to use and reliable. I have actually installed it, registered two SIP accounts for testing and it works properly.

The SDK is simply installed on my computer. It unpacked its .dll file and some sample programs into the Program Files/Ozeki folder. There are a lot of license possibilities for it but I simply use the demo version that can be downloaded from their website [3]. It has some limitations but it is enough for test purposes.

The IDE I use is Visual Studio 2010 Express Edition that is free as I do not want to sell my programs, only use them for my improvement in VoIP solutions.

The Project Structure and GUI

The softphone application I wrote is a basic C# program with two classes and it only contains the basic functions of a softphone. The program has a minimal main GUI and a pop-up window that is for setting the PBX registration data.

First of all I created a Windows Forms project in Visual Studio and registered the Ozeki SDK to it as a Reference (Figure 1).

SDK-as-reference.jpg
 

Figure 1 - Using third-party .dll as a reference

My project contains two classes for the two GUI Forms. The main class is Softphone.cs and its layout can be seen in Figure 2.

Softphone-main-GUI.jpg

Figure 2 - The main window of my softphone

The GUI only contains the basic elements that are needed for a softphone. I used the Ozeki sample projects and the online manual [4] as a basis for my implementation, so in some aspects my program is similar to those.

The downloaded examples use in-line registration for the softphones, this means that in case of a new softphone registration, you need to modify the source code. As I wanted to make a more flexible solution, I exported the softphone registration data settings onto another window that is defined in the RegisterInfo.cs file. The GUI is simple and handy, it only contains the necessary elements for setting the registration data (Figure 3) 

Reginfo-window.jpg

Figure 3 - The pop-up window for PBX registration

This registration window pops-up when the application starts and it can also be opened any time later with the Register button on the main window.

The Registration Info window only checks if the port number is set properly - actually it checks if it is a valid number. The other exception handling is in the main class, the softphone registration can invoke a VoIPException that is defined in the Ozeki SDK. This Exception occurs when you set a wrong PBX IP.

The Source Code

The RegisterInfo class is a really simple one, it contains fields for the registration data each bound to the proper textboxes and when you press the OK button these fields get their value. The code for this is shown below:

       private void button1_Click(object sender, EventArgs e)
        {

            try
            {
                displayname = textBox1.Text;
                username = textBox2.Text;
                registername = textBox3.Text;
                regpass = textBox9.Text;
                domainhost = textBox4.Text + "." + textBox5.Text + "." + textBox6.Text + "." + textBox7.Text;
                port = Int32.Parse(textBox8.Text);
                switch (comboBox1.SelectedIndex)
                {
                    case -1:
                    case 0:
                        natTraversal = NatTraversalMethod.None;
                        break;
                    case 1:
                        natTraversal = NatTraversalMethod.STUN;
                        break;
                    case 2:
                        natTraversal = NatTraversalMethod.TURN;
                        break;
                }
                this.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("The port number you set is invalid, please set a valid port number.\n {0}", ex.Message), string.Empty, MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            }
        }

This code only checks the valid port number type. It is not too elegant, but serves the purpose. The window is modal any time it opens and it closes only when at least the port number is set properly.

The NAT traversal is set by a combo box and it has a default value "None" which means there will be no NAT traversal in use. You can also choose STUN and TURN from the list. These traversal types are implemented in the SDK.

If you have set the registration data, the main window opens and you can make a call, if the registration is succesful. If there is any problem with the registration, you can reopen the registration window and correct the registration data.

The Softphone.cs file contains the basic functionality. Writing a softphone needs some basic tools to be defined:

ISoftPhone softPhone;
IPhoneLine phoneLine;
PhoneLineState phoneLineInformation;
IPhoneCall call;
Microphone microphone = new Microphone();
Speaker speaker = new Speaker();
MediaConnector connector = new MediaConnector();
PhoneCallAudioSender mediaSender = new PhoneCallAudioSender();
PhoneCallAudioReceiver mediaReceiver = new PhoneCallAudioReceiver();
bool inComingCall;
RegisterInfo ri;

The most essential method in the class is the InitializeSoftphone that creates a softphone instance and registers it to the PBX:

        private void InitializeSoftPhone()
        {
            try
            {
                softPhone = SoftPhoneFactory.CreateSoftPhone(SoftPhoneFactory.GetLocalIP(), 5700, 5750, 5700);
                softPhone.IncomingCall += new EventHandler>(softPhone_IncomingCall); 
                //getting registration information
                SIPAccount sa = new SIPAccount(ri.IsRegRequired, ri.displayname, ri.username, ri.registername, ri.regpass, ri.domainhost, ri.port);
                NatConfiguration nc = new NatConfiguration(ri.natTraversal);
                phoneLine = softPhone.CreatePhoneLine(sa, nc);
                phoneLine.PhoneLineStateChanged += new EventHandler>(phoneLine_PhoneLineInformation);
                softPhone.RegisterPhoneLine(phoneLine);
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("You didn't give your local IP adress. Please press the Register button and try it again.\n {0}", ex.Message), string.Empty, MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            }
        }

The Exception that occurs here is a VoIPException that is defined in the SDK. The softphones need a port range for outgoing data and a port number for listening purposes. There are some event handlers that also need to be written in the class. For these I basically used the same methods that were written in the sample programs.

The softphone is subscribed to the incoming call event during the initialization. This event is handled in the following method:

        private void softPhone_IncomingCall(object sender, VoIPEventArgs e)
        {

            InvokeGUIThread(() =>
            {
                label2.Text = "Incoming call";
                label5.Text = String.Format("from {0}", e.Item.DialInfo);
                call = e.Item;
                WireUpCallEvents();
                inComingCall = true;
            });
        }

The GUI labels inform you about the basic events like an incoming call. The WireUpCallEvents will subscribe the call for the CallStateChanged and the CallErrorOccured events.  The call itself is basically handled in the call_CallStateChanged method:

        private void call_CallStateChanged(object sender, VoIPEventArgs e)
        {
            InvokeGUIThread(() => { label2.Text = e.Item.ToString(); });
            switch (e.Item)
            {
                case CallState.InCall:
                    microphone.Start();
                    connector.Connect(microphone, mediaSender);
                    speaker.Start();
                    connector.Connect(mediaReceiver, speaker);
                    mediaSender.AttachToCall(call);
                    mediaReceiver.AttachToCall(call);
                    break;
                case CallState.Completed:
                    microphone.Stop();
                    connector.Disconnect(microphone, mediaSender);
                    speaker.Stop();
                    connector.Disconnect(mediaReceiver, speaker);
                    mediaSender.Detach();
                    mediaReceiver.Detach();
                    WireDownCallEvents();
                    call = null;
                    InvokeGUIThread(() => { label5.Text = string.Empty; });
                    break;
                case CallState.Cancelled:
                    WireDownCallEvents();
                    call = null;
                    break;
            }
        }

When a call starts the media connector connects the sender and the receiver to the microphone and the speaker, and then both are attached to the call. The microphone and the speaker, of course, has to be started first. In case of the end of the call the whole process is made backwards. The tools are detached from the call and the devices are disconnected and stopped.

The other methods, like the ones for the keypad button presses, can be used without any modification in any softphone program as I saw. The Ozeki examples also contain DTMF signal handling, but I have not yet used them in my program.

What you will need to run the program

The C# source code that is attached to this article is fully executable without any modifications. You will need a PBX and two registered SIP accounts for the proper work and you will also need to download and install the Ozeki SDK and register it to the project.

When running the project, you will need to set the PBX IP, the listening port and the SIP accounts you have set in the PBX previously. After this you can have your softphones communicate with each other. If you register an IP telephone to the PBX you can also make calls between this softphone and the IP telephone too without any modifications in the code.

Conclusion

This article contained a basic introduction to softphone programming and showed a possible implementation for VoIP communication. The source code I wrote for this article is free to use and to modify by anybody.

Acknowledgement

I need to say thanks to the great developer and support teams of Ozeki Systems Ltd. who kindly answered all my questions about softphone technology and provided the possibility to try their SDK for putting my work into practice.

References

[1] http://voip-sip-sdk.com/p_103-voip-pbx-sdk-compatibility-voip.html

[2] http://www.freepbx.org/

[3] http://voip-sip-sdk.com/p_21-download-ozeki-voip-sip-sdk-voip.html

[4] http://voip-sip-sdk.com/p_100-introduction-to-ozeki-voip-sip-sdk-voip.html

Login to add your contents and source code to this article
share this article :
post comment
 

Nice Article!

Posted by Manoj Bhoir Apr 07, 2012

I am glad to hear that your problem is solved. Feel free to ask me if you have any other question regarding this topic. Csilla

Posted by Csilla SZABO KOZELL Feb 21, 2012

Hi Csilla you know that i have been struggling with a small thing all along, i tried all the possibility to get connected but failed because i did 'nt set the Text property on the ipaddress textBox. so thanks a lot for your time. now i'm connected and can call and recieve a call, but it does not pick the media devices, only quiet, but i set the them to getdefaultdevices.

Posted by mike michaels Feb 21, 2012

Actually it cathes all the Exceptions as you can see by the catch instruction. You may specify the exception types or check the property values you tried to set in that method, that will show which instruction went wrong. If the problem is really with the IP address, the SIP account creation will invoke the exception.

Posted by Csilla SZABO KOZELL Feb 20, 2012

Hi again sorry was still in class. i gave the correct address and still get the same error. one thing to ask this exception error, is't only for the IP address or for any error ocured inside the try braces. i also set to give massege if all textboxs are left empty.

Posted by mike michaels Feb 20, 2012
Nevron Gauge for SharePoint
Become a Sponsor
PREMIUM SPONSORS
  • ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications. Visit DynamicPDF here
    Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor