Fixed conflict in server/config/config.example.js

auto_join_3.3
Astagor 2020-05-05 07:49:30 +02:00
commit 311936d21a
7 changed files with 341 additions and 19 deletions

View File

@ -33,7 +33,7 @@ var config =
*/ */
audioOutputSupportedBrowsers : audioOutputSupportedBrowsers :
[ [
'chrome', 'chrome',
'opera' 'opera'
], ],
// Socket.io request timeout // Socket.io request timeout

View File

@ -38,6 +38,7 @@ import messagesCzech from './translations/cs';
import messagesItalian from './translations/it'; import messagesItalian from './translations/it';
import messagesUkrainian from './translations/uk'; import messagesUkrainian from './translations/uk';
import messagesTurkish from './translations/tr'; import messagesTurkish from './translations/tr';
import messagesLatvian from './translations/lv';
import './index.css'; import './index.css';
@ -63,7 +64,8 @@ const messages =
'cs' : messagesCzech, 'cs' : messagesCzech,
'it' : messagesItalian, 'it' : messagesItalian,
'uk' : messagesUkrainian, 'uk' : messagesUkrainian,
'tr' : messagesTurkish 'tr' : messagesTurkish,
'lv' : messagesLatvian
}; };
const locale = navigator.language.split(/[-_]/)[0]; // language without region code const locale = navigator.language.split(/[-_]/)[0]; // language without region code

View File

