info@voip-sip-sdk.com Tel: 00 36 52 532 731

Flash SIP client

Download: 06_Web2SIP_DesignedGUI.zip

This article demonstrates a Flash SIP sample application that connects to a console server for SIP communication based on the professional support of Ozeki VoIP SIP SDK. After reading through this page you will be familiar with all the knowledge you need to write a Flash SIP client and connect it to a server application.

Introduction

This sample program demonstrates a one-line Flash SIP softphone that is created by using the advantageous Ozeki VoIP SIP SDK. The sample program supports the following functions: initiating/receiving calls and sending/receiving DTMF signals.

The Flash clients that connect to the server will register in a SIP PBX with a SIP account that is selected by the server. This SIP PBX is specified on the server side. After the Flash softphone registered in the SIP PBX, it is possible to communicate with any device in the SIP network.

The source codes on this page are easy-to-use and transparent that is why they can be used for realizing SIP projects effectively.

How to create the project

This is a client-server application in which the client is a Flash application, the server is a console application written in C#. This way the whole project consists of a server side project created in Visual Studio and a client side project created in Flash Builder 4.5.

Server-side project

  1. According to the above mentioned the server is created in VS 2010 with the help of File->New menu. Its name is ChatGatewaySample. .Net Framework 3.5 has been set as the projects target framework.
    Note: Sometimes it occurs that projects that are set with .Net 3.5 framework are created by default with .NET 3.5 Client Profile in VS2010. In this case, it needs to be set back to .NET 3.5 in order to boost the full toolkit.

  2. In order to use the toolkit of Ozeki VoIP SIP SDK, the ozeki.dll needs to be added to the project references. It makes the project implementation much easier.

Flash client-side project

  1. The client side is created by using the File->New->Flex project menu item of Flash builder 4.5 development environment as a web application. It is called FlashSIPClientExample.

  2. The FlashClientSDK.swc file (that belongs to the SDK and it includes the client side tools) has been added to the Ozeki VoIP SIP SDK path with the Add SWC button of Project/ Properties / Flex Build Path / Library path tab.

Server implementation

In this example, the server is responsible for keeping connection with the SIP PBX, setting up/accepting/hanging up calls and transferring media data between the PBX/SIP device and the Silverlight client. The server also distributes the accounts that are required for logging into the PBX. Then it also makes the accounts logged into the PBX for the connected Silverlight clients.

The server is a console application. The SIPGateway class implements the servers functionality toward the client. This class will use and extend the basic server implementation and functionality (client connection handling, data forwarding services, mechanisms) that is provided by the Ozeki VoIP SIP SDK. It also uses the tools provided by Ozeki VoIP SIP SDK in order to implement SIP and VoIP related functionality easily and quickly. The object of SIPGateway class is created by the Main(string[] args) method (that is the entry point of the application) in the following way (Code 1):

static void Main(string[] args)
        {
            Console.WriteLine("Remaining days: {0}",LicenseManager.Instance.RemainingDays);

            var sipGateway = new SIPGateway();
            sipGateway.Start();
            Console.ReadLine();
        }

Code 1 - The Main method of the server-side application

The ChatGateway derives from the MediaGateway, this way its constructor can be called in two ways: without a parameter and with a MediaGatewayConfig parameter. In the first case, the constructor expects the configuration from the App.Config file of the application, while in the second case, it expects the configuration from the MedaiGatewayConfig type parameter. The App.Config configuration file is demonstrated in Code 2. It includes the follows:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="mediaGateway">
      <section name="mediaGatewayConfig" type="Ozeki.MediaGateway.Config.MediaGatewayAppConfig, VoIPSDK"/>
    </sectionGroup>
  </configSections>
  <mediaGateway>
    <mediaGatewayConfig>
      <providers>
        <add type="silverlight" localIPAddress="0.0.0.0" listenedPort="4502" serviceName="SIPGateway"/>
        <add type="flash" serviceName="SIPGateway"/>
      </providers>
    </mediaGatewayConfig>
  </mediaGateway>
</configuration>

Code 2 - The App.config file for the server configuration

Basically, it can be seen that a MediaGatewayAppConfig type configuration section (that belongs to the MediaGateway class) has been added to the configuration file. Then a Silverlight and Flash provider have been added to the Providers item of this a MediaGatewayAppConfig type configuration section. By adding these two providers to the configuration, the server will be available for both Silverlight clients and Flash clients.

This way the same code will be able to handle both client types. It can also be seen that the localIPAddress and listenedPort are specified for one of the providers while they are not specified for the other provider. The reason for this is that these configurations have default values that allow missing out the configuration of these variables.

