diff --git a/src/config.ts b/src/config.ts index d0882ab4ed..d386c03808 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,13 +9,21 @@ import type { IDefaultConfig } from "./default_config"; import DEFAULT_CONFIG from "./default_config"; import deepMerge from "./utils/deep_merge"; +import EventEmitter from "./utils/event_emitter"; -class ConfigHandler { - _config = DEFAULT_CONFIG; +interface IConfigHandlerEvents { + update: Partial; +} + +class ConfigHandler extends EventEmitter { + public updated = false; + private _config = DEFAULT_CONFIG; update(config: Partial) { const newConfig = deepMerge(this._config, config); this._config = newConfig; + this.updated = true; + this.trigger("update", config); } getCurrent(): IDefaultConfig { diff --git a/src/core/main/worker/worker_main.ts b/src/core/main/worker/worker_main.ts index c3532e789b..df04cd118d 100644 --- a/src/core/main/worker/worker_main.ts +++ b/src/core/main/worker/worker_main.ts @@ -401,6 +401,11 @@ export default function initializeWorkerMain() { break; } + case MainThreadMessageType.ConfigUpdate: { + config.update(msg.value); + break; + } + default: assertUnreachable(msg); } diff --git a/src/default_config.ts b/src/default_config.ts index bffc6498f9..7e1490d5c9 100644 --- a/src/default_config.ts +++ b/src/default_config.ts @@ -1195,3 +1195,24 @@ const DEFAULT_CONFIG = { export type IDefaultConfig = typeof DEFAULT_CONFIG; export default DEFAULT_CONFIG; + +// NOTE Because the config may have to be serialized and shared between several +// environments, we check here that some strict type is respected: +// - only a subset of types are authorized for now, just make it easier to +// reason about. +// - Needs to make sense in JSON: no `function`, no `Date`, no `undefined`... +interface IGenericConfigData { + [key: string]: + | string + | number + | boolean + | number[] + | string[] + | Partial> + | IGenericConfigData; +} + +function checkIsSerializable(_conf: IGenericConfigData): void { + // noop +} +checkIsSerializable(DEFAULT_CONFIG); diff --git a/src/main_thread/api/public_api.ts b/src/main_thread/api/public_api.ts index 6c4e1d2e19..d77991fdc7 100644 --- a/src/main_thread/api/public_api.ts +++ b/src/main_thread/api/public_api.ts @@ -32,6 +32,7 @@ import getStartDate from "../../compat/get_start_date"; import hasMseInWorker from "../../compat/has_mse_in_worker"; import hasWorkerApi from "../../compat/has_worker_api"; import isDebugModeEnabled from "../../compat/is_debug_mode_enabled"; +import config from "../../config"; import type { ISegmentSinkMetrics } from "../../core/segment_sinks/segment_buffers_store"; import type { IAdaptationChoice, @@ -39,6 +40,7 @@ import type { IABRThrottlers, IBufferType, } from "../../core/types"; +import type { IDefaultConfig } from "../../default_config"; import type { IErrorCode, IErrorType } from "../../errors"; import { ErrorCodes, ErrorTypes, formatError, MediaError } from "../../errors"; import WorkerInitializationError from "../../errors/worker_initialization_error"; @@ -573,6 +575,21 @@ class Player extends EventEmitter { }, this._destroyCanceller.signal, ); + + const sendConfigUpdates = (updates: Partial) => { + if (this._priv_worker === null) { + return; + } + log.debug("---> Sending To Worker:", MainThreadMessageType.ConfigUpdate); + this._priv_worker.postMessage({ + type: MainThreadMessageType.ConfigUpdate, + value: updates, + }); + }; + if (config.updated) { + sendConfigUpdates(config.getCurrent()); + } + config.addEventListener("update", sendConfigUpdates, this._destroyCanceller.signal); }); } diff --git a/src/multithread_types.ts b/src/multithread_types.ts index a9460942cd..139b5bd82b 100644 --- a/src/multithread_types.ts +++ b/src/multithread_types.ts @@ -14,6 +14,7 @@ import type { IRepresentationsChoice, ITrackSwitchingMode, } from "./core/types"; +import type { IDefaultConfig } from "./default_config"; import type { ISerializedMediaError, ISerializedNetworkError, @@ -158,6 +159,12 @@ export interface ILogLevelUpdateMessage { }; } +/** Message sent by the main thread to update the Worker's global config. */ +export interface IConfigUpdateMessage { + type: MainThreadMessageType.ConfigUpdate; + value: Partial; +} + /** * Message sent by the main thread when a new content should be "prepared". * @@ -542,6 +549,7 @@ export const enum MainThreadMessageType { RemoveTextDataError = "remove-text-error", CodecSupportUpdate = "codec-support-update", ContentUrlsUpdate = "urls-update", + ConfigUpdate = "config-update", DecipherabilityStatusUpdate = "decipherability-update", LogLevelUpdate = "log-level-update", MediaSourceReadyStateChange = "media-source-ready-state-change", @@ -560,6 +568,7 @@ export const enum MainThreadMessageType { export type IMainThreadMessage = | IInitMessage | ILogLevelUpdateMessage + | IConfigUpdateMessage | IPrepareContentMessage | IStopContentMessage | IStartPreparedContentMessage