Videoconferencing with webrtc + node.js - node.js

first sorry for my bad english.
I'm trying to make a video call with WebRTC but it doesn't work.
I'm using node.js+socket.io+express for the server.
I appreciate any help or suggestions you can give me.
Thank you very much.
This is my code.
SERVER
var express = require('express')
, io = require('socket.io')
, app = express()
, server = require('http').createServer(app)
, io = io.listen(server);
server.listen(8080);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
var usuarios = [];
io.sockets.on('connection', function (socket) {
usuarios.push(socket);
console.log('Nuevo usuario conectado - ' + usuarios.length + ' en total');
socket.on('message', function (mensaje) {
usuarios.forEach(function (usuario) {
if (usuario != socket) {
usuario.send(mensaje);
}
});
});
socket.on('disconnect', function () {
console.log("Usuario desconectado");
// ...
});
});
CLIENT
<html>
<head>
<title>Cliente</title>
</head>
<body>
<video id='videolocal' autoplay style='width: 200px; height: 150px; border: 1px solid black;'></video>
<video id='videoremoto' autoplay style='width: 200px; height: 150px; border: 1px solid black;'></video>
<button type="button" onclick="iniciarCamara();">Iniciar Camara</button>
<button type="button" onclick="pararCamara();">Parar Camara</button>
<button type="button" onclick="conectar();">Conectar</button>
<button type="button" onclick="desconectar();">Desconectar</button>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
var videolocal = document.getElementById('videolocal');
var videoremoto = document.getElementById('videoremoto');
var streamlocal = null;
var pc = null;
var conectado = false;
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
socket.on('message', function (mensaje) {
var msg = JSON.parse(mensaje);
if (msg.type === 'oferta') {
pc.setRemoteDescription(pc.SDP_OFFER, new SessionDescription(msg.sdp));
responder();
} else if (msg.type === 'respuesta' && conectado) {
pc.setRemoteDescription(pc.SDP_ANSWER, new SessionDescription(msg.sdp));
} else if (msg.type === 'candidate' && conectado) {
var candidate = new IceCandidate(msg.label, msg.candidate);
pc.processIceMessage(candidate);
} else if (msg.type === 'desconectar' && conectado) {
//...
}
});
function responder() {
var oferta = pc.remoteDescription;
var respuesta = pc.createAnswer(oferta.toSdp(), {has_audio:true, has_video:true});
pc.setLocalDescription(pc.SDP_ANSWER, respuesta);
socket.send({type: 'respuesta', sdp: respuesta.toSdp()});
pc.startIce();
}
function crearPeerConnection() {
pc = new webkitPeerConnection00(null, iceCallback);
pc.addEventListener("addstream", anadirStreamRemoto, false);
pc.addEventListener("removestream", eliminarStreamRemoto, false);
function anadirStreamRemoto(event) {
videoremoto.src = window.webkitURL.createObjectURL(event.stream);
}
function eliminarStreamRemoto(event) {
videoremoto.src = "";
}
}
function iniciarCamara() {
navigator.getUserMedia({video: true, audio: true}, okCallback, errorCallback);
function okCallback(stream) {
videolocal.src = window.URL.createObjectURL(stream);
streamlocal = stream;
}
function errorCallback(error) {
alert("Error");
return;
}
}
function pararCamara() {
videolocal.src = "";
}
function iceCallback(candidate, bMore) {
if(candidate) {
socket.send({type: 'candidate', label: candidate.label, candidate: candidate.toSdp()});
}
}
function conectar() {
if (!conectado && streamlocal) {
crearPeerConnection();
conectado = true;
var oferta = pc.createOffer({has_audio:true, has_video:true});
pc.setLocalDescription(pc.SDP_OFFER, oferta);
socket.send({type: 'oferta', sdp: oferta.toSdp()});
pc.startIce();
} else {
alert("No se ha iniciado el stream local");
}
}
function desconectar() {
pc.close();
pc = null;
conectado = false;
}
</script>
</body>
ERROR
Uncaught SyntaxError: Unexpected token o localhost:25
(anonymous function) localhost:25
EventEmitter.emit socket.io.js:633
SocketNamespace.onPacket socket.io.js:2239
Socket.onPacket socket.io.js:1930
Transport.onPacket socket.io.js:1332
Transport.onData socket.io.js:1303
websocket.onmessage
Regards.

You have to send jsObjects while the socket.io method .send() sends messages, to serve data you need to use .emit() method, so you have to replace all
socket.send({...});
with:
socket.emit('message', {...})
and so you have to remove this line:
var msg = JSON.parse(mensaje);

Related

Restarting Continuous Recognition doesn't listen to microphone

