diff --git a/src/lotus/lotusActions.ts b/src/lotus/lotusActions.ts index b19e9f37..44cb4339 100644 --- a/src/lotus/lotusActions.ts +++ b/src/lotus/lotusActions.ts @@ -11,7 +11,13 @@ Please see LICENSE in the repository root for full details. * a circular dependency. */ export enum LotusWidgetActions { - /** fromWidget: in-call per-participant speaking / mute state. */ + /** + * fromWidget: in-call per-participant speaking / mute state. + * NOTE: matrix-widget-api `transport.send` is request/response — the host + * MUST reply/ack each one (cinny's `listenAction` does, replying `{}`), + * otherwise every send sits pending for the 10s transport timeout and then + * rejects, producing continuous churn + log noise for the whole call. + */ CallState = "io.lotus.call_state", /** toWidget: pin/spotlight (or clear, with userId=null) a participant. */ FocusParticipant = "io.lotus.focus_participant", diff --git a/src/lotus/lotusCallState.ts b/src/lotus/lotusCallState.ts index ee60d38e..86c7ea88 100644 --- a/src/lotus/lotusCallState.ts +++ b/src/lotus/lotusCallState.ts @@ -12,7 +12,7 @@ import { type CallViewModel } from "../state/CallViewModel/CallViewModel"; import { LotusWidgetActions, lotusFlag, lotusSendToHost } from "./lotusWidget"; interface ParticipantState { - /** Opaque media id (stable per tile). */ + /** EC media id (`${userId}:${deviceId}`), stable per participant device. */ id: string; /** Matrix user id this media belongs to. */ userId: string; @@ -59,7 +59,9 @@ export function startLotusCallState(vm: CallViewModel): () => void { ), ), // `speaking` flips rapidly; cap the send rate and drop no-op repeats. - throttleTime(150, undefined, { leading: true, trailing: true }), + // 250ms is plenty for speaking rings / mute badges and keeps the + // request/response widget traffic modest. + throttleTime(250, undefined, { leading: true, trailing: true }), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), ) .subscribe((participants) => { diff --git a/src/lotus/lotusWidget.ts b/src/lotus/lotusWidget.ts index 4144b315..77d7d7ba 100644 --- a/src/lotus/lotusWidget.ts +++ b/src/lotus/lotusWidget.ts @@ -30,10 +30,12 @@ let cachedParams: URLSearchParams | undefined; */ export function lotusParam(name: string): string | null { if (!cachedParams) { - cachedParams = new URLSearchParams(window.location.search); + // Match EC's own ParamParser precedence: the hash fragment wins over the + // query string. So seed from the fragment first, then fill gaps from query. const hash = window.location.hash.replace(/^#\/?/, ""); const hashQuery = hash.includes("?") ? hash.slice(hash.indexOf("?") + 1) : ""; - for (const [k, v] of new URLSearchParams(hashQuery)) { + cachedParams = new URLSearchParams(hashQuery); + for (const [k, v] of new URLSearchParams(window.location.search)) { if (!cachedParams.has(k)) cachedParams.append(k, v); } }