Programmable Voice

  1. Home
  2. Docs
  3. Programmable Voice
  4. Voice Elements Demo
  5. Sample Solution Tutorials
  6. ‘Getting Started’ Sample Solution

‘Getting Started’ Sample Solution

This tutorial is a walk-through explanation of the Getting Started sample solution that can be downloaded from your demo dashboard on the Voice Elements Customer Portal.

(If you haven’t already, sign up for a demo account and get 100 minutes of free call time for the next 30 days with the Voice Elements servers.)

Our demo gives you access to the source code behind the solution, so you can begin developing your application and test it using the demo phone number we provide for you.  When you’ve fine-tuned your application during testing, you can activate your production account and roll out your product.

We make it quick and easy to get your application into production!  Let’s get started.

Table of Contents

Getting Started Sample Solution

The Getting Started solution is designed to demonstrate how easily Voice Elements can:

    • Receive an Inbound Call
    • Place an Outbound Call
    • Receive a Text (or SMS) Message
    • Send a Text (or SMS) Message

Download the Sample Solution

Sign In to the Voice Elements Customer Portal.

If you are not brought directly to the Dashboard screen, click on Dashboard in the top navigation links.

Voice Elements Demo Dashboard

Sample Solutions Available in Three Download Formats

We offer three download formats for running the Sample Solutions: Windows Executable Program, Windows Source Code Download, or .NET Core Cross Platform Code.  You can download any option and run them as often as you like.

Demo Dashboard Sample Solutions noting the three download formats available.

Choosing to Download the Windows Executable Program

You’ll enjoy this user friendly option if you are not a programmer, if Visual Studio is not installed on the device or machine you are currently using for the demo, or if you just want to jump straight to seeing Voice Elements in action.

Select the Windows Program button ‘Download exe’.  The ZIP file will be downloaded to your machine’s Downloads folder.  You might also find it in the tray at the bottom of your browser window.  Unzip the folder and extract the files to your chosen location.  Look for the application named VoiceApp and run it.

Choosing to Download the Windows Source Code

If you are a programmer and have Visual Studio loaded on the device or machine you are using, you may enjoy downloading the Windows Source Code and seeing it in action from that perspective.  Not only will you see how easy it is to program the code, you will also see how simple it is to create your telephony application.

Select the Windows Source Code button ‘Download sln’.  Unzip the folder and extract the files to your chosen location.  Run the Microsoft Visual Studio Solution ‘Getting Started’.

Choosing to Download the .NET Core Cross Platform Solution

This download format is designed for Linux or Windows  You will need a .NET Core compatible compiler to run the solution.

Run Anyway and Allow Access

Your device might recognize the file as an unrecognized app with an unknown publisher and ask if you are sure you want to run it.  Select the option that will confirm that you want to run the application anyway.

Your firewall might prompt you to confirm access to the app.  Select the option that allows access.

Once you have removed the obstacles, the application will run.

Getting Started Client Application

Getting Started Sample Solution

Just a few things to note in the screenshot above:

    • The demo phone number that you were assigned will be shown as your test phone number.
    • The window at the bottom of the application is a real-time log of what Voice Elements is internally doing for you with each action you take.

Ready to take that test drive?

1. Inbound Calls

Call your demo phone number from any phone.  When you answer the call, you can watch the Voice Elements application log each activity: answering the call, playing text to speech to say your name, and playing a file.

2. Outbound Calls

Type a phone number where you want to receive a test call and click the button Call Me.  Watch Voice Elements place the call.  When you answer the call, watch Voice Elements log the results.

3. Receive a Text (SMS) Message

Send a text to your demo phone number and watch Voice Elements receive the text.

4. Send a Text (SMS)Message

Type your outgoing message in the field.  We’ve also provided two emojis you can use to demonstrate how Voice Elements uses the full functionality of standard SMS messages.  When you click the button Call Me!, the app will send a text to the number you have entered in the Outbound Call field.

Ready to try more Sample Solutions?

You can click on More Samples within the app, or go back to your browser and log in to the Voice Elements Customer Portal.  We have a tutorial for each sample solution to guide you through running each sample.

You must close the current sample before running another one.

If you want to run the Sample Solution again, you might consider moving the folder out of downloads to your desktop or a location where you want to store all the Sample Solutions.

We hope you try all our Sample Solutions to really see how comprehensive and robust Voice Elements is.

 


Understanding the Source Code

For more detailed information about the Voice Elements Classes and Methods, explore our Class Library documentation at Voice Elements Developer Help.  We’ve linked a few classes and methods in the sections below to encourage you to take advantage of this treasure-trove of knowledge from our developers.

Voice Elements MainCode

