@mentra/engine 3.2.0-dev.227 → 3.2.0-dev.233
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/services/AcsMeetingService.d.ts +12 -6
- package/build/services/AcsMeetingService.d.ts.map +1 -1
- package/build/services/AcsMeetingService.js +23 -8
- package/build/services/AcsMeetingService.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +2 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +21 -6
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/SoftapCallTransport.d.ts +3 -0
- package/build/services/SoftapCallTransport.d.ts.map +1 -1
- package/build/services/SoftapCallTransport.js +17 -4
- package/build/services/SoftapCallTransport.js.map +1 -1
- package/package.json +8 -8
- package/src/generated/releaseMetadata.ts +5 -5
- package/src/services/AcsMeetingService.ts +28 -8
- package/src/services/LocalMiniappRuntime.ts +20 -7
- package/src/services/SoftapCallTransport.ts +20 -4
|
@@ -998,13 +998,14 @@ class LocalMiniappRuntime {
|
|
|
998
998
|
// remain active for another subscriber; a rejected FOV release then stops
|
|
999
999
|
// renewing the departed owner's lease and ASG restores it once idle.
|
|
1000
1000
|
const cameraCleanup = Promise.allSettled([
|
|
1001
|
+
this.leaveMeetingForApp(packageName),
|
|
1001
1002
|
phonePhotoCoordinator.stopWarmUpForApp(packageName),
|
|
1002
1003
|
phoneStreamCoordinator.stop(packageName),
|
|
1003
1004
|
phoneVideoCoordinator.stopForApp(packageName),
|
|
1004
1005
|
]).then((results) => {
|
|
1005
1006
|
for (const result of results) {
|
|
1006
1007
|
if (result.status === "rejected") {
|
|
1007
|
-
console.warn(`${LOG_TAG}: failed to stop
|
|
1008
|
+
console.warn(`${LOG_TAG}: failed to stop miniapp resource for ${packageName} on unregister`, result.reason)
|
|
1008
1009
|
}
|
|
1009
1010
|
}
|
|
1010
1011
|
})
|
|
@@ -1038,10 +1039,6 @@ class LocalMiniappRuntime {
|
|
|
1038
1039
|
// so a crashed/closed miniapp doesn't leak partial files or file handles.
|
|
1039
1040
|
this.blobStore.onAppGone(packageName)
|
|
1040
1041
|
|
|
1041
|
-
void acsMeetingService.leaveIfOwner(packageName).catch((error) => {
|
|
1042
|
-
console.warn(`${LOG_TAG}: failed to leave ACS meeting for ${packageName} on unregister`, error)
|
|
1043
|
-
})
|
|
1044
|
-
|
|
1045
1042
|
// Detach the per-app nav event forwarder but leave the native nav session
|
|
1046
1043
|
// running. The user may have just closed the mini-app UI and will reopen
|
|
1047
1044
|
// it; stopping the session here would kill an active trip mid-route.
|
|
@@ -3668,6 +3665,9 @@ class LocalMiniappRuntime {
|
|
|
3668
3665
|
|
|
3669
3666
|
private ensureMeetingStateBridge(): void {
|
|
3670
3667
|
acsMeetingService.setStateHandler((owner, state) => {
|
|
3668
|
+
const attempt = this.softapAttempt
|
|
3669
|
+
// While a replacement waits for cleanup, native events still describe its predecessor.
|
|
3670
|
+
if (attempt?.packageName === owner && !attempt.ownsResources) return
|
|
3671
3671
|
this.sendToMiniapp(owner, {
|
|
3672
3672
|
type: MiniappResponseType.MEETING_STATE,
|
|
3673
3673
|
...state,
|
|
@@ -3675,6 +3675,16 @@ class LocalMiniappRuntime {
|
|
|
3675
3675
|
})
|
|
3676
3676
|
}
|
|
3677
3677
|
|
|
3678
|
+
/** Startup owns the hotspot before ACS has an owner. Closing the app must retire both. */
|
|
3679
|
+
private async leaveMeetingForApp(packageName: string): Promise<void> {
|
|
3680
|
+
const attempt = this.softapAttempt
|
|
3681
|
+
if (attempt?.packageName === packageName) {
|
|
3682
|
+
await this.retireSoftapAttempt({attempt})
|
|
3683
|
+
} else {
|
|
3684
|
+
await acsMeetingService.leaveIfOwner(packageName)
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3678
3688
|
private async handleMeetingJoin(
|
|
3679
3689
|
packageName: string,
|
|
3680
3690
|
payload: Record<string, unknown>,
|
|
@@ -3903,7 +3913,8 @@ class LocalMiniappRuntime {
|
|
|
3903
3913
|
return
|
|
3904
3914
|
}
|
|
3905
3915
|
attempt.progress = progress
|
|
3906
|
-
|
|
3916
|
+
// A reservation waiting behind another call must not inherit that call's connected state.
|
|
3917
|
+
const current = attempt.transport ? acsMeetingService.getState() : {state: "connecting", muted: false}
|
|
3907
3918
|
this.sendToMiniapp(attempt.packageName, {
|
|
3908
3919
|
type: MiniappResponseType.MEETING_STATE,
|
|
3909
3920
|
...current,
|
|
@@ -3937,6 +3948,7 @@ class LocalMiniappRuntime {
|
|
|
3937
3948
|
): Promise<MeetingState> {
|
|
3938
3949
|
const packageName = attempt.packageName
|
|
3939
3950
|
if (previous) {
|
|
3951
|
+
this.narrateSoftapPreflight(attempt, "Finishing the previous call’s cleanup…")
|
|
3940
3952
|
softapTrace("softap_join_superseding", {
|
|
3941
3953
|
previousAttempt: previous.id,
|
|
3942
3954
|
previousAgeMs: Date.now() - previous.startedAt,
|
|
@@ -4000,6 +4012,7 @@ class LocalMiniappRuntime {
|
|
|
4000
4012
|
joinScopedNetwork: (ssid, passphrase, gateway) =>
|
|
4001
4013
|
acsMeetingService.joinScopedNetwork(ssid, passphrase, gateway),
|
|
4002
4014
|
leaveScopedNetwork: () => acsMeetingService.leaveScopedNetwork(),
|
|
4015
|
+
cancelScopedNetworkJoin: () => acsMeetingService.cancelScopedNetworkJoin(),
|
|
4003
4016
|
probeGateway: async () => {
|
|
4004
4017
|
const verdict = await acsMeetingService.probeScopedGateway()
|
|
4005
4018
|
// No native probe means no verdict, and the orchestrator must not read that as "down".
|
|
@@ -4251,7 +4264,7 @@ class LocalMiniappRuntime {
|
|
|
4251
4264
|
// Teams configuration problem.
|
|
4252
4265
|
const defaultNetworkStartedAt = Date.now()
|
|
4253
4266
|
try {
|
|
4254
|
-
const network = await acsMeetingService.
|
|
4267
|
+
const network = await acsMeetingService.awaitDefaultNetworkAfterHotspot()
|
|
4255
4268
|
softapTrace("softap_teardown_step", {
|
|
4256
4269
|
attempt: attempt.id,
|
|
4257
4270
|
step: "awaitValidatedDefaultNetwork",
|
|
@@ -107,6 +107,8 @@ export interface SoftapCallDeps {
|
|
|
107
107
|
/** Join the hotspot without taking the phone's default route. Resolves to the phone's own IPv4. */
|
|
108
108
|
joinScopedNetwork(ssid: string, passphrase: string, report?: SoftapStepReporter): Promise<string | undefined>
|
|
109
109
|
leaveScopedNetwork(): Promise<void>
|
|
110
|
+
/** Interrupt a pending native join while retaining its cleanup barrier. Unsupported hosts wait. */
|
|
111
|
+
cancelScopedNetworkJoin?(): Promise<void>
|
|
110
112
|
/**
|
|
111
113
|
* Join the meeting. This is what binds the local WHIP listener and arms the ACS raw outputs, so
|
|
112
114
|
* it must resolve before the glasses are told to publish.
|
|
@@ -411,7 +413,7 @@ export class SoftapCallTransport {
|
|
|
411
413
|
throw new Error("the meeting reported no ingest URL")
|
|
412
414
|
}
|
|
413
415
|
this.ingestUrl = ingestUrl
|
|
414
|
-
softapTrace("
|
|
416
|
+
softapTrace("acs_receiver_ready", {ingestUrl})
|
|
415
417
|
report(`Receiver ready at ${ingestUrl}`)
|
|
416
418
|
})
|
|
417
419
|
|
|
@@ -424,10 +426,10 @@ export class SoftapCallTransport {
|
|
|
424
426
|
})
|
|
425
427
|
|
|
426
428
|
await this.step(generation, "live", "NO_FIRST_FRAME", async (report) => {
|
|
427
|
-
report("Waiting for the first video frame
|
|
429
|
+
report("Waiting for the first glasses video frame on this phone")
|
|
428
430
|
await this.deps.awaitFirstFrame(report)
|
|
429
|
-
softapTrace("
|
|
430
|
-
report("
|
|
431
|
+
softapTrace("first_glasses_frame_received")
|
|
432
|
+
report("Glasses video is reaching this phone")
|
|
431
433
|
})
|
|
432
434
|
|
|
433
435
|
if (generation !== this.generation) {
|
|
@@ -500,9 +502,21 @@ export class SoftapCallTransport {
|
|
|
500
502
|
// this call is still coming". Deliberately unbounded: a native call that never returns must
|
|
501
503
|
// hold the next call back, never let it race this one's cleanup.
|
|
502
504
|
if (running) {
|
|
505
|
+
const cancellation =
|
|
506
|
+
running.step === "scopedJoin" && this.deps.cancelScopedNetworkJoin
|
|
507
|
+
? Promise.resolve()
|
|
508
|
+
.then(() => this.deps.cancelScopedNetworkJoin!())
|
|
509
|
+
.catch((error) => {
|
|
510
|
+
if (!this.teardownFailures.includes("scopedJoin")) this.teardownFailures.push("scopedJoin")
|
|
511
|
+
softapTraceFailure("softap_join_cancel_failed", {
|
|
512
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
513
|
+
})
|
|
514
|
+
})
|
|
515
|
+
: undefined
|
|
503
516
|
softapTrace("softap_stop_waiting_for_step", {step: running.step})
|
|
504
517
|
const waitStartedAt = Date.now()
|
|
505
518
|
await running.settled
|
|
519
|
+
await cancellation
|
|
506
520
|
// This wait is unbounded by design, so its duration is the difference between "the leave
|
|
507
521
|
// was slow" and "the leave was held by a native call that had not returned".
|
|
508
522
|
softapTrace("softap_stop_step_settled", {step: running.step, waitedMs: Date.now() - waitStartedAt})
|
|
@@ -710,6 +724,7 @@ export function createSoftapCallDeps(args: {
|
|
|
710
724
|
setHotspotState: (enabled: boolean) => Promise<{state: string; ssid?: string; password?: string; localIp?: string}>
|
|
711
725
|
joinScopedNetwork: (ssid: string, passphrase: string, gateway?: string) => Promise<string | undefined>
|
|
712
726
|
leaveScopedNetwork: () => Promise<void>
|
|
727
|
+
cancelScopedNetworkJoin?: () => Promise<void>
|
|
713
728
|
joinMeeting: (
|
|
714
729
|
packageName: string,
|
|
715
730
|
options: {
|
|
@@ -853,6 +868,7 @@ export function createSoftapCallDeps(args: {
|
|
|
853
868
|
return address
|
|
854
869
|
},
|
|
855
870
|
leaveScopedNetwork: () => subsystems.leaveScopedNetwork(),
|
|
871
|
+
cancelScopedNetworkJoin: subsystems.cancelScopedNetworkJoin,
|
|
856
872
|
joinMeeting: async ({ssid, passphrase, bindAddress}, report) => {
|
|
857
873
|
// The hotspot join just took this phone off Wi-Fi, so the route Teams needs is whatever
|
|
858
874
|
// Android promoted in its place. Waiting for it to validate is what stopped the ACS join
|