Merge branch 'feature-socketio' into develop

master
Håvar Aambø Fosstveit 2018-10-19 10:06:42 +02:00
commit 10c3427355
8 changed files with 4423 additions and 4292 deletions

View File

@ -1,9 +1,9 @@
import protooClient from 'protoo-client'; import io from 'socket.io-client';
import * as mediasoupClient from 'mediasoup-client'; import * as mediasoupClient from 'mediasoup-client';
import Logger from './Logger'; import Logger from './Logger';
import hark from 'hark'; import hark from 'hark';
import ScreenShare from './ScreenShare'; import ScreenShare from './ScreenShare';
import { getProtooUrl } from './urlFactory'; import { getSignalingUrl } from './urlFactory';
import * as cookiesManager from './cookiesManager'; import * as cookiesManager from './cookiesManager';
import * as requestActions from './redux/requestActions'; import * as requestActions from './redux/requestActions';
import * as stateActions from './redux/stateActions'; import * as stateActions from './redux/stateActions';
@ -37,8 +37,7 @@ export default class RoomClient
'constructor() [roomId:"%s", peerName:"%s", displayName:"%s", device:%s]', 'constructor() [roomId:"%s", peerName:"%s", displayName:"%s", device:%s]',
roomId, peerName, displayName, device.flag); roomId, peerName, displayName, device.flag);
const protooUrl = getProtooUrl(peerName, roomId); const signalingUrl = getSignalingUrl(peerName, roomId);
const protooTransport = new protooClient.WebSocketTransport(protooUrl);
// window element to external login site // window element to external login site
this._loginWindow; this._loginWindow;
@ -64,8 +63,8 @@ export default class RoomClient
// My peer name. // My peer name.
this._peerName = peerName; this._peerName = peerName;
// protoo-client Peer instance. // Socket.io peer connection
this._protoo = new protooClient.Peer(protooTransport); this._signalingSocket = io(signalingUrl);
// mediasoup-client Room instance. // mediasoup-client Room instance.
this._room = new mediasoupClient.Room(ROOM_OPTIONS); this._room = new mediasoupClient.Room(ROOM_OPTIONS);
@ -120,9 +119,9 @@ export default class RoomClient
// Leave the mediasoup Room. // Leave the mediasoup Room.
this._room.leave(); this._room.leave();
// Close protoo Peer (wait a bit so mediasoup-client can send // Close signaling Peer (wait a bit so mediasoup-client can send
// the 'leaveRoom' notification). // the 'leaveRoom' notification).
setTimeout(() => this._protoo.close(), 250); setTimeout(() => this._signalingSocket.close(), 250);
this._dispatch(stateActions.setRoomState('closed')); this._dispatch(stateActions.setRoomState('closed'));
} }
@ -144,6 +143,57 @@ export default class RoomClient
this._loginWindow.close(); this._loginWindow.close();
} }
timeoutCallback(callback)
{
let called = false;
const interval = setTimeout(
() =>
{
if (called)
return;
called = true;
callback(new Error('Callback timeout'));
},
5000
);
return (...args) =>
{
if (called)
return;
called = true;
clearTimeout(interval);
callback(...args);
};
}
sendRequest(method, data)
{
return new Promise((resolve, reject) =>
{
if (!this._signalingSocket)
{
reject('No socket connection.');
}
else
{
this._signalingSocket.emit(method, data, this.timeoutCallback((err, response) =>
{
if (err)
{
reject(err);
}
else
{
resolve(response);
}
}));
}
});
}
changeDisplayName(displayName) changeDisplayName(displayName)
{ {
logger.debug('changeDisplayName() [displayName:"%s"]', displayName); logger.debug('changeDisplayName() [displayName:"%s"]', displayName);
@ -151,7 +201,7 @@ export default class RoomClient
// Store in cookie. // Store in cookie.
cookiesManager.setUser({ displayName }); cookiesManager.setUser({ displayName });
return this._protoo.send('change-display-name', { displayName }) return this.sendRequest('change-display-name', { displayName })
.then(() => .then(() =>
{ {
this._dispatch( this._dispatch(
@ -182,7 +232,7 @@ export default class RoomClient
{ {
logger.debug('changeProfilePicture() [picture: "%s"]', picture); logger.debug('changeProfilePicture() [picture: "%s"]', picture);
this._protoo.send('change-profile-picture', { picture }).catch((error) => return this.sendRequest('change-profile-picture', { picture }).catch((error) =>
{ {
logger.error('shareProfilePicure() | failed: %o', error); logger.error('shareProfilePicure() | failed: %o', error);
}); });
@ -192,7 +242,7 @@ export default class RoomClient
{ {
logger.debug('sendChatMessage() [chatMessage:"%s"]', chatMessage); logger.debug('sendChatMessage() [chatMessage:"%s"]', chatMessage);
return this._protoo.send('chat-message', { chatMessage }) return this.sendRequest('chat-message', { chatMessage })
.catch((error) => .catch((error) =>
{ {
logger.error('sendChatMessage() | failed: %o', error); logger.error('sendChatMessage() | failed: %o', error);
@ -209,7 +259,7 @@ export default class RoomClient
{ {
logger.debug('sendFile() [file: %o]', file); logger.debug('sendFile() [file: %o]', file);
return this._protoo.send('send-file', { file }) return this.sendRequest('send-file', { file })
.catch((error) => .catch((error) =>
{ {
logger.error('sendFile() | failed: %o', error); logger.error('sendFile() | failed: %o', error);
@ -225,7 +275,7 @@ export default class RoomClient
{ {
logger.debug('getChatHistory()'); logger.debug('getChatHistory()');
return this._protoo.send('chat-history', {}) return this.sendRequest('chat-history', {})
.catch((error) => .catch((error) =>
{ {
logger.error('getChatHistory() | failed: %o', error); logger.error('getChatHistory() | failed: %o', error);
@ -242,7 +292,7 @@ export default class RoomClient
{ {
logger.debug('getFileHistory()'); logger.debug('getFileHistory()');
return this._protoo.send('file-history', {}) return this.sendRequest('file-history', {})
.catch((error) => .catch((error) =>
{ {
logger.error('getFileHistory() | failed: %o', error); logger.error('getFileHistory() | failed: %o', error);
@ -940,7 +990,7 @@ export default class RoomClient
this._dispatch( this._dispatch(
stateActions.setMyRaiseHandStateInProgress(true)); stateActions.setMyRaiseHandStateInProgress(true));
return this._protoo.send('raisehand-message', { raiseHandState: state }) return this.sendRequest('raisehand-message', { raiseHandState: state })
.then(() => .then(() =>
{ {
this._dispatch( this._dispatch(
@ -997,16 +1047,16 @@ export default class RoomClient
{ {
this._dispatch(stateActions.setRoomState('connecting')); this._dispatch(stateActions.setRoomState('connecting'));
this._protoo.on('open', () => this._signalingSocket.on('connect', () =>
{ {
logger.debug('protoo Peer "open" event'); logger.debug('signaling Peer "connect" event');
this._joinRoom({ displayName, device }); this._joinRoom({ displayName, device });
}); });
this._protoo.on('disconnected', () => this._signalingSocket.on('disconnect', () =>
{ {
logger.warn('protoo Peer "disconnected" event'); logger.warn('signaling Peer "disconnect" event');
this._dispatch(requestActions.notify( this._dispatch(requestActions.notify(
{ {
@ -1015,59 +1065,41 @@ export default class RoomClient
})); }));
// Leave Room. // Leave Room.
try { this._room.remoteClose({ cause: 'protoo disconnected' }); } try { this._room.remoteClose({ cause: 'signaling disconnected' }); }
catch (error) {} catch (error) {}
this._dispatch(stateActions.setRoomState('connecting')); this._dispatch(stateActions.setRoomState('connecting'));
}); });
this._protoo.on('close', () => this._signalingSocket.on('close', () =>
{ {
if (this._closed) if (this._closed)
return; return;
logger.warn('protoo Peer "close" event'); logger.warn('signaling Peer "close" event');
this.close(); this.close();
}); });
this._protoo.on('request', (request, accept, reject) => this._signalingSocket.on('mediasoup-notification', (data) =>
{ {
logger.debug( const notification = data;
'_handleProtooRequest() [method:%s, data:%o]',
request.method, request.data);
switch (request.method)
{
case 'mediasoup-notification':
{
accept();
const notification = request.data;
this._room.receiveNotification(notification); this._room.receiveNotification(notification);
});
break; this._signalingSocket.on('active-speaker', (data) =>
}
case 'active-speaker':
{ {
accept(); const { peerName } = data;
const { peerName } = request.data;
this._dispatch( this._dispatch(
stateActions.setRoomActiveSpeaker(peerName)); stateActions.setRoomActiveSpeaker(peerName));
});
break; this._signalingSocket.on('display-name-changed', (data) =>
}
case 'display-name-changed':
{ {
accept();
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
const { peerName, displayName, oldDisplayName } = request.data; const { peerName, displayName, oldDisplayName } = data;
// NOTE: Hack, we shouldn't do this, but this is just a demo. // NOTE: Hack, we shouldn't do this, but this is just a demo.
const peer = this._room.getPeerByName(peerName); const peer = this._room.getPeerByName(peerName);
@ -1076,7 +1108,7 @@ export default class RoomClient
{ {
logger.error('peer not found'); logger.error('peer not found');
break; return;
} }
peer.appData.displayName = displayName; peer.appData.displayName = displayName;
@ -1088,75 +1120,58 @@ export default class RoomClient
{ {
text : `${oldDisplayName} is now ${displayName}` text : `${oldDisplayName} is now ${displayName}`
})); }));
});
break; this._signalingSocket.on('profile-picture-changed', (data) =>
}
case 'profile-picture-changed':
{ {
accept(); const { peerName, picture } = data;
const { peerName, picture } = request.data;
this._dispatch(stateActions.setPeerPicture(peerName, picture)); this._dispatch(stateActions.setPeerPicture(peerName, picture));
});
break;
}
// This means: server wants to change MY user information // This means: server wants to change MY user information
case 'auth': this._signalingSocket.on('auth', (data) =>
{ {
logger.debug('got auth event from server', request.data); logger.debug('got auth event from server', data);
accept();
this.changeDisplayName(request.data.name); this.changeDisplayName(data.name);
this.changeProfilePicture(request.data.picture); this.changeProfilePicture(data.picture);
this._dispatch(stateActions.setPicture(request.data.picture)); this._dispatch(stateActions.setPicture(data.picture));
this._dispatch(stateActions.loggedIn()); this._dispatch(stateActions.loggedIn());
this._dispatch(requestActions.notify( this._dispatch(requestActions.notify(
{ {
text : `Authenticated successfully: ${request.data}` text : `Authenticated successfully: ${data}`
} }
)); ));
this.closeLoginWindow(); this.closeLoginWindow();
});
break; this._signalingSocket.on('raisehand-message', (data) =>
}
case 'raisehand-message':
{ {
accept(); const { peerName, raiseHandState } = data;
const { peerName, raiseHandState } = request.data;
logger.debug('Got raiseHandState from "%s"', peerName); logger.debug('Got raiseHandState from "%s"', peerName);
this._dispatch( this._dispatch(
stateActions.setPeerRaiseHandState(peerName, raiseHandState)); stateActions.setPeerRaiseHandState(peerName, raiseHandState));
break; });
}
case 'chat-message-receive': this._signalingSocket.on('chat-message-receive', (data) =>
{ {
accept(); const { peerName, chatMessage } = data;
const { peerName, chatMessage } = request.data;
logger.debug('Got chat from "%s"', peerName); logger.debug('Got chat from "%s"', peerName);
this._dispatch( this._dispatch(
stateActions.addResponseMessage({ ...chatMessage, peerName })); stateActions.addResponseMessage({ ...chatMessage, peerName }));
});
break; this._signalingSocket.on('chat-history-receive', (data) =>
}
case 'chat-history-receive':
{ {
accept(); const { chatHistory } = data;
const { chatHistory } = request.data;
if (chatHistory.length > 0) if (chatHistory.length > 0)
{ {
@ -1164,30 +1179,22 @@ export default class RoomClient
this._dispatch( this._dispatch(
stateActions.addChatHistory(chatHistory)); stateActions.addChatHistory(chatHistory));
} }
});
break; this._signalingSocket.on('file-receive', (data) =>
}
case 'file-receive':
{ {
accept(); const payload = data.file;
const payload = request.data.file;
this._dispatch(stateActions.addFile(payload)); this._dispatch(stateActions.addFile(payload));
this._dispatch(requestActions.notify({ this._dispatch(requestActions.notify({
text : `${payload.name} shared a file` text : `${payload.name} shared a file`
})); }));
});
break; this._signalingSocket.on('file-history-receive', (data) =>
}
case 'file-history-receive':
{ {
accept(); const files = data.fileHistory;
const files = request.data.fileHistory;
if (files.length > 0) if (files.length > 0)
{ {
@ -1195,17 +1202,6 @@ export default class RoomClient
this._dispatch(stateActions.addFileHistory(files)); this._dispatch(stateActions.addFileHistory(files));
} }
break;
}
default:
{
logger.error('unknown protoo method "%s"', request.method);
reject(404, 'unknown method');
}
}
}); });
} }
@ -1213,7 +1209,7 @@ export default class RoomClient
{ {
logger.debug('_joinRoom()'); logger.debug('_joinRoom()');
// NOTE: We allow rejoining (room.join()) the same mediasoup Room when Protoo // NOTE: We allow rejoining (room.join()) the same mediasoup Room when
// WebSocket re-connects, so we must clean existing event listeners. Otherwise // WebSocket re-connects, so we must clean existing event listeners. Otherwise
// they will be called twice after the reconnection. // they will be called twice after the reconnection.
this._room.removeAllListeners(); this._room.removeAllListeners();
@ -1235,7 +1231,7 @@ export default class RoomClient
logger.debug( logger.debug(
'sending mediasoup request [method:%s]:%o', request.method, request); 'sending mediasoup request [method:%s]:%o', request.method, request);
this._protoo.send('mediasoup-request', request) this.sendRequest('mediasoup-request', request)
.then(callback) .then(callback)
.catch(errback); .catch(errback);
}); });
@ -1246,7 +1242,7 @@ export default class RoomClient
'sending mediasoup notification [method:%s]:%o', 'sending mediasoup notification [method:%s]:%o',
notification.method, notification); notification.method, notification);
this._protoo.send('mediasoup-notification', notification) this.sendRequest('mediasoup-notification', notification)
.catch((error) => .catch((error) =>
{ {
logger.warn('could not send mediasoup notification:%o', error); logger.warn('could not send mediasoup notification:%o', error);

View File

@ -1,4 +1,4 @@
export function getProtooUrl(peerName, roomId) export function getSignalingUrl(peerName, roomId)
{ {
const hostname = window.location.hostname; const hostname = window.location.hostname;
const port = window.location.port; const port = window.location.port;

4621
app/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,6 @@
"marked": "^0.4.0", "marked": "^0.4.0",
"mediasoup-client": "^2.1.1", "mediasoup-client": "^2.1.1",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"protoo-client": "^3.0.0",
"random-string": "^0.2.0", "random-string": "^0.2.0",
"react": "^16.4.2", "react": "^16.4.2",
"react-copy-to-clipboard": "^5.0.1", "react-copy-to-clipboard": "^5.0.1",

View File

@ -1,7 +1,6 @@
'use strict'; 'use strict';
const EventEmitter = require('events').EventEmitter; const EventEmitter = require('events').EventEmitter;
const protooServer = require('protoo-server');
const WebTorrent = require('webtorrent-hybrid'); const WebTorrent = require('webtorrent-hybrid');
const Logger = require('./Logger'); const Logger = require('./Logger');
const config = require('../config'); const config = require('../config');
@ -39,11 +38,10 @@ class Room extends EventEmitter
this._fileHistory = []; this._fileHistory = [];
this._signalingPeers = new Map();
try try
{ {
// Protoo Room instance.
this._protooRoom = new protooServer.Room();
// mediasoup Room instance. // mediasoup Room instance.
this._mediaRoom = mediaServer.Room(config.mediasoup.mediaCodecs); this._mediaRoom = mediaServer.Room(config.mediasoup.mediaCodecs);
} }
@ -75,9 +73,14 @@ class Room extends EventEmitter
this._closed = true; this._closed = true;
// Close the protoo Room. // Close the signalingPeers
if (this._protooRoom) if (this._signalingPeers)
this._protooRoom.close(); for (let peer of this._signalingPeers)
{
peer.socket.disconnect();
};
this._signalingPeers.clear();
// Close the mediasoup Room. // Close the mediasoup Room.
if (this._mediaRoom) if (this._mediaRoom)
@ -93,31 +96,32 @@ class Room extends EventEmitter
return; return;
logger.info( logger.info(
'logStatus() [room id:"%s", protoo peers:%s, mediasoup peers:%s]', 'logStatus() [room id:"%s", peers:%s, mediasoup peers:%s]',
this._roomId, this._roomId,
this._protooRoom.peers.length, this._signalingPeers.length,
this._mediaRoom.peers.length); this._mediaRoom.peers.length);
} }
handleConnection(peerName, transport) handleConnection(peerName, socket)
{ {
logger.info('handleConnection() [peerName:"%s"]', peerName); logger.info('handleConnection() [peerName:"%s"]', peerName);
if (this._protooRoom.hasPeer(peerName)) if (this._signalingPeers.has(peerName))
{ {
logger.warn( logger.warn(
'handleConnection() | there is already a peer with same peerName, ' + 'handleConnection() | there is already a peer with same peerName, ' +
'closing the previous one [peerName:"%s"]', 'closing the previous one [peerName:"%s"]',
peerName); peerName);
const protooPeer = this._protooRoom.getPeer(peerName); const signalingPeer = this._signalingPeers.get(peerName);
protooPeer.close(); signalingPeer.socket.disconnect();
this._signalingPeers.delete(peerName);
} }
const protooPeer = this._protooRoom.createPeer(peerName, transport); const signalingPeer = { peerName : peerName, socket : socket };
this._handleProtooPeer(protooPeer); this._handleSignalingPeer(signalingPeer);
} }
_handleMediaRoom() _handleMediaRoom()
@ -173,8 +177,8 @@ class Room extends EventEmitter
} }
} }
// Spread to others via protoo. // Spread to room
this._protooRoom.spread( this.emit(
'active-speaker', 'active-speaker',
{ {
peerName : activePeer ? activePeer.name : null peerName : activePeer ? activePeer.name : null
@ -182,110 +186,99 @@ class Room extends EventEmitter
}); });
} }
_handleProtooPeer(protooPeer) _handleSignalingPeer(signalingPeer)
{ {
logger.debug('_handleProtooPeer() [peer:"%s"]', protooPeer.id); logger.debug('_handleSignalingPeer() [peer:"%s"]', signalingPeer.id);
protooPeer.on('request', (request, accept, reject) => signalingPeer.socket.on('mediasoup-request', (request, cb) =>
{ {
logger.debug( const mediasoupRequest = request;
'protoo "request" event [method:%s, peer:"%s"]',
request.method, protooPeer.id);
switch (request.method)
{
case 'mediasoup-request':
{
const mediasoupRequest = request.data;
this._handleMediasoupClientRequest( this._handleMediasoupClientRequest(
protooPeer, mediasoupRequest, accept, reject); signalingPeer, mediasoupRequest, cb);
});
break; signalingPeer.socket.on('mediasoup-notification', (request, cb) =>
}
case 'mediasoup-notification':
{ {
accept(); // Return no error
cb(null);
const mediasoupNotification = request.data; const mediasoupNotification = request;
this._handleMediasoupClientNotification( this._handleMediasoupClientNotification(
protooPeer, mediasoupNotification); signalingPeer, mediasoupNotification);
});
break; signalingPeer.socket.on('change-display-name', (request, cb) =>
}
case 'change-display-name':
{ {
accept(); // Return no error
cb(null);
const { displayName } = request.data; const { displayName } = request;
const { mediaPeer } = protooPeer.data; const mediaPeer = this._mediaRoom.getPeerByName(peerName);
const oldDisplayName = mediaPeer.appData.displayName; const oldDisplayName = mediaPeer.appData.displayName;
mediaPeer.appData.displayName = displayName; mediaPeer.appData.displayName = displayName;
// Spread to others via protoo. signalingPeer.socket.broadcast.to(this._roomId).emit(
this._protooRoom.spread(
'display-name-changed', 'display-name-changed',
{ {
peerName : protooPeer.id, peerName : signalingPeer.peerName,
displayName : displayName, displayName : displayName,
oldDisplayName : oldDisplayName oldDisplayName : oldDisplayName
},
[ protooPeer ]);
break;
} }
);
});
case 'change-profile-picture': signalingPeer.socket.on('change-profile-picture', (request, cb) =>
{ {
accept(); // Return no error
cb(null);
this._protooRoom.spread('profile-picture-changed', { signalingPeer.socket.broadcast.to(this._roomId).emit(
peerName : protooPeer.id, 'profile-picture-changed',
picture : request.data.picture {
}, [ protooPeer ]); peerName : signalingPeer.peerName,
picture : request.picture
break;
} }
);
});
case 'chat-message': signalingPeer.socket.on('chat-message', (request, cb) =>
{ {
accept(); // Return no error
cb(null);
const { chatMessage } = request.data; const { chatMessage } = request;
this._chatHistory.push(chatMessage); this._chatHistory.push(chatMessage);
// Spread to others via protoo. // Spread to others
this._protooRoom.spread( signalingPeer.socket.broadcast.to(this._roomId).emit(
'chat-message-receive', 'chat-message-receive',
{ {
peerName : protooPeer.id, peerName : signalingPeer.peerName,
chatMessage : chatMessage chatMessage : chatMessage
},
[ protooPeer ]);
break;
} }
);
});
case 'chat-history': signalingPeer.socket.on('chat-history', (request, cb) =>
{ {
accept(); // Return no error
cb(null);
protooPeer.send( // Return to socket
signalingPeer.socket.emit(
'chat-history-receive', 'chat-history-receive',
{ chatHistory: this._chatHistory } { chatHistory: this._chatHistory }
); );
});
break; signalingPeer.socket.on('send-file', (request, cb) =>
}
case 'send-file':
{ {
accept(); // Return no error
cb(null);
const fileData = request.data.file; const fileData = request.data.file;
@ -296,58 +289,53 @@ class Room extends EventEmitter
torrentClient.add(fileData.file.magnet); torrentClient.add(fileData.file.magnet);
} }
this._protooRoom.spread('file-receive', { // Spread to others
file : fileData signalingPeer.socket.broadcast.to(this._roomId).emit(
}, [ protooPeer ]); 'file-receive',
break;
}
case 'file-history':
{ {
accept(); file : fileData
}
protooPeer.send('file-history-receive', { );
fileHistory : this._fileHistory
}); });
break; signalingPeer.socket.on('file-history', (request, cb) =>
}
case 'raisehand-message':
{ {
accept(); // Return no error
cb(null);
// Return to socket
signalingPeer.socket.emit(
'file-history-receive',
{
fileHistory : this._fileHistory
}
);
});
signalingPeer.socket.on('raisehand-message', (request, cb) =>
{
// Return no error
cb(null);
const { raiseHandState } = request.data; const { raiseHandState } = request.data;
const { mediaPeer } = protooPeer.data; const { mediaPeer } = signalingPeer;
mediaPeer.appData.raiseHandState = request.data.raiseHandState; mediaPeer.appData.raiseHandState = request.data.raiseHandState;
// Spread to others via protoo. // Spread to others
this._protooRoom.spread( signalingPeer.socket.broadcast.to(this._roomId).emit(
'raisehand-message', 'raisehand-message',
{ {
peerName : protooPeer.id, peerName : signalingPeer.peerName,
raiseHandState : raiseHandState raiseHandState : raiseHandState
}, },
[ protooPeer ]); );
break;
}
default:
{
logger.error('unknown request.method "%s"', request.method);
reject(400, `unknown request.method "${request.method}"`);
}
}
}); });
protooPeer.on('close', () => signalingPeer.socket.on('disconnect', () =>
{ {
logger.debug('protoo Peer "close" event [peer:"%s"]', protooPeer.id); logger.debug('Peer "close" event [peer:"%s"]', signalingPeer.peerName);
const { mediaPeer } = protooPeer.data; const mediaPeer = this._mediaRoom.getPeerByName(signalingPeer.peerName);
if (mediaPeer && !mediaPeer.closed) if (mediaPeer && !mediaPeer.closed)
mediaPeer.close(); mediaPeer.close();
@ -371,12 +359,11 @@ class Room extends EventEmitter
}); });
} }
_handleMediaPeer(protooPeer, mediaPeer) _handleMediaPeer(signalingPeer, mediaPeer)
{ {
mediaPeer.on('notify', (notification) => mediaPeer.on('notify', (notification) =>
{ {
protooPeer.send('mediasoup-notification', notification) signalingPeer.socket.emit('mediasoup-notification', notification);
.catch(() => {});
}); });
mediaPeer.on('newtransport', (transport) => mediaPeer.on('newtransport', (transport) =>
@ -424,12 +411,11 @@ class Room extends EventEmitter
// Notify about the existing active speaker. // Notify about the existing active speaker.
if (this._currentActiveSpeaker) if (this._currentActiveSpeaker)
{ {
protooPeer.send( signalingPeer.socket.emit(
'active-speaker', 'active-speaker',
{ {
peerName : this._currentActiveSpeaker.name peerName : this._currentActiveSpeaker.name
}) });
.catch(() => {});
} }
} }
@ -495,19 +481,19 @@ class Room extends EventEmitter
consumer.setPreferredProfile('low'); consumer.setPreferredProfile('low');
} }
_handleMediasoupClientRequest(protooPeer, request, accept, reject) _handleMediasoupClientRequest(signalingPeer, request, cb)
{ {
logger.debug( logger.debug(
'mediasoup-client request [method:%s, peer:"%s"]', 'mediasoup-client request [method:%s, peer:"%s"]',
request.method, protooPeer.id); request.method, signalingPeer.peerName);
switch (request.method) switch (request.method)
{ {
case 'queryRoom': case 'queryRoom':
{ {
this._mediaRoom.receiveRequest(request) this._mediaRoom.receiveRequest(request)
.then((response) => accept(response)) .then((response) => cb(null, response))
.catch((error) => reject(500, error.toString())); .catch((error) => cb(error.toString()));
break; break;
} }
@ -517,15 +503,15 @@ class Room extends EventEmitter
// TODO: Handle appData. Yes? // TODO: Handle appData. Yes?
const { peerName } = request; const { peerName } = request;
if (peerName !== protooPeer.id) if (peerName !== signalingPeer.peerName)
{ {
reject(403, 'that is not your corresponding mediasoup Peer name'); cb('that is not your corresponding mediasoup Peer name');
break; break;
} }
else if (protooPeer.data.mediaPeer) else if (signalingPeer.mediaPeer)
{ {
reject(500, 'already have a mediasoup Peer'); cb('already have a mediasoup Peer');
break; break;
} }
@ -533,18 +519,18 @@ class Room extends EventEmitter
this._mediaRoom.receiveRequest(request) this._mediaRoom.receiveRequest(request)
.then((response) => .then((response) =>
{ {
accept(response); cb(null, response);
// Get the newly created mediasoup Peer. // Get the newly created mediasoup Peer.
const mediaPeer = this._mediaRoom.getPeerByName(peerName); const mediaPeer = this._mediaRoom.getPeerByName(peerName);
protooPeer.data.mediaPeer = mediaPeer; signalingPeer.mediaPeer = mediaPeer;
this._handleMediaPeer(protooPeer, mediaPeer); this._handleMediaPeer(signalingPeer, mediaPeer);
}) })
.catch((error) => .catch((error) =>
{ {
reject(500, error.toString()); cb(error.toString());
}); });
break; break;
@ -552,7 +538,7 @@ class Room extends EventEmitter
default: default:
{ {
const { mediaPeer } = protooPeer.data; const { mediaPeer } = signalingPeer;
if (!mediaPeer) if (!mediaPeer)
{ {
@ -560,25 +546,25 @@ class Room extends EventEmitter
'cannot handle mediasoup request, no mediasoup Peer [method:"%s"]', 'cannot handle mediasoup request, no mediasoup Peer [method:"%s"]',
request.method); request.method);
reject(400, 'no mediasoup Peer'); cb('no mediasoup Peer');
} }
mediaPeer.receiveRequest(request) mediaPeer.receiveRequest(request)
.then((response) => accept(response)) .then((response) => cb(null, response))
.catch((error) => reject(500, error.toString())); .catch((error) => cb(error.toString()));
} }
} }
} }
_handleMediasoupClientNotification(protooPeer, notification) _handleMediasoupClientNotification(signalingPeer, notification)
{ {
logger.debug( logger.debug(
'mediasoup-client notification [method:%s, peer:"%s"]', 'mediasoup-client notification [method:%s, peer:"%s"]',
notification.method, protooPeer.id); notification.method, signalingPeer.peerName);
// NOTE: mediasoup-client just sends notifications with target 'peer', // NOTE: mediasoup-client just sends notifications with target 'peer',
// so first of all, get the mediasoup Peer. // so first of all, get the mediasoup Peer.
const { mediaPeer } = protooPeer.data; const { mediaPeer } = signalingPeer;
if (!mediaPeer) if (!mediaPeer)
{ {

3321
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,8 +13,8 @@
"express": "^4.16.3", "express": "^4.16.3",
"mediasoup": "^2.1.0", "mediasoup": "^2.1.0",
"passport-dataporten": "^1.3.0", "passport-dataporten": "^1.3.0",
"protoo-server": "^2.0.7", "webtorrent-hybrid": "^1.0.6",
"webtorrent-hybrid": "^1.0.6" "socket.io": "^2.1.1"
}, },
"devDependencies": { "devDependencies": {
"gulp": "^4.0.0", "gulp": "^4.0.0",

View File

@ -9,7 +9,6 @@ const fs = require('fs');
const https = require('https'); const https = require('https');
const express = require('express'); const express = require('express');
const url = require('url'); const url = require('url');
const protooServer = require('protoo-server');
const Logger = require('./lib/Logger'); const Logger = require('./lib/Logger');
const Room = require('./lib/Room'); const Room = require('./lib/Room');
const Dataporten = require('passport-dataporten'); const Dataporten = require('passport-dataporten');
@ -98,29 +97,18 @@ httpsServer.listen(config.listeningPort, '0.0.0.0', () =>
logger.info('Server running on port: ', config.listeningPort); logger.info('Server running on port: ', config.listeningPort);
}); });
// Protoo WebSocket server listens to same webserver so everything is available const io = require('socket.io')(httpsServer);
// via same port
const webSocketServer = new protooServer.WebSocketServer(httpsServer,
{
maxReceivedFrameSize : 960000, // 960 KBytes.
maxReceivedMessageSize : 960000,
fragmentOutgoingMessages : true,
fragmentationThreshold : 960000
});
// Handle connections from clients. // Handle connections from clients.
webSocketServer.on('connectionrequest', (info, accept, reject) => io.on('connection', (socket) =>
{ {
// The client indicates the roomId and peerId in the URL query. const { roomId, peerName } = socket.handshake.query;
const u = url.parse(info.request.url, true);
const roomId = u.query['roomId'];
const peerName = u.query['peerName'];
if (!roomId || !peerName) if (!roomId || !peerName)
{ {
logger.warn('connection request without roomId and/or peerName'); logger.warn('connection request without roomId and/or peerName');
reject(400, 'Connection request without roomId and/or peerName'); socket.disconnect(true);
return; return;
} }
@ -145,7 +133,7 @@ webSocketServer.on('connectionrequest', (info, accept, reject) =>
{ {
logger.error('error creating a new Room: %s', error); logger.error('error creating a new Room: %s', error);
reject(error); socket.disconnect(true);
return; return;
} }
@ -157,6 +145,11 @@ webSocketServer.on('connectionrequest', (info, accept, reject) =>
rooms.set(roomId, room); rooms.set(roomId, room);
room.on('active-speaker', (message) =>
{
io.to(roomId).emit('active-speaker', message);
});
room.on('close', () => room.on('close', () =>
{ {
rooms.delete(roomId); rooms.delete(roomId);
@ -168,7 +161,8 @@ webSocketServer.on('connectionrequest', (info, accept, reject) =>
room = rooms.get(roomId); room = rooms.get(roomId);
} }
const transport = accept(); socket.join(roomId);
socket.room = roomId;
room.handleConnection(peerName, transport); room.handleConnection(peerName, socket);
}); });