The core class of this project is IvrApplication. This class contains a lot of logic that sets up the application as a windows service so you can ignore a lot of the code in it for now. The most important method here is MainCode().

When the application is run, it starts a new thread which runs MainCode(). This connects to the Voice Elements servers in the cloud. Then loops indefinitely checking for new tasks to run, and inbound call events.

Note that Log.Write() is used frequently to log call progress and help with debugging. It is recommended that you continue to do this as you program your own Voice Elements applications.

The first thing MainCode() does is connect to the Voice Elements servers. This is done by constructing a new TelephonyServer object passing in server ip, username, and password as parameters. These values have already been generated for your account but you can change them in your Settings.settings file.

MainCode() also sets the CacheMode on the TelephonyServer object.

ClientSession mode means that the server will stream and cache the files to and from your client machine. These files are flushed after you disconnect. Server mode means that the files reside on the server and will use the full path name to find them there. Note that Server mode can only be used on your own dedicated Voice Elements server.

After connecting to the server and setting its cache mode the new call event should be subscribed to. This sets a method to be called when an incoming call is received. In this example TelephonyServer_NewCall() is the method to be called on new incoming call events.

RegisterDNIS() is then called on the TelephonyServer to tell the server which phone numbers the application will handle. This method can be called with no parameters to instruct Voice Elements to handle calls from all phone numbers on your account. Otherwise you can specify numbers to handle as parameters.

MainCode() then sets everything on the TelephonyServer needed for SMS. Private and public keypairs have already been generated for your account, located in Settings. The API Keys can be found and changed in the customer portal.  The TelephonyServer is then subscribed to the TelephonyServer_SmsMessage() method for handling inbound texts and the TelephonyServer_SmsDeliveryReport() method for logging message delivery status.

try
{
    Log.Write("Connecting to: {0}", Properties.Settings.Default.PhoneServer);

    s_telephonyServer = new TelephonyServer("gtcp://" + Properties.Settings.Default.PhoneServer, Properties.Settings.Default.UserName, Properties.Settings.Default.Password);

    // CHANGE YOUR CACHE MODE HERE
    s_telephonyServer.CacheMode = VoiceElements.Interface.CacheMode.ClientSession;

    // SUBSCRIBE to the new call event.
    s_telephonyServer.NewCall += new VoiceElements.Client.NewCall(TelephonyServer_NewCall);
    s_telephonyServer.RegisterDNIS();

    s_telephonyServer.SmsMyPrivateKeyXml = Properties.Settings.Default.CustomerKeyPairXml;
    s_telephonyServer.SmsBorderElementsPublicKeyXml = Properties.Settings.Default.BorderKeyPairXml;
    s_telephonyServer.SmsMessage += TelephonyServer_SmsMessage;
    s_telephonyServer.SmsDeliveryReport += TelephonyServer_SmsDeliveryReport;

    // Subscribe to the connection events to allow you to reconnect if something happens to the internet connection.
    // If you are running your own VE server, this is less likely to happen except when you restart your VE server.
    s_telephonyServer.ConnectionLost += new ConnectionLost(TelephonyServer_ConnectionLost);
    s_telephonyServer.ConnectionRestored += new ConnectionRestored(TelephonyServer_ConnectionRestored);
}

Inbound Call

Let’s take a look at the logic for taking care of an inbound call. In the MainCode() of IvrApplication we set TelephonyServer_NewCall() to be called when a new phone call is received. This generates the ChannelResource which you can basically think of as the object that is the phone line. The ChannelResource class contains all of the methods and properties that you would expect to be able to perform with a phone line. The InboundCall class is used for handling all of the logic for inbound phone calls.

TelephonyServer_NewCall() constructs a new InboundCall object for which the TelephonyServer object and the ChannelResource object are provided as parameters.

The RunScript() method is then called on the new InboundCall object. This method contains much of the logic for programmable voice on inbound phone calls.

static void TelephonyServer_NewCall(object sender, VoiceElements.Client.NewCallEventArgs e)
{
    try
    {
        Log.Write("NewCall Arrival! DNIS: {0}  ANI: {1}  Caller ID Name: {2}", e.ChannelResource.Dnis, e.ChannelResource.Ani, e.ChannelResource.CallerIdName);

        InboundCall inboundCall = new InboundCall(s_telephonyServer, e.ChannelResource);
        inboundCall.RunScript();
    }
    catch (Exception ex)
    {
        Log.WriteException(ex, "IvrApplication::NewCall");
        e.ChannelResource.Disconnect();
        e.ChannelResource.Dispose();
    }
}

 

