High performance VoIP SDK for .Net developers

VoIP SIP SDK

Source code explanation for using Ozeki C# VoIP SDK source for creating voice conference room

Download: Voice_Conference.zip

This page is entitled to be a source code explanation for help you use the Ozeki C# VoIP SDK source for creating voice conference room.

Graphical User Interface

This sample program is intended to be a demonstration for creating a conference conversation. Its interface is based on Microsoft Windows Forms technology. For making it simple but demonstrative, the sample program does not include design elements.

The sample program presents a conference room where participants can make conference conversations. It provides the option for making conference calls by mixing the audio data arriving from remote end (the audio data is mixed to be a single one). Finally, the mixed data is transferred to the participants of the conference room. The sample program displays incoming calls on the interface. Therefore, the user can accept or reject the incoming calls easily. The program also offers the option of automatic response. Automatic response means that incoming calls are automatically accepted.


Figure 1 - GUI

Running the program

The program automatically tries to register in the SIP PBX, that has been defined in the source code, via the specified SIP account right after it has been started. If you have not replaced the IP address of your PC during the configuration settings (for details check Configuration steps), the program cannot register into the SIP PBX and it cannot be used until the right configuration. In case of successful registration, the Registration succeeded notification is displayed on the interface. From this point the application is ready to connect calls.

Code

FormMain.cs code-behind file describes the control events belonging to the interface and connects the GUI with the logic. For being simple and representative, the sample program ignores the use of development sample and other conventions. Opening the FormMain.cs code-behind file you can see some lines of declaration at the beginning, that are required for the use of Ozeki VoIP SIP SDK.

public partial class FormMain : Form
{
    private ISoftPhone softPhone;
    private IPhoneLine phoneLine;
    private IPhoneCall currentCall;
    bool inComingCall;

    private Microphone microphone;
    private Speaker speaker;
    private ConferenceRoom conferenceRoom;
    ...

ISoftphone:
It represents a telephone and its telephoneline is represented by IphoneLine. A softphone can have more phonelines but this example uses one phoneline for being simple and demonstrative.

IphoneLine:
It represents a phoneline that can be registered into a SIP PBX, e.g.: ASTERISK, 3CX, or other PBXs provided by free SIP providers. It is registered via a SIP account.

PhoneLineInformation:
This is an enum type that represents the status of the phone line regarding to the PBX. E.g. registered, not registered, successful/unsuccessful registration, etc.

IPhoneCall:
It represents a call and its status, direction, which phoneline it has been established on, who is the called party, etc.

Microphone:
Class for capturing audio data with microphone.

Speaker:
Class for playing audio through speakers.

ConferenceRoom:
Class for audio conferencing.

The program initializes the softphone after it loads the GUI

The application tries to register to the specified SIP PBX right after loading. It does so with a method call; the call is made when the event of Windows Forms technology windows loading occurs. This is a 'Load' event where I call the following method:

 private void InitializeSoftPhone()
{
    try
    {
        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<PhoneLineState>>(phoneLine_PhoneLineInformation);

        softPhone.RegisterPhoneLine(phoneLine);


        microphone = Microphone.GetDefaultDevice();
        microphone.Start();

        speaker = Speaker.GetDefaultDevice();
        speaker.Start();

        conferenceRoom = new ConferenceRoom();
        conferenceRoom.ConnectSender(microphone);
        conferenceRoom.ConnectReceiver(speaker);
        conferenceRoom.StartConferencing();
    }
    catch (Exception ex)
    {
        MessageBox.Show(String.Format("You didn't give your local IP adress, so the program won't run properly.\n {0}", ex.Message), string.Empty, MessageBoxButtons.OK,
        MessageBoxIcon.Error);

        var sb = new StringBuilder();
        sb.AppendLine("Some error happened.");
        sb.AppendLine();
        sb.AppendLine("Exception:");
        sb.AppendLine(ex.Message);
        sb.AppendLine();
        if(ex.InnerException != null)
        {
            sb.AppendLine("Inner Exception:");
            sb.AppendLine(ex.InnerException.Message);
            sb.AppendLine();
        }
        sb.AppendLine("StackTrace:");
        sb.AppendLine(ex.StackTrace);

        MessageBox.Show(sb.ToString());
    }
}

Now make an instance of the telephone via the ’softPhone’ object. Here you need to specify the IP address of the PC and the port domain that can be used by the telephone. As the last parameter specify the port at which SIP messages arrives from the PBX are listened.

Subscribe to the event that handles incoming calls (’softPhone.IncommingCall’). This will be triggered when there are incoming calls from the remote end. Create a 'phoneline' with a SIP account. This can be a user account of your corporate SIP PBX or an account from a free SIP provider. Subscribe to the 'phoneLine.PhoneLineInformation' event of the created phoneline to display the status of the phoneline.

After this you only need to register the created 'phoneline' to your 'softphone'. In this example I register one 'phoneline' but, of course, it is possible to register more phonelines according to your needs. Now you can concentrate on call handling and call displaying on the GUI.

Handling of calls

Ozeki VoIP SIP SDK represents incoming and outgoing calls via IpPhoneCall interface. It includes the status of the given call, notifies which of the phonelines the call has been established on, and who is the called party. Calls can be accepted or hung up on this object. In this case, the program handles only incoming calls so let's have look for an actual example for this case.

a.) Handling of incoming calls

