Creating a call assistant software using C# and SQL (advanced VoIP softphone for business communication)

Rajnarayan
Posted by in C# category on for Intermediate level | Points: 250 | Views : 21551 red flag
Rating: 4 out of 5  
 1 vote(s)

This article is meant to be a complete solution description that explains step-by-step how to build a call assistant software using C# and SQL. This application is a kind of call center clients. This is nothing more than a VoIP softphone with some extra features that can facilitate the work of those who need to handle hugh amount of phone calls by serving customer data for the right person, to the right interface in the appropriate time.


 Download source code for Creating a call assistant software using C# and SQL (advanced VoIP softphone for business communication)


Contents


I. About the technology
I.1. What you need to know about VoIP softphones
I.2. How softphones can be used in business environment
I.3. What exactly is a call assistant application?
II. C# development
II.1. Configuration steps
II.2. Implemention of the Windows Forms application
II.3. Test conversation
Summary
References


I. About the technology

VoIP is the abbreviation for Voice over Internet Protocol. This is a methodology and group of technologies for the delivery of voice communications and multimedia session over IP network (e.g. the Internet). The term „Internet telephony” is a commonly used expression as well for VoIP. VoIP uses Internet Protocol to establish communication between two (or more) parties. Software and hardware devices can be also used to ensure VoIP services. This article focuses on the VoIP softphones that allow computers to become a virtual phone to be able to make and receive calls through VoIP services. 


I.1. What you need to know about VoIP softphones


For the sake of perfection, take a look at the definition of „softphone” provided by the highly respected VoIP-Info.org: „A VoIP softphone is a program that is installed on and runs from your computer. A VoIP softphone enables you to make calls with just your computer using a VoIP service.” So it allows you to make and receive telephone calls on your workstation, PC, laptop, tablet or smartphone over the Internet. (For this purpose a realiable high-speed Internet connectivity is required of course.)

As VoIP softphones are only software applications installed on the computer, a headset or a separated microphone and speakers (or earphones) are also needed to be able to make calls (Figure 1).


Figure 1: A VoIP softphone installed on a PC with a headset (Source: Self-made)

 

A VoIP softphone has the same functionalites that traditional desktop phones provide: DND (Do-Not-Disturb), transfer, mute, conference call, hold, voicemail, address book, etc. However, a VoIP softphone can offer much more (e.g. think Instant Messaging or presence indication).

To establish communication, each end-point should support the same VoIP protocol and at least one common audio codec (a typical minimum set is G.711 and G.729). Regarding to the protocols, many (perhaps it can be said that most) service providers use the SIP protocol (Session Initiation Protocol) that is a standardized set of formats and can be used to create, modify and terminate two-party (unicast) or multiparty (multicast) sessions (including Internet telephone calls, multimedia distribution, multimedia conferences, instant messaging, file transfer, etc.). Softphones that support the SIP protocol can be used with any SIP-based VoIP service.

There are many widely used softphones that use the SIP protocol, e.g. Bria or X-Lite provided by the CounterPath Corporation or the CSIPSimple mobile application for Android devices, etc. Through the example of Bria, it can be seen on Figure 2 that it is needed to create a SIP account and specify the required user details (user ID, password, display name, authorization name) to be able to connect the softphone to a PBX (Private Branch Exchange, saying more simply:: a telephone system). It is necessary to be able to make and receive phone calls.


Figure 2: A SIP account needs to be specified to use SIP softphones such as Bria (Source: Self-made)

 

There are several different softphones available on the market that use special protocols. Some of the most popular, well-known services: Skype or Google Hangouts (G-Talk), etc. Skype (Figure 3) uses proprietary P2P protocol, while Google Hangouts leverages the Extensible Messaging and Presence Protocol (XMPP).


Figure 3: Skype uses proprietary P2P protocol (Source: Self-made)

 

Additional protocols supported by softphones are H.323, MGCP, Cisco’s proprietary skinny protocol SCCP and Asterisk’s proprietary protocol IAX.


I.2. How softphones can be used in business environment


