WebRTC: Unable to to receive remote video or audio - javascript

The goal is to have a webrtc video/audio p2p connection.
I did take some examples and put them together and manage to get far enough that "most" exchange (via eventsource on NodeJS) is done, just remote stream is not received.
I found that Chrome browser had a bug in which the request is send twice (any fix for this?).
But even when I use firefox (on laptop and phone), there is just no stream received.
with no error on both sides.
This is the full script:
if (!console || !console.log) {
var console = {
log: function() {}
};
}
// Ugh, globals.
// const signaling = new SignalingChannel(); hier moet een module voor komen, als een EventServerSide en/of Websocket...
var peerc;
var source = new EventSource("events");
var selfView = document.getElementById('localvideo');
var remoteView = document.getElementById('remotevideo');
//var TextHistory = ["apple", "orange", "cherry"]; //[ ];
var audio = null;
var audioSendTrack = null;
var video = null;
var videoSendTrack = null;
var chatbox = document.getElementById("chatbox");
var constraints = {video:true, audio:true};
var configuration = {
iceServers: [{
'urls': 'stun:stun.l.google.com:19302'
}]
};
var started = false;
var pc;
$("#incomingCall").modal();
$("#incomingCall").modal("hide");
$("#incomingCall").on("hidden", function() {
document.getElementById("incomingRing").pause();
});
source.addEventListener("ping", function(e) {}, false);
source.addEventListener("userjoined", function(e) {
appendUser(e.data);
}, false);
source.addEventListener("userleft", function(e) {
removeUser(e.data);
}, false);
source.addEventListener("offer", async function(e) {
log("offer received");
if (!pc) {
log("PeerConnection ontbreekt");
warmup(false);
} else {
warmup(true);
}
try {
const message = JSON.parse(e.data);
if (message.desc) {
log("Offer: Desc");
const desc = message.desc;
// if we get an offer, we need to reply with an answer
if (desc.type == 'offer') {
log("Offer: Desc offer");
var connectionState = pc.connectionState;
log(connectionState);
await pc.setRemoteDescription(JSON.parse(desc)); // Parse nodig?
await pc.setLocalDescription(await pc.createAnswer());
var connectionState = pc.connectionState;
log(connectionState);
//signaling.send(JSON.stringify({desc: pc.localDescription}));
jQuery.post(
"offer", {
to: message.from,
from: document.getElementById("user").innerHTML,
desc: JSON.stringify(pc.localDescription)
},
function() { log("Offer sent!"); }
).error("desc", error);
} else {
log("Offer: Desc answer");
await pc.setRemoteDescription(JSON.parse(desc));
}
} else if (message.start) {
log("Offer: Start received from: " + message.from);
started = true;
voor = message.from
van = message.to
if (audio && audioSendTrack) {
log("Wacht op audio");
await audio.sender.replaceTrack(audioSendTrack);
}
if (video && videoSendTrack) {
log("Wacht op video");
await video.sender.replaceTrack(videoSendTrack);
}
log("Offer: Started....wat next???");
} else {
log("Offer: wacht op candidate");
log(message.candidate);
await pc.addIceCandidate(message.candidate);
}
} catch (err) {
console.log(err);
log("Error in Offer event: " + err);
}
}, false);
source.addEventListener("message", function(e) {
var message = JSON.parse(e.data);
text = "User: " + message.from + " - Say: " + message.text;
WriteChat(text);
}, false);
source.addEventListener("answer", function(e) {
var answer = JSON.parse(e.data);
peerc.setRemoteDescription(new RTCSessionDescription(JSON.parse(answer.answer)), function() {
console.log("Call established!");
}, error);
}, false);
function log(info) {
var d = document.getElementById("debug");
d.innerHTML += info + "\n\n";
}
function appendUser(user) {
// If user already exists, ignore it
var index = users.indexOf(user);
if (index > -1)
return;
users.push(user);
console.log("appendUser: user = " + user + ", users.length = " + users.length);
var d = document.createElement("div");
d.setAttribute("id", btoa(user));
var a = document.createElement("button");
a.setAttribute("class", "vertical-align");
a.setAttribute("onclick", "initiateCall('" + user + "');"); //Dit moet dus prive chat worden.
a.innerHTML = "<i class='icon-user icon-white'></i> " + user;
d.appendChild(a);
d.appendChild(document.createElement("br"));
document.getElementById("users").appendChild(d);
}
function removeUser(user) {
// If user already exists, ignore it
var index = users.indexOf(user);
if (index == -1)
return;
users.splice(index, 1)
var d = document.getElementById(btoa(user));
if (d) {
document.getElementById("users").removeChild(d);
}
}
function sendPrive(user) {
log("Prive message"); // + JSON.stringify(offer));
if(!user) { user = "niets!"};
jQuery.post(
"message", {
to: user,
from: document.getElementById("user").innerHTML,
text: JSON.stringify(message)
},
function() { console.log("Message sent!"); }
).error("privemsg",error);
}
function offer(data){
log("Offer to send message: " + JSON.stringify(data));
// start
// desc + type
// candidate
jQuery.post(
"offer", {data: JSON.stringify(data)},
function() { console.log("Message sent!"); }
).error("offer",error);
}
function BroadcastMessage() {
log("Broadcast Message"); // + JSON.stringify(offer)); //function uitbreiden met argumentinvoer
message = document.getElementById("text_input").value;
jQuery.post(
"message", {
to: user,
from: document.getElementById("user").innerHTML,
text: JSON.stringify(message)
},
function() { console.log("Message sent!"); }
).error("BroadcastMessage",error);
//WriteChat(msg);
}
// Dit is een interne, dit moet dus via events gaan!!
function WriteChat(text){
// kan nog user en tijd bijkomen...
chatbox.innerHTML += text + "<br>"; // deze werkt dus niet meer, canvas wil andere methode
}
// Call warmup() to warm-up ICE, DTLS, and media, but not send media yet.
async function warmup(isAnswerer) {
log("Warming up...");
pc = new RTCPeerConnection(configuration);
if (!isAnswerer) { //uitzoeken waarom deze uitgeschakelen...
audio = pc.addTransceiver('audio');
video = pc.addTransceiver('video');
}
// send any ice candidates to the other peer
pc.onicecandidate = (event) => {
log("Offer: onicecandidate...");
//signaling.send(JSON.stringify({candidate: event.candidate}));
log(event.candidate)
if(event.candidate){
jQuery.post(
"offer", {
to: voor,
from: document.getElementById("user").innerHTML,
data: event.candidate, // debugging...
candidate: event.candidate
}, // hier zijn we nu...candidate blijft leeg????
function() { log("Offer: onicecandidate sent!"); }
).error("onicecandidate",error);
} else {
log("geen candidate");
}
};
pc.onnegotiationneeded = function() {
log("negotiation nodig...");
//var connectionState = RTCPeerConnection.connectionState;
pc.createOffer().then(function(aanbod) {
var connectionState = pc.connectionState;
log(connectionState);
log(JSON.stringify(aanbod));
return pc.setLocalDescription(aanbod);
})
.then(function() {
log(JSON.stringify(pc.localDescription));
jQuery.post(
"offer", {
to: document.getElementById("user").innerHTML,
from: voor,
desc: JSON.stringify(pc.localDescription)
},
function() { log("Offer: localDescription sent!"); }
).error("onnegotiationneeded",error);
})
.catch(error);
}
log("Remote video");
// once media for the remote track arrives, show it in the remote video element
pc.ontrack = async (event) => {
log("start ontrack...");
remoteView.srcObject = event.streams[0];
remoteView.play();
selfView.play();
log("oude ontrack...");
try {
log(event.track.kind);
if (event.track.kind == 'audio') {
log("Track heeft audio");
if (isAnswerer) {
log("beantwoord audio");
audio = event.transceiver;
audio.direction = 'sendrecv';
if (started && audioSendTrack) {
await audio.sender.replaceTrack(audioSendTrack);
}
}
}
} catch (err) {
console.log(err);
log("Error in audio ontrack: " + err);
}
try {
log(event.track.kind);
if (event.track.kind == 'video') {
log("Track heeft video");
if (isAnswerer) {
log("beantwoord video");
video = event.transceiver;
video.direction = 'sendrecv';
if (started && videoSendTrack) {
await video.sender.replaceTrack(videoSendTrack);
}
}
}
} catch (err) {
console.log(err);
log("Error in video ontrack: " + err);
}
try {
// don't set srcObject again if it is already set.
if (!remoteView.srcObject) {
log("Nog geen remote video...");
remoteView.srcObject = new MediaStream();
}
log("Voeg remote video toe...");
log(event.track);
remoteView.srcObject.addTrack(event.track);
} catch (err) {
console.log(err);
log("Error in last ontrack: " + err);
}
};
log("Local video & audio");
try {
// get a local stream, show it in a self-view and add it to be sent
const stream = await navigator.mediaDevices.getUserMedia(constraints);
selfView.srcObject = stream;
audioSendTrack = stream.getAudioTracks()[0];
if (started) {
log("Started = True => audio");
log(audio)
await audio.sender.replaceTrack(audioSendTrack);
}
videoSendTrack = stream.getVideoTracks()[0];
if (started) {
log("Started = True => video");
log(video)
await video.sender.replaceTrack(videoSendTrack);
}
} catch (err) {
console.log(err);
log("Error in local video & audio: " + err);
}
log("Warmup completed");
}
function initiateCall(user) {
log("Start van video verzoek");
// Verander UI
//document.getElementById("main").style.display = "none";
//document.getElementById("call").style.display = "block";
log("Voor gebruiker: " + user);
voor = user;
log("Van gebruiker: " + document.getElementById("user").innerHTML);
van = document.getElementById("user").innerHTML;
started = true;
//offer(JSON.stringify({start: true}));
jQuery.post(
"offer", {
to: user,
from: document.getElementById("user").innerHTML,
start: true
},
function() { console.log("Offer sent!"); }
).error("initiateCall",error);
}
function endCall() {
log("Ending call");
document.getElementById("call").style.display = "none";
document.getElementById("main").style.display = "block";
document.getElementById("localvideo").mozSrcObject.stop();
document.getElementById("localvideo").mozSrcObject = null;
document.getElementById("remotevideo").mozSrcObject = null;
peerc.close();
peerc = null;
}
function error(from,e) {
if (typeof e == typeof {}) {
//alert("Oh no! " + JSON.stringify(e));
log("Oh no! " + from + " ERROR: " + JSON.stringify(e));
} else {
alert("Oh no!!!! " + from + " ERROR: " + e);
}
//endCall();
}
var users = [];
users.push(document.getElementById("user").innerHTML);
Please note that I combined examples for:
developer.mozilla.org
w3c.github.io
www.html5rocks.com
So there might be unnecessary code
If required, I can put all code in repository and share that for full view.
Additional logging shows the following errors:
DOMException: "Cannot add ICE candidate when there is no remote SDP"
InvalidModificationError: Cannot set local offer when createOffer has not been called.