RunScript() contains the basic logic for handling an inbound phone call. The call is answered by calling the Answer() method on the ChannelResource. Then text to speech and recorded messages can be played by calling PlayTTS() and Play() on the VoiceResource. The phone call is then disconnected by calling Disconnect() on the ChannelResource. This can also be used to reject a call instead of answering.

try
{
    // Answer the call
    Log.WriteWithId(m_channelResource.DeviceName, "Answering...");
    m_channelResource.Answer();

    // Play text
    Log.WriteWithId(m_channelResource.DeviceName, "Playing text to speech...");
    m_channelResource.VoiceResource.PlayTTS("Hello, " + Properties.Settings.Default.FirstName + ".");

    // Play a recorded message
    Log.WriteWithId(m_channelResource.DeviceName, "Playing welcome message...");
    m_channelResource.VoiceResource.Play("..\\..\\WelcomeMessage.wav");


    // Uncomment this to test receiving digits from the caller
    // ReceiveDigits();


    // Uncomment this to see how a voicemail message could be recorded
    // RecordVoicemail();
}

Programmable Voice Methods

The InboundCall class also contains some methods for some more advanced voice operations ReceiveDigits() contains the basic structure for getting numeric input from the connected phone. This method is set up to simply accept input, then text to speech that input back to the caller.

This is done by first setting the ClearDigitBuffer property of the VoiceResource to false. This makes it so that if the user begins to press digits during the prompt for input, those digits will not be lost.

The MaximumDigits property is also set, So that the program will only take up to that many digits as input.

The TerminationDigits property can also be set. This sets the next voice function to terminate on the input of any of these digits. The GetDigits() method is the called on the VoiceResource. At this point the input digits are located in the DigitBuffer property of the VoiceResource as a string. Be sure to reset the ClearDigitBuffer property back to true. The TerminationDigits property can also be reset.

private void ReceiveDigits()
{
    // Use the log file often to help with debugging.
    Log.Write("Prompting for extension...");
    
    // Prompt the user for an extension
    m_voiceResource.PlayTTS("Please enter an extension, followed by the Pound sign");
    
    // Instruct the voice resource NOT to clear the digit buffer on the next voice function.
    m_voiceResource.ClearDigitBuffer = false;
    
    // Instruct the voice resource to return a maximum of 10 digits
    m_voiceResource.MaximumDigits = 4;
    
    // Instruct the voice resource to terminate the next voice function on just a "#" DTMF digit.
    m_voiceResource.TerminationDigits = "#";
    
    // Wait until the above condition are met.
    _voiceResource.GetDigits();
    
    // Log the response.
    Log.Write("Digits Returned: " + m_voiceResource.DigitBuffer);
    
    // On the next voice function, clear the digit buffer.
    m_voiceResource.ClearDigitBuffer = true;
    
    // On the next voice function, Do not permit the play to be terminated
    m_voiceResource.TerminationDigits = "";
    
    // Play the prompt: "You have entered..."
    m_voiceResource.PlayTTS("You entered " + m_voiceResource.DigitBuffer);
}

 

RecordVoiceMail() contains the basic structure for recording a voice mail. The caller is first prompted to record a message with the PlayTTS() method. A filename is also created and stored as a string. The TerminationDigits property can also be set. This sets the next voice function to terminate on the input of any of these digits. The Record() method is then called on the VoiceResource with the desired file name as a parameter. At this point the program is recording and will stop recording when on of the TerminationDigits is pressed by the caller.

private void RecordVoicemail()
{
    // Play prompt text (or play your own previously recorded file too)
    m_voiceResource.PlayTTS("Please record your message");

    string filename = "VM_" + DateTime.Now.ToString("yyMMddhhmmss") + m_channelResource.DeviceName + ".wav";

    // Log Often
    Log.Write("Recording to " + filename);

    // On the next voice function, stop on any DTMF digit.
    m_voiceResource.TerminationDigits = "ANY";

    // Record the caller's message to your local hard disk
    m_voiceResource.Record(filename);

    // Log often
    Log.Write("Playing " + filename);

    // On the next voice function, clear the digit buffer.
    m_voiceResource.ClearDigitBuffer = true;

    // Play back the recorded message to the caller.
    m_voiceResource.Play(filename);
}

Outbound Call

Let’s look at how making an outbound call with Voice Elements works. The IvrApplication class contains the method MakeOutboundCall()  which is called when the button is clicked on the GUI. This project uses the OutboundCall class to handle the logic for outbound calls. This method first constructs a new OutboundCall object passing in the TelephonyServer object and the number that is to be called. The constructor creates a new ChannelResource to the TelephonyServer. A new thread is then started to call the RunScript() method on the new OutboundCall object.

