diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts index d6dc5914a..a91815b95 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts @@ -696,6 +696,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { authorizationHeader: () => this.authService.getRequestHeaderValue(), serverUrl: environment.originServerUrl || window.location.origin, + stunServers: this.serverConfig.webrtc.stunServers, errorNotifier: (message: string) => this.notifier.error(message), diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts index 12c8b5e84..7bccbc42a 100644 --- a/client/src/assets/player/peertube-player.ts +++ b/client/src/assets/player/peertube-player.ts @@ -165,7 +165,7 @@ export class PeerTubePlayer { private async loadP2PMediaLoader () { const hlsOptionsBuilder = new HLSOptionsBuilder({ - ...pick(this.options, [ 'pluginsManager', 'serverUrl', 'authorizationHeader' ]), + ...pick(this.options, [ 'pluginsManager', 'serverUrl', 'authorizationHeader', 'stunServers' ]), ...pick(this.currentLoadOptions, [ 'videoPassword', 'requiresUserAuth', diff --git a/client/src/assets/player/shared/common/utils.ts b/client/src/assets/player/shared/common/utils.ts index 80c784ea3..721727eeb 100644 --- a/client/src/assets/player/shared/common/utils.ts +++ b/client/src/assets/player/shared/common/utils.ts @@ -15,16 +15,9 @@ export function bytes (value: number) { return [ calc, format.type ] } -export function getRtcConfig () { +export function getRtcConfig (stunServers: string[]) { return { - iceServers: [ - { - urls: 'stun:stun.stunprotocol.org' - }, - { - urls: 'stun:stun.framasoft.org' - } - ] + iceServers: stunServers.map(s => ({ urls: s })) } } diff --git a/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts b/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts index 7ba4faaee..e0c8a2d73 100644 --- a/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts +++ b/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts @@ -17,9 +17,12 @@ import { getRtcConfig, isSameOrigin } from '../common' import { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager' import { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder' import { SegmentValidator } from '../p2p-media-loader/segment-validator' +import debug from 'debug' + +const debugLogger = debug('peertube:player:hls') type ConstructorOptions = - Pick & + Pick & Pick @@ -86,6 +89,8 @@ export class HLSOptionsBuilder { } } + debugLogger('Creating HLS player options', { hlsjs, p2pMediaLoader, loaderOptions: p2pMediaLoaderConfig }) + return { p2pMediaLoader, hlsjs } } @@ -116,7 +121,7 @@ export class HLSOptionsBuilder { return { loader: { trackerAnnounce, - rtcConfig: getRtcConfig(), + rtcConfig: getRtcConfig(this.options.stunServers), simultaneousHttpDownloads: 1, httpFailedSegmentTimeout: 1000, diff --git a/client/src/assets/player/types/peertube-player-options.ts b/client/src/assets/player/types/peertube-player-options.ts index 5ba73374d..2bb883f40 100644 --- a/client/src/assets/player/types/peertube-player-options.ts +++ b/client/src/assets/player/types/peertube-player-options.ts @@ -41,6 +41,8 @@ export type PeerTubePlayerContructorOptions = { pluginsManager: PluginsManager + stunServers: string[] + autoPlayerRatio?: { cssRatioVariable: string cssPlayerPortraitModeVariable: string diff --git a/client/src/standalone/videos/shared/player-options-builder.ts b/client/src/standalone/videos/shared/player-options-builder.ts index 4436170d6..fde8783eb 100644 --- a/client/src/standalone/videos/shared/player-options-builder.ts +++ b/client/src/standalone/videos/shared/player-options-builder.ts @@ -206,6 +206,7 @@ export class PlayerOptionsBuilder { theaterButton: false, serverUrl: getBackendUrl(), + stunServers: serverConfig.webrtc.stunServers, language: navigator.language, pluginsManager: this.peertubePlugin.getPluginsManager(), diff --git a/config/default.yaml b/config/default.yaml index 281bb7f78..c1a8f8bf0 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -514,6 +514,12 @@ stats: total_admins: enabled: true +webrtc: + # 1 or 2 STUN servers are sufficient + stun_servers: + - 'stun:stunserver2024.stunprotocol.org' + - 'stun:stun.framasoft.org' + cache: previews: size: 500 # Max number of previews you want to cache diff --git a/config/production.yaml.example b/config/production.yaml.example index f41ec9706..710e6f0a9 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example @@ -512,6 +512,12 @@ stats: total_admins: enabled: true +webrtc: + # 1 or 2 STUN servers are sufficient + stun_servers: + - 'stun:stunserver2024.stunprotocol.org' + - 'stun:stun.framasoft.org' + ############################################################################### # # From this point, almost all following keys can be overridden by the web interface diff --git a/packages/models/src/server/server-config.model.ts b/packages/models/src/server/server-config.model.ts index 5b4f6b5f8..529c10f6c 100644 --- a/packages/models/src/server/server-config.model.ts +++ b/packages/models/src/server/server-config.model.ts @@ -354,6 +354,10 @@ export interface ServerConfig { enabled: boolean } } + + webrtc: { + stunServers: string[] + } } export type HTMLServerConfig = Omit diff --git a/packages/tests/src/api/server/config.ts b/packages/tests/src/api/server/config.ts index 77c90e4ed..19ec1050d 100644 --- a/packages/tests/src/api/server/config.ts +++ b/packages/tests/src/api/server/config.ts @@ -444,6 +444,11 @@ describe('Test config', function () { expect(data.views.videos.watchingInterval.anonymous).to.equal(5000) expect(data.views.videos.watchingInterval.users).to.equal(5000) + + expect(data.webrtc.stunServers).to.have.members([ + 'stun:stunserver2024.stunprotocol.org', + 'stun:stun.framasoft.org' + ]) }) it('Should have a correct config on a server with registration enabled', async function () { diff --git a/server/core/initializers/config.ts b/server/core/initializers/config.ts index 65ccb62a9..9b68384ba 100644 --- a/server/core/initializers/config.ts +++ b/server/core/initializers/config.ts @@ -396,6 +396,9 @@ const CONFIG = { ENABLED: config.get('stats.total_admins.enabled') } }, + WEBRTC: { + STUN_SERVERS: config.get('webrtc.stun_servers') + }, ADMIN: { get EMAIL () { return config.get('admin.email') } }, diff --git a/server/core/lib/redis.ts b/server/core/lib/redis.ts index 9092db08d..ed2f9c903 100644 --- a/server/core/lib/redis.ts +++ b/server/core/lib/redis.ts @@ -37,7 +37,7 @@ class Redis { const redisMode = CONFIG.REDIS.SENTINEL.ENABLED ? 'sentinel' : 'standalone' logger.info(`Connecting to Redis in "${redisMode}" mode...`, lTags()) - this.client = new IoRedis(Redis.getRedisClientOptions('', { enableAutoPipelining: true })) + this.client = new IoRedis(Redis.getRedisClientOptions('', { enableAutoPipelining: true }, true)) this.client.on('error', err => logger.error('Redis failed to connect', { err, ...lTags() })) this.client.on('connect', () => { logger.info('Connected to redis.', lTags()) @@ -59,15 +59,17 @@ class Redis { this.prefix = 'redis-' + WEBSERVER.HOST + '-' } - static getRedisClientOptions (name?: string, options: RedisOptions = {}): RedisOptions { + static getRedisClientOptions (name?: string, options: RedisOptions = {}, logOptions = false): RedisOptions { const connectionName = [ 'PeerTube', name ].join('') const connectTimeout = 20000 // Could be slow since node use sync call to compile PeerTube if (CONFIG.REDIS.SENTINEL.ENABLED) { - logger.info( - `Using sentinel redis options`, - { sentinels: CONFIG.REDIS.SENTINEL.SENTINELS, name: CONFIG.REDIS.SENTINEL.MASTER_NAME, ...lTags() } - ) + if (logOptions) { + logger.info( + `Using sentinel redis options`, + { sentinels: CONFIG.REDIS.SENTINEL.SENTINELS, name: CONFIG.REDIS.SENTINEL.MASTER_NAME, ...lTags() } + ) + } return { connectionName, @@ -80,10 +82,12 @@ class Redis { } } - logger.info( - `Using standalone redis options`, - { db: CONFIG.REDIS.DB, host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT, path: CONFIG.REDIS.SOCKET, ...lTags() } - ) + if (logOptions) { + logger.info( + `Using standalone redis options`, + { db: CONFIG.REDIS.DB, host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT, path: CONFIG.REDIS.SOCKET, ...lTags() } + ) + } return { connectionName, diff --git a/server/core/lib/server-config-manager.ts b/server/core/lib/server-config-manager.ts index 88cbb8a10..2f87e94c4 100644 --- a/server/core/lib/server-config-manager.ts +++ b/server/core/lib/server-config-manager.ts @@ -320,6 +320,10 @@ class ServerConfigManager { storyboards: { enabled: CONFIG.STORYBOARDS.ENABLED + }, + + webrtc: { + stunServers: CONFIG.WEBRTC.STUN_SERVERS } } }