These applications are widely used programs in business and private life as well among those who have computers and/or Internet-enabled mobile devices. Certain kind of softphones (e.g. Skype, Facetime or Google Hangouts, etc.) are extremely popular among young and older people alike, because this is a quick and cheap way to keep in contact with distant friends and relatives. In addition, softphones have some indisputable benefits in general:

  • Ergonomic advantages: Users no longer need to keep the phone handset between their shoulder and ear to be able for multitasking. 
  • Freedom of movement: A softphone enables the user to move around the office and frees up the user’s hands to be able to do any other activity (multi-tasking).
  • Lower cost: VoIP technology can reduce telephone costs. Softphone costs range from free to approximately the half of traditional telephony.
  • High quality phone calls: Most softphones comply with the wideband standard that enables better sounding telephone calls.
  • Dialing from your computer: Many softphones enable to dial telephone numbers from computer applications, and provide click-to-call feature to make the telephony more effective.
  • Instant Messaging (IM): Several softphones have a built-in chat console that makes the communication more efficient.
  • Video chat: Video calling is supported on almost all softphones that can be achieved by clicking on only one button.


Furthermore, small businesses and large companies can gain further benefits from the usage of VoIP softphones. There are a few types of users who can really benefit from the features of a VoIP softphone:

  • VoIP beginners: By installing and testing a softphone, it provide a great way for VoIP beginner developers (or system administrators or company leaders, etc.) to discover how the service works.
  • Heavy travelers and frequent long-distance callers: With a softphone application, employees, especially frequent travelers, can take and use their office phone anywhere. E.g. by using a softphone, traveling employees can make calls on their business line via Wi-Fi connection at a hotel or a coffee shop. International and long-distance rates are much lower when using a VoIP softphone.
  • Telecommuters: Telecommuters can register a VoIP softphone with their corporate PBX system to enjoy the same call features available to them at the office while they are on the move.
  • Call center employees: Call center employees can save on costs by pairing a VoIP service with a softphone to avoid purchasing and maintaining physical devices. Special softphone applications (e.g. a call assistant) that are unavailable in desktop phones can make the call center work more effective.


I.3. What exactly is a call assistant application?


A call assistant application is a special kind of softphones. In other words: this is a collection of useful applications. It is also called „call center client”. These programs usually save and display all customer data, that makes the customer relationship management (CRM) more flexible, direct and personal by serving customer data for the right person, to the right interface in the appropriate time.

This basic functionality can be used to follow up all customer interactions and to show up customer information for the call center agents. Therefore, the agents will be able to recognise and identify callers and serve them accordingly.

Although the main role of this kind of applications is to make the work of call center / sales / telemarketing agents easier, a call assistant application allows users to create consistently remarkable customer experiences as well. Taken together, this leads to achieve sales, marketing and customer relationship objectives.

Let’s take a look at the following figure (Figure 4) to have a taste how conversation can be carried out between a customer and a sales representative who uses a call assistant application. The figure highlights that the conversation can be more personal due to caller identification and the problem solving can be much faster as well due to displaying of customer data. This feature can be also used to make more sales or achieve any other corporate objective.


Figure 4: An imaginary phone conversation using a call assistant application (Source: Self-made)



II. C# development


The rest of the article will introduce how to implement a call assistant (or a call center client) like the one described above in C#. The SIP-based application that will be presented below is able to make and receive audio phone calls through VoIP. It has some additional features such as hold and transfer and it is capable to check for the caller party in a database, and if it detects the caller in the database, the caller information (username, full name, country, note) will be displayed.



II.1. Configuration steps


To be able to implement this call assistant application, first of all, make your system ready for the project.

  1. Open your development environment (such as Microsoft Visual Studio 2012)
  2. Create a new project for creating an application with a Windows Forms user interface
  3. Make sure that .NET Framework 4.0 is installed on your PC and that this is the target framework in your IDE
  4. Add the Ozeki VoIPSDK.dll file to your references
  5. For managing user data, a local database provided by Visual Studio 2012 is used. (To create a local database, please right click on the project then choose: Add > New Item > Service-based Database.  The name of the database should be UserInfoContainer.mdf. Thereafter, you can create the UserInfos table that can be used to store the user data (username, real name, country, note).
  6. To be able to test your call assistant application, you will need some further equipments. A PBX is essentially needed to be able to register the call assistant softphone, and at least one additional VoIP phone (desktop or softphone) is also needed to make a test call.

If you miss any of the software listed above, you can obtain them from the following places for free:



II.2. Implementation of the Windows Forms application

For the implementation of this call assistant software, you will need the following 5 classes: Program.cs; Form1.cs; UserInfo.cs; DatabaseManager.cs; Form1.Designer.cs. Let’s see the classes one-by-one.


Program.cs

The Program.cs class is the main entry point for the application. It is used to run the project (Code 1).

static class Program

    {

        [STAThread]

        static void Main()

        {

            Application.EnableVisualStyles();

            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new FormCallAssistant());

        }

    }