At the initialization of the softphone, subscribe to the event that handles incoming calls ('softPhone.IncommingCall'). This event is triggered if there is an incoming call on the phone and the IPhoneCall object that represent the call is transferred.

private void softPhone_IncomingCall(object sender, VoIPEventArgs<IPhoneCall> e)
{
    InvokeGUIThread(() =>
    {
        labelCallStateInfo.Text = "Incoming call";
        labelDialingNumber.Text = String.Format("from {0}", e.Item.DialInfo.UserName);
        IPhoneCall call = e.Item;
        inComingCall = true;
        if (phoneLine.AutoAnswer)
        {
            listBoxActiveCalls.Items.Add(call);
            WireUpCallEvents(call);
        }
        else
             currentCall = call;
    });
}

The application includes the pickup call method. This method is invoked if the checkbox assigned to it is checked on the interface. If it is enabled and there is an incoming call, the call will be picked up with the PickUpCall(call) method. In this way, the caller will be connected to the conference conversation.

private void buttonPickUp_Click(object sender, EventArgs e)
{
    if (inComingCall && currentCall!= null)
    {
        inComingCall = false;
        PickUpCall(currentCall);
        return;
    }

    if (currentCall != null)
        return;
}

You also need to subscribe to some events (WireUpCallEvents(p_call);) for accepting calls. Therefore, you will be notified about the changes in the call status (pickup, hang up). Furthermore, it is also required for processing the audio data arriving from the remote ends.

To handle audio data that potentially arrive from more incoming calls, I create an OzPipeStream for each call in a dictionar. This will include the audio data of the given call arriving from the remote end. These audio data will be mixed by the AudioMixer object.

I just would like to point out that OzPipeStream is a stram that empties the read data after reading, so as to help the tasks of AudioMixer.

Then, pickup the call and place it into the active call collection to be able to send out the mixed data to the remote end easier. On the interface, a listbox illustrates the active call list. The content of this control can be updated by calling listBoxActiveCalls.Items.Add(p_call);. Subscription for the necessary events in case of incoming calls:

private void WireUpCallEvents(IPhoneCall call)
{
    call.CallStateChanged += (call_CallStateChanged);
    call.DtmfReceived += (call_DtmfReceived);
    call.CallErrorOccured += (call_CallErrorOccured);
}

CallStateChanged
This event is responsible for displaying the changes in the call status.

MediaDataRecived
The audio data from remote end arrive via this event.

DtmfReceived
This event is responsible for processing the DTMF signals from the remote end.

You can be notified about the reasons that prevent the establishment of the call via call.CallErrorOccured (can be seen above). Such reason is e.g. when the called party is busy, the called party rejects the call, the called phone number does not exist, or it is not available.

b.) End Active calls

It is possible to ban participants from the conference conversation with the help of 'Hang up' button. That call will be hung up that is selected in the active call list.

private void buttonHangUp_Click(object sender, EventArgs e)
{
    if (currentCall != null)
    {
        inComingCall = false;
        currentCall.HangUp();
        currentCall = null;
    }
    labelDialingNumber.Text = string.Empty;
}

c.) Handling of audio data arriving from remote end

private void PickUpCall(IPhoneCall p_call)
{
    WireUpCallEvents(p_call);
    p_call.Accept();
    listBoxActiveCalls.Items.Add(p_call);

    conferenceRoom.AddToConference(p_call);
}

d.) Receiving DTMF signals

Receiving DTMF signals is very similar to receiving audio data. Regarding DTMF signal processing, this sample program only displays the reference value of the received DTMF signal on the interface.

Possibilities for further development

Regarding DTMF signal processing, this sample program only displays the DTMF signals arriving from the device. An application for creating more complex conference room can include IVR controlled functions that requires a more complex processing of DTMF signals.

Audiomixing and sending only demonstrate the simplicity of call connection by Ozeki VoIP SIP SDK in this sample program. In this way mixing does not include the function that would prevent the speaker's voice from returning to himself. Therefore, there is an echo at the speaker. This problem needs to be definitely overcome within the framework of an actual project.

Name:C# Voice Confernece Room Example Program
Download:Voice_Conference.zip (14.9 MB)


For further tips on utilization possibilities, please go to the fields of applications page!

For more information please contact us at info@voip-sip-sdk.com!