After creating and configuring SIPGateway object, sipGateway.Start(); instruction will launch the publication of the servers functionality.

The SIPGateway is responsible for managing client connections and distributing a free account for the new clients. The SIPGateway also publishes the extended methods of the MediaGateway such as initiating/rejecting/receiving calls and sending DTMF signals.

The servers methods are started via MediaGateway.Start(). Then the OnStart method (Code 3) is invoked which is overridden in the SIPGateway class. Here the necessary initializations are made. Then the the follows are created: the collection that includes SIPClients, the object that models the softphone, and the SIPAccountPool that manages SIP accounts with some specified SIP accounts.

Furthermore, in order to boost the easy-to-handle two-way communication between the client and the server provided by the Ozeki VoIP SIP SDK, the stream service of the SDK is requested by calling the GetService<IStreamService>(); instruction.

public override void OnStart()
{
    Console.WriteLine("SIP Gateway started");

    sipClients = new Dictionary<IClient, SIPClient>();
    softPhone = SoftPhoneFactory.CreateSoftPhone(SoftPhoneFactory.GetLocalIP(), 5060, 5800, 5060);

    sipAccountPool = new SIPAccountPool();

    for (int i = 80; i < 99; i++)
    {
        var name = "oz8" + i;
        var sipAccount = new SIPAccount(true, name, name, name, name, "192.168.112.100", 5060);

        sipAccountPool.AddSIPAcount(sipAccount);
    }

    streamService = GetService<IStreamService>();
}

Code 3 - The OnStart() method of the server

The softphone (that can be found in the code) is a tool that is provided by the Ozeki VoIP SIP SDK. It represents a fully featured telephone. Due to the flexible licensing of Ozeki SIP SDK, it is even possible to add more telephone lines to the softphone on which calls can be handled simultaneously. This object is created with the SoftPhoneFactory.CreateSoftPhone. In this example, the IP address of Asterisk PBX and the port range used by the PBX are used.

Methods of SIPGateway that manage client connections

OnClientConnect (Code 4) is an overridden method can be found in SIPGateway class. Ozeki VoIP SIP SDK indicates via OnClientConnect method if a client tries to connect.

public override void OnClientConnect(IClient client, object[] parameters)
{
    Console.WriteLine("New client connected. Remote address: {0}", client.RemoteAddress);

    var sipAccount = sipAccountPool.GetSIPAccount();

    if(sipAccount == null)
    {
        client.InvokeMethod("OnRegistrationStateChanged", RegistrationState.ConnectionLimit);
        client.Close();
        return;
    }

    var sipClient = new SIPClient(client, streamService, softPhone, sipAccount);
    sipClients.TryAdd(client, sipClient);

    sipClient.Register();
}

Code 4 - The method that invokes when a client sends a connection request to the server

As the next step, a SIPClient object of the client is created if there is a free SIP account in the SIPAccountPool for the client that requested to connect. This way it will be registered with the selected account into the SIP PBX that has been specified in the softphone constructor. If the SIPAccountPool has no free SIP account when the client tries to connect, the client will be notified about this fact and the connection is closed.

As opposed to this, OnClientDisconnect method (Code 5) is only responsible for removing the connected clients reference from the ConcurrentDictionary. Then it resolves the SIP account that has been used by the given client and unregisters the account from the SIP PBX.

ublic override void OnClientDisconnect(IClient client)
{
    Console.WriteLine("Client disconnected");

    lock (sipClients)
    {
        SIPClient sipClient;
        if (sipClients.TryGetValue(client, out sipClient))
        {
            sipClient.Unregister();
            sipAccountPool.AddSIPAcount(sipClient.Account);
            sipClients.Remove(client);
        }
    }

}

Code 5 - This method invokes when a client disconnects from the server

OnSteamPublishStart (Code 6) will indicate if the given client publishes its MediaStreamSender object. This way it subscribes the MediaDataReceived event of the media stream to the MediaDataReceived event handler of the SIPClient. It will then forward the incoming voice data to the right direction.

It has significance in case of setup calls between two Flash clients or two Silverlight clients: it determines when the server should start to forward media data from one participating client to the other one.

public override void OnStreamPublishStart(IClient client, IMediaStream mediaStream)
{
    Console.WriteLine("Media stream published. Stream name {0}", mediaStream.Name);

    lock (sipClients)
    {
        SIPClient sipClient;
        if (sipClients.TryGetValue(client, out sipClient))
            sipClient.StreamPublished(mediaStream);
    }

}

Code 6 - The OnStreamPublishStrat method of the server application

As opposed to this, OnStreamClose (Code 7) stops data forwarding of the published stream by unsubscribing the previously subscribed event handler.

