From fc5a9029ea7b656321f63426ae5c505f68402fe7 Mon Sep 17 00:00:00 2001 From: Franz Rolfsvaag Date: Wed, 22 Jul 2026 21:41:03 +0200 Subject: [PATCH] Deduplicate OBS source state traffic --- TODO.md | 4 ++++ companion/installer/Lumi.Companion.iss | 2 +- companion/scripts/publish-companion.ps1 | 2 +- .../src/Lumi.Companion.App/CompanionRuntime.cs | 7 ++++++- .../Lumi.Companion.App/Lumi.Companion.App.csproj | 2 +- .../backend/companion/gateway.js | 8 ++++++++ .../lumi_transcription/companion_manifest.json | 16 ++++++++-------- plugins/lumi_transcription/plugin.json | 2 +- plugins/lumi_transcription/tests/verify.js | 1 + 9 files changed, 31 insertions(+), 13 deletions(-) diff --git a/TODO.md b/TODO.md index f8d80bf..008598d 100644 --- a/TODO.md +++ b/TODO.md @@ -59,6 +59,10 @@ audio and initial OBS source inventory their own soft gateway budgets, so normal or pathological capture cadence cannot rate-limit and disconnect the Companion control connection. +Experimental.10 deduplicates OBS source inventories and unchanged source-state +notifications at both ends, removing the high-volume source-update feedback seen +with large scene collections while retaining the non-disconnecting safety budget. + Release-blocking work remains: - Package the native whisper.cpp worker as the Windows CUDA runtime, then benchmark diff --git a/companion/installer/Lumi.Companion.iss b/companion/installer/Lumi.Companion.iss index e4ece72..16cd263 100644 --- a/companion/installer/Lumi.Companion.iss +++ b/companion/installer/Lumi.Companion.iss @@ -1,5 +1,5 @@ #ifndef AppVersion - #define AppVersion "0.1.0-experimental.9" + #define AppVersion "0.1.0-experimental.10" #endif #ifndef SourceRoot #error SourceRoot must point at the self-contained Companion publish directory. diff --git a/companion/scripts/publish-companion.ps1 b/companion/scripts/publish-companion.ps1 index 1e440fd..8bd7a04 100644 --- a/companion/scripts/publish-companion.ps1 +++ b/companion/scripts/publish-companion.ps1 @@ -1,5 +1,5 @@ param( - [string]$Version = "0.1.0-experimental.9", + [string]$Version = "0.1.0-experimental.10", [string]$BridgeVersion = "0.1.0-experimental.5" ) diff --git a/companion/src/Lumi.Companion.App/CompanionRuntime.cs b/companion/src/Lumi.Companion.App/CompanionRuntime.cs index 74f9d02..256bb8d 100644 --- a/companion/src/Lumi.Companion.App/CompanionRuntime.cs +++ b/companion/src/Lumi.Companion.App/CompanionRuntime.cs @@ -564,7 +564,10 @@ public sealed class CompanionRuntime : IAsyncDisposable ReadString(source, "display_name") ?? ReadString(source, "name") ?? "OBS source", ReadBoolean(source, "program_active") || ReadBoolean(source, "active"), ReadBoolean(source, "source_missing") || ReadBoolean(source, "missing"))) - .Where(source => Guid.TryParse(source.Uuid, out _)).ToArray(); + .Where(source => Guid.TryParse(source.Uuid, out _)) + .GroupBy(source => source.Uuid) + .Select(group => group.Last()) + .ToArray(); _bridgeSelectionAttached = null; ObsSourcesChanged?.Invoke(ObsSources); foreach (var source in ObsSources) await SendSourceUpdateAsync(source); @@ -576,6 +579,8 @@ public sealed class CompanionRuntime : IAsyncDisposable var source = new ObsSource(ReadString(message, "source_uuid") ?? string.Empty, ReadString(message, "display_name") ?? "OBS source", ReadBoolean(message, "program_active"), ReadBoolean(message, "source_missing")); if (Guid.TryParse(source.Uuid, out _)) { + var previous = ObsSources.FirstOrDefault(item => item.Uuid == source.Uuid); + if (previous == source) return; ObsSources = ObsSources.Where(item => item.Uuid != source.Uuid).Append(source).OrderBy(item => item.Name).ToArray(); ObsSourcesChanged?.Invoke(ObsSources); await SendSourceUpdateAsync(source); diff --git a/companion/src/Lumi.Companion.App/Lumi.Companion.App.csproj b/companion/src/Lumi.Companion.App/Lumi.Companion.App.csproj index c22cecc..f0567ec 100644 --- a/companion/src/Lumi.Companion.App/Lumi.Companion.App.csproj +++ b/companion/src/Lumi.Companion.App/Lumi.Companion.App.csproj @@ -5,7 +5,7 @@ enable enable app.manifest - 0.1.0-experimental.9 + 0.1.0-experimental.10 0.1.0.0 diff --git a/plugins/lumi_transcription/backend/companion/gateway.js b/plugins/lumi_transcription/backend/companion/gateway.js index c7a2808..650385a 100644 --- a/plugins/lumi_transcription/backend/companion/gateway.js +++ b/plugins/lumi_transcription/backend/companion/gateway.js @@ -36,6 +36,7 @@ class CompanionGateway { let sourceMessagesInWindow = 0; let audioMessagesDropped = 0; let sourceMessagesDropped = 0; + const sourceStates = new Map(); let messageChain = Promise.resolve(); const send = (type, payload, sessionId = session?.id || null) => { if (socket.readyState === WebSocket.OPEN) socket.send(JSON.stringify(envelope(type, payload, sessionId))); @@ -65,6 +66,13 @@ class CompanionGateway { } const message = parseEnvelope(body); if (helloComplete && message.type === "source_update") { + const sourceId = String(message.payload?.source_uuid || ""); + const signature = JSON.stringify(message.payload || {}); + if (sourceId && sourceStates.get(sourceId) === signature) return; + if (sourceId) { + sourceStates.set(sourceId, signature); + if (sourceStates.size > 2048) sourceStates.delete(sourceStates.keys().next().value); + } sourceMessagesInWindow += 1; if (sourceMessagesInWindow > MAX_SOURCE_MESSAGES_PER_SECOND) { sourceMessagesDropped += 1; return; } } else { diff --git a/plugins/lumi_transcription/companion_manifest.json b/plugins/lumi_transcription/companion_manifest.json index cd48480..fcc2970 100644 --- a/plugins/lumi_transcription/companion_manifest.json +++ b/plugins/lumi_transcription/companion_manifest.json @@ -1,17 +1,17 @@ { "schema_version": 1, - "version": "0.1.0-experimental.9", + "version": "0.1.0-experimental.10", "signed": false, - "release_notes": "Prevents OBS audio and initial source-inventory bursts from rate-limiting the Companion connection by sending steady 20 ms audio frames and bounding high-volume capture traffic separately from control messages.", + "release_notes": "Prevents OBS capture bursts from rate-limiting the Companion connection, sends steady 20 ms audio frames, and removes duplicate source-state traffic from large scene collections.", "installer": { "id": "windows-x64-installer", "platform": "win32", "architecture": "x64", "label": "Windows x64 per-user installer", "filename": "Lumi.Companion-Setup.exe", - "url": "https://git.rolfsvaag.no/Rolfsvaag_Datateknikk/Lumi/releases/download/companion-v0.1.0-experimental.9/Lumi.Companion-Setup.exe", - "sha256": "22bdb0f351e5b4960e2c1ae40e3bdbd8de8a8d6326b30714defb5eb202c0efcf", - "bytes": 32039974 + "url": "https://git.rolfsvaag.no/Rolfsvaag_Datateknikk/Lumi/releases/download/companion-v0.1.0-experimental.10/Lumi.Companion-Setup.exe", + "sha256": "8207620c1fa2a3f6371c7f5fad40f9a467146a3c44068ed6ae655ee701d98e6a", + "bytes": 32031916 }, "artifacts": [ { @@ -20,9 +20,9 @@ "architecture": "x64", "label": "Windows x64 self-contained", "filename": "Lumi.Companion-win-x64.zip", - "url": "https://git.rolfsvaag.no/Rolfsvaag_Datateknikk/Lumi/releases/download/companion-v0.1.0-experimental.9/Lumi.Companion-win-x64.zip", - "sha256": "70d9a780859824aa7b8a12e9f25ae8871778b83458889237f171484b2a200dbc", - "bytes": 41757969, + "url": "https://git.rolfsvaag.no/Rolfsvaag_Datateknikk/Lumi/releases/download/companion-v0.1.0-experimental.10/Lumi.Companion-win-x64.zip", + "sha256": "f5a00c9bb778790caec596da475c33b3f7c8e6e67921da75e1e8e3b463bee624", + "bytes": 41757850, "entrypoint": "Lumi.Companion.App.exe" } ] diff --git a/plugins/lumi_transcription/plugin.json b/plugins/lumi_transcription/plugin.json index 21bb26b..9ee6be0 100644 --- a/plugins/lumi_transcription/plugin.json +++ b/plugins/lumi_transcription/plugin.json @@ -1,7 +1,7 @@ { "id": "lumi_transcription", "name": "Lumi Transcription", - "version": "0.1.0-experimental.9", + "version": "0.1.0-experimental.10", "description": "Server-hosted whisper.cpp transcription for Lumi Companion and OBS closed captions.", "main": "index.js", "channel": "experimental", diff --git a/plugins/lumi_transcription/tests/verify.js b/plugins/lumi_transcription/tests/verify.js index 2e3a303..63ba710 100644 --- a/plugins/lumi_transcription/tests/verify.js +++ b/plugins/lumi_transcription/tests/verify.js @@ -117,6 +117,7 @@ function verifyLocalhostTransportPolicy() { } function verifyCompanionVersionOrdering() { + assert.equal(plugin.compareVersions("0.1.0-experimental.10", "0.1.0-experimental.9"), 1); assert.equal(plugin.compareVersions("0.1.0-experimental.9", "0.1.0-experimental.8"), 1); assert.equal(plugin.compareVersions("0.1.0-experimental.8", "0.1.0-experimental.7"), 1); assert.equal(plugin.compareVersions("0.1.0-experimental.7", "0.1.0-experimental.6"), 1);