Sipek VoIP

Recent site activity

612days since
SipekSdk Project Started

About

Copyright (c) 2008 Sasa Coh

Instant Softphone Tutorial







Introduction


In this tutorial you'll see how easy it is to build a simple Softphone with SipekSdk. This document guides you from a scratch to a working Softphone. In less than an hour you will create the SIP application with one you can call and talk with anyone in the SIP world. If you don't believe, read on...

The complete Instant Softphone source code is available at SVN repository http://sipekapps.googlecode.com/svn/trunk/Example_InstantSoftphone as a Example_InstantSoftphone project.

Development Environment Setup


The SipekSdk project is built with Visual Studio 2005 for C#. You can use any newer version of VS by converting project files appropriately. 


Create new Project


  1. Open VS and select File -> New -> Project
  2. Choose Visual C# project type and select Windows Application template
  3. In the Name field enter for example: InstantSoftphone
  4. Choose Location on disk
  5. and press OK
A project window is opened with Form1 design view.

Create Simple GUI Form


Now we'll create a simple GUI for our Softphone. The look&feel is up to you. But for simple Softphone you'll need at least the controls below:
  1. A TextBox for displaying dialled digits and call state
  2. A Button to start a call
  3. A Button to release a call
An example form:




Using SipekSdk


Now let's do some coding. For VoIP (SIP) programming we'll use SipekSdk library. Don't be afraid, it's easy. SipekSdk is a simple and powerful SIP abstraction library that enables rapid VoIP application development.

First prepare the project for SipekSdk.

Import SipekSdk Library

  1. Copy SipekSdk.dll to project folder (get the SipekSdk.dll from SVN or build your own from sources)
  2. In VS Solution Explorer right click References and select Add Reference...
  3. In Add Reference dialog select Browse tab and navigate to SipekSdk.dll file  
  4. Confirm selection and the References list must now contain SipekSdk
Do the same with pjsipDll.dll !!! Get the pjsipDll.dll from SVN or build your own from sources.

I encourage you to build the libraries on your own. For instructions see the relevant pages (SipekSdk, pjsipWrapper)


Prepare Configuration Settings


The next step is necessary to configure SipekSdk library appropriately. Here we'll set mandatory parameters only. 

Implement Config Interface


Before you start using SipekSdk it's necessary to set up the configuration data. The SipekSdk contains abstract configuration classes. In order to provide your configuration data you need to implement these classes and fill it with values. After that you just need to inject the classes into SipekSdk.

The main configuration interface class is IConfiguratorInterface. The other configuration interface is IAccount used for SIP account configuration. SipekSdk actualy supports more than 1 account. In this tutorial we'll use only one.

How to implement configuration for SipekSdk:
  1. Create new class (Right click on project in Solution Explorer, click Add and select New Item...)
  2. Select Class template and enter the name. for example: PhoneConfig.cs
  3. The new file is opened (you can delete the contents if any)
  4. On the top add line: using Sipek.Common;
  5. Now we'll extend the IConfiguratorInterface interface. 

    internal class PhoneConfig : IConfiguratorInterface

  6. and implement abstract methods (manualy or let VS wizard to do that)
  7. in case of wizard; you'll see properties filled with: throw new Exception("The method or operation is not implemented.");
  8. We can leave this for now
  9. Implement another important SipekSdk interface IAccount

    class AccountConfig : IAccount

  10. and implement abstract methods (or let VS to do that)
  11. Let's try to compile the project now

Now we have two interfaces implemented. Next step is to integrate account instance into PhoneConfig class and implement some settings.
  1. Add account list to PhoneConfig and initializer list in construtor

    List<IAccount> _acclist = new List<IAccount>();

    internal PhoneConfig()
    {
         _acclist.Add(new AccountConfig());
    }

  2. Implement property Accounts

        public List<IAccount> Accounts
        {
          get { return _acclist; }  
        }

  3. Set some other properties (otherwise you'll have an exception):
    CFNRFlag to return false
    CFUFlag to return false
    DNDFlag to return false
    DefaultAccountIndex to return 0
    IsNull to return false
    SipPort to return 5060

In AccountConfig set the properties (hard coded) to connect to your SIP server. In the second part of tutorial I'll show you how to use .Net Application Settings mechanism to persist configuration settings.


Define Callbacks/Events


Now as we finish with configuration settings we can proceed to defining callbacks. Callbacks are methods called from SIP stack informing us about Call state, Registration state etc,... SipekSdk defines Events listening to state updates of call or registration or about some other SIP event. 

Before we register callbacks, let's do some coding in Form1.cs:

  1. Add imports:
       using Sipek.Common.CallControl;
       using Sipek.Sip;

  2. Define CCallManager instance property (singleton): 
        
        CCallManager CallManager
        {
          get { return CCallManager.Instance; }
        }


  3. Now we're ready to register callbacks (again let's VS to do the callback method stubs)

          CallManager.CallStateRefresh += new DCallStateRefresh(CallManager_CallStateRefresh);
          pjsipRegistrar.Instance.AccountStateChanged += new Sipek.Common.DAccountStateChanged(Instance_AccountStateChanged);