@ -0,0 +1,170 @@
{
"socket.disconnected": "Esat bezsaistē",
"socket.reconnecting": "Esat bezsaistē, tiek mēģināts pievienoties",
"socket.reconnected": "Esat atkārtoti pievienojies",
"socket.requestError": "Kļūme servera pieprasījumā",
"room.chooseRoom": "Ievadiet sapulces telpas nosaukumu (ID), kurai vēlaties pievienoties",
"room.cookieConsent": "Lai uzlabotu lietotāja pieredzi, šī vietne izmanto sīkfailus",
"room.consentUnderstand": "Es saprotu un piekrītu",
"room.joined": "Jūs esiet pievienojies sapulces telpai",
"room.cantJoin": "Nav iespējams pievienoties sapulces telpai",
"room.youLocked": "Jūs aizslēdzāt sapulces telpu",
"room.cantLock": "Nav iespējams aizslēgt sapulces telpu",
"room.youUnLocked": "Jūs atslēdzāt sapulces telpu",
"room.cantUnLock": "Nav iespējams atslēgt sapulces telpu",
"room.locked": "Sapulces telpa tagad ir AIZSLĒGTA",
"room.unlocked": "Sapulces telpa tagad ir ATSLĒGTA",
"room.newLobbyPeer": "Jauns dalībnieks ienācis uzgaidāmajā telpā",
"room.lobbyPeerLeft": "Dalībnieks uzgaidāmo telpu pameta",
"room.lobbyPeerChangedDisplayName": "Dalībnieks uzgaidāmajā telpā nomainīja vārdu uz {displayName}",
"room.lobbyPeerChangedPicture": "Dalībnieks uzgaidāmajā telpā nomainīja pašattēlu",
"room.setAccessCode": "Pieejas kods sapulces telpai aktualizēts",
"room.accessCodeOn": "Pieejas kods sapulces telpai tagad ir aktivēts",
"room.accessCodeOff": "Pieejas kods sapulces telpai tagad ir deaktivēts (atslēgts)",
"room.peerChangedDisplayName": "{oldDisplayName} pārsaucās par {displayName}",
"room.newPeer": "{displayName} pievienojās sapulces telpai",
"room.newFile": "Pieejams jauns fails",
"room.toggleAdvancedMode": "Pārslēgt uz advancēto režīmu",
"room.setDemocraticView": "Nomainīts izkārtojums uz demokrātisko skatu",
"room.setFilmStripView": "Nomainīts izkārtojums uz diapozitīvu (filmstrip) skatu",
"room.loggedIn": "Jūs esat ierakstījies (sistēmā)",
"room.loggedOut": "Jūs esat izrakstījies (no sistēmas)",
"room.changedDisplayName": "Jūsu vārds mainīts uz {displayName}",
"room.changeDisplayNameError": "Gadījās ķibele ar Jūsu vārda nomaiņu",
"room.chatError": "Nav iespējams nosūtīt tērziņa ziņu",
"room.aboutToJoin": "Jūs grasāties pievienoties sapulcei",
"room.roomId": "Sapulces telpas nosaukums (ID): {roomName}",
"room.setYourName": "Norādiet savu dalības vārdu un izvēlieties kā vēlaties pievienoties sapulcei:",
"room.audioOnly": "Vienīgi audio",
"room.audioVideo": "Audio & video",
"room.youAreReady": "Ok, Jūs esiet gatavi!",
"room.emptyRequireLogin": "Sapulces telpa ir tukša! Jūs varat Ierakstīties sistēmā, lai uzsāktu vadīt sapulci vai pagaidīt kamēr pievienojas sapulces rīkotājs/vadītājs",
"room.locketWait": "Sapulce telpa ir slēgta. Jūs atrodaties tās uzgaidāmajā telpā. Uzkavējieties, kamēr kāds Jūs sapulcē ielaiž ...",
"room.lobbyAdministration": "Uzgaidāmās telpas administrēšana",
"room.peersInLobby": "Dalībnieki uzgaidāmajā telpā",
"room.lobbyEmpty": "Pašreiz uzgaidāmajā telpā neviena nav",
"room.hiddenPeers": "{hiddenPeersCount, plural, one {participant} other {participants}}",
"room.me": "Es",
"room.spotlights": "Aktīvie (referējošie) dalībnieki",
"room.passive": "Pasīvie dalībnieki",
"room.videoPaused": "Šis video ir pauzēts",
"room.muteAll": "Noklusināt visus dalībnieku mikrofonus",
"room.stopAllVideo": "Izslēgt visu dalībnieku kameras",
"room.closeMeeting": "Beigt sapulci",
"room.clearChat": "Nodzēst visus tērziņus",
"room.clearFileSharing": "Notīrīt visus kopīgotos failus",
"room.speechUnsupported": "Jūsu pārlūks neatbalsta balss atpazīšanu",
"room.moderatoractions": "Moderatora rīcība",
"room.raisedHand": "{displayName} pacēla roku",
"room.loweredHand": "{displayName} nolaida roku",
"room.extraVideo": "Papildus video",
"me.mutedPTT": "Jūs esat noklusināts. Turiet taustiņu SPACE-BAR, lai runātu",
"roles.gotRole": "Jūs ieguvāt lomu: {role}",
"roles.lostRole": "Jūs zaudējāt lomu: {role}",
"tooltip.login": "Ierakstīties",
"tooltip.logout": "Izrakstīties",
"tooltip.admitFromLobby": "Ielaist no uzgaidāmās telpas",
"tooltip.lockRoom": "Aizslēgt sapulces telpu",
"tooltip.unLockRoom": "Atlēgt sapulces telpu",
"tooltip.enterFullscreen": "Aktivēt pilnekrāna režīmu",
"tooltip.leaveFullscreen": "Pamest pilnekrānu",
"tooltip.lobby": "Parādīt uzgaidāmo telpu",
"tooltip.settings": "Parādīt iestatījumus",
"tooltip.participants": "Parādīt dalībniekus",
"tooltip.kickParticipant": "Izvadīt (izspert) dalībnieku",
"tooltip.muteParticipant": "Noklusināt dalībnieku",
"tooltip.muteParticipantVideo": "Atslēgt dalībnieka video",
"tooltip.raisedHand": "Pacelt roku",
"label.roomName": "Sapulces telpas nosaukums (ID)",
"label.chooseRoomButton": "Turpināt",
"label.yourName": "Jūu vārds",
"label.newWindow": "Jauns logs",
"label.fullscreen": "Pilnekrāns",
"label.openDrawer": "Atvērt atvilkni",
"label.leave": "Pamest",
"label.chatInput": "Rakstiet tērziņa ziņu...",
"label.chat": "Tērzētava",
"label.filesharing": "Failu koplietošana",
"label.participants": "Dalībnieki",
"label.shareFile": "Koplietot failu",
"label.fileSharingUnsupported": "Failu koplietošana netiek atbalstīta",
"label.unknown": "Nezināms",
"label.democratic": "Demokrātisks skats",
"label.filmstrip": "Diapozitīvu (filmstrip) skats",
"label.low": "Zema",
"label.medium": "Vidēja",
"label.high": "Augsta (HD)",
"label.veryHigh": "Ļoti augsta (FHD)",
"label.ultra": "Ultra (UHD)",
"label.close": "Aizvērt",
"label.media": "Mediji",
"label.appearence": "Izskats",
"label.advanced": "Advancēts",
"label.addVideo": "Pievienot video",
"settings.settings": "Iestatījumi",
"settings.camera": "Kamera",
"settings.selectCamera": "Izvēlieties kameru (video ierīci)",
"settings.cantSelectCamera": "Nav iespējams lietot šo kameru (video ierīci)",
"settings.audio": "Skaņas ierīce",
"settings.selectAudio": "Izvēlieties skaņas ierīci",
"settings.cantSelectAudio": "Nav iespējams lietot šo skaņas (audio) ierīci",
"settings.resolution": "Iestatiet jūsu video izšķirtspēju",
"settings.layout": "Sapulces telpas izkārtojums",
"settings.selectRoomLayout": "Iestatiet sapulces telpas izkārtojumu",
"settings.advancedMode": "Advancētais režīms",
"settings.permanentTopBar": "Pastāvīga augšējā (ekrānaugšas) josla",
"settings.lastn": "Jums redzamo video/kameru skaits",
"settings.hiddenControls": "Slēpto mediju vadība",
"settings.notificationSounds": "Paziņojumu skaņas",
"filesharing.saveFileError": "Nav iespējams saglabāt failu",
"filesharing.startingFileShare": "Tiek mēģināts kopīgot failu",
"filesharing.successfulFileShare": "Fails sekmīgi kopīgots",
"filesharing.unableToShare": "Nav iespējams kopīgot failu",
"filesharing.error": "Atgadījās faila kopīgošanas kļūme",
"filesharing.finished": "Fails ir lejupielādēts",
"filesharing.save": "Saglabāt",
"filesharing.sharedFile": "{displayName} kopīgoja failu",
"filesharing.download": "Lejuplādēt",
"filesharing.missingSeeds": "Ja šis process aizņem ilgu laiku, iespējams nav neviena, kas sēklo (seed) šo torentu. Mēģiniet palūgt kādu atkārtoti augšuplādēt Jūsu gribēto failu.",
"devices.devicesChanged": "Jūsu ierīces pamainījās. Iestatījumu izvēlnē (dialogā) iestatiet jaunās ierīces.",
"device.audioUnsupported": "Skaņa (audio) netiek atbalstīta",
"device.activateAudio": "Iespējot/aktivēt mikrofonu (izejošo skaņu)",
"device.muteAudio": "Atslēgt/noklusināt mikrofonu (izejošo skaņu) ",
"device.unMuteAudio": "Ieslēgt mikrofonu (izejošo skaņu)",
"device.videoUnsupported": "Kamera (izejošais video) netiek atbalstīta",
"device.startVideo": "Ieslēgt kameru (izejošo video)",
"device.stopVideo": "Izslēgt kameru (izejošo video)",
"device.screenSharingUnsupported": "Ekrāna kopīgošana netiek atbalstīta",
"device.startScreenSharing": "Sākt ekrāna kopīgošanu",
"device.stopScreenSharing": "Beigt ekrāna kopīgošanu",
"devices.microphoneDisconnected": "Mikrofons atvienots",
"devices.microphoneError": "Atgadījās kļūme, piekļūstot jūsu mikrofonam",
"devices.microPhoneMute": "Mikrofons izslēgts/noklusināts",
"devices.micophoneUnMute": "Mikrofons ieslēgts",
"devices.microphoneEnable": "Mikrofons iespējots",
"devices.microphoneMuteError": "Nav iespējams izslēgt Jūsu mikrofonu",
"devices.microphoneUnMuteError": "Nav iespējams ieslēgt Jūsu mikrofonu",
"devices.screenSharingDisconnected" : "Ekrāna kopīgošana nenotiek (atvienota)",
"devices.screenSharingError": "Atgadījās kļūme, piekļūstot Jūsu ekrānam",
"devices.cameraDisconnected": "Kamera atvienota",
"devices.cameraError": "Atgadījās kļūme, piekļūstot Jūsu kamerai",
"moderator.clearChat": "Moderators nodzēsa tērziņus",
"moderator.clearFiles": "Moderators notīrīja failus",
"moderator.muteAudio": "Moderators noklusināja jūsu mikrofonu",
"moderator.muteVideo": "Moderators atslēdza jūsu kameru"
}

