refactor(nests): replace hand-built catalog JSON with typed MoqLiteHangCatalog
The two SPEAKER_CATALOG_JSON call sites (MoqLiteNestsSpeaker for the non-reconnecting path, ReconnectingNestsSpeaker for the JWT-refresh hot- swap path) both built the manifest as a `\\` + `\"` + `+`-concatenated string literal. One missed escape and the watcher's parser fails silently — the broadcast becomes invisible to hang.js with no indication of why. The two literals had also drifted independently in review (same content today; nothing prevents drift tomorrow). Replace both with `MoqLiteHangCatalog.opusMono48k(track).encodeJsonBytes()`, a Serializable data class that encodes via kotlinx.serialization with `encodeDefaults = false` + `explicitNulls = false` pinned (so a future global default-flip can't surface `"bitrate": null` on hang.js's parser). The new type lives in :nestsClient because :nestsClient does not depend on :commons and the parser-side `RoomSpeakerCatalog` (in :commons) isn't reachable from the publish path. The two classes target the same wire shape independently; a byte-exact assertion in the new MoqLiteHangCatalogTest plus the existing RoomSpeakerCatalogTest's inline-literal round-trip together pin both sides — desync on either end fails one of the two tests immediately. https://claude.ai/code/session_014JfZJHSTvyYYWJbC9VbB47
This commit is contained in:
+7
-6
@@ -127,12 +127,13 @@ class RoomSpeakerCatalogTest {
|
||||
|
||||
@Test
|
||||
fun stripPrefixRoundTripsCanonicalCatalog() {
|
||||
// The catalog payload [com.vitorpamplona.nestsclient.MoqLiteNestsSpeaker]
|
||||
// emits MUST round-trip through the parser — guards against
|
||||
// either side drifting from the kixelated/hang shape.
|
||||
// SPEAKER_CATALOG_JSON lives in nestsClient and isn't
|
||||
// accessible from commons; keep an inline literal that mirrors
|
||||
// it verbatim so a desync triggers this assertion.
|
||||
// The catalog payload `MoqLiteHangCatalog.opusMono48k(...)` emits
|
||||
// (in `:nestsClient`) MUST round-trip through this parser — the
|
||||
// two classes target the same wire shape independently because
|
||||
// `:nestsClient` does not depend on `:commons` and vice versa.
|
||||
// `MoqLiteHangCatalog` isn't reachable from this module; keep an
|
||||
// inline literal that mirrors what the publisher emits verbatim
|
||||
// so a desync on either side trips this assertion.
|
||||
val emitted =
|
||||
"{\"audio\":{\"renditions\":{\"audio/data\":{" +
|
||||
"\"codec\":\"opus\",\"container\":{\"kind\":\"legacy\"}," +
|
||||
|
||||
Reference in New Issue
Block a user