Two (Callback) methods CallManager_CallStateRefresh and Instance_AccountStateChanged are ready for implementation. We'll do that later.

Sipek Initialization

Ok, let's look what have now:
  1. GUI form with basic controls
  2. Prepared configuration settings
  3. Defined Callbacks (but not implemented yet)

In next tutorial I'll show you how to implement Media (playing tones) and Timer handling. For now we'll let SipekSdk to handle (ie. ignore) it.

Are you ready to do SipekSdk initialization?
  1. In Form1 constructor assign SipekSdk module instances:
          // Inject VoIP stack engine to CallManager
          CallManager.StackProxy = pjsipStackProxy.Instance;

  2. Inject configuration settings to SipekSdk (remember PhoneConfig):
          CallManager.Config = Config;
          pjsipStackProxy.Instance.Config = Config;
          pjsipRegistrar.Instance.Config = Config;

  3. Initialize SipekSdk:

          CallManager.Initialize()

  4. And finally try to register configured account(s)

          pjsipRegistrar.Instance.registerAccounts()



Finish GUI


Implement Callbacks


If you remember we declared two callback methods for updates on registration and call states. Before we dive into implementation we need to resolve a small synchronization problem. 

How to avoid synchronization problem:

Syncronizing problem

The callbacks are usually called from different thread than GUI and that causes crash. To solve this problem you need to synchronize the callbacks with GUI thread. 

Synchronizing using Form.Invoke method:

    void CallManager_CallStateRefresh(int sessionId)
    {
      // MUST synchronize threads
      if (InvokeRequired)
        this.BeginInvoke(new DCallStateRefresh(OnStateUpdate), new object[] { sessionId });
      else
        OnStateUpdate(sessionId);
    }






Fortunately there is another solution that solves this problem. See more details in advanced tutorial...

Threading Strategy

SipekSdk offers two threading models. In multi threaded mode the pjsip stack creates its own threads for handling callbacks. This is dangerous because of simultaneous access to GUI controls (from callbacks) which is not allowed. The the other disadvantage is possible deadlocks when accessing pjsipී;s functions guarded by mutexes. 

In order to avoid these problems the other strategy was introduced in pjsipDll. The poll for events. This way a GUI thread is registered with pjsip engine and GUI periodically polls for events. The callbacks are now executed in the same context as GUI. No more synchronization needed! 

To use polling you just need to set pollingEventsEnabled flag in pjsipConfig. Next step is to implement timer that calls dll_pollForEvents periodically. Thatී;s it. 





The implementation of callbacks:

 
    private void OnRegistrationUpdate(int accountId, int accState)
    {
      textBoxRegState.Text = accState.ToString();
    }

    private void OnStateUpdate(int sessionId)
    {
      textBoxCallState.Text = CallManager.getCall(sessionId).StateId.ToString();
    }


Implement button handlers


private void buttonMakeCall_Click(object sender, EventArgs e)
{
    _call = CallManager.createOutboundCall(textBoxDial.Text);
}


private void buttonReleaseCall_Click(object sender, EventArgs e)
{
    textBoxDial.Clear(); 
    CallManager.destroySession(_call.Session);
}


Using Instant Softphone


It's simple:

Be sure to enter correct configuration settings in PhoneConfig and Account properties, especially: 
  • HostName
  • Username
  • Password
If you have SIP server up and running the Softphone should register. Check the "Registration status" value. 200 is OK


Now you are ready to make your 1st call. Enter number or sip uri into textBoxDial and check the call status.

For more advanced feature see advanced tutorial...

Enjoy!!!