C# VoIP Softphone Video Tutorial Part 3
SIP call controlling

Download: my-first-soft-phone-three.zip (Tutorial part 3)

This video demonstrates the final steps concerning to how to build a softphone by using Ozeki VoIP SIP SDK. This tutorial is the 3. part of a 3-part video tutorial series, in which you can learn how to create a call status display and how to add such an advanced SIP call control features as call transferring, call holding/unholding or redialing.

From the previous parts of the series, you could learn how to create a softphone, which can register to a PBX, able to dial numbers, make and accept calls, while logging everything into the lb_Log ListBox.

From the final episode of the series, you can learn how to create a status display, and how to implement special call control features:


Step 1 - Creating a status display

The status display of the softphone will be represented by a TextBox (called "tb_Display" in the example), so at the Design View, drag and drop a TextBox to your Form, from the Toolbox.
This TextBox will be used to display the main events' results, such as the call's and the phone line's states. To do it, you need to insert a few commands into your methods:

  • at the softPhone_inComingCall() method, you need to add the following line to the lambda expression, to get and display the caller's phone number:
    tb_Display.Text = "Ringing (" + e.Item.DialInfo.Dialed + ")";
    
    after the changes, the InvokeGUIThread() method will look like:
    InvokeGUIThread(() => { lb_Log.Items.Add("Incoming call from: " + e.Item.DialInfo.ToString()); tb_Display.Text = "Ringing (" + e.Item.DialInfo.Dialed + ")"; });
    
  • at the call_CallStateChanged() method, also add the following line to the lambda expression:
    tb_Display.Text = e.State.ToString();
    
    This will display the call's current state, when it changes.
  • when the call ends, the status display should be empty, so insert this line into the lambda expression at the call's ending block:
    tb_Display.Text = string.Empty; 
    
    Please note that, you can also insert this line to the initializer method of the softphone (called InitializeSoftPhone() in the example), to make sure about your display textbox is empty at the startup.
  • when you are dialing, you would probably like to see the dialed number, so to the end of the buttonKeyPadButton_Click() method, add:
    tb_Display.Text += btn.Text.Trim();
    
    It's highly recommended to remove the following line, and change all of the dependencies of its Text field to the tb_Display TextBox's Text field, over the whole source code:
    lbl_NumberToDial.Text += btn.Text.Trim();  
    
    This will allow you to follow everything within the status display, and to edit the dialed numbers from your computer's keyboard as well.
    You can use the label for other purposes, or you can even remove that.
  • whenever the Hang Up button is being clicked, the status display should be cleared, so add this line to the end of the button's Click event:
    tb_Display.Text = string.Empty;
    
  • at the Pick Up button's Click event, you've set a case during the previous tutorial, which is checking if the softphone wasn't able to register to the PBX. In this case, you can display that the phone is offline:
    tb_Display.Text = "OFFLINE";
    

Step 2 - Creating the special buttons

From this example, you can learn how to redial, put the call on hold, take the call off hold, and transfer the call to another number.
For this purpose, you will need to add 3 new Buttons to your Form: Redial, Hold, Transfer.

Redial button

The function of this button is to dial the last called, or the last caller's phone number.
To be able to do it, you will need to follow the following steps:

  • to store the last called or the last caller's number, you have to create a new String variable (called "reDialNumber" in the example). At the softphone's initialization the variable should be set to be empty.
  • when there is an incoming call, the caller's number should be stored in the previously created String value. To do this, at the softPhone_inComingCall() method, you have to add the following line:
    reDialNumber = e.Item.DialInfo.Dialed;
    
  • the calls which are going to be made, are being created at the Pick Up button's Click event, so you can store the last called number here, at the creation of the call object:
    reDialNumber = tb_Display.Text;
    
    As you can see, the TextBox's Text field is simply going to be stored in the "reDialNumber" variable, when the call is about to be made.
  • if you are done with the previous steps, you have to implement the Redial button's Click event:
    private void btn_Redial_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(reDialNumber))
                return;
    
            if (call != null)
                return;
    
            call = softPhone.CreateCallObject(phoneLine, reDialNumber);
            WireUpCallEvents();
            call.Start();
        }
    
    This method checks first, if there is a number to be dialed, and there should be no active call as well, than it simply creates a call object, subscribes to that's events, and makes the call.