You should try to use a TURN-Server. Even for usage in development. The traffic will be relayed if a direct P2P-connection can't be stablished.
Have a look at Coturn.
I can't say that this will be the solution for the current problem, but in my opinion most of the issues will be solved - and for production use, you will need it definitely.

I found the problem and solution.
First:
The STUN/TURN server was not a problem, this
urls: 'stun:stun.l.google.com:19302'
Is enough for local network development.
But I did install turnserver (ubuntu 18) which seems fine.
Second:
My problem was first in de message exchange, you need to make sure the OFFER/ANSWER go to right clients.
Last:
The negotiation needs to be stable before sending/receiving media.
I modified my code that connection and start video sending are separated.
Also this allows for just one side to send media or not.

Related

Opentok chat is running slowly according I execute session.disconnect() and session.connect()

I am new to the Opentok API and I am writing tests. In my tests I simulated disconnecting from the room and connecting again, but if I execute it at various times, the chat is runs slowly, until broken.
To init the chat I run $scope.initSession() and to disconnect I run $scope.disconnectFromSession().
I am using the Opentok.js version 2.13.2. See my following code:
var apiKey, sessionId, token;
apiKey = //my api key;
sessionId = //my sessionid;
token = //my token;
var session = null;
var publisher = null;
var stream = null;
var connectionCount = 0;
var publisherProperties = {frameRate: 7};
$scope.connected = false;
$scope.initSession = function() {
if (OT.checkSystemRequirements() == 1) {
// Initialize Session Object
session = OT.initSession(apiKey, sessionId);
createElement("publisher");
// initialize a publisher
publisher = OT.initPublisher('publisher', publisherProperties);
session.on({
streamCreated: function(event) {
console.log("EVENT streamCreated: " + event.stream.name + " - " + event.reason);
createElement("subscriber");
stream = event.stream;
session.subscribe(stream, 'subscriber');
},
streamDestroyed: function(event) {
event.preventDefault();
console.log("EVENT streamDestroyed: " + event.stream.name + " - " + event.reason);
console.log('Stream ${event.stream.name} ended because ${event.reason}.');
}
});
connectToSession();
} else {
console.log('Browser havenĀ“t support to WebRTC');
}
}
function connectToSession() {
session.connect(token, function(err) {
if (err) {
if (err.name === "OT_NOT_CONNECTED") {
showMessage('Failed to connect. Please check your connection and try connecting again.');
} else {
showMessage('An unknown error occurred connecting. Please try again later.');
}
} else {
// publish to the session
session.publish(publisher);
$scope.connected = true;
}
});
}
function createElement(id) {
console.log(document.getElementById(id));
if (document.getElementById(id) === null) {
var divPublisher = document.createElement("div");
divPublisher.setAttribute("id", id);
document.getElementById("div-videos").appendChild(divPublisher);
}
}
$scope.disconnectFromSession = function() {
session.disconnect();
$scope.connected = false;
OT.off();
}
$scope.initSession();
I appreciate any help.

