.NET Tutorials, Forums, Interview Questions And Answers
Welcome :Guest
Sign In
Win Surprise Gifts!!!

Top 5 Contributors of the Month
Sandeep Singh

Home >> Articles >> General >> Post New Resource Bookmark and Share   

 Subscribe to Articles

How to make your SIP SMS system

Posted By:Evan Miller       Posted Date: July 06, 2011    Points: 200    Category: General    URL: http://www.dotnetspark.com  

I'm writing this article because I would like to share my experiences of sip sms systems with you.

Graphical User Interface

The GUI of this sample program has been developed with Microsoft WPF (Window Presentation Foundation) technology. The reason for this is that it allows great flexibility regarding the appearance of the program. 

The main goal of this sample program is to demonstrate the simple and convenient use of Ozeki SDK (I do not enlist the great functions of WPF technology in this article). That is why I created a simple but representative GUI (Figure 1) with basic telephone functions. The softphone has all the functions that are required for establishing phone calls effectively like make a call, receive a call, sending and receiving DTMF signals and display of call events on the interface.

Running the program

After running the program the telephone automatically registers to the given SIP PBX with the given SIP account. If the registration process is ended successfully we can see Registration succeeded on the display. From this point the softphone is ready to establish and receive calls, to send and receive DTMF signals during calls for navigating in IVR systems. (The source code of the sample program includes settings that depend on the environment so after the download do not forget to customize it. For details please go to Configuration section).


PhoneMain.cs code-behind
 file belonging to the program interface describes the control events related to the interface and connects the GUI with the logics. The sample program focuses on simplicity and representativeness. The PhoneMain.cs file includes the full logic of the sample program. By opening this PhoneMain.cs file, you can see a few lines of declaration right the beginning that are needed for the use of Ozeki VoIP SIP SDK.

  1. public partial class PhoneMain : Form 
  2.  ISoftPhone softPhone; 
  3.  IPhoneLine phoneLine; 
  4.  PhoneLineInformation phoneLineInformation; 
  5.  IPhoneCall call; 
  6.  ActiveAudio ActiveAudioCallListener; 
  7.  AudioMixer Mixer; 
  8.  bool inComingCall; 
  9.  ... 

It represents a telephone, and its telephone line is represented by IphoneLine. It is also possible to develop a multiline phone.

It represents a telephone line that we can register to a SIP PBX, for example, Asterisk, 3CX, or to other PBXs that are offered by free SIP providers. Registration is made via a SIP account.

It is an enum type that represents the telephone line status related to the PBX. For example registered, not registered, successful/unsuccessful registration.

It represents a call: the status of the call, the direction of the call, on which telephone line it was created, who is the called person, etc.

It is an optional device and it helps process the incoming audio data that comes from the remote end.

It plays the received audio data on the speaker.

It processes the audio data that comes from the default input device (microphone) of the operation system.

The softphone is initialized after loading the GUI

By subscribing to the 'Loaded' event of Windows Form windows, it is possible to start the initialization and registration of Ozeki SDK softphone right after 'PhoneMain' window is loaded.

  1. private void InitializeSoftPhone() 
  2.  try 
  3.  { 
  4.  softPhone = SoftPhoneFactory.CreateSoftPhone( 
  5.  GetLocalIP().ToString(), 5700, 5750, 5700); 
  6.  softPhone.ChangeNATSettings(NATTraversalMethodType.NONE, """"""); 
  7.  softPhone.IncommingCall += 
  8.  new EventHandler 
  9.  >(softPhone_IncommingCall); 
  10.  phoneLine = 
  11.  softPhone.CreatePhoneLine( 
  12.  new SIPAccount(true"oz891""oz891""oz891"
  13.  "oz891""", 5060) 
  14.  ); 
  15.  phoneLine.PhoneLineInformation += 
  16.  new EventHandler>(phoneLine_PhoneLineInformation); 
  18.  softPhone.RegisterPhoneLine(phoneLine); 
  20.  ActiveAudioCallListener = ActiveAudio.Instance; 
  21.  Mixer = new AudioMixer(); 
  22.  Mixer.Add(ActiveAudioCallListener); 
  23.  } 
  24.  catch(Exception ex) 
  25.  { 
  26.  MessageBox.Show( 
  27.  String.Format("You didn't give your local IP adress, so the program won't run properly.\n {0}"
  28.  ex.Message), "Ozeki WPF Softphone Sample", MessageBoxButton.OK, MessageBoxImage.Error); 
  29.  } 

