Working Hello World WebRTC DataChannel Examples with Signaling Implemented - javascript

The intent is for this to become a Community Wiki post that is kept up-to-date so developers interested in implementing communication of JSON messages browser-to-browser (p2p) with WebRTC DataChannels have simple yet functional examples.
WebRTC DataChannels are experimental and still in draft. It seems that currently the web is a minefield of outdated WebRTC examples and even more so if a developer is trying to learn the RTCDataChannel API.
Simple yet functional 1-page examples that work today across WebRTC compliant browsers seem very difficult to find. For example, some examples leave out a signaling implementation, others only work for a single browser (e.g. Chrome-Chrome), many are outdated due to recent API changes, and others are so complex they create a barrier to getting started.
Please post examples that meet the following criteria (if something is not met please specify):
Client-side code is 1-page (200 lines or less)
Server-side code is 1-page and technology is referenced (e.g. node.js, php, python, etc.)
Signaling mechanism is implemented and protocol technology is referenced (e.g. WebSockets, long polling, GCM, etc.)
Working code that runs cross-browser (Chrome, Firefox, Opera, and/or Bowser)
Minimal options, error handling, abstraction, etc. -- the intent is an elementary example

Here is a working example that uses HTML5 WebSockets for signaling and a node.js backend
signaling technology: WebSockets
client: pure html/javascript
server: node.js, ws
last tested on: Firefox 40.0.2, Chrome 44.0.2403.157 m, Opera 31.0.1889.174
client-side code:
<html>
<head>
</head>
<body>
<p id='msg'>Click the following in different browser windows</p>
<button type='button' onclick='init(false)'>I AM Answerer Peer (click first)</button>
<button type='button' onclick='init(true)'>I AM Offerer Peer</button>
<script>
(function() {
var offererId = 'Gandalf', // note: client id conflicts can happen
answererId = 'Saruman', // no websocket cleanup code exists
ourId, peerId,
RTC_IS_MOZILLA = !!window.mozRTCPeerConnection,
RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection,
RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.msRTCSessionDescription,
RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.msRTCIceCandidate,
rtcpeerconn = new RTCPeerConnection(
{iceServers: [{ 'url': 'stun:stun.services.mozilla.com'}, {'url': 'stun:stun.l.google.com:19302'}]},
{optional: [{RtpDataChannels: false}]}
),
rtcdatachannel,
websocket = new WebSocket('ws://' + window.location.hostname + ':8000'),
comready, onerror;
window.init = function(weAreOfferer) {
ourId = weAreOfferer ? offererId : answererId;
peerId = weAreOfferer ? answererId : offererId;
websocket.send(JSON.stringify({
inst: 'init',
id: ourId
}));
if(weAreOfferer) {
rtcdatachannel = rtcpeerconn.createDataChannel(offererId+answererId);
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;
rtcpeerconn.createOffer(function(offer) {
rtcpeerconn.setLocalDescription(offer, function() {
var output = offer.toJSON();
if(typeof output === 'string') output = JSON.parse(output); // normalize: RTCSessionDescription.toJSON returns a json str in FF, but json obj in Chrome
websocket.send(JSON.stringify({
inst: 'send',
peerId: peerId,
message: output
}));
}, onerror);
}, onerror);
}
};
rtcpeerconn.ondatachannel = function(event) {
rtcdatachannel = event.channel;
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;
};
websocket.onmessage = function(input) {
var message = JSON.parse(input.data);
if(message.type && message.type === 'offer') {
var offer = new RTCSessionDescription(message);
rtcpeerconn.setRemoteDescription(offer, function() {
rtcpeerconn.createAnswer(function(answer) {
rtcpeerconn.setLocalDescription(answer, function() {
var output = answer.toJSON();
if(typeof output === 'string') output = JSON.parse(output); // normalize: RTCSessionDescription.toJSON returns a json str in FF, but json obj in Chrome
websocket.send(JSON.stringify({
inst: 'send',
peerId: peerId,
message: output
}));
}, onerror);
}, onerror);
}, onerror);
} else if(message.type && message.type === 'answer') {
var answer = new RTCSessionDescription(message);
rtcpeerconn.setRemoteDescription(answer, function() {/* handler required but we have nothing to do */}, onerror);
} else if(rtcpeerconn.remoteDescription) {
// ignore ice candidates until remote description is set
rtcpeerconn.addIceCandidate(new RTCIceCandidate(message.candidate));
}
};
rtcpeerconn.onicecandidate = function (event) {
if (!event || !event.candidate) return;
websocket.send(JSON.stringify({
inst: 'send',
peerId: peerId,
message: {candidate: event.candidate}
}));
};
/** called when RTC signaling is complete and RTCDataChannel is ready */
comready = function() {
rtcdatachannel.send('hello world!');
rtcdatachannel.onmessage = function(event) {
document.getElementById('msg').innerHTML = 'RTCDataChannel peer ' + peerId + ' says: ' + event.data;
}
};
/** global error function */
onerror = websocket.onerror = function(e) {
console.log('====== WEBRTC ERROR ======', arguments);
document.getElementById('msg').innerHTML = '====== WEBRTC ERROR ======<br>' + e;
throw new Error(e);
};
})();
</script>
</body>
</html>
server-side code:
var server = require('http').createServer(),
express = require('express'),
app = express(),
WebSocketServer = require('ws').Server,
wss = new WebSocketServer({ server: server, port: 8000 });
app.use(express.static(__dirname + '/static')); // client code goes in static directory
var clientMap = {};
wss.on('connection', function (ws) {
ws.on('message', function (inputStr) {
var input = JSON.parse(inputStr);
if(input.inst == 'init') {
clientMap[input.id] = ws;
} else if(input.inst == 'send') {
clientMap[input.peerId].send(JSON.stringify(input.message));
}
});
});
server.on('request', app);
server.listen(80, YOUR_HOSTNAME_OR_IP_HERE, function () { console.log('Listening on ' + server.address().port) });