public override void OnStreamClose(IClient client, IMediaStream mediaStream)
{
    Console.WriteLine("Media stream closed.");

    lock (sipClients)
    {
        SIPClient sipClient;
        if (sipClients.TryGetValue(client, out sipClient))
            sipClient.StreamClosed();
    }

}

Code 7 - This code segment stops the media stream sending

The methods described above are parts of the basic services of Ozeki VoIP SIP SDK. They are overridden according to the current implementation in order to provide the appropriate and requested functionality for this task. The further methods such as start Call, HangUp (accept/reject/hang up active call), Accept call, StartDtmf and StopDtmf are not parts of the basic tools of the SDK, they only extend these basic tools. That is why, these methods are invoked on the client side differently from the basic tools (Code 8).

public function invokeOnConnection(methodName:String, ... params):void

Code 8 - The client-side instruction for invoking server-side methods

The client-side functions can invoke server-side methods by using an instruction similar to the one in Code 9. This particular instruction will invoke the proper server-side function in case of a call.

mediaConnection.invokeOnConnection("Call", dialNumber);

Code 9 - This instruction will invoke the Call function on the server's side

The above seen instruction invokes the Call function that is shown in Code 10 and defined in the client-side Flash code.

public void Call(IClient client, string phoneNumber)
        {
            SIPClient sipClient;
            if (sipClients.TryGetValue(client, out sipClient))
                sipClient.Call(phoneNumber);
        }

Code 10 The Flash code of the Call function that is invoked from server-side

This will basically forward the request to the SIPClient class, and it starts calling the device with the telephone number received in parameter. HangUp, Accept, Reject, StartDtmf, etc. methods are functioning similarly to Call, this way they are not detailed in this example. Their functions can be checked in the attached source code.

The SIPClient class that represent clients on the server-side

A SIPClient object will be created on server-side for each connected client and manages the telephone line status of these clients (Code 11).

public virtual void Register()
        {
            phoneLine = softPhone.CreatePhoneLine(Account);

            phoneLine.PhoneLineStateChanged += PhoneLine_PhoneLineInformationCanged;
            softPhone.IncomingCall += SoftPhone_IncomingCall;


            softPhone.RegisterPhoneLine(phoneLine);
        }

Code 11 - The server-side method for registering a client

The PhoneLine_PhoneLineInformationCanged event is for indicating the status changes of the phone line. Meanwhile the IncomingCall event of the Softphone is for indicating incoming calls.

The Unregister() method, as opposed to Register(), unregisters the phone lines and unsubscribes from the previously subscribed events.

Call(string dialNumber) method (Code 12) will dial the phone number received in parameter via the Call object provided by Ozeki VoIP SIP SDK. It also subscribes to the events of this object that are necessary to make the call.

public virtual void Call(string dialNumber)
        {
            if (phoneLine == null)
            {
                System.Diagnostics.Debug.Fail("PhoneLine null");
                return;
            }

            if ((phoneLine.RegisteredInfo == PhoneLineState.RegistrationSucceded || phoneLine.RegisteredInfo == PhoneLineState.NoRegNeeded) && call == null)
            {
                call = softPhone.CreateCallObject(phoneLine, dialNumber);

                call.CallErrorOccured += Call_ErrorOccured;
                call.CallStateChanged += Call_StateChanged;
                call.MediaDataReceived += Call_MediaDataReceived;
                call.DtmfReceived += call_DtmfReceived;
                call.Start();
            }
        }

Code 12 - This method performs the dialing process on server-side

The Accept() method is for accepting the request of an incoming call, while HangUp() rejects an incoming call or terminates active calls. The Call_StateChanged event indicates the current status of the call (Busy, Cancelled, Ringing, Incall, Completed, etc.). It is for indicating call status during the call. Here, InCall status is handled. InCall status indicates that the call reaches that call status when sending/receiving media data can be started (Code 13).

  protected virtual void Call_StateChanged(object sender, VoIPEventArgs<CallState> e)
        {
            switch (e.Item)
            {
                case CallState.InCall:
                    phoneCallMediaSender.AttachToCall(call);
publishStreamName = Guid.NewGuid().ToString();                    playStreamName = Guid.NewGuid().ToString();

                    mediaStream = streamService.CreateStream(playStreamName);
                    timeStamp = 1000;
                    OnInCall(publishStreamName, playStreamName);
                    break;

                case CallState.Completed:
                    phoneCallMediaSender.Detach(call);

                    streamService.RemoveStream(mediaStream);
                    call = null;
                    break;
            }
            OnCallStateChanged(e.Item);
        }

Code 13 - This method is the EventHandler for the state changes of the call