Code 1: Program.cs


Form1.cs

The Form1.cs class contains the implementation of the softphone that is the base of the call assistant application. The Form1.cs present how to build a softphone and how to register it to the PBX by using a SIP account. This class also contains methods to be able to manage media handlers, to make and receive calls, and some simple call control methods (transfer, hold, hang up) are also described here.

As a first step, add the necessary using lines:

using System;

using System.Windows.Forms;

using Ozeki.Media.MediaHandlers;

using Ozeki.VoIP;

using Ozeki.VoIP.SDK;

Code 2: The necessary using lines


Thereafter, you need to create some objects by using the corresponding interfaces as follows. The softphone and phoneline objects are needed to declare, define and initialize the softphone. The microphone will be connected to the mediaSender, and the speaker will be connected to the mediaReceiver by using the connector object. To be able to send media data (such as voice), the mediaSender and the mediaReceiver media handlers should be attached to the call object.

ISoftPhone _softPhone;

IPhoneLine _phoneLine;

RegState _phoneLineState;

IPhoneCall _call;



Microphone _microphone;

Speaker _speaker;

MediaConnector _connector;

PhoneCallAudioSender _mediaSender;

PhoneCallAudioReceiver _mediaReceiver;



DatabaseManager _databaseManager;



UserInfo _otherParty;

Code 3: The necessary objects


The following variable is needed to indicate if there is an incoming call:

bool _incomingCall;

Code 4: Variable to indicate the incoming calls


Now there is a need to initialize the previous new objects and variables in a constructor:

public FormCallAssistant()

{

	InitializeComponent();

}



void form_CallAssistant_Load(object sender, EventArgs e)

{

	_microphone = Microphone.GetDefaultDevice();

	_speaker = Speaker.GetDefaultDevice();

	_connector = new MediaConnector();

	_mediaSender = new PhoneCallAudioSender();

	_mediaReceiver = new PhoneCallAudioReceiver();



	_databaseManager = new DatabaseManager();



	InitializeSoftphone();

}

Code 5: Initialize the new objects


Now take a closer look at the InitializeSoftphone method that is used to initialize the softphone with default parameters. (The 5700 and 5750 parameters determine the port interval.) Here you need to create a new SIP account to be able to register the application to your PBX. For this purpose you need to set the followings:

  • registration required (true)
  • display name (1000)
  • user name (1000)
  • authentication ID (1000)
  • register password (1000)
  • domain host (192.168.115.103 - IP address of the PBX)
  • domain port (5060 - port number of the PBX)

There is also a need to create the phone line to communicate with the PBX. The RegisterPhoneLine can be used to register the phone line:

void InitializeSoftphone()

        {

            try

            {

                _softPhone = SoftPhoneFactory.CreateSoftPhone(SoftPhoneFactory.GetLocalIP(), 5700, 5750);

                SIPAccount sa = new SIPAccount(true, "1000", "1000", "1000", "1000", "192.168.115.103", 5060);



                _phoneLine = _softPhone.CreatePhoneLine(sa);

                _phoneLine.RegistrationStateChanged += _phoneLine_RegistrationStateChanged;



                _softPhone.IncomingCall += _softPhone_IncomingCall;



                _softPhone.RegisterPhoneLine(_phoneLine);



                _incomingCall = false;



                ConnectMedia();

            }

            catch (Exception ex)

            {

                InvokeGUIThread(() => { tb_Display.Text = ex.Message; });

            }

        }

Code 6: Softphone initialization


The following code is used when the registration state of the phone line changes:

void _phoneLine_RegistrationStateChanged(object sender, RegistrationStateChangedArgs e)

{

    _phoneLineState = e.State;



    if (_phoneLineState == RegState.RegistrationSucceeded)

    {

        InvokeGUIThread(() => { lbl_UserName.Text = _phoneLine.SIPAccount.UserName; });

        InvokeGUIThread(() => { lbl_DomainHost.Text = _phoneLine.SIPAccount.DomainServerHost; });

    }

}

Code 7: Code to handle the changes of the registration state


This is used when there is an incoming call:

