Click here to Skip to main content
Click here to Skip to main content

Tagged as

Go to top

SIP SMS Example

, 9 Jun 2011
Rate this:
Please Sign up or sign in to vote.
How to create a C# SIP SMS example

Introduction

The importance of SIP messages is great because often they are used for various purposes. They are used for establishing phone calls, making complementary actions, etc. Today when we live in a rushing world, fast and efficient communication is more important than ever. SMS technology offers one of the quickest ways to send information to each other. This way, you can be absolutely sure that your message will be received by the recipient because most people keep their mobile phones near themselves.

This sample program was developed to give an effective solution for this kind of matter. During development, I used the SDK offered by Ozeki and the Microsoft Windows Forms presentation technology.

I developed a telephone which can forward and receive phone calls and it also sends and receives DTMF signals to navigate in IVR systems.

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, on the display Registration succeeded can be seen. From now on, the softphone is ready to make, receive calls, during the calls it can send, receive DTMF signals to navigate in IVR systems. (The source code of the sample program contains settings that depend on the environment so after the download do not forget to customize it.) When the call is ended, a notification is received about the keywords.

Code

The PhoneMain.cs code behind file writes down the actuating events which are related to the interface and connects the logics to the GUI. The sample program lacks design samples and other proprieties and focuses on simplicity because it is only for presentation. This means that the PhoneMain.cs file consists of the full logic of the sample program. As you open the file, you can see a few lines of declaration which are needed to use Ozeki VoIP SIP SDK.

