At last year’s AstriDevcon, we showed a video conference demonstration application called CyberMegaPhone. It was a very simple app but it showed how a web developer could create a video conference app of their own using Asterisk’s new WebRTC capabilities. While we made some significant enhancements to Asterisk’s video capabilities over the past year, we also introduced a companion set of features called “Enhanced Messaging” designed to help enrich the conference app experience. This blog post will demonstrate using Enhanced Messaging to create a chat channel for your conferences and a future post will demonstrate how Enhanced Messaging can provide information about the conference bridge and its participants.
Chat Away!
It’s a video call, why do I need chat?
If you’re making a simple two-party video call, having a chat channel isn’t all that important but it could come in handy for quickly sending the other party links related to what you’re discussing. In a large video conference where there’s a presenter and/or moderator, having a chat channel can be a powerful addition to the experience. Participants can ask questions among themselves without disturbing the presenter, or queue up questions for the presenter to answer when they get a chance. The presenter could even post links to companion or reference material for the participants to follow.
I’m sold. How do I implement it?
Using Enhanced Messaging of course. Enhanced Messaging added to Asterisk (specifically to chan_pjsip and app_confbridge) the ability to use the SIP MESSAGE messages to carry non-plain-text information and to send it to all participants in a multi-party bridge.
Configuring Asterisk
There is no configuration needed. Enhanced Messaging is built-in and always available.
In the browser…
How you design the user interface portion is totally up to you but here’s a quick sample of how CyberMegaPhone could be extended to send a message using JsSIP. In this example, this._ua is a JsSIP.UA instance and this.rtc is a JsSIP.RTCSession instance. Refer to the CyberMegaPhone code to see where this might fit.
CyberMegaPhone.prototype.sendMessage = function (string_msg, options = {} ) { /* You could allow the user to set a nickname * for themselves which JsSIP can send as the * display name in the SIP From header. In the code * that receives the message, you can then grab the * display name from the packet. */ if (options.from) { from = options.from; this._ua.set("display_name", from); } /* * The message payload can be any UTF-8 string but you're not * limited to plain text. The Content-Type must be set to one * of the text/ or application/ types but as long as the sender * and receiver agree on the payload format, it can contain * whatever you want. In this example, we're going to send * a JSON blob. * * If you don't want to alter the display name on the actual * SIP MESSAGE From header, you could include the user's * nickname in the payload. */ let msg = { 'From': from, 'Body': string_msg }; let body = JSON.stringify(msg); let extraHeaders = [ 'Content-Type: application/x-myphone-confbridge-chat+json' ]; this.rtc.sendRequest(JsSIP.C.MESSAGE, { extraHeaders, body: body, eventHandlers: options.handlers }); }; /* * Now here's how you'd call sendMessage */ phone.sendMessage("Hello!", {from: "My Name", handlers: { onSuccessResponse(response) { // You may want to show an indicator that the message was sent successfully. console.log("Message Sent: " + response); }, onErrorResponse(response) { console.log("Message ERROR: " + response); }, onTransportError() { console.log("Could not send message"); }, onRequestTimeout() { console.log("Timeout sending message"); }, onDialogError() { console.log("Dialog Error sending message"); }, }});
Congratulations, you’ve just sent a text message! Assuming the user called a conference bridge in the first place, all the other participants should receive it. The code to retrieve the message is even simpler than the code to send it. Once again, in this CyberMegaPhone example, this._ua is the JsSIP.UA instance.
this._ua.on('newMessage', function (data) { /* We don't care about message we send. */ if (data.originator === 'local') { return; } /* Grab the Content-Type header from the packet */ let ct = data.request.headers['Content-Type'][0].raw; /* Make sure the message is one we care about */ if (ct === 'application/x-myphone-confbridge-chat+json') { /* Parse the body back into an object */ let msg = JSON.parse(data.request.body); /* Tell the UI that we got a chat message */ that.raise('messageReceived', msg); } });
Wrap Up
As stated earlier, how you design your user interface is totally up to you but hopefully this blog post gives you a head start on implementing chat functionality in your conferencing app. Oh, and while this post used video conferencing as the example, video isn’t a requirement. An audio conference web app could implement chat just as easily and of course, you can also use Enhanced Messaging to pass non-chat messages between your web app instances. For instance, you could use it to implement a “Raise Hand” feature.
In the next Enhanced Messaging blog post, I’ll be showing you how to integrate information about a conference bridge and it’s participants into your app. Stay tuned!