void _softPhone_IncomingCall(object sender, VoIPEventArgs e)

        {

            var userName = e.Item.DialInfo.Dialed;

            InvokeGUIThread(() => { tb_Display.Text = "Ringing (" + userName + ")"; });



            _call = e.Item;

            WireUpCallEvents();

            _incomingCall = true;



            _otherParty = _databaseManager.GetOtherPartyInfos(userName);

            ShowUserInfos(_otherParty);

        }

Code 8: Code to manage an incoming call


The following snippet shows how to manage the calls in different states:

void call_CallStateChanged(object sender, CallStateChangedArgs e)

{

    InvokeGUIThread(() => { lbl_CallState.Text = e.State.ToString(); });



    if (e.State == CallState.Answered)

    {

        StartDevices();

        _mediaSender.AttachToCall(_call);

        _mediaReceiver.AttachToCall(_call);



        InvokeGUIThread(() => { tb_Display.Text = "In call with: " + ((IPhoneCall)sender).DialInfo.Dialed; });

    }

    else if (e.State == CallState.InCall)

    {

        StartDevices();

    }



    if (e.State == CallState.LocalHeld || e.State == CallState.InactiveHeld)

    {

        StopDevices();

        InvokeGUIThread(() => { btn_Hold.Text = "Unhold"; });

    }

    else

    {

        InvokeGUIThread(() => { btn_Hold.Text = "Hold"; });

    }



    if (e.State.IsCallEnded())

    {

        StopDevices();



        _mediaSender.Detach();

        _mediaReceiver.Detach();



        WireDownCallEvents();



        _call = null;



        InvokeGUIThread(() => { tb_Display.Text = String.Empty; });

        ClearUserInfos();

    }

}

Code 9: Code to manage the calls in different states


Below you can see how to display the user data of the other party during a call:

void ShowUserInfos(UserInfo otherParty)

{

    InvokeGUIThread(() =>

        {

            tb_OtherPartyUserName.Text = otherParty.UserName;

            tb_OtherPartyRealName.Text = otherParty.RealName;

            tb_OtherPartyCountry.Text = otherParty.Country;

            tb_OtherPartyNote.Text = otherParty.Note;

        });

}



void ClearUserInfos()

{

    InvokeGUIThread(() =>

    {

        tb_OtherPartyUserName.Text = String.Empty;

        tb_OtherPartyRealName.Text = String.Empty;

        tb_OtherPartyCountry.Text = String.Empty;

        tb_OtherPartyNote.Text = String.Empty;

    });

}

Code 10: Displaying the user data of the other party during a call


This code example shows what happens when the user presses the buttons on the keypad of the call assistant:

void buttonKeyPadButton_Click(object sender, EventArgs e)

{

    var btn = sender as Button;



    if (_call != null)

        return;



    if (btn == null)

        return;



    tb_Display.Text += btn.Text.Trim();

}

Code 11: Code for pressing the buttons on the keypad


The following code snippet presents how to manage when the user of the call assistant picks up the phone if there is an incoming call:

void btn_PickUp_Click(object sender, EventArgs e)

{

    if (_incomingCall)

    {

        _incomingCall = false;

        _call.Answer();



        return;

    }



    if (_call != null)

        return;



    if (_phoneLineState != RegState.RegistrationSucceeded)

    {

        InvokeGUIThread(() => { tb_Display.Text = "OFFLINE! Please register."; });

        return;

    }



    if (!String.IsNullOrEmpty(tb_Display.Text))

    {

        var userName = tb_Display.Text;



        _call = _softPhone.CreateCallObject(_phoneLine, userName);

        WireUpCallEvents();

        _call.Start();



        _otherParty = _databaseManager.GetOtherPartyInfos(userName);

        ShowUserInfos(_otherParty);

    }

}

Code 12: Accepting the call


The following code snippet presents the media handler methods that can be used to make the usage of the microphone and the spreakers possible: StartDevice, StopDevice, ConnectMedia.

void StartDevices()

{

    if (_microphone != null)

        _microphone.Start();



    if (_speaker != null)

        _speaker.Start();

}



void StopDevices()

{

    if (_microphone != null)

        _microphone.Stop();



    if (_speaker != null)

        _speaker.Stop();

}



void ConnectMedia()

{

    if (_microphone != null)

        _connector.Connect(_microphone, _mediaSender);



    if (_speaker != null)

        _connector.Connect(_mediaReceiver, _speaker);

}

Code 13: The media handler methods