This way two unique stream identifiers are created in InCall status for the client. One ID is for sending audio data, the other ID is for receiving audio data from the remote end. This will be indicated for the client via OnInCall. Callstate.Completed status indicates that the actual call is completed. This way the created streams are removed from the service and from the call. The method notifies the client about the change with its last line.

The media data from the client will be received by the MediaDataReceived event handler (Code 14). It will forward the media data to the Ozeki VoIP SIP SDK via the myMediaSender object. Note: It needs to be mentioned that the received media data are data encoded by a compression mechanism. That is why, it needs to be decoded into raw PCM data. It is necessary because it is possible that the VoIP SDK uses another compression mechanism during call setup.

public void MediaDataReceived(object sender, GenericEventArgs<IData> e)
        {
            if (e.Item is AudioData)
            {
                var audioData = (AudioData) e.Item;
                myMediaSender.SendMediaData(codecConverter.Convert(audioData.CodecType, CodecType.PCM, audioData.RawData));
            }
        }

Code 14 - The MediaDataReceived event handler method

Call_MediaDataReceived event handler (Code 15) forwards the raw PCM media data from the VoIP SDK to the client via its mediaStream object. Then the media data will be compressed into smaller data size with a compression mechanism.

void Call_MediaDataReceived(object sender, VoIPEventArgs<VoIPMediaData> e)
        {
            if (mediaStream != null)
                mediaStream.SendMediaData(new AudioData(CodecType.PCM, e.Item.PCMData));
        }

Code 15 - This method forwards the media data to the remote client

A two-way communication is set up between the server and the client. This way the server can also invoke some certain methods of the client. It is similar to the case when the server can call the clients extended service functions. The difference is that in this case it is made via the InvokeMethod of the IClient object (Code 16).

void OnIncomingCall(string phoneNumber)
        {
            client.InvokeMethod("OnIncomingCall", phoneNumber);
        }

Code 16 - This method invokes the OnIncomingCall client-side function from the server-side code

Where the server indicates to the client that there is an incoming call from the phone number provided in parameter. InvokeMethod is the method declared in Code 17.

public void InvokeMethod(string methoName, params object[] parameters)

Code 17 - This is the definition of the function invocating method

Similarly, the SIPClient also sends the call status changes to the client via OnCallStateChanged and OnCallErrorOccured methods.

Client implementation

The Flash client represents a one-line webphone with the following functionally: start/receive/hangup calls, send/receive DTMF signals.

The client implements the GUI (graphical user interface) of a simple softphone with a keypad and a display. The connection with the server is ensured by the clients SIPClient class. This way it will be present from the loading of the interface. That is why creating an object that belongs to this class requires to load the web application (code 18)

protected function init(event:FlexEvent):void
{
        ...
        sipClient = new SIPClient();

        sipClient.addEventListener(ConnectionEvent.CONNECTION_STATE_CHANGED, connectionStateChanged);
        sipClient.addEventListener(RegistrationEvent.REGISTRATION_STATE_CHANGED, registrationStateChanged);
        sipClient.addEventListener(PhoneLineEvent.PHONE_LINE_STATE_CHANGED, phoneLineStateChanged);

        sipClient.addEventListener(CallStateEvent.CALL_STATE_CHANGED, callStateChanged);
        sipClient.addEventListener(CallErrorEvent.CALL_ERROR_OCCURRED, callErrorOccurred);
        sipClient.addEventListener(IncomingCallEvent.INCOMING_CALL, incomingCall);
        sipClient.addEventListener(DtmfEvent.DTMF_RECEIVED, callDtmfReceived);

        sipClient.connect();
}

Code 18 - The initialization function of the SIP client

It signs up to the events of the SIPClient in order to display the changes of the server on the interface. Then it connects to the server.

The interactions of the interface will also reach the servers certain services via this SIPClient object.

SIPClient

The SIPClient (Code 19) is responsible for ensuring an interface for the client and the server for the two-way client server communication. For easy implementation, the MediaConnection class provided by the client side implementation of the Ozeki MediaGateway SDK has been used. Since the program immediately connects to the server after loading, this object is initialized in the SIPClients constructor with the help of the server address parameter.

public function SIPClient()
{
        mediaConnection = new MediaConnection("localhost/SIPGateway");
        mediaConnection.client = this;

        mediaConnection.addEventListener(ConnectionEvent.CONNECTION_STATE_CHANGED, connectionStateChanged);
}

Code 19 - Initializing the media connection

Subscription to CONNECTION_STATE_CHANGED event is necessary to get information about the result of the connection to the server.