View File

@ -249,6 +249,8 @@ module.exports =
activateOnHostJoin : true, activateOnHostJoin : true,
// When set, maxUsersPerRoom defines how many users can join a single room. If not set, there is not limit. // When set, maxUsersPerRoom defines how many users can join a single room. If not set, there is not limit.
// maxUsersPerRoom : 20, // maxUsersPerRoom : 20,
// Room size before spreading to new router
routerScaleSize : 20,
// Mediasoup settings // Mediasoup settings
mediasoup : mediasoup :
{ {

View File

@ -39,6 +39,8 @@ class Peer extends EventEmitter
this._email = null; this._email = null;
this._routerId = null;
this._rtpCapabilities = null; this._rtpCapabilities = null;
this._raisedHand = false; this._raisedHand = false;
@ -238,6 +240,16 @@ class Peer extends EventEmitter
this._email = email; this._email = email;
} }
get routerId()
{
return this._routerId;
}
set routerId(routerId)
{
this._routerId = routerId;
}
get rtpCapabilities() get rtpCapabilities()
{ {
return this._rtpCapabilities; return this._rtpCapabilities;

View File

@ -31,6 +31,8 @@ const permissionsFromRoles =
...config.permissionsFromRoles ...config.permissionsFromRoles
}; };
const ROUTER_SCALE_SIZE = config.routerScaleSize || 20;
class Room extends EventEmitter class Room extends EventEmitter
{ {
/** /**
@ -38,32 +40,45 @@ class Room extends EventEmitter
* *
* @async * @async
* *
* @param {mediasoup.Worker} mediasoupWorker - The mediasoup Worker in which a new * @param {mediasoup.Worker} mediasoupWorkers - The mediasoup Worker in which a new
* mediasoup Router must be created. * mediasoup Router must be created.
* @param {String} roomId - Id of the Room instance. * @param {String} roomId - Id of the Room instance.
*/ */
static async create({ mediasoupWorker, roomId }) static async create({ mediasoupWorkers, roomId })
{ {
logger.info('create() [roomId:"%s"]', roomId); logger.info('create() [roomId:"%s"]', roomId);
// Router media codecs. // Router media codecs.
const mediaCodecs = config.mediasoup.router.mediaCodecs; const mediaCodecs = config.mediasoup.router.mediaCodecs;
// Create a mediasoup Router. const mediasoupRouters = new Map();
const mediasoupRouter = await mediasoupWorker.createRouter({ mediaCodecs });
// Create a mediasoup AudioLevelObserver. let firstRouter = null;
const audioLevelObserver = await mediasoupRouter.createAudioLevelObserver(
for (const worker of mediasoupWorkers)
{
const router = await worker.createRouter({ mediaCodecs });
if (!firstRouter)
firstRouter = router;
mediasoupRouters.set(router.id, router);
}
// Create a mediasoup AudioLevelObserver on first router
const audioLevelObserver = await firstRouter.createAudioLevelObserver(
{ {
maxEntries : 1, maxEntries : 1,
threshold : -80, threshold : -80,
interval : 800 interval : 800
}); });
return new Room({ roomId, mediasoupRouter, audioLevelObserver }); firstRouter = null;
return new Room({ roomId, mediasoupRouters, audioLevelObserver });
} }
constructor({ roomId, mediasoupRouter, audioLevelObserver }) constructor({ roomId, mediasoupRouters, audioLevelObserver })
{ {
logger.info('constructor() [roomId:"%s"]', roomId); logger.info('constructor() [roomId:"%s"]', roomId);
@ -98,8 +113,13 @@ class Room extends EventEmitter
this._peers = {}; this._peers = {};
// mediasoup Router instance. // Array of mediasoup Router instances.
this._mediasoupRouter = mediasoupRouter; this._mediasoupRouters = mediasoupRouters;
// The router we are currently putting peers in
this._routerIterator = this._mediasoupRouters.values();
this._currentRouter = this._routerIterator.next().value;
// mediasoup AudioLevelObserver. // mediasoup AudioLevelObserver.
this._audioLevelObserver = audioLevelObserver; this._audioLevelObserver = audioLevelObserver;
@ -122,8 +142,14 @@ class Room extends EventEmitter
this._closed = true; this._closed = true;
this._chatHistory = null;
this._fileHistory = null;
this._lobby.close(); this._lobby.close();
this._lobby = null;
// Close the peers. // Close the peers.
for (const peer in this._peers) for (const peer in this._peers)
{ {
@ -133,8 +159,19 @@ class Room extends EventEmitter
this._peers = null; this._peers = null;
// Close the mediasoup Router. // Close the mediasoup Routers.
this._mediasoupRouter.close(); for (const router of this._mediasoupRouters.values())
{
router.close();
}
this._routerIterator = null;
this._currentRouter = null;
this._mediasoupRouters.clear();
this._audioLevelObserver = null;
// Emit 'close' event. // Emit 'close' event.
this.emit('close'); this.emit('close');
@ -409,6 +446,9 @@ class Room extends EventEmitter
this._peers[peer.id] = peer; this._peers[peer.id] = peer;
// Assign routerId
peer.routerId = await this._getRouterId();
this._handlePeer(peer); this._handlePeer(peer);
if (returning) if (returning)
@ -568,11 +608,14 @@ class Room extends EventEmitter
async _handleSocketRequest(peer, request, cb) async _handleSocketRequest(peer, request, cb)
{ {
const router =
this._mediasoupRouters.get(peer.routerId);
switch (request.method) switch (request.method)
{ {
case 'getRouterRtpCapabilities': case 'getRouterRtpCapabilities':
{ {
cb(null, this._mediasoupRouter.rtpCapabilities); cb(null, router.rtpCapabilities);
break; break;
} }
@ -681,7 +724,7 @@ class Room extends EventEmitter
webRtcTransportOptions.enableTcp = true; webRtcTransportOptions.enableTcp = true;
} }
const transport = await this._mediasoupRouter.createWebRtcTransport( const transport = await router.createWebRtcTransport(
webRtcTransportOptions webRtcTransportOptions
); );
@ -780,6 +823,19 @@ class Room extends EventEmitter
const producer = const producer =
await transport.produce({ kind, rtpParameters, appData }); await transport.produce({ kind, rtpParameters, appData });
const pipeRouters = this._getRoutersToPipeTo(peer.routerId);
for (const [ routerId, destinationRouter ] of this._mediasoupRouters)
{
if (pipeRouters.includes(routerId))
{
await router.pipeToRouter({
producerId : producer.id,
router : destinationRouter
});
}
}
// Store the Producer into the Peer data Object. // Store the Producer into the Peer data Object.
peer.addProducer(producer.id, producer); peer.addProducer(producer.id, producer);
@ -1387,6 +1443,8 @@ class Room extends EventEmitter
producer.id producer.id
); );
const router = this._mediasoupRouters.get(producerPeer.routerId);
// Optimization: // Optimization:
// - Create the server-side Consumer. If video, do it paused. // - Create the server-side Consumer. If video, do it paused.
// - Tell its Peer about it and wait for its response. // - Tell its Peer about it and wait for its response.
@ -1397,7 +1455,7 @@ class Room extends EventEmitter
// NOTE: Don't create the Consumer if the remote Peer cannot consume it. // NOTE: Don't create the Consumer if the remote Peer cannot consume it.
if ( if (
!consumerPeer.rtpCapabilities || !consumerPeer.rtpCapabilities ||
!this._mediasoupRouter.canConsume( !router.canConsume(
{ {
producerId : producer.id, producerId : producer.id,
rtpCapabilities : consumerPeer.rtpCapabilities rtpCapabilities : consumerPeer.rtpCapabilities
@ -1609,6 +1667,84 @@ class Room extends EventEmitter
socket.emit('notification', { method, data }); socket.emit('notification', { method, data });
} }
} }
async _pipeProducersToNewRouter()
{
const peersToPipe =
Object.values(this._peers)
.filter((peer) => peer.routerId !== this._currentRouter.id);
for (const peer of peersToPipe)
{
const srcRouter = this._mediasoupRouters.get(peer.routerId);
for (const producerId of peer.producers.keys())
{
await srcRouter.pipeToRouter({
producerId,
router : this._currentRouter
});
}
}
}
async _getRouterId()
{
if (this._currentRouter)
{
const routerLoad =
Object.values(this._peers)
.filter((peer) => peer.routerId === this._currentRouter.id).length;
if (routerLoad >= ROUTER_SCALE_SIZE)
{
this._currentRouter = this._routerIterator.next().value;
if (this._currentRouter)
{
await this._pipeProducersToNewRouter();
return this._currentRouter.id;
}
}
else
{
return this._currentRouter.id;
}
}
return this._getLeastLoadedRouter();
}
// Returns an array of router ids we need to pipe to
_getRoutersToPipeTo(originRouterId)
{
return Object.values(this._peers)
.map((peer) => peer.routerId)
.filter((routerId, index, self) =>
routerId !== originRouterId && self.indexOf(routerId) === index
);
}
_getLeastLoadedRouter()
{
let load = Infinity;
let id;
for (const routerId of this._mediasoupRouters.keys())
{
const routerLoad =
Object.values(this._peers).filter((peer) => peer.routerId === routerId).length;
if (routerLoad < load)
{
id = routerId;
load = routerLoad;
}
}
return id;
}
} }
module.exports = Room; module.exports = Room;

View File

@ -644,9 +644,9 @@ async function getOrCreateRoom({ roomId })
{ {
logger.info('creating a new Room [roomId:"%s"]', roomId); logger.info('creating a new Room [roomId:"%s"]', roomId);
const mediasoupWorker = getMediasoupWorker(); // const mediasoupWorker = getMediasoupWorker();
room = await Room.create({ mediasoupWorker, roomId }); room = await Room.create({ mediasoupWorkers, roomId });
rooms.set(roomId, room); rooms.set(roomId, room);