public partial class PhoneMain : Form
    {
        ISoftPhone softPhone;
        IPhoneLine phoneLine;
        PhoneLineInformation phoneLineInformation;
        IPhoneCall call;
        OzPipeStream speakerStream;
        ozWavePlayer wavePlayer;
        ozWaveRecorder waveRecorder;
        bool inComingCall;
        Stream ReceivedStream;
        Stream SentStream;

ISoftphone

It represents a telephone, and its telephone line is represented by the IphoneLine. There can be more telephone lines which means that we can develop a multi line phone.

Iphoneline

It represents a telephone line that can be registered to a SIP PBX, for example, Asterisk, 3CX, or maybe to other PBXs that are offered by SIP providers. Registration happens through SIP account.

PhoneLineInformation

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

IphoneCall

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

OzPipeStream

It is an optional device and it helps in the processing of the incoming sound data which comes from the other party.

ozWavePlayer

It plays the received sound data on the speaker.

ozWavRecorder

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

ReceivedStream

It is the stream that saves the received stream.

SentStream

It is the stream that saves the sent stream.

Thereby assign to the 'Loaded' events of Windows Form window and after the loading of 'PhoneMain' window, the initialization and registration of Ozeki SDK softphone can be started.

private void InitializeSoftPhone()
        {
            softPhone = SoftPhoneFactory.CreateSoftPhone
			("192.168.91.42", 5700, 5750, 5780);
            softPhone.IncommingCall += new EventHandler
            	<VoIPEventArgs<IPhoneCall>>(softPhone_IncommingCall);
            phoneLine = softPhone.CreatePhoneLine(new SIPAccount
            (true, "oz891", "oz891", "oz891", 
            "oz891", "192.168.91.212", 5060));
            phoneLine.PhoneLineInformation += new EventHandler<VoIPEventArgs
            <PhoneLineInformation>>(phoneLine_PhoneLineInformation);

            softPhone.RegisterPhoneLine(phoneLine);
        }

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

For an outgoing call, we provide the number we want to dial. Then, press the Pick Up button and the call starts. The interface buttons are addressed to triggers so let us look at it in the case of the ’Pick Up’ button.

private void buttonPickUp_Click(object sender, EventArgs e)
        {
            if (inComingCall)
            {
                inComingCall = false;
                call.Accept();
                return;
            }

            if (call != null)
                return;

            if (string.IsNullOrWhiteSpace(labelDialingNumber.Text))
                return;

            if (phoneLineInformation != PhoneLineInformation.RegistrationSucceeded 
            && phoneLineInformation != PhoneLineInformation.NoRegNeeded)
            {
                MessageBox.Show("Phone line state is not valid!");
                return;
            }

            call = softPhone.Call(phoneLine, labelDialingNumber.Text);
            WireUpCallEvents();
            call.Start();
        }

Below, you can see how I did the wire up:

private void WireUpCallEvents()
        {
            call.CallStateChanged += new EventHandler
            <VoIPEventArgs<CallState>>(call_CallStateChanged);
            call.MediaDataReceived += new EventHandler
            <VoIPEventArgs<VoIPMediaData>>(call_MediaDataReceived);
            call.DtmfReceived += new EventHandler<VoIPEventArgs
            <Tuple<VoIPMediaType, DtmfSignal>>>(call_DtmfReceived);
            call.CallErrorOccured += new EventHandler
            <VoIPEventArgs<CallError>>(call_CallErrorOccured);
        }

Through the CallErrorOccured event information is received about why the call was not created. They can be the following: the call is rejected, the called party is busy, the called number is not available or the number does not exist.

In order to wire up to these essential events, start a real call. You can achieve this with the Start function of the call object. It is the ’call.Start()’ line in the example.

The Ozeki VoIP SIP SDK publicates the incoming calls through the ’ISoftphoneInComingCall event.

private void softPhone_IncommingCall(object sender, VoIPEventArgs<IPhoneCall> e)
        {
            InvokeGUIThread(()=>
                 {
                     labelCallStateInfo.Text = "Incoming call";
                     labelDialingNumber.Text = String.Format
				("from {0}", e.Item.DialInfo);
                     call = e.Item;
                     WireUpCallEvents();
                     inComingCall = true;
                 });
        }

The code sample shown above handles this and if there is an incoming call, it signals the call on the display. Then register to the necessary events of the incoming calls. The incoming call variable signals for the ’Pick Up’ button if it is an outgoing or an incoming call.

The ’Hang Up’ button is also connected to the event handler similarly to the ’Pick Up’ button. The event handler shown below ends the call, you only need to press the ’Hang Up’ button.

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

Ozeki VoIP SIP SDK gives information about the status of the calls. They can be the follows: InCall, Completed, Rejected, Ringing, etc. Through the CallStateChange event, the displaying of these call status happens. The sample program does not handle all possibilities because I only concentrated on the vital ones. According to these significant programs, the other programs can be created easily.

private void call_CallStateChanged(object sender, VoIPEventArgs<CallState> e)
        {
            InvokeGUIThread(() => { labelCallStateInfo.Text = e.Item.ToString(); });

            switch (e.Item)
            {
               ozWaveFormat waveFormat = new ozWaveFormat(8000, 16, 1);
	      ReceivedStream = new ozWaveFileWriter(waveFormat, receivedFilePath);
              SentStream = new ozWaveFileWriter(waveFormat, sentFilePath);
 
              waveRecorder = new ozWaveRecorder();
              waveRecorder.DataArrived += waveRecorder_DataArrived;
              waveRecorder.StartRecording();
 
              speakerStream = new OzPipeStream();
              wavePlayer = new ozWavePlayer(speakerStream);
              wavePlayer.Play();
              break;
                case CallState.Completed:
                    waveRecorder.Dispose();
                    speakerStream.Dispose();
                    speakerStream = null;
                    wavePlayer.Dispose();

                    call = null;
                    InvokeGUIThread(() => 
			{ labelDialingNumber.Text = string.Empty; });
                    break;
                case CallState.Cancelled:
                    call = null;
                    break;
            }        
        }

Since at the outgoing/incoming wire up to the ’call’ MediaDataReceived, the incoming PCM sound data only needs to be forwarded to the sound system as it is shown below:

private void call_MediaDataReceived(object sender, VoIPEventArgs<VoIPMediaData> e)
        {
            if (speakerStream != null)
                speakerStream.Write(e.Item.PCMData, 0, e.Item.PCMData.Length);
	   if (ReceivedStream.CanWrite)
            {
                ((ozWaveFileWriter)ReceivedStream).Save(e.Item.PCMData);
            }
        }

Pass the PCM sound data that is originated from the microphone to the call object that represents the actual call. This happens through the process of SendMediaData and the sound will be sent according to the built communication channel. The sound data will be compressed with the help of the right sound codec and then it will be forwarded to the recipient.

private void waveRecorder_DataArrived(object sender, ozDataArrivedEventArgs e)
        {
            if (call != null)
                call.SendMediaData(VoIPMediaType.Audio, e.Data);
	   if (SentStream.CanWrite)
            {
                ((ozWaveFileWriter)SentStream).Save(e.Data);
            }
        }

After the call has been established, there is an opportunity to send DTMF signals. You can navigate in the called customer service’s IVR system. Ozeki VoIP SIP SDK sends DTMF signals in a simple way. Invite the ’StartDTMFSignal’ method on the object that represents the current call as it is shown below:

private void buttonKeyPadButton_MouseDown(object sender, MouseEventArgs e)
        {
            if (call != null && call.CallState == CallState.InCall)
            {
                var btn = sender as Button;
                if (btn != null)
                {
                    int id;

                    if (btn.Tag != null && int.TryParse(btn.Tag.ToString(), out id))
                    {
                        call.StartDTMFSignal(VoIPMediaType.Audio, id);
                    }
                }
            }
        }

Ending DTMF signal is similar to the start. On the object which represents the current call, the 'StopDTMFSignal' method is invited. Below this can be seen where the id is a referential number type DTMF signal and it is related to the pressed button.

call.StopDTMFSignal(VoIPMediaType.Audio, id);

Ozeki VoIP SIP SDK informs the content of SIP messages in a simple way. To do so, assign to the event that is shown below:

OzSIP.Log.SIPMessageLogger.NewSIPMessage += SIPMessageLogger_NewSIPMessage;

Now check the message content:

void SIPMessageLogger_NewSIPMessage(object sender, VoIPEventArgs<string> e)
  { 
    if (e.Item.Contains(txb_SIPText.Text))
      {
         SendSMS();
      }
  }

If there is a match for the searched SIP text snippet, you only need to send an SMS. It can be implemented with a request sent to the http API of an SMS server:

private void SendSMS()
 {
   string url =
   string.Format(@"http://{0}/api?action=sendmessage&username={1}
   &password={2}&recipient={3}&messagetype=SMS:TEXT&messagedata={4}",
   Txb_IpAddress.Text, txb_UserName.Text, 
	Txb_Password.Text, Txb_recipient.Text, Txb_SmsText.Text);
 
   WebRequest request = WebRequest.Create(url);
 
   request.GetResponse();
 }

Summary

SMS sending has become part of our lives just like mobile phones, TV or the Internet. It is a very efficient and fast way to communicate with each other. The implementation is simple so it is easy to create your own C# SIP SMS example. More specific information can be found on the webpage. I can only recommend this solution to everyone.

History

  • 9th June, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Tim Davis98

United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 4 PinmemberMic6-Aug-13 14:50 
GeneralSample Code? Pinmembernz_ham9-Jun-11 17:34 
GeneralRe: Sample Code? PinmemberTim Davis989-Jun-11 19:40 
GeneralSuggestion Pinmvpthatraja10-Jun-11 4:09 
GeneralQuestion PinmemberMember 1101166913-Aug-14 16:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 9 Jun 2011
Article Copyright 2011 by Tim Davis98
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid