edumeet: Bug: unable to join more then 19 peers in a room

Hi,

we have a problem that we are unable to join more then 19 persons in a meeting. When extra people try to join while not authenticated (they access lobby), I get list of blank users (pic in attachment). If more than 19 moderators try to access same room, they end up in an empty room on the same URL. Here is our entire server config:

const os = require('os');
const userRoles = require('../userRoles');

const {
	BYPASS_ROOM_LOCK,
	BYPASS_LOBBY
} = require('../access');

const {
	CHANGE_ROOM_LOCK,
	PROMOTE_PEER,
	MODIFY_ROLE,
	SEND_CHAT,
	MODERATE_CHAT,
	SHARE_AUDIO,
	SHARE_VIDEO,
	SHARE_SCREEN,
	EXTRA_VIDEO,
	SHARE_FILE,
	MODERATE_FILES,
	MODERATE_ROOM
} = require('../permissions');

const AwaitQueue = require('awaitqueue');
// const axios = require('axios');

module.exports =
{

	// Auth conf
	auth :
	{
		lti :
		{
			consumerKey    : 'xxxx',
			consumerSecret : 'xxxxx'
		},
		strategy : 'oidc',
		oidc:
		{
			// The issuer URL for OpenID Connect discovery
			// The OpenID Provider Configuration Document
			// could be discovered on:
			// issuerURL + '/.well-known/openid-configuration'

			issuerURL     : 'xxxxxxx,
			clientOptions :
			{
				client_id     : 'xxxxxxx',
				client_secret : 'xxxxxxx',
				scope         : 'openid profile email cn hrEduPersonAffiliation',
				// where client.example.com is your multiparty meeting server
				redirect_uri  : 'xxxxxxx'
			}

		}
	},
	// URI and key for requesting geoip-based TURN server closest to the client
	turnAPIKey    : 'xxxxxxx',
	turnAPIURI    : 'https://api.turn.geant.org/turn',
	turnAPIparams : {
		'uri_schema' 	: 'turn',
		'transport' 		: 'tcp',
		'ip_ver'    		: 'ipv4',
		'servercount'	: '2'
	},
	// Backup turnservers if REST fails or is not configured
	backupTurnServers : [
		{
			urls : [
				'turn:ltc.turn.geant.org:443?transport=tcp'
			],
			username   : 'xxxxxxx',
			credential : 'xxxxxxx'
		}
	],
	fileTracker  : 'wss://tracker.lab.vvc.niif.hu:443',
	//redisOptions : {},
	//redisOptions : { host: '10.8.62.11' },
	redisOptions : { host: 'xxxxxxx', prefix: 'meet_'},
	// session cookie secret
	cookieSecret : 'T0P-S3cR3t_cook!e',
	cookieName   : 'edumeet.sid',
	// if you use encrypted private key the set the passphrase
	tls          :
	{
		cert : `${__dirname}/../certs/mediasoup-demo.localhost.cert.pem`,
		// passphrase: 'key_password'
		key  : `${__dirname}/../certs/mediasoup-demo.localhost.key.pem`
	},
	// listening Host or IP 
	// If omitted listens on every IP. ("0.0.0.0" and "::")
	// listeningHost: 'localhost',
	// Listening port for https server.
	listeningPort         : 80,
	// Any http request is redirected to https.
	// Listening port for http server.
	//listeningRedirectPort : 80,
	// Listens only on http, only on listeningPort
	// listeningRedirectPort disabled
	// use case: loadbalancer backend
	httpOnly              : true,
	// WebServer/Express trust proxy config for httpOnly mode
	// You can find more info:
	//  - https://expressjs.com/en/guide/behind-proxies.html
	//  - https://www.npmjs.com/package/proxy-addr
	// use case: loadbalancer backend
	trustProxy            : '161.53.2.121, 161.53.2.122',
	//trustProxy		: '161.53.252.203',
	// This logger class will have the log function
	// called every time there is a room created or destroyed,
	// or peer created or destroyed. This would then be able
	// to log to a file or external service.
	StatusLogger          : class
	{
		constructor()
		{
			this._queue = new AwaitQueue();
		}

		// rooms: rooms object
		// peers: peers object
		// eslint-disable-next-line no-unused-vars
		async log({ rooms, peers })
		{
			this._queue.push(async () =>
			{
				// Do your logging in here, use queue to keep correct order
				// eslint-disable-next-line no-console
				// eslint-disable-next-line no-console
			})
				.catch((error) =>
				{
					// eslint-disable-next-line no-console
					console.log('error in log', error);
				});
		}
	},
	// This function will be called on successful login through oidc.
	// Use this function to map your oidc userinfo to the Peer object.
	// The roomId is equal to the room name.
	userMapping : async ({ peer, roomId, userinfo }) =>
	{
		if (userinfo.picture != null)
		{
			if (!userinfo.picture.match(/^http/g))
			{
				peer.picture = `data:image/jpeg;base64, ${userinfo.picture}`;
			}
			else
			{
				peer.picture = userinfo.picture;
			}
		}

		if (userinfo.nickname != null)
		{
			peer.displayName = userinfo.nickname;
		}

		if (userinfo.name != null)
		{
			peer.displayName = userinfo.name;
		}

		if (userinfo.email != null)
		{
			peer.email = userinfo.email;
		}

                if (userinfo.lti && userinfo.lti.roles && userinfo.lti.roles.includes('Administrator'))
		{
			peer.addRole(userRoles.AUTHENTICATED);
			peer.addRole(userRoles.ADMIN);
		}
		
		if (userinfo.lti && userinfo.lti.roles && userinfo.lti.roles.includes('Instructor'))
		{
			peer.addRole(userRoles.AUTHENTICATED);
			peer.addRole(userRoles.MODERATOR);
		}
		
		if (userinfo.lti && userinfo.lti.roles && userinfo.lti.roles.includes('Learner'))
		{
			peer.addRole(userRoles.AUTHENTICATED);
		}

		if (userinfo.hrEduPersonAffiliation)
		{
			peer.displayName = userinfo.cn[0];
			peer.addRole(userRoles.AUTHENTICATED);
			if (userinfo.hrEduPersonAffiliation.includes('djelatnik') && userinfo.email.endsWith('@srce.hr'))
			{
				peer.addRole(userRoles.MODERATOR);
			}
		}
		
	},
	// All users have the role "NORMAL" by default. Other roles need to be
	// added in the "userMapping" function. The following accesses and
	// permissions are arrays of roles. Roles can be changed in userRoles.js
	//
	// Example:
	// [ userRoles.MODERATOR, userRoles.AUTHENTICATED ]
	accessFromRoles : {
		// The role(s) will gain access to the room
		// even if it is locked (!)
		[BYPASS_ROOM_LOCK] : [ userRoles.MODERATOR ],
		// The role(s) will gain access to the room without
		// going into the lobby. If you want to restrict access to your
		// server to only directly allow authenticated users, you could
		// add the userRoles.AUTHENTICATED to the user in the userMapping
		// function, and change to BYPASS_LOBBY : [ userRoles.AUTHENTICATED ]
		[BYPASS_LOBBY]     : [ userRoles.AUTHENTICATED ]
	},
	permissionsFromRoles : {
		// The role(s) have permission to lock/unlock a room
		[CHANGE_ROOM_LOCK] : [ userRoles.MODERATOR ],
		// The role(s) have permission to promote a peer from the lobby
		[PROMOTE_PEER]		 : [ userRoles.MODERATOR ],
		// The role(s) have permission to give/remove other peers roles
		[MODIFY_ROLE]			 : [ userRoles.MODERATOR ],
		// The role(s) have permission to send chat messages
		[SEND_CHAT]				 : [ userRoles.NORMAL ],
		// The role(s) have permission to moderate chat
		[MODERATE_CHAT]		 : [ userRoles.MODERATOR ],
		// The role(s) have permission to share audio
		[SHARE_AUDIO]			 : [ userRoles.MODERATOR, userRoles.PRESENTER ],
		// The role(s) have permission to share video
		[SHARE_VIDEO]			 : [ userRoles.MODERATOR, userRoles.PRESENTER ],
		// The role(s) have permission to share screen
		[SHARE_SCREEN]		 : [ userRoles.MODERATOR, userRoles.PRESENTER ],
		// The role(s) have permission to produce extra video
		[EXTRA_VIDEO]			 : [ userRoles.MODERATOR, userRoles.PRESENTER ],
		// The role(s) have permission to share files
		[SHARE_FILE]			 : [ userRoles.MODERATOR, userRoles.PRESENTER ],
		// The role(s) have permission to moderate files
		[MODERATE_FILES]	 : [ userRoles.MODERATOR ],
		// The role(s) have permission to moderate room (e.g. kick user)
		[MODERATE_ROOM]		 : [ userRoles.MODERATOR ]
	},
	// Array of permissions. If no peer with the permission in question
	// is in the room, all peers are permitted to do the action. The peers
	// that are allowed because of this rule will not be able to do this 
	// action as soon as a peer with the permission joins. In this example
	// everyone will be able to lock/unlock room until a MODERATOR joins.
	//allowWhenRoleMissing : [ CHANGE_ROOM_LOCK ],
	// When truthy, the room will be open to all users when as long as there
	// are allready users in the room
	activateOnHostJoin   : false,
	// When set, maxUsersPerRoom defines how many users can join
	// a single room. If not set, there is no limit.
	// maxUsersPerRoom    : 20,
	// Room size before spreading to new router
	routerScaleSize      : 40,
	// Socket timout value
	requestTimeout       : 20000,
	// Socket retries when timeout
	requestRetries       : 3,
	// Mediasoup settings
	mediasoup            :
	{
		numWorkers : Object.keys(os.cpus()).length,
		// mediasoup Worker settings.
		worker     :
		{
			logLevel : 'warn',
			logTags  :
			[
				'info',
				'ice',
				'dtls',
				'rtp',
				'srtp',
				'rtcp'
			],
			rtcMinPort : 40000,
			rtcMaxPort : 49999
		},
		// mediasoup Router settings.
		router :
		{
			// Router media codecs.
			mediaCodecs :
			[
				{
					kind      : 'audio',
					mimeType  : 'audio/opus',
					clockRate : 48000,
					channels  : 2
				},
				{
					kind       : 'video',
					mimeType   : 'video/VP8',
					clockRate  : 90000,
					parameters :
					{
						'x-google-start-bitrate' : 1000
					}
				},
				{
					kind       : 'video',
					mimeType   : 'video/VP9',
					clockRate  : 90000,
					parameters :
					{
						'profile-id'             : 2,
						'x-google-start-bitrate' : 1000
					}
				},
				{
					kind       : 'video',
					mimeType   : 'video/h264',
					clockRate  : 90000,
					parameters :
					{
						'packetization-mode'      : 1,
						'profile-level-id'        : '4d0032',
						'level-asymmetry-allowed' : 1,
						'x-google-start-bitrate'  : 1000
					}
				},
				{
					kind       : 'video',
					mimeType   : 'video/h264',
					clockRate  : 90000,
					parameters :
					{
						'packetization-mode'      : 1,
						'profile-level-id'        : '42e01f',
						'level-asymmetry-allowed' : 1,
						'x-google-start-bitrate'  : 1000
					}
				}
			]
		},
		// mediasoup WebRtcTransport settings.
		webRtcTransport :
		{
			listenIps :
			[
				// change 192.0.2.1 IPv4 to your server's IPv4 address!!
				{ ip: '161.53.3.177', announcedIp: null }

				// Can have multiple listening interfaces
				// change 2001:DB8::1 IPv6 to your server's IPv6 address!!
				// { ip: '2001:DB8::1', announcedIp: null }
			],
			initialAvailableOutgoingBitrate : 1000000,
			minimumAvailableOutgoingBitrate : 600000,
			// Additional options that are not part of WebRtcTransportOptions.
			maxIncomingBitrate              : 1500000
		}
	}
	// Prometheus exporter
	/*
	prometheus: {
		deidentify: false, // deidentify IP addresses
		numeric: false, // show numeric IP addresses
		port: 8889, // allocated port
		quiet: false // include fewer labels
	}
	*/
};

We have 3 servers in a cluster, and are using develop branch some 2 weeks old (with b7f07dcce9466204a901122dc881bc58af28b250 revision).

Has anyone experienced this kind of problem and how to fix it?

Best, Zvonko

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 25

Most upvoted comments

Hell, just looked at HAProxy config and yes, we did have 20 connections limit -_- (probably copy&paste from https://github.com/edumeet/edumeet/blob/master/HAproxy.md and forgot to update) server meet01.srce.hr XXX.XXX.XXX.XXX:80 check maxconn 20 verify none

Even on our Moodle servers we have 300 connections, so it was a mistake on our part. Tomorrow we will test with a new maxconn settings and will let you know. Thanks @Astagor and @so010 for your help 😃