To make a successful call, you need to subscribe to specific events by using the WireUpCallEvents and the WireDownCallEvents methods.

void WireUpCallEvents()

{

    _call.CallStateChanged += (call_CallStateChanged);

}



void WireDownCallEvents()

{

    _call.CallStateChanged -= (call_CallStateChanged);

}

Code 14: Subscribing to specific events by using WireUpCallEvents and WireDownCallEvents


To handle the GUI, you need to create a background thread for this purpose. This is a simple method that invokes the action, given as parameter:

void InvokeGUIThread(Action action)

{

    Invoke(action);

}

Code 15: Background thread to handle the GUI


Below you can see the background processes when the user hangs up the call. If there is an incoming call that has not been accepted yet, and the user presses the Hang up button, the call will be rejected. If the user presses this button during a call, the call will be finished.

void btn_HangUp_Click(object sender, EventArgs e)

{

    if (_call != null)

    {

        if (_incomingCall && _call.CallState == CallState.Ringing)

        {

            _call.Reject();

        }

        else

        {

            _call.HangUp();

        }

        _incomingCall = false;

        _call = null;

    }

    tb_Display.Text = string.Empty;

}

Code 16: Hanging up the call


The following code snippet illustrates how to transfer the call to an other destination (to an other client) by using the BlindTransfer method. Using this method, during a call, the phone of the third party (this is the destination) starts to ring, like it would be dialled firstly. When the third party answers the call, the original call assistant user steps out from the conversation.

void btn_Transfer_Click(object sender, EventArgs e)

{

    string transferTo = "1001";



    if (_call == null)

        return;



    if (string.IsNullOrEmpty(transferTo))

        return;



    if (_call.CallState != CallState.InCall)

        return;



    _call.BlindTransfer(transferTo);

    InvokeGUIThread(() => { tb_Display.Text = "Transfering to:" + transferTo; });

}

Code 17: Transferring the call to an other destination


And finally, the code snippet below can be used to implement the hold functionality by using the ToggleHold method. First, the method checks whether there is an active phone call or not (is the call object "null" or not), and if there is an active call, it puts the call on hold.

void btn_Hold_Click(object sender, EventArgs e)

{

    if (_call != null)

        _call.ToggleHold();

}

Code 18: The hold feature


Userinfo.cs

The UserInfo.cs class is used to manage the UserInfo object that handles the user data.

class UserInfo

{

    public UserInfo(string userName, string realName, string country, string note)

    {

        UserName = userName;

        RealName = realName;

        Country = country;

        Note = note;

    }



    public string UserName { get; private set; }

    public string RealName { get; private set; }

    public string Country { get; private set; }

    public string Note { get; private set; }

}

Code 19: Transferring the call to an other destination


DatabaseManager.cs 

The DatabaseManager.cs class is used to access the local database. For this purpose, there is a need for a connectionString (the name that can be found in the name property of the App.config files). The constructor of the DatabaseManager class creates this connectionString variable and the SqlConnection object as well. Thereafter, it calls the OpenConnection method to connect to the local database.

string _connectionString;

SqlConnection _connection;



public DatabaseManager()

{

    _connectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString();

    _connection = new SqlConnection(_connectionString);



    OpenConnection();

    TestAdder();

}



void OpenConnection()

{

    try

    {

        _connection.Open();

    }

    catch (Exception ex)

    {

        MessageBox.Show(ex.Message);

    }

}

Code 20: ConnectionString to access the local database


It also calls the TestAdder method. It is used for test purposes. By using this method, you can create some users will be added to the database with the help of a simple SQL INSERT command.

void TestAdder()

{

    UserInfo userInfo;

    userInfo = new UserInfo("1001", "First User", "Hungary", "Only a user with no creative note.");

    AddUserInfo(userInfo);



    userInfo = new UserInfo("1002", "Second User", "England", "User from far-far away, still with no creative note.");

    AddUserInfo(userInfo);



    userInfo = new UserInfo("1003", "Third User", "Chile", "User who can bring us cherries.");

    AddUserInfo(userInfo);

}

Code 21: The TestAdder method


The relevant AddUserInfo method can be seen below:

public void AddUserInfo(UserInfo userInfo)

{

    using (var command = _connection.CreateCommand())

    {

        command.CommandText = "INSERT INTO UserInfos (UserName, RealName, Country, Note) values ('" + userInfo.UserName + "', '" + userInfo.RealName + "', '" + userInfo.Country + "', '" + userInfo.Note + "')";

        command.ExecuteNonQuery();

    }

}

