@glassly/engine 0.3.3-beta.630 → 0.3.3-beta.639
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/engine.d.ts +1 -0
- package/build/engine.d.ts.map +1 -1
- package/build/facades/glasses.d.ts +6 -0
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +33 -1
- package/build/facades/glasses.js.map +1 -1
- package/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/services/MicStateCoordinator.d.ts +8 -0
- package/build/services/MicStateCoordinator.d.ts.map +1 -1
- package/build/services/MicStateCoordinator.js +24 -3
- package/build/services/MicStateCoordinator.js.map +1 -1
- package/build/stores/settings.js +5 -5
- package/build/stores/settings.js.map +1 -1
- package/package.json +7 -7
- package/src/facades/glasses.ts +33 -1
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/services/MicStateCoordinator.ts +25 -3
- package/src/stores/settings.ts +5 -5
package/build/engine.d.ts
CHANGED
|
@@ -81,6 +81,7 @@ export declare const engine: {
|
|
|
81
81
|
getMediaVolume: () => Promise<import("@glassly/bluetooth-sdk").GlassesMediaVolumeGetResult>;
|
|
82
82
|
setMediaVolume: (level: number) => Promise<import("@glassly/bluetooth-sdk").GlassesMediaVolumeSetResult>;
|
|
83
83
|
setOwnAppPlaying: (playing: boolean) => Promise<void>;
|
|
84
|
+
onMicLevel: (cb: (dbfs: number) => void) => (() => void);
|
|
84
85
|
};
|
|
85
86
|
wifi: {
|
|
86
87
|
scan(): Promise<import("@glassly/bluetooth-sdk").WifiSearchResult[]>;
|
package/build/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAC,SAAS,EAAkD,aAAa,EAAC,MAAM,qBAAqB,CAAA;AA4C5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IAgG7C;;yCAEqC
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAC,SAAS,EAAkD,aAAa,EAAC,MAAM,qBAAqB,CAAA;AA4C5G,eAAO,MAAM,MAAM;IACjB,2EAA2E;;IAE3E,8EAA8E;;IAE9E;iDAC6C;;IAgG7C;;yCAEqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmCrC,wEAAwE;;;;;;;;IAExE,sEAAsE;;;;;;;;;;;;IAEtE,qFAAqF;;;;gBA5HV,CAAC;mBAAiB,CAAC;;;gBAM5F,CADA;mBAAiB,CAAC;;;;;;;;;;;;;;;;;IAyHpB,qEAAqE;;;;IAErE,sFAAsF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEtF,6EAA6E;;;;;;;;;;;;IAE7E,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;IAEjF,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE9C,uDAAuD;;;;;;;;;;;;;;;;IAEvD,8EAA8E;;;;;;;;IAE9E,qFAAqF;;;;IAErF,4EAA4E;;;;;;;;;;;IAE5E,+EAA+E;;;;;;;;;;;;IAE/E,kFAAkF;;;;;+BAlJ3D,CAAC;;;+BAUf,CAAC;;;;;;;;;;;;IA0IV,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGpF,CAAA"}
|
|
@@ -165,6 +165,12 @@ export declare const glasses: {
|
|
|
165
165
|
setMediaVolume: (level: number) => Promise<import("@glassly/bluetooth-sdk").GlassesMediaVolumeSetResult>;
|
|
166
166
|
/** Tell native whether THIS app is currently playing audio (for ducking). */
|
|
167
167
|
setOwnAppPlaying: (playing: boolean) => Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Stream the active mic's level in dBFS, one reading per PCM chunk. Holds
|
|
170
|
+
* raw PCM open while subscribed, so the mic runs with no miniapp listening
|
|
171
|
+
* (and the G2 volume gate stays open).
|
|
172
|
+
*/
|
|
173
|
+
onMicLevel: (cb: (dbfs: number) => void) => (() => void);
|
|
168
174
|
};
|
|
169
175
|
wifi: {
|
|
170
176
|
scan(): Promise<import("@glassly/bluetooth-sdk").WifiSearchResult[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glasses.d.ts","sourceRoot":"","sources":["../../src/facades/glasses.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,MAAM,EACN,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACX,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"glasses.d.ts","sourceRoot":"","sources":["../../src/facades/glasses.ts"],"names":[],"mappings":"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"}
|
package/build/facades/glasses.js
CHANGED
|
@@ -14,6 +14,7 @@ import BluetoothSdk from "@glassly/bluetooth-sdk/internal";
|
|
|
14
14
|
import { useGlassesStore } from "../stores/glasses";
|
|
15
15
|
import { useSettingsStore, SETTINGS } from "../stores/settings";
|
|
16
16
|
import { hasDefaultDevice } from "../services/DeviceStoreHydration";
|
|
17
|
+
import micStateCoordinator from "../services/MicStateCoordinator";
|
|
17
18
|
import { projectPairingIdentity } from "../services/PairingIdentity";
|
|
18
19
|
import { isGlassesConnected, isGlassesReady } from "../services/GlassesReadiness";
|
|
19
20
|
import { pushAllBluetoothSettings } from "../services/GlassesSettingsSync";
|
|
@@ -22,6 +23,20 @@ import { recordSupportProfileConnectionFailure } from "../services/SupportProfil
|
|
|
22
23
|
import { getModelCapabilities } from "../types";
|
|
23
24
|
import { glassesWifi } from "./glassesWifi";
|
|
24
25
|
import { glassesSettings } from "./glassesSettings";
|
|
26
|
+
/** Floor for the mic level readout; digital silence would otherwise be -Infinity. */
|
|
27
|
+
const MIC_LEVEL_FLOOR_DBFS = -120;
|
|
28
|
+
/** RMS level of one s16le chunk in dBFS, on the volume gate's 32767 full scale. */
|
|
29
|
+
function pcmLevelDbfs(pcm) {
|
|
30
|
+
const samples = new Int16Array(pcm, 0, pcm.byteLength >> 1);
|
|
31
|
+
if (samples.length === 0)
|
|
32
|
+
return MIC_LEVEL_FLOOR_DBFS;
|
|
33
|
+
let sumSquares = 0;
|
|
34
|
+
for (let i = 0; i < samples.length; i++)
|
|
35
|
+
sumSquares += samples[i] * samples[i];
|
|
36
|
+
const rms = Math.sqrt(sumSquares / samples.length);
|
|
37
|
+
return Math.max(MIC_LEVEL_FLOOR_DBFS, 20 * Math.log10(rms / 32767));
|
|
38
|
+
}
|
|
39
|
+
let micLevelSubscriptions = 0;
|
|
25
40
|
function projectStatus() {
|
|
26
41
|
const s = useGlassesStore.getState();
|
|
27
42
|
return {
|
|
@@ -275,7 +290,7 @@ export const glasses = {
|
|
|
275
290
|
setPointer: (enabled) => BluetoothSdk.neuralBandSetPointer(enabled),
|
|
276
291
|
setHand: (hand) => BluetoothSdk.neuralBandSetHand(hand),
|
|
277
292
|
},
|
|
278
|
-
// --- audio (glasses media-volume
|
|
293
|
+
// --- audio (glasses media-volume, own-app playback hint, live mic level) ---
|
|
279
294
|
audio: {
|
|
280
295
|
/** Read the glasses' current media volume. */
|
|
281
296
|
getMediaVolume: () => BluetoothSdk.getGlassesMediaVolume(),
|
|
@@ -283,6 +298,23 @@ export const glasses = {
|
|
|
283
298
|
setMediaVolume: (level) => BluetoothSdk.setGlassesMediaVolume(level),
|
|
284
299
|
/** Tell native whether THIS app is currently playing audio (for ducking). */
|
|
285
300
|
setOwnAppPlaying: (playing) => BluetoothSdk.setOwnAppAudioPlaying(playing),
|
|
301
|
+
/**
|
|
302
|
+
* Stream the active mic's level in dBFS, one reading per PCM chunk. Holds
|
|
303
|
+
* raw PCM open while subscribed, so the mic runs with no miniapp listening
|
|
304
|
+
* (and the G2 volume gate stays open).
|
|
305
|
+
*/
|
|
306
|
+
onMicLevel: (cb) => {
|
|
307
|
+
const owner = `mic_level_${++micLevelSubscriptions}`;
|
|
308
|
+
micStateCoordinator.acquireHostPcm(owner);
|
|
309
|
+
const sub = BluetoothSdk.addListener("mic_pcm", (event) => {
|
|
310
|
+
if (event?.pcm)
|
|
311
|
+
cb(pcmLevelDbfs(event.pcm));
|
|
312
|
+
});
|
|
313
|
+
return () => {
|
|
314
|
+
sub.remove();
|
|
315
|
+
micStateCoordinator.releaseHostPcm(owner);
|
|
316
|
+
};
|
|
317
|
+
},
|
|
286
318
|
},
|
|
287
319
|
// --- sub-facades ---
|
|
288
320
|
wifi: glassesWifi,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glasses.js","sourceRoot":"","sources":["../../src/facades/glasses.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * glasses facade — the core `engine.glasses.*` surface: connection actions (over\n * the bluetooth-sdk passthrough), a curated status/info read-model (projected from\n * the engine-owned glasses store), capabilities (from the model table), and the\n * discrete input events. The `wifi` sub-facade is nested here.\n *\n * Read-models project the raw glasses store into the stable shape OEM UIs consume,\n * so the device store's field layout doesn't leak into every screen.\n */\n// Internal btsdk surface — connectSimulated/reconnect/controller live on the full\n// surface, not the public entry. Relative path (the alias doesn't resolve in engine's\n// standalone build); jest moduleNameMapper + tsconfig both resolve it.\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport type {\n ButtonPressEvent,\n ConnectOptions,\n Device,\n KeyboardAdvertEvent,\n KeyboardPairingEvent,\n TouchEvent,\n} from \"@glassly/bluetooth-sdk\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {useSettingsStore, SETTINGS} from \"../stores/settings\"\nimport {hasDefaultDevice} from \"../services/DeviceStoreHydration\"\nimport {projectPairingIdentity} from \"../services/PairingIdentity\"\nimport {isGlassesConnected, isGlassesReady} from \"../services/GlassesReadiness\"\nimport {pushAllBluetoothSettings} from \"../services/GlassesSettingsSync\"\nimport neuralBandInput, {\n type NeuralBandClaimStatus,\n type NeuralBandHandwritingStatus,\n} from \"../services/neuralBand/NeuralBandInput\"\nimport {recordSupportProfileConnectionFailure} from \"../services/SupportProfileSync\"\nimport {getModelCapabilities, type DeviceTypes} from \"../types\"\nimport {glassesWifi} from \"./glassesWifi\"\nimport {glassesSettings} from \"./glassesSettings\"\n\nfunction projectStatus() {\n const s = useGlassesStore.getState()\n return {\n state: s.connection.state,\n fullyBooted: isGlassesReady(s.connection),\n battery: s.batteryLevel,\n charging: s.charging,\n case: {battery: s.caseBatteryLevel, charging: s.caseCharging, open: s.caseOpen, removed: s.caseRemoved},\n signal: s.signalStrength,\n micEnabled: s.micEnabled,\n vadEnabled: s.voiceActivityDetectionEnabled,\n btClassic: s.bluetoothClassicConnected,\n // iOS: glasses may read the phone's ANCS stream (\"Share System Notifications\").\n ancsAuthorized: Boolean(s.ancsAuthorized),\n }\n}\n\nfunction projectControllerStatus() {\n const s = useGlassesStore.getState()\n return {\n connected: s.controllerConnected,\n fullyBooted: s.controllerFullyBooted,\n battery: s.controllerBatteryLevel,\n signal: s.controllerSignalStrength,\n }\n}\n\nfunction projectKeyboardStatus() {\n const s = useGlassesStore.getState()\n return {\n /** Connected glasses run a firmware that can host a keyboard (G2 Glassly CFW 39+). */\n available: s.keyboardBridge === true,\n connected: s.keyboardConnected === true,\n name: s.keyboardName ?? \"\",\n /** A keyboard is remembered and reconnects automatically. */\n saved: s.keyboardSaved === true,\n state: s.keyboardState ?? \"idle\",\n error: s.keyboardError ?? \"\",\n }\n}\n\nfunction projectInfo() {\n const s = useGlassesStore.getState()\n return {\n model: s.deviceModel,\n style: s.style,\n color: s.color,\n bluetoothName: s.bluetoothName,\n firmwareVersion: s.firmwareVersion,\n mtkFirmware: s.mtkFirmwareVersion,\n besFirmware: s.besFirmwareVersion,\n appVersion: s.appVersion,\n androidVersion: s.androidVersion,\n serialNumber: s.serialNumber,\n buildNumber: s.buildNumber,\n btMac: s.bluetoothMacAddress,\n wifiMac: s.wifiMacAddress,\n leftMac: s.leftMacAddress,\n rightMac: s.rightMacAddress,\n sceneCanvasWidth: s.sceneCanvasWidth,\n sceneCanvasHeight: s.sceneCanvasHeight,\n volumeGate: s.volumeGate === true,\n // Copy: the snapshot must not hand callers a mutable reference into the store.\n wifi: {...s.wifi},\n }\n}\n\nexport type GlassesStatusSnapshot = ReturnType<typeof projectStatus>\nexport type ControllerStatusSnapshot = ReturnType<typeof projectControllerStatus>\nexport type KeyboardStatusSnapshot = ReturnType<typeof projectKeyboardStatus>\nexport type GlassesInfoSnapshot = ReturnType<typeof projectInfo>\n\nexport const glasses = {\n // --- connection (bluetooth-sdk passthrough) ---\n /**\n * Reconnect the default wearable. Seeds the phone's current device settings to\n * native first, so they're primed before the connect handshake replays them to\n * the glasses (this used to be a host-side step before `connectDefault`).\n */\n connectDefault: async (): Promise<void> => {\n try {\n await pushAllBluetoothSettings()\n await BluetoothSdk.connectDefault()\n } catch (error) {\n recordSupportProfileConnectionFailure(error, \"connect_default\")\n throw error\n }\n },\n disconnect: (): Promise<void> => BluetoothSdk.disconnect(),\n forget: (): Promise<void> => BluetoothSdk.forget(),\n /** Connect to a specific (discovered) device. */\n connect: async (device: Device, options?: ConnectOptions): Promise<void> => {\n try {\n await pushAllBluetoothSettings()\n await BluetoothSdk.connect(device, options)\n } catch (error) {\n recordSupportProfileConnectionFailure(error, \"connect\")\n throw error\n }\n },\n /** Connect the built-in simulated glasses (dev/testing). */\n connectSimulated: (): Promise<void> => BluetoothSdk.connectSimulated(),\n /** Set a device as the `connectDefault()` target. */\n setDefault: (device: Device | null): Promise<void> => BluetoothSdk.setDefaultDevice(device),\n /**\n * Reconnect to the saved default glasses. Resolves `false` when there's nothing to\n * reconnect to (no default paired) or the connect attempt fails (e.g. BLE powered\n * off), `true` when already connected or after kicking off the connect. Never\n * rejects — the boolean contract holds. The host gates connectivity/permissions\n * (its UI) before calling.\n */\n reconnect: async (): Promise<boolean> => {\n const defaultWearable = useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key)\n if (!defaultWearable) return false\n if (isGlassesConnected(useGlassesStore.getState().connection)) return true\n try {\n await pushAllBluetoothSettings()\n await BluetoothSdk.connectDefault()\n } catch (error) {\n recordSupportProfileConnectionFailure(error, \"reconnect\")\n console.warn(\"engine.glasses.reconnect failed:\", error)\n return false\n }\n return true\n },\n /** True when no glasses has ever been paired NOR selected (the pairing-identity\n * lifecycle is in its `none` state) — e.g. to route a first-run host into the\n * pairing/onboarding flow. A pending selection is not \"first\" — the host should\n * offer finish-pairing (see `engine.pairing.identity()`). */\n isFirstPairing: (): boolean => projectPairingIdentity().kind === \"none\",\n /**\n * True when the SDK has an actual default DEVICE to reconnect to. Distinct from\n * `default_wearable` (a model string that a pending or orphaned selection can\n * hold without any paired device): connectDefault() throws without a device, so\n * hosts should route to the pairing flow when this is false.\n *\n * Hydration-aware: awaits the device-store seed internally, so a cold-start\n * read can't see a false \"absent\" for genuinely-paired users. Rejects if\n * hydration failed — callers guarding destructive or routing decisions must\n * fail open (treat as \"has a device\").\n */\n hasDefaultDevice: (): Promise<boolean> => hasDefaultDevice(),\n\n // --- read-model (projected from the engine-owned glasses store) ---\n status: (): GlassesStatusSnapshot => projectStatus(),\n onStatus: (cb: (status: GlassesStatusSnapshot) => void): (() => void) => {\n // Dedupe: the glasses store updates on many fields; only fire when the\n // projected status snapshot actually changes.\n let last = JSON.stringify(projectStatus())\n return useGlassesStore.subscribe(() => {\n const snap = projectStatus()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n info: (): GlassesInfoSnapshot => projectInfo(),\n onInfo: (cb: (info: GlassesInfoSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectInfo())\n return useGlassesStore.subscribe(() => {\n const snap = projectInfo()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n capabilities: () => getModelCapabilities(useGlassesStore.getState().deviceModel as DeviceTypes),\n /** Ask the glasses to report fresh firmware/version info (updates the store). */\n requestVersionInfo: () => BluetoothSdk.requestVersionInfo(),\n\n // --- discrete input events (passthrough listeners) ---\n onButtonPress: (cb: (event: ButtonPressEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"button_press\", cb)\n return () => sub.remove()\n },\n onTouchGesture: (cb: (event: TouchEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"touch_event\", cb)\n return () => sub.remove()\n },\n\n // --- BLE keyboard bridged through G2 Glassly CFW (revision 39+) ---\n keyboard: {\n /** Five-second scan; distinct advertisers, HID ones flagged. Also streams via onAdvert. */\n scan: (): Promise<KeyboardAdvertEvent[]> => BluetoothSdk.g2KeyboardScan(),\n /** Connect, pair and subscribe; the keyboard is remembered and auto-reconnected. */\n connect: async (device: {address: string; addressType: number; name: string}): Promise<void> => {\n await BluetoothSdk.g2KeyboardConnect(device.address, device.addressType, device.name)\n useSettingsStore.getState().setSetting(SETTINGS.keyboard_name.key, device.name)\n },\n reconnect: (): Promise<void> => BluetoothSdk.g2KeyboardReconnect(),\n disconnect: (): Promise<void> => BluetoothSdk.g2KeyboardDisconnect(),\n forget: async (): Promise<void> => {\n await BluetoothSdk.g2KeyboardForget()\n useSettingsStore.getState().setSetting(SETTINGS.keyboard_name.key, \"\")\n },\n passkey: (pin: number): Promise<void> => BluetoothSdk.g2KeyboardPasskey(pin),\n compare: (accept: boolean): Promise<void> => BluetoothSdk.g2KeyboardCompare(accept),\n status: (): KeyboardStatusSnapshot => projectKeyboardStatus(),\n onStatus: (cb: (status: KeyboardStatusSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectKeyboardStatus())\n return useGlassesStore.subscribe(() => {\n const snap = projectKeyboardStatus()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n onAdvert: (cb: (advert: KeyboardAdvertEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"keyboard_advert\", cb)\n return () => sub.remove()\n },\n onPairing: (cb: (prompt: KeyboardPairingEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"keyboard_pairing\", cb)\n return () => sub.remove()\n },\n },\n\n // --- ring controller (optional input device) ---\n controller: {\n connectDefault: (): Promise<void> => BluetoothSdk.connectDefaultController(),\n disconnect: (): Promise<void> => BluetoothSdk.disconnectController(),\n forget: (): Promise<void> => BluetoothSdk.forgetController(),\n status: (): ControllerStatusSnapshot => projectControllerStatus(),\n onStatus: (cb: (status: ControllerStatusSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectControllerStatus())\n return useGlassesStore.subscribe(() => {\n const snap = projectControllerStatus()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n },\n\n // --- Meta Neural Band (a controller with a claim step and its own features) ---\n neuralBand: {\n /** Store the Meta account session the one-time band claim uses. */\n setMetaSession: (accessToken: string, userId: string): Promise<void> =>\n BluetoothSdk.neuralBandSetMetaSession(accessToken, userId),\n clearMetaSession: (): Promise<void> => BluetoothSdk.neuralBandClearMetaSession(),\n hasMetaSession: (): Promise<boolean> => BluetoothSdk.neuralBandHasMetaSession(),\n /** A band identity is stored on this phone, so the remembered band connects without a claim. */\n isClaimed: (): Promise<boolean> => BluetoothSdk.neuralBandIsClaimed(),\n /** The latest claim progress, kept across screens. */\n claimStatus: (): NeuralBandClaimStatus => neuralBandInput.claimStatus(),\n resetClaim: (): void => neuralBandInput.resetClaim(),\n onClaimStatus: (cb: (status: NeuralBandClaimStatus) => void): (() => void) => neuralBandInput.onClaimStatus(cb),\n /** The band's handwriting model; writing arrives on the miniapp keyboard stream. */\n setHandwriting: (enabled: boolean): Promise<void> => BluetoothSdk.neuralBandSetHandwriting(enabled),\n handwritingStatus: (): NeuralBandHandwritingStatus => neuralBandInput.handwritingStatus(),\n onHandwritingStatus: (cb: (status: NeuralBandHandwritingStatus) => void): (() => void) =>\n neuralBandInput.onHandwritingStatus(cb),\n /** The band's air mouse; movement reaches miniapps on the pointer stream. */\n setPointer: (enabled: boolean): Promise<void> => BluetoothSdk.neuralBandSetPointer(enabled),\n setHand: (hand: \"left\" | \"right\"): Promise<void> => BluetoothSdk.neuralBandSetHand(hand),\n },\n\n // --- audio (glasses media-volume + own-app playback hint) ---\n audio: {\n /** Read the glasses' current media volume. */\n getMediaVolume: () => BluetoothSdk.getGlassesMediaVolume(),\n /** Set the glasses' media volume. */\n setMediaVolume: (level: number) => BluetoothSdk.setGlassesMediaVolume(level),\n /** Tell native whether THIS app is currently playing audio (for ducking). */\n setOwnAppPlaying: (playing: boolean): Promise<void> => BluetoothSdk.setOwnAppAudioPlaying(playing),\n },\n\n // --- sub-facades ---\n wifi: glassesWifi,\n settings: glassesSettings,\n}\n"]}
|
|
1
|
+
{"version":3,"file":"glasses.js","sourceRoot":"","sources":["../../src/facades/glasses.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * glasses facade — the core `engine.glasses.*` surface: connection actions (over\n * the bluetooth-sdk passthrough), a curated status/info read-model (projected from\n * the engine-owned glasses store), capabilities (from the model table), and the\n * discrete input events. The `wifi` sub-facade is nested here.\n *\n * Read-models project the raw glasses store into the stable shape OEM UIs consume,\n * so the device store's field layout doesn't leak into every screen.\n */\n// Internal btsdk surface — connectSimulated/reconnect/controller live on the full\n// surface, not the public entry. Relative path (the alias doesn't resolve in engine's\n// standalone build); jest moduleNameMapper + tsconfig both resolve it.\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport type {\n ButtonPressEvent,\n ConnectOptions,\n Device,\n KeyboardAdvertEvent,\n KeyboardPairingEvent,\n TouchEvent,\n} from \"@glassly/bluetooth-sdk\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {useSettingsStore, SETTINGS} from \"../stores/settings\"\nimport {hasDefaultDevice} from \"../services/DeviceStoreHydration\"\nimport micStateCoordinator from \"../services/MicStateCoordinator\"\nimport {projectPairingIdentity} from \"../services/PairingIdentity\"\nimport {isGlassesConnected, isGlassesReady} from \"../services/GlassesReadiness\"\nimport {pushAllBluetoothSettings} from \"../services/GlassesSettingsSync\"\nimport neuralBandInput, {\n type NeuralBandClaimStatus,\n type NeuralBandHandwritingStatus,\n} from \"../services/neuralBand/NeuralBandInput\"\nimport {recordSupportProfileConnectionFailure} from \"../services/SupportProfileSync\"\nimport {getModelCapabilities, type DeviceTypes} from \"../types\"\nimport {glassesWifi} from \"./glassesWifi\"\nimport {glassesSettings} from \"./glassesSettings\"\n\n/** Floor for the mic level readout; digital silence would otherwise be -Infinity. */\nconst MIC_LEVEL_FLOOR_DBFS = -120\n\n/** RMS level of one s16le chunk in dBFS, on the volume gate's 32767 full scale. */\nfunction pcmLevelDbfs(pcm: ArrayBuffer): number {\n const samples = new Int16Array(pcm, 0, pcm.byteLength >> 1)\n if (samples.length === 0) return MIC_LEVEL_FLOOR_DBFS\n let sumSquares = 0\n for (let i = 0; i < samples.length; i++) sumSquares += samples[i] * samples[i]\n const rms = Math.sqrt(sumSquares / samples.length)\n return Math.max(MIC_LEVEL_FLOOR_DBFS, 20 * Math.log10(rms / 32767))\n}\n\nlet micLevelSubscriptions = 0\n\nfunction projectStatus() {\n const s = useGlassesStore.getState()\n return {\n state: s.connection.state,\n fullyBooted: isGlassesReady(s.connection),\n battery: s.batteryLevel,\n charging: s.charging,\n case: {battery: s.caseBatteryLevel, charging: s.caseCharging, open: s.caseOpen, removed: s.caseRemoved},\n signal: s.signalStrength,\n micEnabled: s.micEnabled,\n vadEnabled: s.voiceActivityDetectionEnabled,\n btClassic: s.bluetoothClassicConnected,\n // iOS: glasses may read the phone's ANCS stream (\"Share System Notifications\").\n ancsAuthorized: Boolean(s.ancsAuthorized),\n }\n}\n\nfunction projectControllerStatus() {\n const s = useGlassesStore.getState()\n return {\n connected: s.controllerConnected,\n fullyBooted: s.controllerFullyBooted,\n battery: s.controllerBatteryLevel,\n signal: s.controllerSignalStrength,\n }\n}\n\nfunction projectKeyboardStatus() {\n const s = useGlassesStore.getState()\n return {\n /** Connected glasses run a firmware that can host a keyboard (G2 Glassly CFW 39+). */\n available: s.keyboardBridge === true,\n connected: s.keyboardConnected === true,\n name: s.keyboardName ?? \"\",\n /** A keyboard is remembered and reconnects automatically. */\n saved: s.keyboardSaved === true,\n state: s.keyboardState ?? \"idle\",\n error: s.keyboardError ?? \"\",\n }\n}\n\nfunction projectInfo() {\n const s = useGlassesStore.getState()\n return {\n model: s.deviceModel,\n style: s.style,\n color: s.color,\n bluetoothName: s.bluetoothName,\n firmwareVersion: s.firmwareVersion,\n mtkFirmware: s.mtkFirmwareVersion,\n besFirmware: s.besFirmwareVersion,\n appVersion: s.appVersion,\n androidVersion: s.androidVersion,\n serialNumber: s.serialNumber,\n buildNumber: s.buildNumber,\n btMac: s.bluetoothMacAddress,\n wifiMac: s.wifiMacAddress,\n leftMac: s.leftMacAddress,\n rightMac: s.rightMacAddress,\n sceneCanvasWidth: s.sceneCanvasWidth,\n sceneCanvasHeight: s.sceneCanvasHeight,\n volumeGate: s.volumeGate === true,\n // Copy: the snapshot must not hand callers a mutable reference into the store.\n wifi: {...s.wifi},\n }\n}\n\nexport type GlassesStatusSnapshot = ReturnType<typeof projectStatus>\nexport type ControllerStatusSnapshot = ReturnType<typeof projectControllerStatus>\nexport type KeyboardStatusSnapshot = ReturnType<typeof projectKeyboardStatus>\nexport type GlassesInfoSnapshot = ReturnType<typeof projectInfo>\n\nexport const glasses = {\n // --- connection (bluetooth-sdk passthrough) ---\n /**\n * Reconnect the default wearable. Seeds the phone's current device settings to\n * native first, so they're primed before the connect handshake replays them to\n * the glasses (this used to be a host-side step before `connectDefault`).\n */\n connectDefault: async (): Promise<void> => {\n try {\n await pushAllBluetoothSettings()\n await BluetoothSdk.connectDefault()\n } catch (error) {\n recordSupportProfileConnectionFailure(error, \"connect_default\")\n throw error\n }\n },\n disconnect: (): Promise<void> => BluetoothSdk.disconnect(),\n forget: (): Promise<void> => BluetoothSdk.forget(),\n /** Connect to a specific (discovered) device. */\n connect: async (device: Device, options?: ConnectOptions): Promise<void> => {\n try {\n await pushAllBluetoothSettings()\n await BluetoothSdk.connect(device, options)\n } catch (error) {\n recordSupportProfileConnectionFailure(error, \"connect\")\n throw error\n }\n },\n /** Connect the built-in simulated glasses (dev/testing). */\n connectSimulated: (): Promise<void> => BluetoothSdk.connectSimulated(),\n /** Set a device as the `connectDefault()` target. */\n setDefault: (device: Device | null): Promise<void> => BluetoothSdk.setDefaultDevice(device),\n /**\n * Reconnect to the saved default glasses. Resolves `false` when there's nothing to\n * reconnect to (no default paired) or the connect attempt fails (e.g. BLE powered\n * off), `true` when already connected or after kicking off the connect. Never\n * rejects — the boolean contract holds. The host gates connectivity/permissions\n * (its UI) before calling.\n */\n reconnect: async (): Promise<boolean> => {\n const defaultWearable = useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key)\n if (!defaultWearable) return false\n if (isGlassesConnected(useGlassesStore.getState().connection)) return true\n try {\n await pushAllBluetoothSettings()\n await BluetoothSdk.connectDefault()\n } catch (error) {\n recordSupportProfileConnectionFailure(error, \"reconnect\")\n console.warn(\"engine.glasses.reconnect failed:\", error)\n return false\n }\n return true\n },\n /** True when no glasses has ever been paired NOR selected (the pairing-identity\n * lifecycle is in its `none` state) — e.g. to route a first-run host into the\n * pairing/onboarding flow. A pending selection is not \"first\" — the host should\n * offer finish-pairing (see `engine.pairing.identity()`). */\n isFirstPairing: (): boolean => projectPairingIdentity().kind === \"none\",\n /**\n * True when the SDK has an actual default DEVICE to reconnect to. Distinct from\n * `default_wearable` (a model string that a pending or orphaned selection can\n * hold without any paired device): connectDefault() throws without a device, so\n * hosts should route to the pairing flow when this is false.\n *\n * Hydration-aware: awaits the device-store seed internally, so a cold-start\n * read can't see a false \"absent\" for genuinely-paired users. Rejects if\n * hydration failed — callers guarding destructive or routing decisions must\n * fail open (treat as \"has a device\").\n */\n hasDefaultDevice: (): Promise<boolean> => hasDefaultDevice(),\n\n // --- read-model (projected from the engine-owned glasses store) ---\n status: (): GlassesStatusSnapshot => projectStatus(),\n onStatus: (cb: (status: GlassesStatusSnapshot) => void): (() => void) => {\n // Dedupe: the glasses store updates on many fields; only fire when the\n // projected status snapshot actually changes.\n let last = JSON.stringify(projectStatus())\n return useGlassesStore.subscribe(() => {\n const snap = projectStatus()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n info: (): GlassesInfoSnapshot => projectInfo(),\n onInfo: (cb: (info: GlassesInfoSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectInfo())\n return useGlassesStore.subscribe(() => {\n const snap = projectInfo()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n capabilities: () => getModelCapabilities(useGlassesStore.getState().deviceModel as DeviceTypes),\n /** Ask the glasses to report fresh firmware/version info (updates the store). */\n requestVersionInfo: () => BluetoothSdk.requestVersionInfo(),\n\n // --- discrete input events (passthrough listeners) ---\n onButtonPress: (cb: (event: ButtonPressEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"button_press\", cb)\n return () => sub.remove()\n },\n onTouchGesture: (cb: (event: TouchEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"touch_event\", cb)\n return () => sub.remove()\n },\n\n // --- BLE keyboard bridged through G2 Glassly CFW (revision 39+) ---\n keyboard: {\n /** Five-second scan; distinct advertisers, HID ones flagged. Also streams via onAdvert. */\n scan: (): Promise<KeyboardAdvertEvent[]> => BluetoothSdk.g2KeyboardScan(),\n /** Connect, pair and subscribe; the keyboard is remembered and auto-reconnected. */\n connect: async (device: {address: string; addressType: number; name: string}): Promise<void> => {\n await BluetoothSdk.g2KeyboardConnect(device.address, device.addressType, device.name)\n useSettingsStore.getState().setSetting(SETTINGS.keyboard_name.key, device.name)\n },\n reconnect: (): Promise<void> => BluetoothSdk.g2KeyboardReconnect(),\n disconnect: (): Promise<void> => BluetoothSdk.g2KeyboardDisconnect(),\n forget: async (): Promise<void> => {\n await BluetoothSdk.g2KeyboardForget()\n useSettingsStore.getState().setSetting(SETTINGS.keyboard_name.key, \"\")\n },\n passkey: (pin: number): Promise<void> => BluetoothSdk.g2KeyboardPasskey(pin),\n compare: (accept: boolean): Promise<void> => BluetoothSdk.g2KeyboardCompare(accept),\n status: (): KeyboardStatusSnapshot => projectKeyboardStatus(),\n onStatus: (cb: (status: KeyboardStatusSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectKeyboardStatus())\n return useGlassesStore.subscribe(() => {\n const snap = projectKeyboardStatus()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n onAdvert: (cb: (advert: KeyboardAdvertEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"keyboard_advert\", cb)\n return () => sub.remove()\n },\n onPairing: (cb: (prompt: KeyboardPairingEvent) => void): (() => void) => {\n const sub = BluetoothSdk.addListener(\"keyboard_pairing\", cb)\n return () => sub.remove()\n },\n },\n\n // --- ring controller (optional input device) ---\n controller: {\n connectDefault: (): Promise<void> => BluetoothSdk.connectDefaultController(),\n disconnect: (): Promise<void> => BluetoothSdk.disconnectController(),\n forget: (): Promise<void> => BluetoothSdk.forgetController(),\n status: (): ControllerStatusSnapshot => projectControllerStatus(),\n onStatus: (cb: (status: ControllerStatusSnapshot) => void): (() => void) => {\n let last = JSON.stringify(projectControllerStatus())\n return useGlassesStore.subscribe(() => {\n const snap = projectControllerStatus()\n const key = JSON.stringify(snap)\n if (key === last) return\n last = key\n cb(snap)\n })\n },\n },\n\n // --- Meta Neural Band (a controller with a claim step and its own features) ---\n neuralBand: {\n /** Store the Meta account session the one-time band claim uses. */\n setMetaSession: (accessToken: string, userId: string): Promise<void> =>\n BluetoothSdk.neuralBandSetMetaSession(accessToken, userId),\n clearMetaSession: (): Promise<void> => BluetoothSdk.neuralBandClearMetaSession(),\n hasMetaSession: (): Promise<boolean> => BluetoothSdk.neuralBandHasMetaSession(),\n /** A band identity is stored on this phone, so the remembered band connects without a claim. */\n isClaimed: (): Promise<boolean> => BluetoothSdk.neuralBandIsClaimed(),\n /** The latest claim progress, kept across screens. */\n claimStatus: (): NeuralBandClaimStatus => neuralBandInput.claimStatus(),\n resetClaim: (): void => neuralBandInput.resetClaim(),\n onClaimStatus: (cb: (status: NeuralBandClaimStatus) => void): (() => void) => neuralBandInput.onClaimStatus(cb),\n /** The band's handwriting model; writing arrives on the miniapp keyboard stream. */\n setHandwriting: (enabled: boolean): Promise<void> => BluetoothSdk.neuralBandSetHandwriting(enabled),\n handwritingStatus: (): NeuralBandHandwritingStatus => neuralBandInput.handwritingStatus(),\n onHandwritingStatus: (cb: (status: NeuralBandHandwritingStatus) => void): (() => void) =>\n neuralBandInput.onHandwritingStatus(cb),\n /** The band's air mouse; movement reaches miniapps on the pointer stream. */\n setPointer: (enabled: boolean): Promise<void> => BluetoothSdk.neuralBandSetPointer(enabled),\n setHand: (hand: \"left\" | \"right\"): Promise<void> => BluetoothSdk.neuralBandSetHand(hand),\n },\n\n // --- audio (glasses media-volume, own-app playback hint, live mic level) ---\n audio: {\n /** Read the glasses' current media volume. */\n getMediaVolume: () => BluetoothSdk.getGlassesMediaVolume(),\n /** Set the glasses' media volume. */\n setMediaVolume: (level: number) => BluetoothSdk.setGlassesMediaVolume(level),\n /** Tell native whether THIS app is currently playing audio (for ducking). */\n setOwnAppPlaying: (playing: boolean): Promise<void> => BluetoothSdk.setOwnAppAudioPlaying(playing),\n /**\n * Stream the active mic's level in dBFS, one reading per PCM chunk. Holds\n * raw PCM open while subscribed, so the mic runs with no miniapp listening\n * (and the G2 volume gate stays open).\n */\n onMicLevel: (cb: (dbfs: number) => void): (() => void) => {\n const owner = `mic_level_${++micLevelSubscriptions}`\n micStateCoordinator.acquireHostPcm(owner)\n const sub = BluetoothSdk.addListener(\"mic_pcm\", (event: {pcm: ArrayBuffer}) => {\n if (event?.pcm) cb(pcmLevelDbfs(event.pcm))\n })\n return () => {\n sub.remove()\n micStateCoordinator.releaseHostPcm(owner)\n }\n },\n },\n\n // --- sub-facades ---\n wifi: glassesWifi,\n settings: glassesSettings,\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export const ENGINE_RELEASE_METADATA = Object.freeze({
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"familyBaseVersion": "0.3.3",
|
|
4
|
-
"releaseIdentity": "0.3.3-beta.
|
|
5
|
-
"releaseSetId": "glassly-0.3.3-beta.
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"releaseIdentity": "0.3.3-beta.639",
|
|
5
|
+
"releaseSetId": "glassly-0.3.3-beta.639",
|
|
6
|
+
"sourceCommit": "2f573069edc77578d99369a6893567135b6e4673",
|
|
7
7
|
"otaManifestUrl": null,
|
|
8
8
|
"otaManifestSha256": null
|
|
9
9
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,gBAAgB;IACnC,cAAc,EAAE,wBAAwB;IACxC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.3\",\n \"releaseIdentity\": \"0.3.3-beta.
|
|
1
|
+
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,gBAAgB;IACnC,cAAc,EAAE,wBAAwB;IACxC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CAC1B,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"0.3.3\",\n \"releaseIdentity\": \"0.3.3-beta.639\",\n \"releaseSetId\": \"glassly-0.3.3-beta.639\",\n \"sourceCommit\": \"2f573069edc77578d99369a6893567135b6e4673\",\n \"otaManifestUrl\": null,\n \"otaManifestSha256\": null\n})\n"]}
|
|
@@ -16,6 +16,7 @@ declare class MicStateCoordinator {
|
|
|
16
16
|
private static instance;
|
|
17
17
|
private localWantsPcm;
|
|
18
18
|
private localWantsLc3;
|
|
19
|
+
private readonly hostPcmOwners;
|
|
19
20
|
private configuredVad;
|
|
20
21
|
private configuredLoudnessGate;
|
|
21
22
|
private readonly miniappVadOverrides;
|
|
@@ -31,6 +32,12 @@ declare class MicStateCoordinator {
|
|
|
31
32
|
pcm: boolean;
|
|
32
33
|
lc3: boolean;
|
|
33
34
|
} & ConfiguredMicGates): void;
|
|
35
|
+
/**
|
|
36
|
+
* Hold raw PCM open for a host-side consumer, independent of miniapp
|
|
37
|
+
* subscriptions. Release with `releaseHostPcm` using the same owner.
|
|
38
|
+
*/
|
|
39
|
+
acquireHostPcm(owner: string): void;
|
|
40
|
+
releaseHostPcm(owner: string): void;
|
|
34
41
|
/**
|
|
35
42
|
* Apply a miniapp-owned gate override without changing the OS preference.
|
|
36
43
|
* Overrides are lifecycle-scoped and last-live-owner-wins independently for
|
|
@@ -63,6 +70,7 @@ declare class MicStateCoordinator {
|
|
|
63
70
|
* on-device PCM consumers; cloud audio uses LC3 through AudioCloudUplink.
|
|
64
71
|
*/
|
|
65
72
|
private applyUnion;
|
|
73
|
+
private wantsPcm;
|
|
66
74
|
private rememberConfiguredGates;
|
|
67
75
|
private overridesFor;
|
|
68
76
|
private latestOverride;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MicStateCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/MicStateCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,KAAK,OAAO,GAAG,KAAK,GAAG,cAAc,CAAA;AAOrC,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IAC3B,mBAAmB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CACrC;AAkBD,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmC;IAG1D,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,aAAa,CAAQ;
|
|
1
|
+
{"version":3,"file":"MicStateCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/MicStateCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,KAAK,OAAO,GAAG,KAAK,GAAG,cAAc,CAAA;AAOrC,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IAC3B,mBAAmB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CACrC;AAkBD,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmC;IAG1D,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,sBAAsB,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkC;IACtE,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAkC;IAC/E,OAAO,CAAC,gBAAgB,CAAI;IAE5B,OAAO;WAEO,WAAW,IAAI,mBAAmB;IAOhD;;;OAGG;IACI,oBAAoB,CAAC,GAAG,EAAE;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAC,GAAG,kBAAkB,GAAG,IAAI;IAQzF;;;OAGG;IACI,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMnC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1C;;;;OAIG;IACU,sBAAsB,CACjC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,OAAO,EAChB,UAAU,GAAE,kBAAuB,GAClC,OAAO,CAAC,IAAI,CAAC;IAoBhB;;;OAGG;IACI,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAM9D,sEAAsE;IACzD,uBAAuB,CAAC,UAAU,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxF;;;;;OAKG;IACI,qBAAqB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAaxF;;;;OAIG;IACI,wBAAwB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAO3F,OAAO,CAAC,2BAA2B;IAiBnC;;;OAGG;IACH,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,kBAAkB;IAmB1B;;OAEG;IACI,KAAK,IAAI,IAAI;IAMb,OAAO,IAAI,IAAI;CAQvB;AAED,QAAA,MAAM,mBAAmB,qBAAoC,CAAA;AAC7D,eAAe,mBAAmB,CAAA"}
|
|
@@ -31,6 +31,8 @@ class MicStateCoordinator {
|
|
|
31
31
|
// Local miniapp requirements (set when miniapps subscribe to audio streams)
|
|
32
32
|
localWantsPcm = false;
|
|
33
33
|
localWantsLc3 = false;
|
|
34
|
+
// Host screens that read raw PCM themselves (e.g. the Microphone settings level meter)
|
|
35
|
+
hostPcmOwners = new Set();
|
|
34
36
|
configuredVad;
|
|
35
37
|
configuredLoudnessGate;
|
|
36
38
|
miniappVadOverrides = new Map();
|
|
@@ -54,6 +56,21 @@ class MicStateCoordinator {
|
|
|
54
56
|
console.log(`${LOG_TAG}: local requirements updated — pcm=${req.pcm} lc3=${req.lc3}`);
|
|
55
57
|
this.applyUnion();
|
|
56
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Hold raw PCM open for a host-side consumer, independent of miniapp
|
|
61
|
+
* subscriptions. Release with `releaseHostPcm` using the same owner.
|
|
62
|
+
*/
|
|
63
|
+
acquireHostPcm(owner) {
|
|
64
|
+
if (this.hostPcmOwners.has(owner))
|
|
65
|
+
return;
|
|
66
|
+
this.hostPcmOwners.add(owner);
|
|
67
|
+
this.applyUnion();
|
|
68
|
+
}
|
|
69
|
+
releaseHostPcm(owner) {
|
|
70
|
+
if (!this.hostPcmOwners.delete(owner))
|
|
71
|
+
return;
|
|
72
|
+
this.applyUnion();
|
|
73
|
+
}
|
|
57
74
|
/**
|
|
58
75
|
* Apply a miniapp-owned gate override without changing the OS preference.
|
|
59
76
|
* Overrides are lifecycle-scoped and last-live-owner-wins independently for
|
|
@@ -127,7 +144,7 @@ class MicStateCoordinator {
|
|
|
127
144
|
const runtimeSettings = { ...settings };
|
|
128
145
|
const vadOverride = this.latestOverride(this.miniappVadOverrides);
|
|
129
146
|
const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides);
|
|
130
|
-
if (this.
|
|
147
|
+
if (this.wantsPcm()) {
|
|
131
148
|
runtimeSettings.voice_activity_detection_enabled = false;
|
|
132
149
|
}
|
|
133
150
|
else if (vadOverride) {
|
|
@@ -143,7 +160,7 @@ class MicStateCoordinator {
|
|
|
143
160
|
* on-device PCM consumers; cloud audio uses LC3 through AudioCloudUplink.
|
|
144
161
|
*/
|
|
145
162
|
applyUnion() {
|
|
146
|
-
const shouldSendPcm = this.
|
|
163
|
+
const shouldSendPcm = this.wantsPcm();
|
|
147
164
|
const shouldSendLc3 = this.localWantsLc3;
|
|
148
165
|
// console.log(
|
|
149
166
|
// `${LOG_TAG}: applying requirements — pcm=${shouldSendPcm} lc3=${shouldSendLc3}`,
|
|
@@ -158,6 +175,9 @@ class MicStateCoordinator {
|
|
|
158
175
|
};
|
|
159
176
|
flushMicRequirementsPatch(patch);
|
|
160
177
|
}
|
|
178
|
+
wantsPcm() {
|
|
179
|
+
return this.localWantsPcm || this.hostPcmOwners.size > 0;
|
|
180
|
+
}
|
|
161
181
|
rememberConfiguredGates(configured) {
|
|
162
182
|
// null means the connected device intentionally omits that setting.
|
|
163
183
|
// undefined means the caller is not updating the remembered preference.
|
|
@@ -185,7 +205,7 @@ class MicStateCoordinator {
|
|
|
185
205
|
const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides);
|
|
186
206
|
// Hardware VAD suppresses silence. Raw-audio consumers need a continuous
|
|
187
207
|
// timeline, so their requirement wins over both OS and miniapp VAD values.
|
|
188
|
-
if (this.
|
|
208
|
+
if (this.wantsPcm())
|
|
189
209
|
patch.voice_activity_detection_enabled = false;
|
|
190
210
|
else if (vadOverride)
|
|
191
211
|
patch.voice_activity_detection_enabled = vadOverride.enabled;
|
|
@@ -210,6 +230,7 @@ class MicStateCoordinator {
|
|
|
210
230
|
console.log(`${LOG_TAG}: cleanup()`);
|
|
211
231
|
this.miniappVadOverrides.clear();
|
|
212
232
|
this.miniappLoudnessGateOverrides.clear();
|
|
233
|
+
this.hostPcmOwners.clear();
|
|
213
234
|
this.reset();
|
|
214
235
|
MicStateCoordinator.instance = null;
|
|
215
236
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MicStateCoordinator.js","sourceRoot":"","sources":["../../src/services/MicStateCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,YAAY,MAAM,iCAAiC,CAAA;AAE1D,OAAO,EAAC,2BAA2B,EAAC,MAAM,yBAAyB,CAAA;AAEnE,MAAM,OAAO,GAAG,iBAAiB,CAAA;AAcjC;qDACqD;AACrD,MAAM,yBAAyB,GAAG,2BAA2B,CAA0B,CAAC,KAAK,EAAE,EAAE;IAC/F,IAAI,CAAC;QACH,2EAA2E;QAC3E,uEAAuE;QACvE,gDAAgD;QAChD,MAAM,YAAY,GAAG,mBAAmB,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAA;QACxE,KAAK,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACrF,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,qCAAqC,EAAE,GAAG,CAAC,CAAA;QACrE,CAAC,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,qCAAqC,EAAE,GAAG,CAAC,CAAA;IACrE,CAAC;AACH,CAAC,EAAE,GAAG,CAAC,CAAA;AAEP,MAAM,mBAAmB;IACf,MAAM,CAAC,QAAQ,GAA+B,IAAI,CAAA;IAE1D,4EAA4E;IACpE,aAAa,GAAG,KAAK,CAAA;IACrB,aAAa,GAAG,KAAK,CAAA;IACrB,aAAa,CAAqB;IAClC,sBAAsB,CAAqB;IAClC,mBAAmB,GAAG,IAAI,GAAG,EAAwB,CAAA;IACrD,4BAA4B,GAAG,IAAI,GAAG,EAAwB,CAAA;IACvE,gBAAgB,GAAG,CAAC,CAAA;IAE5B,gBAAuB,CAAC;IAEjB,MAAM,CAAC,WAAW;QACvB,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC;YAClC,mBAAmB,CAAC,QAAQ,GAAG,IAAI,mBAAmB,EAAE,CAAA;QAC1D,CAAC;QACD,OAAO,mBAAmB,CAAC,QAAQ,CAAA;IACrC,CAAC;IAED;;;OAGG;IACI,oBAAoB,CAAC,GAAsD;QAChF,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,GAAG,CAAA;QAC5B,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,GAAG,CAAA;QAC5B,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAA;QACjC,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,sCAAsC,GAAG,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,EAAE,CAAC,CAAA;QACrF,IAAI,CAAC,UAAU,EAAE,CAAA;IACnB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,sBAAsB,CACjC,WAAmB,EACnB,IAAa,EACb,OAAgB,EAChB,aAAiC,EAAE;QAEnC,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAA;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QACzC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAC3C,MAAM,IAAI,GAAG,EAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC,gBAAgB,EAAC,CAAA;QACtD,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QAEhC,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,uBAAuB,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAA;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,qEAAqE;YACrE,yCAAyC;YACzC,IAAI,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC;gBACxC,IAAI,QAAQ;oBAAE,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;;oBAC7C,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;YACpC,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,yBAAyB,CAAC,WAAmB;QAClD,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QAC/D,MAAM,eAAe,GAAG,IAAI,CAAC,4BAA4B,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QAC7E,OAAO,UAAU,IAAI,eAAe,CAAA;IACtC,CAAC;IAED,sEAAsE;IAC/D,KAAK,CAAC,uBAAuB,CAAC,aAAiC,EAAE;QACtE,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAA;QACvC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAC3C,MAAM,YAAY,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAA;IACnD,CAAC;IAED;;;;;OAKG;IACI,qBAAqB,CAAC,QAAiC;QAC5D,IAAI,CAAC,uBAAuB,CAAC;YAC3B,UAAU,EACR,OAAO,QAAQ,CAAC,gCAAgC,KAAK,SAAS;gBAC5D,CAAC,CAAC,QAAQ,CAAC,gCAAgC;gBAC3C,CAAC,CAAC,SAAS;YACf,mBAAmB,EACjB,OAAO,QAAQ,CAAC,qBAAqB,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS;SACnG,CAAC,CAAA;QAEF,OAAO,IAAI,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAA;IACnD,CAAC;IAED;;;;OAIG;IACI,wBAAwB,CAAC,QAAiC;QAC/D,OAAO;YACL,GAAG,QAAQ;YACX,GAAG,IAAI,CAAC,kBAAkB,EAAE;SAC7B,CAAA;IACH,CAAC;IAEO,2BAA2B,CAAC,QAAiC;QACnE,MAAM,eAAe,GAAG,EAAC,GAAG,QAAQ,EAAC,CAAA;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACjE,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;QAE/E,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,eAAe,CAAC,gCAAgC,GAAG,KAAK,CAAA;QAC1D,CAAC;aAAM,IAAI,WAAW,EAAE,CAAC;YACvB,eAAe,CAAC,gCAAgC,GAAG,WAAW,CAAC,OAAO,CAAA;QACxE,CAAC;QACD,IAAI,gBAAgB,EAAE,CAAC;YACrB,eAAe,CAAC,qBAAqB,GAAG,gBAAgB,CAAC,OAAO,CAAA;QAClE,CAAC;QAED,OAAO,eAAe,CAAA;IACxB,CAAC;IAED;;;OAGG;IACK,UAAU;QAChB,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAA;QACxC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAA;QAExC,eAAe;QACf,qFAAqF;QACrF,IAAI;QAEJ,kFAAkF;QAClF,uDAAuD;QACvD,MAAM,KAAK,GAA4B;YACrC,eAAe,EAAE,aAAa;YAC9B,eAAe,EAAE,aAAa;YAC9B,sBAAsB,EAAE,KAAK;YAC7B,GAAG,IAAI,CAAC,kBAAkB,EAAE;SAC7B,CAAA;QAED,yBAAyB,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC;IAEO,uBAAuB,CAAC,UAA8B;QAC5D,oEAAoE;QACpE,wEAAwE;QACxE,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACxC,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,UAAU,IAAI,SAAS,CAAA;QACzD,CAAC;QACD,IAAI,UAAU,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;YACjD,IAAI,CAAC,sBAAsB,GAAG,UAAU,CAAC,mBAAmB,IAAI,SAAS,CAAA;QAC3E,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,IAAa;QAChC,OAAO,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAA;IACtF,CAAC;IAEO,cAAc,CAAC,SAAoC;QACzD,IAAI,MAAgC,CAAA;QACpC,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK;gBAAE,MAAM,GAAG,KAAK,CAAA;QAC3D,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAEO,kBAAkB;QACxB,MAAM,KAAK,GAA4B,EAAE,CAAA;QACzC,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACjE,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;QAE/E,yEAAyE;QACzE,2EAA2E;QAC3E,IAAI,IAAI,CAAC,aAAa;YAAE,KAAK,CAAC,gCAAgC,GAAG,KAAK,CAAA;aACjE,IAAI,WAAW;YAAE,KAAK,CAAC,gCAAgC,GAAG,WAAW,CAAC,OAAO,CAAA;aAC7E,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS;YAAE,KAAK,CAAC,gCAAgC,GAAG,IAAI,CAAC,aAAa,CAAA;QAEtG,IAAI,gBAAgB;YAAE,KAAK,CAAC,qBAAqB,GAAG,gBAAgB,CAAC,OAAO,CAAA;aACvE,IAAI,IAAI,CAAC,sBAAsB,KAAK,SAAS,EAAE,CAAC;YACnD,KAAK,CAAC,qBAAqB,GAAG,IAAI,CAAC,sBAAsB,CAAA;QAC3D,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;OAEG;IACI,KAAK;QACV,IAAI,CAAC,aAAa,GAAG,KAAK,CAAA;QAC1B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAA;QAC1B,IAAI,CAAC,UAAU,EAAE,CAAA;IACnB,CAAC;IAEM,OAAO;QACZ,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,aAAa,CAAC,CAAA;QACpC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAA;QAChC,IAAI,CAAC,4BAA4B,CAAC,KAAK,EAAE,CAAA;QACzC,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,mBAAmB,CAAC,QAAQ,GAAG,IAAI,CAAA;IACrC,CAAC;;AAGH,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,WAAW,EAAE,CAAA;AAC7D,eAAe,mBAAmB,CAAA","sourcesContent":["/**\n * MicStateCoordinator\n *\n * Owns local-miniapp-driven microphone requirements.\n *\n * Local miniapps subscribe to audio_chunk / transcription streams.\n * This coordinator pushes the aggregate local requirement set to BluetoothSdk\n * so the mic runs whenever at least one local consumer needs it.\n */\n\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\n\nimport {createDebouncedPatchFlusher} from \"../utils/debouncedPatch\"\n\nconst LOG_TAG = \"MIC_COORDINATOR\"\n\ntype MicGate = \"vad\" | \"loudnessGate\"\n\ninterface GateOverride {\n enabled: boolean\n order: number\n}\n\ninterface ConfiguredMicGates {\n vadEnabled?: boolean | null\n loudnessGateEnabled?: boolean | null\n}\n\n/** Mic-requirement flips are debounced (300ms) and merged into one BLE write\n * (wire v2 keeps BLE JSON small and infrequent). */\nconst flushMicRequirementsPatch = createDebouncedPatchFlusher<Record<string, unknown>>((patch) => {\n try {\n // Resolve runtime overrides at flush time. A miniapp can acquire/release a\n // gate override during the debounce window, and a captured stale value\n // must not win after that lifecycle transition.\n const runtimePatch = micStateCoordinator.applyEffectiveGatePolicy(patch)\n void Promise.resolve(BluetoothSdk.updateBluetoothSettings(runtimePatch)).catch((err) => {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n })\n } catch (err) {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n }\n}, 300)\n\nclass MicStateCoordinator {\n private static instance: MicStateCoordinator | null = null\n\n // Local miniapp requirements (set when miniapps subscribe to audio streams)\n private localWantsPcm = false\n private localWantsLc3 = false\n private configuredVad: boolean | undefined\n private configuredLoudnessGate: boolean | undefined\n private readonly miniappVadOverrides = new Map<string, GateOverride>()\n private readonly miniappLoudnessGateOverrides = new Map<string, GateOverride>()\n private overrideSequence = 0\n\n private constructor() {}\n\n public static getInstance(): MicStateCoordinator {\n if (!MicStateCoordinator.instance) {\n MicStateCoordinator.instance = new MicStateCoordinator()\n }\n return MicStateCoordinator.instance\n }\n\n /**\n * Update local miniapp requirements. Called by LocalMiniappRuntime when\n * the aggregated set of local subscriptions changes.\n */\n public setLocalRequirements(req: {pcm: boolean; lc3: boolean} & ConfiguredMicGates): void {\n this.localWantsPcm = req.pcm\n this.localWantsLc3 = req.lc3\n this.rememberConfiguredGates(req)\n console.log(`${LOG_TAG}: local requirements updated — pcm=${req.pcm} lc3=${req.lc3}`)\n this.applyUnion()\n }\n\n /**\n * Apply a miniapp-owned gate override without changing the OS preference.\n * Overrides are lifecycle-scoped and last-live-owner-wins independently for\n * VAD and Barrier.\n */\n public async setMiniappGateOverride(\n packageName: string,\n gate: MicGate,\n enabled: boolean,\n configured: ConfiguredMicGates = {},\n ): Promise<void> {\n this.rememberConfiguredGates(configured)\n const overrides = this.overridesFor(gate)\n const previous = overrides.get(packageName)\n const next = {enabled, order: ++this.overrideSequence}\n overrides.set(packageName, next)\n\n try {\n await BluetoothSdk.updateBluetoothSettings(this.effectiveGatePatch())\n } catch (error) {\n // Do not roll back a newer request from the same package that landed\n // while this native write was in flight.\n if (overrides.get(packageName) === next) {\n if (previous) overrides.set(packageName, previous)\n else overrides.delete(packageName)\n }\n throw error\n }\n }\n\n /**\n * Remove every gate override owned by a miniapp. This is synchronous so\n * unregister can drop ownership before recomputing aggregate mic state.\n */\n public clearMiniappGateOverrides(packageName: string): boolean {\n const removedVad = this.miniappVadOverrides.delete(packageName)\n const removedLoudness = this.miniappLoudnessGateOverrides.delete(packageName)\n return removedVad || removedLoudness\n }\n\n /** Re-apply the current runtime policy after an owner is released. */\n public async syncEffectiveGatePolicy(configured: ConfiguredMicGates = {}): Promise<void> {\n this.rememberConfiguredGates(configured)\n const patch = this.effectiveGatePatch()\n if (Object.keys(patch).length === 0) return\n await BluetoothSdk.updateBluetoothSettings(patch)\n }\n\n /**\n * Preserve the runtime microphone contract when the persisted device\n * settings are replayed (for example after a glasses reconnect). Active\n * miniapp gate overrides replace the OS values, and raw PCM keeps VAD off\n * until the last raw-audio consumer unsubscribes.\n */\n public applyRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n this.rememberConfiguredGates({\n vadEnabled:\n typeof settings.voice_activity_detection_enabled === \"boolean\"\n ? settings.voice_activity_detection_enabled\n : undefined,\n loudnessGateEnabled:\n typeof settings.loudness_gate_enabled === \"boolean\" ? settings.loudness_gate_enabled : undefined,\n })\n\n return this.applyActiveRuntimeOverrides(settings)\n }\n\n /**\n * Apply the complete current gate policy without treating the input as an OS\n * preference update. Used by debounced mic-requirement writes, whose queued\n * gate values may be stale after an override is acquired or released.\n */\n public applyEffectiveGatePolicy(settings: Record<string, unknown>): Record<string, unknown> {\n return {\n ...settings,\n ...this.effectiveGatePatch(),\n }\n }\n\n private applyActiveRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n const runtimeSettings = {...settings}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n if (this.localWantsPcm) {\n runtimeSettings.voice_activity_detection_enabled = false\n } else if (vadOverride) {\n runtimeSettings.voice_activity_detection_enabled = vadOverride.enabled\n }\n if (loudnessOverride) {\n runtimeSettings.loudness_gate_enabled = loudnessOverride.enabled\n }\n\n return runtimeSettings\n }\n\n /**\n * Push local requirements to BluetoothSdk. `should_send_pcm` is strictly for\n * on-device PCM consumers; cloud audio uses LC3 through AudioCloudUplink.\n */\n private applyUnion(): void {\n const shouldSendPcm = this.localWantsPcm\n const shouldSendLc3 = this.localWantsLc3\n\n // console.log(\n // `${LOG_TAG}: applying requirements — pcm=${shouldSendPcm} lc3=${shouldSendLc3}`,\n // )\n\n // The mic control plane is a direct btsdk call now (was a host setMicRequirements\n // hook) so a bare OEM streams audio without wiring it.\n const patch: Record<string, unknown> = {\n should_send_pcm: shouldSendPcm,\n should_send_lc3: shouldSendLc3,\n should_send_transcript: false,\n ...this.effectiveGatePatch(),\n }\n\n flushMicRequirementsPatch(patch)\n }\n\n private rememberConfiguredGates(configured: ConfiguredMicGates): void {\n // null means the connected device intentionally omits that setting.\n // undefined means the caller is not updating the remembered preference.\n if (configured.vadEnabled !== undefined) {\n this.configuredVad = configured.vadEnabled ?? undefined\n }\n if (configured.loudnessGateEnabled !== undefined) {\n this.configuredLoudnessGate = configured.loudnessGateEnabled ?? undefined\n }\n }\n\n private overridesFor(gate: MicGate): Map<string, GateOverride> {\n return gate === \"vad\" ? this.miniappVadOverrides : this.miniappLoudnessGateOverrides\n }\n\n private latestOverride(overrides: Map<string, GateOverride>): GateOverride | undefined {\n let latest: GateOverride | undefined\n for (const entry of overrides.values()) {\n if (!latest || entry.order > latest.order) latest = entry\n }\n return latest\n }\n\n private effectiveGatePatch(): Record<string, unknown> {\n const patch: Record<string, unknown> = {}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n // Hardware VAD suppresses silence. Raw-audio consumers need a continuous\n // timeline, so their requirement wins over both OS and miniapp VAD values.\n if (this.localWantsPcm) patch.voice_activity_detection_enabled = false\n else if (vadOverride) patch.voice_activity_detection_enabled = vadOverride.enabled\n else if (this.configuredVad !== undefined) patch.voice_activity_detection_enabled = this.configuredVad\n\n if (loudnessOverride) patch.loudness_gate_enabled = loudnessOverride.enabled\n else if (this.configuredLoudnessGate !== undefined) {\n patch.loudness_gate_enabled = this.configuredLoudnessGate\n }\n\n return patch\n }\n\n /**\n * Reset all requirements to off. Called during cleanup.\n */\n public reset(): void {\n this.localWantsPcm = false\n this.localWantsLc3 = false\n this.applyUnion()\n }\n\n public cleanup(): void {\n console.log(`${LOG_TAG}: cleanup()`)\n this.miniappVadOverrides.clear()\n this.miniappLoudnessGateOverrides.clear()\n this.reset()\n MicStateCoordinator.instance = null\n }\n}\n\nconst micStateCoordinator = MicStateCoordinator.getInstance()\nexport default micStateCoordinator\n"]}
|
|
1
|
+
{"version":3,"file":"MicStateCoordinator.js","sourceRoot":"","sources":["../../src/services/MicStateCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MicStateCoordinator\n *\n * Owns local-miniapp-driven microphone requirements.\n *\n * Local miniapps subscribe to audio_chunk / transcription streams.\n * This coordinator pushes the aggregate local requirement set to BluetoothSdk\n * so the mic runs whenever at least one local consumer needs it.\n */\n\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\n\nimport {createDebouncedPatchFlusher} from \"../utils/debouncedPatch\"\n\nconst LOG_TAG = \"MIC_COORDINATOR\"\n\ntype MicGate = \"vad\" | \"loudnessGate\"\n\ninterface GateOverride {\n enabled: boolean\n order: number\n}\n\ninterface ConfiguredMicGates {\n vadEnabled?: boolean | null\n loudnessGateEnabled?: boolean | null\n}\n\n/** Mic-requirement flips are debounced (300ms) and merged into one BLE write\n * (wire v2 keeps BLE JSON small and infrequent). */\nconst flushMicRequirementsPatch = createDebouncedPatchFlusher<Record<string, unknown>>((patch) => {\n try {\n // Resolve runtime overrides at flush time. A miniapp can acquire/release a\n // gate override during the debounce window, and a captured stale value\n // must not win after that lifecycle transition.\n const runtimePatch = micStateCoordinator.applyEffectiveGatePolicy(patch)\n void Promise.resolve(BluetoothSdk.updateBluetoothSettings(runtimePatch)).catch((err) => {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n })\n } catch (err) {\n console.error(`${LOG_TAG}: failed to apply mic requirements:`, err)\n }\n}, 300)\n\nclass MicStateCoordinator {\n private static instance: MicStateCoordinator | null = null\n\n // Local miniapp requirements (set when miniapps subscribe to audio streams)\n private localWantsPcm = false\n private localWantsLc3 = false\n // Host screens that read raw PCM themselves (e.g. the Microphone settings level meter)\n private readonly hostPcmOwners = new Set<string>()\n private configuredVad: boolean | undefined\n private configuredLoudnessGate: boolean | undefined\n private readonly miniappVadOverrides = new Map<string, GateOverride>()\n private readonly miniappLoudnessGateOverrides = new Map<string, GateOverride>()\n private overrideSequence = 0\n\n private constructor() {}\n\n public static getInstance(): MicStateCoordinator {\n if (!MicStateCoordinator.instance) {\n MicStateCoordinator.instance = new MicStateCoordinator()\n }\n return MicStateCoordinator.instance\n }\n\n /**\n * Update local miniapp requirements. Called by LocalMiniappRuntime when\n * the aggregated set of local subscriptions changes.\n */\n public setLocalRequirements(req: {pcm: boolean; lc3: boolean} & ConfiguredMicGates): void {\n this.localWantsPcm = req.pcm\n this.localWantsLc3 = req.lc3\n this.rememberConfiguredGates(req)\n console.log(`${LOG_TAG}: local requirements updated — pcm=${req.pcm} lc3=${req.lc3}`)\n this.applyUnion()\n }\n\n /**\n * Hold raw PCM open for a host-side consumer, independent of miniapp\n * subscriptions. Release with `releaseHostPcm` using the same owner.\n */\n public acquireHostPcm(owner: string): void {\n if (this.hostPcmOwners.has(owner)) return\n this.hostPcmOwners.add(owner)\n this.applyUnion()\n }\n\n public releaseHostPcm(owner: string): void {\n if (!this.hostPcmOwners.delete(owner)) return\n this.applyUnion()\n }\n\n /**\n * Apply a miniapp-owned gate override without changing the OS preference.\n * Overrides are lifecycle-scoped and last-live-owner-wins independently for\n * VAD and Barrier.\n */\n public async setMiniappGateOverride(\n packageName: string,\n gate: MicGate,\n enabled: boolean,\n configured: ConfiguredMicGates = {},\n ): Promise<void> {\n this.rememberConfiguredGates(configured)\n const overrides = this.overridesFor(gate)\n const previous = overrides.get(packageName)\n const next = {enabled, order: ++this.overrideSequence}\n overrides.set(packageName, next)\n\n try {\n await BluetoothSdk.updateBluetoothSettings(this.effectiveGatePatch())\n } catch (error) {\n // Do not roll back a newer request from the same package that landed\n // while this native write was in flight.\n if (overrides.get(packageName) === next) {\n if (previous) overrides.set(packageName, previous)\n else overrides.delete(packageName)\n }\n throw error\n }\n }\n\n /**\n * Remove every gate override owned by a miniapp. This is synchronous so\n * unregister can drop ownership before recomputing aggregate mic state.\n */\n public clearMiniappGateOverrides(packageName: string): boolean {\n const removedVad = this.miniappVadOverrides.delete(packageName)\n const removedLoudness = this.miniappLoudnessGateOverrides.delete(packageName)\n return removedVad || removedLoudness\n }\n\n /** Re-apply the current runtime policy after an owner is released. */\n public async syncEffectiveGatePolicy(configured: ConfiguredMicGates = {}): Promise<void> {\n this.rememberConfiguredGates(configured)\n const patch = this.effectiveGatePatch()\n if (Object.keys(patch).length === 0) return\n await BluetoothSdk.updateBluetoothSettings(patch)\n }\n\n /**\n * Preserve the runtime microphone contract when the persisted device\n * settings are replayed (for example after a glasses reconnect). Active\n * miniapp gate overrides replace the OS values, and raw PCM keeps VAD off\n * until the last raw-audio consumer unsubscribes.\n */\n public applyRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n this.rememberConfiguredGates({\n vadEnabled:\n typeof settings.voice_activity_detection_enabled === \"boolean\"\n ? settings.voice_activity_detection_enabled\n : undefined,\n loudnessGateEnabled:\n typeof settings.loudness_gate_enabled === \"boolean\" ? settings.loudness_gate_enabled : undefined,\n })\n\n return this.applyActiveRuntimeOverrides(settings)\n }\n\n /**\n * Apply the complete current gate policy without treating the input as an OS\n * preference update. Used by debounced mic-requirement writes, whose queued\n * gate values may be stale after an override is acquired or released.\n */\n public applyEffectiveGatePolicy(settings: Record<string, unknown>): Record<string, unknown> {\n return {\n ...settings,\n ...this.effectiveGatePatch(),\n }\n }\n\n private applyActiveRuntimeOverrides(settings: Record<string, unknown>): Record<string, unknown> {\n const runtimeSettings = {...settings}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n if (this.wantsPcm()) {\n runtimeSettings.voice_activity_detection_enabled = false\n } else if (vadOverride) {\n runtimeSettings.voice_activity_detection_enabled = vadOverride.enabled\n }\n if (loudnessOverride) {\n runtimeSettings.loudness_gate_enabled = loudnessOverride.enabled\n }\n\n return runtimeSettings\n }\n\n /**\n * Push local requirements to BluetoothSdk. `should_send_pcm` is strictly for\n * on-device PCM consumers; cloud audio uses LC3 through AudioCloudUplink.\n */\n private applyUnion(): void {\n const shouldSendPcm = this.wantsPcm()\n const shouldSendLc3 = this.localWantsLc3\n\n // console.log(\n // `${LOG_TAG}: applying requirements — pcm=${shouldSendPcm} lc3=${shouldSendLc3}`,\n // )\n\n // The mic control plane is a direct btsdk call now (was a host setMicRequirements\n // hook) so a bare OEM streams audio without wiring it.\n const patch: Record<string, unknown> = {\n should_send_pcm: shouldSendPcm,\n should_send_lc3: shouldSendLc3,\n should_send_transcript: false,\n ...this.effectiveGatePatch(),\n }\n\n flushMicRequirementsPatch(patch)\n }\n\n private wantsPcm(): boolean {\n return this.localWantsPcm || this.hostPcmOwners.size > 0\n }\n\n private rememberConfiguredGates(configured: ConfiguredMicGates): void {\n // null means the connected device intentionally omits that setting.\n // undefined means the caller is not updating the remembered preference.\n if (configured.vadEnabled !== undefined) {\n this.configuredVad = configured.vadEnabled ?? undefined\n }\n if (configured.loudnessGateEnabled !== undefined) {\n this.configuredLoudnessGate = configured.loudnessGateEnabled ?? undefined\n }\n }\n\n private overridesFor(gate: MicGate): Map<string, GateOverride> {\n return gate === \"vad\" ? this.miniappVadOverrides : this.miniappLoudnessGateOverrides\n }\n\n private latestOverride(overrides: Map<string, GateOverride>): GateOverride | undefined {\n let latest: GateOverride | undefined\n for (const entry of overrides.values()) {\n if (!latest || entry.order > latest.order) latest = entry\n }\n return latest\n }\n\n private effectiveGatePatch(): Record<string, unknown> {\n const patch: Record<string, unknown> = {}\n const vadOverride = this.latestOverride(this.miniappVadOverrides)\n const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)\n\n // Hardware VAD suppresses silence. Raw-audio consumers need a continuous\n // timeline, so their requirement wins over both OS and miniapp VAD values.\n if (this.wantsPcm()) patch.voice_activity_detection_enabled = false\n else if (vadOverride) patch.voice_activity_detection_enabled = vadOverride.enabled\n else if (this.configuredVad !== undefined) patch.voice_activity_detection_enabled = this.configuredVad\n\n if (loudnessOverride) patch.loudness_gate_enabled = loudnessOverride.enabled\n else if (this.configuredLoudnessGate !== undefined) {\n patch.loudness_gate_enabled = this.configuredLoudnessGate\n }\n\n return patch\n }\n\n /**\n * Reset all requirements to off. Called during cleanup.\n */\n public reset(): void {\n this.localWantsPcm = false\n this.localWantsLc3 = false\n this.applyUnion()\n }\n\n public cleanup(): void {\n console.log(`${LOG_TAG}: cleanup()`)\n this.miniappVadOverrides.clear()\n this.miniappLoudnessGateOverrides.clear()\n this.hostPcmOwners.clear()\n this.reset()\n MicStateCoordinator.instance = null\n }\n}\n\nconst micStateCoordinator = MicStateCoordinator.getInstance()\nexport default micStateCoordinator\n"]}
|
package/build/stores/settings.js
CHANGED
|
@@ -568,11 +568,11 @@ export const SETTINGS = {
|
|
|
568
568
|
persist: true,
|
|
569
569
|
},
|
|
570
570
|
// G2 Glassly CFW microphone volume gate (revision 40+): the temples stop
|
|
571
|
-
// streaming audio while nothing reaches the threshold.
|
|
572
|
-
//
|
|
571
|
+
// streaming audio while nothing reaches the threshold. Default on; shown only
|
|
572
|
+
// when the connected firmware reports the capability.
|
|
573
573
|
volume_gate_enabled: {
|
|
574
574
|
key: "volume_gate_enabled",
|
|
575
|
-
defaultValue: () =>
|
|
575
|
+
defaultValue: () => true,
|
|
576
576
|
writable: true,
|
|
577
577
|
saveOnServer: true,
|
|
578
578
|
persist: true,
|
|
@@ -588,7 +588,7 @@ export const SETTINGS = {
|
|
|
588
588
|
// Quiet time before the gate closes.
|
|
589
589
|
volume_gate_hold_ms: {
|
|
590
590
|
key: "volume_gate_hold_ms",
|
|
591
|
-
defaultValue: () =>
|
|
591
|
+
defaultValue: () => 5000,
|
|
592
592
|
writable: true,
|
|
593
593
|
saveOnServer: true,
|
|
594
594
|
persist: true,
|
|
@@ -596,7 +596,7 @@ export const SETTINGS = {
|
|
|
596
596
|
// Minimum time the gate stays open once sound opens it.
|
|
597
597
|
volume_gate_min_open_ms: {
|
|
598
598
|
key: "volume_gate_min_open_ms",
|
|
599
|
-
defaultValue: () =>
|
|
599
|
+
defaultValue: () => 10000,
|
|
600
600
|
writable: true,
|
|
601
601
|
saveOnServer: true,
|
|
602
602
|
persist: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/stores/settings.ts"],"names":[],"mappings":"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","sourcesContent":["import {getTimeZone} from \"react-native-localize\"\nimport {AsyncResult, result as Res, Result} from \"typesafe-ts\"\nimport {create} from \"zustand\"\nimport {subscribeWithSelector} from \"zustand/middleware\"\n\nimport {storage} from \"../utils/storage\"\nimport {getBluetoothSettingKeysForDevice} from \"./bluetoothSettingKeys\"\nimport {useGlassesStore} from \"./glasses\"\n\nexport {MENTRA_LIVE_SETTING_KEYS, getBluetoothSettingKeysForDevice} from \"./bluetoothSettingKeys\"\n\nexport interface Setting {\n key: string\n defaultValue: () => any\n writable: boolean\n saveOnServer: boolean\n // change the key to a different key based on the indexer\n // NEVER do any network calls in the indexer (or performance will suffer greatly\n indexer?: (key: string) => string\n // optionally override the value of the setting when it's accessed\n override?: () => any\n // onWrite?: () => void\n persist: boolean\n // Pairing-identity keys are NATIVE-authoritative: the native layer writes\n // them on pairing success (handleDeviceReady) / forget and echoes them down\n // via save_setting; JS鈫抧ative they travel only in the explicit SEEDS\n // (hydration, pre-connect, post-demotion, abandon re-seed) — never the\n // change-push and never the on-connect replay, whose mid-relay snapshot can\n // overwrite a just-promoted identity. PAIRING_IDENTITY_KEYS is derived from\n // this flag so the sync exclusions can't drift from the descriptors.\n nativeAuthoritative?: true\n /**\n * Clear this setting when the build's environment changes.\n *\n * A persisted override normally outranks both the build's env and the\n * compiled default, which is right within one environment: a developer's\n * METRO_AUTO pin should survive a rebuild. It is wrong across environments,\n * where an override pinned under a dev build would silently follow the\n * install onto a store build pointed at production.\n *\n * Note this keys off the build's environment label, so it does NOT fire on a\n * TestFlight to App Store promotion: that ships the same binary with the same\n * label. Promotion is safe because the publishing lane bakes prod URLs, not\n * because this reset runs. See the resolution block in loadSettings.\n *\n * Absent means the value is never invalidated automatically.\n */\n resetOnBuildEnvChange?: true\n}\n\n// The provider list the data-consent screen currently shows. Stored per\n// install so a later bump can be told apart from an older answer; the boot\n// router only shows the screen during first onboarding today.\nexport const AI_DATA_CONSENT_VERSION = 1\n\nexport const SETTINGS: Record<string, Setting> = {\n // feature flags / mantle settings:\n dev_mode: {key: \"dev_mode\", defaultValue: () => __DEV__, writable: true, saveOnServer: true, persist: true}, // deprecated\n debug_mode: {key: \"debug_mode\", defaultValue: () => __DEV__, writable: true, saveOnServer: true, persist: true},\n android_notification_listener_enabled: {\n key: \"android_notification_listener_enabled\",\n // Operational kill switch. The listener now runs in a guarded lightweight\n // process, so normal installs can safely capture notifications by default.\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n super_mode: {key: \"super_mode\", defaultValue: () => false, writable: true, saveOnServer: true, persist: true},\n appearance_menu_enabled: {\n key: \"appearance_menu_enabled\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n app_boot_extra_info: {\n key: \"app_boot_extra_info\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Developer tools: shows the Miniapp Developer launcher and the dev-only\n // bundled miniapps (see DEV_TOOLS_PACKAGES). Off by default so ordinary\n // installs never see them. Replaced the legacy `miniapp_dev_mode` key,\n // which only controlled the Miniapp Developer home tile.\n dev_tools: {\n key: \"dev_tools\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n enable_squircles: {\n key: \"enable_squircles\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n android_blur: {\n key: \"android_blur\",\n defaultValue: () => {\n return false\n },\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n android_inner_shadow: {\n key: \"android_inner_shadow\",\n defaultValue: () => {\n return false\n },\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n ios_glass_effect: {\n key: \"ios_glass_effect\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n ios_app_switcher_bottom_swipe: {\n key: \"ios_app_switcher_bottom_swipe\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n debug_console: {\n key: \"debug_console\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Show the glasses display mirror on the home screen even when a real\n // (non-simulated) pair of glasses is paired. Toggled from the glasses card's\n // long-press menu. Default on.\n home_mirror: {\n key: \"home_mirror\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Tint the glasses display mirror text with the green chart color instead of\n // the theme foreground. Toggled from Super Settings.\n mirror_green_text: {\n key: \"mirror_green_text\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n debug_navigation_history: {\n key: \"debug_navigation_history\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n debug_core_status_bar: {\n key: \"debug_core_status_bar\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Mentra Nex feature flags (off by default; toggled from Nex Developer Settings).\n // When on, the Nex display skips ASCII-only text sanitization so CJK/Chinese\n // captions render on glasses. Synced to the Bluetooth SDK via BLUETOOTH_SETTING_KEYS.\n nex_chinese_captions: {\n key: \"nex_chinese_captions\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // When on, LC3 audio received from Nex glasses is played back (Android only).\n // Local-only dev toggle: defaults off and never synced to the cloud account\n // (saveOnServer: false); persists locally so it survives app restarts.\n // Key renamed from the legacy `nex_audio_playback` so stale server/local\n // values (saved back when this was saveOnServer:true) can't re-enable it.\n nex_lc3_audio_playback: {\n key: \"nex_lc3_audio_playback\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Passive conversation memory: when on, the runtime persists every FINAL\n // transcript into the shared user-scoped MemoryStore (Settings > Memory),\n // independent of which miniapps are running or subscribed. Off = nothing is\n // written; existing history is kept until the user clears it. Device-local\n // only (saveOnServer: false) — the timeline itself never leaves the phone,\n // so the switch that governs it shouldn't either. Defaults ON to preserve\n // the behavior the Assistant miniapp previously provided.\n memory_save_conversations: {\n key: \"memory_save_conversations\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n china_deployment: {\n key: \"china_deployment\",\n defaultValue: () => (process.env.EXPO_PUBLIC_DEPLOYMENT_REGION === \"china\" ? true : false),\n override: () => (process.env.EXPO_PUBLIC_DEPLOYMENT_REGION === \"china\" ? true : false),\n writable: false,\n saveOnServer: false,\n persist: true,\n },\n // Hard privacy stance (Settings > Privacy): when true the app never talks to\n // Glassly cloud at all — the CloudClient is not constructed, so the runtime\n // websocket, cloud STT/TTS, managed photo/stream uploads, and report uploads\n // all go away with it. Distinct from `offline_mode`, which is a transient\n // \"I'm offline right now\" app-grid filter the user flips from Speech; this\n // one is a durable choice that survives reconnecting to a good network.\n // Device-local by design: a \"don't use the cloud\" preference must not itself\n // be uploaded to the cloud, so saveOnServer stays false. Not in\n // BLUETOOTH_SETTING_KEYS — glasses firmware has no use for it.\n disable_cloud: {\n key: \"disable_cloud\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // In-app disclosure of which third parties receive user data (App Store\n // 5.1.2(i)). `_version` is the AI_DATA_CONSENT_VERSION the user last saw\n // and `_agreed` is their answer. Declining turns disable_cloud on. The\n // screen is part of first onboarding only. Device-local: consent is a\n // property of this install, and logout's resetAllLocal() clears it so the\n // next account is asked afresh.\n ai_data_consent_version: {\n key: \"ai_data_consent_version\",\n defaultValue: () => 0,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n ai_data_consent_agreed: {\n key: \"ai_data_consent_agreed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // The user chose \"Continue without an account\" on the login screen. Boot\n // treats no-session + this flag as guest mode (cloud disabled, no token\n // exchange). Signing in clears it. Device-local like disable_cloud; logout's\n // resetAllLocal() drops it so the login screen offers Skip again.\n login_skipped: {\n key: \"login_skipped\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Cloud endpoint OVERRIDES. Empty = no override; cloudClient's resolveUrl\n // owns the full precedence (override -> env -> Metro-derived dev default).\n // The value may be an explicit URL or the METRO_AUTO sentinel (\"my dev\n // laptop\", resolved live from Metro so it survives network changes). Never\n // bake an env var or a personal LAN IP into the default here: that makes the\n // override branch always-truthy and strands devs on a stale address.\n cloud_core_url: {\n key: \"cloud_core_url\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n resetOnBuildEnvChange: true,\n },\n cloud_runtime_url: {\n key: \"cloud_runtime_url\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n resetOnBuildEnvChange: true,\n },\n // Bookmarked Cloud endpoint pairs. Each entry is {label, coreUrl,\n // runtimeUrl} — core + runtime are saved together because they are always\n // applied as a matched set (presets fill both; Save & Test verifies both).\n saved_cloud_url_pairs: {\n key: \"saved_cloud_url_pairs\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // User-supplied Soniox API key (Settings > Keys). Non-empty enables\n // phone -> Soniox direct transcription: audio streams from the device to\n // Soniox and transcription/translation subscriptions are withheld from the\n // cloud. Device-local by design — the key must never sync to a server\n // (saveOnServer: false) and must never ride BLE to glasses (do NOT add to\n // bluetoothSettingKeys).\n soniox_api_key: {\n key: \"soniox_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // User-supplied Mapbox access token (Settings > Keys). The app ships no\n // baked Mapbox key: every consumer resolves this key first, else the public\n // render token served by Glassly Cloud at runtime (MapboxTokenService) —\n // and with the cloud disabled this key is the ONLY token source, by\n // design. The `_api_key`\n // suffix is load-bearing: diagnosticContext redacts settings by that suffix,\n // so renaming would leak the key into bug reports. Device-local by design —\n // never synced to a server (saveOnServer: false) and never on BLE (do NOT\n // add to bluetoothSettingKeys).\n mapbox_api_key: {\n key: \"mapbox_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // User-supplied AI/voice provider keys (Settings > API Keys). Not consumed\n // by the app itself — they exist so miniapps declaring the API_KEYS manifest\n // permission can read them via session.keys.get() (see\n // MINIAPP_READABLE_API_KEYS in LocalMiniappRuntime; mapbox is also readable\n // there, soniox is not). Same invariants as the other provider keys: the\n // `_api_key` suffix is load-bearing (diagnosticContext redacts by suffix),\n // device-local by design — never synced to a server (saveOnServer: false)\n // and never on BLE (do NOT add to bluetoothSettingKeys).\n anthropic_api_key: {\n key: \"anthropic_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n gemini_api_key: {\n key: \"gemini_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n openai_api_key: {\n key: \"openai_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n elevenlabs_api_key: {\n key: \"elevenlabs_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Per-tier model picks for session.ai completions (Settings > AI Models).\n // Miniapps request a TIER (\"quick\"/\"balanced\"/\"frontier\"), never a\n // provider/model; these settings are how the user overrides what each tier\n // resolves to. Value is \"auto\" (pick by which provider keys are saved — see\n // AiTierResolution) or \"<provider>:<model>\" from the curated registry.\n // Device-local: the mapping only matters to this phone's direct/cloud calls.\n ai_model_quick: {\n key: \"ai_model_quick\",\n defaultValue: () => \"auto\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n ai_model_balanced: {\n key: \"ai_model_balanced\",\n defaultValue: () => \"auto\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n ai_model_frontier: {\n key: \"ai_model_frontier\",\n defaultValue: () => \"auto\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Developer override for the ASG OTA manifest URL. null/empty = no override;\n // the normal selection applies (legacy-glasses gate, EXPO_PUBLIC_ASG_OTA_VERSION_URL,\n // glasses-reported URL, then production). See resolveOtaManifestUrl.\n ota_version_url: {\n key: \"ota_version_url\",\n defaultValue: () => null,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n saved_ota_version_urls: {\n key: \"saved_ota_version_urls\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n reconnect_on_app_foreground: {\n key: \"reconnect_on_app_foreground\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n location_tier: {key: \"location_tier\", defaultValue: () => \"\", writable: true, saveOnServer: true, persist: true},\n // Volatile bearer synced to Bluetooth for glasses-side Cloud calls. The\n // key name is kept for BLE compatibility, but the value must never be loaded\n // from or saved to the legacy Cloud V1 settings store.\n core_token: {key: \"core_token\", defaultValue: () => \"\", writable: true, saveOnServer: false, persist: false},\n auth_email: {key: \"auth_email\", defaultValue: () => \"\", writable: true, saveOnServer: false, persist: true},\n // Pairing identity is per-phone, not per-account: two phones on one account\n // can be paired to different glasses, so none of these keys may sync to the\n // server (saveOnServer: false — a stale server copy resurrecting a local\n // pairing identity is exactly the desync this group's flags prevent).\n //\n // Two-phase identity: pending_wearable is the model the user last STARTED\n // pairing (written at selection, rendered as a finish-pairing card);\n // default_wearable + device_name + device_address are only promoted by the\n // native layer when pairing actually succeeds (handleDeviceReady).\n // pending_wearable persists so an abandoned selection still shows its\n // finish-pairing card after an app restart.\n pending_wearable: {\n key: \"pending_wearable\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n default_wearable: {\n key: \"default_wearable\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n device_name: {\n key: \"device_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n device_address: {\n key: \"device_address\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n project_name: {\n key: \"project_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n // Latched true the first time the identity projects as paired to real\n // (non-simulated) glasses; never cleared, so forgetting the glasses keeps\n // what it unlocked (the Store). Per-phone like the identity it derives from.\n has_paired_glasses: {\n key: \"has_paired_glasses\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n default_controller: {\n key: \"default_controller\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n // Display name of the keyboard the glasses remember (G2 Glassly CFW). The\n // native bridge owns the address/bond; this only keeps the home card and\n // settings row populated before the glasses connect, like default_controller.\n keyboard_name: {\n key: \"keyboard_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n pending_controller: {\n key: \"pending_controller\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n controller_device_name: {\n key: \"controller_device_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n controller_address: {\n key: \"controller_address\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n // ui state:\n home_background: {\n key: \"home_background\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n theme_preference: {\n key: \"theme_preference\",\n defaultValue: () => \"system\",\n // override: () => \"light\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n settings_access_count: {\n key: \"settings_access_count\",\n defaultValue: () => 0,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n show_advanced_settings: {\n key: \"show_advanced_settings\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n onboarding_completed: {\n key: \"onboarding_completed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n onboarding_live_completed: {\n key: \"onboarding_live_completed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n onboarding_os_completed: {\n key: \"onboarding_os_completed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n has_ever_activated_app: {\n key: \"has_ever_activated_app\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n\n // Bluetooth SDK settings:\n sensing_enabled: {\n key: \"sensing_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n power_saving_mode: {\n key: \"power_saving_mode\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // The Glassly App intentionally preserves Mentra Live's historical VAD-on\n // product default. Standalone public Bluetooth SDK hosts default VAD off so\n // their microphone audio remains continuous.\n voice_activity_detection_enabled: {\n key: \"voice_activity_detection_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Mentra Live center-mic loudness / \"Barrier\" gate (cs_swit type 10). Default on.\n loudness_gate_enabled: {\n key: \"loudness_gate_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // G2 Glassly CFW microphone volume gate (revision 40+): the temples stop\n // streaming audio while nothing reaches the threshold. Off until the user\n // turns it on; shown only when the connected firmware reports the capability.\n volume_gate_enabled: {\n key: \"volume_gate_enabled\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // dBFS RMS a 50 ms chunk must reach to count as sound.\n volume_gate_threshold_db: {\n key: \"volume_gate_threshold_db\",\n defaultValue: () => -45,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Quiet time before the gate closes.\n volume_gate_hold_ms: {\n key: \"volume_gate_hold_ms\",\n defaultValue: () => 3000,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Minimum time the gate stays open once sound opens it.\n volume_gate_min_open_ms: {\n key: \"volume_gate_min_open_ms\",\n defaultValue: () => 2000,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n always_on_status_bar: {\n key: \"always_on_status_bar\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Legacy cloud/mobile setting name. Locally it maps to glasses-side Voice Activity Detection.\n bypass_vad_for_debugging: {\n key: \"bypass_vad_for_debugging\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n bypass_audio_encoding_for_debugging: {\n key: \"bypass_audio_encoding_for_debugging\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n metric_system: {\n key: \"metric_system\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n twelve_hour_time: {\n key: \"twelve_hour_time\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n enforce_local_transcription: {\n key: \"enforce_local_transcription\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // \"Recognize my voice\" (Settings > Voice Recognition). Drives the on-device\n // SpeakerIdEngine. Device-local by design — voice profiles are biometric\n // data, so nothing about this feature syncs to the server.\n speaker_id_enabled: {\n key: \"speaker_id_enabled\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // LC3 audio quality setting (frame size in bytes)\n // 20 = 16kbps (low bandwidth), 40 = 32kbps (balanced), 60 = 48kbps (high quality)\n lc3_frame_size: {\n key: \"lc3_frame_size\",\n defaultValue: () => 60,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n preferred_mic: {\n key: \"preferred_mic\",\n defaultValue: () => \"auto\",\n writable: true,\n indexer: (key: string) => {\n const glasses = useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key)\n if (glasses) {\n return `${key}:${glasses}`\n }\n return key\n },\n saveOnServer: true,\n persist: true,\n },\n screen_disabled: {\n key: \"screen_disabled\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // glasses settings:\n contextual_dashboard: {\n key: \"contextual_dashboard\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Debug escape hatch: G2 scene rendering through the Glassly CFW\n // direct-framebuffer path (rasterized mode-3 frames into the carrier).\n // ON by default — the working production path on CFW glasses; OFF falls\n // back to stock EvenHub containers for isolating renderer regressions.\n // Synced to the Bluetooth SDK via BLUETOOTH_SETTING_KEYS; the SGC re-reads\n // it per frame, but a glasses reconnect gives the cleanest switch.\n // Device-local debug knob, so not saved on the server.\n cfw_scene_renderer: {\n key: \"cfw_scene_renderer\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: ask Glassly CFW glasses (revision 26+) for the 7.5 ms / latency-0\n // fast BLE connection profile with slow mode suppressed, instead of the\n // stock 15-30 ms link and its one-minute slow-mode timer. OFF by default:\n // the fast link costs battery whenever the phone is merely connected, and\n // the phone must agree to the interval. Synced to the Bluetooth SDK, which\n // sends the control to both lenses and re-sends it on every CFW detection.\n // Device-local debug knob, so not saved on the server.\n cfw_fast_ble: {\n key: \"cfw_fast_ble\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: the G2's G2PERF display performance lines (a sample per busy\n // second, plus stalls) in the console and the log buffer bug reports carry.\n // OFF by default: they crowd out everything else in the ten-minute buffer.\n // Synced to the Bluetooth SDK, which keeps counting either way and only\n // logs while this is on. Device-local debug knob, so not saved on the server.\n g2_perf_logs: {\n key: \"g2_perf_logs\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: route the R1 ring through the glasses (advStart + RING_CONNECT_INFO,\n // events forwarded by the CFW) instead of the phone link. OFF by default:\n // the ring is a direct phone link whether or not a G2 is paired, which is\n // how the Faceclaw reference client runs it. Synced to the Bluetooth SDK,\n // which re-routes a connected ring on change. Device-local debug knob, so\n // not saved on the server.\n ring_via_glasses: {\n key: \"ring_via_glasses\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Meta Neural Band: the air mouse streams the band's orientation at 128 Hz, so it\n // stays off unless asked for. The band side is pushed when the band connects.\n neural_band_air_mouse: {\n key: \"neural_band_air_mouse\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Which wrist wears the band: flips the air mouse's forearm axis and is written\n // to the band's own hand setting on connect.\n neural_band_hand: {\n key: \"neural_band_hand\",\n defaultValue: () => \"right\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Maximum rate at which display updates leave the phone for the glasses.\n // The Bluetooth SDK paces every scene frame and legacy layout to this,\n // coalescing faster updates last-wins; clears bypass it. No effect on G2\n // custom firmware, whose driver coalesces off the link itself. Device-local\n // debug knob (2..20), so not saved on the server.\n display_max_fps: {\n key: \"display_max_fps\",\n defaultValue: () => 8,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Master switch for the Scene API dashboard on G2 custom firmware\n // (the dashboard's eligibility). Off leaves an eligible device on the\n // native head-up behavior. Device-local debug knob, so not saved on the\n // server.\n custom_dashboard_enabled: {\n key: \"custom_dashboard_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: time each dashboard open (head-up / double tap → glasses frame)\n // and post the stage timeline as a phone notification. Persisted so a\n // slow first open after an app restart is still caught. Device-local.\n debug_dashboard_open_timing: {\n key: \"debug_dashboard_open_timing\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug escape hatch: enter the G2's firmware-rendered navigation mode on\n // custom firmware too. Off by default: CFW draws the navigation miniapp's\n // own HUD through the scene canvas and reads session.compass directly, so\n // native nav mode is reserved for stock firmware. Device-local debug knob,\n // so not saved on the server.\n cfw_native_navigation: {\n key: \"cfw_native_navigation\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: open miniapps from their last screenshot, fading straight into the\n // app. Off shows the splash instead. Device-local, default on.\n use_screenshot_transition: {\n key: \"use_screenshot_transition\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Gesture-dots debug indicator: flash a glyph on the glasses when a touch\n // gesture is received while the display is empty. Works on any\n // scene-capable device, not only CFW. Device-local debug knob, default off.\n gesture_dots: {\n key: \"gesture_dots\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n head_up_angle: {key: \"head_up_angle\", defaultValue: () => 45, writable: true, saveOnServer: true, persist: true},\n brightness: {key: \"brightness\", defaultValue: () => 50, writable: true, saveOnServer: true, persist: true},\n auto_brightness: {\n key: \"auto_brightness\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n dashboard_height: {\n key: \"dashboard_height\",\n defaultValue: () => 4,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n dashboard_depth: {\n key: \"dashboard_depth\",\n defaultValue: () => 2,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n menu_apps: {\n key: \"menu_apps\",\n defaultValue: () => null,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n calendar_events: {\n key: \"calendar_events\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n // button settings\n // Legacy persisted/cloud key; hardware behavior is now controlled by gallery_mode plus capture settings.\n button_mode: {key: \"button_mode\", defaultValue: () => \"photo\", writable: true, saveOnServer: true, persist: true},\n button_photo_size: {\n key: \"button_photo_size\",\n defaultValue: () => \"max\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n button_video_settings: {\n key: \"button_video_settings\",\n defaultValue: () => ({width: 1920, height: 1080, fps: 30}),\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n button_max_recording_time: {\n key: \"button_max_recording_time\",\n defaultValue: () => 10,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n camera_fov: {\n key: \"camera_fov\",\n defaultValue: () => ({fov: 118, roi_position: 0}),\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n media_post_processing: {\n key: \"media_post_processing\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n\n // time zone settings\n time_zone: {\n key: \"time_zone\",\n defaultValue: () => \"\",\n writable: true,\n override: () => {\n const override = useSettingsStore.getState().getSetting(SETTINGS.time_zone_override.key)\n if (override) {\n return override\n }\n return getTimeZone()\n },\n saveOnServer: true,\n persist: true,\n },\n time_zone_override: {\n key: \"time_zone_override\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // offline applets\n offline_mode: {key: \"offline_mode\", defaultValue: () => false, writable: true, saveOnServer: true, persist: true},\n // Runtime flag: coordinator flips this on when cloud STT has failed and fallback is active.\n // Native GlassesStore watches it to gate PCM 鈫?Sherpa feeding. Not user-facing.\n local_stt_fallback_active: {\n key: \"local_stt_fallback_active\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n // Runtime flag: why the coordinator activated local STT (\"\" while inactive).\n // Values are LocalSttFallbackReason strings. UI-only; native ignores it.\n local_stt_fallback_reason: {\n key: \"local_stt_fallback_reason\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n gallery_mode: {key: \"gallery_mode\", defaultValue: () => true, writable: true, saveOnServer: true, persist: true},\n gallery_sync_explained: {\n key: \"gallery_sync_explained\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n offline_camera_running: {\n key: \"offline_camera_running\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // offline translation\n offline_translation_running: {\n key: \"offline_translation_running\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n offline_translation_source: {\n key: \"offline_translation_source\",\n defaultValue: () => \"en\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n offline_translation_target: {\n key: \"offline_translation_target\",\n defaultValue: () => \"es\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // button action settings\n default_button_action_enabled: {\n key: \"default_button_action_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n default_button_action_app: {\n key: \"default_button_action_app\",\n defaultValue: () => \"com.glassly.camera\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // notifications\n notifications_blocklist: {\n key: \"notifications_blocklist\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Apps the connected glasses reported posting notifications (bundle/package\n // id + display name). Backs the filter UI where the phone cannot enumerate\n // apps itself and the allowlist pushed to firmware that filters on-glass.\n notification_seen_apps: {\n key: \"notification_seen_apps\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Notification display, any glasses: firmware that presents notifications\n // itself receives these as a GlassesNotificationConfig; the engine's own\n // viewer reads the same four. Master switch first.\n notifications_enabled: {\n key: \"notifications_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Show a popup when a notification arrives; off keeps history only.\n notifications_popups: {\n key: \"notifications_popups\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Popup duration in seconds; 0 lets the firmware or viewer pick its default.\n notifications_popup_seconds: {\n key: \"notifications_popup_seconds\",\n defaultValue: () => 5,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Hold popups while another glasses feature (navigation, a miniapp) is on screen.\n notifications_hold_during_apps: {\n key: \"notifications_hold_during_apps\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Experimental, any glasses: hold notification popups while the phone is in\n // use (unlocked, or the Glassly App foregrounded), so a notification isn't\n // shown on the glasses and the phone screen at once. The dashboard reducer\n // reads it with PhoneActivity when a notification posts; on iOS\n // PhoneNotificationsSync also folds it into the stock G2 firmware's\n // auto_display, which pops notifications up on its own.\n notifications_ignore_while_active: {\n key: \"notifications_ignore_while_active\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Cached required version from server - used to enforce updates even when offline\n cached_required_version: {\n key: \"cached_required_version\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // OTA update dismissal - stores the version code user dismissed (not persisted so resets on app restart)\n dismissed_ota_version: {\n key: \"dismissed_ota_version\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n // Contact email for feedback (persisted for Apple private relay users)\n contact_email: {\n key: \"contact_email\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n} as const\n\nexport const OFFLINE_APPLETS: string[] = [\"com.glassly.livecaptions\", \"com.glassly.camera\"]\n\n// These settings are automatically synced to the Bluetooth SDK.\n// Keep this list hardware-facing; app/UI/cloud-only preferences should stay in JS/Crust.\nexport const BLUETOOTH_SETTING_KEYS: string[] = [\n // Bluetooth settings:\n SETTINGS.sensing_enabled.key,\n SETTINGS.power_saving_mode.key,\n SETTINGS.voice_activity_detection_enabled.key,\n SETTINGS.loudness_gate_enabled.key,\n SETTINGS.volume_gate_enabled.key,\n SETTINGS.volume_gate_threshold_db.key,\n SETTINGS.volume_gate_hold_ms.key,\n SETTINGS.volume_gate_min_open_ms.key,\n SETTINGS.lc3_frame_size.key,\n SETTINGS.preferred_mic.key,\n SETTINGS.screen_disabled.key,\n SETTINGS.auth_email.key,\n SETTINGS.core_token.key,\n // glasses settings (contextual_dashboard is phone-side policy now — native\n // no longer reads it):\n SETTINGS.head_up_angle.key,\n SETTINGS.brightness.key,\n SETTINGS.auto_brightness.key,\n SETTINGS.dashboard_height.key,\n SETTINGS.dashboard_depth.key,\n SETTINGS.menu_apps.key,\n SETTINGS.calendar_events.key,\n SETTINGS.cfw_scene_renderer.key,\n SETTINGS.cfw_fast_ble.key,\n SETTINGS.g2_perf_logs.key,\n SETTINGS.ring_via_glasses.key,\n SETTINGS.display_max_fps.key,\n SETTINGS.twelve_hour_time.key,\n SETTINGS.metric_system.key,\n // button:\n SETTINGS.button_photo_size.key,\n // Legacy MentraLive native code reads the object form when syncing video settings.\n SETTINGS.button_video_settings.key,\n SETTINGS.button_max_recording_time.key,\n SETTINGS.camera_fov.key,\n // device / pairing:\n SETTINGS.pending_wearable.key,\n SETTINGS.default_wearable.key,\n SETTINGS.device_name.key,\n SETTINGS.device_address.key,\n SETTINGS.project_name.key,\n SETTINGS.default_controller.key,\n SETTINGS.pending_controller.key,\n SETTINGS.controller_device_name.key,\n SETTINGS.controller_address.key,\n // offline applets:\n SETTINGS.offline_mode.key,\n // Runtime flag flipped by LocalSttFallbackCoordinator. Native reads it from\n // GlassesStore to gate PCM 鈫?Sherpa feeding in handlePcm and to keep the\n // mic on while local STT is the active engine.\n SETTINGS.local_stt_fallback_active.key,\n SETTINGS.gallery_mode.key,\n // Mentra Nex feature flags:\n SETTINGS.nex_chinese_captions.key,\n SETTINGS.nex_lc3_audio_playback.key,\n]\n\n// Pairing identity is NATIVE-authoritative: the native layer writes it on\n// pairing success (handleDeviceReady) / forget and echoes it down via\n// save_setting; JS persists those echoes. JS鈫抧ative, identity travels ONLY in\n// the explicit full seeds (device-store hydration, pre-connect push,\n// post-demotion re-push) — never in the change-push subscription. Relaying an\n// echoed identity change back up would make the sync bidirectional with loop\n// gain 1: two identity values in flight (e.g. a boot demotion crossing a\n// native promotion) then chase each other through push鈫抋pply鈫抏cho鈫抪ush\n// forever, flapping the UI.\n//\n// Derived from the `nativeAuthoritative` descriptor flag (not maintained as a\n// parallel list) so the change-push exclusion in GlassesSettingsSync can't\n// drift from the setting declarations.\nexport const PAIRING_IDENTITY_KEYS: string[] = Object.values(SETTINGS)\n .filter((setting) => setting.nativeAuthoritative)\n .map((setting) => setting.key)\n\n// const PER_GLASSES_SETTINGS_KEYS: string[] = [SETTINGS.preferred_mic.key]\n\nexport interface SettingsState {\n // Settings values\n settings: Record<string, any>\n // Loading states\n isInitialized: boolean\n // Actions\n setSetting: (key: string, value: any, updateServer?: boolean) => AsyncResult<void, Error>\n setManyLocally: (settings: Record<string, any>) => AsyncResult<void, Error>\n getSetting: (key: string) => any\n // loadSetting: (key: string) => AsyncResult<void, Error>\n loadAllSettings: () => AsyncResult<void, Error>\n // Utility methods\n getBluetoothSettings: () => Record<string, any>\n resetAllSettingsLocally: () => void\n}\n\nconst getDefaultSettings = () =>\n Object.keys(SETTINGS).reduce((acc, key) => {\n acc[key] = SETTINGS[key].defaultValue()\n return acc\n }, {} as Record<string, any>)\n\n// Single-flight for loadAllSettings: the host fires it at module load and\n// engine.start()'s device-store hydration awaits it — without the memo the\n// second caller runs a duplicate full disk load while the first is still in\n// flight. Cleared on failure so a later call can retry.\nlet loadAllSettingsInFlight: AsyncResult<void, Error> | null = null\n\nfunction printableSettingValue(key: string, value: unknown): string {\n return key.includes(\"token\") || key.includes(\"email\") || key.includes(\"api_key\")\n ? \"<redacted>\"\n : JSON.stringify(value)\n}\n\nexport const useSettingsStore = create<SettingsState>()(\n subscribeWithSelector((set, get) => ({\n settings: getDefaultSettings(),\n isInitialized: false,\n loadingKeys: new Set(),\n setSetting: (key: string, value: any, _updateServer = true): AsyncResult<void, Error> => {\n return Res.try_async(async () => {\n const setting = SETTINGS[key]\n const originalKey = key\n\n if (!setting) {\n throw new Error(`SETTINGS: SET: ${originalKey} is not a valid setting!`)\n }\n\n if (setting.indexer) {\n key = setting.indexer(originalKey)\n }\n\n if (!setting.writable) {\n throw new Error(`SETTINGS: ${originalKey} is not writable!`)\n }\n\n // Update store immediately for optimistic UI\n console.log(`SETTINGS: SET: ${key} = ${printableSettingValue(key, value)}`)\n set((state) => ({\n settings: {...state.settings, [key]: value},\n }))\n\n if (setting.persist) {\n let res = await storage.save(key, value)\n if (res.is_error()) {\n throw new Error(`SETTINGS: couldn't save setting to storage: ${res.error}`)\n }\n\n // Cloud V1 per-change server sync removed with the V1 ripout (issue\n // #3392). Settings are local-first until a V2 sync lands; the\n // saveOnServer flags are retained as intent markers for that work.\n }\n })\n },\n getSetting: (key: string) => {\n const state = get()\n const originalKey = key\n const setting = SETTINGS[originalKey]\n\n if (!setting) {\n console.error(`SETTINGS: GET: ${originalKey} is not a valid setting!`)\n return undefined\n }\n\n if (setting.override) {\n let override = setting.override()\n if (override !== undefined) {\n return override\n }\n }\n\n if (setting.indexer) {\n key = setting.indexer(originalKey)\n }\n\n // console.log(`GET SETTING: ${key} = ${state.settings[key]}`)\n\n try {\n const raw = state.settings[key] ?? SETTINGS[originalKey].defaultValue()\n return raw\n } catch (e) {\n // for dynamically created settings, we need to create a new setting in SETTINGS:\n console.log(`Failed to get setting, creating new setting:(${key}):`, e)\n SETTINGS[key] = {key: key, defaultValue: () => undefined, writable: true, saveOnServer: false, persist: true}\n return SETTINGS[key].defaultValue()\n }\n },\n // batch update many settings from the server:\n setManyLocally: (settings: Record<string, any>): AsyncResult<void, Error> => {\n return Res.try_async(async () => {\n const settingsToLoad: Record<string, any> = {}\n // if a setting should not persist, don't load it:\n for (const [key, value] of Object.entries(settings)) {\n const stg: Setting | undefined = SETTINGS[key.toLowerCase()]\n if (!stg) {\n continue\n }\n if (!stg.persist) {\n continue\n }\n settingsToLoad[key.toLowerCase()] = value\n }\n // console.log(\"SETTINGS: SET MANY LOCALLY: \", settingsToLoad)\n\n set((state) => ({\n settings: {...state.settings, ...settingsToLoad},\n }))\n\n // save to storage:\n await Promise.all(Object.entries(settingsToLoad).map(([key, value]) => storage.save(key, value)))\n })\n },\n // loads any preferences that have been changed from the default and saved to DISK!\n loadAllSettings: (): AsyncResult<void, Error> => {\n console.log(\"SETTINGS: loadAllSettings()\")\n if (loadAllSettingsInFlight) {\n return loadAllSettingsInFlight\n }\n const inFlight = Res.try_async(async () => {\n const state = get()\n let loadedSettings: Record<string, any> = {}\n\n if (state.isInitialized) {\n return undefined\n }\n\n for (const setting of Object.values(SETTINGS)) {\n // if the settings should not persist, don't load it:\n if (!setting.persist) {\n continue\n }\n\n // load all subkeys for an indexed setting:\n if (setting?.indexer) {\n console.log(`SETTINGS: LOAD: ${setting.key} with indexer!`)\n\n let res: Result<Record<string, unknown>, Error> = storage.loadSubKeys(setting.key)\n if (res.is_error()) {\n console.log(`SETTINGS: LOAD: ${setting.key}`, res.error)\n continue\n }\n\n let subKeys: Record<string, unknown> = res.value\n console.log(`SETTINGS: LOAD: ${setting.key} subkeys are set!`, subKeys)\n loadedSettings = {...loadedSettings, ...subKeys}\n continue\n }\n\n let res = storage.load<any>(setting.key)\n if (res.is_error()) {\n console.log(`SETTINGS: LOAD: ${setting.key} is not set!`, res.error)\n // this setting isn't set from the default, so we don't load anything\n continue\n }\n // normal key:value pair:\n let value = res.value\n // res.value IS the stored value; logging value.value printed\n // \"undefined\" for every loaded setting and disguised present\n // values as missing. Redact token- and email-bearing keys: console\n // logs are uploaded in bug-report artifacts (same keys\n // diagnosticContext's SENSITIVE_SETTINGS_KEYS strips, minus an\n // import that would cycle stores <-> utils).\n console.log(`SETTINGS: LOAD: ${setting.key} = ${printableSettingValue(setting.key, value)}`)\n loadedSettings[setting.key] = value\n }\n\n // console.log(\"##############################################\")\n // console.log(loadedSettings)\n // console.log(\"##############################################\")\n\n set((state) => ({\n isInitialized: true,\n settings: {...state.settings, ...loadedSettings},\n }))\n\n // This hidden debug switch originally shipped default-off while the\n // notification-listener cold-start ANR was being investigated. Now\n // that the listener runs in its own guarded process, migrate existing\n // installs to the new default once; later explicit debug changes still\n // persist normally.\n // Reset the cloud backend override when the build's environment changes.\n //\n // cloud_core_url / cloud_runtime_url are persist:true and outrank both\n // the build's env and the compiled default (see resolveUrl in\n // cloudClient.ts). That is what we want inside one environment: a\n // developer's METRO_AUTO pin should survive a rebuild. It is wrong\n // across environments.\n //\n // The concrete case is an install that moves BETWEEN environments: an\n // internal tester running a dev build with a pinned override who then\n // installs the store build. The override outranks that build's prod\n // URLs, so without this they keep talking to dev with nothing\n // surfacing it.\n //\n // Note what this deliberately does NOT do, because the distinction is\n // easy to get backwards. TestFlight and the App Store receive the SAME\n // binary, so promotion does not change EXPO_PUBLIC_BUILD_ENV and this\n // reset never fires on it. Promotion is safe for a different reason:\n // the publishing lane bakes the selected release cloud environment, and\n // production promotes the already-tested binary. The same holds for\n // Android beta-track to production.\n //\n // The residual gap is therefore an override pinned while already on a\n // prod-labelled build, which no label comparison can see. That is a\n // deliberate limit: reaching it means typing a URL into a dev-only\n // screen, VersionInfo renders the current value, and the same screen\n // clears it.\n //\n // Comparing the baked EXPO_PUBLIC_BUILD_ENV against the last one seen\n // on this device covers those environment switches and fresh installs\n // without touching the setting write path. A reinstall needs no\n // handling: it drops the marker and the override together\n // (android:allowBackup=\"false\", and iOS deletes the container).\n const BUILD_ENV_KEY = \"settings.lastBuildEnv\"\n const buildEnv = (process.env.EXPO_PUBLIC_BUILD_ENV ?? \"dev\").trim() || \"dev\"\n const lastBuildEnv = storage.load<string>(BUILD_ENV_KEY)\n const previousBuildEnv = lastBuildEnv.is_error() ? undefined : lastBuildEnv.value\n if (previousBuildEnv !== buildEnv) {\n // Clear when there is no marker yet, not just on a recorded change.\n // The first build carrying this code meets every existing install\n // with previousBuildEnv === undefined, and those are exactly the\n // installs that may hold an override set before the pin existed --\n // the population this is here to repair. Treating \"no marker\" as a\n // fresh install would record the marker and never look again. A\n // genuinely fresh install has nothing persisted, so the clear below\n // writes each default over itself and costs nothing.\n //\n // Driven by the descriptors rather than a hardcoded key list, so a\n // setting that needs this behaviour declares it in one place and\n // cannot be missed here.\n const scoped = Object.values(SETTINGS).filter((setting) => setting.resetOnBuildEnvChange)\n console.log(\n `SETTINGS: build env ${previousBuildEnv ?? \"(none recorded)\"} -> ${buildEnv}, ` +\n `clearing ${scoped.length} build-scoped setting(s)`,\n )\n let allCleared = true\n for (const setting of scoped) {\n const cleared = await get().setSetting(setting.key, setting.defaultValue(), false)\n if (cleared.is_error()) {\n allCleared = false\n console.log(`SETTINGS: could not clear ${setting.key}:`, cleared.error)\n }\n }\n // Advance the marker only once the reset actually landed. Recording\n // it after a failed write would retire the retry and leave the stale\n // override for the life of the install; leaving it unset costs one\n // repeated attempt per launch until a write succeeds.\n if (allCleared) {\n storage.save(BUILD_ENV_KEY, buildEnv)\n }\n }\n\n const NOTIFICATION_LISTENER_MIGRATION_KEY = \"migration:android_notification_listener_default_on_v1\"\n const notificationListenerMigrationDone = storage.load<boolean>(NOTIFICATION_LISTENER_MIGRATION_KEY)\n if (notificationListenerMigrationDone.is_error() || !notificationListenerMigrationDone.value) {\n const result = await get().setSetting(SETTINGS.android_notification_listener_enabled.key, true, false)\n if (result.is_error()) {\n console.log(\"SETTINGS: notification listener migration failed:\", result.error)\n } else {\n storage.save(NOTIFICATION_LISTENER_MIGRATION_KEY, true)\n }\n }\n\n // One-time migration: force android_blur=false for existing users.\n // The setting's default is already false; this migration covers users\n // who explicitly opted into Android blur effects before we discovered\n // they're a major source of frame drops on cheap Android phones.\n // The dimezisBlurViewSdk31Plus blur each costs ~5-10ms/frame; with\n // multiple blurs on home (top fade + AppSwitcherButton x2) a low-end\n // device misses the 16ms budget consistently. Users can turn it back\n // on under Settings 鈫?Appearance once we've optimized further.\n //\n // The setSetting call also pushes to the server (saveOnServer: true)\n // so the server-stored value flips too — otherwise the next sync\n // from the user's server-stored prefs would re-enable blur.\n // Best-effort: a server failure (offline, 5xx) shouldn't block boot;\n // we still mark the migration done locally so we don't loop.\n const MIGRATION_KEY = \"migration:android_blur_default_false_v1\"\n const migrationDone = storage.load<boolean>(MIGRATION_KEY)\n if (migrationDone.is_error() || !migrationDone.value) {\n const current = get().getSetting(SETTINGS.android_blur.key)\n if (current === true) {\n const result = await get().setSetting(SETTINGS.android_blur.key, false, true)\n if (result.is_error()) {\n // Server push failed (offline / 5xx). Local storage was still\n // updated, so the user immediately gets the new behavior. The\n // server-side stale `true` will be overwritten the next time\n // the user opens Appearance settings and the auto-sync runs.\n console.log(\"SETTINGS: android_blur migration server-push failed:\", result.error)\n }\n }\n // Mark done unconditionally — even on server-push failure we don't\n // want to retry the migration on every boot. The local value is\n // already correct.\n storage.save(MIGRATION_KEY, true)\n }\n\n // The old camera default cropped the sensor to 102掳. Move existing\n // default-shaped values to the full 118掳 sensor once; named miniapp\n // requests for the 102掳 \"standard\" preset remain available.\n const CAMERA_FOV_MIGRATION_KEY = \"migration:camera_fov_full_sensor_v1\"\n const cameraFovMigrationDone = storage.load<boolean>(CAMERA_FOV_MIGRATION_KEY)\n if (cameraFovMigrationDone.is_error() || !cameraFovMigrationDone.value) {\n const current = get().getSetting(SETTINGS.camera_fov.key) as {fov?: number; roi_position?: number} | undefined\n let migrationSucceeded = true\n if (current?.fov === 102 && (current.roi_position ?? 0) === 0) {\n const result = await get().setSetting(SETTINGS.camera_fov.key, {fov: 118, roi_position: 0}, true)\n if (result.is_error()) {\n console.log(\"SETTINGS: camera FOV migration failed:\", result.error)\n migrationSucceeded = false\n }\n }\n // Unlike the blur migration above, a failed camera set may leave the\n // local value unchanged. Only mark this migration complete once the\n // desired value was applied so a transient failure retries on boot.\n if (migrationSucceeded) storage.save(CAMERA_FOV_MIGRATION_KEY, true)\n }\n })\n loadAllSettingsInFlight = inFlight\n void Promise.resolve(inFlight).then((result) => {\n if (result.is_error()) {\n loadAllSettingsInFlight = null\n }\n })\n return inFlight\n },\n getBluetoothSettings: () => {\n const state = get()\n // Device-model-filtered key set (wire v2): Mentra Live (no display) gets\n // the reduced MENTRA_LIVE_SETTING_KEYS; display glasses get the full set.\n const deviceModel = useGlassesStore.getState().deviceModel || state.getSetting(SETTINGS.default_wearable.key)\n const keys = getBluetoothSettingKeysForDevice(deviceModel, BLUETOOTH_SETTING_KEYS)\n const bluetoothSettings: Record<string, any> = {}\n for (const key of keys) {\n const value = state.getSetting(key)\n if (key === SETTINGS.core_token.key && (typeof value !== \"string\" || value.trim().length === 0)) {\n continue\n }\n bluetoothSettings[key] = value\n }\n return bluetoothSettings\n },\n resetAllSettingsLocally: () => {\n set((_state) => ({\n settings: getDefaultSettings(),\n isInitialized: true,\n }))\n },\n })),\n)\n\nexport const useSetting = <T = any>(key: string): [T, (value: T) => AsyncResult<void, Error>] => {\n const value = useSettingsStore((state) => state.getSetting(key))\n const setSetting = useSettingsStore((state) => state.setSetting)\n return [value, (newValue: T) => setSetting(key, newValue)]\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/stores/settings.ts"],"names":[],"mappings":"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","sourcesContent":["import {getTimeZone} from \"react-native-localize\"\nimport {AsyncResult, result as Res, Result} from \"typesafe-ts\"\nimport {create} from \"zustand\"\nimport {subscribeWithSelector} from \"zustand/middleware\"\n\nimport {storage} from \"../utils/storage\"\nimport {getBluetoothSettingKeysForDevice} from \"./bluetoothSettingKeys\"\nimport {useGlassesStore} from \"./glasses\"\n\nexport {MENTRA_LIVE_SETTING_KEYS, getBluetoothSettingKeysForDevice} from \"./bluetoothSettingKeys\"\n\nexport interface Setting {\n key: string\n defaultValue: () => any\n writable: boolean\n saveOnServer: boolean\n // change the key to a different key based on the indexer\n // NEVER do any network calls in the indexer (or performance will suffer greatly\n indexer?: (key: string) => string\n // optionally override the value of the setting when it's accessed\n override?: () => any\n // onWrite?: () => void\n persist: boolean\n // Pairing-identity keys are NATIVE-authoritative: the native layer writes\n // them on pairing success (handleDeviceReady) / forget and echoes them down\n // via save_setting; JS鈫抧ative they travel only in the explicit SEEDS\n // (hydration, pre-connect, post-demotion, abandon re-seed) — never the\n // change-push and never the on-connect replay, whose mid-relay snapshot can\n // overwrite a just-promoted identity. PAIRING_IDENTITY_KEYS is derived from\n // this flag so the sync exclusions can't drift from the descriptors.\n nativeAuthoritative?: true\n /**\n * Clear this setting when the build's environment changes.\n *\n * A persisted override normally outranks both the build's env and the\n * compiled default, which is right within one environment: a developer's\n * METRO_AUTO pin should survive a rebuild. It is wrong across environments,\n * where an override pinned under a dev build would silently follow the\n * install onto a store build pointed at production.\n *\n * Note this keys off the build's environment label, so it does NOT fire on a\n * TestFlight to App Store promotion: that ships the same binary with the same\n * label. Promotion is safe because the publishing lane bakes prod URLs, not\n * because this reset runs. See the resolution block in loadSettings.\n *\n * Absent means the value is never invalidated automatically.\n */\n resetOnBuildEnvChange?: true\n}\n\n// The provider list the data-consent screen currently shows. Stored per\n// install so a later bump can be told apart from an older answer; the boot\n// router only shows the screen during first onboarding today.\nexport const AI_DATA_CONSENT_VERSION = 1\n\nexport const SETTINGS: Record<string, Setting> = {\n // feature flags / mantle settings:\n dev_mode: {key: \"dev_mode\", defaultValue: () => __DEV__, writable: true, saveOnServer: true, persist: true}, // deprecated\n debug_mode: {key: \"debug_mode\", defaultValue: () => __DEV__, writable: true, saveOnServer: true, persist: true},\n android_notification_listener_enabled: {\n key: \"android_notification_listener_enabled\",\n // Operational kill switch. The listener now runs in a guarded lightweight\n // process, so normal installs can safely capture notifications by default.\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n super_mode: {key: \"super_mode\", defaultValue: () => false, writable: true, saveOnServer: true, persist: true},\n appearance_menu_enabled: {\n key: \"appearance_menu_enabled\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n app_boot_extra_info: {\n key: \"app_boot_extra_info\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Developer tools: shows the Miniapp Developer launcher and the dev-only\n // bundled miniapps (see DEV_TOOLS_PACKAGES). Off by default so ordinary\n // installs never see them. Replaced the legacy `miniapp_dev_mode` key,\n // which only controlled the Miniapp Developer home tile.\n dev_tools: {\n key: \"dev_tools\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n enable_squircles: {\n key: \"enable_squircles\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n android_blur: {\n key: \"android_blur\",\n defaultValue: () => {\n return false\n },\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n android_inner_shadow: {\n key: \"android_inner_shadow\",\n defaultValue: () => {\n return false\n },\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n ios_glass_effect: {\n key: \"ios_glass_effect\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n ios_app_switcher_bottom_swipe: {\n key: \"ios_app_switcher_bottom_swipe\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n debug_console: {\n key: \"debug_console\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Show the glasses display mirror on the home screen even when a real\n // (non-simulated) pair of glasses is paired. Toggled from the glasses card's\n // long-press menu. Default on.\n home_mirror: {\n key: \"home_mirror\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Tint the glasses display mirror text with the green chart color instead of\n // the theme foreground. Toggled from Super Settings.\n mirror_green_text: {\n key: \"mirror_green_text\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n debug_navigation_history: {\n key: \"debug_navigation_history\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n debug_core_status_bar: {\n key: \"debug_core_status_bar\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Mentra Nex feature flags (off by default; toggled from Nex Developer Settings).\n // When on, the Nex display skips ASCII-only text sanitization so CJK/Chinese\n // captions render on glasses. Synced to the Bluetooth SDK via BLUETOOTH_SETTING_KEYS.\n nex_chinese_captions: {\n key: \"nex_chinese_captions\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // When on, LC3 audio received from Nex glasses is played back (Android only).\n // Local-only dev toggle: defaults off and never synced to the cloud account\n // (saveOnServer: false); persists locally so it survives app restarts.\n // Key renamed from the legacy `nex_audio_playback` so stale server/local\n // values (saved back when this was saveOnServer:true) can't re-enable it.\n nex_lc3_audio_playback: {\n key: \"nex_lc3_audio_playback\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Passive conversation memory: when on, the runtime persists every FINAL\n // transcript into the shared user-scoped MemoryStore (Settings > Memory),\n // independent of which miniapps are running or subscribed. Off = nothing is\n // written; existing history is kept until the user clears it. Device-local\n // only (saveOnServer: false) — the timeline itself never leaves the phone,\n // so the switch that governs it shouldn't either. Defaults ON to preserve\n // the behavior the Assistant miniapp previously provided.\n memory_save_conversations: {\n key: \"memory_save_conversations\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n china_deployment: {\n key: \"china_deployment\",\n defaultValue: () => (process.env.EXPO_PUBLIC_DEPLOYMENT_REGION === \"china\" ? true : false),\n override: () => (process.env.EXPO_PUBLIC_DEPLOYMENT_REGION === \"china\" ? true : false),\n writable: false,\n saveOnServer: false,\n persist: true,\n },\n // Hard privacy stance (Settings > Privacy): when true the app never talks to\n // Glassly cloud at all — the CloudClient is not constructed, so the runtime\n // websocket, cloud STT/TTS, managed photo/stream uploads, and report uploads\n // all go away with it. Distinct from `offline_mode`, which is a transient\n // \"I'm offline right now\" app-grid filter the user flips from Speech; this\n // one is a durable choice that survives reconnecting to a good network.\n // Device-local by design: a \"don't use the cloud\" preference must not itself\n // be uploaded to the cloud, so saveOnServer stays false. Not in\n // BLUETOOTH_SETTING_KEYS — glasses firmware has no use for it.\n disable_cloud: {\n key: \"disable_cloud\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // In-app disclosure of which third parties receive user data (App Store\n // 5.1.2(i)). `_version` is the AI_DATA_CONSENT_VERSION the user last saw\n // and `_agreed` is their answer. Declining turns disable_cloud on. The\n // screen is part of first onboarding only. Device-local: consent is a\n // property of this install, and logout's resetAllLocal() clears it so the\n // next account is asked afresh.\n ai_data_consent_version: {\n key: \"ai_data_consent_version\",\n defaultValue: () => 0,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n ai_data_consent_agreed: {\n key: \"ai_data_consent_agreed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // The user chose \"Continue without an account\" on the login screen. Boot\n // treats no-session + this flag as guest mode (cloud disabled, no token\n // exchange). Signing in clears it. Device-local like disable_cloud; logout's\n // resetAllLocal() drops it so the login screen offers Skip again.\n login_skipped: {\n key: \"login_skipped\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Cloud endpoint OVERRIDES. Empty = no override; cloudClient's resolveUrl\n // owns the full precedence (override -> env -> Metro-derived dev default).\n // The value may be an explicit URL or the METRO_AUTO sentinel (\"my dev\n // laptop\", resolved live from Metro so it survives network changes). Never\n // bake an env var or a personal LAN IP into the default here: that makes the\n // override branch always-truthy and strands devs on a stale address.\n cloud_core_url: {\n key: \"cloud_core_url\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n resetOnBuildEnvChange: true,\n },\n cloud_runtime_url: {\n key: \"cloud_runtime_url\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n resetOnBuildEnvChange: true,\n },\n // Bookmarked Cloud endpoint pairs. Each entry is {label, coreUrl,\n // runtimeUrl} — core + runtime are saved together because they are always\n // applied as a matched set (presets fill both; Save & Test verifies both).\n saved_cloud_url_pairs: {\n key: \"saved_cloud_url_pairs\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // User-supplied Soniox API key (Settings > Keys). Non-empty enables\n // phone -> Soniox direct transcription: audio streams from the device to\n // Soniox and transcription/translation subscriptions are withheld from the\n // cloud. Device-local by design — the key must never sync to a server\n // (saveOnServer: false) and must never ride BLE to glasses (do NOT add to\n // bluetoothSettingKeys).\n soniox_api_key: {\n key: \"soniox_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // User-supplied Mapbox access token (Settings > Keys). The app ships no\n // baked Mapbox key: every consumer resolves this key first, else the public\n // render token served by Glassly Cloud at runtime (MapboxTokenService) —\n // and with the cloud disabled this key is the ONLY token source, by\n // design. The `_api_key`\n // suffix is load-bearing: diagnosticContext redacts settings by that suffix,\n // so renaming would leak the key into bug reports. Device-local by design —\n // never synced to a server (saveOnServer: false) and never on BLE (do NOT\n // add to bluetoothSettingKeys).\n mapbox_api_key: {\n key: \"mapbox_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // User-supplied AI/voice provider keys (Settings > API Keys). Not consumed\n // by the app itself — they exist so miniapps declaring the API_KEYS manifest\n // permission can read them via session.keys.get() (see\n // MINIAPP_READABLE_API_KEYS in LocalMiniappRuntime; mapbox is also readable\n // there, soniox is not). Same invariants as the other provider keys: the\n // `_api_key` suffix is load-bearing (diagnosticContext redacts by suffix),\n // device-local by design — never synced to a server (saveOnServer: false)\n // and never on BLE (do NOT add to bluetoothSettingKeys).\n anthropic_api_key: {\n key: \"anthropic_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n gemini_api_key: {\n key: \"gemini_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n openai_api_key: {\n key: \"openai_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n elevenlabs_api_key: {\n key: \"elevenlabs_api_key\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Per-tier model picks for session.ai completions (Settings > AI Models).\n // Miniapps request a TIER (\"quick\"/\"balanced\"/\"frontier\"), never a\n // provider/model; these settings are how the user overrides what each tier\n // resolves to. Value is \"auto\" (pick by which provider keys are saved — see\n // AiTierResolution) or \"<provider>:<model>\" from the curated registry.\n // Device-local: the mapping only matters to this phone's direct/cloud calls.\n ai_model_quick: {\n key: \"ai_model_quick\",\n defaultValue: () => \"auto\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n ai_model_balanced: {\n key: \"ai_model_balanced\",\n defaultValue: () => \"auto\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n ai_model_frontier: {\n key: \"ai_model_frontier\",\n defaultValue: () => \"auto\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Developer override for the ASG OTA manifest URL. null/empty = no override;\n // the normal selection applies (legacy-glasses gate, EXPO_PUBLIC_ASG_OTA_VERSION_URL,\n // glasses-reported URL, then production). See resolveOtaManifestUrl.\n ota_version_url: {\n key: \"ota_version_url\",\n defaultValue: () => null,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n saved_ota_version_urls: {\n key: \"saved_ota_version_urls\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n reconnect_on_app_foreground: {\n key: \"reconnect_on_app_foreground\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n location_tier: {key: \"location_tier\", defaultValue: () => \"\", writable: true, saveOnServer: true, persist: true},\n // Volatile bearer synced to Bluetooth for glasses-side Cloud calls. The\n // key name is kept for BLE compatibility, but the value must never be loaded\n // from or saved to the legacy Cloud V1 settings store.\n core_token: {key: \"core_token\", defaultValue: () => \"\", writable: true, saveOnServer: false, persist: false},\n auth_email: {key: \"auth_email\", defaultValue: () => \"\", writable: true, saveOnServer: false, persist: true},\n // Pairing identity is per-phone, not per-account: two phones on one account\n // can be paired to different glasses, so none of these keys may sync to the\n // server (saveOnServer: false — a stale server copy resurrecting a local\n // pairing identity is exactly the desync this group's flags prevent).\n //\n // Two-phase identity: pending_wearable is the model the user last STARTED\n // pairing (written at selection, rendered as a finish-pairing card);\n // default_wearable + device_name + device_address are only promoted by the\n // native layer when pairing actually succeeds (handleDeviceReady).\n // pending_wearable persists so an abandoned selection still shows its\n // finish-pairing card after an app restart.\n pending_wearable: {\n key: \"pending_wearable\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n default_wearable: {\n key: \"default_wearable\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n device_name: {\n key: \"device_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n device_address: {\n key: \"device_address\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n project_name: {\n key: \"project_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n // Latched true the first time the identity projects as paired to real\n // (non-simulated) glasses; never cleared, so forgetting the glasses keeps\n // what it unlocked (the Store). Per-phone like the identity it derives from.\n has_paired_glasses: {\n key: \"has_paired_glasses\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n default_controller: {\n key: \"default_controller\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n // Display name of the keyboard the glasses remember (G2 Glassly CFW). The\n // native bridge owns the address/bond; this only keeps the home card and\n // settings row populated before the glasses connect, like default_controller.\n keyboard_name: {\n key: \"keyboard_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n pending_controller: {\n key: \"pending_controller\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n controller_device_name: {\n key: \"controller_device_name\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n controller_address: {\n key: \"controller_address\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n nativeAuthoritative: true,\n },\n // ui state:\n home_background: {\n key: \"home_background\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n theme_preference: {\n key: \"theme_preference\",\n defaultValue: () => \"system\",\n // override: () => \"light\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n settings_access_count: {\n key: \"settings_access_count\",\n defaultValue: () => 0,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n show_advanced_settings: {\n key: \"show_advanced_settings\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n onboarding_completed: {\n key: \"onboarding_completed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n onboarding_live_completed: {\n key: \"onboarding_live_completed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n onboarding_os_completed: {\n key: \"onboarding_os_completed\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n has_ever_activated_app: {\n key: \"has_ever_activated_app\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n\n // Bluetooth SDK settings:\n sensing_enabled: {\n key: \"sensing_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n power_saving_mode: {\n key: \"power_saving_mode\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // The Glassly App intentionally preserves Mentra Live's historical VAD-on\n // product default. Standalone public Bluetooth SDK hosts default VAD off so\n // their microphone audio remains continuous.\n voice_activity_detection_enabled: {\n key: \"voice_activity_detection_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Mentra Live center-mic loudness / \"Barrier\" gate (cs_swit type 10). Default on.\n loudness_gate_enabled: {\n key: \"loudness_gate_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // G2 Glassly CFW microphone volume gate (revision 40+): the temples stop\n // streaming audio while nothing reaches the threshold. Default on; shown only\n // when the connected firmware reports the capability.\n volume_gate_enabled: {\n key: \"volume_gate_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // dBFS RMS a 50 ms chunk must reach to count as sound.\n volume_gate_threshold_db: {\n key: \"volume_gate_threshold_db\",\n defaultValue: () => -45,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Quiet time before the gate closes.\n volume_gate_hold_ms: {\n key: \"volume_gate_hold_ms\",\n defaultValue: () => 5000,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Minimum time the gate stays open once sound opens it.\n volume_gate_min_open_ms: {\n key: \"volume_gate_min_open_ms\",\n defaultValue: () => 10000,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n always_on_status_bar: {\n key: \"always_on_status_bar\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Legacy cloud/mobile setting name. Locally it maps to glasses-side Voice Activity Detection.\n bypass_vad_for_debugging: {\n key: \"bypass_vad_for_debugging\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n bypass_audio_encoding_for_debugging: {\n key: \"bypass_audio_encoding_for_debugging\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n metric_system: {\n key: \"metric_system\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n twelve_hour_time: {\n key: \"twelve_hour_time\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n enforce_local_transcription: {\n key: \"enforce_local_transcription\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // \"Recognize my voice\" (Settings > Voice Recognition). Drives the on-device\n // SpeakerIdEngine. Device-local by design — voice profiles are biometric\n // data, so nothing about this feature syncs to the server.\n speaker_id_enabled: {\n key: \"speaker_id_enabled\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // LC3 audio quality setting (frame size in bytes)\n // 20 = 16kbps (low bandwidth), 40 = 32kbps (balanced), 60 = 48kbps (high quality)\n lc3_frame_size: {\n key: \"lc3_frame_size\",\n defaultValue: () => 60,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n preferred_mic: {\n key: \"preferred_mic\",\n defaultValue: () => \"auto\",\n writable: true,\n indexer: (key: string) => {\n const glasses = useSettingsStore.getState().getSetting(SETTINGS.default_wearable.key)\n if (glasses) {\n return `${key}:${glasses}`\n }\n return key\n },\n saveOnServer: true,\n persist: true,\n },\n screen_disabled: {\n key: \"screen_disabled\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // glasses settings:\n contextual_dashboard: {\n key: \"contextual_dashboard\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Debug escape hatch: G2 scene rendering through the Glassly CFW\n // direct-framebuffer path (rasterized mode-3 frames into the carrier).\n // ON by default — the working production path on CFW glasses; OFF falls\n // back to stock EvenHub containers for isolating renderer regressions.\n // Synced to the Bluetooth SDK via BLUETOOTH_SETTING_KEYS; the SGC re-reads\n // it per frame, but a glasses reconnect gives the cleanest switch.\n // Device-local debug knob, so not saved on the server.\n cfw_scene_renderer: {\n key: \"cfw_scene_renderer\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: ask Glassly CFW glasses (revision 26+) for the 7.5 ms / latency-0\n // fast BLE connection profile with slow mode suppressed, instead of the\n // stock 15-30 ms link and its one-minute slow-mode timer. OFF by default:\n // the fast link costs battery whenever the phone is merely connected, and\n // the phone must agree to the interval. Synced to the Bluetooth SDK, which\n // sends the control to both lenses and re-sends it on every CFW detection.\n // Device-local debug knob, so not saved on the server.\n cfw_fast_ble: {\n key: \"cfw_fast_ble\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: the G2's G2PERF display performance lines (a sample per busy\n // second, plus stalls) in the console and the log buffer bug reports carry.\n // OFF by default: they crowd out everything else in the ten-minute buffer.\n // Synced to the Bluetooth SDK, which keeps counting either way and only\n // logs while this is on. Device-local debug knob, so not saved on the server.\n g2_perf_logs: {\n key: \"g2_perf_logs\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: route the R1 ring through the glasses (advStart + RING_CONNECT_INFO,\n // events forwarded by the CFW) instead of the phone link. OFF by default:\n // the ring is a direct phone link whether or not a G2 is paired, which is\n // how the Faceclaw reference client runs it. Synced to the Bluetooth SDK,\n // which re-routes a connected ring on change. Device-local debug knob, so\n // not saved on the server.\n ring_via_glasses: {\n key: \"ring_via_glasses\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Meta Neural Band: the air mouse streams the band's orientation at 128 Hz, so it\n // stays off unless asked for. The band side is pushed when the band connects.\n neural_band_air_mouse: {\n key: \"neural_band_air_mouse\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Which wrist wears the band: flips the air mouse's forearm axis and is written\n // to the band's own hand setting on connect.\n neural_band_hand: {\n key: \"neural_band_hand\",\n defaultValue: () => \"right\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Maximum rate at which display updates leave the phone for the glasses.\n // The Bluetooth SDK paces every scene frame and legacy layout to this,\n // coalescing faster updates last-wins; clears bypass it. No effect on G2\n // custom firmware, whose driver coalesces off the link itself. Device-local\n // debug knob (2..20), so not saved on the server.\n display_max_fps: {\n key: \"display_max_fps\",\n defaultValue: () => 8,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Master switch for the Scene API dashboard on G2 custom firmware\n // (the dashboard's eligibility). Off leaves an eligible device on the\n // native head-up behavior. Device-local debug knob, so not saved on the\n // server.\n custom_dashboard_enabled: {\n key: \"custom_dashboard_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: time each dashboard open (head-up / double tap → glasses frame)\n // and post the stage timeline as a phone notification. Persisted so a\n // slow first open after an app restart is still caught. Device-local.\n debug_dashboard_open_timing: {\n key: \"debug_dashboard_open_timing\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug escape hatch: enter the G2's firmware-rendered navigation mode on\n // custom firmware too. Off by default: CFW draws the navigation miniapp's\n // own HUD through the scene canvas and reads session.compass directly, so\n // native nav mode is reserved for stock firmware. Device-local debug knob,\n // so not saved on the server.\n cfw_native_navigation: {\n key: \"cfw_native_navigation\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Debug: open miniapps from their last screenshot, fading straight into the\n // app. Off shows the splash instead. Device-local, default on.\n use_screenshot_transition: {\n key: \"use_screenshot_transition\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Gesture-dots debug indicator: flash a glyph on the glasses when a touch\n // gesture is received while the display is empty. Works on any\n // scene-capable device, not only CFW. Device-local debug knob, default off.\n gesture_dots: {\n key: \"gesture_dots\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n head_up_angle: {key: \"head_up_angle\", defaultValue: () => 45, writable: true, saveOnServer: true, persist: true},\n brightness: {key: \"brightness\", defaultValue: () => 50, writable: true, saveOnServer: true, persist: true},\n auto_brightness: {\n key: \"auto_brightness\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n dashboard_height: {\n key: \"dashboard_height\",\n defaultValue: () => 4,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n dashboard_depth: {\n key: \"dashboard_depth\",\n defaultValue: () => 2,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n menu_apps: {\n key: \"menu_apps\",\n defaultValue: () => null,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n calendar_events: {\n key: \"calendar_events\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n // button settings\n // Legacy persisted/cloud key; hardware behavior is now controlled by gallery_mode plus capture settings.\n button_mode: {key: \"button_mode\", defaultValue: () => \"photo\", writable: true, saveOnServer: true, persist: true},\n button_photo_size: {\n key: \"button_photo_size\",\n defaultValue: () => \"max\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n button_video_settings: {\n key: \"button_video_settings\",\n defaultValue: () => ({width: 1920, height: 1080, fps: 30}),\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n button_max_recording_time: {\n key: \"button_max_recording_time\",\n defaultValue: () => 10,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n camera_fov: {\n key: \"camera_fov\",\n defaultValue: () => ({fov: 118, roi_position: 0}),\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n media_post_processing: {\n key: \"media_post_processing\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n\n // time zone settings\n time_zone: {\n key: \"time_zone\",\n defaultValue: () => \"\",\n writable: true,\n override: () => {\n const override = useSettingsStore.getState().getSetting(SETTINGS.time_zone_override.key)\n if (override) {\n return override\n }\n return getTimeZone()\n },\n saveOnServer: true,\n persist: true,\n },\n time_zone_override: {\n key: \"time_zone_override\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // offline applets\n offline_mode: {key: \"offline_mode\", defaultValue: () => false, writable: true, saveOnServer: true, persist: true},\n // Runtime flag: coordinator flips this on when cloud STT has failed and fallback is active.\n // Native GlassesStore watches it to gate PCM 鈫?Sherpa feeding. Not user-facing.\n local_stt_fallback_active: {\n key: \"local_stt_fallback_active\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n // Runtime flag: why the coordinator activated local STT (\"\" while inactive).\n // Values are LocalSttFallbackReason strings. UI-only; native ignores it.\n local_stt_fallback_reason: {\n key: \"local_stt_fallback_reason\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n gallery_mode: {key: \"gallery_mode\", defaultValue: () => true, writable: true, saveOnServer: true, persist: true},\n gallery_sync_explained: {\n key: \"gallery_sync_explained\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n offline_camera_running: {\n key: \"offline_camera_running\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // offline translation\n offline_translation_running: {\n key: \"offline_translation_running\",\n defaultValue: () => false,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n offline_translation_source: {\n key: \"offline_translation_source\",\n defaultValue: () => \"en\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n offline_translation_target: {\n key: \"offline_translation_target\",\n defaultValue: () => \"es\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // button action settings\n default_button_action_enabled: {\n key: \"default_button_action_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n default_button_action_app: {\n key: \"default_button_action_app\",\n defaultValue: () => \"com.glassly.camera\",\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // notifications\n notifications_blocklist: {\n key: \"notifications_blocklist\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Apps the connected glasses reported posting notifications (bundle/package\n // id + display name). Backs the filter UI where the phone cannot enumerate\n // apps itself and the allowlist pushed to firmware that filters on-glass.\n notification_seen_apps: {\n key: \"notification_seen_apps\",\n defaultValue: () => [],\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // Notification display, any glasses: firmware that presents notifications\n // itself receives these as a GlassesNotificationConfig; the engine's own\n // viewer reads the same four. Master switch first.\n notifications_enabled: {\n key: \"notifications_enabled\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Show a popup when a notification arrives; off keeps history only.\n notifications_popups: {\n key: \"notifications_popups\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Popup duration in seconds; 0 lets the firmware or viewer pick its default.\n notifications_popup_seconds: {\n key: \"notifications_popup_seconds\",\n defaultValue: () => 5,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Hold popups while another glasses feature (navigation, a miniapp) is on screen.\n notifications_hold_during_apps: {\n key: \"notifications_hold_during_apps\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Experimental, any glasses: hold notification popups while the phone is in\n // use (unlocked, or the Glassly App foregrounded), so a notification isn't\n // shown on the glasses and the phone screen at once. The dashboard reducer\n // reads it with PhoneActivity when a notification posts; on iOS\n // PhoneNotificationsSync also folds it into the stock G2 firmware's\n // auto_display, which pops notifications up on its own.\n notifications_ignore_while_active: {\n key: \"notifications_ignore_while_active\",\n defaultValue: () => true,\n writable: true,\n saveOnServer: true,\n persist: true,\n },\n // Cached required version from server - used to enforce updates even when offline\n cached_required_version: {\n key: \"cached_required_version\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n // OTA update dismissal - stores the version code user dismissed (not persisted so resets on app restart)\n dismissed_ota_version: {\n key: \"dismissed_ota_version\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: false,\n },\n // Contact email for feedback (persisted for Apple private relay users)\n contact_email: {\n key: \"contact_email\",\n defaultValue: () => \"\",\n writable: true,\n saveOnServer: false,\n persist: true,\n },\n} as const\n\nexport const OFFLINE_APPLETS: string[] = [\"com.glassly.livecaptions\", \"com.glassly.camera\"]\n\n// These settings are automatically synced to the Bluetooth SDK.\n// Keep this list hardware-facing; app/UI/cloud-only preferences should stay in JS/Crust.\nexport const BLUETOOTH_SETTING_KEYS: string[] = [\n // Bluetooth settings:\n SETTINGS.sensing_enabled.key,\n SETTINGS.power_saving_mode.key,\n SETTINGS.voice_activity_detection_enabled.key,\n SETTINGS.loudness_gate_enabled.key,\n SETTINGS.volume_gate_enabled.key,\n SETTINGS.volume_gate_threshold_db.key,\n SETTINGS.volume_gate_hold_ms.key,\n SETTINGS.volume_gate_min_open_ms.key,\n SETTINGS.lc3_frame_size.key,\n SETTINGS.preferred_mic.key,\n SETTINGS.screen_disabled.key,\n SETTINGS.auth_email.key,\n SETTINGS.core_token.key,\n // glasses settings (contextual_dashboard is phone-side policy now — native\n // no longer reads it):\n SETTINGS.head_up_angle.key,\n SETTINGS.brightness.key,\n SETTINGS.auto_brightness.key,\n SETTINGS.dashboard_height.key,\n SETTINGS.dashboard_depth.key,\n SETTINGS.menu_apps.key,\n SETTINGS.calendar_events.key,\n SETTINGS.cfw_scene_renderer.key,\n SETTINGS.cfw_fast_ble.key,\n SETTINGS.g2_perf_logs.key,\n SETTINGS.ring_via_glasses.key,\n SETTINGS.display_max_fps.key,\n SETTINGS.twelve_hour_time.key,\n SETTINGS.metric_system.key,\n // button:\n SETTINGS.button_photo_size.key,\n // Legacy MentraLive native code reads the object form when syncing video settings.\n SETTINGS.button_video_settings.key,\n SETTINGS.button_max_recording_time.key,\n SETTINGS.camera_fov.key,\n // device / pairing:\n SETTINGS.pending_wearable.key,\n SETTINGS.default_wearable.key,\n SETTINGS.device_name.key,\n SETTINGS.device_address.key,\n SETTINGS.project_name.key,\n SETTINGS.default_controller.key,\n SETTINGS.pending_controller.key,\n SETTINGS.controller_device_name.key,\n SETTINGS.controller_address.key,\n // offline applets:\n SETTINGS.offline_mode.key,\n // Runtime flag flipped by LocalSttFallbackCoordinator. Native reads it from\n // GlassesStore to gate PCM 鈫?Sherpa feeding in handlePcm and to keep the\n // mic on while local STT is the active engine.\n SETTINGS.local_stt_fallback_active.key,\n SETTINGS.gallery_mode.key,\n // Mentra Nex feature flags:\n SETTINGS.nex_chinese_captions.key,\n SETTINGS.nex_lc3_audio_playback.key,\n]\n\n// Pairing identity is NATIVE-authoritative: the native layer writes it on\n// pairing success (handleDeviceReady) / forget and echoes it down via\n// save_setting; JS persists those echoes. JS鈫抧ative, identity travels ONLY in\n// the explicit full seeds (device-store hydration, pre-connect push,\n// post-demotion re-push) — never in the change-push subscription. Relaying an\n// echoed identity change back up would make the sync bidirectional with loop\n// gain 1: two identity values in flight (e.g. a boot demotion crossing a\n// native promotion) then chase each other through push鈫抋pply鈫抏cho鈫抪ush\n// forever, flapping the UI.\n//\n// Derived from the `nativeAuthoritative` descriptor flag (not maintained as a\n// parallel list) so the change-push exclusion in GlassesSettingsSync can't\n// drift from the setting declarations.\nexport const PAIRING_IDENTITY_KEYS: string[] = Object.values(SETTINGS)\n .filter((setting) => setting.nativeAuthoritative)\n .map((setting) => setting.key)\n\n// const PER_GLASSES_SETTINGS_KEYS: string[] = [SETTINGS.preferred_mic.key]\n\nexport interface SettingsState {\n // Settings values\n settings: Record<string, any>\n // Loading states\n isInitialized: boolean\n // Actions\n setSetting: (key: string, value: any, updateServer?: boolean) => AsyncResult<void, Error>\n setManyLocally: (settings: Record<string, any>) => AsyncResult<void, Error>\n getSetting: (key: string) => any\n // loadSetting: (key: string) => AsyncResult<void, Error>\n loadAllSettings: () => AsyncResult<void, Error>\n // Utility methods\n getBluetoothSettings: () => Record<string, any>\n resetAllSettingsLocally: () => void\n}\n\nconst getDefaultSettings = () =>\n Object.keys(SETTINGS).reduce((acc, key) => {\n acc[key] = SETTINGS[key].defaultValue()\n return acc\n }, {} as Record<string, any>)\n\n// Single-flight for loadAllSettings: the host fires it at module load and\n// engine.start()'s device-store hydration awaits it — without the memo the\n// second caller runs a duplicate full disk load while the first is still in\n// flight. Cleared on failure so a later call can retry.\nlet loadAllSettingsInFlight: AsyncResult<void, Error> | null = null\n\nfunction printableSettingValue(key: string, value: unknown): string {\n return key.includes(\"token\") || key.includes(\"email\") || key.includes(\"api_key\")\n ? \"<redacted>\"\n : JSON.stringify(value)\n}\n\nexport const useSettingsStore = create<SettingsState>()(\n subscribeWithSelector((set, get) => ({\n settings: getDefaultSettings(),\n isInitialized: false,\n loadingKeys: new Set(),\n setSetting: (key: string, value: any, _updateServer = true): AsyncResult<void, Error> => {\n return Res.try_async(async () => {\n const setting = SETTINGS[key]\n const originalKey = key\n\n if (!setting) {\n throw new Error(`SETTINGS: SET: ${originalKey} is not a valid setting!`)\n }\n\n if (setting.indexer) {\n key = setting.indexer(originalKey)\n }\n\n if (!setting.writable) {\n throw new Error(`SETTINGS: ${originalKey} is not writable!`)\n }\n\n // Update store immediately for optimistic UI\n console.log(`SETTINGS: SET: ${key} = ${printableSettingValue(key, value)}`)\n set((state) => ({\n settings: {...state.settings, [key]: value},\n }))\n\n if (setting.persist) {\n let res = await storage.save(key, value)\n if (res.is_error()) {\n throw new Error(`SETTINGS: couldn't save setting to storage: ${res.error}`)\n }\n\n // Cloud V1 per-change server sync removed with the V1 ripout (issue\n // #3392). Settings are local-first until a V2 sync lands; the\n // saveOnServer flags are retained as intent markers for that work.\n }\n })\n },\n getSetting: (key: string) => {\n const state = get()\n const originalKey = key\n const setting = SETTINGS[originalKey]\n\n if (!setting) {\n console.error(`SETTINGS: GET: ${originalKey} is not a valid setting!`)\n return undefined\n }\n\n if (setting.override) {\n let override = setting.override()\n if (override !== undefined) {\n return override\n }\n }\n\n if (setting.indexer) {\n key = setting.indexer(originalKey)\n }\n\n // console.log(`GET SETTING: ${key} = ${state.settings[key]}`)\n\n try {\n const raw = state.settings[key] ?? SETTINGS[originalKey].defaultValue()\n return raw\n } catch (e) {\n // for dynamically created settings, we need to create a new setting in SETTINGS:\n console.log(`Failed to get setting, creating new setting:(${key}):`, e)\n SETTINGS[key] = {key: key, defaultValue: () => undefined, writable: true, saveOnServer: false, persist: true}\n return SETTINGS[key].defaultValue()\n }\n },\n // batch update many settings from the server:\n setManyLocally: (settings: Record<string, any>): AsyncResult<void, Error> => {\n return Res.try_async(async () => {\n const settingsToLoad: Record<string, any> = {}\n // if a setting should not persist, don't load it:\n for (const [key, value] of Object.entries(settings)) {\n const stg: Setting | undefined = SETTINGS[key.toLowerCase()]\n if (!stg) {\n continue\n }\n if (!stg.persist) {\n continue\n }\n settingsToLoad[key.toLowerCase()] = value\n }\n // console.log(\"SETTINGS: SET MANY LOCALLY: \", settingsToLoad)\n\n set((state) => ({\n settings: {...state.settings, ...settingsToLoad},\n }))\n\n // save to storage:\n await Promise.all(Object.entries(settingsToLoad).map(([key, value]) => storage.save(key, value)))\n })\n },\n // loads any preferences that have been changed from the default and saved to DISK!\n loadAllSettings: (): AsyncResult<void, Error> => {\n console.log(\"SETTINGS: loadAllSettings()\")\n if (loadAllSettingsInFlight) {\n return loadAllSettingsInFlight\n }\n const inFlight = Res.try_async(async () => {\n const state = get()\n let loadedSettings: Record<string, any> = {}\n\n if (state.isInitialized) {\n return undefined\n }\n\n for (const setting of Object.values(SETTINGS)) {\n // if the settings should not persist, don't load it:\n if (!setting.persist) {\n continue\n }\n\n // load all subkeys for an indexed setting:\n if (setting?.indexer) {\n console.log(`SETTINGS: LOAD: ${setting.key} with indexer!`)\n\n let res: Result<Record<string, unknown>, Error> = storage.loadSubKeys(setting.key)\n if (res.is_error()) {\n console.log(`SETTINGS: LOAD: ${setting.key}`, res.error)\n continue\n }\n\n let subKeys: Record<string, unknown> = res.value\n console.log(`SETTINGS: LOAD: ${setting.key} subkeys are set!`, subKeys)\n loadedSettings = {...loadedSettings, ...subKeys}\n continue\n }\n\n let res = storage.load<any>(setting.key)\n if (res.is_error()) {\n console.log(`SETTINGS: LOAD: ${setting.key} is not set!`, res.error)\n // this setting isn't set from the default, so we don't load anything\n continue\n }\n // normal key:value pair:\n let value = res.value\n // res.value IS the stored value; logging value.value printed\n // \"undefined\" for every loaded setting and disguised present\n // values as missing. Redact token- and email-bearing keys: console\n // logs are uploaded in bug-report artifacts (same keys\n // diagnosticContext's SENSITIVE_SETTINGS_KEYS strips, minus an\n // import that would cycle stores <-> utils).\n console.log(`SETTINGS: LOAD: ${setting.key} = ${printableSettingValue(setting.key, value)}`)\n loadedSettings[setting.key] = value\n }\n\n // console.log(\"##############################################\")\n // console.log(loadedSettings)\n // console.log(\"##############################################\")\n\n set((state) => ({\n isInitialized: true,\n settings: {...state.settings, ...loadedSettings},\n }))\n\n // This hidden debug switch originally shipped default-off while the\n // notification-listener cold-start ANR was being investigated. Now\n // that the listener runs in its own guarded process, migrate existing\n // installs to the new default once; later explicit debug changes still\n // persist normally.\n // Reset the cloud backend override when the build's environment changes.\n //\n // cloud_core_url / cloud_runtime_url are persist:true and outrank both\n // the build's env and the compiled default (see resolveUrl in\n // cloudClient.ts). That is what we want inside one environment: a\n // developer's METRO_AUTO pin should survive a rebuild. It is wrong\n // across environments.\n //\n // The concrete case is an install that moves BETWEEN environments: an\n // internal tester running a dev build with a pinned override who then\n // installs the store build. The override outranks that build's prod\n // URLs, so without this they keep talking to dev with nothing\n // surfacing it.\n //\n // Note what this deliberately does NOT do, because the distinction is\n // easy to get backwards. TestFlight and the App Store receive the SAME\n // binary, so promotion does not change EXPO_PUBLIC_BUILD_ENV and this\n // reset never fires on it. Promotion is safe for a different reason:\n // the publishing lane bakes the selected release cloud environment, and\n // production promotes the already-tested binary. The same holds for\n // Android beta-track to production.\n //\n // The residual gap is therefore an override pinned while already on a\n // prod-labelled build, which no label comparison can see. That is a\n // deliberate limit: reaching it means typing a URL into a dev-only\n // screen, VersionInfo renders the current value, and the same screen\n // clears it.\n //\n // Comparing the baked EXPO_PUBLIC_BUILD_ENV against the last one seen\n // on this device covers those environment switches and fresh installs\n // without touching the setting write path. A reinstall needs no\n // handling: it drops the marker and the override together\n // (android:allowBackup=\"false\", and iOS deletes the container).\n const BUILD_ENV_KEY = \"settings.lastBuildEnv\"\n const buildEnv = (process.env.EXPO_PUBLIC_BUILD_ENV ?? \"dev\").trim() || \"dev\"\n const lastBuildEnv = storage.load<string>(BUILD_ENV_KEY)\n const previousBuildEnv = lastBuildEnv.is_error() ? undefined : lastBuildEnv.value\n if (previousBuildEnv !== buildEnv) {\n // Clear when there is no marker yet, not just on a recorded change.\n // The first build carrying this code meets every existing install\n // with previousBuildEnv === undefined, and those are exactly the\n // installs that may hold an override set before the pin existed --\n // the population this is here to repair. Treating \"no marker\" as a\n // fresh install would record the marker and never look again. A\n // genuinely fresh install has nothing persisted, so the clear below\n // writes each default over itself and costs nothing.\n //\n // Driven by the descriptors rather than a hardcoded key list, so a\n // setting that needs this behaviour declares it in one place and\n // cannot be missed here.\n const scoped = Object.values(SETTINGS).filter((setting) => setting.resetOnBuildEnvChange)\n console.log(\n `SETTINGS: build env ${previousBuildEnv ?? \"(none recorded)\"} -> ${buildEnv}, ` +\n `clearing ${scoped.length} build-scoped setting(s)`,\n )\n let allCleared = true\n for (const setting of scoped) {\n const cleared = await get().setSetting(setting.key, setting.defaultValue(), false)\n if (cleared.is_error()) {\n allCleared = false\n console.log(`SETTINGS: could not clear ${setting.key}:`, cleared.error)\n }\n }\n // Advance the marker only once the reset actually landed. Recording\n // it after a failed write would retire the retry and leave the stale\n // override for the life of the install; leaving it unset costs one\n // repeated attempt per launch until a write succeeds.\n if (allCleared) {\n storage.save(BUILD_ENV_KEY, buildEnv)\n }\n }\n\n const NOTIFICATION_LISTENER_MIGRATION_KEY = \"migration:android_notification_listener_default_on_v1\"\n const notificationListenerMigrationDone = storage.load<boolean>(NOTIFICATION_LISTENER_MIGRATION_KEY)\n if (notificationListenerMigrationDone.is_error() || !notificationListenerMigrationDone.value) {\n const result = await get().setSetting(SETTINGS.android_notification_listener_enabled.key, true, false)\n if (result.is_error()) {\n console.log(\"SETTINGS: notification listener migration failed:\", result.error)\n } else {\n storage.save(NOTIFICATION_LISTENER_MIGRATION_KEY, true)\n }\n }\n\n // One-time migration: force android_blur=false for existing users.\n // The setting's default is already false; this migration covers users\n // who explicitly opted into Android blur effects before we discovered\n // they're a major source of frame drops on cheap Android phones.\n // The dimezisBlurViewSdk31Plus blur each costs ~5-10ms/frame; with\n // multiple blurs on home (top fade + AppSwitcherButton x2) a low-end\n // device misses the 16ms budget consistently. Users can turn it back\n // on under Settings 鈫?Appearance once we've optimized further.\n //\n // The setSetting call also pushes to the server (saveOnServer: true)\n // so the server-stored value flips too — otherwise the next sync\n // from the user's server-stored prefs would re-enable blur.\n // Best-effort: a server failure (offline, 5xx) shouldn't block boot;\n // we still mark the migration done locally so we don't loop.\n const MIGRATION_KEY = \"migration:android_blur_default_false_v1\"\n const migrationDone = storage.load<boolean>(MIGRATION_KEY)\n if (migrationDone.is_error() || !migrationDone.value) {\n const current = get().getSetting(SETTINGS.android_blur.key)\n if (current === true) {\n const result = await get().setSetting(SETTINGS.android_blur.key, false, true)\n if (result.is_error()) {\n // Server push failed (offline / 5xx). Local storage was still\n // updated, so the user immediately gets the new behavior. The\n // server-side stale `true` will be overwritten the next time\n // the user opens Appearance settings and the auto-sync runs.\n console.log(\"SETTINGS: android_blur migration server-push failed:\", result.error)\n }\n }\n // Mark done unconditionally — even on server-push failure we don't\n // want to retry the migration on every boot. The local value is\n // already correct.\n storage.save(MIGRATION_KEY, true)\n }\n\n // The old camera default cropped the sensor to 102掳. Move existing\n // default-shaped values to the full 118掳 sensor once; named miniapp\n // requests for the 102掳 \"standard\" preset remain available.\n const CAMERA_FOV_MIGRATION_KEY = \"migration:camera_fov_full_sensor_v1\"\n const cameraFovMigrationDone = storage.load<boolean>(CAMERA_FOV_MIGRATION_KEY)\n if (cameraFovMigrationDone.is_error() || !cameraFovMigrationDone.value) {\n const current = get().getSetting(SETTINGS.camera_fov.key) as {fov?: number; roi_position?: number} | undefined\n let migrationSucceeded = true\n if (current?.fov === 102 && (current.roi_position ?? 0) === 0) {\n const result = await get().setSetting(SETTINGS.camera_fov.key, {fov: 118, roi_position: 0}, true)\n if (result.is_error()) {\n console.log(\"SETTINGS: camera FOV migration failed:\", result.error)\n migrationSucceeded = false\n }\n }\n // Unlike the blur migration above, a failed camera set may leave the\n // local value unchanged. Only mark this migration complete once the\n // desired value was applied so a transient failure retries on boot.\n if (migrationSucceeded) storage.save(CAMERA_FOV_MIGRATION_KEY, true)\n }\n })\n loadAllSettingsInFlight = inFlight\n void Promise.resolve(inFlight).then((result) => {\n if (result.is_error()) {\n loadAllSettingsInFlight = null\n }\n })\n return inFlight\n },\n getBluetoothSettings: () => {\n const state = get()\n // Device-model-filtered key set (wire v2): Mentra Live (no display) gets\n // the reduced MENTRA_LIVE_SETTING_KEYS; display glasses get the full set.\n const deviceModel = useGlassesStore.getState().deviceModel || state.getSetting(SETTINGS.default_wearable.key)\n const keys = getBluetoothSettingKeysForDevice(deviceModel, BLUETOOTH_SETTING_KEYS)\n const bluetoothSettings: Record<string, any> = {}\n for (const key of keys) {\n const value = state.getSetting(key)\n if (key === SETTINGS.core_token.key && (typeof value !== \"string\" || value.trim().length === 0)) {\n continue\n }\n bluetoothSettings[key] = value\n }\n return bluetoothSettings\n },\n resetAllSettingsLocally: () => {\n set((_state) => ({\n settings: getDefaultSettings(),\n isInitialized: true,\n }))\n },\n })),\n)\n\nexport const useSetting = <T = any>(key: string): [T, (value: T) => AsyncResult<void, Error>] => {\n const value = useSettingsStore((state) => state.getSetting(key))\n const setSetting = useSettingsStore((state) => state.setSetting)\n return [value, (newValue: T) => setSetting(key, newValue)]\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassly/engine",
|
|
3
|
-
"version": "0.3.3-beta.
|
|
3
|
+
"version": "0.3.3-beta.639",
|
|
4
4
|
"description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -97,17 +97,17 @@
|
|
|
97
97
|
"registry": "https://registry.npmjs.org/"
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
|
-
"@glassly/bluetooth-sdk": "0.3.3-beta.
|
|
101
|
-
"@glassly/cloud-client": "0.3.3-beta.
|
|
102
|
-
"@glassly/cloud-protocol": "0.3.3-beta.
|
|
103
|
-
"@glassly/crust": "0.3.3-beta.
|
|
104
|
-
"@glassly/miniapp": "0.3.3-beta.
|
|
100
|
+
"@glassly/bluetooth-sdk": "0.3.3-beta.639",
|
|
101
|
+
"@glassly/cloud-client": "0.3.3-beta.639",
|
|
102
|
+
"@glassly/cloud-protocol": "0.3.3-beta.639",
|
|
103
|
+
"@glassly/crust": "0.3.3-beta.639",
|
|
104
|
+
"@glassly/miniapp": "0.3.3-beta.639",
|
|
105
105
|
"buffer": "^6.0.3",
|
|
106
106
|
"events": "^3.3.0",
|
|
107
107
|
"react-native-marked": "8.1.1",
|
|
108
108
|
"semver": "^7.7.4",
|
|
109
109
|
"typesafe-ts": "^1.7.1",
|
|
110
|
-
"@glassly/llm-providers": "0.3.3-beta.
|
|
110
|
+
"@glassly/llm-providers": "0.3.3-beta.639"
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
113
113
|
"@glassly/llm-providers": "workspace:*",
|
package/src/facades/glasses.ts
CHANGED
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
import {useGlassesStore} from "../stores/glasses"
|
|
23
23
|
import {useSettingsStore, SETTINGS} from "../stores/settings"
|
|
24
24
|
import {hasDefaultDevice} from "../services/DeviceStoreHydration"
|
|
25
|
+
import micStateCoordinator from "../services/MicStateCoordinator"
|
|
25
26
|
import {projectPairingIdentity} from "../services/PairingIdentity"
|
|
26
27
|
import {isGlassesConnected, isGlassesReady} from "../services/GlassesReadiness"
|
|
27
28
|
import {pushAllBluetoothSettings} from "../services/GlassesSettingsSync"
|
|
@@ -34,6 +35,21 @@ import {getModelCapabilities, type DeviceTypes} from "../types"
|
|
|
34
35
|
import {glassesWifi} from "./glassesWifi"
|
|
35
36
|
import {glassesSettings} from "./glassesSettings"
|
|
36
37
|
|
|
38
|
+
/** Floor for the mic level readout; digital silence would otherwise be -Infinity. */
|
|
39
|
+
const MIC_LEVEL_FLOOR_DBFS = -120
|
|
40
|
+
|
|
41
|
+
/** RMS level of one s16le chunk in dBFS, on the volume gate's 32767 full scale. */
|
|
42
|
+
function pcmLevelDbfs(pcm: ArrayBuffer): number {
|
|
43
|
+
const samples = new Int16Array(pcm, 0, pcm.byteLength >> 1)
|
|
44
|
+
if (samples.length === 0) return MIC_LEVEL_FLOOR_DBFS
|
|
45
|
+
let sumSquares = 0
|
|
46
|
+
for (let i = 0; i < samples.length; i++) sumSquares += samples[i] * samples[i]
|
|
47
|
+
const rms = Math.sqrt(sumSquares / samples.length)
|
|
48
|
+
return Math.max(MIC_LEVEL_FLOOR_DBFS, 20 * Math.log10(rms / 32767))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let micLevelSubscriptions = 0
|
|
52
|
+
|
|
37
53
|
function projectStatus() {
|
|
38
54
|
const s = useGlassesStore.getState()
|
|
39
55
|
return {
|
|
@@ -295,7 +311,7 @@ export const glasses = {
|
|
|
295
311
|
setHand: (hand: "left" | "right"): Promise<void> => BluetoothSdk.neuralBandSetHand(hand),
|
|
296
312
|
},
|
|
297
313
|
|
|
298
|
-
// --- audio (glasses media-volume
|
|
314
|
+
// --- audio (glasses media-volume, own-app playback hint, live mic level) ---
|
|
299
315
|
audio: {
|
|
300
316
|
/** Read the glasses' current media volume. */
|
|
301
317
|
getMediaVolume: () => BluetoothSdk.getGlassesMediaVolume(),
|
|
@@ -303,6 +319,22 @@ export const glasses = {
|
|
|
303
319
|
setMediaVolume: (level: number) => BluetoothSdk.setGlassesMediaVolume(level),
|
|
304
320
|
/** Tell native whether THIS app is currently playing audio (for ducking). */
|
|
305
321
|
setOwnAppPlaying: (playing: boolean): Promise<void> => BluetoothSdk.setOwnAppAudioPlaying(playing),
|
|
322
|
+
/**
|
|
323
|
+
* Stream the active mic's level in dBFS, one reading per PCM chunk. Holds
|
|
324
|
+
* raw PCM open while subscribed, so the mic runs with no miniapp listening
|
|
325
|
+
* (and the G2 volume gate stays open).
|
|
326
|
+
*/
|
|
327
|
+
onMicLevel: (cb: (dbfs: number) => void): (() => void) => {
|
|
328
|
+
const owner = `mic_level_${++micLevelSubscriptions}`
|
|
329
|
+
micStateCoordinator.acquireHostPcm(owner)
|
|
330
|
+
const sub = BluetoothSdk.addListener("mic_pcm", (event: {pcm: ArrayBuffer}) => {
|
|
331
|
+
if (event?.pcm) cb(pcmLevelDbfs(event.pcm))
|
|
332
|
+
})
|
|
333
|
+
return () => {
|
|
334
|
+
sub.remove()
|
|
335
|
+
micStateCoordinator.releaseHostPcm(owner)
|
|
336
|
+
}
|
|
337
|
+
},
|
|
306
338
|
},
|
|
307
339
|
|
|
308
340
|
// --- sub-facades ---
|
|
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
|
|
|
12
12
|
export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "0.3.3",
|
|
15
|
-
"releaseIdentity": "0.3.3-beta.
|
|
16
|
-
"releaseSetId": "glassly-0.3.3-beta.
|
|
17
|
-
"sourceCommit": "
|
|
15
|
+
"releaseIdentity": "0.3.3-beta.639",
|
|
16
|
+
"releaseSetId": "glassly-0.3.3-beta.639",
|
|
17
|
+
"sourceCommit": "2f573069edc77578d99369a6893567135b6e4673",
|
|
18
18
|
"otaManifestUrl": null,
|
|
19
19
|
"otaManifestSha256": null
|
|
20
20
|
})
|
|
@@ -48,6 +48,8 @@ class MicStateCoordinator {
|
|
|
48
48
|
// Local miniapp requirements (set when miniapps subscribe to audio streams)
|
|
49
49
|
private localWantsPcm = false
|
|
50
50
|
private localWantsLc3 = false
|
|
51
|
+
// Host screens that read raw PCM themselves (e.g. the Microphone settings level meter)
|
|
52
|
+
private readonly hostPcmOwners = new Set<string>()
|
|
51
53
|
private configuredVad: boolean | undefined
|
|
52
54
|
private configuredLoudnessGate: boolean | undefined
|
|
53
55
|
private readonly miniappVadOverrides = new Map<string, GateOverride>()
|
|
@@ -75,6 +77,21 @@ class MicStateCoordinator {
|
|
|
75
77
|
this.applyUnion()
|
|
76
78
|
}
|
|
77
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Hold raw PCM open for a host-side consumer, independent of miniapp
|
|
82
|
+
* subscriptions. Release with `releaseHostPcm` using the same owner.
|
|
83
|
+
*/
|
|
84
|
+
public acquireHostPcm(owner: string): void {
|
|
85
|
+
if (this.hostPcmOwners.has(owner)) return
|
|
86
|
+
this.hostPcmOwners.add(owner)
|
|
87
|
+
this.applyUnion()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public releaseHostPcm(owner: string): void {
|
|
91
|
+
if (!this.hostPcmOwners.delete(owner)) return
|
|
92
|
+
this.applyUnion()
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
/**
|
|
79
96
|
* Apply a miniapp-owned gate override without changing the OS preference.
|
|
80
97
|
* Overrides are lifecycle-scoped and last-live-owner-wins independently for
|
|
@@ -159,7 +176,7 @@ class MicStateCoordinator {
|
|
|
159
176
|
const vadOverride = this.latestOverride(this.miniappVadOverrides)
|
|
160
177
|
const loudnessOverride = this.latestOverride(this.miniappLoudnessGateOverrides)
|
|
161
178
|
|
|
162
|
-
if (this.
|
|
179
|
+
if (this.wantsPcm()) {
|
|
163
180
|
runtimeSettings.voice_activity_detection_enabled = false
|
|
164
181
|
} else if (vadOverride) {
|
|
165
182
|
runtimeSettings.voice_activity_detection_enabled = vadOverride.enabled
|
|
@@ -176,7 +193,7 @@ class MicStateCoordinator {
|
|
|
176
193
|
* on-device PCM consumers; cloud audio uses LC3 through AudioCloudUplink.
|
|
177
194
|
*/
|
|
178
195
|
private applyUnion(): void {
|
|
179
|
-
const shouldSendPcm = this.
|
|
196
|
+
const shouldSendPcm = this.wantsPcm()
|
|
180
197
|
const shouldSendLc3 = this.localWantsLc3
|
|
181
198
|
|
|
182
199
|
// console.log(
|
|
@@ -195,6 +212,10 @@ class MicStateCoordinator {
|
|
|
195
212
|
flushMicRequirementsPatch(patch)
|
|
196
213
|
}
|
|
197
214
|
|
|
215
|
+
private wantsPcm(): boolean {
|
|
216
|
+
return this.localWantsPcm || this.hostPcmOwners.size > 0
|
|
217
|
+
}
|
|
218
|
+
|
|
198
219
|
private rememberConfiguredGates(configured: ConfiguredMicGates): void {
|
|
199
220
|
// null means the connected device intentionally omits that setting.
|
|
200
221
|
// undefined means the caller is not updating the remembered preference.
|
|
@@ -225,7 +246,7 @@ class MicStateCoordinator {
|
|
|
225
246
|
|
|
226
247
|
// Hardware VAD suppresses silence. Raw-audio consumers need a continuous
|
|
227
248
|
// timeline, so their requirement wins over both OS and miniapp VAD values.
|
|
228
|
-
if (this.
|
|
249
|
+
if (this.wantsPcm()) patch.voice_activity_detection_enabled = false
|
|
229
250
|
else if (vadOverride) patch.voice_activity_detection_enabled = vadOverride.enabled
|
|
230
251
|
else if (this.configuredVad !== undefined) patch.voice_activity_detection_enabled = this.configuredVad
|
|
231
252
|
|
|
@@ -250,6 +271,7 @@ class MicStateCoordinator {
|
|
|
250
271
|
console.log(`${LOG_TAG}: cleanup()`)
|
|
251
272
|
this.miniappVadOverrides.clear()
|
|
252
273
|
this.miniappLoudnessGateOverrides.clear()
|
|
274
|
+
this.hostPcmOwners.clear()
|
|
253
275
|
this.reset()
|
|
254
276
|
MicStateCoordinator.instance = null
|
|
255
277
|
}
|
package/src/stores/settings.ts
CHANGED
|
@@ -612,11 +612,11 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
612
612
|
persist: true,
|
|
613
613
|
},
|
|
614
614
|
// G2 Glassly CFW microphone volume gate (revision 40+): the temples stop
|
|
615
|
-
// streaming audio while nothing reaches the threshold.
|
|
616
|
-
//
|
|
615
|
+
// streaming audio while nothing reaches the threshold. Default on; shown only
|
|
616
|
+
// when the connected firmware reports the capability.
|
|
617
617
|
volume_gate_enabled: {
|
|
618
618
|
key: "volume_gate_enabled",
|
|
619
|
-
defaultValue: () =>
|
|
619
|
+
defaultValue: () => true,
|
|
620
620
|
writable: true,
|
|
621
621
|
saveOnServer: true,
|
|
622
622
|
persist: true,
|
|
@@ -632,7 +632,7 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
632
632
|
// Quiet time before the gate closes.
|
|
633
633
|
volume_gate_hold_ms: {
|
|
634
634
|
key: "volume_gate_hold_ms",
|
|
635
|
-
defaultValue: () =>
|
|
635
|
+
defaultValue: () => 5000,
|
|
636
636
|
writable: true,
|
|
637
637
|
saveOnServer: true,
|
|
638
638
|
persist: true,
|
|
@@ -640,7 +640,7 @@ export const SETTINGS: Record<string, Setting> = {
|
|
|
640
640
|
// Minimum time the gate stays open once sound opens it.
|
|
641
641
|
volume_gate_min_open_ms: {
|
|
642
642
|
key: "volume_gate_min_open_ms",
|
|
643
|
-
defaultValue: () =>
|
|
643
|
+
defaultValue: () => 10000,
|
|
644
644
|
writable: true,
|
|
645
645
|
saveOnServer: true,
|
|
646
646
|
persist: true,
|