@mentra/engine 3.2.0-dev.248 → 3.2.0-dev.250

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.
@@ -152,6 +152,13 @@ export interface SoftapCallDeps {
152
152
  * that never delivers a frame reads as healthy behind a frozen tile.
153
153
  */
154
154
  awaitFirstFrame(report?: SoftapStepReporter): Promise<void>;
155
+ /**
156
+ * Mid-call camera recovery. Resolves `true` only when ingest is live again.
157
+ * A standing `failed` is the reason we are republishing, so it must not abort the wait.
158
+ */
159
+ waitUntilLive?(timeoutMs: number): Promise<boolean>;
160
+ /** Delay after a failed `start_stream` before the next republish attempt. Tests set 0. */
161
+ republishRetryDelayMs?: number;
155
162
  }
156
163
  export interface SoftapCallOptions {
157
164
  /** Override the minted trace id, so a caller can correlate with logs it already started. */
@@ -169,6 +176,8 @@ export interface SoftapCallOptions {
169
176
  */
170
177
  initialSteps?: SoftapStepState[];
171
178
  }
179
+ /** How long a mid-call republish waits for a frame after re-issuing `start_stream`. */
180
+ export declare const SOFTAP_REPUBLISH_LIVE_MS = 20000;
172
181
  /**
173
182
  * How a call is being taken down.
174
183
  *
@@ -240,8 +249,24 @@ export declare class SoftapCallTransport {
240
249
  private startedAt;
241
250
  private traceId;
242
251
  private onProgress;
252
+ private republishing;
253
+ /** Bumped by `stop` so an in-flight republish cannot start_stream after Leave. */
254
+ private republishGeneration;
243
255
  constructor(deps: SoftapCallDeps);
244
256
  currentPhase(): SoftapPhase;
257
+ /**
258
+ * The glasses camera died after this call was already live. Re-issue `start_stream` at the
259
+ * existing ingest URL — do not rebind the WHIP listener, or the glasses POST to a dead port.
260
+ */
261
+ shouldRepublish(mediaSource?: string): boolean;
262
+ /**
263
+ * Rebuild the glasses publisher onto the standing SoftAP ingest URL.
264
+ *
265
+ * ACS, BLE mic, and the WHIP listener stay up. The glasses process is what usually vanished
266
+ * (UVC/`system_server` crash); a new `start_stream` is what they need after ASG comes back.
267
+ */
268
+ republish(reason: string): Promise<void>;
269
+ private runRepublish;
245
270
  /**
246
271
  * True once a teardown has been decided. Anything that would otherwise report a failure — a lost
247
272
  * hotspot, a dropped ACS call — must check this first: after the wearer asks to leave, those are
@@ -347,6 +372,11 @@ export declare function createSoftapCallDeps(args: {
347
372
  };
348
373
  /** Resolves when the meeting reports a frame reached ACS; rejects on a failed feed. */
349
374
  awaitFirstFrame: () => Promise<void>;
375
+ /**
376
+ * Mid-call camera recovery. Resolves `true` only when ingest is live again.
377
+ * A standing `failed` is the reason we are republishing, so it must not abort the wait.
378
+ */
379
+ waitUntilLive?: (timeoutMs: number) => Promise<boolean>;
350
380
  subsystems: {
351
381
  setHotspotState: (enabled: boolean) => Promise<{
352
382
  state: string;
@@ -1 +1 @@
1
- {"version":3,"file":"SoftapCallTransport.d.ts","sourceRoot":"","sources":["../../src/services/SoftapCallTransport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SoftapCallTransport.d.ts","sourceRoot":"","sources":["../../src/services/SoftapCallTransport.ts"],"names":[],"mappings":"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"}
@@ -114,6 +114,14 @@ function deferred() {
114
114
  });
115
115
  return { promise, resolve };
116
116
  }
117
+ function sleep(ms) {
118
+ if (ms <= 0)
119
+ return Promise.resolve();
120
+ return new Promise((resolve) => setTimeout(resolve, ms));
121
+ }
122
+ /** How long a mid-call republish waits for a frame after re-issuing `start_stream`. */
123
+ export const SOFTAP_REPUBLISH_LIVE_MS = 20_000;
124
+ const REPUBLISH_RETRY_DELAY_MS = 2_000;
117
125
  export class SoftapEndNotSupportedError extends Error {
118
126
  constructor() {
119
127
  super("This host cannot end a meeting for everyone");
@@ -176,12 +184,84 @@ export class SoftapCallTransport {
176
184
  startedAt = 0;
177
185
  traceId = "";
178
186
  onProgress;
187
+ republishing = null;
188
+ /** Bumped by `stop` so an in-flight republish cannot start_stream after Leave. */
189
+ republishGeneration = 0;
179
190
  constructor(deps) {
180
191
  this.deps = deps;
181
192
  }
182
193
  currentPhase() {
183
194
  return this.phase;
184
195
  }
196
+ /**
197
+ * The glasses camera died after this call was already live. Re-issue `start_stream` at the
198
+ * existing ingest URL — do not rebind the WHIP listener, or the glasses POST to a dead port.
199
+ */
200
+ shouldRepublish(mediaSource) {
201
+ return this.phase === "live" && !this.terminating && mediaSource === "failed";
202
+ }
203
+ /**
204
+ * Rebuild the glasses publisher onto the standing SoftAP ingest URL.
205
+ *
206
+ * ACS, BLE mic, and the WHIP listener stay up. The glasses process is what usually vanished
207
+ * (UVC/`system_server` crash); a new `start_stream` is what they need after ASG comes back.
208
+ */
209
+ republish(reason) {
210
+ if (this.phase !== "live" || this.terminating || !this.ingestUrl)
211
+ return Promise.resolve();
212
+ if (this.republishing)
213
+ return this.republishing;
214
+ const generation = this.republishGeneration;
215
+ this.republishing = this.runRepublish(reason, generation).finally(() => {
216
+ if (this.republishGeneration === generation)
217
+ this.republishing = null;
218
+ });
219
+ return this.republishing;
220
+ }
221
+ async runRepublish(reason, generation) {
222
+ const ingestUrl = this.ingestUrl;
223
+ if (!ingestUrl)
224
+ return;
225
+ const retryDelayMs = this.deps.republishRetryDelayMs ?? REPUBLISH_RETRY_DELAY_MS;
226
+ let attempt = 0;
227
+ softapTrace("glasses_republish_begin", { reason, ingestUrl });
228
+ while (generation === this.republishGeneration &&
229
+ !this.terminating &&
230
+ this.phase === "live" &&
231
+ this.ingestUrl === ingestUrl) {
232
+ attempt += 1;
233
+ try {
234
+ await this.deps.stopPublishing();
235
+ if (generation !== this.republishGeneration || this.terminating)
236
+ return;
237
+ await this.deps.startPublishing({ ingestUrl, traceId: this.traceId });
238
+ if (generation !== this.republishGeneration || this.terminating) {
239
+ await this.deps.stopPublishing().catch(() => undefined);
240
+ return;
241
+ }
242
+ softapTrace("glasses_republish_sent", { attempt, ingestUrl });
243
+ if (!this.deps.waitUntilLive)
244
+ return;
245
+ const live = await this.deps.waitUntilLive(SOFTAP_REPUBLISH_LIVE_MS);
246
+ if (generation !== this.republishGeneration || this.terminating)
247
+ return;
248
+ if (live) {
249
+ softapTrace("glasses_republish_live", { attempt });
250
+ return;
251
+ }
252
+ softapTraceFailure("glasses_republish_no_frame", { attempt });
253
+ }
254
+ catch (error) {
255
+ if (generation !== this.republishGeneration || this.terminating)
256
+ return;
257
+ softapTraceFailure("glasses_republish_start_failed", {
258
+ attempt,
259
+ reason: error instanceof Error ? error.message : String(error),
260
+ });
261
+ await sleep(retryDelayMs);
262
+ }
263
+ }
264
+ }
185
265
  /**
186
266
  * True once a teardown has been decided. Anything that would otherwise report a failure — a lost
187
267
  * hotspot, a dropped ACS call — must check this first: after the wearer asks to leave, those are
@@ -413,6 +493,7 @@ export class SoftapCallTransport {
413
493
  // Intent before action, always: a watcher must be able to tell a deliberate teardown from a
414
494
  // failure even during the very first await below.
415
495
  this.terminating = true;
496
+ this.republishGeneration++;
416
497
  if (options.mode)
417
498
  this.teardownMode = options.mode;
418
499
  if (this.stopping) {
@@ -835,6 +916,7 @@ export function createSoftapCallDeps(args) {
835
916
  },
836
917
  stopPublishing: () => subsystems.stopPublishing(packageName),
837
918
  awaitFirstFrame: args.awaitFirstFrame,
919
+ waitUntilLive: args.waitUntilLive,
838
920
  };
839
921
  }
840
922
  //# sourceMappingURL=SoftapCallTransport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SoftapCallTransport.js","sourceRoot":"","sources":["../../src/services/SoftapCallTransport.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Sequences a SoftAP call. Sequencing only — no sockets, no peers, no BLE.\n *\n * The glasses open a hotspot, the phone joins it without giving up its cellular route, and the\n * glasses publish WebRTC straight to a listener on the phone. Cloudflare is not involved at all.\n *\n * The order below is the whole point of this file, and one step in it is load-bearing:\n *\n * hotspot on -> scoped join -> ACS join (binds the listener and arms the raw outputs)\n * -> glasses publish -> WHIP negotiation -> first frame -> LIVE\n *\n * Publishing must come after the ACS join, not before. `LIVE` means a frame reached ACS, so if the\n * glasses start publishing first, decoded video and audio can arrive before the raw outgoing\n * streams exist and the first frames are dropped by whatever happens to be null at the time. That\n * is not a lifecycle anyone designed; making the order explicit is what removes it.\n *\n * Ownership is deliberately narrow. This object owns the *sequence* and nothing else: the meeting\n * session owns the WHIP listener and the peer, `PhoneStreamCoordinator` owns the publisher, and\n * `localNetworkTransport` owns the scoped network. Every step therefore has exactly one owner that\n * can tear it down, which is what makes leaving mid-join safe.\n */\n\nimport {softapTrace, softapTraceFailure, beginSoftapTrace, resetSoftapTrace} from \"../utils/softapTrace\"\n\n/** Steps in order. Also the teardown order, reversed. */\nexport const SOFTAP_STEPS = [\"hotspot\", \"scopedJoin\", \"acsJoin\", \"publish\", \"live\"] as const\n\nexport type SoftapStep = (typeof SOFTAP_STEPS)[number]\n\n/**\n * Where the sequence is.\n *\n * `starting` covers every step up to `live` because the caller's only useful distinction is\n * \"not yet usable\" versus \"carrying media\"; the step names are for diagnostics, not for branching.\n */\nexport type SoftapPhase = \"idle\" | \"starting\" | \"live\" | \"stopping\" | \"failed\"\n\n/** A failure, named by the step that produced it so the UI and the logs agree on the cause. */\nexport class SoftapCallError extends Error {\n constructor(readonly step: SoftapStep, readonly code: string, message: string, readonly cause?: unknown) {\n super(message)\n this.name = \"SoftapCallError\"\n }\n}\n\n/** Gallery sync already learned this: glasses report enabled before the SSID is in the phone scan. */\nexport const HOTSPOT_BROADCAST_WAIT_MS = 3_000\n\n/**\n * What the glasses→phone hop is worth at 540p over a hotspot with one client and no contention.\n *\n * Not the ACS ceiling: this link is a metre of air between two devices that are already paired,\n * and the profile's `maxBitrateBps` describes the phone→Teams hop, which crosses the internet.\n * Sharing one number between them makes the easy hop obey the hard hop's limits.\n */\nexport const GLASSES_PHONE_BITRATE_BPS = 2_500_000\n\n/** Where the encoder starts. High, because the link is good from the first frame. */\nconst SOFTAP_START_BITRATE_BPS = 2_000_000\n\n/**\n * The floor. This is the whole point of the policy.\n *\n * WHIP's default has none, so after an ICE interruption WebRTC restarts at its own minimum and\n * climbs by probing — which is the \"potato for a while\" the wearer reports. The link did not get\n * worse; the estimator merely forgot what it knew. A floor says: this hop is a hotspot, not a\n * congested uplink, and it is never worth less than this.\n *\n * That trade is the opposite of Mentra-Call#27's cloud-WHIP review: a 1 Mbps floor on Auto over\n * LTE turns a weak WAN into freezes. This function is SoftAP-only. Cloud WHIP must not call it.\n */\nconst SOFTAP_MIN_BITRATE_BPS = 1_200_000\n\n/** Field names are the glasses' `WhipStreamConfig` parser's, where `bitrate` means the maximum. */\nexport interface SoftapVideoPolicy {\n width: number\n height: number\n fps: number\n bitrate: number\n initialBitrateBps: number\n minBitrateBps: number\n}\n\n/**\n * The bitrate the glasses are told to hold on the hop to the phone.\n *\n * The hotspot has its own bitrate budget, independent of the phone-to-Teams cap. Above 540p,\n * allow a higher requested ceiling while retaining the hotspot budget for low WAN caps.\n */\nexport function softapVideoPolicy(video: {\n width: number\n height: number\n fps: number\n maxBitrateBps: number\n}): SoftapVideoPolicy {\n const isSmall = video.width * video.height <= 960 * 540\n if (!Number.isFinite(video.maxBitrateBps) || video.maxBitrateBps <= 0) {\n throw new Error(`invalid SoftAP video bitrate: ${video.maxBitrateBps}`)\n }\n const max = isSmall ? GLASSES_PHONE_BITRATE_BPS : Math.max(GLASSES_PHONE_BITRATE_BPS, video.maxBitrateBps)\n const initialBitrateBps = Math.min(SOFTAP_START_BITRATE_BPS, max)\n const minBitrateBps = Math.min(SOFTAP_MIN_BITRATE_BPS, initialBitrateBps)\n if (!(minBitrateBps <= initialBitrateBps && initialBitrateBps <= max)) {\n throw new Error(`incoherent SoftAP video policy: min=${minBitrateBps} start=${initialBitrateBps} max=${max}`)\n }\n return {\n width: video.width,\n height: video.height,\n fps: video.fps,\n bitrate: max,\n initialBitrateBps,\n minBitrateBps,\n }\n}\n\n/**\n * Android's WifiNetworkSpecifier called onUnavailable. The native message lists three causes\n * because the callback does not say which one happened; on the 18:02 Samsung path the SSID was\n * in scan and the join sheet was bypassed — assoc rejected after leaving another AP.\n */\nfunction isScopedJoinUnavailable(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error)\n return /SOFTAP_UNAVAILABLE|ScopedNetworkError\\$Unavailable|SSID not in scan, Wi-Fi off, or the system join prompt/i.test(\n message,\n )\n}\n\nexport type SoftapStepStatus = \"pending\" | \"running\" | \"done\" | \"failed\"\n\n/**\n * One step as the UI should show it. `detail` is the fact the step produced (SSID, phone address,\n * ingest URL, what the glasses last reported); `error` is set only on `failed`.\n */\nexport interface SoftapStepState {\n step: SoftapStep\n status: SoftapStepStatus\n detail?: string\n error?: string\n /** Wall-clock ms the step took; present once it is done or failed. */\n durationMs?: number\n}\n\n/**\n * Whole-sequence snapshot, re-sent on every transition so a consumer that missed one still holds\n * the truth. This is what the miniapp renders as its join checklist.\n */\nexport interface SoftapProgress {\n traceId: string\n phase: SoftapPhase\n steps: SoftapStepState[]\n /** ms since `start()` was called. */\n elapsedMs: number\n}\n\n/** Sub-status callback a step can use to narrate what it is doing while it runs. */\nexport type SoftapStepReporter = (detail: string) => void\n\nexport interface SoftapCallDeps {\n /**\n * Is this phone's Wi-Fi radio on? Asked before anything is built.\n *\n * The station radio is what reaches the glasses, and no app can turn it on since Android 10.\n * Finding out at `scopedJoin` means the glasses already raised a hotspot for a join that cannot\n * happen, so the wearer pays a teardown for a condition that was knowable up front. Optional:\n * a host that cannot answer skips the preflight and relies on the native throw at `scopedJoin`.\n */\n isWifiEnabled?(): Promise<boolean>\n /** Enable the glasses hotspot and return its credentials. */\n startHotspot(report?: SoftapStepReporter): Promise<{ssid: string; passphrase: string}>\n /**\n * Wait until the phone can actually see the AP. `setHotspotState` resolves when the glasses\n * accept the command, not when `ap0` is beaconing. A WifiNetworkSpecifier issued too early\n * comes back `Unavailable` in well under a second — it does not keep scanning for the timeout.\n */\n waitUntilHotspotJoinable?(report?: SoftapStepReporter): Promise<void>\n /** Disable it. Must tolerate being called when it was never enabled. */\n stopHotspot(): Promise<void>\n /** Join the hotspot without taking the phone's default route. Resolves to the phone's own IPv4. */\n joinScopedNetwork(ssid: string, passphrase: string, report?: SoftapStepReporter): Promise<string | undefined>\n leaveScopedNetwork(): Promise<void>\n /** Interrupt a pending native join while retaining its cleanup barrier. Unsupported hosts wait. */\n cancelScopedNetworkJoin?(): Promise<void>\n /**\n * Join the meeting. This is what binds the local WHIP listener and arms the ACS raw outputs, so\n * it must resolve before the glasses are told to publish.\n *\n * @returns the URL the glasses must POST their offer to\n */\n joinMeeting(\n args: {ssid: string; passphrase: string; bindAddress?: string},\n report?: SoftapStepReporter,\n ): Promise<{ingestUrl: string}>\n leaveMeeting(): Promise<void>\n /**\n * End the meeting for everyone instead of leaving it. Optional: a host that cannot do this still\n * tears down correctly, it just cannot honour `stop({mode: \"end\"})`.\n */\n endMeeting?(): Promise<void>\n /** Tell the glasses to publish to [ingestUrl] in host-only ICE mode. */\n startPublishing(args: {ingestUrl: string; traceId: string}, report?: SoftapStepReporter): Promise<void>\n stopPublishing(): Promise<void>\n /**\n * Resolves when a frame has reached ACS, rejects if the feed failed or the deadline passed.\n * Separate from [joinMeeting] because an answered negotiation is not a working call: a session\n * that never delivers a frame reads as healthy behind a frozen tile.\n */\n awaitFirstFrame(report?: SoftapStepReporter): Promise<void>\n}\n\nexport interface SoftapCallOptions {\n /** Override the minted trace id, so a caller can correlate with logs it already started. */\n traceId?: string\n /**\n * Receives a fresh snapshot on every transition: step begins, step narrates, step ends, sequence\n * ends. Exceptions thrown here are swallowed — a broken listener must not fail the call.\n */\n onProgress?: (progress: SoftapProgress) => void\n /**\n * Narration the caller already showed before the sequence existed — signing in to Teams, asking\n * for a permission. Without it the first `emitProgress` would blank the checklist the wearer is\n * already reading. Only `detail` is taken: the caller reports what it did, it does not get to\n * claim a step ran.\n */\n initialSteps?: SoftapStepState[]\n}\n\nfunction freshSteps(): SoftapStepState[] {\n return SOFTAP_STEPS.map((step) => ({step, status: \"pending\"}))\n}\n\n/** See {@link SoftapCallOptions.initialSteps}. */\nfunction seededSteps(initial: SoftapStepState[] | undefined): SoftapStepState[] {\n if (!initial?.length) return freshSteps()\n return freshSteps().map((step) => {\n const seed = initial.find((entry) => entry.step === step.step)\n return seed?.detail ? {...step, detail: seed.detail} : step\n })\n}\n\n/** A promise plus the function that settles it. */\nfunction deferred(): {promise: Promise<void>; resolve: () => void} {\n let resolve!: () => void\n const promise = new Promise<void>((settle) => {\n resolve = settle\n })\n return {promise, resolve}\n}\n\n/**\n * How a call is being taken down.\n *\n * `leave` takes this device out; `end` terminates the group call for everyone first. Everything\n * after that step is identical, which is the point: End is not a second teardown path, it is one\n * different verb at one step of the same one.\n */\nexport type SoftapTeardownMode = \"leave\" | \"end\"\n\nexport interface SoftapStopOptions {\n mode?: SoftapTeardownMode\n keepProgress?: boolean\n}\n\nexport class SoftapEndNotSupportedError extends Error {\n constructor() {\n super(\"This host cannot end a meeting for everyone\")\n this.name = \"SoftapEndNotSupportedError\"\n }\n}\n\nexport class SoftapCallTransport {\n private phase: SoftapPhase = \"idle\"\n /**\n * Steps completed and not yet undone, in the order they succeeded. Teardown walks this\n * backwards, so a failure halfway through unwinds exactly what was built and nothing else.\n */\n private completed: SoftapStep[] = []\n /**\n * Bumped by every start and stop. A step that resolves after the caller has moved on must not\n * write to the new attempt's state, which is the leave-during-join race.\n */\n private generation = 0\n private stopping: Promise<void> | null = null\n /**\n * The step currently in flight, and a promise that settles only after its body *and* the undo it\n * runs when it finds itself cancelled are both finished.\n *\n * This is what [stop] waits on. A step that resolves late still owns a resource — a hotspot that\n * came up after the wearer left — and its release happens inside the step, out of the teardown's\n * sight. Without this wait, `stop()` resolves while that release is still pending and the next\n * call brings a hotspot up straight into it.\n */\n private running: {step: SoftapStep; settled: Promise<void>} | null = null\n /** True once [start] has been called at least once, so [stop] can tell \"cancelled\" from \"reusable\". */\n private startedEver = false\n /**\n * A [stop] that landed before the sequence ever began.\n *\n * There is nothing to unwind in that case, so the flag is the only thing that can carry the\n * cancellation forward: a `start()` arriving afterwards belongs to the attempt that was just\n * cancelled and must refuse rather than build a call nobody is waiting for.\n */\n private cancelledBeforeStart = false\n /** Failed undos for this attempt, retained across repeated stops. See [lastTeardownFailures]. */\n private teardownFailures: SoftapStep[] = []\n /**\n * Raised the instant a teardown is decided, before any resource is touched.\n *\n * Everything that watches the call for failure — a lost hotspot above all — has to be able to ask\n * \"was this supposed to happen?\". Without the flag, releasing the scoped network during a\n * successful Leave looks exactly like the glasses walking out of range, and the wearer gets an\n * error screen for a call that ended the way they asked.\n */\n private terminating = false\n /** How this teardown ends the meeting. Read by the `acsJoin` undo. */\n private teardownMode: SoftapTeardownMode = \"leave\"\n /** Set when `stop({mode: \"end\"})` could not end for everyone. The caller must not claim it did. */\n private endFailure: unknown = null\n private hotspot: {ssid: string; passphrase: string} | null = null\n private ingestUrl: string | null = null\n private steps: SoftapStepState[] = freshSteps()\n private stepStartedAt = new Map<SoftapStep, number>()\n private startedAt = 0\n private traceId = \"\"\n private onProgress: ((progress: SoftapProgress) => void) | undefined\n\n constructor(private readonly deps: SoftapCallDeps) {}\n\n currentPhase(): SoftapPhase {\n return this.phase\n }\n\n /**\n * True once a teardown has been decided. Anything that would otherwise report a failure — a lost\n * hotspot, a dropped ACS call — must check this first: after the wearer asks to leave, those are\n * the sound of it working.\n */\n isTerminating(): boolean {\n return this.terminating\n }\n\n /** What the UI should show right now. Safe to call in any phase. */\n progress(): SoftapProgress {\n return {\n traceId: this.traceId,\n phase: this.phase,\n steps: this.steps.map((step) => ({...step})),\n elapsedMs: this.startedAt ? Date.now() - this.startedAt : 0,\n }\n }\n\n private emitProgress(): void {\n const listener = this.onProgress\n if (!listener) return\n try {\n listener(this.progress())\n } catch (error) {\n softapTraceFailure(\"softap_progress_listener_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private setStep(step: SoftapStep, patch: Partial<SoftapStepState>): void {\n this.steps = this.steps.map((entry) => (entry.step === step ? {...entry, ...patch} : entry))\n this.emitProgress()\n }\n\n /** Narration for a running step: what the phone or the glasses just reported. */\n private note(generation: number, step: SoftapStep, detail: string): void {\n if (generation !== this.generation) {\n // A step that is still narrating after the sequence moved on. The detail is dropped rather\n // than written onto the new attempt's checklist, and the drop is said out loud because a\n // step that goes quiet here is usually one that is still holding a native call open.\n softapTrace(\"softap_step_note_dropped\", {step, generation, current: this.generation, detail})\n return\n }\n softapTrace(\"softap_step_note\", {step, detail})\n this.setStep(step, {detail})\n }\n\n /** Steps currently built up, oldest first. Empty when nothing needs tearing down. */\n activeSteps(): SoftapStep[] {\n return [...this.completed]\n }\n\n /** The URL handed to the glasses, for diagnostics. Null outside a live attempt. */\n currentIngestUrl(): string | null {\n return this.ingestUrl\n }\n\n /**\n * Steps whose undo threw during the last teardown, so the caller can refuse the next call.\n *\n * Teardown deliberately swallows these to keep unwinding — but a hotspot that would not turn off\n * is exactly the state the next call cannot be built on, and starting anyway is what produced\n * \"Cannot start glasses hotspot\" followed by a scoped join that never found the SSID.\n */\n lastTeardownFailures(): SoftapStep[] {\n // Logged on read rather than only on write, because this is the moment the list turns into a\n // refusal for the next call: a wearer told to power-cycle the hotspot needs the reason to be\n // findable, and the write happened somewhere in the middle of a noisy teardown.\n if (this.teardownFailures.length > 0) {\n softapTraceFailure(\"softap_teardown_failures_read\", {steps: this.teardownFailures.join(\",\")})\n }\n return [...this.teardownFailures]\n }\n\n /**\n * Refuse the call while the Wi-Fi radio is off, before the glasses are asked for anything.\n *\n * Ordered ahead of the hotspot step rather than folded into `scopedJoin` because the cost of\n * learning late is paid by the glasses: a hotspot raised, a teardown, and a wearer watching a\n * checklist fail at step 2 for a toggle on their own phone. The native join keeps its own throw\n * for the radio that goes off in between — this is the explainable path, that one is the racy\n * backstop.\n *\n * A probe that throws is treated as \"unknown, carry on\": an unanswerable question about the\n * radio must not be the thing that stops a call the radio would have carried.\n */\n private async preflightWifi(): Promise<void> {\n if (!this.deps.isWifiEnabled) return\n let enabled: boolean\n try {\n enabled = await this.deps.isWifiEnabled()\n } catch (error) {\n softapTraceFailure(\"softap_wifi_preflight_unknown\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n return\n }\n softapTrace(\"softap_wifi_preflight\", {enabled})\n if (enabled) return\n this.setStep(\"hotspot\", {status: \"failed\", error: \"This phone's Wi-Fi is off\"})\n this.emitProgress()\n // Code in the message as well as on the error: the miniapp classifies on the message today\n // (the structured code only arrives on the join rejection), and every other SoftAP failure\n // carries its code the same way.\n throw new SoftapCallError(\n \"hotspot\",\n \"SOFTAP_WIFI_DISABLED\",\n \"SOFTAP_WIFI_DISABLED: this phone's Wi-Fi is off, so it cannot reach the glasses.\",\n )\n }\n\n /**\n * Runs the sequence. On any failure the partial sequence is torn down before the error is\n * rethrown, so a failed start never leaves a hotspot up or a publisher running.\n */\n async start(options: SoftapCallOptions = {}): Promise<void> {\n if (this.cancelledBeforeStart) {\n // The wearer's Cancel landed before the sequence began, so there is no step to name and no\n // trace id yet. This line is the only evidence that the flag did its job rather than the\n // join having silently never been asked for.\n softapTraceFailure(\"softap_call_refused\", {reason: \"cancelled before start\"})\n throw new SoftapCallError(\"hotspot\", \"CANCELLED\", \"SoftAP call was cancelled before it started\")\n }\n if (this.phase !== \"idle\" && this.phase !== \"failed\") {\n softapTraceFailure(\"softap_call_refused\", {reason: \"already active\", phase: this.phase})\n throw new SoftapCallError(\"hotspot\", \"ALREADY_ACTIVE\", `A SoftAP call is already ${this.phase}`)\n }\n this.startedEver = true\n const generation = ++this.generation\n this.phase = \"starting\"\n this.terminating = false\n this.teardownMode = \"leave\"\n this.endFailure = null\n this.completed = []\n this.ingestUrl = null\n this.hotspot = null\n this.teardownFailures = []\n this.steps = seededSteps(options.initialSteps)\n this.stepStartedAt.clear()\n this.startedAt = Date.now()\n this.onProgress = options.onProgress\n const traceId = beginSoftapTrace(options.traceId)\n this.traceId = traceId\n softapTrace(\"softap_call_start\", {traceId})\n this.emitProgress()\n\n try {\n await this.preflightWifi()\n\n await this.step(generation, \"hotspot\", \"HOTSPOT_FAILED\", async (report) => {\n report(\"Asking the glasses to turn on their hotspot\")\n const hotspot = await this.deps.startHotspot(report)\n if (!hotspot.ssid) {\n throw new Error(\"the glasses reported no hotspot SSID\")\n }\n this.hotspot = hotspot\n // The passphrase never reaches the log; softapTrace redacts it by key, and only the SSID\n // is useful for matching against the phone's Wi-Fi state anyway.\n softapTrace(\"hotspot_enabled\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid} is on; waiting for it to broadcast`)\n await this.deps.waitUntilHotspotJoinable?.(report)\n softapTrace(\"hotspot_broadcast_wait_done\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid}`)\n })\n\n const hotspot = this.requireHotspot()\n let bindAddress: string | undefined\n await this.step(generation, \"scopedJoin\", \"SCOPED_JOIN_FAILED\", async (report) => {\n report(`Phone joining ${hotspot.ssid}. Turn Wi-Fi on if a panel opens — Teams stays on cellular.`)\n bindAddress = await this.deps.joinScopedNetwork(hotspot.ssid, hotspot.passphrase, report)\n softapTrace(\"scoped_network_joined\", {bindAddress: bindAddress ?? \"unknown\"})\n if (bindAddress) report(`Phone is ${bindAddress} on ${hotspot.ssid}`)\n })\n\n await this.step(generation, \"acsJoin\", \"ACS_JOIN_FAILED\", async (report) => {\n report(bindAddress ? `Opening video receiver on ${bindAddress}, then joining Teams` : \"Joining Teams\")\n const {ingestUrl} = await this.deps.joinMeeting(\n {\n ssid: hotspot.ssid,\n passphrase: hotspot.passphrase,\n bindAddress,\n },\n report,\n )\n if (!ingestUrl) {\n // Without a bound listener there is nowhere for the glasses to publish, and telling them\n // to publish anyway produces a failure several seconds later on the wrong device.\n throw new Error(\"the meeting reported no ingest URL\")\n }\n this.ingestUrl = ingestUrl\n softapTrace(\"acs_receiver_ready\", {ingestUrl})\n report(`Receiver ready at ${ingestUrl}`)\n })\n\n const ingestUrl = this.requireIngestUrl()\n await this.step(generation, \"publish\", \"PUBLISH_FAILED\", async (report) => {\n report(\"Telling the glasses to start the camera and publish to the phone\")\n await this.deps.startPublishing({ingestUrl, traceId}, report)\n softapTrace(\"glasses_publishing\", {ingestUrl})\n report(\"Glasses camera is streaming to the phone\")\n })\n\n await this.step(generation, \"live\", \"NO_FIRST_FRAME\", async (report) => {\n report(\"Waiting for the first glasses video frame on this phone\")\n await this.deps.awaitFirstFrame(report)\n softapTrace(\"first_glasses_frame_received\")\n report(\"Glasses video is reaching this phone\")\n })\n\n if (generation !== this.generation) {\n // Every step succeeded and the call is nevertheless not this transport's any more. The\n // steps released themselves on the way past, so there is nothing to undo — but a join\n // that got all the way to a frame and then vanished is otherwise a log that simply stops.\n softapTraceFailure(\"softap_call_abandoned_at_live\", {generation, current: this.generation})\n return\n }\n this.phase = \"live\"\n softapTrace(\"softap_call_live\")\n this.emitProgress()\n } catch (error) {\n // Unwind before rethrowing. A caller that sees a rejection is entitled to assume nothing was\n // left running, and a hotspot left up is both a battery cost and a second call's failure.\n await this.stop({keepProgress: true})\n this.phase = \"failed\"\n this.emitProgress()\n throw error\n }\n }\n\n /**\n * Tears down in exact reverse order, and only what was built.\n *\n * Every step is attempted even if an earlier one throws: a failure to stop the publisher must\n * not leave the hotspot on. Concurrent calls share one teardown rather than racing each other\n * through the same resources, and a second `stop()` after one finished is a no-op — this is the\n * only SoftAP exit, so every terminal path can call it without checking whether another already\n * did.\n *\n * `mode: \"end\"` swaps the meeting verb and nothing else. If ending for everyone fails, the rest of\n * the teardown still runs and the failure is rethrown at the end, so the caller can tell the\n * wearer they left a meeting that may still be live rather than inventing a clean end.\n */\n async stop(options: SoftapStopOptions = {}): Promise<void> {\n // Intent before action, always: a watcher must be able to tell a deliberate teardown from a\n // failure even during the very first await below.\n this.terminating = true\n if (options.mode) this.teardownMode = options.mode\n if (this.stopping) {\n softapTrace(\"softap_stop_joined_in_flight\", {mode: this.teardownMode})\n return this.stopping\n }\n const running = this.running\n if (this.completed.length === 0 && this.phase === \"idle\" && !running) {\n // Nothing was built, so there is nothing to unwind — but a start() that has not run yet\n // still has to be refused, and a generation bump still has to invalidate anything holding\n // the old one.\n this.generation++\n if (!this.startedEver) this.cancelledBeforeStart = true\n softapTrace(\"softap_stop_nothing_built\", {\n // The distinction the next `start()` turns on: a transport that was never started refuses\n // outright, one that has already run is reusable.\n cancelledBeforeStart: this.cancelledBeforeStart,\n generation: this.generation,\n })\n return\n }\n\n this.generation++\n this.phase = \"stopping\"\n this.endFailure = null\n softapTrace(\"softap_call_stop\", {steps: this.completed.join(\",\"), mode: this.teardownMode})\n this.emitProgress()\n\n this.stopping = (async () => {\n // The generation bump above has already told the in-flight step to release whatever it\n // produced. Waiting for that release is what makes a resolved `stop()` mean \"nothing from\n // this call is still coming\". Deliberately unbounded: a native call that never returns must\n // hold the next call back, never let it race this one's cleanup.\n if (running) {\n const cancellation =\n running.step === \"scopedJoin\" && this.deps.cancelScopedNetworkJoin\n ? Promise.resolve()\n .then(() => this.deps.cancelScopedNetworkJoin!())\n .catch((error) => {\n if (!this.teardownFailures.includes(\"scopedJoin\")) this.teardownFailures.push(\"scopedJoin\")\n softapTraceFailure(\"softap_join_cancel_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n })\n : undefined\n softapTrace(\"softap_stop_waiting_for_step\", {step: running.step})\n const waitStartedAt = Date.now()\n await running.settled\n await cancellation\n // This wait is unbounded by design, so its duration is the difference between \"the leave\n // was slow\" and \"the leave was held by a native call that had not returned\".\n softapTrace(\"softap_stop_step_settled\", {step: running.step, waitedMs: Date.now() - waitStartedAt})\n }\n // The late step may have recorded a failed self-undo while we waited. Preserve it,\n // and any earlier teardown result, until start() explicitly begins a new attempt.\n const failures: SoftapStep[] = [...this.teardownFailures]\n for (const step of [...this.completed].reverse()) {\n const undoStartedAt = Date.now()\n try {\n await this.undo(step)\n softapTrace(\"softap_step_undone\", {step, durationMs: Date.now() - undoStartedAt})\n } catch (error) {\n // Recorded, not rethrown: the remaining steps still have to be undone. The caller reads\n // them back through [lastTeardownFailures] and refuses the next call, because a hotspot\n // that would not turn off is exactly the state the next call cannot build on.\n failures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n durationMs: Date.now() - undoStartedAt,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n this.completed = []\n this.hotspot = null\n this.ingestUrl = null\n this.phase = \"idle\"\n this.teardownFailures = failures\n softapTrace(\"softap_call_stopped\", {undoFailures: failures.join(\",\")})\n resetSoftapTrace()\n // A failed start keeps its checklist so the UI can show which step broke; a deliberate\n // leave wipes it, because there is nothing left to explain.\n if (!options.keepProgress) {\n this.steps = freshSteps()\n this.emitProgress()\n }\n })()\n\n try {\n await this.stopping\n } finally {\n this.stopping = null\n }\n // Rethrown last, after every resource is released. An End that could not terminate the meeting\n // has still taken this device out; only the claim about the others is wrong.\n const endFailure = this.endFailure\n this.endFailure = null\n if (endFailure) throw endFailure\n }\n\n private async undo(step: SoftapStep): Promise<void> {\n switch (step) {\n // `live` is an observation, not a resource — there is nothing to release.\n case \"live\":\n return\n case \"publish\":\n return this.deps.stopPublishing()\n case \"acsJoin\":\n return this.leaveOrEndMeeting()\n case \"scopedJoin\":\n return this.deps.leaveScopedNetwork()\n case \"hotspot\":\n return this.deps.stopHotspot()\n }\n }\n\n /**\n * The one step End changes.\n *\n * A failed End falls back to leaving, so the wearer is out either way, and the original failure is\n * kept for [stop] to rethrow. Recording it rather than throwing here is what keeps the hotspot\n * teardown — the steps after this one — unconditional.\n */\n private async leaveOrEndMeeting(): Promise<void> {\n if (this.teardownMode !== \"end\") return this.deps.leaveMeeting()\n const endMeeting = this.deps.endMeeting\n if (!endMeeting) {\n this.endFailure = new SoftapEndNotSupportedError()\n return this.deps.leaveMeeting()\n }\n try {\n await endMeeting()\n softapTrace(\"softap_meeting_ended_for_everyone\")\n } catch (error) {\n this.endFailure = error\n softapTraceFailure(\"softap_end_for_everyone_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n // Native ends the local call even when the hang-up is refused, so this is a belt-and-braces\n // leave rather than a second teardown: it must not resurrect the failure it is covering for.\n await this.deps.leaveMeeting().catch(() => undefined)\n }\n }\n\n /**\n * Runs one step, records it as undoable, and maps any throw to a [SoftapCallError] naming the\n * step. The generation check is what makes leaving mid-step safe: a step that resolves after the\n * caller gave up is not recorded, so teardown does not try to undo it twice.\n */\n private async step(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n if (generation !== this.generation) {\n // The sequence stopped between two steps. Named here because the caller only ever sees one\n // CANCELLED error, and which step it never reached is the thing worth knowing.\n softapTraceFailure(\"softap_step_skipped_after_cancel\", {step, generation, current: this.generation})\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled before ${step}`)\n }\n // Published before the first await so a `stop()` on the very next tick can see it. Settled in\n // the `finally`, after any self-undo, so waiting on it means the step owns nothing any more.\n const settle = deferred()\n this.running = {step, settled: settle.promise}\n try {\n await this.runStep(generation, step, code, run)\n } finally {\n if (this.running?.settled === settle.promise) this.running = null\n settle.resolve()\n }\n }\n\n /** The step body itself. Split out so [step] can publish and settle {@link running} around it. */\n private async runStep(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n softapTrace(\"softap_step_begin\", {step})\n const startedAt = Date.now()\n this.stepStartedAt.set(step, startedAt)\n this.setStep(step, {status: \"running\", error: undefined})\n const report: SoftapStepReporter = (detail) => this.note(generation, step, detail)\n try {\n await run(report)\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n softapTraceFailure(\"softap_step_failed\", {step, code, reason})\n if (generation === this.generation) {\n this.setStep(step, {status: \"failed\", error: reason, durationMs: Date.now() - startedAt})\n }\n throw new SoftapCallError(step, code, error instanceof Error ? error.message : `${step} failed`, error)\n }\n if (generation !== this.generation) {\n // The step succeeded after the caller gave up. Release it here rather than recording it for\n // the teardown to find: that teardown may already have walked past this step, or finished\n // altogether, in which case nothing else ever would. This is the leak the generation guard\n // exists to close — a meeting joined a few milliseconds after the user left.\n softapTrace(\"softap_step_completed_after_cancel\", {step})\n await this.undoSafely(step)\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled during ${step}`)\n }\n this.completed.push(step)\n softapTrace(\"softap_step_done\", {step, durationMs: Date.now() - startedAt})\n this.setStep(step, {status: \"done\", durationMs: Date.now() - startedAt})\n }\n\n /** Undo that reports rather than throws, for the cancellation path where there is no caller. */\n private async undoSafely(step: SoftapStep): Promise<void> {\n try {\n await this.undo(step)\n } catch (error) {\n if (!this.teardownFailures.includes(step)) this.teardownFailures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private requireHotspot(): {ssid: string; passphrase: string} {\n const hotspot = this.hotspot\n if (!hotspot) throw new SoftapCallError(\"hotspot\", \"HOTSPOT_FAILED\", \"no hotspot credentials\")\n return hotspot\n }\n\n private requireIngestUrl(): string {\n const url = this.ingestUrl\n if (!url) throw new SoftapCallError(\"acsJoin\", \"ACS_JOIN_FAILED\", \"no ingest URL\")\n return url\n }\n}\n\n/**\n * Binds the sequence to the real subsystems.\n *\n * Kept separate from the class so the ordering above is tested against fakes rather than against\n * BLE and ACS. The only logic here is adapting shapes; anything that needs a decision belongs in\n * the class.\n *\n * @param packageName the miniapp that owns the call\n * @param meeting the meeting to join, and how to observe its media health\n */\nexport function createSoftapCallDeps(args: {\n packageName: string\n meetingUrl: string\n token: string\n displayName?: string\n /**\n * The ACS outgoing profile. Used here only to size the glasses→phone hop; when absent the\n * glasses keep their WHIP defaults, which is what every pre-policy build did.\n */\n video?: {width: number; height: number; fps: number; maxBitrateBps: number}\n /** Resolves when the meeting reports a frame reached ACS; rejects on a failed feed. */\n awaitFirstFrame: () => Promise<void>\n subsystems: {\n setHotspotState: (enabled: boolean) => Promise<{state: string; ssid?: string; password?: string; localIp?: string}>\n /** Whether this phone's Wi-Fi radio is on. Optional: only Android hosts can answer it. */\n isWifiEnabled?: () => Promise<boolean>\n joinScopedNetwork: (ssid: string, passphrase: string, gateway?: string) => Promise<string | undefined>\n leaveScopedNetwork: () => Promise<void>\n cancelScopedNetworkJoin?: () => Promise<void>\n joinMeeting: (\n packageName: string,\n options: {\n meetingUrl: string\n token: string\n videoSource: {type: \"softap\"; ssid?: string; passphrase?: string; bindAddress?: string}\n displayName?: string\n },\n ) => Promise<unknown>\n leaveMeeting: (packageName: string) => Promise<void>\n /** Terminate the group call for everyone. Absent on hosts that cannot. */\n endMeeting?: (packageName: string) => Promise<void>\n ingestUrl: () => string | null\n startPublishing: (\n packageName: string,\n options: {\n streamUrl: string\n ice: {stun: string}\n traceId: string\n captureAudio?: boolean\n video?: SoftapVideoPolicy\n },\n ) => Promise<unknown>\n stopPublishing: (packageName: string) => Promise<void>\n /**\n * Whether the host is taking the wearer's voice off the glasses over BLE LC3 for this call.\n *\n * Asked after the meeting join and before the publish, because that is the only moment the\n * answer is both known (the host has seen the native's capabilities) and still actionable (the\n * glasses have not been told what to capture). True means the WHIP publish is video-only;\n * false means the glasses put their microphone on the WHIP track as they always have. Absent\n * on hosts that only have the WHIP audio path.\n */\n glassesLc3Uplink?: () => boolean\n /**\n * Prove the phone can reach the glasses over the hotspot it just joined. Optional because\n * only Android hosts have the scoped network handle; when present its verdict is narrated\n * into the scoped-join step and a failure is reported, not thrown — the glasses-to-phone\n * direction is what the call actually needs, and that is tested by the publish step.\n */\n probeGateway?: () => Promise<{reachable: boolean; detail: string}>\n /**\n * Wait for the phone's default network to be validated again after the hotspot join took Wi-Fi\n * away. Optional because only Android hosts can answer it.\n *\n * Not fatal when it reports an unusable network: the wearer is told, and the join is attempted\n * anyway. Aborting here would fail calls that recover a second later, and the ACS join has its\n * own bounded timeout for the case that does not.\n */\n awaitValidatedDefaultNetwork?: () => Promise<{usable: boolean; detail: string} | null>\n /**\n * Glasses `stream_status` events, so the publish step can say \"camera starting\" and \"offer\n * posted\" instead of going quiet for the whole BLE round trip. Returns an unsubscribe.\n */\n onGlassesStreamStatus?: (\n listener: (event: {status: string; streamId?: string; reason?: string; error?: string}) => void,\n ) => () => void\n }\n /** Override only in tests. Production waits the gallery-proven broadcast window. */\n hotspotBroadcastWaitMs?: number\n}): SoftapCallDeps {\n const {packageName, subsystems} = args\n const hotspotBroadcastWaitMs = args.hotspotBroadcastWaitMs ?? HOTSPOT_BROADCAST_WAIT_MS\n let gatewayAddress: string | undefined\n return {\n isWifiEnabled: subsystems.isWifiEnabled ? () => subsystems.isWifiEnabled!() : undefined,\n startHotspot: async (report) => {\n const enable = async () => {\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid) {\n throw new Error(`the glasses hotspot did not start (state=${status.state})`)\n }\n if (!status.password) {\n throw new Error(\"the glasses hotspot reported no password\")\n }\n report?.(`Glasses report hotspot ${status.ssid} enabled`)\n gatewayAddress = status.localIp\n return {ssid: status.ssid, passphrase: status.password}\n }\n try {\n return await enable()\n } catch (error) {\n if (error instanceof Error && /no password/.test(error.message)) throw error\n // Cancel-then-start races the previous disable: the glasses report disabled (or no SSID)\n // and the UI said \"Couldn't start glasses hotspot\" before step 2 ran on a leftover AP.\n softapTraceFailure(\"hotspot_enable_retry\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n report?.(\"Glasses hotspot did not start; turning it off and trying again\")\n await subsystems.setHotspotState(false)\n if (hotspotBroadcastWaitMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, Math.min(1_000, hotspotBroadcastWaitMs)))\n }\n return await enable()\n }\n },\n waitUntilHotspotJoinable: async (report) => {\n if (hotspotBroadcastWaitMs <= 0) return\n softapTrace(\"hotspot_broadcast_wait\", {ms: hotspotBroadcastWaitMs})\n report?.(`Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`)\n await new Promise<void>((resolve) => setTimeout(resolve, hotspotBroadcastWaitMs))\n },\n stopHotspot: async () => {\n await subsystems.setHotspotState(false)\n },\n joinScopedNetwork: async (ssid, passphrase, report) => {\n const joinOnce = (nextSsid: string, nextPassphrase: string) =>\n gatewayAddress\n ? subsystems.joinScopedNetwork(nextSsid, nextPassphrase, gatewayAddress)\n : subsystems.joinScopedNetwork(nextSsid, nextPassphrase)\n let address: string | undefined\n try {\n address = await joinOnce(ssid, passphrase)\n } catch (error) {\n if (!isScopedJoinUnavailable(error)) throw error\n // First specifier left the phone's previous Wi-Fi and assoc-rejected the glasses AP.\n // Cycle the AP and join again from an idle STA — the radio is free now.\n softapTraceFailure(\"scoped_join_unavailable_retry\", {ssid})\n report?.(\"Phone couldn't join; cycling the glasses hotspot and trying again\")\n await subsystems.setHotspotState(false)\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid || !status.password) throw error\n gatewayAddress = status.localIp\n if (hotspotBroadcastWaitMs > 0) {\n report?.(`Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`)\n await new Promise<void>((resolve) => setTimeout(resolve, hotspotBroadcastWaitMs))\n }\n address = await joinOnce(status.ssid, status.password)\n }\n if (subsystems.probeGateway) {\n report?.(`Phone is ${address ?? \"on the hotspot\"}; checking it can reach the glasses`)\n try {\n const probe = await subsystems.probeGateway()\n softapTrace(probe.reachable ? \"gateway_probe_ok\" : \"gateway_probe_failed\", {detail: probe.detail})\n report?.(\n probe.reachable\n ? `Phone ${address ?? \"\"} ↔ glasses OK (${probe.detail})`\n : `Phone ${address ?? \"\"} joined, but cannot reach the glasses: ${probe.detail}`,\n )\n } catch (error) {\n softapTraceFailure(\"gateway_probe_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n return address\n },\n leaveScopedNetwork: () => subsystems.leaveScopedNetwork(),\n cancelScopedNetworkJoin: subsystems.cancelScopedNetworkJoin,\n joinMeeting: async ({ssid, passphrase, bindAddress}, report) => {\n // The hotspot join just took this phone off Wi-Fi, so the route Teams needs is whatever\n // Android promoted in its place. Waiting for it to validate is what stopped the ACS join\n // from burning its whole timeout on DNS that could not resolve yet.\n if (subsystems.awaitValidatedDefaultNetwork) {\n report?.(\"Waiting for this phone's mobile data to take over so Teams can connect\")\n try {\n const network = await subsystems.awaitValidatedDefaultNetwork()\n if (network) {\n softapTrace(network.usable ? \"default_network_ok\" : \"default_network_unvalidated\", {\n detail: network.detail,\n })\n report?.(\n network.usable\n ? `Internet is on ${network.detail}`\n : `Internet is not confirmed yet (${network.detail}); joining Teams anyway`,\n )\n }\n } catch (error) {\n softapTraceFailure(\"default_network_check_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n report?.(\"Binding the video receiver and joining Teams over cellular\")\n await subsystems.joinMeeting(packageName, {\n meetingUrl: args.meetingUrl,\n token: args.token,\n videoSource: {type: \"softap\", ssid, passphrase, bindAddress},\n displayName: args.displayName,\n })\n // The listener binds during the join, so the URL only exists now.\n return {ingestUrl: subsystems.ingestUrl() ?? \"\"}\n },\n leaveMeeting: () => subsystems.leaveMeeting(packageName),\n ...(subsystems.endMeeting ? {endMeeting: () => subsystems.endMeeting!(packageName)} : {}),\n startPublishing: async ({ingestUrl, traceId}, report) => {\n // Narrate the glasses side while the BLE start command is in flight. `initializing` means\n // the glasses accepted the command and are opening the camera; `streaming` means the WHIP\n // offer was answered and ICE connected; anything else is the reason it did not.\n const unsubscribe = subsystems.onGlassesStreamStatus?.((event) => {\n if (event.status === \"initializing\") {\n report?.(\"Glasses accepted the command: camera starting, gathering ICE, posting offer to the phone\")\n } else if (event.status === \"streaming\") {\n report?.(\"Glasses are streaming to the phone\")\n } else if (event.status === \"error\") {\n report?.(`Glasses reported: ${event.error ?? event.reason ?? \"stream error\"}`)\n } else if (event.status === \"reconnecting\") {\n report?.(`Glasses reconnecting: ${event.reason ?? \"\"}`)\n }\n })\n // Decided before the command goes out, never after: the glasses cannot drop an audio track\n // they already negotiated, and two live copies of the wearer's voice in one call is worse\n // than either one alone.\n const lc3Uplink = subsystems.glassesLc3Uplink?.() ?? false\n softapTrace(\"publish_audio_decision\", {captureAudio: !lc3Uplink, micTransport: lc3Uplink ? \"ble-lc3\" : \"whip\"})\n report?.(\n lc3Uplink\n ? \"Publishing video only; the wearer's voice comes over Bluetooth LC3\"\n : \"Publishing video and the glasses microphone\",\n )\n const policy = args.video ? softapVideoPolicy(args.video) : undefined\n if (policy) {\n // Traced at send time rather than read back: the glasses log what they applied in\n // `applyBitrateConstraints`, and the pair of lines is what shows a clamp we did not\n // intend. One line alone can only ever show agreement with itself.\n softapTrace(\"softap_video_policy\", {\n width: policy.width,\n height: policy.height,\n fps: policy.fps,\n min: policy.minBitrateBps,\n start: policy.initialBitrateBps,\n max: policy.bitrate,\n })\n }\n try {\n await subsystems.startPublishing(packageName, {\n streamUrl: ingestUrl,\n // Empty STUN server means host-only: there is no route from the hotspot to a STUN server,\n // so a configured one would add doomed gathering to every call.\n ice: {stun: \"\"},\n traceId,\n captureAudio: !lc3Uplink,\n ...(policy ? {video: policy} : {}),\n })\n } finally {\n unsubscribe?.()\n }\n },\n stopPublishing: () => subsystems.stopPublishing(packageName),\n awaitFirstFrame: args.awaitFirstFrame,\n }\n}\n"]}
1
+ {"version":3,"file":"SoftapCallTransport.js","sourceRoot":"","sources":["../../src/services/SoftapCallTransport.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Sequences a SoftAP call. Sequencing only — no sockets, no peers, no BLE.\n *\n * The glasses open a hotspot, the phone joins it without giving up its cellular route, and the\n * glasses publish WebRTC straight to a listener on the phone. Cloudflare is not involved at all.\n *\n * The order below is the whole point of this file, and one step in it is load-bearing:\n *\n * hotspot on -> scoped join -> ACS join (binds the listener and arms the raw outputs)\n * -> glasses publish -> WHIP negotiation -> first frame -> LIVE\n *\n * Publishing must come after the ACS join, not before. `LIVE` means a frame reached ACS, so if the\n * glasses start publishing first, decoded video and audio can arrive before the raw outgoing\n * streams exist and the first frames are dropped by whatever happens to be null at the time. That\n * is not a lifecycle anyone designed; making the order explicit is what removes it.\n *\n * Ownership is deliberately narrow. This object owns the *sequence* and nothing else: the meeting\n * session owns the WHIP listener and the peer, `PhoneStreamCoordinator` owns the publisher, and\n * `localNetworkTransport` owns the scoped network. Every step therefore has exactly one owner that\n * can tear it down, which is what makes leaving mid-join safe.\n */\n\nimport {softapTrace, softapTraceFailure, beginSoftapTrace, resetSoftapTrace} from \"../utils/softapTrace\"\n\n/** Steps in order. Also the teardown order, reversed. */\nexport const SOFTAP_STEPS = [\"hotspot\", \"scopedJoin\", \"acsJoin\", \"publish\", \"live\"] as const\n\nexport type SoftapStep = (typeof SOFTAP_STEPS)[number]\n\n/**\n * Where the sequence is.\n *\n * `starting` covers every step up to `live` because the caller's only useful distinction is\n * \"not yet usable\" versus \"carrying media\"; the step names are for diagnostics, not for branching.\n */\nexport type SoftapPhase = \"idle\" | \"starting\" | \"live\" | \"stopping\" | \"failed\"\n\n/** A failure, named by the step that produced it so the UI and the logs agree on the cause. */\nexport class SoftapCallError extends Error {\n constructor(readonly step: SoftapStep, readonly code: string, message: string, readonly cause?: unknown) {\n super(message)\n this.name = \"SoftapCallError\"\n }\n}\n\n/** Gallery sync already learned this: glasses report enabled before the SSID is in the phone scan. */\nexport const HOTSPOT_BROADCAST_WAIT_MS = 3_000\n\n/**\n * What the glasses→phone hop is worth at 540p over a hotspot with one client and no contention.\n *\n * Not the ACS ceiling: this link is a metre of air between two devices that are already paired,\n * and the profile's `maxBitrateBps` describes the phone→Teams hop, which crosses the internet.\n * Sharing one number between them makes the easy hop obey the hard hop's limits.\n */\nexport const GLASSES_PHONE_BITRATE_BPS = 2_500_000\n\n/** Where the encoder starts. High, because the link is good from the first frame. */\nconst SOFTAP_START_BITRATE_BPS = 2_000_000\n\n/**\n * The floor. This is the whole point of the policy.\n *\n * WHIP's default has none, so after an ICE interruption WebRTC restarts at its own minimum and\n * climbs by probing — which is the \"potato for a while\" the wearer reports. The link did not get\n * worse; the estimator merely forgot what it knew. A floor says: this hop is a hotspot, not a\n * congested uplink, and it is never worth less than this.\n *\n * That trade is the opposite of Mentra-Call#27's cloud-WHIP review: a 1 Mbps floor on Auto over\n * LTE turns a weak WAN into freezes. This function is SoftAP-only. Cloud WHIP must not call it.\n */\nconst SOFTAP_MIN_BITRATE_BPS = 1_200_000\n\n/** Field names are the glasses' `WhipStreamConfig` parser's, where `bitrate` means the maximum. */\nexport interface SoftapVideoPolicy {\n width: number\n height: number\n fps: number\n bitrate: number\n initialBitrateBps: number\n minBitrateBps: number\n}\n\n/**\n * The bitrate the glasses are told to hold on the hop to the phone.\n *\n * The hotspot has its own bitrate budget, independent of the phone-to-Teams cap. Above 540p,\n * allow a higher requested ceiling while retaining the hotspot budget for low WAN caps.\n */\nexport function softapVideoPolicy(video: {\n width: number\n height: number\n fps: number\n maxBitrateBps: number\n}): SoftapVideoPolicy {\n const isSmall = video.width * video.height <= 960 * 540\n if (!Number.isFinite(video.maxBitrateBps) || video.maxBitrateBps <= 0) {\n throw new Error(`invalid SoftAP video bitrate: ${video.maxBitrateBps}`)\n }\n const max = isSmall ? GLASSES_PHONE_BITRATE_BPS : Math.max(GLASSES_PHONE_BITRATE_BPS, video.maxBitrateBps)\n const initialBitrateBps = Math.min(SOFTAP_START_BITRATE_BPS, max)\n const minBitrateBps = Math.min(SOFTAP_MIN_BITRATE_BPS, initialBitrateBps)\n if (!(minBitrateBps <= initialBitrateBps && initialBitrateBps <= max)) {\n throw new Error(`incoherent SoftAP video policy: min=${minBitrateBps} start=${initialBitrateBps} max=${max}`)\n }\n return {\n width: video.width,\n height: video.height,\n fps: video.fps,\n bitrate: max,\n initialBitrateBps,\n minBitrateBps,\n }\n}\n\n/**\n * Android's WifiNetworkSpecifier called onUnavailable. The native message lists three causes\n * because the callback does not say which one happened; on the 18:02 Samsung path the SSID was\n * in scan and the join sheet was bypassed — assoc rejected after leaving another AP.\n */\nfunction isScopedJoinUnavailable(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error)\n return /SOFTAP_UNAVAILABLE|ScopedNetworkError\\$Unavailable|SSID not in scan, Wi-Fi off, or the system join prompt/i.test(\n message,\n )\n}\n\nexport type SoftapStepStatus = \"pending\" | \"running\" | \"done\" | \"failed\"\n\n/**\n * One step as the UI should show it. `detail` is the fact the step produced (SSID, phone address,\n * ingest URL, what the glasses last reported); `error` is set only on `failed`.\n */\nexport interface SoftapStepState {\n step: SoftapStep\n status: SoftapStepStatus\n detail?: string\n error?: string\n /** Wall-clock ms the step took; present once it is done or failed. */\n durationMs?: number\n}\n\n/**\n * Whole-sequence snapshot, re-sent on every transition so a consumer that missed one still holds\n * the truth. This is what the miniapp renders as its join checklist.\n */\nexport interface SoftapProgress {\n traceId: string\n phase: SoftapPhase\n steps: SoftapStepState[]\n /** ms since `start()` was called. */\n elapsedMs: number\n}\n\n/** Sub-status callback a step can use to narrate what it is doing while it runs. */\nexport type SoftapStepReporter = (detail: string) => void\n\nexport interface SoftapCallDeps {\n /**\n * Is this phone's Wi-Fi radio on? Asked before anything is built.\n *\n * The station radio is what reaches the glasses, and no app can turn it on since Android 10.\n * Finding out at `scopedJoin` means the glasses already raised a hotspot for a join that cannot\n * happen, so the wearer pays a teardown for a condition that was knowable up front. Optional:\n * a host that cannot answer skips the preflight and relies on the native throw at `scopedJoin`.\n */\n isWifiEnabled?(): Promise<boolean>\n /** Enable the glasses hotspot and return its credentials. */\n startHotspot(report?: SoftapStepReporter): Promise<{ssid: string; passphrase: string}>\n /**\n * Wait until the phone can actually see the AP. `setHotspotState` resolves when the glasses\n * accept the command, not when `ap0` is beaconing. A WifiNetworkSpecifier issued too early\n * comes back `Unavailable` in well under a second — it does not keep scanning for the timeout.\n */\n waitUntilHotspotJoinable?(report?: SoftapStepReporter): Promise<void>\n /** Disable it. Must tolerate being called when it was never enabled. */\n stopHotspot(): Promise<void>\n /** Join the hotspot without taking the phone's default route. Resolves to the phone's own IPv4. */\n joinScopedNetwork(ssid: string, passphrase: string, report?: SoftapStepReporter): Promise<string | undefined>\n leaveScopedNetwork(): Promise<void>\n /** Interrupt a pending native join while retaining its cleanup barrier. Unsupported hosts wait. */\n cancelScopedNetworkJoin?(): Promise<void>\n /**\n * Join the meeting. This is what binds the local WHIP listener and arms the ACS raw outputs, so\n * it must resolve before the glasses are told to publish.\n *\n * @returns the URL the glasses must POST their offer to\n */\n joinMeeting(\n args: {ssid: string; passphrase: string; bindAddress?: string},\n report?: SoftapStepReporter,\n ): Promise<{ingestUrl: string}>\n leaveMeeting(): Promise<void>\n /**\n * End the meeting for everyone instead of leaving it. Optional: a host that cannot do this still\n * tears down correctly, it just cannot honour `stop({mode: \"end\"})`.\n */\n endMeeting?(): Promise<void>\n /** Tell the glasses to publish to [ingestUrl] in host-only ICE mode. */\n startPublishing(args: {ingestUrl: string; traceId: string}, report?: SoftapStepReporter): Promise<void>\n stopPublishing(): Promise<void>\n /**\n * Resolves when a frame has reached ACS, rejects if the feed failed or the deadline passed.\n * Separate from [joinMeeting] because an answered negotiation is not a working call: a session\n * that never delivers a frame reads as healthy behind a frozen tile.\n */\n awaitFirstFrame(report?: SoftapStepReporter): Promise<void>\n /**\n * Mid-call camera recovery. Resolves `true` only when ingest is live again.\n * A standing `failed` is the reason we are republishing, so it must not abort the wait.\n */\n waitUntilLive?(timeoutMs: number): Promise<boolean>\n /** Delay after a failed `start_stream` before the next republish attempt. Tests set 0. */\n republishRetryDelayMs?: number\n}\n\nexport interface SoftapCallOptions {\n /** Override the minted trace id, so a caller can correlate with logs it already started. */\n traceId?: string\n /**\n * Receives a fresh snapshot on every transition: step begins, step narrates, step ends, sequence\n * ends. Exceptions thrown here are swallowed — a broken listener must not fail the call.\n */\n onProgress?: (progress: SoftapProgress) => void\n /**\n * Narration the caller already showed before the sequence existed — signing in to Teams, asking\n * for a permission. Without it the first `emitProgress` would blank the checklist the wearer is\n * already reading. Only `detail` is taken: the caller reports what it did, it does not get to\n * claim a step ran.\n */\n initialSteps?: SoftapStepState[]\n}\n\nfunction freshSteps(): SoftapStepState[] {\n return SOFTAP_STEPS.map((step) => ({step, status: \"pending\"}))\n}\n\n/** See {@link SoftapCallOptions.initialSteps}. */\nfunction seededSteps(initial: SoftapStepState[] | undefined): SoftapStepState[] {\n if (!initial?.length) return freshSteps()\n return freshSteps().map((step) => {\n const seed = initial.find((entry) => entry.step === step.step)\n return seed?.detail ? {...step, detail: seed.detail} : step\n })\n}\n\n/** A promise plus the function that settles it. */\nfunction deferred(): {promise: Promise<void>; resolve: () => void} {\n let resolve!: () => void\n const promise = new Promise<void>((settle) => {\n resolve = settle\n })\n return {promise, resolve}\n}\n\nfunction sleep(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve()\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/** How long a mid-call republish waits for a frame after re-issuing `start_stream`. */\nexport const SOFTAP_REPUBLISH_LIVE_MS = 20_000\nconst REPUBLISH_RETRY_DELAY_MS = 2_000\n\n/**\n * How a call is being taken down.\n *\n * `leave` takes this device out; `end` terminates the group call for everyone first. Everything\n * after that step is identical, which is the point: End is not a second teardown path, it is one\n * different verb at one step of the same one.\n */\nexport type SoftapTeardownMode = \"leave\" | \"end\"\n\nexport interface SoftapStopOptions {\n mode?: SoftapTeardownMode\n keepProgress?: boolean\n}\n\nexport class SoftapEndNotSupportedError extends Error {\n constructor() {\n super(\"This host cannot end a meeting for everyone\")\n this.name = \"SoftapEndNotSupportedError\"\n }\n}\n\nexport class SoftapCallTransport {\n private phase: SoftapPhase = \"idle\"\n /**\n * Steps completed and not yet undone, in the order they succeeded. Teardown walks this\n * backwards, so a failure halfway through unwinds exactly what was built and nothing else.\n */\n private completed: SoftapStep[] = []\n /**\n * Bumped by every start and stop. A step that resolves after the caller has moved on must not\n * write to the new attempt's state, which is the leave-during-join race.\n */\n private generation = 0\n private stopping: Promise<void> | null = null\n /**\n * The step currently in flight, and a promise that settles only after its body *and* the undo it\n * runs when it finds itself cancelled are both finished.\n *\n * This is what [stop] waits on. A step that resolves late still owns a resource — a hotspot that\n * came up after the wearer left — and its release happens inside the step, out of the teardown's\n * sight. Without this wait, `stop()` resolves while that release is still pending and the next\n * call brings a hotspot up straight into it.\n */\n private running: {step: SoftapStep; settled: Promise<void>} | null = null\n /** True once [start] has been called at least once, so [stop] can tell \"cancelled\" from \"reusable\". */\n private startedEver = false\n /**\n * A [stop] that landed before the sequence ever began.\n *\n * There is nothing to unwind in that case, so the flag is the only thing that can carry the\n * cancellation forward: a `start()` arriving afterwards belongs to the attempt that was just\n * cancelled and must refuse rather than build a call nobody is waiting for.\n */\n private cancelledBeforeStart = false\n /** Failed undos for this attempt, retained across repeated stops. See [lastTeardownFailures]. */\n private teardownFailures: SoftapStep[] = []\n /**\n * Raised the instant a teardown is decided, before any resource is touched.\n *\n * Everything that watches the call for failure — a lost hotspot above all — has to be able to ask\n * \"was this supposed to happen?\". Without the flag, releasing the scoped network during a\n * successful Leave looks exactly like the glasses walking out of range, and the wearer gets an\n * error screen for a call that ended the way they asked.\n */\n private terminating = false\n /** How this teardown ends the meeting. Read by the `acsJoin` undo. */\n private teardownMode: SoftapTeardownMode = \"leave\"\n /** Set when `stop({mode: \"end\"})` could not end for everyone. The caller must not claim it did. */\n private endFailure: unknown = null\n private hotspot: {ssid: string; passphrase: string} | null = null\n private ingestUrl: string | null = null\n private steps: SoftapStepState[] = freshSteps()\n private stepStartedAt = new Map<SoftapStep, number>()\n private startedAt = 0\n private traceId = \"\"\n private onProgress: ((progress: SoftapProgress) => void) | undefined\n private republishing: Promise<void> | null = null\n /** Bumped by `stop` so an in-flight republish cannot start_stream after Leave. */\n private republishGeneration = 0\n\n constructor(private readonly deps: SoftapCallDeps) {}\n\n currentPhase(): SoftapPhase {\n return this.phase\n }\n\n /**\n * The glasses camera died after this call was already live. Re-issue `start_stream` at the\n * existing ingest URL — do not rebind the WHIP listener, or the glasses POST to a dead port.\n */\n shouldRepublish(mediaSource?: string): boolean {\n return this.phase === \"live\" && !this.terminating && mediaSource === \"failed\"\n }\n\n /**\n * Rebuild the glasses publisher onto the standing SoftAP ingest URL.\n *\n * ACS, BLE mic, and the WHIP listener stay up. The glasses process is what usually vanished\n * (UVC/`system_server` crash); a new `start_stream` is what they need after ASG comes back.\n */\n republish(reason: string): Promise<void> {\n if (this.phase !== \"live\" || this.terminating || !this.ingestUrl) return Promise.resolve()\n if (this.republishing) return this.republishing\n const generation = this.republishGeneration\n this.republishing = this.runRepublish(reason, generation).finally(() => {\n if (this.republishGeneration === generation) this.republishing = null\n })\n return this.republishing\n }\n\n private async runRepublish(reason: string, generation: number): Promise<void> {\n const ingestUrl = this.ingestUrl\n if (!ingestUrl) return\n const retryDelayMs = this.deps.republishRetryDelayMs ?? REPUBLISH_RETRY_DELAY_MS\n let attempt = 0\n softapTrace(\"glasses_republish_begin\", {reason, ingestUrl})\n while (\n generation === this.republishGeneration &&\n !this.terminating &&\n this.phase === \"live\" &&\n this.ingestUrl === ingestUrl\n ) {\n attempt += 1\n try {\n await this.deps.stopPublishing()\n if (generation !== this.republishGeneration || this.terminating) return\n await this.deps.startPublishing({ingestUrl, traceId: this.traceId})\n if (generation !== this.republishGeneration || this.terminating) {\n await this.deps.stopPublishing().catch(() => undefined)\n return\n }\n softapTrace(\"glasses_republish_sent\", {attempt, ingestUrl})\n if (!this.deps.waitUntilLive) return\n const live = await this.deps.waitUntilLive(SOFTAP_REPUBLISH_LIVE_MS)\n if (generation !== this.republishGeneration || this.terminating) return\n if (live) {\n softapTrace(\"glasses_republish_live\", {attempt})\n return\n }\n softapTraceFailure(\"glasses_republish_no_frame\", {attempt})\n } catch (error) {\n if (generation !== this.republishGeneration || this.terminating) return\n softapTraceFailure(\"glasses_republish_start_failed\", {\n attempt,\n reason: error instanceof Error ? error.message : String(error),\n })\n await sleep(retryDelayMs)\n }\n }\n }\n\n /**\n * True once a teardown has been decided. Anything that would otherwise report a failure — a lost\n * hotspot, a dropped ACS call — must check this first: after the wearer asks to leave, those are\n * the sound of it working.\n */\n isTerminating(): boolean {\n return this.terminating\n }\n\n /** What the UI should show right now. Safe to call in any phase. */\n progress(): SoftapProgress {\n return {\n traceId: this.traceId,\n phase: this.phase,\n steps: this.steps.map((step) => ({...step})),\n elapsedMs: this.startedAt ? Date.now() - this.startedAt : 0,\n }\n }\n\n private emitProgress(): void {\n const listener = this.onProgress\n if (!listener) return\n try {\n listener(this.progress())\n } catch (error) {\n softapTraceFailure(\"softap_progress_listener_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private setStep(step: SoftapStep, patch: Partial<SoftapStepState>): void {\n this.steps = this.steps.map((entry) => (entry.step === step ? {...entry, ...patch} : entry))\n this.emitProgress()\n }\n\n /** Narration for a running step: what the phone or the glasses just reported. */\n private note(generation: number, step: SoftapStep, detail: string): void {\n if (generation !== this.generation) {\n // A step that is still narrating after the sequence moved on. The detail is dropped rather\n // than written onto the new attempt's checklist, and the drop is said out loud because a\n // step that goes quiet here is usually one that is still holding a native call open.\n softapTrace(\"softap_step_note_dropped\", {step, generation, current: this.generation, detail})\n return\n }\n softapTrace(\"softap_step_note\", {step, detail})\n this.setStep(step, {detail})\n }\n\n /** Steps currently built up, oldest first. Empty when nothing needs tearing down. */\n activeSteps(): SoftapStep[] {\n return [...this.completed]\n }\n\n /** The URL handed to the glasses, for diagnostics. Null outside a live attempt. */\n currentIngestUrl(): string | null {\n return this.ingestUrl\n }\n\n /**\n * Steps whose undo threw during the last teardown, so the caller can refuse the next call.\n *\n * Teardown deliberately swallows these to keep unwinding — but a hotspot that would not turn off\n * is exactly the state the next call cannot be built on, and starting anyway is what produced\n * \"Cannot start glasses hotspot\" followed by a scoped join that never found the SSID.\n */\n lastTeardownFailures(): SoftapStep[] {\n // Logged on read rather than only on write, because this is the moment the list turns into a\n // refusal for the next call: a wearer told to power-cycle the hotspot needs the reason to be\n // findable, and the write happened somewhere in the middle of a noisy teardown.\n if (this.teardownFailures.length > 0) {\n softapTraceFailure(\"softap_teardown_failures_read\", {steps: this.teardownFailures.join(\",\")})\n }\n return [...this.teardownFailures]\n }\n\n /**\n * Refuse the call while the Wi-Fi radio is off, before the glasses are asked for anything.\n *\n * Ordered ahead of the hotspot step rather than folded into `scopedJoin` because the cost of\n * learning late is paid by the glasses: a hotspot raised, a teardown, and a wearer watching a\n * checklist fail at step 2 for a toggle on their own phone. The native join keeps its own throw\n * for the radio that goes off in between — this is the explainable path, that one is the racy\n * backstop.\n *\n * A probe that throws is treated as \"unknown, carry on\": an unanswerable question about the\n * radio must not be the thing that stops a call the radio would have carried.\n */\n private async preflightWifi(): Promise<void> {\n if (!this.deps.isWifiEnabled) return\n let enabled: boolean\n try {\n enabled = await this.deps.isWifiEnabled()\n } catch (error) {\n softapTraceFailure(\"softap_wifi_preflight_unknown\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n return\n }\n softapTrace(\"softap_wifi_preflight\", {enabled})\n if (enabled) return\n this.setStep(\"hotspot\", {status: \"failed\", error: \"This phone's Wi-Fi is off\"})\n this.emitProgress()\n // Code in the message as well as on the error: the miniapp classifies on the message today\n // (the structured code only arrives on the join rejection), and every other SoftAP failure\n // carries its code the same way.\n throw new SoftapCallError(\n \"hotspot\",\n \"SOFTAP_WIFI_DISABLED\",\n \"SOFTAP_WIFI_DISABLED: this phone's Wi-Fi is off, so it cannot reach the glasses.\",\n )\n }\n\n /**\n * Runs the sequence. On any failure the partial sequence is torn down before the error is\n * rethrown, so a failed start never leaves a hotspot up or a publisher running.\n */\n async start(options: SoftapCallOptions = {}): Promise<void> {\n if (this.cancelledBeforeStart) {\n // The wearer's Cancel landed before the sequence began, so there is no step to name and no\n // trace id yet. This line is the only evidence that the flag did its job rather than the\n // join having silently never been asked for.\n softapTraceFailure(\"softap_call_refused\", {reason: \"cancelled before start\"})\n throw new SoftapCallError(\"hotspot\", \"CANCELLED\", \"SoftAP call was cancelled before it started\")\n }\n if (this.phase !== \"idle\" && this.phase !== \"failed\") {\n softapTraceFailure(\"softap_call_refused\", {reason: \"already active\", phase: this.phase})\n throw new SoftapCallError(\"hotspot\", \"ALREADY_ACTIVE\", `A SoftAP call is already ${this.phase}`)\n }\n this.startedEver = true\n const generation = ++this.generation\n this.phase = \"starting\"\n this.terminating = false\n this.teardownMode = \"leave\"\n this.endFailure = null\n this.completed = []\n this.ingestUrl = null\n this.hotspot = null\n this.teardownFailures = []\n this.steps = seededSteps(options.initialSteps)\n this.stepStartedAt.clear()\n this.startedAt = Date.now()\n this.onProgress = options.onProgress\n const traceId = beginSoftapTrace(options.traceId)\n this.traceId = traceId\n softapTrace(\"softap_call_start\", {traceId})\n this.emitProgress()\n\n try {\n await this.preflightWifi()\n\n await this.step(generation, \"hotspot\", \"HOTSPOT_FAILED\", async (report) => {\n report(\"Asking the glasses to turn on their hotspot\")\n const hotspot = await this.deps.startHotspot(report)\n if (!hotspot.ssid) {\n throw new Error(\"the glasses reported no hotspot SSID\")\n }\n this.hotspot = hotspot\n // The passphrase never reaches the log; softapTrace redacts it by key, and only the SSID\n // is useful for matching against the phone's Wi-Fi state anyway.\n softapTrace(\"hotspot_enabled\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid} is on; waiting for it to broadcast`)\n await this.deps.waitUntilHotspotJoinable?.(report)\n softapTrace(\"hotspot_broadcast_wait_done\", {ssid: hotspot.ssid})\n report(`Hotspot ${hotspot.ssid}`)\n })\n\n const hotspot = this.requireHotspot()\n let bindAddress: string | undefined\n await this.step(generation, \"scopedJoin\", \"SCOPED_JOIN_FAILED\", async (report) => {\n report(`Phone joining ${hotspot.ssid}. Turn Wi-Fi on if a panel opens — Teams stays on cellular.`)\n bindAddress = await this.deps.joinScopedNetwork(hotspot.ssid, hotspot.passphrase, report)\n softapTrace(\"scoped_network_joined\", {bindAddress: bindAddress ?? \"unknown\"})\n if (bindAddress) report(`Phone is ${bindAddress} on ${hotspot.ssid}`)\n })\n\n await this.step(generation, \"acsJoin\", \"ACS_JOIN_FAILED\", async (report) => {\n report(bindAddress ? `Opening video receiver on ${bindAddress}, then joining Teams` : \"Joining Teams\")\n const {ingestUrl} = await this.deps.joinMeeting(\n {\n ssid: hotspot.ssid,\n passphrase: hotspot.passphrase,\n bindAddress,\n },\n report,\n )\n if (!ingestUrl) {\n // Without a bound listener there is nowhere for the glasses to publish, and telling them\n // to publish anyway produces a failure several seconds later on the wrong device.\n throw new Error(\"the meeting reported no ingest URL\")\n }\n this.ingestUrl = ingestUrl\n softapTrace(\"acs_receiver_ready\", {ingestUrl})\n report(`Receiver ready at ${ingestUrl}`)\n })\n\n const ingestUrl = this.requireIngestUrl()\n await this.step(generation, \"publish\", \"PUBLISH_FAILED\", async (report) => {\n report(\"Telling the glasses to start the camera and publish to the phone\")\n await this.deps.startPublishing({ingestUrl, traceId}, report)\n softapTrace(\"glasses_publishing\", {ingestUrl})\n report(\"Glasses camera is streaming to the phone\")\n })\n\n await this.step(generation, \"live\", \"NO_FIRST_FRAME\", async (report) => {\n report(\"Waiting for the first glasses video frame on this phone\")\n await this.deps.awaitFirstFrame(report)\n softapTrace(\"first_glasses_frame_received\")\n report(\"Glasses video is reaching this phone\")\n })\n\n if (generation !== this.generation) {\n // Every step succeeded and the call is nevertheless not this transport's any more. The\n // steps released themselves on the way past, so there is nothing to undo — but a join\n // that got all the way to a frame and then vanished is otherwise a log that simply stops.\n softapTraceFailure(\"softap_call_abandoned_at_live\", {generation, current: this.generation})\n return\n }\n this.phase = \"live\"\n softapTrace(\"softap_call_live\")\n this.emitProgress()\n } catch (error) {\n // Unwind before rethrowing. A caller that sees a rejection is entitled to assume nothing was\n // left running, and a hotspot left up is both a battery cost and a second call's failure.\n await this.stop({keepProgress: true})\n this.phase = \"failed\"\n this.emitProgress()\n throw error\n }\n }\n\n /**\n * Tears down in exact reverse order, and only what was built.\n *\n * Every step is attempted even if an earlier one throws: a failure to stop the publisher must\n * not leave the hotspot on. Concurrent calls share one teardown rather than racing each other\n * through the same resources, and a second `stop()` after one finished is a no-op — this is the\n * only SoftAP exit, so every terminal path can call it without checking whether another already\n * did.\n *\n * `mode: \"end\"` swaps the meeting verb and nothing else. If ending for everyone fails, the rest of\n * the teardown still runs and the failure is rethrown at the end, so the caller can tell the\n * wearer they left a meeting that may still be live rather than inventing a clean end.\n */\n async stop(options: SoftapStopOptions = {}): Promise<void> {\n // Intent before action, always: a watcher must be able to tell a deliberate teardown from a\n // failure even during the very first await below.\n this.terminating = true\n this.republishGeneration++\n if (options.mode) this.teardownMode = options.mode\n if (this.stopping) {\n softapTrace(\"softap_stop_joined_in_flight\", {mode: this.teardownMode})\n return this.stopping\n }\n const running = this.running\n if (this.completed.length === 0 && this.phase === \"idle\" && !running) {\n // Nothing was built, so there is nothing to unwind — but a start() that has not run yet\n // still has to be refused, and a generation bump still has to invalidate anything holding\n // the old one.\n this.generation++\n if (!this.startedEver) this.cancelledBeforeStart = true\n softapTrace(\"softap_stop_nothing_built\", {\n // The distinction the next `start()` turns on: a transport that was never started refuses\n // outright, one that has already run is reusable.\n cancelledBeforeStart: this.cancelledBeforeStart,\n generation: this.generation,\n })\n return\n }\n\n this.generation++\n this.phase = \"stopping\"\n this.endFailure = null\n softapTrace(\"softap_call_stop\", {steps: this.completed.join(\",\"), mode: this.teardownMode})\n this.emitProgress()\n\n this.stopping = (async () => {\n // The generation bump above has already told the in-flight step to release whatever it\n // produced. Waiting for that release is what makes a resolved `stop()` mean \"nothing from\n // this call is still coming\". Deliberately unbounded: a native call that never returns must\n // hold the next call back, never let it race this one's cleanup.\n if (running) {\n const cancellation =\n running.step === \"scopedJoin\" && this.deps.cancelScopedNetworkJoin\n ? Promise.resolve()\n .then(() => this.deps.cancelScopedNetworkJoin!())\n .catch((error) => {\n if (!this.teardownFailures.includes(\"scopedJoin\")) this.teardownFailures.push(\"scopedJoin\")\n softapTraceFailure(\"softap_join_cancel_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n })\n : undefined\n softapTrace(\"softap_stop_waiting_for_step\", {step: running.step})\n const waitStartedAt = Date.now()\n await running.settled\n await cancellation\n // This wait is unbounded by design, so its duration is the difference between \"the leave\n // was slow\" and \"the leave was held by a native call that had not returned\".\n softapTrace(\"softap_stop_step_settled\", {step: running.step, waitedMs: Date.now() - waitStartedAt})\n }\n // The late step may have recorded a failed self-undo while we waited. Preserve it,\n // and any earlier teardown result, until start() explicitly begins a new attempt.\n const failures: SoftapStep[] = [...this.teardownFailures]\n for (const step of [...this.completed].reverse()) {\n const undoStartedAt = Date.now()\n try {\n await this.undo(step)\n softapTrace(\"softap_step_undone\", {step, durationMs: Date.now() - undoStartedAt})\n } catch (error) {\n // Recorded, not rethrown: the remaining steps still have to be undone. The caller reads\n // them back through [lastTeardownFailures] and refuses the next call, because a hotspot\n // that would not turn off is exactly the state the next call cannot build on.\n failures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n durationMs: Date.now() - undoStartedAt,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n this.completed = []\n this.hotspot = null\n this.ingestUrl = null\n this.phase = \"idle\"\n this.teardownFailures = failures\n softapTrace(\"softap_call_stopped\", {undoFailures: failures.join(\",\")})\n resetSoftapTrace()\n // A failed start keeps its checklist so the UI can show which step broke; a deliberate\n // leave wipes it, because there is nothing left to explain.\n if (!options.keepProgress) {\n this.steps = freshSteps()\n this.emitProgress()\n }\n })()\n\n try {\n await this.stopping\n } finally {\n this.stopping = null\n }\n // Rethrown last, after every resource is released. An End that could not terminate the meeting\n // has still taken this device out; only the claim about the others is wrong.\n const endFailure = this.endFailure\n this.endFailure = null\n if (endFailure) throw endFailure\n }\n\n private async undo(step: SoftapStep): Promise<void> {\n switch (step) {\n // `live` is an observation, not a resource — there is nothing to release.\n case \"live\":\n return\n case \"publish\":\n return this.deps.stopPublishing()\n case \"acsJoin\":\n return this.leaveOrEndMeeting()\n case \"scopedJoin\":\n return this.deps.leaveScopedNetwork()\n case \"hotspot\":\n return this.deps.stopHotspot()\n }\n }\n\n /**\n * The one step End changes.\n *\n * A failed End falls back to leaving, so the wearer is out either way, and the original failure is\n * kept for [stop] to rethrow. Recording it rather than throwing here is what keeps the hotspot\n * teardown — the steps after this one — unconditional.\n */\n private async leaveOrEndMeeting(): Promise<void> {\n if (this.teardownMode !== \"end\") return this.deps.leaveMeeting()\n const endMeeting = this.deps.endMeeting\n if (!endMeeting) {\n this.endFailure = new SoftapEndNotSupportedError()\n return this.deps.leaveMeeting()\n }\n try {\n await endMeeting()\n softapTrace(\"softap_meeting_ended_for_everyone\")\n } catch (error) {\n this.endFailure = error\n softapTraceFailure(\"softap_end_for_everyone_failed\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n // Native ends the local call even when the hang-up is refused, so this is a belt-and-braces\n // leave rather than a second teardown: it must not resurrect the failure it is covering for.\n await this.deps.leaveMeeting().catch(() => undefined)\n }\n }\n\n /**\n * Runs one step, records it as undoable, and maps any throw to a [SoftapCallError] naming the\n * step. The generation check is what makes leaving mid-step safe: a step that resolves after the\n * caller gave up is not recorded, so teardown does not try to undo it twice.\n */\n private async step(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n if (generation !== this.generation) {\n // The sequence stopped between two steps. Named here because the caller only ever sees one\n // CANCELLED error, and which step it never reached is the thing worth knowing.\n softapTraceFailure(\"softap_step_skipped_after_cancel\", {step, generation, current: this.generation})\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled before ${step}`)\n }\n // Published before the first await so a `stop()` on the very next tick can see it. Settled in\n // the `finally`, after any self-undo, so waiting on it means the step owns nothing any more.\n const settle = deferred()\n this.running = {step, settled: settle.promise}\n try {\n await this.runStep(generation, step, code, run)\n } finally {\n if (this.running?.settled === settle.promise) this.running = null\n settle.resolve()\n }\n }\n\n /** The step body itself. Split out so [step] can publish and settle {@link running} around it. */\n private async runStep(\n generation: number,\n step: SoftapStep,\n code: string,\n run: (report: SoftapStepReporter) => Promise<void>,\n ): Promise<void> {\n softapTrace(\"softap_step_begin\", {step})\n const startedAt = Date.now()\n this.stepStartedAt.set(step, startedAt)\n this.setStep(step, {status: \"running\", error: undefined})\n const report: SoftapStepReporter = (detail) => this.note(generation, step, detail)\n try {\n await run(report)\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n softapTraceFailure(\"softap_step_failed\", {step, code, reason})\n if (generation === this.generation) {\n this.setStep(step, {status: \"failed\", error: reason, durationMs: Date.now() - startedAt})\n }\n throw new SoftapCallError(step, code, error instanceof Error ? error.message : `${step} failed`, error)\n }\n if (generation !== this.generation) {\n // The step succeeded after the caller gave up. Release it here rather than recording it for\n // the teardown to find: that teardown may already have walked past this step, or finished\n // altogether, in which case nothing else ever would. This is the leak the generation guard\n // exists to close — a meeting joined a few milliseconds after the user left.\n softapTrace(\"softap_step_completed_after_cancel\", {step})\n await this.undoSafely(step)\n throw new SoftapCallError(step, \"CANCELLED\", `SoftAP call was cancelled during ${step}`)\n }\n this.completed.push(step)\n softapTrace(\"softap_step_done\", {step, durationMs: Date.now() - startedAt})\n this.setStep(step, {status: \"done\", durationMs: Date.now() - startedAt})\n }\n\n /** Undo that reports rather than throws, for the cancellation path where there is no caller. */\n private async undoSafely(step: SoftapStep): Promise<void> {\n try {\n await this.undo(step)\n } catch (error) {\n if (!this.teardownFailures.includes(step)) this.teardownFailures.push(step)\n softapTraceFailure(\"softap_step_undo_failed\", {\n step,\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n private requireHotspot(): {ssid: string; passphrase: string} {\n const hotspot = this.hotspot\n if (!hotspot) throw new SoftapCallError(\"hotspot\", \"HOTSPOT_FAILED\", \"no hotspot credentials\")\n return hotspot\n }\n\n private requireIngestUrl(): string {\n const url = this.ingestUrl\n if (!url) throw new SoftapCallError(\"acsJoin\", \"ACS_JOIN_FAILED\", \"no ingest URL\")\n return url\n }\n}\n\n/**\n * Binds the sequence to the real subsystems.\n *\n * Kept separate from the class so the ordering above is tested against fakes rather than against\n * BLE and ACS. The only logic here is adapting shapes; anything that needs a decision belongs in\n * the class.\n *\n * @param packageName the miniapp that owns the call\n * @param meeting the meeting to join, and how to observe its media health\n */\nexport function createSoftapCallDeps(args: {\n packageName: string\n meetingUrl: string\n token: string\n displayName?: string\n /**\n * The ACS outgoing profile. Used here only to size the glasses→phone hop; when absent the\n * glasses keep their WHIP defaults, which is what every pre-policy build did.\n */\n video?: {width: number; height: number; fps: number; maxBitrateBps: number}\n /** Resolves when the meeting reports a frame reached ACS; rejects on a failed feed. */\n awaitFirstFrame: () => Promise<void>\n /**\n * Mid-call camera recovery. Resolves `true` only when ingest is live again.\n * A standing `failed` is the reason we are republishing, so it must not abort the wait.\n */\n waitUntilLive?: (timeoutMs: number) => Promise<boolean>\n subsystems: {\n setHotspotState: (enabled: boolean) => Promise<{state: string; ssid?: string; password?: string; localIp?: string}>\n /** Whether this phone's Wi-Fi radio is on. Optional: only Android hosts can answer it. */\n isWifiEnabled?: () => Promise<boolean>\n joinScopedNetwork: (ssid: string, passphrase: string, gateway?: string) => Promise<string | undefined>\n leaveScopedNetwork: () => Promise<void>\n cancelScopedNetworkJoin?: () => Promise<void>\n joinMeeting: (\n packageName: string,\n options: {\n meetingUrl: string\n token: string\n videoSource: {type: \"softap\"; ssid?: string; passphrase?: string; bindAddress?: string}\n displayName?: string\n },\n ) => Promise<unknown>\n leaveMeeting: (packageName: string) => Promise<void>\n /** Terminate the group call for everyone. Absent on hosts that cannot. */\n endMeeting?: (packageName: string) => Promise<void>\n ingestUrl: () => string | null\n startPublishing: (\n packageName: string,\n options: {\n streamUrl: string\n ice: {stun: string}\n traceId: string\n captureAudio?: boolean\n video?: SoftapVideoPolicy\n },\n ) => Promise<unknown>\n stopPublishing: (packageName: string) => Promise<void>\n /**\n * Whether the host is taking the wearer's voice off the glasses over BLE LC3 for this call.\n *\n * Asked after the meeting join and before the publish, because that is the only moment the\n * answer is both known (the host has seen the native's capabilities) and still actionable (the\n * glasses have not been told what to capture). True means the WHIP publish is video-only;\n * false means the glasses put their microphone on the WHIP track as they always have. Absent\n * on hosts that only have the WHIP audio path.\n */\n glassesLc3Uplink?: () => boolean\n /**\n * Prove the phone can reach the glasses over the hotspot it just joined. Optional because\n * only Android hosts have the scoped network handle; when present its verdict is narrated\n * into the scoped-join step and a failure is reported, not thrown — the glasses-to-phone\n * direction is what the call actually needs, and that is tested by the publish step.\n */\n probeGateway?: () => Promise<{reachable: boolean; detail: string}>\n /**\n * Wait for the phone's default network to be validated again after the hotspot join took Wi-Fi\n * away. Optional because only Android hosts can answer it.\n *\n * Not fatal when it reports an unusable network: the wearer is told, and the join is attempted\n * anyway. Aborting here would fail calls that recover a second later, and the ACS join has its\n * own bounded timeout for the case that does not.\n */\n awaitValidatedDefaultNetwork?: () => Promise<{usable: boolean; detail: string} | null>\n /**\n * Glasses `stream_status` events, so the publish step can say \"camera starting\" and \"offer\n * posted\" instead of going quiet for the whole BLE round trip. Returns an unsubscribe.\n */\n onGlassesStreamStatus?: (\n listener: (event: {status: string; streamId?: string; reason?: string; error?: string}) => void,\n ) => () => void\n }\n /** Override only in tests. Production waits the gallery-proven broadcast window. */\n hotspotBroadcastWaitMs?: number\n}): SoftapCallDeps {\n const {packageName, subsystems} = args\n const hotspotBroadcastWaitMs = args.hotspotBroadcastWaitMs ?? HOTSPOT_BROADCAST_WAIT_MS\n let gatewayAddress: string | undefined\n return {\n isWifiEnabled: subsystems.isWifiEnabled ? () => subsystems.isWifiEnabled!() : undefined,\n startHotspot: async (report) => {\n const enable = async () => {\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid) {\n throw new Error(`the glasses hotspot did not start (state=${status.state})`)\n }\n if (!status.password) {\n throw new Error(\"the glasses hotspot reported no password\")\n }\n report?.(`Glasses report hotspot ${status.ssid} enabled`)\n gatewayAddress = status.localIp\n return {ssid: status.ssid, passphrase: status.password}\n }\n try {\n return await enable()\n } catch (error) {\n if (error instanceof Error && /no password/.test(error.message)) throw error\n // Cancel-then-start races the previous disable: the glasses report disabled (or no SSID)\n // and the UI said \"Couldn't start glasses hotspot\" before step 2 ran on a leftover AP.\n softapTraceFailure(\"hotspot_enable_retry\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n report?.(\"Glasses hotspot did not start; turning it off and trying again\")\n await subsystems.setHotspotState(false)\n if (hotspotBroadcastWaitMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, Math.min(1_000, hotspotBroadcastWaitMs)))\n }\n return await enable()\n }\n },\n waitUntilHotspotJoinable: async (report) => {\n if (hotspotBroadcastWaitMs <= 0) return\n softapTrace(\"hotspot_broadcast_wait\", {ms: hotspotBroadcastWaitMs})\n report?.(`Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`)\n await new Promise<void>((resolve) => setTimeout(resolve, hotspotBroadcastWaitMs))\n },\n stopHotspot: async () => {\n await subsystems.setHotspotState(false)\n },\n joinScopedNetwork: async (ssid, passphrase, report) => {\n const joinOnce = (nextSsid: string, nextPassphrase: string) =>\n gatewayAddress\n ? subsystems.joinScopedNetwork(nextSsid, nextPassphrase, gatewayAddress)\n : subsystems.joinScopedNetwork(nextSsid, nextPassphrase)\n let address: string | undefined\n try {\n address = await joinOnce(ssid, passphrase)\n } catch (error) {\n if (!isScopedJoinUnavailable(error)) throw error\n // First specifier left the phone's previous Wi-Fi and assoc-rejected the glasses AP.\n // Cycle the AP and join again from an idle STA — the radio is free now.\n softapTraceFailure(\"scoped_join_unavailable_retry\", {ssid})\n report?.(\"Phone couldn't join; cycling the glasses hotspot and trying again\")\n await subsystems.setHotspotState(false)\n const status = await subsystems.setHotspotState(true)\n if (status.state !== \"enabled\" || !status.ssid || !status.password) throw error\n gatewayAddress = status.localIp\n if (hotspotBroadcastWaitMs > 0) {\n report?.(`Giving the hotspot ${Math.round(hotspotBroadcastWaitMs / 1000)}s to start broadcasting`)\n await new Promise<void>((resolve) => setTimeout(resolve, hotspotBroadcastWaitMs))\n }\n address = await joinOnce(status.ssid, status.password)\n }\n if (subsystems.probeGateway) {\n report?.(`Phone is ${address ?? \"on the hotspot\"}; checking it can reach the glasses`)\n try {\n const probe = await subsystems.probeGateway()\n softapTrace(probe.reachable ? \"gateway_probe_ok\" : \"gateway_probe_failed\", {detail: probe.detail})\n report?.(\n probe.reachable\n ? `Phone ${address ?? \"\"} ↔ glasses OK (${probe.detail})`\n : `Phone ${address ?? \"\"} joined, but cannot reach the glasses: ${probe.detail}`,\n )\n } catch (error) {\n softapTraceFailure(\"gateway_probe_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n return address\n },\n leaveScopedNetwork: () => subsystems.leaveScopedNetwork(),\n cancelScopedNetworkJoin: subsystems.cancelScopedNetworkJoin,\n joinMeeting: async ({ssid, passphrase, bindAddress}, report) => {\n // The hotspot join just took this phone off Wi-Fi, so the route Teams needs is whatever\n // Android promoted in its place. Waiting for it to validate is what stopped the ACS join\n // from burning its whole timeout on DNS that could not resolve yet.\n if (subsystems.awaitValidatedDefaultNetwork) {\n report?.(\"Waiting for this phone's mobile data to take over so Teams can connect\")\n try {\n const network = await subsystems.awaitValidatedDefaultNetwork()\n if (network) {\n softapTrace(network.usable ? \"default_network_ok\" : \"default_network_unvalidated\", {\n detail: network.detail,\n })\n report?.(\n network.usable\n ? `Internet is on ${network.detail}`\n : `Internet is not confirmed yet (${network.detail}); joining Teams anyway`,\n )\n }\n } catch (error) {\n softapTraceFailure(\"default_network_check_threw\", {\n reason: error instanceof Error ? error.message : String(error),\n })\n }\n }\n report?.(\"Binding the video receiver and joining Teams over cellular\")\n await subsystems.joinMeeting(packageName, {\n meetingUrl: args.meetingUrl,\n token: args.token,\n videoSource: {type: \"softap\", ssid, passphrase, bindAddress},\n displayName: args.displayName,\n })\n // The listener binds during the join, so the URL only exists now.\n return {ingestUrl: subsystems.ingestUrl() ?? \"\"}\n },\n leaveMeeting: () => subsystems.leaveMeeting(packageName),\n ...(subsystems.endMeeting ? {endMeeting: () => subsystems.endMeeting!(packageName)} : {}),\n startPublishing: async ({ingestUrl, traceId}, report) => {\n // Narrate the glasses side while the BLE start command is in flight. `initializing` means\n // the glasses accepted the command and are opening the camera; `streaming` means the WHIP\n // offer was answered and ICE connected; anything else is the reason it did not.\n const unsubscribe = subsystems.onGlassesStreamStatus?.((event) => {\n if (event.status === \"initializing\") {\n report?.(\"Glasses accepted the command: camera starting, gathering ICE, posting offer to the phone\")\n } else if (event.status === \"streaming\") {\n report?.(\"Glasses are streaming to the phone\")\n } else if (event.status === \"error\") {\n report?.(`Glasses reported: ${event.error ?? event.reason ?? \"stream error\"}`)\n } else if (event.status === \"reconnecting\") {\n report?.(`Glasses reconnecting: ${event.reason ?? \"\"}`)\n }\n })\n // Decided before the command goes out, never after: the glasses cannot drop an audio track\n // they already negotiated, and two live copies of the wearer's voice in one call is worse\n // than either one alone.\n const lc3Uplink = subsystems.glassesLc3Uplink?.() ?? false\n softapTrace(\"publish_audio_decision\", {captureAudio: !lc3Uplink, micTransport: lc3Uplink ? \"ble-lc3\" : \"whip\"})\n report?.(\n lc3Uplink\n ? \"Publishing video only; the wearer's voice comes over Bluetooth LC3\"\n : \"Publishing video and the glasses microphone\",\n )\n const policy = args.video ? softapVideoPolicy(args.video) : undefined\n if (policy) {\n // Traced at send time rather than read back: the glasses log what they applied in\n // `applyBitrateConstraints`, and the pair of lines is what shows a clamp we did not\n // intend. One line alone can only ever show agreement with itself.\n softapTrace(\"softap_video_policy\", {\n width: policy.width,\n height: policy.height,\n fps: policy.fps,\n min: policy.minBitrateBps,\n start: policy.initialBitrateBps,\n max: policy.bitrate,\n })\n }\n try {\n await subsystems.startPublishing(packageName, {\n streamUrl: ingestUrl,\n // Empty STUN server means host-only: there is no route from the hotspot to a STUN server,\n // so a configured one would add doomed gathering to every call.\n ice: {stun: \"\"},\n traceId,\n captureAudio: !lc3Uplink,\n ...(policy ? {video: policy} : {}),\n })\n } finally {\n unsubscribe?.()\n }\n },\n stopPublishing: () => subsystems.stopPublishing(packageName),\n awaitFirstFrame: args.awaitFirstFrame,\n waitUntilLive: args.waitUntilLive,\n }\n}\n"]}