Code 22: The AddUserInfo method


Below the GetOtherPartyInfos method can be seen that is responsible for reading the user data in the local database. This happens by using a simple SQL SELECT query. (The the username is equal to the caller’s username. If the database does not contain the caller username, the application displays N/A.)

public UserInfo GetOtherPartyInfos(string userName)

{

    UserInfo userInfo;



    using (var command = _connection.CreateCommand())

    {

        command.CommandText = "SELECT * FROM UserInfos WHERE Username = '" + userName + "'";



        using (var reader = command.ExecuteReader())

        {

            if (reader.HasRows)

            {

                reader.Read();

                var realName = reader["RealName"].ToString();

                var country = reader["Country"].ToString();

                var note = reader["Note"].ToString();



                userInfo = new UserInfo(userName, realName, country, note);



                return userInfo;

            }

        }

    }



    userInfo = new UserInfo("userName", "N/A", "N/A", "N/A");

    return userInfo;

}

Code 23: The GetOtherPartyInfos method


Form1.Designer.cs

The Form1.Designer.cs class contains the code belonging to the Graphical User Interface (GUI) of the call assistant application. Let’s take a look at some important code snippets that is used to build the following appearance:



Figure 5: The GUI of the call assistant application (Source: Self-made)


The Form1.Designer.cs class starts with the following required designer variable. The diposing parameter of the Dispose method is true if managed resources should be disposed; otherwise, false.

private System.ComponentModel.IContainer components = null;



protected override void Dispose(bool disposing)

{

    if (disposing && (components != null))

    {

        components.Dispose();

    }

    base.Dispose(disposing);

}

Code 24: The the beginning of the Form1.Designer.cs


This is followed by the Windows Form Designer generated code. It would be several pages long to present the full code, so below only some important code snippets have been highlighted.

The InitializeComponent method is required method for Designer support. At the beginning of this method the following component can be seen:

this.tb_Display = new System.Windows.Forms.TextBox();

this.panel1 = new System.Windows.Forms.Panel();

this.btn_Transfer = new System.Windows.Forms.Button();

this.btn_Hold = new System.Windows.Forms.Button();

this.groupBox2 = new System.Windows.Forms.GroupBox();

this.lbl_CallState = new System.Windows.Forms.Label();

this.lbl_DomainHost = new System.Windows.Forms.Label();

this.label6 = new System.Windows.Forms.Label();

this.button14 = new System.Windows.Forms.Button();

this.button13 = new System.Windows.Forms.Button();

this.button12 = new System.Windows.Forms.Button();

this.button11 = new System.Windows.Forms.Button();

this.button10 = new System.Windows.Forms.Button();

this.button9 = new System.Windows.Forms.Button();

this.button8 = new System.Windows.Forms.Button();

this.button7 = new System.Windows.Forms.Button();

this.button6 = new System.Windows.Forms.Button();

this.button5 = new System.Windows.Forms.Button();

this.button4 = new System.Windows.Forms.Button();

this.button3 = new System.Windows.Forms.Button();

this.btn_HangUp = new System.Windows.Forms.Button();

this.btn_PickUp = new System.Windows.Forms.Button();

this.lbl_UserName = new System.Windows.Forms.Label();

this.label1 = new System.Windows.Forms.Label();

this.groupBox1 = new System.Windows.Forms.GroupBox();

this.tb_OtherPartyNote = new System.Windows.Forms.TextBox();

this.tb_OtherPartyCountry = new System.Windows.Forms.TextBox();

this.tb_OtherPartyRealName = new System.Windows.Forms.TextBox();

this.tb_OtherPartyUserName = new System.Windows.Forms.TextBox();

this.label5 = new System.Windows.Forms.Label();

this.label4 = new System.Windows.Forms.Label();

this.label3 = new System.Windows.Forms.Label();

this.label2 = new System.Windows.Forms.Label();

this.panel1.SuspendLayout();

this.groupBox2.SuspendLayout();

this.groupBox1.SuspendLayout();

this.SuspendLayout();

Code 25: The beginning of the InitializeComponent method


The following code belongs to the Pick Up button. The Hold, Transfer and Hang Up buttons can be implemented in the same way.

this.btn_PickUp.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));

this.btn_PickUp.Location = new System.Drawing.Point(24, 115);