Related

Why does "WebRTC Screen sharing" is not streaming when using different computers?

I am developing a web application, like an online classroom in which I want to share the screen of a browser from a computer and view it in another. I am getting an error "Uncaught (in promise) DOMException: Error" in chrome when I tried to share the screen from a computer and view it on another computer.
I am using WebRTC for this and WebSocket for signaling. At the backend, java jersey would be doing the searching & forwarding of the request to the appropriate clients. I can share the screen from one browser window and view it in another on the same machine. But when I'm using different computers I get this error. When I debug the RTCPeerConnection object, it shows that the property connectionState as failed and iceConnectionState as disconnected.
Javascript: Request to share the screen
var urlS = [];
var config = {iceServers: urlS};
var $source = $('#monitor-src');
$scope.context.peerConnection = new RTCPeerConnection();
$scope.context.peerConnection.onicecandidate = function(event)
{
console.log(event)
if (event.candidate)
{
var json =
{
type:event.type,
label:event.candidate.sdpMLineIndex,
id:event.candidate.sdpMid,
candidate:event.candidate
}
WebSocket.send({desc:json,usrId:$scope.context.me.id},$scope)
}
else
{
console.error("Failed to create ice candidate")
}
};
try
{
$scope.context.peerConnection.createOffer({offerToReceiveAudio: true,offerToReceiveVideo: true}).then(function(offer)
{
return $scope.context.peerConnection.setLocalDescription(offer);
}).then(function()
{
WebSocket.send({desc:$scope.context.peerConnection.localDescription,callee:mentee.id,caller:$scope.context.me.id,usrId:$scope.context.me.id},$scope)
});
}
catch(error)
{
console.error("onnegotiationneeded-"+error)
}
$scope.context.peerConnection.onnegotiationneeded = function()
{
console.error("onnegotiationneeded")
};
try
{
console.log($scope.context.peerConnection);
$scope.context.peerConnection.ontrack = function(event)
{
console.log("ontrack:"+event.streams.length)
$source.parent()[0].srcObject= event.streams[0];
};
$scope.context.peerConnection.onaddstream = function(event)
{
console.log("onaddstream:"+event.stream)
$source.parent()[0].srcObject = event.stream;
};
}
catch(error)
{
console.error(error)
}
Javascript:WebSocket Handling of the request and sending response
$rootScope.socket.onMessage(function(message)
{
data = angular.fromJson(message.data);
if(data.type == 'offer')
{
var stream = null;
//var urlS = [{urls: 'stun:192.168.1.16:8443'}];
var urlS = [];
var config = {iceServers: urlS};
scope.context.peerConnection = new RTCPeerConnection();
scope.context.peerConnection.setRemoteDescription(data).then(function(){
return navigator.mediaDevices.getDisplayMedia({video:true,audio: true});
}).then(function(stream){
console.log(scope.context.peerConnection)
scope.context.peerConnection.addStream(stream);
stream.getTracks().forEach(function(track)
{
//var rtpSender =
});
scope.context.peerConnection.createAnswer().then(function(answer){
return scope.context.peerConnection.setLocalDescription(answer)
}).then(function()
{
send({desc:scope.context.peerConnection.localDescription,usrId:scope.context.me.id},scope)
}).catch(function(error){
console.error(error)});
})
}
else if(data.type == 'answer')
{
scope.context.peerConnection.setRemoteDescription(data);
}
else if(data.type == 'icecandidate')
{
console.log("icecandidate:"+angular.toJson(data))
var promise = scope.context.peerConnection.addIceCandidate(data.candidate).then(function success(){
console.log("ice success")
}).catch(function error(err)
{
console.log(err);
});
}
});
};
The ontrack and onaddstream events are triggered when a stream is added to the peer connection. But I get nothing on the requested peer.
I am not a JavaScript expert but your urlS array seems to be empty. Try to add both Turn and Stun servers in your urlS.
For more info take a look here

