powered by Jive Software

WebRTC Demo for Openfire using WebSockets & JingleNodes

Now that WebRTC is now live in Chrome version 23, which is now rolling out to the public, expect some new exciting web applications with audio and video that will change the way we communicate beyond what we have seen so far with Skype and Flash.

The SIP community have already forged ahead with SIP over WebSockets and a number of SIP signaling libraries have started to appear. I am not convinced that employing heavy bloated SIP messages for WebRTC signaling is the best approach, but I am not ready to re-open an ancient debate.

Meanwhile at Ignite-realtime here, If you want to see what you can do with Openfire using the WebSockets and JingleNodes plugins, then take a look at my demo based on the Mobiecents SIP demo I replaced their SIP JavaScript library with a simpler XMPP Jingle library. I also added support for Jingle Relay Nodes to bridge the media when both peers cannot communicate directly with each other.


To try it out, you would need two PCs with webcams both running latest Chrome version 23+. Use any two unique user names (eg user1 and user2) with no spaces and special characters. From user1, enter contact JID to call as user2@redfire.4ng.net/user2 or vice-versa.

For those interested in the source code, it is attached to this blog.
webrtc.zip (305402 Bytes)


Tried this on a Openfire 3.7.2 Beta build and I’m unable to initially connect with websockets. I get a 302 error. Should the websockets connection should be ws://yourserverhere:7070/ws/server?user=null&password=null&resource=foo ?

I also saw this strangeness when I restarted the plugin.

2012.11.26 19:22:36 org.jivesoftware.openfire.component.InternalComponentManager - InternalComponentManager: Unregistering component for domain: presence

2012.11.26 19:22:36 org.jivesoftware.openfire.component.InternalComponentManager - InternalComponentManager: Component unregistered for domain: presence

2012.11.26 19:22:43 org.jivesoftware.openfire.container.PluginManager - PluginManager: Extracting plugin: websockets 2

2012.11.26 19:22:43 org.jivesoftware.openfire.container.PluginManager - PluginManager: Extracting plugin: presence

2012.11.26 19:22:43 org.jivesoftware.openfire.container.PluginManager - PluginManager: Loading plugin presence

2012.11.26 19:22:43 org.jivesoftware.openfire.co

mponent.InternalComponentManager - InternalComponentManager: Registering component for domain: presence

2012.11.26 19:22:43 org.jivesoftware.openfire.component.InternalComponentManager - InternalComponentManager: Component registered for domain: presence

2012.11.26 19:22:43 org.jivesoftware.openfire.container.PluginManager - PluginManager: Loading plugin websockets 2

Are you adding a plugin for websockets based presence?



No, just websockets ver and jinglenodes plugins

As the websockets plugin creates an embedded jetty web service, it does not restart properly. just restart openfire.

my websocket connection is an anonymous conection and the files are loded in openfire at openfire_home\resources\spank\webrtc

ws = new WebSocket(“ws://” + window.location.host + “/ws/server?username=null&password=null&resource=” + me, “xmpp”);

You may have to enable anonymous connections in openfire, otherwise, use a valid username and password

This is very very neat! I’m still in the closed beta mode of offering my users the full webrtc experience at jabber-server.de. I’m excited to see some new web applications in the future too.

If the plugin has an embedded jetty server, what port is configured to be used? 7070? Should I have turned off BOSH?



embedded web service “ws”, not server. Openfire already has jetty web server embedded. websockets is reusing the http-bind manager and consequently whatever port htttp-bind is set to. 7070 is the default.

After cleaning up my logs and restarting openfire, I get this error

2012.11.27 10:36:30 WebSocketsPlugin - An error has occurred


at com.ifsoft.websockets.servlet.XMPPServlet.(XMPPServlet.java:55)

at com.ifsoft.websockets.plugin.WebSocketsPlugin.initializePlugin(WebSocketsPlugin .java:58)

at org.jivesoftware.openfire.container.PluginManager.loadPlugin(PluginManager.java :483)

at org.jivesoftware.openfire.container.PluginManager.access$300(PluginManager.java :80)

at org.jivesoftware.openfire.container.PluginManager$PluginMonitor.run(PluginManag er.java:1067)

at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)

