Course 1 / Lecture 8

How to develop a softphone in C#

How to build Autodialer with Ozeki VoIP SIP SDK

Download: auto-dialer.zip

To be able to create softphones, which are dialing numbers simultaneously from a file (or database etc.) and plays audio data (mp3, wav, text to speech etc.) into the calls, you can learn the necessary steps from this guide.

What is autodialer?

An autodialer is an electronic device or software that automatically dials telephone numbers, and once a call has been answered, the autodialer either plays a recorded message or connects the call to a live person.
From this example you can learn how to create an autodialer softphone, which receives the phone numbers and messages to be sent to them from a csv file, and plays the message as audio data to the call, using the Ozeki VoIP SIP SDK's TextToSpeech media handler.

What knowledge would you need?

To fully understand this guide, you might need to study the following chapters first:

  • SIP registration: you can learn how to begin softphone developing and how to be able to register to a pbx with a sip account.
    Learn more...
  • Managing media handlers: you can find here examples and a simple guide about how to be able to use, connect and manage different media handlers, and how can you attach them to calls.
    Learn more...
  • Making and accepting calls: from this guide you can learn how can your softphone make and accept calls, and handle the calls' states.
    Learn more...
  • Parallel call management: from this guide you can learn how can you develop softphones, which are able to manage multiple calls simultenaously.
    Learn more...

How to develop an autodialer softphone?

Since the autodialer softphone should be able to communicate with users, read and parse (.csv) files, make and manage parallel calls, provide the availability of the use of TextToSpeech function and much more, it's highly recommended to design and separate functions and classes providently.

The example is using five classes:

  • Softphone.cs: a simple softphone which is able to register to a PBX, and can create call objects.
  • Program.cs: a class to communicate with users; asks them about register information, amount of simultaneously makeable calls and a .csv file path.
  • CallInfo.cs: instances of this class are functioning as types; each CallInfo objects represents a line within the csv file, and contains a phone number and a message separately.
  • CallHandler.cs: since the autodialer softphone should be able to manage calls simultaneously, the softphone can create instances from this class for each of the calls, to handle those separately in the same time.
  • Autodialer.cs: creates CallHandler objects for the purpose to handle the calls, defined by the CallInfo objects.

What is Softphone.cs used for?

The autodialer's softphone class is able to register to a pbx, provides information about the phone line's sate, and also creates call objects, when needed.
Please note that, since the softphone doesn't need to be able to receive incoming calls, it shouldn't be registered to a PBX, which means that the registrationRequired field of the sip account can be set to "false". Without registering to a pbx, the autodialer is still able to dial phone numbers through the pbx, if that is reachable and allows it.

What is SIP Registration?

To learn more about SIP account, NAT Traversal methods and SIP registration, please read the SIP Registration chapter.

How to create call objects?

The class has got a public function which will be called within the CallHandler class, to create call objects:

public IPhoneCall CreateCall(string member)
    {
        return _softphone.CreateCallObject(_phoneLine, member);
    }

What is Program.cs used for?

The Program class uses a Softphone instance, handles the phone line's state, asks the user about sip account information, amount of simultaneously makeable calls and a .csv file path, reads, parses the given file and creates CallInfo objects to represent the file's lines.
When all of the previous steps are done, it calls the Autodialer class's Start() method.

Why should be the amount of simultaneously made calls set?

Network providers usually restrict how many calls can be made simultaneously, so to avoid further complications, set this integer number to be less or equal to that amount.
For example: if you set the number to "30", there will be always 30 or less outgoing calls.

What is csv file, and how that will be used?

A comma-separated values (CSV) (also sometimes called character-separated values, because the separator character does not have to be a comma) file stores tabular data (numbers and text) in plain-text form.
An example csv file:

phonenumber1;message1
phonenumber2;message2

