From 16bed36624d6c65f7f68b20ba6bfca9d7628694c Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Thu, 28 Jun 2018 14:21:52 +0000 Subject: [PATCH] Change title --- server.js.save | 444 ++++++++++++++++++++++++++++++++++++++++++++++ static/index.html | 2 +- 2 files changed, 445 insertions(+), 1 deletion(-) create mode 100755 server.js.save diff --git a/server.js.save b/server.js.save new file mode 100755 index 0000000..4472336 --- /dev/null +++ b/server.js.save @@ -0,0 +1,444 @@ +/* + * (C) Copyright 2014-2015 Kurento (http://kurento.org/) + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public License + * (LGPL) version 2.1 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-2.1.html + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +var path = require('path'); +var url = require('url'); +var express = require('express'); +var minimist = require('minimist'); +var kurento = require('kurento-client'); +var fs = require('fs'); +var http = require('http'); +var socketio = require('socket.io'); + +var argv = minimist(process.argv.slice(2), { + default: { + as_uri: 'https://localhost:8443/', + ws_uri: 'ws://localhost:8888/kurento' + } +}); + +var app = express(); + +/* + * Definition of global variables. + */ +var candidatesQueue = {}; +var kurentoClient = null; +var noPresenterMessage = 'No active presenter. Try again later...'; +var anotherPresenterIsActive = "Another user is currently acting as presenter. Try again later ..."; + +var rooms = []; + + +/* + * Server startup + */ +var asUrl = url.parse(argv.as_uri); +var port = asUrl.port; +var server = http.createServer(app); +var io = socketio(server); + +server.listen(port, function() { + console.log('Open ' + url.format(asUrl)); +}); + + +/* + * Rooms related methods + */ + +function getRoom(socket) { + var room = socket.room.slice(0, 6); + if (rooms[room] === undefined) { + createRoom(room); + } + return rooms[room]; +} + +function createRoom(room) { + rooms[room] = { + presenter: null, + pipeline: null, + viewers: [], + chat: [] + }; +} + +function joinRoom(socket, room) { + // leave all other socket.id rooms + while(socket.rooms.length) { + socket.leave(socket.rooms[0]); + } + + // join new socket.io room + socket.room = room; + socket.username = socket.id; + + socket.emit('joinedRoom'); + + console.log('Join room: ' + room); +} + +function newChatMessage(socket, message){ + var message = {message: message, username: socket.username} + io.in(socket.room).emit('chat:newMessage', message) + + var room = getRoom(socket); + room.chat.push(message); + + if (room.chat.length > 30) + room.chat.shift() +} + +/* + * Define possible actions which we'll send thru Websocket + */ +function acceptPeerResponse(peerType, sdpAnswer) { + return { + id : peerType + 'Response', + response : 'accepted', + sdpAnswer : sdpAnswer + }; +} + +function rejectPeerResponse(peerType, reason) { + return { + id : peerType + 'Response', + response : 'rejected', + message : reason + }; +} + +/* + * Socket pipeline + */ +io.on('connection', function(socket) { + console.log('Connection received with sessionId - ' + socket.id); + + socket.on('error', function(error) { + console.error('Connection ' + socket.id + ' error', error); + stop(socket); + }); + + socket.on('disconnect', function() { + console.log('Connection ' + socket.id + ' closed'); + stop(socket); + }); + + // Handle events from clients + socket.on('presenter', function (data) { + startPresenter(socket, data.sdpOffer, function(error, sdpAnswer) { + var response = (error) ? rejectPeerResponse('presenter', error) : acceptPeerResponse('presenter', sdpAnswer); + socket.emit(response.id, response); + if (!error) { + console.log(socket.username + ' starting publishing to ' + socket.room + ' room'); + socket.broadcast.emit('streamStarted'); + } + }); + }); + + socket.on('viewer', function (data){ + startViewer(socket, data.sdpOffer, function(error, sdpAnswer) { + response = (error) ? rejectPeerResponse('viewer', error) : acceptPeerResponse('viewer', sdpAnswer); + socket.emit(response.id, response); + }); + }); + + socket.on('stop', function(){ + stop(socket); + }); + + socket.on('onIceCandidate', function (data){ + onIceCandidate(socket, data.candidate); + }); + + socket.on('subscribeToStream', function (data){ + joinRoom(socket, data); + var room = getRoom(socket); + if (room.presenter) { + socket.emit('streamStarted'); + } + }); + + socket.on('joinRoom', function (data){ + joinRoom(socket, data) + }); + + + // Chat methods + socket.on('chat:newMessage', function(message) { + newChatMessage(socket, message); + }); + + socket.on('chat:loadMessages', function() { + var room = getRoom(socket); + + socket.emit('chat:messages', room.chat); + }); +}); + + + +/* + * Definition of functions + */ + +// Recover kurentoClient for the first time. +function getKurentoClient(callback) { + if (kurentoClient !== null) { + return callback(null, kurentoClient); + } + + kurento(argv.ws_uri, function(error, _kurentoClient) { + if (error) { + console.log("Could not find media server at address " + argv.ws_uri); + return callback("Could not find media server at address" + argv.ws_uri + + ". Exiting with error " + error); + } + + kurentoClient = _kurentoClient; + callback(null, kurentoClient); + }); +} + +function startPresenter(socket, sdpOffer, callback) { + clearCandidatesQueue(socket); + + var room = getRoom(socket); + if (room.presenter !== null) { + stop(socket); + return callback(anotherPresenterIsActive); + } + + room.presenter = { + webRtcEndpoint : null, + id: socket.id + }; + + getKurentoClient(function(error, kurentoClient) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + kurentoClient.create('MediaPipeline', function(error, pipeline) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + room.pipeline = pipeline; + pipeline.create('WebRtcEndpoint', function(error, webRtcEndpoint) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + room.presenter.webRtcEndpoint = webRtcEndpoint; + + if (candidatesQueue[socket.id]) { + while(candidatesQueue[socket.id].length) { + var candidate = candidatesQueue[socket.id].shift(); + webRtcEndpoint.addIceCandidate(candidate); + } + } + + webRtcEndpoint.on('OnIceCandidate', function(event) { + var candidate = kurento.register.complexTypes.IceCandidate(event.candidate); + socket.emit('iceCandidate', { candidate : candidate }); + }); + + webRtcEndpoint.processOffer(sdpOffer, function(error, sdpAnswer) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + callback(null, sdpAnswer); + }); + + webRtcEndpoint.gatherCandidates(function(error) { + if (error) { + stop(socket); + return callback(error); + } + }); + }); + }); + }); +} + +function startViewer(socket, sdpOffer, callback) { + clearCandidatesQueue(socket); + + var room = getRoom(socket); + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + room.pipeline.create('WebRtcEndpoint', function(error, webRtcEndpoint) { + if (error) { + stop(socket); + return callback(error); + } + room.viewers[socket.id] = { + "webRtcEndpoint" : webRtcEndpoint, + "socket" : socket + }; + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + if (candidatesQueue[socket.id]) { + while(candidatesQueue[socket.id].length) { + var candidate = candidatesQueue[socket.id].shift(); + webRtcEndpoint.addIceCandidate(candidate); + } + } + + webRtcEndpoint.on('OnIceCandidate', function(event) { + var candidate = kurento.register.complexTypes.IceCandidate(event.candidate); + socket.emit('iceCandidate', { candidate : candidate }); + }); + + webRtcEndpoint.processOffer(sdpOffer, function(error, sdpAnswer) { + if (error) { + stop(socket.id); + return callback(error); + } + if (room.presenter === null) { + stop(socket.id); + return callback(noPresenterMessage); + } + + room.presenter.webRtcEndpoint.connect(webRtcEndpoint, function(error) { + if (error) { + stop(socket.id); + return callback(error); + } + if (room.presenter === null) { + stop(socket.id); + return callback(noPresenterMessage); + } + + callback(null, sdpAnswer); + webRtcEndpoint.gatherCandidates(function(error) { + if (error) { + stop(socket.id); + return callback(error); + } + }); + }); + }); + }); +} + +function clearCandidatesQueue(socket) { + if (candidatesQueue[socket.id]) { + delete candidatesQueue[socket.id]; + } +} + +function stop(socket) { + var room = getRoom(socket); + + if (room.presenter !== null && room.presenter.id == socket.id) { + stopPresenter(socket); + } else if (room.viewers[socket.id]) { + stopViewing(socket); + } +} + +function stopPresenter(socket){ + var room = getRoom(socket); + var viewers = room.viewers; + + for (var i in viewers) { + var viewer = viewers[i]; + if (viewer.socket) { + clearCandidatesQueue(socket); + viewer.webRtcEndpoint.release(); + viewer.socket.emit('stopCommunication'); + } + } + + room.presenter.webRtcEndpoint.release(); + room.presenter = null; + room.pipeline.release(); + room.viewers = []; +} + +function stopViewing(socket){ + var room = getRoom(socket); + + clearCandidatesQueue(socket.id); + room.viewers[socket.id].webRtcEndpoint.release(); + delete room.viewers[socket.id]; +} + +function onIceCandidate(socket, _candidate) { + var room = getRoom(socket); + + var candidate = kurento.register.complexTypes.IceCandidate(_candidate); + + if (room.presenter && room.presenter.id === socket.id && room.presenter.webRtcEndpoint) { + console.info('Sending presenter candidate'); + room.presenter.webRtcEndpoint.addIceCandidate(candidate); + } + else if (room.viewers[socket.id] && room.viewers[socket.id].webRtcEndpoint) { + console.info('Sending viewer candidate'); + room.viewers[socket.id].webRtcEndpoint.addIceCandidate(candidate); + } + else { + console.info('Queueing candidate'); + if (!candidatesQueue[socket.id]) { + candidatesQueue[socket.id] = []; + } + candidatesQueue[socket.id].push(candidate); + } +} + +app.use(function (req, res, next) { + // Website you wish to allow to connect + res.setHeader('Access-Control-Allow-Origin', '*'); + + next(); +}); + +app.use(express.static(path.join(__dirname, 'static'))); diff --git a/static/index.html b/static/index.html index a51467f..7b1a3c9 100755 --- a/static/index.html +++ b/static/index.html @@ -19,7 +19,7 @@ - Steam + GTO Broadcasting