at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source)

at java.util.concurrent.FutureTask.runAndReset(Unknown Source)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101 (Unknown Source)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodi c(Unknown Source)

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknow n Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

from this line

sockets = ( ( WebSocketsPlugin) XMPPServer.getInstance().getPluginManager().getPlugin( “websockets” ) ).getSockets();

I noticed that 0.0.4 loads as Websockets 2 and that it was possible to have both 0.0.3 and 0.0.4 installed at the same time. Should both be installed simultaneously?

no. why do you need both at the same time? that would confuse openfire

I don’t have both running, but I was curious why you renamed 0.0.4. Isn’t it a race condition where the Plugin is constructing the Servlet and the Servlet is asking for information before the plugin has finished initializing itself?

Any idea why getting the sockets from the plugin is failing? It would appear that Jetty is running, and I can connect to port 7070, so it appears that the Servlet is failing to run because it can’t initialize.



the only thing the plugin does is to start the web sockets service. The getsockets request is to the singleton sockets object which is initialised by the plugin class constructor. By the time Openfire calls initializePlugin, the sockets hashmap is ready to go.

I noticed that a plugin name is not set, which means the file name would be used by default. Are you sure your plugin is labelled “websockets.war”

Otherwise, you may be right and it could be a race condition, because Openfire has not registered the plugin name causing the reference later on to fail. Funny, I have not seen this error in months of using the plugin.

The WAR file as unpacked is “websockets 2” so, it sounds like that is the problem.



That was the problem. The download unpacks as “websockets 2”. Renaming that to websockets works.



The code expects the web application to be run from the openfire websockets which uses location OPENFIRE_HOME/resources/spank

see code

var defaultWsUrl = “ws://” + window.location.host + “/ws/server?username=null&password=null&resource=” + defaultSipDisplayName

if you are running from a different web service change this line to point to the Openfire websockets on port 7070 or whatever you change it to.

var defaultWsUrl = “ws://localhost:7070/ws/server?username=null&password=null&resource=” + defaultSipDisplayName

If your clients are are on different IP within the same network, then localhost will not work you need a doman name that resolves via DNS. That is basic networking stuff. Don’t use IP addresses for XMPP, you need a proper domain name. You openfire server name is fine if it resolves by IP address on all clients.

From the error message, I can see you either do not have jingle relay nodes plugin running on openfire server or your openfire server is not configured correctly with a domain name instead of an IP address or your jingle relay nodes is not configured with a public IP adress.

It handles those cases where your peers are behind restrictive NAT or no STUN support and cannot see each other and need a third party to relay the media just like Skype super nodes.

You can ignore the message when working from a local network, but as soon as you put your openfire server on the Internet, you will need Jingle relay nodes for WebRTC to work reliably.


Very nice work.

I tried it and it works the chat. However, it does not work the audio and video.

I asked permission to access the microphone and cam, but I receive nothing at the other end.

These are the logs that appear in the chrome console.

doMakeCall true user1@um.es assistant.js:903

doMakeCall [object Object] assistant.js:920

startCall undefined assistant.js:941

new JingleCall webrtc6hqr4w0f6 0 jingle.js:19

JingleCall - start outbound call to user1@um.es/ofchat jingle.js:41

JingleCall - createPeerConnection jingle.js:125

_sendJingleSessionIQ jingle.js:165