Need Help Making Java Script Discord Music Bot

I have tried to use this code to make a discord music bot but i am getting error telling me i need ffmpeg, but how would I implement it into this code?
index.js file
const Discord = require('discord.js');
const bot = new Discord.Client();
const config = require("./config.json");
const ytdl = require('ytdl-core');
var youtube = require('./youtube.js');
var ytAudioQueue = [];
var dispatcher = null;
bot.on('message', function(message) {
var messageParts = message.content.split(' ');
var command = messageParts[0].toLowerCase();
var parameters = messageParts.splice(1, messageParts.length);
switch (command) {
case "-join" :
message.reply("Attempting to join channel " + parameters[0]);
JoinCommand(parameters[0], message);
break;
case "-play" :
PlayCommand(parameters.join(" "), message);
break;
case "-playqueue":
PlayQueueCommand(message);
break;
}
});
function PlayCommand(searchTerm) {
if(bot.voiceConnections.array().length == 0) {
var defaultVoiceChannel = bot.channels.find(val => val.type === 'voice').name;
JoinCommand(defaultVoiceChannel);
}
youtube.search(searchTerm, QueueYtAudioStream);
}
function PlayQueueCommand(message) {
var queueString = "";
for(var x = 0; x < ytAudioQueue.length; x++) {
queueString += ytAudioQueue[x].videoName + ", ";
}
queueString = queueString.substring(0, queueString.length - 2);
message.reply(queueString);
}
function JoinCommand(ChannelName) {
var voiceChannel = GetChannelByName(ChannelName);
if (voiceChannel) {
voiceChannel.join();
console.log("Joined " + voiceChannel.name);
}
return voiceChannel;
}
/* Helper Methods */
function GetChannelByName(name) {
var channel = bot.channels.find(val => val.name === name);
return channel;
}
function QueueYtAudioStream(videoId, videoName) {
var streamUrl = youtube.watchVideoUrl + videoId;
if (!ytAudioQueue.length) {
ytAudioQueue.push(
{
'streamUrl' : streamUrl,
'videoName' : videoName
}
);
console.log('Queued audio ' + videoName);
PlayStream(ytAudioQueue[0].streamUrl);
}
else {
ytAudioQueue.push(
{
'streamUrl' : streamUrl,
'videoName' : videoName
}
);
}
console.log("Queued audio " + videoName);
}
function PlayStream(streamUrl) {
const streamOptions = {seek: 0, volume: 1};
if (streamUrl) {
const stream = ytdl(streamUrl, {filter: 'audioonly'});
if (dispatcher == null) {
var voiceConnection = bot.voiceConnections.first();
if(voiceConnection) {
console.log("Now Playing " + ytAudioQueue[0].videoname);
dispatcher = bot.voiceConnections.first().playStream(stream, streamOptions);
dispatcher.on('end', () => {
dispatcher = null;
PlayNextStreamInQueue();
});
dispatcher.on('error', (err) => {
console.log(err);
});
}
} else {
dispatcher = bot.voiceConnections.first().playStream(stream, streamOptions);
}
}
}
function PlayNextStreamInQueue() {
ytAudioQueue.splice(0, 1);
if (ytAudioQueue.length != 0) {
console.log("now Playing " + ytAudioQueue[0].videoName);
PlayStream(ytAudioQueue[0].streamUrl);
}
}
bot.login(config.token);
youtube.js file
var request = require('superagent');
const API_KEY = "My API KEY";
const WATCH_VIDEO_URL = "https://www.youtube.com/watch?v=";
exports.watchVideoUrl = WATCH_VIDEO_URL;
exports.search = function search(searchKeywords, callback) {
var requestUrl = 'https://www.googleapis.com/youtube/v3/search' + '?part=snippet&q=' + escape(searchKeywords) + '&key=' + API_KEY;
request(requestUrl, (error, response) => {
if (!error && response.statusCode == 200) {
var body = response.body;
if (body.items.length == 0) {
console.log("I Could Not Find Anything!");
return;
}
for (var item of body.items) {
if (item.id.kind == 'youtube#video') {
callback(item.id.videoId, item.snippet.title);
return;
}
}
} else {
console.log("Unexpected error!");
return;
}
});
return;
};
Error I am getting when I try to run code :
Joined General
C:\Discord Bot\node_modules\discord.js\src\client\voice\pcm\FfmpegConverterEngine.
js:80
throw new Error(
^
Error: FFMPEG was not found on your system, so audio cannot be played. Please make
sure FFMPEG is installed and in your PATH.
You need to download/extract FFMPEG and make it as your PATH/System variable[environment variable]
Make sure that you have it as your System variable like this :
The System Variable should named as 'FFMPEG' and should be directed to where the execution(.exe) file is. It should be in a folder called 'bin' in your FFMPEG folder.
You can google/search online on how to add a new System/PATH variable for your specific OS.

WebRTC Between two pages in the same machine

I'm trying to implement a mechanism to send textual data (JSON for instance) in from page to page, using javascript at the same machine.
I found some code and wrapped it but it only works at the same page.
At the moment I don't want to use a WwebRTC framework, only adapter.js.
//Must include adapter.js before
var WebRTCManager = (function () {
'use strict';
//Ctor
function WebRTCManagerFn() {
console.log('WebRTCManagerFn ctor reached');
this._events = {};
this._localConnection = null
this._remoteConnection = null;
this._sendChannel = null;
this._receiveChannel = null;
}
WebRTCManagerFn.prototype.addEventListener = function (name, handler) {
if (this._events.hasOwnProperty(name))
this._events[name].push(handler);
else
this._events[name] = [handler];
};
WebRTCManagerFn.prototype._fireEvent = function (name, event) {
if (!this._events.hasOwnProperty(name))
return;
if (!event)
event = {};
var listeners = this._events[name], l = listeners.length;
for (var i = 0; i < l; i++) {
listeners[i].call(null, event);
}
};
WebRTCManagerFn.prototype.createConnection = function () {
var servers = null;
var pcConstraint = null;
var dataConstraint = null;
console.log('Using SCTP based data channels');
// SCTP is supported from Chrome 31 and is supported in FF.
// No need to pass DTLS constraint as it is on by default in Chrome 31.
// For SCTP, reliable and ordered is true by default.
// Add localConnection to global scope to make it visible
// from the browser console.
window.localConnection = this._localConnection =
new RTCPeerConnection(servers, pcConstraint);
console.log('Created local peer connection object localConnection');
this._sendChannel = this._localConnection.createDataChannel('sendDataChannel',
dataConstraint);
console.log('Created send data channel');
this._localConnection.onicecandidate = this._localIceCallback.bind(this);
this._sendChannel.onopen = this._onSendChannelStateChange.bind(this);
this._sendChannel.onclose = this._onSendChannelStateChange.bind(this);
// Add remoteConnection to global scope to make it visible
// from the browser console.
window.remoteConnection = this._remoteConnection =
new RTCPeerConnection(servers, pcConstraint);
console.log('Created remote peer connection object remoteConnection');
this._remoteConnection.onicecandidate = this._remoteIceCallback.bind(this);
this._remoteConnection.ondatachannel = this._receiveChannelCallback.bind(this);
this._localConnection.createOffer(this._gotOfferFromLocalConnection.bind(this), this._onCreateSessionDescriptionError.bind(this));
}
WebRTCManagerFn.prototype._onCreateSessionDescriptionError = function (error) {
console.log('Failed to create session description: ' + error.toString());
}
WebRTCManagerFn.prototype.sendMessage = function (msgText) {
var msg = new Message(msgText);
// Send the msg object as a JSON-formatted string.
var data = JSON.stringify(msg);
this._sendChannel.send(data);
console.log('Sent Data: ' + data);
}
WebRTCManagerFn.prototype.closeDataChannels = function () {
console.log('Closing data channels');
this._sendChannel.close();
console.log('Closed data channel with label: ' + this._sendChannel.label);
this._receiveChannel.close();
console.log('Closed data channel with label: ' + this._receiveChannel.label);
this._localConnection.close();
this._remoteConnection.close();
this._localConnection = null;
this._remoteConnection = null;
console.log('Closed peer connections');
}
WebRTCManagerFn.prototype._gotOfferFromLocalConnection = function (desc) {
console.log('reached _gotOfferFromLocalConnection');
if (this && this._localConnection != 'undefined' && this._remoteConnection != 'undefined') {
this._localConnection.setLocalDescription(desc);
console.log('Offer from localConnection \n' + desc.sdp);
this._remoteConnection.setRemoteDescription(desc);
this._remoteConnection.createAnswer(this._gotAnswerFromRemoteConnection.bind(this),
this._onCreateSessionDescriptionError.bind(this));
}
}
WebRTCManagerFn.prototype._gotAnswerFromRemoteConnection = function (desc) {
console.log('reached _gotAnswerFromRemoteConnection');
if (this && this._localConnection != 'undefined' && this._remoteConnection != 'undefined') {
this._remoteConnection.setLocalDescription(desc);
console.log('Answer from remoteConnection \n' + desc.sdp);
this._localConnection.setRemoteDescription(desc);
}
}
WebRTCManagerFn.prototype._localIceCallback = function (event) {
console.log('local ice callback');
if (event.candidate) {
this._remoteConnection.addIceCandidate(event.candidate,
this._onAddIceCandidateSuccess.bind(this), this._onAddIceCandidateError.bind(this));
console.log('Local ICE candidate: \n' + event.candidate.candidate);
}
}
WebRTCManagerFn.prototype._remoteIceCallback = function (event) {
console.log('remote ice callback');
if (event.candidate) {
this._localConnection.addIceCandidate(event.candidate,
this._onAddIceCandidateSuccess.bind(this), this._onAddIceCandidateError.bind(this));
console.log('Remote ICE candidate: \n ' + event.candidate.candidate);
}
}
WebRTCManagerFn.prototype._onAddIceCandidateSuccess = function (evt) {
debugger;
console.log('AddIceCandidate success. evt: '+ evt);
}
WebRTCManagerFn.prototype._onAddIceCandidateError = function (error) {
console.log('Failed to add Ice Candidate: ' + error.toString());
}
WebRTCManagerFn.prototype._receiveChannelCallback = function (event) {
console.log('Receive Channel Callback');
this._receiveChannel = event.channel;
this._receiveChannel.onmessage = this._onReceiveMessageCallback.bind(this);
this._receiveChannel.onopen = this._onReceiveChannelStateChange.bind(this);
this._receiveChannel.onclose = this._onReceiveChannelStateChange.bind(this);
}
WebRTCManagerFn.prototype._onReceiveMessageCallback = function (event) {
console.log('Received Message: ' + event.data);
console.log('Received Message this is: ' + this);
var msgObj = JSON.parse(event.data);
this._fireEvent("messageRecieved", {
details: {
msg: msgObj
}
});
}
WebRTCManagerFn.prototype._onSendChannelStateChange = function () {
console.log('_onSendChannelStateChange');
var readyState = this._sendChannel.readyState;
console.log('Send channel state is: ' + readyState);
}
WebRTCManagerFn.prototype._onReceiveChannelStateChange = function () {
var readyState = this._receiveChannel.readyState;
console.log('Receive channel state is: ' + readyState);
}
return WebRTCManagerFn;
})();
My question is how to pass data between two pages on the same machine using WebRTC?
This WebRTC tab chat demo works across tabs or windows in the same browser without a server: https://jsfiddle.net/f5y48hcd/ (I gave up making it work in a code snippet due to a SecurityError.)
Open the fiddle in two windows and try it out. For reference, here's the WebRTC code:
var pc = new RTCPeerConnection(), dc, enterPressed = e => e.keyCode == 13;
var connect = () => init(dc = pc.createDataChannel("chat"));
pc.ondatachannel = e => init(dc = e.channel);
var init = dc => {
dc.onopen = e => (dc.send("Hi!"), chat.select());
dc.onclose = e => log("Bye!");
dc.onmessage = e => log(e.data);
};
chat.onkeypress = e => {
if (!enterPressed(e)) return;
dc.send(chat.value);
log("> " + chat.value);
chat.value = "";
};
var sc = new localSocket(), send = obj => sc.send(JSON.stringify(obj));
var incoming = msg => msg.sdp &&
pc.setRemoteDescription(new RTCSessionDescription(msg.sdp))
.then(() => pc.signalingState == "stable" || pc.createAnswer()
.then(answer => pc.setLocalDescription(answer))
.then(() => send({ sdp: pc.localDescription })))
.catch(log) || msg.candidate &&
pc.addIceCandidate(new RTCIceCandidate(msg.candidate)).catch(log);
sc.onmessage = e => incoming(JSON.parse(e.data));
pc.oniceconnectionstatechange = e => log(pc.iceConnectionState);
pc.onicecandidate = e => send({ candidate: e.candidate });
pc.onnegotiationneeded = e => pc.createOffer()
.then(offer => pc.setLocalDescription(offer))
.then(() => send({ sdp: pc.localDescription }))
.catch(log);
var log = msg => div.innerHTML += "<br>" + msg;
I use this for demoing WebRTC data channels. Note that the secret sauce is the localSocket.js that I wrote for this, which looks like this:
function localSocket() {
localStorage.a = localStorage.b = JSON.stringify([]);
this.index = 0;
this.interval = setInterval(() => {
if (!this.in) {
if (!JSON.parse(localStorage.a).length) return;
this.in = "a"; this.out = "b";
}
var arr = JSON.parse(localStorage[this.in]);
if (arr.length <= this.index) return;
if (this.onmessage) this.onmessage({ data: arr[this.index] });
this.index++;
}, 200);
setTimeout(() => this.onopen && this.onopen({}));
}
localSocket.prototype = {
send: function(msg) {
if (!this.out) {
this.out = "a"; this.in = "b";
}
var arr = JSON.parse(localStorage[this.out]);
arr.push(msg);
localStorage[this.out] = JSON.stringify(arr);
},
close: function() {
clearInterval(this.interval);
}
};
It basically uses localStorage to simulate web sockets locally between two tabs. If this is all you want to do, then you don't even need WebRTC data channels.
Disclaimer: It's not very robust, and relies on two pages being ready to communicate, so not production-ready by any means.

Use TripleSec encryption with Node.js Socket.io Chat

I am new to Node.js and I've created a simple chat application using Socket.io. I am trying to encrypt the messages using the triplesec library but I am having some issues. What would be the best approach to add this encryption/decryption:
var triplesec = require('triplesec');
// Encrypt Function
triplesec.encrypt({
key: new triplesec.Buffer('secretkey'),
data: new triplesec.Buffer('secretthings'),
}, function (err, buff) {
if(!err) {
var ciphertext = buff.toString('hex')
console.log(buff.toString('hex'))
}
// Decrypt Function
triplesec.decrypt({
data: new triplesec.Buffer(ciphertext, "hex"),
key: new triplesec.Buffer('secretkey')
}, function (err, buff) {
if(!err) {
console.log(buff.toString());
}
});
});
To this client: (All encryption on the messages coming in and going out will be handled client side, assuming this is the best approach?)
// imports
var readline = require('readline');
var socketio = require('socket.io-client');
var util = require('util');
var clc = require("cli-color");
var async = require("async");
// globals
var nick;
var serverAddress;
var serverPort;
var socket;
var rl = readline.createInterface(process.stdin, process.stdout);
// message types
var chat = clc.green;
var pm = clc.yellow;
var notice = clc.cyan;
var emote = clc.blue;
var error = clc.red;
// function definitions
function consoleOut (msg) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
console.log(msg);
rl.prompt(true);
}
// handle a command that the user has entered
function handleCommand (commandType, arg) {
switch (commandType) {
case 'nick': // set the nickname and send a message with the updated nickname
var notice = nick + " changed their name to " + arg;
nick = arg;
socket.emit('send', { type: 'notice', message: notice });
break;
case 'pm': // private message another user
var to = arg.match(/[a-z]+\b/)[0];
var message = arg.substr(to.length, arg.length);
socket.emit('send', { type: 'pm', message: message, to: to, from: nick });
break;
case 'me': // the user performs some emote
var emote = nick + " " + arg;
socket.emit('send', { type: 'emote', message: emote });
break;
default: // invalid command type
consoleOut(error("That is not a valid command."));
}
}
// start of execution
async.series([
function(callback) {
// get the address
rl.question("Please enter the address of the server, such as 192.168.0.10: ", function(address) {
serverAddress = address;
callback();
});
},
function(callback) {
// get the port
rl.question("Please enter the port the server is listening on, such as 8080: ", function(port) {
serverPort = port;
socket = socketio.connect('http://' + serverAddress + ':' + serverPort);
// register the sockets on message event handler
socket.on('message', function (data) {
var leader;
// process message, these are pretty self explainitory
if (data.type == 'chat' && data.nick != nick) {
leader = chat("<" + data.nick + "> ");
consoleOut(leader + data.message);
}
else if (data.type == "notice") {
consoleOut(notice(data.message));
}
else if (data.type == "pm" && data.to == nick) {
leader = pm("["+data.from+"->"+data.to+"]");
consoleOut(leader + data.message);
}
else if (data.type == "emote") {
consoleOut(emote(data.message));
}
});
callback();
});
},
function(callback) {
// get the users nickname
rl.question("Please enter a nickname: ", function(name) {
nick = name;
var msg = nick + " has joined the chat";
socket.emit('send', { type: 'notice', message: msg });
rl.prompt(true);
callback();
});
}
]);
// called when the user hits enter on the command line
// parses what ever they typed into either a command or a chat message
rl.on('line', function (line) {
if (line[0] == "/" && line.length > 1) {
var cmd = line.match(/[a-z]+\b/)[0];
var arg = line.substr(cmd.length+2, line.length);
handleCommand(cmd, arg);
rl.prompt(true);
} else {
// send chat message
socket.emit('send', { type: 'chat', message: line, nick: nick });
rl.prompt(true);
}
});

