WebRTC Deep Dive

If you aren’t sure what WebRTC is, and how you can use Voice Elements to build WebRTC applications, you’ll want to read this link for more information.

For basic information on creating a WebRTC application using Voice Elements, use this link.

Web Socket

WebRTC opens up a websocket connection to send setup messages from the browser to other WebRTC endpoints. In PeerToPeer WebRTC applications, these messages are sent and received directly between browsers.

Voice Elements listens for websocket connections from browsers and responds to the WebRTC messages that the browser sends accordingly to negotiate things like which ports to use for sending audio, etc.

This websocket connection can also be used so that your application can listen to application messages from your WebRTC app. For example, you may want to allow your customers to dial a 10 digit landline. You would need to create a message that your browser application would send, and what your Voice Elements application would listen for.

Messages

You can instruct a WebChannel to listen for Custom messages sent to it via the websocket by subscribing the WebChannel_CustomMessageEvent. We are able to uniquely identify each client that is connected to your WebRTC application, this way you know which clients are sending commands. For example, if you have customer A connected, and customer B connected, when customer A triggers a command to get sent up to the server by pressing a button, you will know which customer triggered that command because the message will be sent on the WebChannel that Customer A is connected to.

Below is code that shows how to subscribe to the CustomMessageEvent:

WebChannel.CustomMessageEvent += new CustomMessageEvent(WebChannel_CustomMessageEvent);

Below is code that you might have in your custom message event:

        void WebChannel_CustomMessageEvent(object sender, CustomMessageEventArgs e)
        {
            try
            {
                Log.Write("Received Message: {0}", e.Message);

                CustomSocketMessage currentMessage = null;
                Command command = null;

                try
                {
                CustomSocketMessage currentMessage = Serializer.Deserialize(e.Message);

                Command command = new Command(null, currentMessage.GetType().FullName, Serializer.Deserialize(e.Message));


                if (command != null)
                {
                    Log.Write("Processing: {0}", command.CommandString);

                    switch (command.CommandString)
                    {
                        case "VoiceApp.StationWebRtcHandler+Hangup":
                            Hangup hangup = (Hangup)command.CustomSocketMessage;
                            m_StationWebRtc.PostHangup(Guid.Parse(hangup.uniqueId));
                            break;
                        case "VoiceApp.StationWebRtcHandler+Hold":
                            Hold hold = (Hold)command.CustomSocketMessage;
                            m_StationWebRtc.PostHold(Guid.Parse(hold.uniqueId));
                            break;
                        case "VoiceApp.StationWebRtcHandler+ResumeCall":
                            ResumeCall resumeCall = (ResumeCall)command.CustomSocketMessage;
                            m_StationWebRtc.PostResumeCall(Guid.Parse(resumeCall.uniqueId));
                            break;
                        case "VoiceApp.StationWebRtcHandler+Transfer":
                            Transfer transfer = (Transfer)command.CustomSocketMessage;
                            m_StationWebRtc.PostTransfer(Guid.Parse(transfer.uniqueId), transfer.destination);
                            break;
                        case "VoiceApp.StationWebRtcHandler+Dial":
                            Dial dial = (Dial)command.CustomSocketMessage;
                            m_StationWebRtc.PostDial(dial);
                            break;
                        case "VoiceApp.StationWebRtcHandler+Mute":
                            Mute mute = (Mute)command.CustomSocketMessage;
                            m_StationWebRtc.ToggleMute(Guid.Parse(mute.uniqueId));
                            break;
                    }
                }
                else
                {

                }
            }
            catch (Exception ex)
            {
                Log.WriteException(ex, "OutboundDialer::WebChannel_CustomMessageEvent");
            }
        }

Notice how we’ve created a class for each type of message that we receive. You can then pass instances of these classes in via the websocket using JSON which is discussed in more detail below.

Also notice how we have created methods to handle these incoming messages. For example, the PostDial command, will pass a Dial message and implement all of the logic for dialing out to another party (Get the Channel Resource, perform the Dial, Route the WebChannel with the Channel Resource).

JSON

Messages that are sent in the WebSocket are sent using JSON. When properly constructed, these JSON messages can be deserialized into instances of .NET classes that you create in your Voice Elements application.

JSON Message

Below is an example of a JSON message that would be used to Dial out to another phone number. The syntax used in this JSON message, makes it easier for the C# deserializer to handle.

 IVLSocketSendApplicationMessage({ __type: 'VoiceApp.StationWebRtcHandler+Dial', version: 1, numbertodial: "5551234567", callerid: "5551234568" });

C# Class Structure

Below is what the C# class looks like:

namespace VoiceApp
{
    public class StationWebRtcHandler
    {
        public class Dial : CustomSocketMessage
        {
            public string numbertodial { get; set; }
            public string callerid { get; set; }
            public string calleridname { get; set; }
        }
    }
    
    public class CustomSocketMessage
    {
        public virtual int version { get; set; }
    }

    public class CustomTypeResolver : JavaScriptTypeResolver
    {
        public override Type ResolveType(string id)
        {
            return Type.GetType(id);
        }
        
        public override string ResolveTypeId(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            return type.FullName;
        }
    }
}

Please note that in the JSON, we have VoiceApp.StationWebRTCHandler+Dial, this is to indicate that VoiceApp is the namespace, StationWebRTCHandler is the main class, and the dial class is a class that is part of the StationWebRTCHandler class.