v=0o=- 2197418107 2 IN IP4 0a=group:BUNDLE audio videom=audio 1 RTP/SAVPF 103 104 111 0 8 106 105 13 126c=IN IP4 IN IP4 ons:google-icea=sendrecva=mid:audioa=rtcp-muxa=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:zX3SGZ7C/VPbOZk3LDkjxgZMMRVAagT1TXBdVnVLa=rtpmap:103 ISAC/16000a=rtpmap:104 ISAC/32000a=rtpmap:111 opus/48000a=rtpmap:0 PCMU/8000a=rtpmap:8 PCMA/8000a=rtpmap:106 CN/32000a=rtpmap:105 CN/16000a=rtpmap:13 CN/8000a=rtpmap:126 telephone-event/8000a=ssrc:572071724 cname:X2LMZSKVO2o29fhma=ssrc:572071724 msid:byf0oEqduF8kobRBYYwKFIAM1vksx3Q5P3lG a0a=ssrc:572071724 mslabel:byf0oEqduF8kobRBYYwKFIAM1vksx3Q5P3lGa=ssrc:572071724 label:byf0oEqduF8kobRBYYwKFIAM1vksx3Q5P3lGa0m=video 1 RTP/SAVPF 100 101 102c=IN IP4 IN IP4 ons:google-icea=sendrecva=mid:videoa=rtcp-muxa=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:zX3SGZ7C/VPbOZk3LDkjxgZMMRVAagT1TXBdVnVLa=rtpmap:100 VP8/90000a=rtpmap:101 red/90000a=rtpmap:102 ulpfec/90000a=ssrc:937256194 cname:X2LMZSKVO2o29fhma=ssrc:937256194 msid:byf0oEqduF8kobRBYYwKFIAM1vksx3Q5P3lG v0a=ssrc:937256194 mslabel:byf0oEqduF8kobRBYYwKFIAM1vksx3Q5P3lGa=ssrc:937256194 label:byf0oEqduF8kobRBYYwKFIAM1vksx3Q5P3lGv0 jingle.js:166

Jingle call webrtc6hqr4w0f6 _onStateChanged jingle.js:181

Event {clipboardData: undefined, cancelBubble: false, returnValue: true, srcElement: RTCPeerConnection, defaultPrevented: false…}


JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

2JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

JingleCall - onIceCandidate jingle.js:141

JingleCall - sendTransportInfo jingle.js:151

8JingleCall - onIceCandidate


Dele & Team,

I am having difficulties in making audio and video call as per Dele’ demo.

I have installed the demo and I can register user1 and user2 with Openfire. My configuration is as follows:

  1. Openfire – version 3.8.1

  2. Jingle Nodes Plugin – version 0.0.3

  3. WebSocket Plugin – version

4.Chrome – version – version 23.0.1271.95 m

  1. websocket connection is an anonymous connection and the files are loaded in openfire at openfire_home\resources\spank\webrtc

When I make the call from user1 to user2, I get the following error at the console:

onLoad www.abc.com:155

connect www.abc.com:240

onOpen www.abc.com:254

startLocalMedia blob:http%3A//www.abc.com%3A7070/e253fd36-ad92-4334-99cd-ddb1ea699bf9 www.abc.com:191

Uncaught Error: TypeMismatchError: DOM Exception 17 webrtc-jingle.js:184

The exception is occurring in webrtc-jingle.js:184

WebRtcJingle.prototype.jingleInitiate = function(farParty)

{ //console.log("jingleInitiate " + farParty);

this.farParty = farParty;

this.inviter = true;

this.sid = “webrtc-initiate-” + Math.random().toString(36).substr(2,9);


if (this.pc != null)

{ var webrtc = this;

this.pc.createOffer( function(desc)

Uncaught Error: TypeMismatchError: DOM Exception 17

{ webrtc.pc.setLocalDescription(desc);


}, null, {has_audio: true, has_video: true}); } }

Any idea as to why this is happening? Hence, I can’t complete the call.



Many changes have been made to the webrtc specification and Chrome implementation. That code is broken and may not work any more

Change to this.

Remove extra parameters “null, {has_audio: true, has_video: true}” That might help

{ webrtc.pc.setLocalDescription(desc);


}); } }

Hello Dele,

I got your demo working. Thanks for your help.



is this still working? I find it cool but i can’t use it.

The web page is using location.hostname and assuming that it has been loaded from the Openfire jetty web server. If you are running from another web server, you should change it.