@pipecat-ai/moq-transport 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +24 -0
- package/README.md +125 -0
- package/dist/index.d.ts +156 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +574 -0
- package/dist/index.js.map +1 -0
- package/dist/index.module.js +557 -0
- package/dist/index.module.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"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","sources":["transports/moq-transport/src/index.ts","transports/moq-transport/src/moqTransport.ts"],"sourcesContent":["export * from \"./moqTransport\";\n","/*\n * Copyright (c) 2024-2026, Daily\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport * as Json from \"@moq/json\";\nimport * as Moq from \"@moq/net\";\nimport * as Publish from \"@moq/publish\";\nimport { Effect, Signal } from \"@moq/signals\";\nimport * as Watch from \"@moq/watch\";\nimport {\n type PipecatClientOptions,\n type RTVIEventCallbacks,\n RTVIMessage,\n RTVIError,\n Transport,\n type Tracks,\n type TransportState,\n} from \"@pipecat-ai/client-js\";\n\nconst DEFAULT_NAMESPACE = \"pipecat\";\nconst DEFAULT_CLIENT_ID = \"client0\";\nconst DEFAULT_BOT_ID = \"bot0\";\nconst DEFAULT_TRANSCRIPT_TRACK = \"transcript.json.z\";\n// Bounded jitter buffer on the audio decoder. Lower = more interactive\n// but more drops on bad networks. Matches the bot's audio_in_max_latency_ms\n// in spirit (each side enforces its own deadline).\nconst DEFAULT_AUDIO_LATENCY_MS = 80;\n// Latency ceiling for buffered TTS playback (ms). A finite cap (vs\n// uncapped) because the player's group/jitter buffer needs a concrete\n// maximum span to retain before dropping. The bot paces its writes a\n// little under this (~25s, see the Python transport's\n// `audio_out_max_buffer_ms`) so the producer self-limits below this drop\n// ceiling and the player never actually has to drop.\nconst DEFAULT_AUDIO_BUFFER_MAX_MS = 30 * 1000;\n// Sample rate we pin on the publish-side Opus encoder. Opus only supports\n// {8, 12, 16, 24, 48} kHz; 48 kHz is the upstream default and what most\n// browsers report as the mic's native rate. The bot reads this from our\n// catalog and resamples to its `audio_in_sample_rate` after decode, so we\n// don't need to match it exactly — but pinning it keeps the catalog\n// unambiguous.\nconst DEFAULT_AUDIO_SAMPLE_RATE = 48000;\n\n/**\n * Constructor options for the MoQ transport.\n *\n * The browser dials a MOQ peer (relay or bot in serve mode) at\n * ``relayUrl`` and publishes its mic under ``<namespace>/<clientId>``\n * while consuming the bot under ``<namespace>/<botId>``. Audio tracks\n * inside each broadcast are catalog-driven (codec, sample rate, channel\n * count are discovered at connect time), so they aren't pinned here.\n */\nexport interface MoqTransportOptions {\n /**\n * Full URL of the MOQ peer (e.g. ``https://relay.example.com:4080/moq``).\n * WebTransport (HTTPS/HTTP3); @moq/net races WebSocket as a fallback\n * if WebTransport isn't reachable.\n */\n relayUrl: string;\n\n /**\n * Pinned cert hashes for self-signed dev setups. Same shape as the\n * native WebTransport ``serverCertificateHashes`` option.\n */\n serverCertificateHashes?: WebTransportHash[];\n\n /**\n * This client's participant id. Combined with ``namespace`` it forms\n * the broadcast path the client publishes under: ``<namespace>/<clientId>``.\n */\n clientId?: string;\n\n /**\n * The peer (bot) participant id to consume. Subscriptions target\n * ``<namespace>/<botId>``; track names come from the bot's catalog.\n */\n botId?: string;\n\n /**\n * Top-level namespace (analogous to a room name). Defaults to ``\"pipecat\"``.\n */\n namespace?: string;\n\n /**\n * Track name for RTVI server→client messages (transcripts, bot-ready,\n * speech events, etc.). The client subscribes at\n * ``<namespace>/<botId>/<transcriptTrack>``. Defaults to\n * ``\"transcript.json.z\"``.\n *\n * Stays pinned because the transcript is a ``@moq/json`` stream track\n * (an ordered, lossless append-log, wire-compatible with the bot's Rust\n * ``moq_json::stream``), not a catalog rendition — the catalog only\n * describes media tracks (audio/video). The ``.z`` suffix marks that the\n * stream is compressed.\n */\n transcriptTrack?: string;\n\n /**\n * Latency floor (ms) — the jitter buffer the player keeps before\n * playback. Lower = more interactive, more drops; higher = smoother,\n * more glass-to-glass delay. Maps to the `min` bound of the\n * ``@moq/watch`` ``Sync.latency`` range.\n */\n audioLatencyMs?: number;\n\n /**\n * Latency ceiling for buffered playback (the `max` bound of the\n * ``@moq/watch`` ``Sync.latency`` range).\n *\n * The bot writes TTS audio faster than real-time with future-dated\n * timestamps; the player buffers it and plays at the encoded pace\n * instead of skipping ahead. This sets how much it's allowed to\n * build up before re-anchoring:\n *\n * - a number (default: 30 s) — cap the buffer at that many ms. The\n * player retains up to this much faster-than-real-time audio before\n * dropping; an interruption (``user-started-speaking``) flushes early\n * via ``reset()``. The bot paces a little under this so it never\n * actually overruns the cap.\n * - ``\"real-time\"`` — collapse to the floor (minimize latency, the old\n * skip-ahead behavior; only useful with a live, real-time publisher).\n */\n audioBufferMaxMs?: number | \"real-time\";\n\n /**\n * Sample rate (Hz) the client publishes its mic audio at. Must be one\n * of Opus's supported rates: 8000, 12000, 16000, 24000, or 48000.\n * Defaults to ``48000`` to match the typical browser mic rate.\n *\n * The bot reads this from the client's catalog and resamples to its\n * own ``audio_in_sample_rate`` after Opus decode, so exact agreement\n * isn't required — pinning a known value just keeps the catalog\n * unambiguous.\n *\n * Bot-side playback sample rate isn't an option here: ``MoqTransport``\n * reads whatever the bot advertises in its catalog and configures its\n * playback ``AudioContext`` accordingly.\n */\n audioSampleRate?: number;\n}\n\ninterface ResolvedOptions {\n relayUrl: string;\n serverCertificateHashes?: WebTransportHash[];\n clientId: string;\n botId: string;\n namespace: string;\n transcriptTrack: string;\n audioLatencyMs: number;\n audioBufferMaxMs: number | \"real-time\";\n audioSampleRate: number;\n}\n\nfunction applyDefaults(opts: MoqTransportOptions): ResolvedOptions {\n return {\n relayUrl: opts.relayUrl,\n serverCertificateHashes: opts.serverCertificateHashes,\n clientId: opts.clientId ?? DEFAULT_CLIENT_ID,\n botId: opts.botId ?? DEFAULT_BOT_ID,\n namespace: opts.namespace ?? DEFAULT_NAMESPACE,\n transcriptTrack: opts.transcriptTrack ?? DEFAULT_TRANSCRIPT_TRACK,\n audioLatencyMs: opts.audioLatencyMs ?? DEFAULT_AUDIO_LATENCY_MS,\n audioBufferMaxMs: opts.audioBufferMaxMs ?? DEFAULT_AUDIO_BUFFER_MAX_MS,\n audioSampleRate: opts.audioSampleRate ?? DEFAULT_AUDIO_SAMPLE_RATE,\n };\n}\n\n/**\n * Shape of the bot's `/start` response when it's running the MoQ transport\n * (``pipecat.transports.moq.transport``). The bot nests its config under\n * ``moq`` so a single `/start` endpoint can serve multiple transport types\n * — apps pass this straight to ``PipecatClient.connect()`` with no\n * transport-specific glue on the app side.\n */\ninterface MoqStartResponse {\n moq?: {\n relayUrl: string;\n certHash: string | null;\n namespace: string;\n clientId: string;\n botId: string;\n transcriptTrack: string;\n };\n}\n\nfunction isMoqStartResponse(value: object): value is MoqStartResponse {\n return \"moq\" in value;\n}\n\n/** Decode the bot's base64 SHA-256 cert hash into the ArrayBuffer shape\n * ``WebTransport.serverCertificateHashes`` expects. */\nfunction decodeCertHash(b64: string): ArrayBuffer {\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes.buffer;\n}\n\n/**\n * ``MoqTransport`` — Pipecat Client SDK transport plugin for Media-over-QUIC.\n *\n * Built on the official ``moq`` library family:\n *\n * - ``@moq/net`` for connection management (``Connection.Reload``\n * auto-reconnects on drops; races WebTransport + WebSocket).\n * - ``@moq/publish`` for mic capture and Opus encoding via\n * ``Publish.Source.Microphone`` + ``Publish.Broadcast``.\n * - ``@moq/watch`` for bot audio playback: ``Watch.Broadcast`` discovers\n * the catalog, ``Watch.Audio.Source`` picks a rendition, and\n * ``Watch.Audio.Decoder`` + ``Watch.Audio.Emitter`` drive an\n * ``AudioWorklet`` with a ring buffer (loss-tolerant, low-latency).\n * - ``@moq/json`` for the transcript tracks — the ``Stream`` mode: an\n * ordered, lossless append-log (wire-compatible with the bot's Rust\n * ``moq_json::stream``), so no RTVI event is dropped. Not the snapshot\n * mode, which collapses to the latest value.\n * - ``@moq/signals`` for reactive plumbing.\n *\n * Two transcript tracks flow in opposite directions, both named\n * ``transcript.json.z`` (or whatever the shared ``transcriptTrack`` option\n * is set to) on their respective broadcasts:\n *\n * - Bot → client: bot publishes RTVI events (``bot-output``,\n * ``bot-transcription``, ``bot-started-speaking``, ``metrics``, …);\n * client subscribes and delivers to ``PipecatClient`` via ``_onMessage``.\n * - Client → bot: ``sendMessage`` writes each RTVI message on the client's\n * own transcript track; the bot's Python transport\n * (``pipecat.transports.moq.transport``) subscribes and dispatches them\n * through ``RTVIProcessor`` the same way any other transport does. This\n * is what carries ``client-ready`` for protocol-version negotiation,\n * typed text input, function-call results, and any other client→server\n * RTVI traffic.\n */\nexport class MoqTransport extends Transport {\n public static SERVICE_NAME = \"moq-transport\";\n\n // Resolved options (defaults applied), captured at construction time\n // and overridden by `_validateConnectionParams` at connect time.\n private _moqOptions: ResolvedOptions;\n\n // Connection + reactive root.\n private _reload: Moq.Connection.Reload | null = null;\n private _signals: Effect | null = null;\n\n // Publish side (mic → bot).\n private _publishBroadcast: Publish.Broadcast | null = null;\n private _microphone: Publish.Source.Microphone | null = null;\n // RTVI JSON side-channel from client → bot, symmetric with the bot's\n // outbound `transcript` track. Published as a lossless `@moq/json`\n // append-stream (compression on); `sendMessage` appends each RTVI\n // message and the bot's `_forward_peer_transcript` on the Python side\n // drains it. The stream Producer binds to a single track with no\n // built-in fan-out, and `publishTrack` serves each subscriber its own\n // track, so we hold one Producer per subscription (`_transcriptOut`)\n // and replay the message log (`_transcriptLog`) into each — so a bot\n // that subscribes late still gets every message, in order.\n private _transcriptOut: Set<Json.Stream.Producer<RTVIMessage>> | null = null;\n private _transcriptLog: RTVIMessage[] | null = null;\n private _micEnabled = new Signal(true);\n private _micConstraints = new Signal<MediaTrackConstraints | undefined>(\n undefined,\n );\n private _preferredMicId = new Signal<string | undefined>(undefined);\n // Encoder sample rate is wired into the catalog the bot reads. We\n // expose this as a Signal so `_connect` can update it from the resolved\n // options at connect time.\n private _audioSampleRate = new Signal<number | undefined>(undefined);\n\n // Watch side (bot → playback). Buffered playback via @moq/watch:\n // Broadcast -> Audio.Source -> Decoder -> Emitter, with `Sync.latencyMax`\n // letting faster-than-real-time TTS build up instead of the player\n // skipping ahead, and `reset()` flushing the buffer on interruption.\n private _watchBroadcast: Watch.Broadcast | null = null;\n private _sync: Watch.Sync | null = null;\n private _audioSource: Watch.Audio.Source | null = null;\n private _audioDecoder: Watch.Audio.Decoder | null = null;\n private _audioEmitter: Watch.Audio.Emitter | null = null;\n\n // Synthesized `MediaStreamTrack` for the bot, so `tracks().bot.audio`\n // returns something a `<audio>` element / visualizer can consume.\n // Tapped off `Watch.Audio.Decoder.root` (an `AudioNode`) into a\n // `MediaStreamAudioDestinationNode`.\n private _botAudioTrack: MediaStreamTrack | undefined;\n\n // Transport lifecycle state. Mirrored to `_callbacks.onTransportStateChanged`.\n declare protected _state: TransportState;\n\n constructor(options: MoqTransportOptions) {\n super();\n this._moqOptions = applyDefaults(options);\n this._state = \"disconnected\";\n }\n\n // --------------------------------------------------------------------\n // Lifecycle\n // --------------------------------------------------------------------\n\n initialize(\n options: PipecatClientOptions,\n messageHandler: (ev: RTVIMessage) => void,\n ): void {\n this._options = options;\n this._callbacks = options.callbacks ?? ({} as RTVIEventCallbacks);\n this._onMessage = messageHandler;\n this.state = \"initialized\";\n }\n\n async initDevices(): Promise<void> {\n // Spin up the Microphone with permission requested so labels are\n // available for the picker before the user clicks Connect. Real\n // capture constraints (incl. sample rate) get applied in `_connect`\n // once we have the resolved options.\n if (!this._microphone) {\n this._microphone = new Publish.Source.Microphone({\n enabled: this._micEnabled,\n constraints: this._micConstraints,\n device: { preferred: this._preferredMicId },\n });\n }\n this._microphone.device.requestPermission();\n }\n\n _validateConnectionParams(connectParams?: unknown): MoqTransportOptions {\n if (connectParams === undefined || connectParams === null) {\n return this._optionsAsInput();\n }\n if (typeof connectParams !== \"object\") {\n throw new RTVIError(\"MoqTransport connect params must be an object\");\n }\n // The bot's `/start` response is `{ moq: {...} }`, not already-shaped\n // `MoqTransportOptions` — unwrap and decode it here so apps can pass\n // the raw response straight through with no transport-specific glue.\n if (isMoqStartResponse(connectParams)) {\n const { moq } = connectParams;\n if (!moq) {\n throw new RTVIError(\n \"MoqTransport connect params did not include `moq` config (server may not be running with `-t moq`)\",\n );\n }\n return {\n ...this._optionsAsInput(),\n relayUrl: moq.relayUrl,\n clientId: moq.clientId,\n botId: moq.botId,\n namespace: moq.namespace,\n transcriptTrack: moq.transcriptTrack,\n serverCertificateHashes: moq.certHash\n ? [{ algorithm: \"sha-256\", value: decodeCertHash(moq.certHash) }]\n : undefined,\n };\n }\n return { ...this._optionsAsInput(), ...(connectParams as Partial<MoqTransportOptions>) };\n }\n\n /** Return the resolved options re-shaped to the public input type\n * (used when merging with connect-time params). */\n private _optionsAsInput(): MoqTransportOptions {\n return { ...this._moqOptions };\n }\n\n async _connect(connectParams?: MoqTransportOptions): Promise<void> {\n const merged = connectParams\n ? { ...this._moqOptions, ...applyDefaults({ ...this._moqOptions, ...connectParams }) }\n : this._moqOptions;\n if (!merged.relayUrl) {\n throw new RTVIError(\"MoqTransport requires `relayUrl`\");\n }\n this._moqOptions = merged;\n\n this.state = \"connecting\";\n\n let url: URL;\n try {\n url = new URL(merged.relayUrl);\n } catch (err) {\n this.state = \"error\";\n throw new RTVIError(\n `MoqTransport invalid relayUrl ${JSON.stringify(merged.relayUrl)}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n\n // @moq/net narrows `algorithm` to the literal `\"sha-256\"`, while\n // the browser's `WebTransportHash` types it as `string`. Cast at\n // the boundary; SHA-256 is the only algorithm WebTransport accepts.\n const webtransport = merged.serverCertificateHashes\n ? {\n serverCertificateHashes: merged.serverCertificateHashes.flatMap(\n (h) =>\n h.value ? [{ algorithm: \"sha-256\" as const, value: h.value }] : [],\n ),\n }\n : undefined;\n\n // Reload auto-reconnects on disconnect; Publish.Broadcast and\n // Watch.Broadcast both react to its `established` signal.\n this._reload = new Moq.Connection.Reload({\n enabled: new Signal(true),\n url: new Signal(url),\n webtransport,\n });\n\n // One reactive root for status mirroring. Connect/Watch are\n // self-driving via their own internal effects.\n this._signals = new Effect();\n this._signals.run((eff) => {\n const status = eff.get(this._reload!.status);\n if (status === \"connected\") {\n if (this._state === \"connecting\") this.state = \"connected\";\n } else if (status === \"connecting\") {\n this.state = \"connecting\";\n } else if (status === \"disconnected\") {\n if (this._state !== \"disconnecting\" && this._state !== \"disconnected\") {\n this.state = \"disconnected\";\n }\n }\n });\n\n const ourPath = Moq.Path.from(merged.namespace, merged.clientId);\n const botPath = Moq.Path.from(merged.namespace, merged.botId);\n\n // ----------------------------------------------------------------\n // Publish — Microphone owns getUserMedia, device selection, and\n // produces a reactive `source` signal that Publish.Broadcast\n // consumes. Constraints (channelCount:1, sampleRate) and preferred\n // deviceId flow through the signals we hold a reference to, so\n // updateMic() re-routes audio without re-creating the broadcast.\n // The encoder's sampleRate Signal pins what the catalog advertises.\n // ----------------------------------------------------------------\n this._micConstraints.set({\n channelCount: { exact: 1 },\n sampleRate: { ideal: merged.audioSampleRate },\n echoCancellation: true,\n noiseSuppression: true,\n });\n this._audioSampleRate.set(merged.audioSampleRate);\n\n if (!this._microphone) {\n this._microphone = new Publish.Source.Microphone({\n enabled: this._micEnabled,\n constraints: this._micConstraints,\n device: { preferred: this._preferredMicId },\n });\n }\n\n this._publishBroadcast = new Publish.Broadcast({\n connection: this._reload.established,\n enabled: new Signal(true),\n name: new Signal(ourPath),\n audio: {\n source: this._microphone.source,\n enabled: this._micEnabled,\n sampleRate: this._audioSampleRate,\n },\n });\n\n // Client-side transcript: `sendMessage` appends each RTVI message to\n // a lossless JSON append-stream. `publishTrack` hands us a fresh track\n // per subscription (only one, in the normal single-bot flow), so we\n // spin up a `Json.Stream.Producer` per subscriber and replay the\n // message log into it — a bot that subscribes after we've already sent\n // messages still gets the full log, in order. The bot subscribes to\n // this track by its name — same convention as the bot's own transcript\n // track — so no catalog entry is needed.\n this._transcriptLog = [];\n this._transcriptOut = new Set<Json.Stream.Producer<RTVIMessage>>();\n this._publishBroadcast.publishTrack(\n merged.transcriptTrack,\n (track, effect) => {\n const producer = new Json.Stream.Producer<RTVIMessage>(track, {\n compression: true,\n });\n for (const msg of this._transcriptLog ?? []) producer.append(msg);\n this._transcriptOut?.add(producer);\n effect.cleanup(() => {\n this._transcriptOut?.delete(producer);\n producer.finish();\n });\n },\n );\n\n // Log the mic settings the browser actually granted, so we can see\n // when a UA ignores the constraint (e.g. macOS often pins 48k\n // regardless of `sampleRate.ideal`).\n this._signals.run((eff) => {\n const src = eff.get(this._microphone!.source);\n if (!src) return;\n const track = \"track\" in src ? src.track : src;\n const s = track.getSettings();\n console.log(\n `[MoqTransport] publish: requested=${merged.audioSampleRate}Hz, ` +\n `mic granted=${s.sampleRate}Hz, channels=${s.channelCount}, ` +\n `deviceId=${s.deviceId}`,\n );\n });\n\n // ----------------------------------------------------------------\n // Watch — Broadcast handles catalog discovery and rendition\n // tracking; Audio.Source picks the active audio rendition;\n // Audio.Decoder runs the WebCodecs decode loop and feeds an\n // AudioWorklet ring buffer; Audio.Emitter routes that to the\n // speakers. `Sync.latencyMax` lets faster-than-real-time TTS build\n // up a buffer instead of the player skipping ahead; `reset()`\n // (invoked on `user-started-speaking`) flushes it on interruption.\n // We also tap Decoder.root → MediaStreamAudioDestinationNode so\n // tracks().bot.audio returns a MediaStreamTrack.\n //\n // `catalogFormat: \"hang\"` is pinned because the pipecat bot publishes\n // a hang-format catalog (camelCase `sampleRate`). The auto-detector\n // would also land on \"hang\" here (no suffix on the broadcast name,\n // and hang is the DEFAULT_FORMAT) but pinning removes ambiguity if\n // a future publisher adds a suffix or a different default ships.\n // ----------------------------------------------------------------\n this._watchBroadcast = new Watch.Broadcast({\n connection: this._reload.established,\n enabled: new Signal(true),\n name: new Signal(botPath),\n catalogFormat: new Signal<Watch.CatalogFormat>(\"hang\"),\n });\n\n // Latency range: floor = interactive jitter buffer (audioLatencyMs),\n // ceiling = how much faster-than-real-time TTS the player will hold\n // before dropping (audioBufferMaxMs). A number-typed max opens the\n // buffer; \"real-time\" collapses to the floor (skip-ahead behavior).\n const sync = new Watch.Sync({\n connection: this._reload.established,\n latency: new Signal<Watch.Latency>({\n min: merged.audioLatencyMs as Moq.Time.Milli,\n max:\n merged.audioBufferMaxMs === \"real-time\"\n ? \"real-time\"\n : (merged.audioBufferMaxMs as Moq.Time.Milli),\n }),\n });\n this._sync = sync;\n this._audioSource = new Watch.Audio.Source(sync, {\n broadcast: this._watchBroadcast,\n });\n this._audioDecoder = new Watch.Audio.Decoder(this._audioSource, {\n enabled: new Signal(true),\n });\n this._audioEmitter = new Watch.Audio.Emitter(this._audioDecoder);\n\n // Bridge Decoder.root (AudioNode) → MediaStreamTrack for tracks().bot.audio.\n this._signals.run((eff) => {\n const ctx = eff.get(this._audioDecoder!.context);\n const root = eff.get(this._audioDecoder!.root);\n if (!ctx || !root) return;\n const dest = ctx.createMediaStreamDestination();\n root.connect(dest);\n this._botAudioTrack = dest.stream.getAudioTracks()[0];\n eff.cleanup(() => {\n try {\n root.disconnect(dest);\n } catch {\n // best-effort.\n }\n this._botAudioTrack?.stop();\n this._botAudioTrack = undefined;\n });\n });\n\n // Log the bot's announced audio config + the AudioContext rate we\n // ended up at. If these disagree the voice will play at the wrong\n // pitch — the catalog drives the AudioContext, so a mismatch means\n // either a parser bug or the bot is advertising a rate that doesn't\n // match its actual Opus stream.\n this._signals.run((eff) => {\n const config = eff.get(this._audioSource!.config);\n const ctx = eff.get(this._audioDecoder!.context);\n if (!config && !ctx) return;\n console.log(\n `[MoqTransport] consume: catalog codec=${config?.codec}, ` +\n `catalog sampleRate=${config?.sampleRate}Hz, ` +\n `catalog channels=${config?.numberOfChannels}, ` +\n `AudioContext rate=${ctx?.sampleRate}Hz`,\n );\n });\n\n // Transcript — a lossless JSON append-stream over a single track. We\n // re-subscribe on each (re)connect; @moq/json's stream Consumer yields\n // every appended record in order, losslessly.\n this._signals.run((eff) => {\n const conn = eff.get(this._reload!.established);\n if (!conn) return;\n const botBroadcast = conn.consume(botPath);\n const track = botBroadcast.subscribe(merged.transcriptTrack, 0);\n const consumer = new Json.Stream.Consumer<RTVIMessage>(track, {\n compression: true,\n });\n const ac = new AbortController();\n this._drainTranscript(consumer, ac.signal).catch((e) => {\n if (!ac.signal.aborted) {\n console.warn(\"MoqTransport bot-transcript loop:\", e);\n }\n });\n eff.cleanup(() => {\n ac.abort();\n try {\n track.close();\n } catch {\n // best-effort.\n }\n });\n });\n }\n\n async _disconnect(): Promise<void> {\n if (this._state === \"disconnected\") return;\n this.state = \"disconnecting\";\n try {\n this._audioEmitter?.close();\n this._audioDecoder?.close();\n this._audioSource?.close();\n this._sync?.close();\n this._watchBroadcast?.close();\n // Each producer's own effect.cleanup (registered in the `publishTrack`\n // callback above) already calls producer.finish() when this cascades\n // through the broadcast's internal effect scope — no need to also\n // finish them explicitly here.\n this._publishBroadcast?.close();\n this._microphone?.close();\n this._signals?.close();\n this._reload?.close();\n } finally {\n this._audioEmitter = null;\n this._audioDecoder = null;\n this._audioSource = null;\n this._sync = null;\n this._watchBroadcast = null;\n this._transcriptOut = null;\n this._transcriptLog = null;\n this._publishBroadcast = null;\n this._microphone = null;\n this._signals = null;\n this._reload = null;\n this.state = \"disconnected\";\n // Fire the SDK's disconnected callback. `state = \"disconnected\"`\n // above already triggers `onTransportStateChanged`, but the SDK\n // wires UI teardown (voice-ui-kit's connection-state hook, the\n // `Disconnected` event, message-dispatcher cleanup) through\n // `onDisconnected` — without this call the transport goes idle\n // but the UI stays stuck in \"connected\" and never restores its\n // \"Connect\" button. Matches the pattern used by\n // small-webrtc-transport, openai-realtime-webrtc-transport, and\n // gemini-live-websocket-transport.\n this._callbacks?.onDisconnected?.();\n }\n }\n\n sendReadyMessage(): void {\n // Flip transport state to `ready` and dispatch the RTVI `client-ready`\n // message on the client→bot transcript track so the bot's RTVIProcessor\n // can negotiate protocol version. Mirrors the pattern used by\n // small-webrtc-transport and daily-transport.\n this.state = \"ready\";\n this.sendMessage(RTVIMessage.clientReady());\n }\n\n // --------------------------------------------------------------------\n // State\n // --------------------------------------------------------------------\n\n get state(): TransportState {\n return this._state;\n }\n\n set state(next: TransportState) {\n if (this._state === next) return;\n this._state = next;\n this._callbacks?.onTransportStateChanged?.(next);\n }\n\n // --------------------------------------------------------------------\n // Devices\n // --------------------------------------------------------------------\n\n async getAllMics(): Promise<MediaDeviceInfo[]> {\n return this._microphone?.device.available.peek() ?? [];\n }\n\n async getAllCams(): Promise<MediaDeviceInfo[]> {\n return [];\n }\n\n async getAllSpeakers(): Promise<MediaDeviceInfo[]> {\n return [];\n }\n\n updateMic(micId: string): void {\n this._preferredMicId.set(micId);\n }\n\n updateCam(_camId: string): void {}\n\n updateSpeaker(_speakerId: string): void {}\n\n get selectedMic(): MediaDeviceInfo | Record<string, never> {\n const id = this._microphone?.device.active.peek();\n if (!id) return {};\n return (\n this._microphone?.device.available.peek()?.find((d) => d.deviceId === id) ??\n {}\n );\n }\n\n get selectedCam(): MediaDeviceInfo | Record<string, never> {\n return {};\n }\n\n get selectedSpeaker(): MediaDeviceInfo | Record<string, never> {\n return {};\n }\n\n enableMic(enable: boolean): void {\n this._micEnabled.set(enable);\n }\n\n enableCam(_enable: boolean): void {}\n\n enableScreenShare(_enable: boolean): void {}\n\n get isCamEnabled(): boolean {\n return false;\n }\n\n get isMicEnabled(): boolean {\n return this._micEnabled.get();\n }\n\n get isSharingScreen(): boolean {\n return false;\n }\n\n // --------------------------------------------------------------------\n // Messaging + tracks\n // --------------------------------------------------------------------\n\n sendMessage(message: RTVIMessage): void {\n if (!this._transcriptOut || !this._transcriptLog) {\n console.warn(\n \"[MoqTransport] sendMessage called before connect; dropping\",\n message,\n );\n return;\n }\n // Append to the lossless stream. Keep a log too, so a bot that\n // subscribes after this point is replayed every message in order\n // (see the `publishTrack` serve callback above).\n this._transcriptLog.push(message);\n for (const producer of this._transcriptOut) producer.append(message);\n }\n\n tracks(): Tracks {\n const localSource = this._microphone?.source.peek();\n const localAudio =\n localSource && \"track\" in localSource ? localSource.track : localSource;\n return {\n local: localAudio ? { audio: localAudio } : {},\n bot: this._botAudioTrack ? { audio: this._botAudioTrack } : {},\n };\n }\n\n // --------------------------------------------------------------------\n // Internals — transcript\n // --------------------------------------------------------------------\n\n /** Pull RTVI messages off the @moq/json stream consumer and hand each\n * one to `PipecatClient` via `_onMessage`. The handler resolves the\n * SDK's connect promise when bot-ready arrives. */\n private async _drainTranscript(\n consumer: Json.Stream.Consumer<RTVIMessage>,\n signal: AbortSignal,\n ): Promise<void> {\n for (;;) {\n const message = await consumer.next();\n if (!message || signal.aborted) break;\n if (typeof message !== \"object\") continue;\n // Intra-transport shutdown signal from the bot: bot is about to\n // close its MoQ session. Disable auto-reconnect, tear down the\n // audio decoder + subscribers on our side while WebTransport is\n // still healthy — without this the connection just vanishes\n // underneath Chrome's WebCodecs decoder and can crash the\n // renderer. Not an RTVI event; don't forward it to `_onMessage`.\n const label = (message as { label?: string }).label;\n const type = (message as { type?: string }).type;\n if (label === \"moq-transport\" && type === \"session-ending\") {\n console.log(\"[MoqTransport] bot signaled session-ending — closing cleanly\");\n // Fire-and-forget; we're returning from the drain loop right\n // after, and _disconnect() aborts the consumer that owns us.\n void this._disconnect();\n return;\n }\n // Interruption: the user started talking, so flush the\n // already-buffered TTS for the bot's previous utterance instead\n // of letting it drain. With the bot writing faster than\n // real-time, that buffer can be seconds long.\n if (type === \"user-started-speaking\") {\n this._resetBotAudio();\n }\n this._onMessage?.(message);\n }\n }\n\n /** Flush buffered bot audio and re-anchor playback at an utterance\n * boundary. Called on interruption (`user-started-speaking`) so the\n * already-buffered TTS for the previous utterance stops immediately\n * instead of draining: re-anchor the sync reference and flush the\n * decoder's ring buffer. */\n private _resetBotAudio(): void {\n this._sync?.reset();\n this._audioDecoder?.reset();\n }\n}\n"],"names":[],"version":3,"file":"index.module.js.map"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pipecat-ai/moq-transport",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "BSD-2-Clause",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.module.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"source": "src/index.ts",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/pipecat-ai/pipecat-client-web-transports.git"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"package.json",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "parcel build --no-cache",
|
|
20
|
+
"dev": "parcel watch",
|
|
21
|
+
"lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@pipecat-ai/client-js": "^1.13.0",
|
|
25
|
+
"@types/node": "^22.9.0",
|
|
26
|
+
"eslint": "9.39.1",
|
|
27
|
+
"eslint-config-prettier": "^9.1.0",
|
|
28
|
+
"eslint-plugin-simple-import-sort": "^12.1.1"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@pipecat-ai/client-js": "~1.13.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@moq/hang": "^0.2.12",
|
|
35
|
+
"@moq/json": "^0.1.2",
|
|
36
|
+
"@moq/net": "^0.1.6",
|
|
37
|
+
"@moq/publish": "^0.2.16",
|
|
38
|
+
"@moq/signals": "^0.1.10",
|
|
39
|
+
"@moq/watch": "^0.2.18"
|
|
40
|
+
},
|
|
41
|
+
"description": "Pipecat Media-over-QUIC (MoQ) Transport Package",
|
|
42
|
+
"author": "Daily.co",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/pipecat-ai/pipecat-client-web-transports/issues"
|
|
45
|
+
}
|
|
46
|
+
}
|