bulkTransfer "Transfer failed."

I'm not getting any kind of transfer to happen between my chrome app and a simple device just waiting for data to come in on its uart rx line. The device's interface's endpoint's type is bulk, although I've tried every transfer type available (control, bulk, isochronous, and interrupt). Examples from here. I've also tried claiming the device, but that does not seem to be applicable if using findDevices and fails as well.
I'm assuming that by finding the device, I know that it has been discovered, permissions are OK and that it has been opened OK.
I'm using a UART-to-USB adapter on a mac. I've spoken to the same hardware setup using pysusb and a python script, so I know it can be done.
var DEVICE_INFO = {"vendorId": 1027, "productId": 24577};
var searchForUsbDevice = function() {
chrome.usb.findDevices(DEVICE_INFO, onDeviceFound);
}
var onDeviceFound = function(devices) {
if (devices) {
if (0 < devices.length) {
if (1 === devices.length) {
device_ = devices[0];
console.log("Device found. And opened?");
getInterfaces();
getConfiguration();
//claimDevice();
investigateDevice();
} else {
console.log("Ensure one and ONLY ONE device is plugged in.");
}
} else {
console.log("Device could not be found");
setTimeout(searchForUsbDevice, 1000);
}
} else {
console.log("Permission denied.");
}
};
var investigateDevice = function() {
testBulkTransfer();
//testIsochronousTransfer();
//testInterruptTransfer();
//testControlTransfer();
setTimeout(investigateDevice, 1000);
};
var testBulkTransfer = function() {
var transferInfo = {
"direction": "out",
"endpoint": 1,
"data": new Uint8Array([32, 2, 1, 2]).buffer
};
chrome.usb.bulkTransfer(device_, transferInfo, function(info) {
if (chrome.runtime.lastError) {
console.log("info: " + JSON.stringify(info));
console.log("runtime error: " + JSON.stringify(chrome.runtime.lastError.message));
return;
}
console.log("transfer result: " + ((0 === info.resultCode) ? "succeeded" : "failed"));
});
};
var getConfiguration = function() {
chrome.usb.getConfiguration(device_, function(config) {
if (chrome.runtime.lastError) {
console.log("runtime error: " + JSON.stringify(chrome.runtime.lastError.message));
return;
}
console.log("config: ");
console.log(config);
});
};
var getInterfaces = function() {
chrome.usb.listInterfaces(device_, function(descriptors) {
if (chrome.runtime.lastError) {
console.log("runtime error: " + JSON.stringify(chrome.runtime.lastError.message));
return;
}
console.log("descriptors: ");
console.log(descriptors);
});
};
The appropriate API for that UART-to-USB adapter is chrome.serial, NOT chrome.usb.
https://developer.chrome.com/apps/app_serial

Categories

Resources