Create an instance of the phone via the 'softPhone' object and give the IP address of your computer and the port domain that can be used by the phone. Finally specify the port, at which the SIM messages arriving from the PBX are listened, as the last parameter.

Subscribe to the event that handles incoming calls of the telephone ('softPhone.IncommingCall') that occurs when there is an incoming call from the remote end.

Create a phoneLine with a SIP account that can be the user account of your corporate SIP PBX or a free SIP provider account. To display the status of the created telephone line, sign up to its'phoneLine.PhoneLineInformation' event.

When these things are done you only need to register the created 'phoneLine' to the 'softPhone'. In this example only one telephone line is registered but of course multiple telephone line registration is also available.

After these steps you only need to deal with the handling of the calls and to display them onto the GUI.

Handling the calls

Ozeki SDK represents the incoming and outgoing calls through IpPhoneCall interface. This interface includes the status of the given call, on which line it was created and who is the called person. On this object we can pick up or hang up calls. Let's see the event of the sample program.

a. Outgoing Calls

For establishing an outgoing call, enter the number you wish to dial. Then click the 'Pick Up' button and the call starts. The surface buttons are assigned to triggers so let's look at the 'Pick Up' button for details:

  1. private void buttonPickUp_Click(object sender, EventArgs e) 
  2.  if (inComingCall) 
  3.  { 
  4.  inComingCall = false
  5.  call.Accept(); 
  6.  return
  7.  } 
  9.  if (call != null
  10.  return
  12.  if (string.IsNullOrWhiteSpace(labelDialingNumber.Text)) 
  13.  return
  15.  if (phoneLineInformation != 
  16.  PhoneLineInformation.RegistrationSucceded && 
  17.  phoneLineInformation != PhoneLineInformation.NoRegNeeded) 
  18.  { 
  19.  MessageBox.Show("Phone line state is not valid!"); 
  20.  return
  21.  } 
  23.  call = softPhone.CreateCallObject(phoneLine, labelDialingNumber.Text); 
  24.  WireUpCallEvents(); 
  25.  call.Start(); 

Since you can make and pick up the call with the very same button first you need to decide if it is an incoming or an outgoing call with the help of a simple bool variable truth verification (Incoming calls will be detailed later). 

Before initiating a phone call, check if the phoneline has successfully registered to the server when registration is required. If an inappropriate result is returned the user is informed about the reason of the failure. 

If the phoneline is registered, create a IPhoneCall object representing a call via the'softPhone.Call' method and its parameters. The first parameter is the telephone line on which we would like to initiate calls, the second parameter is the phone number to be called. In order to make your calls successful, wire up to some Call Events. Therefore, the audio data arriving from the remote end, the DTMF signal or changes in call status can be processed effectively. The wire up process is demonstrated in the sample as follows:
  1. private void WireUpCallEvents() 
  2.  call.CallStateChanged += 
  3.  new EventHandler>(call_CallStateChanged); 
  5.  call.DtmfReceived += 
  6.  new EventHandler>>(call_DtmfReceived); 
  8.  call.CallErrorOccured += 
  9.  new EventHandler>(call_CallErrorOccured); 

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

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

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

Via the CallErrorOccured event above you can receive information about the reasons why the call was not created. For example: the called party is busy, the call is rejected, the called number does not exist or the called number is not available.

To wire up to these necessary events you only need to actually start a call. You can do it with the Start() function of the call object. In this example i t is the 'call.Start()' line.

b. Handling incoming calls

The Ozeki VoIP SIP SDK publishes the incoming calls through the 'ISoftphone' InComingCall event.

  1. private void softPhone_IncomingCall(object sender, VoIPEventArgs e) 
  2.  InvokeGUIThread(()=> 
  3.  { 
  4.  labelCallStateInfo.Text = "Incoming call"
  5.  labelDialingNumber.Text = String.Format("from {0}", e.Item.DialInfo); 
  6.  call = e.Item; 
  7.  WireUpCallEvents(); 
  8.  inComingCall = true
  9.  }); 

The code sample above is for handling this. It displays incoming calls on the display and registers onto the necessary events of the object representing incoming calls which was mentioned above. The incoming call variable notifies the Pick Up button if the call is an outgoing or an incoming one.

c. Ending a call in progress

There are three different ways for ending a call that is in progress.

  • We end the call
  • The remote end ends the call
  • There is a break in network connection
You need to take care of ending the call only if you want to end it. Just like the 'Pick Up' button the 'Hang Up' button is also connected to the event manager.

If you use the 'Hang Up' button the following event manager is responsible for ending the call:
  1. private void buttonHangUp_Click(object sender, EventArgs e) 
  2.  if (call != null
  3.  { 
  4.  inComingCall = false
  5.  call.HangUp(); 
  6.  call = null
  7.  } 
  8.  labelDialingNumber.Text = string.Empty; 

Now it needs to be checked if there is an active call. If there is an active call you need to end it and delete the information related to dialing.
d. Displaying call status

Ozeki VoIP SIP SDK provides the following information about the call status: ringing, InCall, Completed, Rejected, etc. These call statuses are displayed via the CallStateChange event of 'call' object. In this sample program I only focused on the essential options for being simple but demonstrative. Based on these essential options you can easily create further options.

  1. private void call_CallStateChanged(object sender, VoIPEventArgs e) 
  2.  InvokeGUIThread(() => { labelCallStateInfo.Text = e.Item.ToString(); }); 
  4.  switch (e.Item) 
  5.  { 
  6.  case CallState.InCall: 
  7.  Mixer.AttachToCall(call); 
  8.  break
  9.  case CallState.Completed: 
  10.  Mixer.Detach(call); 
  12.  call = null
  13.  InvokeGUIThread(() => { labelDialingNumber.Text = string.Empty; }); 
  14.  break
  15.  case CallState.Cancelled: 
  16.  call = null
  17.  break
  18.  } 

The code above is only for reacting to the changes in the call status. For example: If the phone is picked up it starts the voice recording so we can send our audio data to the other party. Moreover it initializes the devices that are necessary for playing incoming audio data.
e. Handling audio data arriving from the remote end

Since we wired up to the MediaDataReceived event of the 'call' in case of both outgoing and incoming calls, the incoming PCM audio data only needs to be forwarded to the sound system as it is demonstrated below.

  1. private void call_MediaDataReceived(object sender, VoIPEventArgs e) 
  2.  { 
  3.  if (speakerStream != null
  4.  speakerStream.Write(e.Item.PCMData, 0, e.Item.PCMData.Length); 
  5.  } 

f. Forwarding incoming audio from the microphone to the remote end via the SDK

The PCM audio data originating from the microphone is forwarded to the 'call' object that represents the actual call via the process of SendMediaData. Then audio data is compressed by Ozeki SIP SDK with the right audio codecs and then sent to the intended person according to the built communication channel.
g. Receiving DTMF signals

DTMF signals can be received similarly to audio data. Regarding processing, this sample program only displays the reference value of the received DTMF signal on the interface.

  1. private void call_DtmfReceived(object sender, VoIPEventArgs> e) 
  2.  { 
  3.  InvokeGUIThread(() => 
  4.  { 
  5.  labelCallStateInfo.Text = String.Format("DTMF signal received: {0} ", e.Item.Item2.Signal); 
  6.  }); 
  7.  } 

h. Sending DTMF signals

DTMF signals can be sent after the call is established for - for example - navigating i n the IVR menu system of the called call center. Ozeki VoIP SIP SDK allows to send DTMF signals in a simple way: the 'StartDTMFSignal' method is called in the object representing the given call in the following way:
  1. private void buttonKeyPadButton_MouseDown(object sender, MouseEventArgs e) 
  2.  if (call != null && call.CallState == CallState.InCall) 
  3.  { 
  4.  var btn = sender as Button; 
  5.  if (btn != null
  6.  { 
  7.  int id; 
  9.  if (btn.Tag != null && int.TryParse(btn.Tag.ToString(), out id)) 
  10.  { 
  11.  call.StartDTMFSignal(VoIPMediaType.Audio, id); 
  12.  } 
  13.  } 
  14.  } 

According to RFC2833 the sending of the DTMF signal can represent how long the DTMF signal is being sent. In the sample program I would like to demonstrate this with the events ofMouseDown and MouseUP buttons. By using MouseDown, the DTMF signal of the pressed button starts to be sent. By using MouseUP, the sending of the given DTMF signal is ended. The way of ending DTMF signal is similar to the way of start. On the object that represents the current call, the 'StopDTMFSignal' method is called in the following way (where the ID is the number-type DTMF signal according to the reference relating to the pressed button):
  1. call.StopDTMFSignal(VoIPMediaType.Audio, id); 

 Subscribe to Articles


Further Readings:


No response found. Be the first to respond this post

Post Comment

You must Sign In To post reply
Find More Articles on C#, ASP.Net, Vb.Net, SQL Server and more Here

Hall of Fame    Twitter   Terms of Service    Privacy Policy    Contact Us    Archives   Tell A Friend