this.btn_PickUp.Name = "btn_PickUp";

this.btn_PickUp.Size = new System.Drawing.Size(64, 42);

this.btn_PickUp.TabIndex = 3;

this.btn_PickUp.Text = "Pick Up";

this.btn_PickUp.UseVisualStyleBackColor = false;

this.btn_PickUp.Click += new System.EventHandler(this.btn_PickUp_Click);

Code 26: The code belonging to the Pick Up button


The following code belongs to the numbered 1 button. All the rest buttons of the keypad (including # and *) can be implemented in the same way.

this.button3.Location = new System.Drawing.Point(76, 192);

this.button3.Name = "button3";

this.button3.Size = new System.Drawing.Size(64, 34);

this.button3.TabIndex = 5;

this.button3.Text = "1";

this.button3.UseVisualStyleBackColor = true;

this.button3.Click += new System.EventHandler(this.buttonKeyPadButton_Click);

Code 27: The code belonging to the button 1


The following code is a short snippet of the code that is needed to implement the „other party” section.

this.groupBox1.Controls.Add(this.tb_OtherPartyNote);

this.groupBox1.Controls.Add(this.tb_OtherPartyCountry);

this.groupBox1.Controls.Add(this.tb_OtherPartyRealName);

this.groupBox1.Controls.Add(this.tb_OtherPartyUserName);

this.groupBox1.Controls.Add(this.label5);

this.groupBox1.Controls.Add(this.label4);

this.groupBox1.Controls.Add(this.label3);

this.groupBox1.Controls.Add(this.label2);

this.groupBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));

this.groupBox1.Location = new System.Drawing.Point(12, 25);

this.groupBox1.Name = "groupBox1";

this.groupBox1.Size = new System.Drawing.Size(393, 412);

this.groupBox1.TabIndex = 2;

this.groupBox1.TabStop = false;

this.groupBox1.Text = "Information about the other party";

// 

// tb_OtherPartyNote

// 

this.tb_OtherPartyNote.Enabled = false;

this.tb_OtherPartyNote.Location = new System.Drawing.Point(88, 224);

this.tb_OtherPartyNote.Multiline = true;

this.tb_OtherPartyNote.Name = "tb_OtherPartyNote";

this.tb_OtherPartyNote.ReadOnly = true;

this.tb_OtherPartyNote.Size = new System.Drawing.Size(278, 174);

this.tb_OtherPartyNote.TabIndex = 7;

// 

// tb_OtherPartyCountry

// 

this.tb_OtherPartyCountry.Enabled = false;

this.tb_OtherPartyCountry.Location = new System.Drawing.Point(88, 154);

this.tb_OtherPartyCountry.Name = "tb_OtherPartyCountry";

this.tb_OtherPartyCountry.ReadOnly = true;

this.tb_OtherPartyCountry.Size = new System.Drawing.Size(278, 20);

this.tb_OtherPartyCountry.TabIndex = 6;

// 

// tb_OtherPartyRealName

// 

this.tb_OtherPartyRealName.Enabled = false;

this.tb_OtherPartyRealName.Location = new System.Drawing.Point(88, 113);

this.tb_OtherPartyRealName.Name = "tb_OtherPartyRealName";

this.tb_OtherPartyRealName.ReadOnly = true;

this.tb_OtherPartyRealName.Size = new System.Drawing.Size(278, 20);

this.tb_OtherPartyRealName.TabIndex = 5;

// 

// tb_OtherPartyUserName

// 

this.tb_OtherPartyUserName.Enabled = false;

this.tb_OtherPartyUserName.Location = new System.Drawing.Point(88, 52);

this.tb_OtherPartyUserName.Name = "tb_OtherPartyUserName";

this.tb_OtherPartyUserName.ReadOnly = true;

this.tb_OtherPartyUserName.Size = new System.Drawing.Size(278, 20);

this.tb_OtherPartyUserName.TabIndex = 4;

// 

// label5

// 

this.label5.AutoSize = true;

this.label5.Location = new System.Drawing.Point(49, 227);

this.label5.Name = "label5";

this.label5.Size = new System.Drawing.Size(33, 13);

this.label5.TabIndex = 3;

this.label5.Text = "Note:";

// 

// label4

// 

this.label4.AutoSize = true;

this.label4.Location = new System.Drawing.Point(24, 55);

this.label4.Name = "label4";

this.label4.Size = new System.Drawing.Size(58, 13);