I'm using IntentRecognizer and SpeechSynthesizer from Microsoft Cognitive Speech SDK in a elctron app where I'm using stopContinuousRecognitionAsync while SpeechSynthesis is running and after the systhesis stops, I'm starting the recognition again with startContinuousRecognitionAsync.
The function runs properly with callback but doesn't listen to anything I say anymore and keeps firing SpeechSDK.ResultReason.NoMatch. Here's my code:
const SpeechSDK = require("microsoft-cognitiveservices-speech-sdk");
const speechConfig = SpeechSDK.SpeechConfig.fromSubscription(LUIS_API_KEY, COGNITIVE_SERVICE_REGION);
class CognitiveSpeech {
constructor() {
speechConfig.speechRecognitionLanguage = "en-US"; //put language from settings later
var lm = SpeechSDK.LanguageUnderstandingModel.fromAppId(remote.process.env.LUIS_APP_ID);
var audioConfig = SpeechSDK.AudioConfig.fromDefaultMicrophoneInput();
recognizer = new SpeechSDK.IntentRecognizer(speechConfig, audioConfig);
recognizer.addAllIntents(lm);
recognizer.recognizing = (s, e) => {
console.log(`RECOGNIZING: Text=${e.result.text}`, e);
};
recognizer.recognized = (s, e) => {
console.log("(continuation) Reason: " + SpeechSDK.ResultReason[e.result.reason]);
switch (e.result.reason) {
case SpeechSDK.ResultReason.RecognizedSpeech:
console.log(" Text: " + e.result.text);
break;
case SpeechSDK.ResultReason.RecognizedIntent:
console.log(" Text: " + e.result.text + " IntentId: " + e.result.intentId);
///
DO WORK
this.synthesizeSpeech('Sure thing');
///
break;
case SpeechSDK.ResultReason.NoMatch:
var noMatchDetail = SpeechSDK.NoMatchDetails.fromResult(e.result);
if(SpeechSDK.NoMatchReason[noMatchDetail.reason] != 'InitialSilenceTimeout')
console.log(" NoMatchReason: " + SpeechSDK.NoMatchReason[noMatchDetail.reason]);
break;
case SpeechSDK.ResultReason.Canceled:
var cancelDetails = SpeechSDK.CancellationDetails.fromResult(e.result);
console.log(" CancellationReason: " + SpeechSDK.CancellationReason[cancelDetails.reason]);
if (cancelDetails.reason === SpeechSDK.CancellationReason.Error) {
console.log(": " + cancelDetails.errorDetails);
}
break;
}
};
recognizer.canceled = (s, e) => {
console.log(`CANCELED: Reason=${e.reason}`);
if (e.reason == CancellationReason.Error) {
console.log(`"CANCELED: ErrorCode=${e.errorCode}`);
console.log(`"CANCELED: ErrorDetails=${e.errorDetails}`);
console.log("CANCELED: Did you update the subscription info?");
}
recognizer.stopContinuousRecognitionAsync();
};
recognizer.sessionStopped = (s, e) => {
console.log("Session stopped event.");
recognizer.stopContinuousRecognitionAsync();
};
}
startRecognition() {
recognizer.startContinuousRecognitionAsync(()=>{
console.log('Listenning...');
}, err => {
console.log(err);
});
}
stopRecognition() {
recognizer.stopContinuousRecognitionAsync(()=>{
console.log('Stopped Speech Recognition');
}, err => {
console.log(err);
});
}
synthesizeSpeech(string) {
this.stopRecognition();
const speechSynthesisConfig = SpeechSDK.SpeechConfig.fromSubscription(COGNITIVE_API_KEY, COGNITIVE_SERVICE_REGION);
const audioSynthesisConfig = SpeechSDK.AudioConfig.fromDefaultSpeakerOutput();
const synthesizer = new SpeechSDK.SpeechSynthesizer(speechSynthesisConfig, audioSynthesisConfig);
synthesizer.speakSsmlAsync(
'<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="en-US">\
<voice name="en-US-AriaRUS">\
<mstts:express-as style="chat">'
+string+
'</mstts:express-as>\
</voice>\
</speak>', //put voice from settings letter
result => {
if (result) {
if (result.errorDetails) {
console.error(result.errorDetails);
} else {
console.log(JSON.stringify(result));
}
this.startRecognition();
synthesizer.close();
}
},
error => {
console.log(error);
synthesizer.close();
});
}
}
can anybody help me with what's wrong in this picture?
The issue may be that you're not getting the callbacks you expect in the order you expect. I was able to get the following working:
<html>
<head>
<title>Microsoft Cognitive Services Speech SDK JavaScript Quickstart</title>
<meta charset="utf-8" />
</head>
<body style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; font-size:13px;">
<!-- <uidiv> -->
<div id="content">
<table width="100%">
<tr>
<td></td>
<td><h1 style="font-weight:500;">Microsoft Cognitive Services Speech SDK JavaScript Quickstart</h1></td>
</tr>
<tr>
<td></td>
<td><button id="startRecognitionBtn">Start recognition</button></td>
</tr>
<tr>
<td></td>
<td><button id="stopRecognitionBtn">Stop recognition</button></td>
</tr>
<tr>
<td align="right" valign="top">Results</td>
<td><textarea id="phraseDiv" style="display: inline-block;width:500px;height:200px"></textarea></td>
</tr>
</table>
</div>
<!-- </uidiv> -->
<!-- <speechsdkref> -->
<!-- Speech SDK reference sdk. -->
<script src="https://aka.ms/csspeech/jsbrowserpackageraw"></script>
<!-- </speechsdkref> -->
<!-- <quickstartcode> -->
<!-- Speech SDK USAGE -->
<script>
// status fields and start button in UI
var phraseDiv;
var startRecognitionBtn, stopRecognitionBtn;
var SpeechSDK;
var speechConfig;
var recognizer, synthesizer;
var textToSpeak;
document.addEventListener("DOMContentLoaded", function () {
startRecognitionBtn = document.getElementById("startRecognitionBtn");
stopRecognitionBtn = document.getElementById("stopRecognitionBtn");
phraseDiv = document.getElementById("phraseDiv");
const getSpeechConfig = () => {
if (!speechConfig) {
speechConfig = new SpeechSDK.SpeechConfig.fromSubscription("KEY", "REGION");
speechConfig.speechRecognitionLanguage = "en-US";
}
return speechConfig;
};
stopRecognitionBtn.addEventListener("click", function () {
startRecognitionBtn.disabled = false;
if(!!recognizer) {
recognizer.stopContinuousRecognitionAsync(
() => {
},
function (err) {
startRecognitionBtn.disabled = false;
stopRecognitionBtn.disabled = false;
phraseDiv.innerHTML += err;
window.console.log(err);
recognizer.close();
recognizer = undefined;
});
}
});
startRecognitionBtn.addEventListener("click", function () {
startRecognitionBtn.disabled = true;
stopRecognitionBtn.disabled = false;
phraseDiv.innerHTML = "";
var sc = getSpeechConfig();
var lm = SpeechSDK.LanguageUnderstandingModel.fromAppId("APP_ID");
var audioConfig = SpeechSDK.AudioConfig.fromDefaultMicrophoneInput();
recognizer = new SpeechSDK.IntentRecognizer(sc, audioConfig);
recognizer.addAllIntents(lm);
recognizer.canceled = function (_, event) {
window.console.log(event);
if (event.reason === sdk.CancellationReason.Error) {
window.console.log(event.errorDetails);
}
};
recognizer.recognizing = (_, event) => {
console.log('(recognizing)', { text: event.result.text });
//textToSpeak = event.result.text;
textToSpeak = "Sure thing";
phraseDiv.innerHTML = event.result.text;
};
recognizer.recognized = (_, event) => {
console.log(`(recognized) Reason: ${sdk.ResultReason[event.result.reason]} Text: ${event.result.text}`);
startRecognitionBtn.disabled = false;
startRecognitionBtn.disabled = false;
phraseDiv.innerHTML = event.result.text;
};
recognizer.sessionStarted = (_, event) => {
console.log(`(sessionStarted) SessionId: ${event.sessionId}`);
textToSpeak = "";
};
recognizer.sessionStopped = (_, event) => {
console.log(`(sessionStopped) SessionId: ${event.sessionId}`);
startRecognitionBtn.disabled = false;
};
recognizer.speechStartDetected = (_, event) => {
console.log(`(speechStartDetected) SessionId: ${event.sessionId}`);
};
recognizer.speechEndDetected = (_, event) => {
console.log(`(speechEndDetected) SessionId: ${event.sessionId}`);
startRecognitionBtn.disabled = false;
recognizer.stopContinuousRecognitionAsync(
() => {},
function (err) {
startRecognitionBtn.disabled = false;
stopRecognitionBtn.disabled = false;
phraseDiv.innerHTML += err;
window.console.log(err);
recognizer.close();
recognizer = undefined;
});
startSynthesis();
};
startRecognition();
});
const startRecognition = () => {
recognizer?.startContinuousRecognitionAsync(
undefined,
function (err) {
startRecognitionBtn.disabled = false;
phraseDiv.innerHTML += err;
window.console.log(err);
recognizer.close();
recognizer = undefined;
});
};
const startSynthesis = () => {
if(!synthesizer) {
var sc2 = getSpeechConfig();
var player = new SpeechSDK.SpeakerAudioDestination();
player.onAudioEnd = function (_) {
window.console.log("playback finished");
phraseDiv.innerHTML += "playback finished" + "\r\n";
};
var audioOutConfig = SpeechSDK.AudioConfig.fromSpeakerOutput(player);
synthesizer = new SpeechSDK.SpeechSynthesizer(sc2, audioOutConfig);
}
phraseDiv.innerHTML += `detected spoken phrase: ${textToSpeak}\r\n`;
synthesizer.speakSsmlAsync(
`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="en-US">\
<voice name="en-US-AriaRUS">\
<mstts:express-as style="chat">${textToSpeak}</mstts:express-as>\
</voice>\
</speak>`, //put voice from settings letter,
(result) => {
if (result.reason === SpeechSDK.ResultReason.SynthesizingAudioCompleted) {
phraseDiv.innerHTML += "synthesis finished" + "\r\n";
} else if (result.reason === SpeechSDK.ResultReason.Canceled) {
phraseDiv.innerHTML += "synthesis failed. Error detail: " + result.errorDetails;
}
window.console.log(result);
closeSynth();
},
(err) => {
window.console.log(err);
closeSynth();
});
};
const closeSynth = () => {
synthesizer.close();
synthesizer = undefined;
};
if (!!window.SpeechSDK) {
SpeechSDK = window.SpeechSDK;
startRecognitionBtn.disabled = false;
}
});
</script>
<!-- </quickstartcode> -->
</body>
</html>