Please note that, sometimes phone numbers and messages are separated by "," instead of ";", so the example application handles both cases.

  • since the file's path is already set (by default or by the user), it can be opened and read by the help of a StreamReader object, which reads the file line by line until the end of the file:
  • static void ReadCSV()
        {
            try
            {
                using (StreamReader sr = new StreamReader(_path))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        ParseCSVLineToObjectList(line);
                    }
                }
                StartAutodialer();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error occured: {0}", ex.Message.ToString());
            }
        }
    
  • every line contains a phone number, a message, and a separator character between them, so the application should split them by those characters, and create CallInfo object from the data:
  • static void ParseCSVLineToObjectList(string line)
        {
            try
            {
                string[] parse = line.Split(',', ';');
                _callInfo = new CallInfo(parse[0], parse[1]);
                _callList.Add(_callInfo);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error occured: {0}", ex.Message);
            }
        }
    
  • after the file's processing has finished, the CallInfo objects' list is complete, and the autodialer is ready to begin its job. To create the Autodialer instance, three parameters should be set:
    • a softphone, which will communicate to the called parties
    • the list of the CallInfo objects (which means the phone numbers to be called, and the messages to be played)
    • and the maximum amount of calls can be made simultaneously:
  • static void StartAutodialer()
        {
            _autodialer = new Autodialer(_mySoftphone, _callList, _maxConcurrentCall);
            _autodialer.Start();
        }
    

You can learn more about the Autodialer class below.

What is CallInfo.cs used for?

Each CallInfo object represents a line within the csv file, which is being used as a complex value, as it stores a phone number and a message to be sent to that party. CallHandler objects will be created for all of the CallInfo objects, to manage the calls separately.

What is CallHandler.cs used for?

The softphone can handle multiple calls simultaneously, and each of those is being handled by a CallHandler instance, set by a CallInfo object. Since a CallInfo object stores a phone number, the call will be created to that number, and the message is being passed to the TextToSpeech() method which converts the text message to audio data, than being played into the call, when that is being answered.

How are calls being managed simultaneously?

Instances of the class are being created from information stored in CallInfo objects, and within the Start() method of the class, a call object is being created by the Softphone class's CreateCall() method to the CallInfo object's PhoneNumber value, and it also subscribes to the calls' events etc., than makes the call.

public void Start()
    {
        var call = _softphone.CreateCall(_callInfo.PhoneNumber);
        call.CallStateChanged += OutgoingCallStateChanged;
        mediaSender.AttachToCall(call);
        call.Start();
    }

What happens during the outgoing calls?

Since the application is being notified when a call's state is being changed, tasks can be done during those changes:

  • when the call is being Answered, the CallInfo object's Message value is being played into the call with the help of the TextToSpeech() method.
  • the call can be ended by several reasons: the destination is busy or could not be reached, the call is completed etc. In these cases, the Completed event is being invoked:
private void OutgoingCallStateChanged(object sender, CallStateChangedArgs e)
    {
        if (e.State == CallState.Answered)
        {
            TextToSpeech(_callInfo.Message);
        }
        else if (e.State.IsCallEnded())
        {
            var handler = Completed;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }
    }

How does the TextToSpeech function work?

Ozeki VoIP SIP SDK provides media handler, called TextToSpeech for the purpose to convert text to audio data. The TextToSpeech() method uses this media handler as an AudioHandler to send the CallInfo object's Message value into the call, through a PhoneCallAudioSender object:

void TextToSpeech(string text)
    {
        var textToSpeech = new TextToSpeech();
        connector.Connect(textToSpeech, mediaSender);
        textToSpeech.AddAndStartText(text);
    }

What is Autodialer.cs used for?

The Autodialer class creates the CallHandler instances from CallInfo objects and starts them by calling their Start() method.

This class manages two lists:

  • list of CallInfo objects
  • list of CallHandler objects

With the help of these lists and the previously introduced classes, it creates CallHandler instances for all of the members of the CallInfos' list.
Please note that, it won't work with more calls in the same time, than it was set before by the user.

public void Start()
    {
        ThreadPool.QueueUserWorkItem(o => 
        {
            foreach (var callInfo in _callList)
            {
                if (_currentConcurrentCall < _maxConcurrentCall)
                {
                    StartCallHandler(callInfo);
                }
                else
                {
                    _autoResetEvent.WaitOne();
                    StartCallHandler(callInfo);
                }
            }
        });
    }

If there would be too much call, the application waits for a call to be ended.

What happens, when the CallHandler is being started?

When the CallHandler is being started, it increases the amount of currently managed calls, a CallHandler object is being added to the list of the CallHandlers, and it also checks if there is another call to be made by calling the Start() method of the class.

What happens, when the CallHandler's job is done?

The CallHandler object is being removed from the list of the CallHandlers, and the amount of currently managed calls is being decrased. The application is also being notified about the completed call, so it can start to make a new call.

Conclusion

From this example you could learn how to create simple softphone applications which are able to read and process csv files, make calls simultaneously to the destinations and send audio data - which are converted from text messages - into the call.

If you have any questions or need assistance, please contact us at info@voip-sip-sdk.com

Related Pages

More information