public static void MakeOutboundCall(string number)
{
    OutboundCall outbound = new OutboundCall(s_telephonyServer, number);

    // Always spawn calls on new threads
    ThreadStart ts = new ThreadStart(outbound.RunScript);
    Thread t = new Thread(ts);
    t.Name = "Outbound";

    t.Start();
}

 

The RunScript() method contains all of the logic for making an outbound call. It first sets the OriginatingPhoneNumber property of the ChannelResource, which sets the outbound Caller ID. It then sets the MaximumTime property on the ChannelResource so that the call will fail after 30 seconds if it does not connect. To actually place the call, the Dial() method is called on the ChannelResource passing in the number to be called as a parameter. This method returns a DialResult property which is used to determine if the call connects or not. RunScript() then has logic to determine what to do if the call is answered or not. If the call is answered here is where more voice operations logic can be located. The call is then disconnected and all of the resources are cleaned up.

try
{
    // Use WriteWithId to differentiate between separate instances of the class
    Log.WriteWithId(m_channelResource.DeviceName, "OutboundCall Script Starting");
    Log.WriteWithId(m_channelResource.DeviceName, "Dialing {0}", m_numberToCall);

    // With this, the server will detect if a human or machine answers the phone
    // m_channelResource.CallProgress = CallProgress.AnalyzeCall;

    // You can display any outbound Caller ID phone number if needed (this is disabled for testing)
    m_channelResource.OriginatingPhoneNumber = Properties.Settings.Default.TestPhoneNumber;

    // Instruct the server to wait no more then 30 seconds for a connection
    m_channelResource.MaximumTime = 30;

    // Place the call
    DialResult dr = m_channelResource.Dial(m_numberToCall);

    Log.WriteWithId(m_channelResource.DeviceName, "The dial result for {0} was: {1}", m_numberToCall, dr);

    if (dr == DialResult.Connected)
    {
        Log.WriteWithId(m_channelResource.DeviceName, "Playing File..");
        m_voiceResource.Play("../../WelcomeMessage.wav");
    }
    else
    {
        Log.WriteWithId(m_channelResource.DeviceName, "Unexpected dial result, cancelling Call");

        if (dr == DialResult.OperatorIntercept && m_channelResource.GeneralCause == 402)
            Log.WriteWithId(m_channelResource.DeviceName, "You have ran out of minutes. Contact customer support to have more added");
    }
}

SMS

Let’s take a look at the logic behind programmable SMS using Voice Elements. In the MainCode() of IvrApplication private and public key pairs are set on the TelephonyServer. And methods are subscribed to for the SmsMessage event and SmsDeliveryReport event. TelephonyServer_SmsMessage() is called when a SmsMessage event is generated, this is when a message is received as an inbound text. This is where you would put the logic for handling inbound SMS messages. And the TelephonyServer_SmsDeliveryReport() method is called when a SmsDeliveryReport event is generated. This tracks the delivery status of the message.

private static void TelephonyServer_SmsMessage(object sender, SmsMessageEventArgs e)
{
    Log.Write($"Received SMS (From: {e.SmsFrom}, To: {e.SmsTo}): {e.SmsMessage}");
}

private static void TelephonyServer_SmsDeliveryReport(object sender, SmsDeliveryReportEventArgs e)
{
    if (string.IsNullOrWhiteSpace(e.DeliveryDescription) && e.DeliveryState.ToLower() == "waiting")
    {
        Log.Write($"Received SMS Delivery Report (From: {e.SmsFrom}, To: {e.SmsTo}): Message delivery is pending...");
    }
    else
    {
        Log.Write($"Received SMS Delivery Report (From: {e.SmsFrom}, To: {e.SmsTo}): {e.DeliveryDescription}");
    }
}

 

SendSms() is the method that handles logic for outbound sms messages. This method is called by the gui when a button is pressed, passing in the number and message to be texted as parameters. The SmsSendMessage(string message, string toSmsNumber, string fromSmsNumber, string customerTag, out Guid messageGuid, out string[] headers, out string[] sdp) method is called to actually send the sms which returns a sipStatusCode.

public static void SendSms(string number, string smsText)
{
    try
    {
        Guid messageGuid;
        string[] headers;
        string[] sdp;

        var sipStatusCode = s_telephonyServer.SmsSendMessage(smsText, number, Properties.Settings.Default.TestPhoneNumber, null, out messageGuid, out headers, out sdp);
        Log.Write("SMS Result: {0}", sipStatusCode);
    }
    catch (Exception ex)
    {
        Log.WriteException(ex, "SendSms()");
    }
}

 

For more information, please see the article Start Coding Voice Elements.

Was this article helpful to you? Yes 6 No