Hold/Unhold button

The function of this button is to be able to put the call on hold, and to take that call off hold.
There are two types of the Hold function:

  • LocalHeld: you've put the call on hold
  • RemoteHeld: the other party has put the call on hold.

Please note that, you can only take the call off hold, if that is LocalHeld.

To implement the Hold button's tasks, please follow these steps:

  • you have to create a boolean variable, which will store if you are holding a call or not. In the example this variable is being called "localHeld". This variable's value should be "false" at the softphone's initialization, since you have no held call at the startup.
  • when the call's state is "Answered", the Hold button should be enabled, and its Text field should be "Hold":
    btn_Hold.Enabled = true;
    btn_Hold.Text = "Hold";
    
  • you have to handle a new call state: "LocalHeld". When the call enters into this state, the media devices should be stopped by the previously written StopDevices() method:
    if (e.State == CallState.LocalHeld)
        {
            StopDevices();
        }
    
  • if the call is being taken off from hold, it enters into the "InCall" state. Within this state, you have to enable the Hold button again, and you also have to restart the devices, by the previously written StartDevices() method:
    if (e.State == CallState.InCall)
        {
            btn_Hold.Enabled = true;
            btn_Hold.Text = "Hold";
            StartDevices();
        }
    
  • when the call ends, you have to set the boolean variable's value back to its default value, which is "false".
  • if you are done with these steps, you are ready to implement the Hold button's Click event:
    private void btn_Hold_Click(object sender, EventArgs e)
        {
            if (call == null)
                return;
    
            if (!localHeld)
            {
                call.Hold();
                btn_Hold.Text = "Unhold";
                localHeld = true;
            }
            else
            {
                btn_Hold.Text = "Hold";
                localHeld = false;
                call.Unhold();
            }
        }
    
    This method checks first, if there is an active call or not, since to be able to put a call on hold, it is necessary to be in one.
    After that, it checks the localHeld variable's value:
    • true: puts the call on hold by calling the call object's HoldCall() method, than sets the button's Text field to "Unhold", and the localHeld variable's value to "ture".
    • false: sets the button's Text field to "Hold", the localHeld variable's value to "false", and calls the call object's UnholdCall() method, to take the call off hold.

Transfer button

If you would like to transfer a call to an another destination, there are several ways to do this with Ozeki VoIP SIP SDK; for example you can transfer the call with one of the BlindTransfer() or the AttendedTransfer() methods, or you can forward the call with the ForwardCall() one:

  • BlindTransfer(): using this during a call, the third party's phone starts to ring, like it would be dialled first, and not yours. When the third party answers the call, you are stepping out from that.
  • AttendedTransfer(): using this during a call, you can notify the third party about the incoming call by calling it, and then redirect the call.
  • ForwardCall(): without answering the call, you can set the softphone to redirect the incoming call to an other destination. (For example: if you leave your office, you can forward the office's phone's incoming calls to your mobile phone.)

This example will use the BlindTransfer() method, and to make your softphone to be able to transfer calls, you just have to implement the Transfer button's Click event:

private void btn_Transfer_Click(object sender, EventArgs e)
	{
	    string transferTo = "1001";
	
	    if (call == null)
	    	return;
	
	    if (string.IsNullOrEmpty(transferTo))
	        return;
	
	    call.BlindTransfer(transferTo);
	    lb_Log.Items.Add("Transfering to:" + transferTo);
	}

As you can see, the destination number of the transferring is set at the source code as a String variable, but you can create a TextBox within your GUI to ask the user about this number, as a practice.
The method checks first, if there is an active call and the destination of the transfer is set, than calls the call object's BlindTransfer() method, and routes the call to the set destination number.
You can also log this event to the lb_Log ListBox.

Conclusion

From these tutorials, you could learn how to begin the developement of a softphone with Ozeki VoIP SIP SDK, and you could also create a softphone, which is able to register to a PBX with a SIP account, and can make, accept and control calls through Graphical User Interface.

More information