Before describing the implementation of my solution, I am going to explain the most important terms you need to know for better understanding.
First of all, let’s take a look at the operation of the traditional alarm systems in a nutshell. You have an alarm system installed and configured in your office or home. This alarm system is connected to the Central Station. In case of emergency (e.g. fire, burglary, theft or any other intrusion) the alarm system sends an alert to the Central Station that will take the appropriate action to avert the emergency.
But using my solution, you (more specifically: your C# application) can behave as an alarm system. That is, you can send out any alarm in case of emergency to the Central Station. Let’s see a drastic example that illustrates how my application can improve your security system: Due to a protracted work, you are sitting in the office late night. Since you are in the building, the alarm system is not activated yet. But in the meantime you experience something unusual and there is a suspicion of emergency. In this case you can use this C# application in order to send out a Contact ID alarm to the Central Station. The following figure illustrates this process:
Figure 1: How to send a Contact ID alarm to the Central Station in C#
Mini glossary:
- Alarm System: It is a system designed to detect intrusion (unauthorized entry), fire, gas leak, Carbon Monoxide leakage, high or low temperature, system trouble, communication trouble or any other emergency event.
- Central Station: It refers to a company providing services to monitor burglar, fire and residental alarm systems.
- Contact ID protocol: It is the most popular protocol that is used to establish communication between the alarm systems and the Central Station.
Before starting the development, let's see what you need for this project. Considering that my application has been written in C#, you need a development environment that supports C# (such as
Microsoft Visual Studio). Please do not forget to
install .NET Framework on your PC as well. There is also a need for some VoIP components added to your references to be able to implement the VoIP functionality (such as Ozeki VoIP SIP SDK). Since I have used the Ozeki SDK for this project, you need to
install this SDK on your PC, too.
- For creating a new Console Application, open your Visual Studio, click File > New project. Now select the Visual C# Console Application menu item and provide a name for your project. Finally click OK.
- For adding the VoIP components provided by the SDK, right-click on References and select the Add references menu item. Browse and select the VoIPSDK.dll file then click OK.
In order to make the communication possible between the alarm system and the Central Station I used the Contact ID protocol. The essence of the Contact ID procotol is that the receiver side sends a Handshake firstly. When the sender side receives that, it will start to send the message. That is both of the sides need to play the role of the sender and receiver as well. Therefore, in addition to the sender side, it is needed to talk a little about the receiver side as well. This is the reason why both of the sides has been built in one project.
Figure 2 illustrates the communication process using the Contact ID protocol:
Figure 2: The communication process using the Contact ID protocol
As you can see above, the alarm signal is a DTMF signal. However, the DTMF frequencies may be distorted during the communication with the Contact ID protocol, if you do not use a codec applying lossless compression. Therefore, you need to use PCMA or PCMU codecs.
In my project 2 classes have been used: Softphone.cs and Program.cs. Now it’s time to study the implementation of the two classes!
First of all, you need to create a softphone (a software-based telephone that has the same features as an ordinary phone). It is required, because the transmission of the alarm will be carried out through a VoIP call. So the alarm sending will be managed with the help of this softphone. The Softphone.cs class is used to declare, define and initialize a softphone, how to handle the necessary events and how to use its functions. The Softphone.cs will be used to create a new softphone in the Program.cs class.
Code 1 shows that the first step is the addition of some using lines:
Hide Copy Code
using System;
using Ozeki.Media;
using Ozeki.Media.MediaHandlers;
using Ozeki.VoIP;
using Ozeki.VoIP.SDK;
Code 1: Add some using lines
As you can see below, you need to create 3 objects (softphone, phone line and call) from the ISoftphone,IPhoneLine and IPhoneCall interfaces:
Hide Copy Code
ISoftPhone softphone; IPhoneLine phoneLine; IPhoneCall call;
Code 2: Creating the softphone, phone line and call objects
You also need to initialize the softphone in the constructor using the default parameters. You need to set the port range indicated by the first parameter (minPortRange
) and the second parameter (maxPortRange
). This is called the port’s interval. It can be seen in Code 3 that it also contains a third parameter: this is the listening port. As you can see, this is 5060 that is the port of the SIP.
Hide Copy Code
softphone = SoftPhoneFactory.CreateSoftPhone(5000, 10000, 5060);
Code 3: Initializing the softphone in the constructor
By subscribing to the IncomingCall
event, incoming calls will be monitored continuously (Code 4).
Hide Copy Code
softphone.IncomingCall += softphone_IncomingCall;
Code 4: Subscribing to the IncomingCall
event
In order to be able to communicate, you need to register your softphone to a PBX by using the Register()
method (Code 5). This method gets all of the values required for the registration as parameters that are used to create a SIP account with the constructor of the SIPAccount
class:
RegistrationRequired
: Is the registration required or not? To be able to receive incoming calls, this field needs to be set to ’true’.
DisplayName
: A name to be displayed at the called client.
UserName
: If an other client dials this name (number), this user is getting called.
AuthenticationId
: An identifier (like a login name) to the PBX.
RegisterPassword
: The password for registering to the PBX. It works in pair with the authentication ID.
DomainHost
: A domain name, e.g. an IP address.
DomainPort
: Port number.
After that the system will be able to create the phone line (CreatePhoneLine()
method) by using the account. By subscribing to the PhoneLineStateChanged
, you can track the changes of the phone line. When the phone line has been created, you need to register this phone line by calling the RegisterPhoneLine()
method.
Hide Copy Code
public void Register(bool registrationRequired, string displayName, string userName, string authenticationId, string registerPassword, string domainHost, int domainPort)
{
try
{
var account = new SIPAccount(registrationRequired, displayName, userName, authenticationId, registerPassword, domainHost, domainPort);
Console.WriteLine("\n Creating SIP account {0}", account);
phoneLine = softphone.CreatePhoneLine(account);
Console.WriteLine("Phoneline created.");
phoneLine.PhoneLineStateChanged += phoneLine_PhoneLineStateChanged;
softphone.RegisterPhoneLine(phoneLine);
}
catch (Exception ex)
{
Console.WriteLine("Error during SIP registration" + ex.ToString());
}
}
Code 5: Subscribing to the IncomingCall
event
You have already subscribed to get notified if the state of the phone line has been changed. With thephoneLine_PhoneLineStateChanged()
method you can set what to do for each state. If the state of the phone line is RegistrationSucceeded
, the system will examine whether the call has been started or not. You need to setup the numberToDial
(a telephone number to be dialed) and the call object as well. As you can see below, you need to subscribe to the CallStateChanged
by calling the call_CallStateChanged()
method (Code 6).
Hide Copy Code
void phoneLine_PhoneLineStateChanged(object sender, VoIPEventArgs<PhoneLineState> e)
{
Console.WriteLine("Phone line state changed to {0}", e.Item);
if (e.Item == PhoneLineState.RegistrationSucceeded)
{
if (startCall)
{
var numberToDial = "101";
call = softphone.CreateCallObject(phoneLine, numberToDial);
call.CallStateChanged += call_CallStateChanged;
call.Start();
}
}
var handler = PhoneLineStateChanged;
if (handler != null)
handler(this, e.Item);
}
Code 6: Managing the phone line states
If the CallStateChanged
event occurs (that is the call state changes), the state of the call will be displayed.
- If the call state is
Answered
, you need to create a PhoneCallAudioSender
and aPhoneCallAudioReceiver
in order to be able to send and receive audio during a call. In order to ensure that both of the sending and receiving works properly, the contactIdHandler
object should be connected to the phoneCallAudioSender
and phoneCallAudioReceiver
objects when the call is established. It can be completed by using the mediaConnector
. It ensures that both of the incoming and outgoing communication will be carried out through the contactIdHandler
. After that, you need to run the contactIdHandler
by calling the Start()
method.
- If the call state is
Completed
, you need to disconnect the established connections, and stop thecontactIdHandler
by calling the Stop()
method (Code 7).
Hide Shrink
Copy Code
void call_CallStateChanged(object sender, VoIPEventArgs<CallState> e)
{
Console.WriteLine("call state changed: {0}", e.Item);
if (e.Item == CallState.Answered)
{
phoneCallAudioSender = new PhoneCallAudioSender();
phoneCallAudioReceiver = new PhoneCallAudioReceiver();
phoneCallAudioReceiver.AttachToCall(call);
phoneCallAudioSender.AttachToCall(call);
mediaConnector.Connect(contactIdHandler, phoneCallAudioSender); mediaConnector.Connect(phoneCallAudioReceiver, contactIdHandler);
contactIdHandler.Start(); }
else if (e.Item == CallState.Completed)
{
contactIdHandler.Stop();
mediaConnector.Disconnect(contactIdHandler, phoneCallAudioSender);
mediaConnector.Disconnect(phoneCallAudioReceiver, contactIdHandler);
phoneCallAudioReceiver.Detach();
phoneCallAudioSender.Detach();
}
}
Code 7: Managing the call states
The following method (Code 8) examines whether is there an incoming call or not. By calling thecall_CallStateChanged()
method you can subscribe to the events of the CallStateChanged
concerning to the incoming calls. The call will be equal to the current call and the call will be accepted automatically. To hang up an existing call use the HangUpCall()
method.
Hide Copy Code
void softphone_IncomingCall(object sender, VoIPEventArgs<IPhoneCall> e)
{
Console.WriteLine("Incoming call...");
e.Item.CallStateChanged += call_CallStateChanged;
call = e.Item;
call.Accept();
}
Code 8: Accepting an incoming call
To hang up an existing call use the HangUpCall()
method (Code 9).
Hide Copy Code
public void HangUpCall()
{
call.HangUp();
}
Code 9: The HangUpCall()
method
First you need to add some lines in the ’using section’ (Code 10):
Hide Copy Code
using System;
using Ozeki.Media.MediaHandlers;
Code 10: Add some extra using lines