In order to allow the server to call the public methods of the SIPClient object, it needs to be specified for the Client property of the MediaConnection class that it needs to search the method (that is invited by the server) in this SIPClient object. (mediaConnection.xlient = this;)

Since the logic for SIP communication is on the server-side, this class is only responsible for transferring data to the GUI and the server and it also displays data arriving from the server on the GUI. The media data will be the exception. Media data is provided by the Microphone class and attached to a MediaStreamSender object as an input device after the telephone conversation is setup.

Note: It needs to be mentioned that the appropriate audio compression is made by the Ozeki VoIP SIP SDK so there are no further tasks besides attaching the media data. The audio data arriving from the server will be played simply by invoking the Play function on the MediaStreamReceiver object.

The public methods of the SIPClient can be divided into two groups: one of the group includes the methods that invoke the server side (such as: connect, call, hangUp, accept, reject, startDtmf, stopDtmf); the other group includes methods that can be invoked by the server. They are only invoked by the server (such as OnCallStateChanged, OnInComingCall,OnPhoneLineStateChanged, etc.).

Since the methods that invoke the server are not parts of the basic methods provided by the SDK (except for the Connect method), they are invoked via the invokeOnConnection function of the MediaConnection object that has the following method definition that is showni in Code 20.

public function invokeOnConnection(methodName:String, ... params):void

Code 20 - The method invocation function on the client-side

For example, the server side Call method of the client is invoked in the following way (Code 21):

public function call(dialNumber:String):void
{
        mediaConnection.invokeOnConnection("Call", dialNumber);
}

Code 21 - The invocation of the Call server-side method

The Call server-side method dials the phone number received in dialNumber parameter. The other server-side methods are also invoked this way and they are similarly simple. That is why, they are not detailed here.

The functions of the other method group that are invoked only by the server forward information from the server to the GUI. OnInCall function (Code 22) is an exception. It indicates the status of the telephone conversation setup when the audio transfer from the microphone needs to be started, then needs to be forwarded to the server. It also indicates when the audio (received from the remote end) needs to be played.

public function OnInCall(publishStreamName:String, playStreamName:String):void
{
        mediaStreamSender = new MediaStreamSender(mediaConnection);
        mediaStreamSender.attachMicrophone(Microphone.getMicrophone());
        mediaStreamSender.publish(publishStreamName);

        mediaStreamReceiver = new MediaStreamReceiver(mediaConnection);
        mediaStreamReceiver.play(playStreamName);
}

Code 22 - The OnInCall client-side function

The mechanism is the following:

  1. A MediaStreamSender object is created for sending audio data that arrive from the microphone.
  2. The Microphone object provided by Flash has been attached to this created object.
  3. In order to make the server play the outgoing media stream to the remote end (with mediaStreamSender.publish(publishStreamName); instruction) it is published with a unique name.

The other client will play this stream via its MediaStreamReceiver object, after it invoked the Play method on it with the unique ID published by the other client. In this case both stream IDs are generated by the server, then the server distributes these generated IDs to the clients as it can be seen in the code section above.

Different mediaStreams are used for calls that follow each other. That is why when a call is completed, the stream belongs to the given call needs to be closed and resolved. OnCallStateChanged function (Code 23) investigates the end of the call that will make the resolution via closeStreams() call.

private function connectionStateChanged(event:ConnectionEvent):void
{
        dispatchEvent(event);
}

private function closeStreams():void
{
        if(mediaStreamReceiver)
        {
                mediaStreamReceiver.close();
                mediaStreamReceiver = null;
        }
        if(mediaStreamSender)
        {
                mediaStreamSender.close();
                mediaStreamSender = null;
        }
}

Code 23 - Two basic functions for finishing the client-side application programming

If you have any questions or assistance, please contact us at info@voip-sip-sdk.com

You can select a suitable Ozeki VoIP SIP SDK license for building a Flash SIP softphone on Pricing and Licensing page >>>

Operating systems:

Microsoft Windows XP
Microsoft Windows Server 2003
Microsoft Windows Server 2008
Microsoft Windows Vista
Microsoft Windows 7
Microsoft Windows 8
Microsoft Windows 10

Developer environment:

Microsoft Visual Studio 2010
Microsoft .Net Framework 3.5 or 4.0
Flash builder 4.5 or other equivalent IDE
Flash player 10 +

Internet connection

Hardware requirements:

1 GHz or faster processor
1 GB RAM (32-bit) +

Ozeki Cookie Policy
Ozeki Informatics Ltd uses cookies to provide you the best experience on this website. The further use of the website will be considered as an agreement to the use of cookies. For more information read this website.

Cookies are enabled You are browsing the optimized version of this website. For more information read this website.