@mentra/engine 3.2.1-dev.278 → 3.2.1-dev.282

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.
Files changed (53) hide show
  1. package/build/generated/releaseMetadata.js +5 -5
  2. package/build/generated/releaseMetadata.js.map +1 -1
  3. package/build/services/AcsMeetingService.d.ts +56 -6
  4. package/build/services/AcsMeetingService.d.ts.map +1 -1
  5. package/build/services/AcsMeetingService.js +162 -40
  6. package/build/services/AcsMeetingService.js.map +1 -1
  7. package/build/services/CallGainSweep.d.ts +97 -0
  8. package/build/services/CallGainSweep.d.ts.map +1 -0
  9. package/build/services/CallGainSweep.js +249 -0
  10. package/build/services/CallGainSweep.js.map +1 -0
  11. package/build/services/GlassesMicProbe.d.ts +2 -0
  12. package/build/services/GlassesMicProbe.d.ts.map +1 -1
  13. package/build/services/GlassesMicProbe.js +20 -19
  14. package/build/services/GlassesMicProbe.js.map +1 -1
  15. package/build/services/LocalMiniappRuntime.d.ts +18 -0
  16. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  17. package/build/services/LocalMiniappRuntime.js +131 -1
  18. package/build/services/LocalMiniappRuntime.js.map +1 -1
  19. package/build/services/MicSessionManager.d.ts +83 -0
  20. package/build/services/MicSessionManager.d.ts.map +1 -0
  21. package/build/services/MicSessionManager.js +201 -0
  22. package/build/services/MicSessionManager.js.map +1 -0
  23. package/build/services/MicStateCoordinator.d.ts +71 -5
  24. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  25. package/build/services/MicStateCoordinator.js +161 -10
  26. package/build/services/MicStateCoordinator.js.map +1 -1
  27. package/build/services/micPolicy.d.ts +131 -0
  28. package/build/services/micPolicy.d.ts.map +1 -0
  29. package/build/services/micPolicy.js +140 -0
  30. package/build/services/micPolicy.js.map +1 -0
  31. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  32. package/build/stores/bluetoothSettingKeys.js +3 -0
  33. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  34. package/build/stores/settings.d.ts +5 -0
  35. package/build/stores/settings.d.ts.map +1 -1
  36. package/build/stores/settings.js +62 -0
  37. package/build/stores/settings.js.map +1 -1
  38. package/build/utils/pcm16.d.ts +20 -0
  39. package/build/utils/pcm16.d.ts.map +1 -1
  40. package/build/utils/pcm16.js +32 -1
  41. package/build/utils/pcm16.js.map +1 -1
  42. package/package.json +8 -8
  43. package/src/generated/releaseMetadata.ts +5 -5
  44. package/src/services/AcsMeetingService.ts +167 -40
  45. package/src/services/CallGainSweep.ts +318 -0
  46. package/src/services/GlassesMicProbe.ts +20 -17
  47. package/src/services/LocalMiniappRuntime.ts +152 -3
  48. package/src/services/MicSessionManager.ts +258 -0
  49. package/src/services/MicStateCoordinator.ts +153 -10
  50. package/src/services/micPolicy.ts +198 -0
  51. package/src/stores/bluetoothSettingKeys.ts +3 -0
  52. package/src/stores/settings.ts +66 -0
  53. package/src/utils/pcm16.ts +43 -1
