/video signaling proxy and a global public server http path config item

This commit is contained in:
legop3
2026-09-14 19:49:37 -04:00
parent e7d7f2a270
commit 43274e7371
32 changed files with 364 additions and 145 deletions
@@ -61,7 +61,6 @@ let operations;
function replaceAudioForwardRuntime(fullConfig) {
operations?.stopAllWorkers('configuration-change');
const audioForwardConfig = fullConfig.audioForward || {};
const mediaConfig = fullConfig.media || {};
serviceEnabled = Boolean(audioForwardConfig.enabled);
const streamSuffix = typeof audioForwardConfig.streamSuffix === 'string' && audioForwardConfig.streamSuffix.trim()
? audioForwardConfig.streamSuffix.trim()
@@ -72,7 +71,6 @@ function replaceAudioForwardRuntime(fullConfig) {
roverManager,
turnService,
streamSuffix,
mediaConfig,
});
const maxUploadBytes = Number.isFinite(audioForwardConfig.maxUploadBytes)
? Math.max(256 * 1024, Math.floor(audioForwardConfig.maxUploadBytes))
@@ -102,7 +100,7 @@ function replaceAudioForwardRuntime(fullConfig) {
replaceAudioForwardRuntime(loadConfig());
// Stable delegates keep the one-time socket/event registrations below pointed
// at the newest policy and worker engine after either audio or media changes.
// at the newest policy and worker engine after audio-forward changes.
const delegate = (name) => (...args) => operations[name](...args);
const ensureWorker = delegate('ensureWorker');
const stopWorker = delegate('stopWorker');
@@ -166,9 +164,6 @@ registerChargeCompleteSound({
registerConfigurationHandler('audioForward', (_section, _previous, nextConfig) => {
replaceAudioForwardRuntime(nextConfig);
});
registerConfigurationHandler('media', (_section, _previous, nextConfig) => {
replaceAudioForwardRuntime(nextConfig);
});
module.exports = {
getAudioForwardState,
@@ -1,6 +1,8 @@
// audio Forward Service policy
// Purpose: Encapsulates permission checks and media path/url derivation helpers.
// Scope: Keeps runtime behavior unchanged while isolating validation and path-construction logic.
const { PUBLIC_MEDIA_PREFIX } = require('../mediaMtxService/proxy');
function createAudioForwardPolicy(deps) {
const {
isVerified,
@@ -8,7 +10,6 @@ function createAudioForwardPolicy(deps) {
roverManager,
turnService,
streamSuffix,
mediaConfig,
} = deps;
function ensureVipVerified(socket) {
@@ -43,23 +44,8 @@ function createAudioForwardPolicy(deps) {
return `${roverId}${streamSuffix}`;
}
function getMediaPrefix() {
const base = mediaConfig.whepBaseUrl;
if (!base) return '';
try {
const parsed = new URL(base);
return `${parsed.origin}${parsed.pathname}`.replace(/\/+$/, '');
} catch {
return String(base).replace(/\/+$/, '');
}
}
function buildWhipUrl(pathId) {
const prefix = getMediaPrefix();
if (!prefix) {
throw new Error('Server media base URL missing');
}
return `${prefix}/${encodeURIComponent(pathId)}/whip`;
return `${PUBLIC_MEDIA_PREFIX}/${encodeURIComponent(pathId)}/whip`;
}
return {
@@ -12,7 +12,6 @@ function createPolicy({ verified = true, muted = false, driver = true, canDrive
roverManager: { isDriver: () => driver },
turnService: { canDrive: () => canDrive },
streamSuffix: '-fwd',
mediaConfig: {},
});
}
@@ -30,3 +29,8 @@ test('publishes forwarded audio to the local MediaMTX RTSP path', () => {
const policy = createPolicy();
assert.equal(policy.resolveForwardUrl('rover one'), 'rtsp://127.0.0.1:8554/rover%20one-fwd');
});
test('publishes browser microphone signaling through the same-origin proxy', () => {
const policy = createPolicy();
assert.equal(policy.buildWhipUrl('rover one-fwd'), '/video/rover%20one-fwd/whip');
});