Ozeki VoIP SDK - Product Guide
Developers Guide
Source code explanation for creating a Callback form using the Ozeki C# SIP VoIP softphone source
![]() |
Download: | Callback_Form.zip |
This page is entitled to be a source code explanation for creating a Callback form using the Ozeki C# SIP VoIP softphone source.
Graphical User Interface
The sample program has the well-known MS Windows Forms Graphical User Interface (Figure 1). In the upper section of the GUI the status of the given SIP users is displayed. On the interface, it is possible to enter the time of callback and two telephone numbers. By clicking on the Add request button you can finalize the callback request. The Events section informs about the connection of the two parties.

Figure 1 - GUI
Running the program
After the program is started, it will automatically try to register the SIP user in
the SIP PBX. If the registration is successful, you can see "Registration succeeded"
notice. From this point the program is ready to work. You can enter a future date,
when this pre-entered date is come the program will call the phone number of the
operator.
If this call is accepted then the program also calls the customer who required
callback. If the customer also accepts the call, the program transfers the audio
data between the two parties (in other words, the two participants are connected).
If one of the participants hangs up the call or the call is never established, the
call toward the other participant is automatically ended.
The Code
FormCallback.cs code-behind file includes events related to the interface and connects the GUI with the logic. The sample program is simple and representative that is why it does not include development samples and other convention usage. Therefore, the FormCallback.cs file includes the whole logic of the sample program. If you open this file, you can see a few lines of declaration that are needed to connect two call lines:
public partial class FormCallback : Form
{
const bool OperatorCall = false;
const bool CustomerCall = true;
ISoftPhone softPhone;
IPhoneLine phoneLine;
PhoneLineState phoneLineInformation;
IPhoneCall calloperator;
IPhoneCall callcustumer;
Timer countDownTimer;
private PhoneCallAudioSender operatorSender = new PhoneCallAudioSender();
private PhoneCallAudioReceiver operatorReceiver = new PhoneCallAudioReceiver();
private PhoneCallAudioSender customerSender = new PhoneCallAudioSender();
private PhoneCallAudioReceiver customerReceiver = new PhoneCallAudioReceiver();
private MediaConnector connector = new MediaConnector();
OperatorCall/CustomerCall:
They are constants that notifies about the direction of calls.
ISoftphone:
It demonstrates a telephone and its telephone line is represented by the IphoneLine.
A softphone can have more telephone lines, however, this example has one telephone
line for making it simpler.
IphoneLine:
It represents a telephone line that can be registered in a SIP PBX, e.g. Asterisk,
3CX or other PBXs provided by free SIP services providers. The telephone line is
registered in the SIP PBX via a SIP account.
PhoneLineState:
This is an enum type that represents the status of the telephone line regarding the
PBX e.g.: registered, unregistered, successful/unsuccessful registration, etc.
IPhoneCall:
It represents a phone call. It describes the status and the direction of the call,
informs about which phone line the call is established on, who the called party is, etc.
MediaConnector:
Class for creating connections between 'VoIPMediaHandler' objects.
PhoneCallAudioSender:
It can send audio data to the attached 'IPhoneCall' object.
PhoneCallMediaReceiver:
It can receive media data from the attached 'IPhoneCall' object.
Softphone is initialized after loading the GUI
With the Load event (typical for Windows Forms windows), I can make the program connected and registered to the SIP PBX by calling InitializeSoftPhone:
private void InitializeSoftPhone()
{
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);
connector.Connect(operatorReceiver, customerSender);
connector.Connect(customerReceiver, operatorSender);
}
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());
}
}
}
Here, you need to create an instance of the telephone via the softPhone object. Specify the
IP address of the computer and the port domain that can be used by the softphone. The
last parameter should be the port that listens to SIP messages coming from the PBX.
Subscribe to the event of your telephone that handles incoming calls (softPhone.IncomingCall).
It is generated by incoming calls from remote users. In this sample program, incoming calls
have no any roles in this way they will be automatically rejected.
Now create a phoneline with a SIP account that can be a user account of your corporate
SIP PBX or a free SIP service provider account. To be able to display the created
phoneline status, subscribe to its phoneLine.PhoneLineInformation event.
Then you only need to register the created phoneLine to your softPhone. In this
example, one phoneline is registered but, of course, more phonelines can also be
registered. After these steps you only need to work with call handling and displaying
calls on the GUI.
How to connect calls
For connecting two calls, it is required to establish two successful calls with the two given telephone numbers (The call is successful if it is accepted by the called party). First, the operator is called and if the call is successful, the customer is also called. When the two calls are connected the audio data are transferred between the two participants by the sample program.
a.) Initiate a call
Initiation of calls is made in a set time instant. I make the examination of this time instant with the help of the timer offered by .Net Framework. This timer examines in every seconds if it is the time for making the call. When it is time for call, the BeginCall(bool IsCustomerCall) method is called. This method dials the operator or the customer according to the value of the bool parameter. Meanwhile, it informs us about this procedure on the user interface.
private void BeginCall(bool IsCustomerCall)
{
if (IsCustomerCall && !String.IsNullOrEmpty(textBoxCallbackPhone.Text))
{
callcustumer = softPhone.CreateCallObject(phoneLine, textBoxCallbackPhone.Text);
WireUpCallEvents(callcustumer);
InvokeGUIThread(() =>
{
listBoxEvents.Items.Add(String.Format("{0} call starts.", callcustumer));
});
customerReceiver.AttachToCall(callcustumer);
customerSender.AttachToCall(callcustumer);
callcustumer.Start();
}
else
{
if (string.IsNullOrEmpty(textBoxOperator.Text))
return;
if (phoneLineInformation != PhoneLineState.RegistrationSucceeded && phoneLineInformation != PhoneLineState.NoRegNeeded)
{
MessageBox.Show("Phone line state is not valid!");
return;
}
calloperator = softPhone.CreateCallObject(phoneLine, textBoxOperator.Text);
WireUpCallEvents(calloperator);
InvokeGUIThread(() =>
{
listBoxEvents.Items.Add(String.Format("{0} call starts.", calloperator));
});
operatorSender.AttachToCall(calloperator);
operatorReceiver.AttachToCall(calloperator);
calloperator.Start();
}
}
To initiate a call, you need to create an IPhoneCall object representing a call by using teh ’softPhone.Call’ method and its parameters. The first parameter is the phone line via which you wish to initiate the call. The second parameter is the phone number to be called. To make a successful call, you need to subscribe to specific events. Therefore, the audio data and DTMF signals arriving from the remote end, or the changes of the call status can be processed efficiently. I made the subscription in the sample program as follows:
private void WireUpCallEvents(IPhoneCall call)
{
call.CallStateChanged += (call_CallStateChanged);
call.DtmfReceived += (call_DtmfReceived);
call.CallErrorOccured += (call_CallErrorOccured);
}
CallStateChanged:
This event is for demonstrating the changes in the call status.
MediaDataRecived:
The audio data from the remote telephone device arrives via this event.
DtmfReceived:
This event is responsible for processing DTMF signals that are arrived from the remote end.
You will be notified about the causes that prohibit the call via the call.CallErrorOccured
event. Such cause is for example, when the called party is busy, the called party ignores
the call, the called phone number does not exist or it is unavailable. After subscribing
for these necessary events you only need to actually initiate the call with the Start()
method of the ’call’ object. In this sample program it is the ’call.Start()’ line.
Handling of incoming calls
Ozeki VoIP SIP SDK publishes incoming calls via ’ISoftphone’ InComingCall event. Since incoming calls are not determined in the sample program, optional incoming calls are rejected immediately.
private void softPhone_IncomingCall(object sender, VoIPEventArgs<IPhoneCall> e)
{
e.Item.Reject();
}
Displaying call status
Regarding the call status, Ozeki VoIP SIP SDK provides the following information: Ringing, InCall, Completed, Rejected, etc. These statuses are displayed via the CallStateChanged event of ’call’ object. In this sample program I concentrated on the basic options. So the further possibilities can be easily created based on these basic ones.
private void call_CallStateChanged(object sender, VoIPEventArgs<CallState> e)
{
InvokeGUIThread(() =>
{
labelCallStateInfo.Text = e.Item.ToString();
listBoxEvents.Items.Add(String.Format("{0} call statechanged: {1}",sender,e.Item.ToString()));
});
switch (e.Item)
{
case CallState.InCall:
if ((IPhoneCall)sender==calloperator)
{
BeginCall(CustomerCall);
}
break;
case CallState.Completed:
case CallState.Cancelled:
HangUpCall((IPhoneCall)sender);
calloperator = null;
callcustumer = null;
break;
}
}
In the code above you can see how the program reacts to the changes in the call event. In case of „Incall” status, if changes occur in the call object of the operator, the call is started toward the customer. If one of the calls is hanged up, the other call is also hanged up with HangupCall(IPhoneCall call) method. This will hang up the given call via the Stop() method of „IPhoneCall” object.
Handling of audio data arriving from remote end
customerReceiver.AttachToCall(callcustumer); customerSender.AttachToCall(callcustumer);
Receiving DTMF signals
Receiving DTMF signals works in similar way as receiving audio data. The program forwards incoming signals to the other call and displays the reference value of the DTMF signals on the interface in the following way:
private void call_DtmfReceived(object sender, VoIPEventArgs<DtmfInfo> e)
{
DtmfInfo dtmfInfo = e.Item;
InvokeGUIThread(() =>
{
labelCallStateInfo.Text = String.Format("DTMF signal received: {0} ", dtmfInfo.Signal.Signal);
listBoxEvents.Items.Add(String.Format("{0} sended the following DTMF sign: {1}", sender, dtmfInfo.Signal.Signal));
});
}
Possibilities for further development of the IVR system
The following list enlists the functions that are not included in the sample program but
there is a possibility to implement them with Ozeki VoIP SIP SDK. For further information
please contact us at info@voip-sip-sdk.com.
These further functions can also be realized with Ozeki VoIP SIP SDK effectively:
- Since this sample program is developed to be a simple demonstration it handles only
one phoneline. However, if it is required it is possible to register in more phonelines
when you use Ozeki VoIP SIP SDK.
- There is also room for making and serving more callback requests at the same time. For further tips on utilization possibilities, please go to fields of applications page!
For further information please do not hesitate to contact us at: info@voip-sip-sdk.com!
If you have not downloaded Ozeki VoIP SIP SDK yet, you can do it right now by
clicking the download link!
Pricing and licensing information is available at How to buy page or contact
our sales team at info@voip-sip-sdk.com!
INTERMEDIATE
VoIP technology walkthrough
Softphone development
Webphone development
Mobile development
Voice recording
GETTING AROUND
Sitemap
Search the manual
API documentation
FAQ
Appendix