@@ -0,0 +1,83 @@
1
+ /**
2
+ * MicSessionManager
3
+ *
4
+ * The engine's microphone ownership layer. Applications acquire a lease that
5
+ * says what they are doing; this class tracks the live leases, resolves them
6
+ * through `micPolicy`, and pushes the result to MicStateCoordinator.
7
+ *
8
+ * Everything above it is semantic ("I need a glasses microphone for a voice
9
+ * call"). Everything below it is hardware. Audio *sinks* — AcsMeetingService
10
+ * today, another transport later — are downstream of the PCM this produces and
11
+ * must not reach past it to the coordinator or the Bluetooth SDK.
12
+ */
13
+ import { type MicPlatformCaps, type MicSource, type MicUseCase } from "./micPolicy";
14
+ /** Raised when a second source is requested while another is already live. */
15
+ export declare const MIC_SOURCE_CONFLICT = "MIC_SOURCE_CONFLICT";
16
+ export interface MicSessionOptions {
17
+ /** Package name for a miniapp, or `engine:<name>` for an engine feature. */
18
+ owner: string;
19
+ source: MicSource;
20
+ useCase: MicUseCase;
21
+ }
22
+ export interface MicSession {
23
+ readonly id: number;
24
+ readonly owner: string;
25
+ readonly source: MicSource;
26
+ readonly useCase: MicUseCase;
27
+ /** Idempotent. Releasing a session that is already gone is a no-op. */
28
+ release(): void;
29
+ }
30
+ declare class MicSessionManager {
31
+ private static instance;
32
+ private readonly sessions;
33
+ private nextId;
34
+ private caps;
35
+ /** Last pin we asked for, so a no-op change does not re-enter native. */
36
+ private pinned;
37
+ /**
38
+ * One 15→14→15→13 walk per voice-call generation. Cleared when the last
39
+ * glasses voice_call session drops so the next join can measure again.
40
+ */
41
+ private sweepFinished;
42
+ /** One-shot A/B walk. Off now that 15/14/13 is measured; Super Mode can still start it. */
43
+ private sweepEnabled;
44
+ private constructor();
45
+ static getInstance(): MicSessionManager;
46
+ /** Test seam. Production reads the platform once at construction. */
47
+ setPlatformCaps(caps: MicPlatformCaps): void;
48
+ /**
49
+ * Take a microphone lease.
50
+ *
51
+ * Throws [MIC_SOURCE_CONFLICT] when a different source is already live: only
52
+ * the glasses can be pinned, so silently mixing sources would leave one
53
+ * consumer reading a microphone it did not ask for. That is the failure ACS
54
+ * already guards against frame by frame.
55
+ */
56
+ acquire(options: MicSessionOptions): MicSession;
57
+ /** Drop every lease an owner holds. The backstop for unregister / disconnect. */
58
+ releaseOwner(owner: string): boolean;
59
+ /**
60
+ * Whether an owner holds a glasses lease.
61
+ *
62
+ * Ownership only. Whether that lease has any hardware effect is
63
+ * [resolveMicPolicy]'s business, so on a platform without a glasses PCM
64
+ * uplink this still answers true while nothing is claimed.
65
+ */
66
+ hasGlassesSession(owner: string): boolean;
67
+ releaseAll(): void;
68
+ cleanup(): void;
69
+ /** Tests disable the auto-walk so acquire still means "policy 14". */
70
+ setCallGainSweepEnabled(enabled: boolean): void;
71
+ /**
72
+ * Start or restart the 15→14→15→13 comparison on a live voice_call session.
73
+ * Super Mode uses this so a call already in progress can be measured.
74
+ */
75
+ startCallGainSweep(): boolean;
76
+ private releaseId;
77
+ private hasVoiceCallGlasses;
78
+ private stopSweep;
79
+ private recompute;
80
+ }
81
+ declare const micSessionManager: MicSessionManager;
82
+ export default micSessionManager;
83
+ //# sourceMappingURL=MicSessionManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MicSessionManager.d.ts","sourceRoot":"","sources":["../../src/services/MicSessionManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,aAAa,CAAA;AAIpB,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,wBAAwB,CAAA;AAExD,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,CAAA;IACjB,OAAO,EAAE,UAAU,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,uEAAuE;IACvE,OAAO,IAAI,IAAI,CAAA;CAChB;AAgBD,cAAM,iBAAiB;IACrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAiC;IAExD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,IAAI,CAAiC;IAC7C,yEAAyE;IACzE,OAAO,CAAC,MAAM,CAAQ;IACtB;;;OAGG;IACH,OAAO,CAAC,aAAa,CAAQ;IAC7B,2FAA2F;IAC3F,OAAO,CAAC,YAAY,CAAQ;IAE5B,OAAO;WAEO,WAAW,IAAI,iBAAiB;IAO9C,qEAAqE;IAC9D,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAInD;;;;;;;OAOG;IACI,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU;IAuBtD,iFAAiF;IAC1E,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAc3C;;;;;;OAMG;IACI,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAOzC,UAAU,IAAI,IAAI;IAUlB,OAAO,IAAI,IAAI;IAQtB,sEAAsE;IAC/D,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKtD;;;OAGG;IACI,kBAAkB,IAAI,OAAO;IAoBpC,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,SAAS;CAqClB;AAED,QAAA,MAAM,iBAAiB,mBAAkC,CAAA;AACzD,eAAe,iBAAiB,CAAA"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * MicSessionManager
3
+ *
4
+ * The engine's microphone ownership layer. Applications acquire a lease that
5
+ * says what they are doing; this class tracks the live leases, resolves them
6
+ * through `micPolicy`, and pushes the result to MicStateCoordinator.
7
+ *
8
+ * Everything above it is semantic ("I need a glasses microphone for a voice
9
+ * call"). Everything below it is hardware. Audio *sinks* — AcsMeetingService
10
+ * today, another transport later — are downstream of the PCM this produces and
11
+ * must not reach past it to the coordinator or the Bluetooth SDK.
12
+ */
13
+ import { Platform } from "react-native";
14
+ import BluetoothSdk from "@mentra/bluetooth-sdk/internal";
15
+ import { getCallGainSweep } from "./CallGainSweep";
16
+ import micStateCoordinator from "./MicStateCoordinator";
17
+ import { resolveMicPolicy, } from "./micPolicy";
18
+ const LOG_TAG = "MIC_SESSION";
19
+ /** Raised when a second source is requested while another is already live. */
20
+ export const MIC_SOURCE_CONFLICT = "MIC_SOURCE_CONFLICT";
21
+ function defaultCaps() {
22
+ return {
23
+ // iOS has no `setMicSourcePin`, so it cannot promise the phone microphone
24
+ // stays shut, and `glassesLc3UplinkSupported` never selects the BLE LC3
25
+ // uplink there.
26
+ glassesPcmUplink: Platform.OS === "android" && typeof BluetoothSdk.setMicSourcePin === "function",
27
+ };
28
+ }
29
+ class MicSessionManager {
30
+ static instance = null;
31
+ sessions = new Map();
32
+ nextId = 1;
33
+ caps = defaultCaps();
34
+ /** Last pin we asked for, so a no-op change does not re-enter native. */
35
+ pinned = false;
36
+ /**
37
+ * One 15→14→15→13 walk per voice-call generation. Cleared when the last
38
+ * glasses voice_call session drops so the next join can measure again.
39
+ */
40
+ sweepFinished = false;
41
+ /** One-shot A/B walk. Off now that 15/14/13 is measured; Super Mode can still start it. */
42
+ sweepEnabled = false;
43
+ constructor() { }
44
+ static getInstance() {
45
+ if (!MicSessionManager.instance) {
46
+ MicSessionManager.instance = new MicSessionManager();
47
+ }
48
+ return MicSessionManager.instance;
49
+ }
50
+ /** Test seam. Production reads the platform once at construction. */
51
+ setPlatformCaps(caps) {
52
+ this.caps = caps;
53
+ }
54
+ /**
55
+ * Take a microphone lease.
56
+ *
57
+ * Throws [MIC_SOURCE_CONFLICT] when a different source is already live: only
58
+ * the glasses can be pinned, so silently mixing sources would leave one
59
+ * consumer reading a microphone it did not ask for. That is the failure ACS
60
+ * already guards against frame by frame.
61
+ */
62
+ acquire(options) {
63
+ const conflicting = [...this.sessions.values()].find((s) => s.source !== options.source);
64
+ if (conflicting) {
65
+ throw new Error(`${MIC_SOURCE_CONFLICT}: ${options.owner} asked for "${options.source}" while ` +
66
+ `${conflicting.owner} holds "${conflicting.source}"`);
67
+ }
68
+ const id = this.nextId++;
69
+ this.sessions.set(id, { id, owner: options.owner, source: options.source, useCase: options.useCase });
70
+ console.log(`${LOG_TAG}: acquire #${id} ${options.owner} ${options.useCase}/${options.source}`);
71
+ this.recompute();
72
+ return {
73
+ id,
74
+ owner: options.owner,
75
+ source: options.source,
76
+ useCase: options.useCase,
77
+ release: () => this.releaseId(id),
78
+ };
79
+ }
80
+ /** Drop every lease an owner holds. The backstop for unregister / disconnect. */
81
+ releaseOwner(owner) {
82
+ let removed = false;
83
+ for (const [id, session] of this.sessions) {
84
+ if (session.owner !== owner)
85
+ continue;
86
+ this.sessions.delete(id);
87
+ removed = true;
88
+ }
89
+ if (removed) {
90
+ console.log(`${LOG_TAG}: released all sessions for ${owner}`);
91
+ this.recompute();
92
+ }
93
+ return removed;
94
+ }
95
+ /**
96
+ * Whether an owner holds a glasses lease.
97
+ *
98
+ * Ownership only. Whether that lease has any hardware effect is
99
+ * [resolveMicPolicy]'s business, so on a platform without a glasses PCM
100
+ * uplink this still answers true while nothing is claimed.
101
+ */
102
+ hasGlassesSession(owner) {
103
+ for (const session of this.sessions.values()) {
104
+ if (session.owner === owner && session.source === "glasses")
105
+ return true;
106
+ }
107
+ return false;
108
+ }
109
+ releaseAll() {
110
+ if (this.sessions.size === 0) {
111
+ this.stopSweep("released_all");
112
+ return;
113
+ }
114
+ this.sessions.clear();
115
+ console.log(`${LOG_TAG}: released all sessions`);
116
+ this.recompute();
117
+ }
118
+ cleanup() {
119
+ this.stopSweep("cleanup");
120
+ this.sessions.clear();
121
+ this.pinned = false;
122
+ this.sweepFinished = false;
123
+ MicSessionManager.instance = null;
124
+ }
125
+ /** Tests disable the auto-walk so acquire still means "policy 14". */
126
+ setCallGainSweepEnabled(enabled) {
127
+ this.sweepEnabled = enabled;
128
+ if (!enabled)
129
+ this.stopSweep("disabled");
130
+ }
131
+ /**
132
+ * Start or restart the 15→14→15→13 comparison on a live voice_call session.
133
+ * Super Mode uses this so a call already in progress can be measured.
134
+ */
135
+ startCallGainSweep() {
136
+ if (!this.hasVoiceCallGlasses()) {
137
+ console.warn(`${LOG_TAG}: CALL_GAIN_SWEEP ignored — no live voice_call glasses session`);
138
+ return false;
139
+ }
140
+ if (micStateCoordinator.hasConfiguredMicTuning()) {
141
+ console.warn(`${LOG_TAG}: CALL_GAIN_SWEEP Super Mode mic-tuning is set; reset it or the glasses will ignore the sweep`);
142
+ }
143
+ this.sweepFinished = false;
144
+ return getCallGainSweep().restart((gain) => micStateCoordinator.setSessionMicTuning({ gain }), () => {
145
+ this.sweepFinished = true;
146
+ this.recompute();
147
+ });
148
+ }
149
+ releaseId(id) {
150
+ if (!this.sessions.delete(id))
151
+ return;
152
+ console.log(`${LOG_TAG}: release #${id}`);
153
+ this.recompute();
154
+ }
155
+ hasVoiceCallGlasses() {
156
+ if (!this.caps.glassesPcmUplink)
157
+ return false;
158
+ for (const session of this.sessions.values()) {
159
+ if (session.useCase === "voice_call" && session.source === "glasses")
160
+ return true;
161
+ }
162
+ return false;
163
+ }
164
+ stopSweep(reason) {
165
+ if (getCallGainSweep().isActive())
166
+ getCallGainSweep().stop(reason);
167
+ }
168
+ recompute() {
169
+ const policy = resolveMicPolicy([...this.sessions.values()], this.caps);
170
+ const voiceCall = this.hasVoiceCallGlasses();
171
+ if (!voiceCall) {
172
+ this.stopSweep("session_ended");
173
+ this.sweepFinished = false;
174
+ }
175
+ // Pin before claiming PCM, so the first frame the claim produces is
176
+ // already from the right microphone and the phone mic is never opened.
177
+ if (policy.pinGlasses !== this.pinned) {
178
+ this.pinned = policy.pinGlasses;
179
+ void Promise.resolve(BluetoothSdk.setMicSourcePin?.(policy.pinGlasses ? "glasses" : null)).catch((error) => {
180
+ console.warn(`${LOG_TAG}: setMicSourcePin failed`, error);
181
+ });
182
+ }
183
+ micStateCoordinator.setSessionRequirement(policy.rawPcm);
184
+ // Barrier is the only echo control left once the PCM claim turns hardware VAD off, so it
185
+ // rides with the claim rather than with the tuning a sweep may be rewriting.
186
+ micStateCoordinator.setSessionLoudnessGate(policy.loudnessGate);
187
+ if (getCallGainSweep().isActive()) {
188
+ const gain = getCallGainSweep().currentGain();
189
+ micStateCoordinator.setSessionMicTuning(gain == null ? policy.micTuning : { gain });
190
+ return;
191
+ }
192
+ if (this.sweepEnabled && voiceCall && !this.sweepFinished) {
193
+ this.startCallGainSweep();
194
+ return;
195
+ }
196
+ micStateCoordinator.setSessionMicTuning(policy.micTuning);
197
+ }
198
+ }
199
+ const micSessionManager = MicSessionManager.getInstance();
200
+ export default micSessionManager;
201
+ //# sourceMappingURL=MicSessionManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MicSessionManager.js","sourceRoot":"","sources":["../../src/services/MicSessionManager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MicSessionManager\n *\n * The engine's microphone ownership layer. Applications acquire a lease that\n * says what they are doing; this class tracks the live leases, resolves them\n * through `micPolicy`, and pushes the result to MicStateCoordinator.\n *\n * Everything above it is semantic (\"I need a glasses microphone for a voice\n * call\"). Everything below it is hardware. Audio *sinks* — AcsMeetingService\n * today, another transport later — are downstream of the PCM this produces and\n * must not reach past it to the coordinator or the Bluetooth SDK.\n */\n\nimport {Platform} from \"react-native\"\nimport BluetoothSdk from \"@mentra/bluetooth-sdk/internal\"\n\nimport {getCallGainSweep} from \"./CallGainSweep\"\nimport micStateCoordinator from \"./MicStateCoordinator\"\nimport {\n resolveMicPolicy,\n type MicPlatformCaps,\n type MicSessionSpec,\n type MicSource,\n type MicUseCase,\n} from \"./micPolicy\"\n\nconst LOG_TAG = \"MIC_SESSION\"\n\n/** Raised when a second source is requested while another is already live. */\nexport const MIC_SOURCE_CONFLICT = \"MIC_SOURCE_CONFLICT\"\n\nexport interface MicSessionOptions {\n /** Package name for a miniapp, or `engine:<name>` for an engine feature. */\n owner: string\n source: MicSource\n useCase: MicUseCase\n}\n\nexport interface MicSession {\n readonly id: number\n readonly owner: string\n readonly source: MicSource\n readonly useCase: MicUseCase\n /** Idempotent. Releasing a session that is already gone is a no-op. */\n release(): void\n}\n\ninterface LiveSession extends MicSessionSpec {\n id: number\n owner: string\n}\n\nfunction defaultCaps(): MicPlatformCaps {\n return {\n // iOS has no `setMicSourcePin`, so it cannot promise the phone microphone\n // stays shut, and `glassesLc3UplinkSupported` never selects the BLE LC3\n // uplink there.\n glassesPcmUplink: Platform.OS === \"android\" && typeof BluetoothSdk.setMicSourcePin === \"function\",\n }\n}\n\nclass MicSessionManager {\n private static instance: MicSessionManager | null = null\n\n private readonly sessions = new Map<number, LiveSession>()\n private nextId = 1\n private caps: MicPlatformCaps = defaultCaps()\n /** Last pin we asked for, so a no-op change does not re-enter native. */\n private pinned = false\n /**\n * One 15→14→15→13 walk per voice-call generation. Cleared when the last\n * glasses voice_call session drops so the next join can measure again.\n */\n private sweepFinished = false\n /** One-shot A/B walk. Off now that 15/14/13 is measured; Super Mode can still start it. */\n private sweepEnabled = false\n\n private constructor() {}\n\n public static getInstance(): MicSessionManager {\n if (!MicSessionManager.instance) {\n MicSessionManager.instance = new MicSessionManager()\n }\n return MicSessionManager.instance\n }\n\n /** Test seam. Production reads the platform once at construction. */\n public setPlatformCaps(caps: MicPlatformCaps): void {\n this.caps = caps\n }\n\n /**\n * Take a microphone lease.\n *\n * Throws [MIC_SOURCE_CONFLICT] when a different source is already live: only\n * the glasses can be pinned, so silently mixing sources would leave one\n * consumer reading a microphone it did not ask for. That is the failure ACS\n * already guards against frame by frame.\n */\n public acquire(options: MicSessionOptions): MicSession {\n const conflicting = [...this.sessions.values()].find((s) => s.source !== options.source)\n if (conflicting) {\n throw new Error(\n `${MIC_SOURCE_CONFLICT}: ${options.owner} asked for \"${options.source}\" while ` +\n `${conflicting.owner} holds \"${conflicting.source}\"`,\n )\n }\n\n const id = this.nextId++\n this.sessions.set(id, {id, owner: options.owner, source: options.source, useCase: options.useCase})\n console.log(`${LOG_TAG}: acquire #${id} ${options.owner} ${options.useCase}/${options.source}`)\n this.recompute()\n\n return {\n id,\n owner: options.owner,\n source: options.source,\n useCase: options.useCase,\n release: () => this.releaseId(id),\n }\n }\n\n /** Drop every lease an owner holds. The backstop for unregister / disconnect. */\n public releaseOwner(owner: string): boolean {\n let removed = false\n for (const [id, session] of this.sessions) {\n if (session.owner !== owner) continue\n this.sessions.delete(id)\n removed = true\n }\n if (removed) {\n console.log(`${LOG_TAG}: released all sessions for ${owner}`)\n this.recompute()\n }\n return removed\n }\n\n /**\n * Whether an owner holds a glasses lease.\n *\n * Ownership only. Whether that lease has any hardware effect is\n * [resolveMicPolicy]'s business, so on a platform without a glasses PCM\n * uplink this still answers true while nothing is claimed.\n */\n public hasGlassesSession(owner: string): boolean {\n for (const session of this.sessions.values()) {\n if (session.owner === owner && session.source === \"glasses\") return true\n }\n return false\n }\n\n public releaseAll(): void {\n if (this.sessions.size === 0) {\n this.stopSweep(\"released_all\")\n return\n }\n this.sessions.clear()\n console.log(`${LOG_TAG}: released all sessions`)\n this.recompute()\n }\n\n public cleanup(): void {\n this.stopSweep(\"cleanup\")\n this.sessions.clear()\n this.pinned = false\n this.sweepFinished = false\n MicSessionManager.instance = null\n }\n\n /** Tests disable the auto-walk so acquire still means \"policy 14\". */\n public setCallGainSweepEnabled(enabled: boolean): void {\n this.sweepEnabled = enabled\n if (!enabled) this.stopSweep(\"disabled\")\n }\n\n /**\n * Start or restart the 15→14→15→13 comparison on a live voice_call session.\n * Super Mode uses this so a call already in progress can be measured.\n */\n public startCallGainSweep(): boolean {\n if (!this.hasVoiceCallGlasses()) {\n console.warn(`${LOG_TAG}: CALL_GAIN_SWEEP ignored — no live voice_call glasses session`)\n return false\n }\n if (micStateCoordinator.hasConfiguredMicTuning()) {\n console.warn(\n `${LOG_TAG}: CALL_GAIN_SWEEP Super Mode mic-tuning is set; reset it or the glasses will ignore the sweep`,\n )\n }\n this.sweepFinished = false\n return getCallGainSweep().restart(\n (gain) => micStateCoordinator.setSessionMicTuning({gain}),\n () => {\n this.sweepFinished = true\n this.recompute()\n },\n )\n }\n\n private releaseId(id: number): void {\n if (!this.sessions.delete(id)) return\n console.log(`${LOG_TAG}: release #${id}`)\n this.recompute()\n }\n\n private hasVoiceCallGlasses(): boolean {\n if (!this.caps.glassesPcmUplink) return false\n for (const session of this.sessions.values()) {\n if (session.useCase === \"voice_call\" && session.source === \"glasses\") return true\n }\n return false\n }\n\n private stopSweep(reason: string): void {\n if (getCallGainSweep().isActive()) getCallGainSweep().stop(reason)\n }\n\n private recompute(): void {\n const policy = resolveMicPolicy([...this.sessions.values()], this.caps)\n const voiceCall = this.hasVoiceCallGlasses()\n if (!voiceCall) {\n this.stopSweep(\"session_ended\")\n this.sweepFinished = false\n }\n\n // Pin before claiming PCM, so the first frame the claim produces is\n // already from the right microphone and the phone mic is never opened.\n if (policy.pinGlasses !== this.pinned) {\n this.pinned = policy.pinGlasses\n void Promise.resolve(BluetoothSdk.setMicSourcePin?.(policy.pinGlasses ? \"glasses\" : null)).catch(\n (error) => {\n console.warn(`${LOG_TAG}: setMicSourcePin failed`, error)\n },\n )\n }\n\n micStateCoordinator.setSessionRequirement(policy.rawPcm)\n // Barrier is the only echo control left once the PCM claim turns hardware VAD off, so it\n // rides with the claim rather than with the tuning a sweep may be rewriting.\n micStateCoordinator.setSessionLoudnessGate(policy.loudnessGate)\n\n if (getCallGainSweep().isActive()) {\n const gain = getCallGainSweep().currentGain()\n micStateCoordinator.setSessionMicTuning(gain == null ? policy.micTuning : {gain})\n return\n }\n\n if (this.sweepEnabled && voiceCall && !this.sweepFinished) {\n this.startCallGainSweep()\n return\n }\n\n micStateCoordinator.setSessionMicTuning(policy.micTuning)\n }\n}\n\nconst micSessionManager = MicSessionManager.getInstance()\nexport default micSessionManager\n"]}
@@ -6,26 +6,50 @@
6
6
  * Local miniapps subscribe to audio_chunk / transcription streams.
7
7
  * This coordinator pushes the aggregate local requirement set to BluetoothSdk
8
8
  * so the mic runs whenever at least one local consumer needs it.
9
+ *
10
+ * It also merges what the live microphone sessions require (MicSessionManager,
11
+ * via `setSessionRequirement` / `setSessionMicTuning`) with the OS preferences
12
+ * the settings store derives. Applications go through MicSessionManager; this
13
+ * class is an engine implementation detail.
9
14
  */
15
+ import type { MicTuningProfile } from "./micPolicy";
10
16
  type MicGate = "vad" | "loudnessGate";
11
17
  interface ConfiguredMicGates {
12
18
  vadEnabled?: boolean | null;
13
19
  loudnessGateEnabled?: boolean | null;
20
+ micTuning?: Record<string, number> | null;
14
21
  }
15
22
  declare class MicStateCoordinator {
16
23
  private static instance;
17
24
  private localWantsPcm;
18
25
  private localWantsLc3;
19
26
  /**
20
- * A live ACS call taking the wearer's voice off the glasses over BLE LC3.
27
+ * A live microphone session held through MicSessionManager a voice call today.
21
28
  *
22
29
  * Tracked separately from the miniapp requirement because the two have independent lifetimes:
23
30
  * the call miniapp does not subscribe to `audio_chunk`, and a captions miniapp that stops mid-call
24
31
  * must not take the call's microphone with it.
25
32
  */
26
- private callWantsPcm;
33
+ private sessionWantsPcm;
27
34
  private configuredVad;
28
35
  private configuredLoudnessGate;
36
+ /** `mic_tuning` as the settings store last derived it: `super_mode ? desired : {}`. */
37
+ private configuredMicTuning;
38
+ /** Tuning required by the live sessions, resolved by micPolicy. */
39
+ private sessionMicTuning;
40
+ /**
41
+ * Latched once a session profile has actually been written.
42
+ *
43
+ * Before that, `mic_tuning` stays out of every patch, so a device that never
44
+ * runs a profile does not carry the key on unrelated mic writes. After it,
45
+ * the OS value keeps being restated, which is what stops a reconnect after a
46
+ * call from resurrecting the profile.
47
+ */
48
+ private sessionMicTuningWritten;
49
+ /** Barrier required by the live sessions, or null when they have no opinion. */
50
+ private sessionLoudnessGate;
51
+ /** Latched like the tuning, so the OS value is restated once a session has moved it. */
52
+ private sessionLoudnessGateWritten;
29
53
  private readonly miniappVadOverrides;
30
54
  private readonly miniappLoudnessGateOverrides;
31
55
  private overrideSequence;
@@ -40,19 +64,61 @@ declare class MicStateCoordinator {
40
64
  lc3: boolean;
41
65
  } & ConfiguredMicGates): void;
42
66
  /**
43
- * Claim or release raw PCM on behalf of an active call.
67
+ * Claim or release raw PCM on behalf of the live microphone sessions.
44
68
  *
45
- * Called by AcsMeetingService around a call whose uplink is the glasses microphone over BLE LC3.
69
+ * MicSessionManager only. Applications acquire a session; they do not reach past it to here.
46
70
  * Releasing is a claim release, not a mic shutdown: if a captions miniapp still wants PCM the
47
71
  * microphone stays on, which is the whole reason this is a separate flag rather than a setter on
48
72
  * the local requirement.
49
73
  */
50
- setCallRequirement(pcm: boolean): void;
74
+ setSessionRequirement(pcm: boolean): void;
75
+ /**
76
+ * Apply or drop the tuning the live sessions require.
77
+ *
78
+ * MicSessionManager only. Rides `applyUnion` so the profile and the PCM claim land in one
79
+ * debounced write, resolved at flush time: a session released inside the debounce window wins
80
+ * over the value that was queued.
81
+ */
82
+ setSessionMicTuning(profile: MicTuningProfile | null): void;
83
+ /** Last session profile queued, or null when the OS value is in force. */
84
+ getSessionMicTuning(): MicTuningProfile | null;
85
+ /** Last session Barrier queued, or null when the OS value is in force. For call logging. */
86
+ getSessionLoudnessGate(): boolean | null;
87
+ /**
88
+ * Run or stop the center-mic loudness gate on behalf of the live sessions.
89
+ *
90
+ * MicSessionManager only, and the counterpart to the PCM claim rather than a second opinion on
91
+ * it: raw PCM turns hardware VAD off, which leaves Barrier as the only thing standing between
92
+ * the far end and its own echo. Unlike VAD this never stops the stream, so the worst a wrong
93
+ * threshold costs is a zeroed frame instead of a dropped word.
94
+ */
95
+ setSessionLoudnessGate(enabled: boolean | null): void;
96
+ /**
97
+ * Super Mode sliders outrank a session profile. A live override means a gain
98
+ * sweep would write to the coordinator and the glasses would ignore it.
99
+ */
100
+ hasConfiguredMicTuning(): boolean;
51
101
  /**
52
102
  * Whether anything on this device needs a continuous raw-PCM timeline. Also the condition that
53
103
  * forces hardware VAD off: a gate that drops silence turns a call into clipped half-words.
54
104
  */
55
105
  private get wantsRawPcm();
106
+ /**
107
+ * The session profile, but only when it wins.
108
+ *
109
+ * A live Super Mode tuning value outranks it: that screen is how a profile's numbers get found
110
+ * on a real call in the first place. Emptiness is by key count — the settings store hands back a
111
+ * fresh `{}` every time, so reference checks would never match.
112
+ */
113
+ private winningSessionMicTuning;
114
+ /**
115
+ * The session's Barrier, but only when it wins.
116
+ *
117
+ * Suppressed by a live Super Mode tuning value for the same reason the gain is: that screen is
118
+ * the manual override, and a gate running against hand-entered thresholds is the one case where
119
+ * the session's numbers are the wrong ones.
120
+ */
121
+ private winningSessionLoudnessGate;
56
122
  /**
57
123
  * Apply a miniapp-owned gate override without changing the OS preference.
58
124
  * Overrides are lifecycle-scoped and last-live-owner-wins independently for
@@ -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;IAC7B;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAQ;IAC5B,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;;;;;;;OAOG;IACI,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAO7C;;;OAGG;IACH,OAAO,KAAK,WAAW,GAEtB;IAED;;;;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,uBAAuB;IAW/B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,kBAAkB;IAmB1B;;OAEG;IACI,KAAK,IAAI,IAAI;IAOb,OAAO,IAAI,IAAI;CAOvB;AAED,QAAA,MAAM,mBAAmB,qBAAoC,CAAA;AAC7D,eAAe,mBAAmB,CAAA"}
1
+ {"version":3,"file":"MicStateCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/MicStateCoordinator.ts"],"names":[],"mappings":"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"}