Shane's World - Installment IV

Leveraging the full power of the RELAY SDK

By Shane Bryldt, Senior Software Engineer

Hello world! My name is Shane Bryldt, and I am a Senior Software Engineer here at SignalWire. As a developer, I have made it my mission to explain everything that SignalWire can do, provide examples, and give the community my pro tips on how to leverage some of the more obscure options you can set. In my first installment, I talked about RELAY and covered the Calling.DialPhone API, Calling.NewPhoneCall, Call.Dial, and Call.Hangup. You can read all of that that right here!

In Installment II, we continued down the road into the RELAY SDK, and talked about some of the exciting API's we have to offer. We also covered the Call.Play API and its helpers, Call.PlayAudio, Call.PlayTTS, Call.PlaySilence, and Call.PlayRingtone.

In Installment III we took a look into a few more API's of the RELAY SDK. We covered the Call.Prompt API, and its helpers Call.PromptAudio, Call.PromptTTS, as well as Call.Tap.

And now it's time for Shane’s World – Installment IV!

The Feature Dive

Today we will look into a few new API's of the RELAY SDK. We will cover the Call.Answer API, the Call.Connect API, and for a bonus we will cover the Call.SendDigits API.

I will start with a few links to the documentation, please review these for relevant information:

In the past articles we have focused on examples that were based on outbound calls, and invoked when the Consumer was Ready. Today we'll look at how to work with inbound calls, in particular to answer them. Let’s start with the example code in C# like before and we will build on the first example introducing the OnIncomingCall handler, then I will discuss what the code is doing.  

The first thing to notice that has been added is the assignment of a list of contexts during the Setup. This is a list of arbitrary strings each of which represents a context for inbound communication. For the purposes of this example, you will need to go to the SignalWire Portal and either purchase or edit an existing phone number. Set incoming calls as Voice Calls and handle the calls using Relay. You are then offered the option to set the Context to be used, in this case we are using example. After setting up this phone number, use this same context string in the Setup list. This will provide your Relay client with events about incoming calls for that context. The same context may be assigned to multiple phone numbers, and multiple relay clients may ask for the same context and have some failover and distribution support.

After setting the context, we have the OnIncomingCall method that we can override from the Consumer to provide us with the new inbound Call object. From here it is a very simple call to Call.Answer to answer the call after which you may proceed with any other API calls as with the outbound call examples. To show this and keep things interesting we added some text-to-speech being played before the call is hung up.

Advanced Note: In the example we used the blocking API for "Answer", this would cause it to block until the call has been answered or errored out. This is the most common use case, but as with many other API's there is an "AnswerAsync" API that also exists.

Now we will circle back to a previous example for an outbound call and will talk about how to Connect another outbound call to it. Let's start with an example.

Here we have gone back to an outbound dial skeleton example from previous installments. We have introduced the new Connect method which has only two parameters, the first is a nested List<List<CallDevice>> which provides the targets to be attempted. This API allows you to attempt to connect to multiple targets and have only the first one that answers win the race. It must be noted that the form of this list also impacts how the dialing will occur. The outer list represents calling in series, attempting one inner list after the other. The inner lists represent calling in parallel, where the system will attempt to call all or some of them at the same time. Combining these together gives you powerful flexibility to call in series, parallel, or a combination of both. In this example, we create the outer series list, and a single inner parallel list, with a single phone device target to call. This represents the simplest form of the operation.

The other parameter available, is a List<CallMedia> similar to the Play API, which allows you to control custom ringback media to the original parent call while waiting for someone to answer.

Upon completion of a Connect the result contains the second Call object which can then also be used to execute further API calls. Both Call objects will also be linked to each other by their Peer property once answered. In this example we keep things simple by waiting for 15 seconds for the connected side to hang up after it answers, if it doesn't then we hang it up and then hang up the original parent call.

Also note that while we did this starting with an outbound call, we could have also done it from the prior example after answering an inbound call which would effectively create simple call forwarding allowing you to hide a private phone number behind a public SignalWire proxy phone number.

Advanced Note: In the example we used the blocking API for "Connect", this would cause it to block until the call has been answered or errored out. This is the most common use case, but as with many other API's there is a "ConnectAsync" API that also exists and events that can be hooked in support of it.

Now let's talk about the SendDigits API. This API allows you to emit standard Dual-Tone Multi-Frequency (DTMF) audio to a call. As usual, let's start with an example.

We have reused yet again the basic outbound call example, and the only thing added is the API call to SendDigits. This API only has a single string parameter, which contains the text for the digits to be played. Note that there are special w and W characters for short and long pauses between other tones respectively, and these can be stacked for even longer pauses. There are also the less common ABCD tones available. Be aware that any invalid input causes the entire operation to be rejected.

Advanced Note: In the example we used the blocking API for "SendDigits", this would cause it to block until all of the input has been processed or an error occurs. This is the most common use case, but as with many other API's there is a "SendDigitsAsync" API that also exists.

Thank you for reading this article and I hope you find it helpful. The best way to learn about SignalWire is to tinker around with it, so sign up now to receive $5 in free credit and try it out yourself. You can also join us on our community Slack channel, where you can ask me any questions you have about SignalWire. Stay tuned as we dive down the rabbit hole together into more of SignalWire, on the next installment of Shane’s World!