Implementing RabbitMQ in Chrome Kiosk/Extension/Apps and Web Browsers

I'm developing internal applications that require push notifications but we cannot use outside services. I have started to work with RabbitMQ and have it working flawlessly inside of .NET Core. When trying to implement it the same thing with javascript I am not getting the same results.
I developed test clients in C#. I developed a client in javascript. I can make a successful connection but data is not arriving.
In C# I am using:
string e = Console.ReadLine();
Console.WriteLine("Enter a message (blank for test msg)");
string message = Console.ReadLine();
var factory = new ConnectionFactory() { HostName = "10.222.2.160" };
factory.UserName = "Test";
factory.Password = "TestPassword";
factory.VirtualHost = "/";
using (var connection = factory.CreateConnection("TestChannel"))
using (var channel = connection.CreateModel())
{
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: e,
routingKey: "",
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
In Javascript:
var wsbroker = "10.222.2.160"; // mqtt websocket enabled broker
var wsport = 15675; // port for above
var client = new Paho.MQTT.Client(wsbroker, wsport, "/ws/",
"test");
client.onConnectionLost = function (responseObject) {
console.log("CONNECTION LOST - " + responseObject.errorMessage);
};
client.onMessageArrived = function (message) {
console.log("RECEIVE ON " + message.destinationName + " PAYLOAD " + message.payloadString);
};
var options = {
userName: "Test",
password: "TestPassword",
timeout: 3,
keepAliveInterval: 30,
onSuccess: function () {
console.log("CONNECTION SUCCESS");
client.subscribe('test', { qos: 1 });
},
onFailure: function (message) {
console.log("CONNECTION FAILURE - " + message.errorMessage);
}
};
if (location.protocol == "https:") {
options.useSSL = true;
}
console.log("CONNECT TO " + wsbroker + ":" + wsport);
client.connect(options);
I need to be able to connect to rabbitmq from javascript (non-node, chrome kiosk application/chrome extension). However, I'm not sure I am "understanding" RabbitMQ. Pointing me in the right direction would help a girl out. Thanks!
You're publishing without a routing key here:
channel.BasicPublish(exchange: e,
routingKey: "",
basicProperties: null,
body: body);
Ensure that the test queue exists, then change routingKey to test in your publisher, and use the exchange named amq.direct.
You should read the RabbitMQ introduction available here to get familiar with how exchanges, queues, routing keys and bindings interact:
https://www.cloudamqp.com/blog/2015-05-18-part1-rabbitmq-for-beginners-what-is-rabbitmq.html
NOTE: the RabbitMQ team monitors the rabbitmq-users mailing list and only sometimes answers questions on StackOverflow.

How to get Computer Name and IP address by Jquery or JS

How to get Computer Name and IP address by jquery or JS ?
I found this code snippet that actually worked for me
var RTCPeerConnection = /*window.RTCPeerConnection ||*/
window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
if (RTCPeerConnection) (function () {
var rtc = new RTCPeerConnection({ iceServers: [] });
if (1 || window.mozRTCPeerConnection) {
rtc.createDataChannel('', { reliable: false });
};
rtc.onicecandidate = function (evt) {
if (evt.candidate)
grepSDP("a=" + evt.candidate.candidate);
};
rtc.createOffer(function (offerDesc) {
grepSDP(offerDesc.sdp);
rtc.setLocalDescription(offerDesc);
}, function (e) { console.warn("offer failed", e);
});
var addrs = Object.create(null);
addrs["0.0.0.0"] = false;
function updateDisplay(newAddr) {
if (newAddr in addrs) return;
else addrs[newAddr] = true;
var displayAddrs = Object.keys(addrs).filter(function(k) {
return addrs[k];
});
document.getElementById('list').textContent =
displayAddrs.join(" or perhaps ") || "n/a";
}
function grepSDP(sdp) {
var hosts = [];
sdp.split('\r\n').forEach(function (line) {
if (~line.indexOf("a=candidate")) {
var parts = line.split(' '),
addr = parts[4],
type = parts[7];
if (type === 'host') updateDisplay(addr);
} else if (~line.indexOf("c=")) {
var parts = line.split(' '),
addr = parts[2];
updateDisplay(addr);
}
});
}
})(); else
{
document.getElementById('list').innerHTML = "<code>ifconfig| grep inet | grep -v inet6 | cut -d\" \" -f2 | tail -n1</code>";
document.getElementById('list').nextSibling.textContent = "In Chrome and Firefox your IP should display automatically, by the power of WebRTCskull.";
}
<div id="list"></div>
And unlike other codes which mostly returns server IP address it return client ip address of machine.Refer this article
https://www.c-sharpcorner.com/blogs/getting-client-ip-address-or-local-ip-address-in-javascript
To get Computer Name and IP Address using JavaScript,
-- ComputerName
var network = new ActiveXObject('WScript.Network');
// Show a pop up if it works
alert(network.computerName);
-- IP Address
$.getJSON("http://jsonip.com/?callback=?", function (data) {
console.log(data);
alert(data.ip);
});
for computer name
<script type="text/javascript">
var network = new ActiveXObject('WScript.Network');
alert(network.computerName);
</script>
You can get IP address by using simple ajax request as:-
let xhttp = new XMLHttpRequest();
xhttp.open("GET", "https://api.ipify.org/?format=json", true);
xhttp.send();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
let ip = JSON.parse(this.responseText).ip;
}
};
You can get an IP address by using a simple fetch request as:-
async function getIP(){
let req = await fetch("https://peerip.glitch.me/");
let data = await req.json();
let IP = data.ip;
return IP;
}
If you need these details client side,
you could use third party service like https://www.ipify.org/ and make API call to get the details like IP.
For other details, use similar service/services.
But if you are looking this details server side, then it depends what programming language you have used, though on server side this information readily available in HTTP Headers.
Refer similar questions for server side details.
How to get the exact client browser name and version in Spring MVC?
Browser, Operating System, Screen Colors, Screen Resolution, Flash version, and Java Support should all be detectable from JavaScript (and maybe a few more). However, computer name is not possible