When new user connects the previous connection becomes the new user

I've been playing around a bit with NodeJS and recently socket.IO, I come from PHP development and try to understand really how to work with Node and socket.IO
I started building a chat app and when I were to test it on different devices I noticed that when I for instance log in to another account through my phone, the browser window updates and gets the same user as I logged into on my phone
index.html
<!DOCTYPE html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: 0.5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<div id="chatLogin">
<input type="text" name="password" id="username" placeholder="Username..." /><br>
<input type="password" name="password" id="password" placeholder="Password..." /><br>
<button id="chatLoginBtn">Login / Register</button>
</div>
<div id="chatWindow">
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
$(function () {
var socket = io();
$(document).ready(function(){
$("#chatWindow").hide();
$("#chatLoginBtn").click(function(){
socket.emit('loginForm', {
username: $("#username").val(),
password: $("#password").val()
});
});
});
socket.on('returnValue', function(msg) {
var html = '<ul id="messages"></ul>' +
'<form id="sendMsg" action="">' +
'<input id="m" autocomplete="off" /><button>Send</button>' +
'</form>';
$("#chatLogin").html("").hide();
$("#chatWindow").html(html).show();
$('#sendMsg').submit(function(e) {
e.preventDefault(); // prevents page reloading
var time = Date.now();
var msg = $("#m").val();
var data = [time, msg];
socket.emit('chat', data);
$('#m').val('');
return false;
});
});
socket.on('chat', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
</body>
</html>
index.js
var app = require('express')();
var http = require('http').createServer(app);
var phpPass = require('node-php-password');
var mysql = require('mysql');
var io = require('socket.io')(http);
var cookieParser = require('cookie-parser');
var session = require('express-session');
// DECLARE the variables we will be using
// These does not change
let userCount = 0;
// These are declared to be later set
var displayName;
var userDataID;
// POOL MySQL Connection
var pool = mysql.createPool({
connectionLimit : 100,
host : 'localhost',
user : 'root',
password : '....',
port : '3306',
database : '....',
debug : false
});
// session & cookieParser
/*var sessionMiddleware = session({
secret: "keyboard cat"
});
io.use(function (socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
app.use(sessionMiddleware);
app.use(cookieParser());*/
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
var hashPassword;
function checkUser(user, Password, userID) {
pool.getConnection(function(error,connection) {
connection.query("SELECT password FROM accounts WHERE `username` = '"+user+"' LIMIT 1",function(error,rows){
if (!error) {
var hashPassword = rows[0].password;
if (phpPass.verify(Password, hashPassword)) {
console.log(Password);
console.log(hashPassword);
console.log("Went well");
// UPDATE user database with current socketID
connection.query("UPDATE accounts SET `socketID` = '"+userID+"' WHERE `username` = '"+user+"'",function(error,result){
connection.release();
if (!error) {
connection.query("SELECT id,displayName,username,email,fullName,dateofBirth,created,lastSignedIn FROM accounts WHERE socketID = '"+userID+"' LIMIT 1",function(error,userData){
if (!error) {
displayName = userData[0].displayName;
userDataID = userData[0].id;
console.log("Current user: " + userData[0].displayName);
} else {
console.log("Error" + error);
}
});
console.log("No error" + result);
} else {
console.log("We found error" + error);
}
});
// send to function to gather all needed info from database and save for the current session
return true;
} else {
console.log("Wrong pass");
return false;
}
console.log(hashPassword);
} else {
console.log(error);
return false;
}
});
connection.on('error', function(error) {
});
});
return true;
};
io.on('connection', (socket) => {
var req = socket.request;
var userID = socket.id;
// When connection is inited
userCount++;
console.log('User connected' + userCount);
// Take the data from login and pass to check if it is valid
socket.on("loginForm", function(data){
const user = data.username,
pass = data.password;
//console.log(checkUser(user, pass));
if (checkUser(user, pass, userID)) {
io.emit('returnValue', 'hi');
}
});
function joinRoom(room) {
socket.join(room);
console.log("Joined " + room);
return io.emit('chat', "Joined new room " + room);
}
socket.on('join', (data) => {
socket.join(data);
console.log("Joined " + data);
});
socket.on('chat', (data) => {
/* Array: Data;
[0] Time
[1] Message
[2] socketID
[3] User
*/
var msg = data[1];
var time = data[0];
// Calc time
var date = new Date(time);
var hours = date.getHours();
var minutes = date.getMinutes();
var formatted = hours + ":" + minutes;
if (minutes < 10) return minutes = "0" + minutes;
var dateFormatted = "[" + formatted + "] ";
//data.push(user);
pool.getConnection(function(error,connection) {
connection.query("INSERT INTO `chat_messages` (userID, socketID, message, time) VALUES ('"+userDataID+"', '"+userID+"', '"+msg+"', '"+time+"')",function(error,rows){
connection.release();
if (!error) {
console.log("Success");
} else {
console.log(error);
}
});
});
if (msg.startsWith('/me')) return io.emit('chat', dateFormatted + displayName + msg.substring(3));
if (msg.startsWith('/join')) return joinRoom(msg.substring(6));
if (msg.startsWith('/rooms')) return console.log(io.sockets.adapter.rooms);
return io.emit('chat', dateFormatted + displayName + ' said: ' + msg);
//console.log(displayName + 'said:' + msg);
});
// When user disconnects
socket.on('disconnect', () => {
userCount--;
console.log('User disconnected!' + userCount);
});
});
http.listen(3000, () => {
console.log('Listening on *:3000');
});
I do not get any errors and it counts the number of users correctly
The problem is that the user first logged in gets switched to the last logged in user
How do I make the user session unique and so multiple clients can be logged in into different accounts?
I noticed an issue: var userDataID;
It's a global variable. Each time a new user log ing, the userDataID will be updated. It's always the ID of the newest logged user. Then, all new messages will be stored in the database with the userDataID.
EX:
- Log in by account A on window, the userDataID = 1;
- send some messages to server, these message will be stored with userID = 1
- Log in by account B on iphone, the userDataID will be updated, it's = 2 now.
- send some messages from windown & iphone. all these message will be stored with userID 2.
I think that's the error you got.
Should store userID in cookie or session.

webRTC datachannel is not working in chrome62

I am newbie to webRTC. I tried to create a Chat application, sending a simple text message.
But getting this error:
Uncaught DOMException: Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open'
at HTMLButtonElement.
Here is my code.
index.html
<div class = "row">
<div class = "col-md-4 col-md-offset-4">
<h2> Please sign in</h2>
<input type = "email" id = "usernameInput"
class = "form-control formgroup" placeholder = "Enter Name"
required = "" autofocus = "" title="please Enter name">
<button id = "loginBtn" class = "btn btn-lg btn-primary btnblock">
Sign in</button>
</div>
</div>
</div>
<div id = "callPage" class = "call-page container">
<div class = "row">
<div class = "col-md-4 col-md-offset-4 text-center">
<div class = "panel panel-primary">
<div class = "panel-heading">Text chat</div>
<div id = "chatarea" class = "panel-body text-left"></div>
</div>
</div>
</div>
<div class = "row text-center">
<div class = "col-md-12">
<input id = "msgInput" type = "text" placeholder = "Enter message" />
<button id = "sendMsgBtn" class = "btn-success btn">Send</button>
</div>
</div>
</div>
<script >
var name;
var connectedUser;
var conn = new WebSocket('ws://localhost:8000');
conn.onopen = function () {
console.log("Connected to the signaling server");
};
//when we got a message from a signaling server
conn.onmessage = function (msg) {
console.log("Got message", msg.data);
var data =JSON.parse( msg.data);
// console.log(data.type);
switch(data.type) {
case "login":
handleLogin(data.success);
break;
//when somebody wants to call us
case "offer":
handleOffer(data.offer, data.name);
break;
case "answer":
handleAnswer(data.answer);
break;
//when a remote peer sends an ice candidate to us
case "candidate":
handleCandidate(data.candidate);
console.log('candidate');
break;
case "leave":
handleLeave();
break;
default:
break;
}
};
conn.onerror = function (err) {
console.log("Got error", err);
};
//alias for sending JSON encoded messages
function send(message) {
//attach the other peer username to our messages
if (connectedUser) {
message.name = connectedUser;
}
conn.send(JSON.stringify(message));
};
var loginPage = document.querySelector('#loginPage');
var usernameInput = document.querySelector('#usernameInput');
var loginBtn = document.querySelector('#loginBtn');
var callPage = document.querySelector('#callPage');
var callToUsernameInput = document.querySelector('#callToUsernameInput');
// var callBtn = document.querySelector('#callBtn');
// var hangUpBtn = document.querySelector('#hangUpBtn');
var msgInput = document.querySelector('#msgInput');
var sendMsgBtn = document.querySelector('#sendMsgBtn');
var chatArea = document.querySelector('#chatarea');
var yourConn;
var dataChannel;
callPage.style.display = "none";
// Login when the user clicks the button
loginBtn.addEventListener("click", function (event) {
name = usernameInput.value;
if (name.length > 0) {
send({
type: "login",
name: name
});
}
});
function handleLogin(success) {
if (success === false) {
alert("Ooops...try a different username");
} else {
loginPage.style.display = "none";
callPage.style.display = "block";
//using Google public stun server
var configuration = {
"iceServers": [{ "url": "stun:stun2.1.google.com:19302" }]
};
yourConn = new RTCPeerConnection(configuration,{optional: [{RtpDataChannels: true}]});
// Setup ice handling
yourConn.onicecandidate = function (event) {
console.log('enter into login');
if (event.candidate) {
send({
type: "candidate",
candidate: event.candidate
});
}
};
//creating data channel
dataChannel = yourConn.createDataChannel("channel", {reliable:true});
dataChannel.onerror = function (error) {
console.log("Ooops...error:", error);
};
//when we receive a message from the other peer, display it on the screen
dataChannel.onmessage = function (event) {
chatArea.innerHTML += connectedUser + ": " + event.data + "<br />";
};
dataChannel.onclose = function () {
console.log("data channel is closed");
};
}
};
//when we got an answer from a remote user
function handleAnswer(answer) {
yourConn.setRemoteDescription(new RTCSessionDescription(answer));
};
//when we got an ice candidate from a remote user
function handleCandidate(candidate) {
yourConn.addIceCandidate(new RTCIceCandidate(candidate));
};
//when user clicks the "send message" button
sendMsgBtn.addEventListener("click", function (event) {
var val = msgInput.value;
chatArea.innerHTML += name + ": " + val + "<br />";
//sending a message to a connected peer
dataChannel.send(val);
msgInput.value = "";
});
</script>
server.js
var WebSocket = require('ws').Server;
var Port= 8000;
//creating a websocket server at port 9090
var wss = new WebSocket({port: Port});
var fs=require('fs');
var http=require('http');
console.log("STARTED");
var server = http.createServer(function (req, resp) {
fs.readFile("index.html", function (error, pgResp) {
if (error) {
resp.write('Contents you are looking are Not Found');
} else {
resp.end(pgResp);
}
});
});
server.listen(3000);
//all connected to the server users
var users = {};
//when a user connects to our sever
wss.on('connection', function(connection) {
console.log("User connected");
//when server gets a message from a connected user
connection.on('message', function(message) {
var data;
//accepting only JSON messages
try {
data = JSON.parse(message);
} catch (e) {
console.log("Invalid JSON");
data = {};
}
//switching type of the user message
switch (data.type) {
//when a user tries to login
case "login":
console.log("User logged", data.name);
//if anyone is logged in with this username then refuse
if(users[data.name]) {
sendTo(connection, {
type: "login",
success: false
});
} else {
//save user connection on the server
users[data.name] = connection;
connection.name = data.name;
sendTo(connection, {
type: "login",
success: true
});
}
break;
case "offer":
//for ex. UserA wants to call UserB
console.log("Sending offer to: ", data.name);
//if UserB exists then send him offer details
var conn = users[data.name];
if(conn != null) {
//setting that UserA connected with UserB
connection.otherName = data.name;
sendTo(conn, {
type: "offer",
offer: data.offer,
name: connection.name
});
}
break;
case "answer":
console.log("Sending answer to: ", data.name);
//for ex. UserB answers UserA
var conn = users[data.name];
if(conn != null) {
connection.otherName = data.name;
sendTo(conn, {
type: "answer",
answer: data.answer
});
}
break;
case "candidate":
console.log("Sending candidate to:",data.name);
var conn = users[data.name];
if(conn != null) {
sendTo(conn, {
type: "candidate",
candidate: data.candidate
});
}
break;
case "leave":
console.log("Disconnecting from", data.name);
var conn = users[data.name];
conn.otherName = null;
//notify the other user so he can disconnect his peer connection
if(conn != null) {
sendTo(conn, {
type: "leave"
});
}
break;
default:
sendTo(connection, {
type: "error",
message: "Command not found: " + data.type
});
break;
}
});
//when user exits, for example closes a browser window
//this may help if we are still in "offer","answer" or "candidate" state
connection.on("close", function() {
if(connection.name) {
delete users[connection.name];
if(connection.otherName) {
console.log("Disconnecting from ", connection.otherName);
var conn = users[connection.otherName];
conn.otherName = null;
if(conn != null) {
sendTo(conn, {
type: "leave"
});
}
}
}
});
connection.send(JSON.stringify("Hello world"));
});
function sendTo(connection, message) {
connection.send(JSON.stringify(message));
}
I have searched many posts and tried removing "{optional: [{RtpDataChannels: true}]}" ,set reliable=false. But still facing the same problem.Is it the chrome version problem? I am using Version 62.0.3202.75 (Official Build) (32-bit) of chrome.

WebSocket connection to 'ws://localhost:3434/' failed: Connection closed before receiving a handshake response

When using the cmd to run the node server.js and launch the localhost:3434 in the web browser I am getting the error:
in Chrome:
Connection closed before receiving a handshake response.
in firefox:
Firefox can't establish a connection to the server at ws://localhost:3434/
Could you pls help
server.js
var http = require('http'),
fs = require('fs');
fs.readFile('../index.html', function (err, html) {
if (err) {
throw err;
}
http.createServer(function (request, response) {
response.writeHeader(200, { "Content-Type": "text/html" });
response.write(html);
response.end();
}).listen(3434);
});
index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!--<script type="text/javascript" src="../../js/adapter.js"></script>-->
<!--<script type="text/javascript" src="../../js/webrtc.js"></script>-->
<title>Simple WebRTC video chat</title>
</head>
<body>
<header>
<video id="localVideo" autoplay="autoplay" muted="muted" style="width:40%;"></video>
<video id="remoteVideo" autoplay="autoplay" style="width:40%;"></video>
<input type="button" id="start" onclick="start(true)" value="Start Video"; />
</header>
<script>
var RTCPeerConnection = null;
var getUserMedia = null;
var attachMediaStream = null;
var reattachMediaStream = null;
var webrtcDetectedBrowser = null;
var webrtcDetectedVersion = null;
function trace(text) {
// This function is used for logging.
if (text[text.length - 1] == '\n') {
text = text.substring(0, text.length - 1);
}
console.log((performance.now() / 1000).toFixed(3) + ": " + text);
}
if (navigator.mozGetUserMedia) {
console.log("This appears to be Firefox");
webrtcDetectedBrowser = "firefox";
webrtcDetectedVersion =
parseInt(navigator.userAgent.match(/Firefox\/([0- 9]+)\./)[1]);
// The RTCPeerConnection object.
RTCPeerConnection = mozRTCPeerConnection;
// The RTCSessionDescription object.
RTCSessionDescription = mozRTCSessionDescription;
// The RTCIceCandidate object.
RTCIceCandidate = mozRTCIceCandidate;
// Get UserMedia (only difference is the prefix).
getUserMedia = navigator.mozGetUserMedia.bind(navigator);
// Creates iceServer from the url for FF.
createIceServer = function (url, username, password) {
var iceServer = null;
var url_parts = url.split(':');
if (url_parts[0].indexOf('stun') === 0) {
// Create iceServer with stun url.
iceServer = { 'url': url };
} else if (url_parts[0].indexOf('turn') === 0 &&
(url.indexOf('transport=udp') !== -1 ||
url.indexOf('?transport') === -1)) {
// Create iceServer with turn url.
// Ignore the transport parameter from TURN url.
var turn_url_parts = url.split("?");
iceServer = {
'url': turn_url_parts[0],
'credential': password,
'username': username
};
}
return iceServer;
};
// Attach a media stream to an element.
attachMediaStream = function (element, stream) {
console.log("Attaching media stream");
element.mozSrcObject = stream;
element.play();
};
reattachMediaStream = function (to, from) {
console.log("Reattaching media stream");
to.mozSrcObject = from.mozSrcObject;
to.play();
};
MediaStream.prototype.getVideoTracks = function () {
return [];
};
MediaStream.prototype.getAudioTracks = function () {
return [];
};
} else if (navigator.webkitGetUserMedia) {
console.log("This appears to be Chrome");
webrtcDetectedBrowser = "chrome";
webrtcDetectedVersion =
parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]);
// Creates iceServer from the url for Chrome.
createIceServer = function (url, username, password) {
var iceServer = null;
var url_parts = url.split(':');
if (url_parts[0].indexOf('stun') === 0) {
// Create iceServer with stun url.
iceServer = { 'url': url };
} else if (url_parts[0].indexOf('turn') === 0) {
if (webrtcDetectedVersion < 28) {
var url_turn_parts = url.split("turn:");
iceServer = {
'url': 'turn:' + username + '#' + url_turn_parts[1],
'credential': password
};
} else {
iceServer = {
'url': url,
'credential': password,
'username': username
};
}
}
return iceServer;
};
// The RTCPeerConnection object.
RTCPeerConnection = webkitRTCPeerConnection;
// Get UserMedia (only difference is the prefix).
// Code from Adam Barth.
getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
// Attach a media stream to an element.
attachMediaStream = function (element, stream) {
if (typeof element.srcObject !== 'undefined') {
element.srcObject = stream;
} else if (typeof element.mozSrcObject !== 'undefined') {
element.mozSrcObject = stream;
} else if (typeof element.src !== 'undefined') {
element.src = URL.createObjectURL(stream);
} else {
console.log('Error attaching stream to element.');
}
};
reattachMediaStream = function (to, from) {
to.src = from.src;
};
// The representation of tracks in a stream is changed in M26.
// Unify them for earlier Chrome versions in the coexisting period.
if (!webkitMediaStream.prototype.getVideoTracks) {
webkitMediaStream.prototype.getVideoTracks = function () {
return this.videoTracks;
};
webkitMediaStream.prototype.getAudioTracks = function () {
return this.audioTracks;
};
}
if (!webkitRTCPeerConnection.prototype.getLocalStreams) {
webkitRTCPeerConnection.prototype.getLocalStreams = function () {
return this.localStreams;
};
webkitRTCPeerConnection.prototype.getRemoteStreams = function () {
return this.remoteStreams;
};
}
} else {
console.log("Browser does not appear to be WebRTC-capable");
}
var localVideo;
var remoteVideo;
var peerConnection;
var localStream;
var optional = { optional: [{ DtlsSrtpKeyAgreement: true }] }
var peerConnectionConfig = { 'iceServers': [{ 'url': 'stun:stun.services.mozilla.com' }, { 'url': 'stun:stun.l.google.com:19302' }] };
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;
localVideo = document.getElementById("localVideo");
remoteVideo = document.getElementById("remoteVideo");
serverConnection = new WebSocket('ws://localhost:3434');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: true,
};
if (navigator.getUserMedia) {
navigator.getUserMedia(constraints, getUserMediaSuccess, getUserMediaError);
} else {
alert('Your browser does not support getUserMedia API');
}
function getUserMediaSuccess(stream) {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}
function start(isCaller) {
peerConnection = new RTCPeerConnection(peerConnectionConfig, optional);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.onaddstream = gotRemoteStream;
peerConnection.addStream(localStream);
if (isCaller) {
peerConnection.createOffer(gotDescription, createOfferError);
}
}
function gotMessageFromServer(message) {
if (!peerConnection) start(false);
var signal = JSON.parse(message.data);
if (signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp), function () {
peerConnection.createAnswer(gotDescription, createAnswerError);
});
} else if (signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice));
}
}
function gotIceCandidate(event) {
if (event.candidate != null) {
serverConnection.send(JSON.stringify({ 'ice': event.candidate }));
}
}
function gotDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description, function () {
serverConnection.send(JSON.stringify({ 'sdp': description }));
}, function () { console.log('set description error') });
}
function gotRemoteStream(event) {
console.log("got remote stream");
remoteVideo.src = window.URL.createObjectURL(event.stream);
}
// Error functions....
function getUserMediaError(error) {
console.log(error);
}
function createOfferError(error) {
console.log(error);
}
function createAnswerError(error) {
console.log(error);
}
</script>
</body>
</html>
In order to handle websocket connections your http-server should handle 'upgrade'-event (see here - https://nodejs.org/api/http.html#http_event_upgrade_1)
For example, here is the working example (it uses ws-module):
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({noServer: true});
var http = require('http'),
fs = require('fs');
fs.readFile('../index.html', function (err, html) {
if (err) {
throw err;
}
var server = http.createServer(function (request, response) {
response.writeHeader(200, { "Content-Type": "text/html" });
response.write(html);
response.end();
})
server.listen(3434);
server.on('upgrade', wss.handleUpgrade);
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
});
Here are docs for ws - https://github.com/websockets/ws

Socket.io game. How to add new character

I was writinig a game using Socket.io and I have problem, when server create new img (new character) i can only see it on one computer..
I wanna in this case, for every connected computer see the same amount of images
Better if you look on this
Thanks for every help
SERVER:
var handler = function(req, res) {
fs.readFile('./index.html', function (err, data) {
if(err) throw err;
res.writeHead(200);
res.end(data);
});
}
var app = require('http').createServer(handler);
var io = require('socket.io').listen(app);
var fs = require('fs');
var port = 3250;
app.listen(port);
var postacie = [];
var ile=0;
// socket.io
io.sockets.on('connection', function (socket) {
postacie[ile]=createChar();
ile++;
io.sockets.emit("tworz", postacie);
socket.on("disconnect", function()
{
postacie.splice(0, 1);
io.sockets.emit("tworz", postacie);
})
});
function createChar()
{
var postac = {
src: "http://img703.imageshack.us/img703/1416/2st.gif",
id: "character"
}
return postac;
}
CLIENT:
<!DOCTYPE html>
<html>
<head>
<title>Real tie game</title>
<script src="socket.io/socket.io.js"></script>
<script type="text/javascript">
window.onload = function() {
var socket = io.connect('http://localhost:3250');
socket.on("tworz", function(data)
{
for (var i=0; i < data.length; i++) {
var element = document.createElement('img');
element.src = data[i].src;
element.id = data[i].id;
var body = document.getElementsByTagName('body')
body.appendChild(element);
};
})
}
</script>
</head>
<body>
</body>
</html>
AND IT LOOK LIKE THIS
http://img42.imageshack.us/img42/4793/q10w.jpg
I refactored your code a bit. Hope it helps you move in correct direction:
The main idea is to use 3 basic messages:
join -- when new client connects the server send info about newbie to all other clients;
list -- when new client connects the server send him the list of already connected clients;
leave -- when someone disconnected the server send id of disconnected client
Server:
var handler = function(req, res) {
fs.readFile('./index.html', function (err, data) {
if(err) throw err;
res.writeHead(200);
res.end(data);
});
}
var app = require('http').createServer(handler);
var io = require('socket.io').listen(app);
var fs = require('fs');
var port = 3250;
app.listen(port);
var postacie = [];
var idGenerator = 0;
// socket.io
io.sockets.on('connection', function (socket) {
var pId = idGenerator++;
socket.emit("list", postacie);
var postac = createChar(pId);
postacie.push(postac);
io.sockets.emit("join", postac);
socket.on("disconnect", function()
{
var sId = "character" + pId;
for (var i = 0,n=postacie.length; i < n; ++i) {
var postac = postacie[i];
if (postac.id == sId) {
io.sockets.emit("leave", {id:postac.id});
postacie.splice(i, 1);
break;
}
}
});
});
function createChar(id)
{
var postac = {
src: "http://img703.imageshack.us/img703/1416/2st.gif",
id: "character" + id
};
return postac;
}
Client:
<!DOCTYPE html>
<html>
<head>
<title>Real tie game</title>
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
window.onload = function() {
var socket = io.connect('http://localhost:3250');
socket.on("join", function(data)
{
var element = document.createElement('img');
element.src = data.src;
element.id = data.id;
var body = document.getElementsByTagName('body')[0];
body.appendChild(element);
});
socket.on("list", function(data)
{
for (var i=0; i < data.length; i++) {
var element = document.createElement('img');
element.src = data[i].src;
element.id = data[i].id;
var body = document.getElementsByTagName('body')[0];
body.appendChild(element);
};
});
socket.on("leave", function(data)
{
var element = document.getElementById(data.id);
if (element)
element.parentNode.removeChild(element);
});
}
</script>
</head>
<body>
</body>
</html>

Resources