diff --git a/app/README.md b/app/README.md index 99a123b1..74e5ac54 100644 --- a/app/README.md +++ b/app/README.md @@ -19,7 +19,7 @@ var config = | loginEnabled | If the login is enabled. | `"boolean"` | ``false`` | | developmentPort | The development server listening port. | `"port"` | ``3443`` | | productionPort | The production server listening port. | `"port"` | ``443`` | -| serverHostname | If the server component runs on a different host than the app you can specify the host name. | `"*"` | ``null`` | +| serverHostname | If the server component runs on a different host than the app you can specify the host name. | `"string"` | ``""`` | | supportedBrowsers | Supported browsers version in bowser satisfy format. | `"object"` | ``{ "windows": { "internet explorer": ">12", "microsoft edge": ">18" }, "microsoft edge": ">18", "safari": ">12", "firefox": ">=60", "chrome": ">=74", "chromium": ">=74", "opera": ">=62", "samsung internet for android": ">=11.1.1.52"}`` | | networkPriorities | Network priorities. | `"object"` | ``{ "audio": "high", "mainVideo": "high", "additionalVideos": "medium", "screenShare": "medium"}`` | | viewAspectRatio | The aspect ratio of the videos as shown on the screen. | `"float"` | ``1.777`` | @@ -32,11 +32,11 @@ var config = | simulcast | Enable or disable simulcast for webcam video. | `"boolean"` | ``true`` | | simulcastSharing | Enable or disable simulcast for screen sharing video. | `"boolean"` | ``false`` | | simulcastProfiles | Define different encodings for various resolutions of the video. | `"object"` | ``{ "320": [ { "scaleResolutionDownBy": 1, "maxBitRate": 250000 } ], "640": [ { "scaleResolutionDownBy": 2, "maxBitRate": 250000 }, { "scaleResolutionDownBy": 1, "maxBitRate": 900000 } ], "1280": [ { "scaleResolutionDownBy": 4, "maxBitRate": 250000 }, { "scaleResolutionDownBy": 2, "maxBitRate": 900000 }, { "scaleResolutionDownBy": 1, "maxBitRate": 3000000 } ], "1920": [ { "scaleResolutionDownBy": 4, "maxBitRate": 750000 }, { "scaleResolutionDownBy": 2, "maxBitRate": 1500000 }, { "scaleResolutionDownBy": 1, "maxBitRate": 4000000 } ], "3840": [ { "scaleResolutionDownBy": 4, "maxBitRate": 1500000 }, { "scaleResolutionDownBy": 2, "maxBitRate": 4000000 }, { "scaleResolutionDownBy": 1, "maxBitRate": 10000000 } ]}`` | -| adaptiveScalingFactor | The adaptive spatial layer selection scaling factor. | | ``0.75`` | +| adaptiveScalingFactor | The adaptive spatial layer selection scaling factor in the range [0.5, 1.0]. | | ``0.75`` | | audioOutputSupportedBrowsers | White listing browsers that support audio output device selection. | `"array"` | ``[ "chrome", "opera"]`` | | requestTimeout | The Socket.io request timeout. | `"nat"` | ``20000`` | | requestRetries | The Socket.io request maximum retries. | `"nat"` | ``3`` | -| transportOptions | | `"object"` | ``{ "tcp": true}`` | +| transportOptions | The Mediasoup transport options. | `"object"` | ``{ "tcp": true}`` | | autoGainControl | Auto gain control enabled. | `"boolean"` | ``true`` | | echoCancellation | Echo cancellation enabled. | `"boolean"` | ``true`` | | noiseSuppression | Noise suppression enabled. | `"boolean"` | ``true`` | @@ -51,35 +51,46 @@ var config = | opusPtime | The OPUS packet time. | `[ 3, 5, 10, 20, 30, 40, 50, 60]` | ``20`` | | opusMaxPlaybackRate | The OPUS playback rate. | `[ 8000, 16000, 24000, 44100, 48000]` | ``48000`` | | audioPreset | The audio preset | `"string"` | ``"conference"`` | -| audioPresets | The audio presets. | `"*"` | ``{ "conference": { "name": "Conference audio", "autoGainControl": true, "echoCancellation": true, "noiseSuppression": true, "voiceActivatedUnmute": false, "noiseThreshold": -60, "sampleRate": 48000, "channelCount": 1, "sampleSize": 16, "opusStereo": false, "opusDtx": true, "opusFec": true, "opusPtime": 20, "opusMaxPlaybackRate": 48000 }, "hifi": { "name": "HiFi streaming", "autoGainControl": false, "echoCancellation": false, "noiseSuppression": false, "voiceActivatedUnmute": false, "noiseThreshold": -60, "sampleRate": 48000, "channelCount": 2, "sampleSize": 16, "opusStereo": true, "opusDtx": false, "opusFec": true, "opusPtime": 60, "opusMaxPlaybackRate": 48000 }}`` | -| autoMuteThreshold | Set the max number of participants in one room that join unmuted. | `"nat"` | ``4`` | +| audioPresets | The audio presets. | `"object"` | ``{ "conference": { "name": "Conference audio", "autoGainControl": true, "echoCancellation": true, "noiseSuppression": true, "voiceActivatedUnmute": false, "noiseThreshold": -60, "sampleRate": 48000, "channelCount": 1, "sampleSize": 16, "opusStereo": false, "opusDtx": true, "opusFec": true, "opusPtime": 20, "opusMaxPlaybackRate": 48000 }, "hifi": { "name": "HiFi streaming", "autoGainControl": false, "echoCancellation": false, "noiseSuppression": false, "voiceActivatedUnmute": false, "noiseThreshold": -60, "sampleRate": 48000, "channelCount": 2, "sampleSize": 16, "opusStereo": true, "opusDtx": false, "opusFec": true, "opusPtime": 60, "opusMaxPlaybackRate": 48000 }}`` | +| centralAudioOptions | The default audio preset. | `"object"` | ``{ "autoGainControl": true, "echoCancellation": true, "noiseSuppression": true, "voiceActivatedUnmute": false, "noiseThreshold": -60, "sampleRate": 48000, "channelCount": 1, "sampleSize": 16, "opusStereo": false, "opusDtx": true, "opusFec": true, "opusPtime": 20, "opusMaxPlaybackRate": 48000, "volume": 1}`` | +| autoMuteThreshold | It sets the maximum number of participants in one room that can join unmuted. +The next participant will join automatically muted. +Set it to 0 to auto mute all. +Set it to negative (-1) to never automatically auto mute but use it with caution, +full mesh audio strongly decrease room capacity! | `"nat"` | ``4`` | | background | The page background image URL | `"string"` | ``"images/background.jpg"`` | -| defaultLayout | The default layout | `[ "democratic", "filmstrip"]` | ``"democratic"`` | -| buttonControlBar | If true, will show media control buttons in separate control bar, not in the ME container. | `"boolean"` | ``false`` | +| defaultLayout | The default layout. | `[ "democratic", "filmstrip"]` | ``"democratic"`` | +| buttonControlBar | If true, the media control buttons will be shown in separate control bar, not in the ME container. | `"boolean"` | ``false`` | | drawerOverlayed | If false, will push videos away to make room for side drawer. If true, will overlay side drawer over videos. | `"boolean"` | ``true`` | -| notificationPosition | The position of notifications. | `[ "left", "right"]` | ``"right"`` | -| notificationSounds | Set the notifications sounds. | `"object"` | ``{ "chatMessage": { "play": "/sounds/notify-chat.mp3" }, "raisedHand": { "play": "/sounds/notify-hand.mp3" }, "default": { "delay": 5000, "play": "/sounds/notify.mp3" }}`` | -| hideTimeout | Timeout for autohiding topbar and button control bar. | `"int"` | ``3000`` | -| lastN | The max number of participant that will be visible in as speaker. | `"nat"` | ``4`` | -| mobileLastN | The max number of participant that will be visible in as speaker for mobile users. | `"nat"` | ``1`` | +| notificationPosition | The position of the notifications. | `[ "left", "right"]` | ``"right"`` | +| notificationSounds | It sets the notifications sounds. +Valid keys are: +'parkedPeer', 'parkedPeers', 'raisedHand', 'chatMessage', 'sendFile', 'newPeer' and 'default'. + +Not defining a key is equivalent to using the default notification sound. +Setting 'play' to null disables the sound notification. + | `"object"` | ``{ "chatMessage": { "play": "/sounds/notify-chat.mp3" }, "raisedHand": { "play": "/sounds/notify-hand.mp3" }, "default": { "delay": 5000, "play": "/sounds/notify.mp3" }}`` | +| hideTimeout | Timeout for auto hiding the topbar and the buttons control bar. | `"int"` | ``3000`` | +| lastN | The maximum number of participants that will be visible in as speaker. | `"nat"` | ``4`` | +| mobileLastN | The maximum number of participants that will be visible in as speaker for mobile users. | `"nat"` | ``1`` | | maxLastN | The highest number of lastN the user can select manually in the user interface. | `"nat"` | ``5`` | -| lockLastN | If truthy, users can NOT change number of speakers visible. | `"boolean"` | ``false`` | -| logo | If not null, it shows the logo loaded from URL, else it shows the title. | `"url"` | ``"images/logo.edumeet.svg"`` | +| lockLastN | If true, the users can not change the number of visible speakers. | `"boolean"` | ``false`` | +| logo | If not null, it shows the logo loaded from the specified URL, otherwise it shows the title. | `"url"` | ``"images/logo.edumeet.svg"`` | | title | The title to show if the logo is not specified. | `"string"` | ``"edumeet"`` | | supportUrl | The service & Support URL; if `null`, it will be not displayed on the about dialogs. | `"url"` | ``"https://support.example.com"`` | -| privacyUrl | The privacy and data protection URL or path. | `"string"` | ``"privacy/privacy.html"`` | -| theme.palette.primary.main | undefined | `"string"` | ``"#313131"`` | -| theme.overrides.MuiAppBar.colorPrimary.backgroundColor | undefined | `"string"` | ``"#313131"`` | -| theme.overrides.MuiButton.containedPrimary.backgroundColor | undefined | `"string"` | ``"#5F9B2D"`` | -| theme.overrides.MuiButton.containedPrimary.&:hover.backgroundColor | undefined | `"string"` | ``"#5F9B2D"`` | -| theme.overrides.MuiButton.containedSecondary.backgroundColor | undefined | `"string"` | ``"#f50057"`` | -| theme.overrides.MuiButton.containedSecondary.&:hover.backgroundColor | undefined | `"string"` | ``"#f50057"`` | -| theme.overrides.MuiFab.primary.backgroundColor | undefined | `"string"` | ``"#5F9B2D"`` | -| theme.overrides.MuiFab.primary.&:hover.backgroundColor | undefined | `"string"` | ``"#5F9B2D"`` | -| theme.overrides.MuiFab.secondary.backgroundColor | undefined | `"string"` | ``"#f50057"`` | -| theme.overrides.MuiFab.secondary.&:hover.backgroundColor | undefined | `"string"` | ``"#f50057"`` | -| theme.overrides.MuiBadge.colorPrimary.backgroundColor | undefined | `"string"` | ``"#5F9B2D"`` | -| theme.overrides.MuiBadge.colorPrimary.&:hover.backgroundColor | undefined | `"string"` | ``"#518029"`` | +| privacyUrl | The privacy and data protection external URL or local HTML path. | `"string"` | ``"privacy/privacy.html"`` | +| theme.palette.primary.main | The palette main color. | `"string"` | ``"#313131"`` | +| theme.overrides.MuiAppBar.colorPrimary.backgroundColor | The app bar background color. | `"string"` | ``"#313131"`` | +| theme.overrides.MuiButton.containedPrimary.backgroundColor | The primary buttons background color. | `"string"` | ``"#5F9B2D"`` | +| theme.overrides.MuiButton.containedPrimary.&:hover.backgroundColor | The primary buttons background color when in hover state. | `"string"` | ``"#5F9B2D"`` | +| theme.overrides.MuiButton.containedSecondary.backgroundColor | The secondary buttons background color. | `"string"` | ``"#f50057"`` | +| theme.overrides.MuiButton.containedSecondary.&:hover.backgroundColor | The secondary buttons background color when in hover state. | `"string"` | ``"#f50057"`` | +| theme.overrides.MuiFab.primary.backgroundColor | The primary Fab buttons background color. | `"string"` | ``"#5F9B2D"`` | +| theme.overrides.MuiFab.primary.&:hover.backgroundColor | The primary Fab buttons background color when in hover state. | `"string"` | ``"#5F9B2D"`` | +| theme.overrides.MuiFab.secondary.backgroundColor | The secondary Fab buttons background color. | `"string"` | ``"#f50057"`` | +| theme.overrides.MuiFab.secondary.&:hover.backgroundColor | The secondary Fab buttons background color when in hover state. | `"string"` | ``"#f50057"`` | +| theme.overrides.MuiBadge.colorPrimary.backgroundColor | The badges background color. | `"string"` | ``"#5F9B2D"`` | +| theme.overrides.MuiBadge.colorPrimary.&:hover.backgroundColor | The badges background color when in hover state. | `"string"` | ``"#518029"`` | | theme.typography.useNextVariants | undefined | `"boolean"` | ``true`` | diff --git a/app/package.json b/app/package.json index 714442da..692817bc 100644 --- a/app/package.json +++ b/app/package.json @@ -76,7 +76,7 @@ "lint": "eslint -c .eslintrc.json --ext .js,.ts,.tsx src", "lint:fix": "eslint -c .eslintrc.json --ext .js,.ts,.tsx src --fix", "format": "prettier --write 'src/**/*.{ts,tsx}'", - "gen-config-docs": "node --loader ts-node/esm src/config.ts" + "gen-config-docs": "node --loader ts-node/esm src/config.ts && eslint -c .eslintrc.json public/config/config.example.js --fix" }, "browserslist": [ ">0.2%", diff --git a/app/public/config/config.example.js b/app/public/config/config.example.js index 3f4e6a5a..ebc9353f 100644 --- a/app/public/config/config.example.js +++ b/app/public/config/config.example.js @@ -1,29 +1,33 @@ +/** + * Edumeet App Configuration + * + * The configuration documentation is available also: + * - in the app/README.md file in the source tree + * - visiting the /config page in a running instance + */ + // eslint-disable-next-line -var config = -{ - loginEnabled : false, +var config = { + + /* If the login is enabled. */ + loginEnabled : false, + + /* The development server listening port. */ developmentPort : 3443, - productionPort : 443, - /* - // If the server component runs on a different host than the app - // you can uncomment the following line and specify the host name. - serverHostname : 'external-server.com', - */ + /* The production server listening port. */ + productionPort : 443, - /** - * Supported browsers version - * in bowser satisfy format. - * See more: - * https://www.npmjs.com/package/bowser#filtering-browsers - * Otherwise you got a unsupported browser page - */ - supportedBrowsers : - { + /* If the server component runs on a different host than the app you can specify the host name. */ + serverHostname : '', + + /* Supported browsers version in bowser satisfy format. */ + supportedBrowsers : { 'windows' : { 'internet explorer' : '>12', 'microsoft edge' : '>18' }, + 'microsoft edge' : '>18', 'safari' : '>12', 'firefox' : '>=60', 'chrome' : '>=74', @@ -32,304 +36,335 @@ var config = 'samsung internet for android' : '>=11.1.1.52' }, - /** - * Network priorities - * DSCP bits set by browser according this priority values. - * ("high" means actually: EF for audio, and AF41 for Video in chrome) - * https://en.wikipedia.org/wiki/Differentiated_services - */ - networkPriorities : - { + /* Network priorities. */ + networkPriorities : { 'audio' : 'high', 'mainVideo' : 'high', 'additionalVideos' : 'medium', 'screenShare' : 'medium' }, - /** - * Resolutions: - * - * low ~ 320x240 - * medium ~ 640x480 - * high ~ 1280x720 - * veryhigh ~ 1920x1080 - * ultra ~ 3840x2560 - * - **/ + /* The aspect ratio of the videos as shown on the screen. */ + viewAspectRatio : 1.777, - /** - * Frame rates: - * - * 1, 5, 10, 15, 20, 25, 30 - * - **/ - // The aspect ratio of the videos as shown on - // the screen. This is changeable in client settings. - // This value must match one of the defined values in - // viewAspectRatios EXACTLY (e.g. 1.333) - viewAspectRatio : 1.777, - // These are the selectable aspect ratios in the settings - viewAspectRatios : [ { - value : 1.333, // 4 / 3 - label : '4 : 3' - }, { - value : 1.777, // 16 / 9 - label : '16 : 9' - } ], - // The aspect ratio of the video from the camera - // this is not changeable in settings, only config - videoAspectRatio : 1.777, - resolution : 'medium', - frameRate : 15, - screenResolution : 'veryhigh', + /* The selectable aspect ratios in the settings. */ + viewAspectRatios : [ + { + 'value' : 1.333, + 'label' : '4 : 3' + }, + { + 'value' : 1.777, + 'label' : '16 : 9' + } + ], + + /* The aspect ratio of the video from the camera. */ + videoAspectRatio : 1.777, + + /* The default video camera capture resolution. */ + resolution : 'medium', + + /* The default video camera capture framerate. */ + frameRate : 15, + + /* The default screen sharing resolution. */ + screenResolution : 'veryhigh', + + /* The default screen sharing framerate. */ screenSharingFrameRate : 5, - // Enable or disable simulcast for webcam video - simulcast : true, - // Enable or disable simulcast for screen sharing video - simulcastSharing : false, - // Define different encodings for various resolutions of the video - simulcastProfiles : - { - 3840 : - [ - { scaleResolutionDownBy: 4, maxBitRate: 1500000 }, - { scaleResolutionDownBy: 2, maxBitRate: 4000000 }, - { scaleResolutionDownBy: 1, maxBitRate: 10000000 } + + /* Enable or disable simulcast for webcam video. */ + simulcast : true, + + /* Enable or disable simulcast for screen sharing video. */ + simulcastSharing : false, + + /* Define different encodings for various resolutions of the video. */ + simulcastProfiles : { + '320' : [ + { + 'scaleResolutionDownBy' : 1, + 'maxBitRate' : 250000 + } ], - 1920 : - [ - { scaleResolutionDownBy: 4, maxBitRate: 750000 }, - { scaleResolutionDownBy: 2, maxBitRate: 1500000 }, - { scaleResolutionDownBy: 1, maxBitRate: 4000000 } + '640' : [ + { + 'scaleResolutionDownBy' : 2, + 'maxBitRate' : 250000 + }, + { + 'scaleResolutionDownBy' : 1, + 'maxBitRate' : 900000 + } ], - 1280 : - [ - { scaleResolutionDownBy: 4, maxBitRate: 250000 }, - { scaleResolutionDownBy: 2, maxBitRate: 900000 }, - { scaleResolutionDownBy: 1, maxBitRate: 3000000 } + '1280' : [ + { + 'scaleResolutionDownBy' : 4, + 'maxBitRate' : 250000 + }, + { + 'scaleResolutionDownBy' : 2, + 'maxBitRate' : 900000 + }, + { + 'scaleResolutionDownBy' : 1, + 'maxBitRate' : 3000000 + } ], - 640 : - [ - { scaleResolutionDownBy: 2, maxBitRate: 250000 }, - { scaleResolutionDownBy: 1, maxBitRate: 900000 } + '1920' : [ + { + 'scaleResolutionDownBy' : 4, + 'maxBitRate' : 750000 + }, + { + 'scaleResolutionDownBy' : 2, + 'maxBitRate' : 1500000 + }, + { + 'scaleResolutionDownBy' : 1, + 'maxBitRate' : 4000000 + } ], - 320 : - [ - { scaleResolutionDownBy: 1, maxBitRate: 250000 } + '3840' : [ + { + 'scaleResolutionDownBy' : 4, + 'maxBitRate' : 1500000 + }, + { + 'scaleResolutionDownBy' : 2, + 'maxBitRate' : 4000000 + }, + { + 'scaleResolutionDownBy' : 1, + 'maxBitRate' : 10000000 + } ] }, - // The adaptive spatial layer selection scaling factor (in the range [0.5, 1.0]) - // example: - // with level width=640px, the minimum width required to trigger the - // level change will be: 640 * 0.75 = 480px + /* The adaptive spatial layer selection scaling factor in the range [0.5, 1.0]. */ adaptiveScalingFactor : 0.75, - /** - * White listing browsers that support audio output device selection. - * It is not yet fully implemented in Firefox. - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1498512 - */ - audioOutputSupportedBrowsers : - [ + /* White listing browsers that support audio output device selection. */ + audioOutputSupportedBrowsers : [ 'chrome', 'opera' ], - // Socket.io request timeout - requestTimeout : 20000, - requestRetries : 3, - transportOptions : - { - tcp : true - }, - // defaults for audio setting on new clients / can be customized and overruled from client side - autoGainControl : true, // default : true - echoCancellation : true, // default : true - noiseSuppression : true, // default : true - // Automatically unmute speaking above noisThereshold - voiceActivatedUnmute : false, // default : false - // This is only for voiceActivatedUnmute and audio-indicator - noiseThreshold : -60, // default -60 - // Audio options for now only centrally from config file: - centralAudioOptions : - { - // will not eat that much bandwith thanks to opus - sampleRate : 48000, // default : 48000 and don't go higher - // usually mics are mono so this saves bandwidth - channelCount : 1, // default : 1 - volume : 1.0, // default : 1.0 - sampleSize : 16, // default : 16 - // usually mics are mono so this saves bandwidth - opusStereo : false, // default : false - opusDtx : true, // default : true / will save bandwidth - opusFec : true, // default : true / forward error correction - opusPtime : '20', // default : 20 / minimum packet time (3, 5, 10, 20, 40, 60, 120) - opusMaxPlaybackRate : 48000 // default : 48000 and don't go higher + + /* The Socket.io request timeout. */ + requestTimeout : 20000, + + /* The Socket.io request maximum retries. */ + requestRetries : 3, + + /* The Mediasoup transport options. */ + transportOptions : { + 'tcp' : true }, - /** - * Set max number participants in one room that join - * unmuted. Next participant will join automatically muted - * Default value is 4 - * - * Set it to 0 to auto mute all, - * Set it to negative (-1) to never automatically auto mute - * but use it with caution - * full mesh audio strongly decrease room capacity! - */ - autoMuteThreshold : 4, - background : 'images/background.jpg', - defaultLayout : 'democratic', // democratic, filmstrip - // If true, will show media control buttons in separate - // control bar, not in the ME container. - buttonControlBar : false, - // If false, will push videos away to make room for side - // drawer. If true, will overlay side drawer over videos - drawerOverlayed : true, - // Position of notifications + /* Auto gain control enabled. */ + autoGainControl : true, + + /* Echo cancellation enabled. */ + echoCancellation : true, + + /* Noise suppression enabled. */ + noiseSuppression : true, + + /* Automatically unmute speaking above noiseThreshold. */ + voiceActivatedUnmute : false, + + /* This is only for voiceActivatedUnmute and audio-indicator. */ + noiseThreshold : -60, + + /* The audio sample rate. */ + sampleRate : 48000, + + /* The audio channels count. */ + channelCount : 1, + + /* The audio sample size count. */ + sampleSize : 16, + + /* If OPUS FEC stereo be enabled. */ + opusStereo : false, + + /* If OPUS DTX should be enabled. */ + opusDtx : true, + + /* If OPUS FEC should be enabled. */ + opusFec : true, + + /* The OPUS packet time. */ + opusPtime : 20, + + /* The OPUS playback rate. */ + opusMaxPlaybackRate : 48000, + + /* The audio preset */ + audioPreset : 'conference', + + /* The audio presets. */ + audioPresets : { + 'conference' : { + 'name' : 'Conference audio', + 'autoGainControl' : true, + 'echoCancellation' : true, + 'noiseSuppression' : true, + 'voiceActivatedUnmute' : false, + 'noiseThreshold' : -60, + 'sampleRate' : 48000, + 'channelCount' : 1, + 'sampleSize' : 16, + 'opusStereo' : false, + 'opusDtx' : true, + 'opusFec' : true, + 'opusPtime' : 20, + 'opusMaxPlaybackRate' : 48000 + }, + 'hifi' : { + 'name' : 'HiFi streaming', + 'autoGainControl' : false, + 'echoCancellation' : false, + 'noiseSuppression' : false, + 'voiceActivatedUnmute' : false, + 'noiseThreshold' : -60, + 'sampleRate' : 48000, + 'channelCount' : 2, + 'sampleSize' : 16, + 'opusStereo' : true, + 'opusDtx' : false, + 'opusFec' : true, + 'opusPtime' : 60, + 'opusMaxPlaybackRate' : 48000 + } + }, + + /* The default audio preset. */ + centralAudioOptions : { + 'autoGainControl' : true, + 'echoCancellation' : true, + 'noiseSuppression' : true, + 'voiceActivatedUnmute' : false, + 'noiseThreshold' : -60, + 'sampleRate' : 48000, + 'channelCount' : 1, + 'sampleSize' : 16, + 'opusStereo' : false, + 'opusDtx' : true, + 'opusFec' : true, + 'opusPtime' : 20, + 'opusMaxPlaybackRate' : 48000, + 'volume' : 1 + }, + + /* It sets the maximum number of participants in one room that can join unmuted. +The next participant will join automatically muted. +Set it to 0 to auto mute all. +Set it to negative (-1) to never automatically auto mute but use it with caution, +full mesh audio strongly decrease room capacity! */ + autoMuteThreshold : 4, + + /* The page background image URL */ + background : 'images/background.jpg', + + /* The default layout. */ + defaultLayout : 'democratic', + + /* If true, the media control buttons will be shown in separate control bar, not in the ME container. */ + buttonControlBar : false, + + /* If false, will push videos away to make room for side drawer. If true, will overlay side drawer over videos. */ + drawerOverlayed : true, + + /* The position of the notifications. */ notificationPosition : 'right', - /** - * Set the notificationSounds. Valid keys are: - * 'parkedPeer', 'parkedPeers', 'raisedHand', 'chatMessage', - * 'sendFile', 'newPeer' and 'default'. - * - * Not defining a key is equivalent to using the default notification sound. - * Setting 'play' to null disables the sound notification. - */ + /* It sets the notifications sounds. +Valid keys are: +'parkedPeer', 'parkedPeers', 'raisedHand', 'chatMessage', 'sendFile', 'newPeer' and 'default'. + +Not defining a key is equivalent to using the default notification sound. +Setting 'play' to null disables the sound notification. + */ notificationSounds : { - chatMessage : { - play : '/sounds/notify-chat.mp3' + 'chatMessage' : { + 'play' : '/sounds/notify-chat.mp3' }, - raisedHand : { - play : '/sounds/notify-hand.mp3' + 'raisedHand' : { + 'play' : '/sounds/notify-hand.mp3' }, - default : { - delay : 5000, // minimum delay between alert sounds [ms] - play : '/sounds/notify.mp3' + 'default' : { + 'delay' : 5000, + 'play' : '/sounds/notify.mp3' } }, - // Timeout for autohiding topbar and button control bar + + /* Timeout for auto hiding the topbar and the buttons control bar. */ hideTimeout : 3000, - // max number of participant that will be visible in - // as speaker - lastN : 4, + + /* The maximum number of participants that will be visible in as speaker. */ + lastN : 4, + + /* The maximum number of participants that will be visible in as speaker for mobile users. */ mobileLastN : 1, - // Highest number of lastN the user can select manually in - // userinteface - maxLastN : 5, - // If truthy, users can NOT change number of speakers visible - lockLastN : false, - // Show logo if "logo" is not null, else show title - // Set logo file name using logo.* pattern like "logo.png" to not track it by git - logo : 'images/logo.edumeet.svg', - title : 'edumeet', - // Service & Support URL - // if not set then not displayed on the about modals - supportUrl : 'https://support.example.com', - // Privacy and dataprotection URL or path - // by default privacy/privacy.html - // that is a placeholder for your policies - // - // but an external url could be also used here - privacyUrl : 'privacy/privacy.html', - theme : - { - palette : - { - primary : - { - main : '#313131' - } - }, - overrides : - { - MuiAppBar : - { - colorPrimary : - { - backgroundColor : '#313131' - } - }, - MuiButton : - { - containedPrimary : - { - backgroundColor : '#5F9B2D', - '&:hover' : - { - backgroundColor : '#5F9B2D' - } - }, - containedSecondary : - { - backgroundColor : '#f50057', - '&:hover' : - { - backgroundColor : '#f50057' - } - } - }, + /* The highest number of lastN the user can select manually in the user interface. */ + maxLastN : 5, - /* - MuiIconButton : - { - colorPrimary : - { - backgroundColor : '#5F9B2D', - '&:hover' : - { - backgroundColor : '#5F9B2D' - } - }, - colorSecondary : - { - backgroundColor : '#f50057', - '&:hover' : - { - backgroundColor : '#f50057' - } - } + /* If true, the users can not change the number of visible speakers. */ + lockLastN : false, - }, - */ + /* If not null, it shows the logo loaded from the specified URL, otherwise it shows the title. */ + logo : 'images/logo.edumeet.svg', - MuiFab : - { - primary : - { - backgroundColor : '#5F9B2D', - '&:hover' : - { - backgroundColor : '#5F9B2D' - } - }, - secondary : - { - backgroundColor : '#f50057', - '&:hover' : - { - backgroundColor : '#f50057' - } - } + /* The title to show if the logo is not specified. */ + title : 'edumeet', - }, - MuiBadge : - { - colorPrimary : - { - backgroundColor : '#5F9B2D', - '&:hover' : - { - backgroundColor : '#518029' - } - } - } - }, - typography : - { - useNextVariants : true - } - } + /* The service & Support URL; if `null`, it will be not displayed on the about dialogs. */ + supportUrl : 'https://support.example.com', + + /* The privacy and data protection external URL or local HTML path. */ + privacyUrl : 'privacy/privacy.html', + + /* The palette main color. */ + 'theme.palette.primary.main' : '#313131', + + /* The app bar background color. */ + 'theme.overrides.MuiAppBar.colorPrimary.backgroundColor' : '#313131', + + /* The primary buttons background color. */ + 'theme.overrides.MuiButton.containedPrimary.backgroundColor' : '#5F9B2D', + + /* The primary buttons background color when in hover state. */ + 'theme.overrides.MuiButton.containedPrimary.&:hover.backgroundColor' : '#5F9B2D', + + /* The secondary buttons background color. */ + 'theme.overrides.MuiButton.containedSecondary.backgroundColor' : '#f50057', + + /* The secondary buttons background color when in hover state. */ + 'theme.overrides.MuiButton.containedSecondary.&:hover.backgroundColor' : '#f50057', + + /* The primary Fab buttons background color. */ + 'theme.overrides.MuiFab.primary.backgroundColor' : '#5F9B2D', + + /* The primary Fab buttons background color when in hover state. */ + 'theme.overrides.MuiFab.primary.&:hover.backgroundColor' : '#5F9B2D', + + /* The secondary Fab buttons background color. */ + 'theme.overrides.MuiFab.secondary.backgroundColor' : '#f50057', + + /* The secondary Fab buttons background color when in hover state. */ + 'theme.overrides.MuiFab.secondary.&:hover.backgroundColor' : '#f50057', + + /* The badges background color. */ + 'theme.overrides.MuiBadge.colorPrimary.backgroundColor' : '#5F9B2D', + + /* The badges background color when in hover state. */ + 'theme.overrides.MuiBadge.colorPrimary.&:hover.backgroundColor' : '#518029', + + /* undefined */ + 'theme.typography.useNextVariants' : true }; + +// Generated with: yarn gen-config-docs from app/src/config.ts diff --git a/app/src/config.ts b/app/src/config.ts index 081cf24b..dac5f47e 100644 --- a/app/src/config.ts +++ b/app/src/config.ts @@ -37,8 +37,8 @@ const configSchema = convict({ serverHostname : { doc : 'If the server component runs on a different host than the app you can specify the host name.', - format : '*', - default : null, + format : 'String', + default : '', nullable : true }, @@ -191,13 +191,14 @@ const configSchema = convict({ ] } }, + // The adaptive spatial layer selection scaling factor (in the range [0.5, 1.0]) // example: // with level width=640px, the minimum width required to trigger the // level change will be: 640 * 0.75 = 480px adaptiveScalingFactor : { - doc : 'The adaptive spatial layer selection scaling factor.', + doc : 'The adaptive spatial layer selection scaling factor in the range [0.5, 1.0].', format : (value: number) => value >= 0.5 && value <= 1.0, default : 0.75 }, @@ -230,12 +231,13 @@ const configSchema = convict({ }, transportOptions : { - doc : '', + doc : 'The Mediasoup transport options.', format : Object, default : { tcp : true } }, + // audio options autoGainControl : { @@ -325,7 +327,7 @@ const configSchema = convict({ audioPresets : { doc : 'The audio presets.', - format : '*', + format : Object, default : { conference : @@ -375,65 +377,86 @@ const configSchema = convict({ } }, - /** - * Set max 'int' participants in one room that join - * unmuted. Next participant will join automatically muted - * Default value is 4 - * - * Set it to 0 to auto mute all, - * Set it to negative (-1) to never automatically auto mute - * but use it with caution - * full mesh audio strongly decrease room capacity! - */ + // To be removed once the advanced-audio-options PR is merged + centralAudioOptions : + { + doc : 'The default audio preset.', + format : Object, + default : + { + 'autoGainControl' : true, + 'echoCancellation' : true, + 'noiseSuppression' : true, + 'voiceActivatedUnmute' : false, + 'noiseThreshold' : -60, + 'sampleRate' : 48000, + 'channelCount' : 1, + 'sampleSize' : 16, + 'opusStereo' : false, + 'opusDtx' : true, + 'opusFec' : true, + 'opusPtime' : 20, + 'opusMaxPlaybackRate' : 48000, + 'volume' : 1.0 + } + }, + autoMuteThreshold : { - doc : 'Set the max number of participants in one room that join unmuted.', + doc : `It sets the maximum number of participants in one room that can join unmuted. +The next participant will join automatically muted. +Set it to 0 to auto mute all. +Set it to negative (-1) to never automatically auto mute but use it with caution, +full mesh audio strongly decrease room capacity!`, format : 'nat', default : 4 }, + background : { doc : 'The page background image URL', - format : String, + format : 'String', default : 'images/background.jpg', nullable : true }, + defaultLayout : { - doc : 'The default layout', + doc : 'The default layout.', format : [ 'democratic', 'filmstrip' ], default : 'democratic' }, + buttonControlBar : { - doc : 'If true, will show media control buttons in separate control bar, not in the ME container.', + doc : 'If true, the media control buttons will be shown in separate control bar, not in the ME container.', format : 'Boolean', default : false }, + drawerOverlayed : { doc : 'If false, will push videos away to make room for side drawer. If true, will overlay side drawer over videos.', format : 'Boolean', default : true }, + notificationPosition : { - doc : 'The position of notifications.', + doc : 'The position of the notifications.', format : [ 'left', 'right' ], default : 'right' }, - /** - * Set the notificationSounds. Valid keys are: - * 'parkedPeer', 'parkedPeers', 'raisedHand', 'chatMessage', - * 'sendFile', 'newPeer' and 'default'. - * - * Not defining a key is equivalent to using the default notification sound. - * Setting 'play' to null disables the sound notification. - */ notificationSounds : { - doc : 'Set the notifications sounds.', + doc : `It sets the notifications sounds. +Valid keys are: +'parkedPeer', 'parkedPeers', 'raisedHand', 'chatMessage', 'sendFile', 'newPeer' and 'default'. + +Not defining a key is equivalent to using the default notification sound. +Setting 'play' to null disables the sound notification. +`, format : Object, default : { @@ -449,21 +472,22 @@ const configSchema = convict({ } } }, + hideTimeout : { - doc : 'Timeout for autohiding topbar and button control bar.', + doc : 'Timeout for auto hiding the topbar and the buttons control bar.', format : 'int', default : 3000 }, lastN : { - doc : 'The max number of participant that will be visible in as speaker.', + doc : 'The maximum number of participants that will be visible in as speaker.', format : 'nat', default : 4 }, mobileLastN : { - doc : 'The max number of participant that will be visible in as speaker for mobile users.', + doc : 'The maximum number of participants that will be visible in as speaker for mobile users.', format : 'nat', default : 1 }, @@ -475,15 +499,14 @@ const configSchema = convict({ }, lockLastN : { - doc : 'If truthy, users can NOT change number of speakers visible.', + doc : 'If true, the users can not change the number of visible speakers.', format : 'Boolean', default : false }, - // Show logo if "logo" is not null, else show title - // Set logo file name using logo.* pattern like "logo.png" to not track it by git + logo : { - doc : 'If not null, it shows the logo loaded from URL, else it shows the title.', + doc : 'If not null, it shows the logo loaded from the specified URL, otherwise it shows the title.', format : 'url', default : 'images/logo.edumeet.svg', nullable : true @@ -491,7 +514,7 @@ const configSchema = convict({ title : { doc : 'The title to show if the logo is not specified.', - format : String, + format : 'String', default : 'edumeet' }, supportUrl : @@ -501,17 +524,14 @@ const configSchema = convict({ default : 'https://support.example.com', nullable : true }, - // Privacy and data protection URL or path by default privacy/privacy.html - // that is a placeholder for your policies - // - // but an external url could be also used here privacyUrl : { - doc : 'The privacy and data protection URL or path.', - format : String, + doc : 'The privacy and data protection external URL or local HTML path.', + format : 'String', default : 'privacy/privacy.html', nullable : true }, + // UI theme elements theme : { @@ -519,7 +539,12 @@ const configSchema = convict({ { primary : { - main : { format: String, default: '#313131' } + main : + { + doc : 'The palette main color.', + format : 'String', + default : '#313131' + } } }, overrides : @@ -528,25 +553,50 @@ const configSchema = convict({ { colorPrimary : { - backgroundColor : { format: String, default: '#313131' } + backgroundColor : + { + doc : 'The app bar background color.', + format : 'String', + default : '#313131' + } } }, MuiButton : { containedPrimary : { - backgroundColor : { format: String, default: '#5F9B2D' }, - '&:hover' : + backgroundColor : { - backgroundColor : { format: String, default: '#5F9B2D' } + doc : 'The primary buttons background color.', + format : 'String', + default : '#5F9B2D' + }, + '&:hover' : + { + backgroundColor : + { + doc : 'The primary buttons background color when in hover state.', + format : 'String', + default : '#5F9B2D' + } } }, containedSecondary : { - backgroundColor : { format: String, default: '#f50057' }, - '&:hover' : + backgroundColor : { - backgroundColor : { format: String, default: '#f50057' } + doc : 'The secondary buttons background color.', + format : 'String', + default : '#f50057' + }, + '&:hover' : + { + backgroundColor : + { + doc : 'The secondary buttons background color when in hover state.', + format : 'String', + default : '#f50057' + } } } @@ -579,18 +629,38 @@ const configSchema = convict({ { primary : { - backgroundColor : { format: String, default: '#5F9B2D' }, - '&:hover' : + backgroundColor : { - backgroundColor : { format: String, default: '#5F9B2D' } + doc : 'The primary Fab buttons background color.', + format : 'String', + default : '#5F9B2D' + }, + '&:hover' : + { + backgroundColor : + { + doc : 'The primary Fab buttons background color when in hover state.', + format : 'String', + default : '#5F9B2D' + } } }, secondary : { - backgroundColor : { format: String, default: '#f50057' }, - '&:hover' : + backgroundColor : { - backgroundColor : { format: String, default: '#f50057' } + doc : 'The secondary Fab buttons background color.', + format : 'String', + default : '#f50057' + }, + '&:hover' : + { + backgroundColor : + { + doc : 'The secondary Fab buttons background color when in hover state.', + format : 'String', + default : '#f50057' + } } } @@ -599,17 +669,31 @@ const configSchema = convict({ { colorPrimary : { - backgroundColor : { format: String, default: '#5F9B2D' }, - '&:hover' : + backgroundColor : { - backgroundColor : { format: String, default: '#518029' } + doc : 'The badges background color.', + format : 'String', + default : '#5F9B2D' + }, + '&:hover' : + { + backgroundColor : + { + doc : 'The badges background color when in hover state.', + format : 'String', + default : '#518029' + } } } } }, typography : { - useNextVariants : { format: 'Boolean', default: true } + useNextVariants : + { + format : 'Boolean', + default : true + } } } }); @@ -687,12 +771,48 @@ var config = return data; } +function dumpExampleConfigJs() +{ + let data = `/** + * Edumeet App Configuration + * + * The configuration documentation is available also: + * - in the app/README.md file in the source tree + * - visiting the /config page in a running instance + */ + +// eslint-disable-next-line +var config = { +`; + + Object.entries(formatDocs()).forEach((entry: [string, any]) => + { + // eslint-disable-next-line + let [ name, value ] = entry; + + if (name.includes('.')) + name = `'${name}'`; + + data += `\n\t/* ${value.doc} */ +\t${name} : ${value.default}, +`; + }); + + data += `}; + +// Generated with: yarn gen-config-docs from app/src/config.ts +`; + + return data; +} + // run the docs generator if (typeof window === 'undefined') { import('fs').then((fs) => { fs.writeFileSync('README.md', dumpDocsMarkdown()); + fs.writeFileSync('public/config/config.example.js', dumpExampleConfigJs()); }); } diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index f4e39467..b03f1c4d 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -19,7 +19,8 @@ services: - ${PWD}/..:/edumeet - ${PWD}/config/edumeet-server-config.js:/edumeet/server/config/config.js:ro - ${PWD}/config/edumeet-server-config.yaml:/edumeet/server/config/config.yaml:ro - - ${PWD}/config/edumeet-app-config.js:/edumeet/app/public/config/config.js:ro + #- ${PWD}/config/edumeet-app-config.js:/edumeet/app/public/config/config.js:ro + - ${PWD}/../app/public/config/config.example.js:/edumeet/app/public/config/config.js:ro network_mode: "host" extra_hosts: redis: 172.22.0.2