Unsupported URL with post data from IOS to backend service

I want to use webrtc in an IOS (Swift) project. I find so much difficulties to implement it properly. So I searched for an library so I can get how it is implemented to do it later myself.
I found this project:
https://github.com/sushilthe/webrtc-ios-swift
It works fine with https://apprtc.appspot.com. But it is making a POST? request when you want to join a room:
Base url:
https://apprtc.appspot.com/
Part that is appended to the base:
static NSString *kARDRoomServerRegisterFormat =
#"%#/join/%#";
Result:
https://apprtc.appspot.com/join/'roomnr'
I have build a server with some resources from the internet:
$(document).ready(function() { //wait for DOM to be ready for JS execution
easyrtc.setVideoDims(1280, 768);
easyrtc.easyApp('vcdemo', 'self', ['peer'], connectSuccess, failureCallback); //connect to easyrtc app; initiate media sources and elements
});
//global state variables
var myEasyrtcId; //id of client in the signaling framework
//global functions
var connectSuccess = function(easyrtcid) { //join room as defined by "room" parameter in URL
myEasyrtcId = easyrtcid;
console.log('Connect successful. My id is ' + myEasyrtcId + '.');
var room = decodeURIComponent((new RegExp('[?|&]room=' + '([^&;]+?)(&|#|;|$)'). //retrieve room name from URL
exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null;
console.log('join room: ' + room);
easyrtc.joinRoom(room, null, joinSuccess, failureCallback);
};
var failureCallback = function(errorCode, errorMsg) { //log error
console.log(errorCode);
console.log(errorMsg);
};
var joinSuccess = function(roomName) { //listen for peers joining the room
setTimeout(function() {
console.log('successfully joined room: ' + roomName);
var peers = easyrtc.getRoomOccupantsAsArray(roomName) || []; //get list of client connected to room
console.log('peers: ' + peers);
var peersLength = peers.length;
if (peersLength > 2) { //support only 1-1 video conferences
alert('The meeting room is already full. ' +
'Only the two peers connecting first will be allowed access.');
} else if(peersLength === 1) { //if no other peer is connected
console.log('waiting for peer to connect...');
} else if(peers[0] != myEasyrtcId) {//get peer id
easyrtc.call(peers[0]);
} else {
easyrtc.call(peers[1]);
}
}, 100);
};
This works perfect in chrome and firefox via this url:
localhost:8080/?room=123
And I can connect to that stream when I reuse that room number. Perfect!
So I thought I can implement that in the app, I have changed the serverHostUrl to: client?.serverHostUrl = "192.168.1.59:8080"
And the other variable:
static NSString *kARDRoomServerRegisterFormat = #"%#/?room=%#";
But I get an error when it try's to submit the url:
Client Connecting
2016-10-17 19:24:51.151795 WebRTC iOS Swift[3944:1036130] Registering with room server.
2016-10-17 19:24:51.151900 WebRTC iOS Swift[3944:1036130] url = 192.168.1.59:8080/?room=123
2016-10-17 19:24:51.207496 WebRTC iOS Swift[3944:1036130] Error posting data: unsupported URL
Client Disconnected
I have searched a few hours why this is happening. But I can't find the problem. Thank you very much!
EDIT
The Code where it goes wrong:
The roomURL is: 192.168.1.59:8080/?room=123 at that moment.
[NSURLConnection sendAsyncPostToURL:roomURL
withData:nil
completionHandler:^(BOOL succeeded, NSData *data) {
ARDAppClient *strongSelf = weakSelf;
if (!succeeded) {
NSError *error = [self roomServerNetworkError];
[strongSelf.delegate appClient:strongSelf didError:error];
completionHandler(nil);
return;
}
ARDRegisterResponse *response =
[ARDRegisterResponse responseFromJSONData:data];
completionHandler(response);
}];

Javascript cannot connect to websocket server endpoint

I have a java web application running on my private JVM on MochaHost. Application is running fine expect the websocket.
I have a websocket endpoint on my JAVA application. I use annotations.
#ServerEndpoint(value = "/websocket/chat/{room}", configurator = ServletAwareConfig.class)
My domain is www.instacollaboration.com. The application is working fine in general except my java script client cannot connect to the websocket server end point.
var Chat = {};
Chat.socket = null;
Chat.connect = (function(host) {
if ('WebSocket' in window) {
Chat.socket = new WebSocket(host);
} else if ('MozWebSocket' in window) {
Chat.socket = new MozWebSocket(host);
} else {
Console.log('Error: WebSocket is not supported by this browser.');
return;
}
Chat.socket.onopen = function() {
Console.log('Info: WebSocket connection opened. Meeting Room#' + myMeeringRoomNum);
document.getElementById('chat').onkeydown = function(event) {
if (event.keyCode == 13) {
Chat.sendMessage();
}
};
};
Chat.socket.onclose = function() {
document.getElementById('chat').onkeydown = null;
Console.log('Info: WebSocket closed.');
};
Chat.socket.onmessage = function(message) {
// Console.log(message.data);
processCommands(message.data);
};
});
Chat.initialize = function() {
var url = window.location.host + '/websocket/chat/';
if (window.location.protocol == 'http:') {
Chat.connect('ws://' + url + myMeeringRoomNum);
} else {
Chat.connect('wss://' + url + myMeeringRoomNum);
}
};
I am seeing this error.
Firefox can't establish a connection to the server at ws://instacollaboration.com/websocket/chat/Y6LA.
Am I missing something? Do mochahost support websockets?
My application and websocket connection run fine on my local tomcat server. This problem is only when running on remote server on MochaHost.
Just chatted with MochaHost support. They don't support websocket on shared servers. I have to buy/rent a private server. :(

Categories

Resources