this.label4.TabIndex = 2;

this.label4.Text = "Username:";

// 

// label3

// 

this.label3.AutoSize = true;

this.label3.Location = new System.Drawing.Point(33, 157);

this.label3.Name = "label3";

this.label3.Size = new System.Drawing.Size(49, 13);

this.label3.TabIndex = 1;

this.label3.Text = "Country: ";

// 

// label2

// 

this.label2.AutoSize = true;

this.label2.Location = new System.Drawing.Point(21, 116);

this.label2.Name = "label2";

this.label2.Size = new System.Drawing.Size(61, 13);

this.label2.TabIndex = 0;

this.label2.Text = "Real name:";

Code 28: Code for displaying information about the other party


And finally take a look at the „status section”:

this.groupBox2.Controls.Add(this.lbl_CallState);

this.groupBox2.Location = new System.Drawing.Point(219, 3);

this.groupBox2.Name = "groupBox2";

this.groupBox2.Size = new System.Drawing.Size(116, 66);

this.groupBox2.TabIndex = 19;

this.groupBox2.TabStop = false;

this.groupBox2.Text = "CallState";

// 

// lbl_CallState

// 

this.lbl_CallState.AutoSize = true;

this.lbl_CallState.Location = new System.Drawing.Point(31, 35);

this.lbl_CallState.Name = "lbl_CallState";

this.lbl_CallState.Size = new System.Drawing.Size(0, 13);

this.lbl_CallState.TabIndex = 20;

this.lbl_CallState.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;

// 

// lbl_DomainHost

// 

this.lbl_DomainHost.AutoSize = true;

this.lbl_DomainHost.Location = new System.Drawing.Point(80, 38);

this.lbl_DomainHost.Name = "lbl_DomainHost";

this.lbl_DomainHost.Size = new System.Drawing.Size(51, 13);

this.lbl_DomainHost.TabIndex = 18;

this.lbl_DomainHost.Text = "OFFLINE";

Code 29: Code for displaying the status



II.3. Test conversation


Having done the implementation of the application, let’s start debugging by pressing F5. If you followed the previous steps carefully, the program should run perfectly.

First of all, you need to create the same SIP account in your PBX that you have specified for the call assistant application above (Code 6). After this, the application will be registered to the PBX and the appropriate user name („Online as”) and the host’s IP address („Online at”) can be seen on the top of the application.

To make a test call, launch a VoIP phone that has been registered previously to the PBX. (Of course, you can make a test call by using an external phone number as well. But if you use an internal telephone extension, you can make some test calls free of charge. If you have no any VoIP desktop phone, you can use a free softphone, such as X-Lite.)

So, dial the telephone number of the call assistant by using a VoIP phone. Below (Figure 6)you can see that I have registered a softphone (numbered 1003) to my PBX and I dialled „1000” this is the phone number of my call assistant software.




Figure 6: A test call is established by using a SIP softphone (Source: Self-made)


On the GUI of the call assistant we can see that the software is registered successfully as „1000”. After clicking on the Pink Up button, the CallState indicates that the call is established with 1003. On the left side of the application all the stored information related to the 1003 numbered client will appear (Figure 7).


 
Figure 7: The call assistant accepts the call and displays the corresponding user data (Source: Self-made)

It is as easy as that - even if the description above is a bit extensive! :-) I wanted to cover all details. Congratulations for your job!



Summary


If you are reading this section right now, thank you for reading through multipage article. I hope you found it useful and interesting. This article provided a complete solution related to implementing a call assistant software (call center client) using C# and SQL. Due to this application,  your customer relationship management (CRM) can bemore flexible, direct and personal by serving customer data for the right person, to the right interface in the appropriate time.



References


Page copy protected against web site content infringement by Copyscape

About the Author

Rajnarayan
Full Name: Rajesh Narayan
Member Level: Starter
Member Status: Member
Member Since: 2/2/2015 4:47:17 AM
Country: India



Login to vote for this post.

Comments or Responses

Posted by: Ruisu1357 on: 5/16/2018 | Points: 25
Hello, Great tutorial, very well explained. Everything is going well except for a little error I have.

In the _softPhone_IncomingCall method, I get an error with the VoIPEventArgs. It tells me:

Using the generic tyoe 'VoIPEventArgs<T>' requires 1 type arguments

What should I do here? Many thanks in advance.

Login to post response

Comment using Facebook(Author doesn't get notification)