@burdenoff/fe-libs 2026.1005.1 → 2026.1005.3
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/dist/chrome/ContextSwitcher.d.ts +2 -0
- package/dist/chrome/ContextSwitcher.d.ts.map +1 -1
- package/dist/chrome/ContextSwitcher.js +70 -67
- package/dist/chrome/contextSwitcher/ProjectList.d.ts +1 -0
- package/dist/chrome/contextSwitcher/ProjectList.d.ts.map +1 -1
- package/dist/chrome/contextSwitcher/ProjectList.js +18 -5
- package/dist/node_modules/fflate/esm/browser.js +3 -3
- package/dist/node_modules/hast-util-to-jsx-runtime/lib/index.js +51 -51
- package/dist/node_modules/pdfjs-dist/build/pdf.js +2268 -1656
- package/dist/node_modules/pdfjs-dist/build/pdf.worker.min.js +8719 -7535
- package/dist/shared/assistant/attachments.js +1 -0
- package/dist/shared/assistant/i18nManifest.d.ts +4 -0
- package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
- package/dist/shared/assistant/i18nManifest.js +4 -0
- package/dist/shared/assistant/images.js +1 -1
- package/dist/shared/assistant/index.d.ts +16 -0
- package/dist/shared/assistant/index.d.ts.map +1 -1
- package/dist/shared/assistant/runtime.js +1 -0
- package/dist/shared/assistant/speech/browserSpeechEngine.d.ts.map +1 -1
- package/dist/shared/assistant/speech/browserSpeechEngine.js +46 -45
- package/dist/shared/assistant/speech/createSpeechEngine.js +1 -1
- package/dist/shared/assistant/speech/hostedTtsSpeechEngine.d.ts.map +1 -1
- package/dist/shared/assistant/speech/hostedTtsSpeechEngine.js +80 -79
- package/dist/shared/assistant/store.d.ts +3 -0
- package/dist/shared/assistant/store.d.ts.map +1 -1
- package/dist/shared/assistant/store.js +43 -35
- package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantChatArea.js +1076 -1074
- package/dist/shared/assistant/ui/AssistantMoreMenu.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantMoreMenu.js +59 -57
- package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.d.ts +17 -0
- package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.d.ts.map +1 -0
- package/dist/shared/assistant/ui/composer/AssistantHandsFreeInterruptToggle.js +34 -0
- package/dist/shared/assistant/ui/useVoiceSession.d.ts +29 -2
- package/dist/shared/assistant/ui/useVoiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/ui/useVoiceSession.js +247 -213
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +2 -0
- package/dist/shared/assistant/uiActions/deixis.js +1 -1
- package/dist/shared/assistant/voice/handsfree/audioTrackTransport.d.ts +33 -0
- package/dist/shared/assistant/voice/handsfree/audioTrackTransport.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/audioTrackTransport.js +98 -0
- package/dist/shared/assistant/voice/handsfree/backendStreamTransport.d.ts +34 -0
- package/dist/shared/assistant/voice/handsfree/backendStreamTransport.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/backendStreamTransport.js +130 -0
- package/dist/shared/assistant/voice/handsfree/bargeIn.d.ts +43 -0
- package/dist/shared/assistant/voice/handsfree/bargeIn.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/bargeIn.js +32 -0
- package/dist/shared/assistant/voice/handsfree/captureWorklet.d.ts +47 -0
- package/dist/shared/assistant/voice/handsfree/captureWorklet.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/captureWorklet.js +85 -0
- package/dist/shared/assistant/voice/handsfree/echoGate.d.ts +140 -0
- package/dist/shared/assistant/voice/handsfree/echoGate.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/echoGate.js +198 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeController.d.ts +77 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeController.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeController.js +126 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeRuntime.d.ts +15 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeRuntime.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeRuntime.js +78 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeSetting.d.ts +26 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeSetting.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/handsFreeSetting.js +25 -0
- package/dist/shared/assistant/voice/handsfree/micCapture.d.ts +21 -0
- package/dist/shared/assistant/voice/handsfree/micCapture.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/micCapture.js +73 -0
- package/dist/shared/assistant/voice/handsfree/playbackReference.d.ts +38 -0
- package/dist/shared/assistant/voice/handsfree/playbackReference.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/playbackReference.js +55 -0
- package/dist/shared/assistant/voice/handsfree/preRollRing.d.ts +32 -0
- package/dist/shared/assistant/voice/handsfree/preRollRing.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/preRollRing.js +34 -0
- package/dist/shared/assistant/voice/handsfree/sttTransport.d.ts +94 -0
- package/dist/shared/assistant/voice/handsfree/sttTransport.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/sttTransport.js +27 -0
- package/dist/shared/assistant/voice/handsfree/useHandsFreeInterrupt.d.ts +33 -0
- package/dist/shared/assistant/voice/handsfree/useHandsFreeInterrupt.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/useHandsFreeInterrupt.js +70 -0
- package/dist/shared/assistant/voice/handsfree/vad.d.ts +55 -0
- package/dist/shared/assistant/voice/handsfree/vad.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/vad.js +41 -0
- package/dist/shared/assistant/voice/handsfree/webSpeechTransport.d.ts +3 -0
- package/dist/shared/assistant/voice/handsfree/webSpeechTransport.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsfree/webSpeechTransport.js +16 -0
- package/dist/shared/assistant/voice/voiceSession.d.ts +9 -0
- package/dist/shared/assistant/voice/voiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/voice/voiceSession.js +2 -2
- package/dist/shared/assistant/voice/voiceTranscript.js +14 -14
- package/dist/shared/config/gatewayUrls.js +2 -2
- package/dist/shared/graphql/workspaceToken.d.ts +1 -0
- package/dist/shared/graphql/workspaceToken.d.ts.map +1 -1
- package/dist/shared/graphql/workspaceToken.js +18 -14
- package/dist/shared/plugins/iframe-mount/client/message-bus.js +1 -0
- package/dist/shared/plugins/iframe-mount/client/rpc.js +1 -0
- package/dist/shared/providers/shell/ActiveContextProvider.d.ts.map +1 -1
- package/dist/shared/providers/shell/ActiveContextProvider.js +165 -144
- package/dist/shared/providers/shell/AuthTokenProvider.d.ts.map +1 -1
- package/dist/shared/providers/shell/AuthTokenProvider.js +51 -46
- package/dist/shared/providers/shell/WorkspaceWideSelection.d.ts +10 -0
- package/dist/shared/providers/shell/WorkspaceWideSelection.d.ts.map +1 -0
- package/dist/shared/providers/shell/WorkspaceWideSelection.js +37 -0
- package/dist/shared/providers/shell/index.d.ts +2 -0
- package/dist/shared/providers/shell/index.d.ts.map +1 -1
- package/dist/shared/tours/TourTooltip.js +8 -8
- package/dist/shared/utils/format.js +1 -1
- package/dist/shared/utils/gatewayFetchRewrite.js +1 -1
- package/dist/shared-assistant.js +218 -202
- package/dist/shared-providers-shell.js +25 -24
- package/package.json +18 -8
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
//#region src/shared/assistant/voice/handsfree/echoGate.ts
|
|
2
|
+
var e = Object.freeze({
|
|
3
|
+
windowFrames: 12,
|
|
4
|
+
lowCorr: .3,
|
|
5
|
+
lowRunFrames: 3,
|
|
6
|
+
headsetLowRunFrames: 2,
|
|
7
|
+
calibFrames: 50,
|
|
8
|
+
maxLagFrames: 25,
|
|
9
|
+
minCalibCorr: .5,
|
|
10
|
+
tailFrames: 30,
|
|
11
|
+
floorDb: -60,
|
|
12
|
+
referenceSilentDb: -58,
|
|
13
|
+
quietMicDb: -55,
|
|
14
|
+
flatStdDb: 1,
|
|
15
|
+
tailDecayDbPerFrame: 3
|
|
16
|
+
}), t = 2400, n = 150, r = 1200, i = (e, t) => {
|
|
17
|
+
let n = [...e].sort((e, t) => e - t);
|
|
18
|
+
return n[Math.min(n.length - 1, Math.floor(t * n.length))] ?? 0;
|
|
19
|
+
};
|
|
20
|
+
function a(e, t, n) {
|
|
21
|
+
let r = e.length, i = 0, a = 0;
|
|
22
|
+
for (let n = 0; n < r; n += 1) i += e[n] ?? 0, a += t[n] ?? 0;
|
|
23
|
+
i /= r, a /= r;
|
|
24
|
+
let o = 0, s = 0, c = 0;
|
|
25
|
+
for (let n = 0; n < r; n += 1) {
|
|
26
|
+
let r = (e[n] ?? 0) - i, l = (t[n] ?? 0) - a;
|
|
27
|
+
o += r * l, s += r * r, c += l * l;
|
|
28
|
+
}
|
|
29
|
+
let l = Math.sqrt(c / r) < n;
|
|
30
|
+
return s === 0 || c === 0 ? {
|
|
31
|
+
corr: 0,
|
|
32
|
+
refFlat: l
|
|
33
|
+
} : {
|
|
34
|
+
corr: o / Math.sqrt(s * c),
|
|
35
|
+
refFlat: l
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
var o = class {
|
|
39
|
+
params;
|
|
40
|
+
mic = [];
|
|
41
|
+
ref = [];
|
|
42
|
+
tail = [];
|
|
43
|
+
base = 0;
|
|
44
|
+
total = 0;
|
|
45
|
+
playing = !1;
|
|
46
|
+
hasReference = !0;
|
|
47
|
+
playStart = 0;
|
|
48
|
+
armedUntil = -1;
|
|
49
|
+
current = null;
|
|
50
|
+
prior = null;
|
|
51
|
+
noEchoPath = !1;
|
|
52
|
+
lowRun = 0;
|
|
53
|
+
headset = !1;
|
|
54
|
+
constructor(t = {}) {
|
|
55
|
+
this.params = {
|
|
56
|
+
...e,
|
|
57
|
+
...t
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
get isPlaying() {
|
|
61
|
+
return this.playing;
|
|
62
|
+
}
|
|
63
|
+
get hasPrior() {
|
|
64
|
+
return this.prior !== null;
|
|
65
|
+
}
|
|
66
|
+
get calibration() {
|
|
67
|
+
let e = this.current ?? this.prior;
|
|
68
|
+
return e ? {
|
|
69
|
+
lagMs: e.lag * 20,
|
|
70
|
+
corr: e.corr
|
|
71
|
+
} : null;
|
|
72
|
+
}
|
|
73
|
+
setHeadset(e) {
|
|
74
|
+
this.headset = e;
|
|
75
|
+
}
|
|
76
|
+
playbackStarted(e) {
|
|
77
|
+
this.playing = !0, this.hasReference = e, this.playStart = this.total, this.current = null, this.noEchoPath = !1, this.lowRun = 0;
|
|
78
|
+
}
|
|
79
|
+
playbackStopped() {
|
|
80
|
+
this.playing && (this.playing = !1, this.armedUntil = this.total + this.params.tailFrames);
|
|
81
|
+
}
|
|
82
|
+
pushFrame(e, t) {
|
|
83
|
+
let n = this.total;
|
|
84
|
+
this.total += 1;
|
|
85
|
+
let r = this.params.floorDb;
|
|
86
|
+
this.mic.push(Math.min(0, Math.max(r, e)));
|
|
87
|
+
let i = Math.min(0, Math.max(r, t));
|
|
88
|
+
this.ref.push(i);
|
|
89
|
+
let a = this.tail[this.tail.length - 1] ?? r;
|
|
90
|
+
if (this.tail.push(Math.max(i, a - this.params.tailDecayDbPerFrame)), this.trim(), !(this.playing || n < this.armedUntil)) return this.lowRun = 0, {
|
|
91
|
+
pass: !0,
|
|
92
|
+
reason: "no-playback",
|
|
93
|
+
coherence: null
|
|
94
|
+
};
|
|
95
|
+
if (!this.hasReference) return this.lowRun = 0, {
|
|
96
|
+
pass: !1,
|
|
97
|
+
reason: "no-reference",
|
|
98
|
+
coherence: null
|
|
99
|
+
};
|
|
100
|
+
let o = n - this.playStart;
|
|
101
|
+
if (this.playing && this.current === null && !this.noEchoPath && o >= this.params.calibFrames && n % 10 == 0 && this.calibrate(n), this.noEchoPath) return this.lowRun = 0, {
|
|
102
|
+
pass: !0,
|
|
103
|
+
reason: "no-echo-path",
|
|
104
|
+
coherence: null
|
|
105
|
+
};
|
|
106
|
+
let s = this.current ?? this.prior;
|
|
107
|
+
if (!s) {
|
|
108
|
+
let e = this.windowMax(this.ref, n, 0) > this.params.referenceSilentDb;
|
|
109
|
+
return this.lowRun = 0, {
|
|
110
|
+
pass: !e,
|
|
111
|
+
reason: e ? "calibrating" : "reference-silent",
|
|
112
|
+
coherence: null
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
let c = this.params.windowFrames;
|
|
116
|
+
if (this.windowMax(this.ref, n - s.lag, c + 6) <= this.params.referenceSilentDb) return this.lowRun = 0, {
|
|
117
|
+
pass: !0,
|
|
118
|
+
reason: "reference-silent",
|
|
119
|
+
coherence: null
|
|
120
|
+
};
|
|
121
|
+
let { corr: l, refFlat: u } = this.coherence(n, s.lag);
|
|
122
|
+
if (l === null) return this.lowRun = 0, {
|
|
123
|
+
pass: !1,
|
|
124
|
+
reason: "calibrating",
|
|
125
|
+
coherence: null
|
|
126
|
+
};
|
|
127
|
+
if (u) return {
|
|
128
|
+
pass: !1,
|
|
129
|
+
reason: "flat-reference",
|
|
130
|
+
coherence: l
|
|
131
|
+
};
|
|
132
|
+
this.lowRun = l < this.params.lowCorr ? this.lowRun + 1 : 0;
|
|
133
|
+
let d = this.headset ? this.params.headsetLowRunFrames : this.params.lowRunFrames, f = this.lowRun >= d;
|
|
134
|
+
return {
|
|
135
|
+
pass: f,
|
|
136
|
+
reason: f ? "uncorrelated" : "follows-reference",
|
|
137
|
+
coherence: l
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
at(e, t) {
|
|
141
|
+
return e[t - this.base];
|
|
142
|
+
}
|
|
143
|
+
windowMax(e, t, n) {
|
|
144
|
+
let r = this.params.floorDb;
|
|
145
|
+
for (let i = t - n; i <= t; i += 1) {
|
|
146
|
+
let t = this.at(e, i);
|
|
147
|
+
t !== void 0 && t > r && (r = t);
|
|
148
|
+
}
|
|
149
|
+
return r;
|
|
150
|
+
}
|
|
151
|
+
coherence(e, t) {
|
|
152
|
+
let n = this.params.windowFrames, r = [], i = [];
|
|
153
|
+
for (let a = e - n + 1; a <= e; a += 1) {
|
|
154
|
+
let e = this.at(this.mic, a), n = this.at(this.tail, a - t);
|
|
155
|
+
if (e === void 0 || n === void 0) return {
|
|
156
|
+
corr: null,
|
|
157
|
+
refFlat: !1
|
|
158
|
+
};
|
|
159
|
+
r.push(e), i.push(n);
|
|
160
|
+
}
|
|
161
|
+
return a(r, i, this.params.flatStdDb);
|
|
162
|
+
}
|
|
163
|
+
calibrate(e) {
|
|
164
|
+
let t = Math.max(this.playStart, e - n + 1), r = [], o = 0;
|
|
165
|
+
for (let n = t; n <= e; n += 1) {
|
|
166
|
+
let e = this.at(this.mic, n), t = this.at(this.ref, n);
|
|
167
|
+
e !== void 0 && r.push(e), t !== void 0 && t > this.params.referenceSilentDb && (o += 1);
|
|
168
|
+
}
|
|
169
|
+
if (o < this.params.calibFrames * .6) return;
|
|
170
|
+
let s = null;
|
|
171
|
+
for (let n = 0; n <= this.params.maxLagFrames; n += 1) {
|
|
172
|
+
let r = [], i = [];
|
|
173
|
+
for (let a = t; a <= e; a += 1) {
|
|
174
|
+
let e = this.at(this.mic, a), t = this.at(this.tail, a - n);
|
|
175
|
+
e !== void 0 && t !== void 0 && (r.push(e), i.push(t));
|
|
176
|
+
}
|
|
177
|
+
if (r.length < 30) continue;
|
|
178
|
+
let { corr: o, refFlat: c } = a(r, i, this.params.flatStdDb);
|
|
179
|
+
c || (!s || o > s.corr) && (s = {
|
|
180
|
+
lag: n,
|
|
181
|
+
corr: o
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (s && s.corr >= this.params.minCalibCorr) {
|
|
185
|
+
this.current = s, this.prior = s;
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
i(r, .9) <= this.params.quietMicDb && (this.noEchoPath = !0);
|
|
189
|
+
}
|
|
190
|
+
trim() {
|
|
191
|
+
this.mic.length <= t || (this.mic = this.mic.slice(r), this.ref = this.ref.slice(r), this.tail = this.tail.slice(r), this.base += r);
|
|
192
|
+
}
|
|
193
|
+
reset() {
|
|
194
|
+
this.mic = [], this.ref = [], this.tail = [], this.base = 0, this.total = 0, this.playing = !1, this.armedUntil = -1, this.current = null, this.prior = null, this.noEchoPath = !1, this.lowRun = 0;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
//#endregion
|
|
198
|
+
export { e as DEFAULT_ECHO_GATE_PARAMS, o as EchoGate };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { CaptureFrameMessage } from './captureWorklet';
|
|
2
|
+
import { EpochGuard } from './bargeIn';
|
|
3
|
+
import { MicCaptureHandle } from './micCapture';
|
|
4
|
+
import { PlaybackSource } from './playbackReference';
|
|
5
|
+
import { SttTransport } from './sttTransport';
|
|
6
|
+
import { VoiceSessionPhase } from '../voiceSession';
|
|
7
|
+
export type FallbackReason = "mic-denied" | "mic-unavailable" | "transport-unavailable" | "transport-auth" | "transport-quota" | "transport-upstream" | "phantom-barge-ins";
|
|
8
|
+
export interface ControllerSession {
|
|
9
|
+
phase: VoiceSessionPhase;
|
|
10
|
+
muted: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface ControllerDeps {
|
|
13
|
+
/** Open the microphone; frames are delivered to the callback. */
|
|
14
|
+
startCapture: (onFrame: (frame: CaptureFrameMessage) => void) => Promise<MicCaptureHandle | FakeCapture>;
|
|
15
|
+
transport: SttTransport;
|
|
16
|
+
getSession: () => ControllerSession;
|
|
17
|
+
/** What is making sound right now. */
|
|
18
|
+
getPlaybackSource: () => PlaybackSource;
|
|
19
|
+
/** Is the output route a headset (a hint)? */
|
|
20
|
+
getHeadsetHint?: () => boolean;
|
|
21
|
+
language: () => string;
|
|
22
|
+
/** The user's voice started while the assistant was audible: STOP PLAYBACK and abandon the turn. */
|
|
23
|
+
onBargeIn: () => void;
|
|
24
|
+
/** Words from the user, already epoch-checked. */
|
|
25
|
+
onTranscript: (text: string, final: boolean, language: string | undefined) => void;
|
|
26
|
+
/** Hands-free gave up: the session falls back to the tap-first Web Speech path. */
|
|
27
|
+
onFallback: (reason: FallbackReason) => void;
|
|
28
|
+
/** A barge-in that produced no words within `NOTHING_HEARD_MS`. */
|
|
29
|
+
onNothingHeard?: () => void;
|
|
30
|
+
isEnabled: () => boolean;
|
|
31
|
+
prerollMs?: number;
|
|
32
|
+
setTimer?: (fn: () => void, ms: number) => ReturnType<typeof setTimeout>;
|
|
33
|
+
clearTimer?: (handle: ReturnType<typeof setTimeout>) => void;
|
|
34
|
+
onTelemetry?: (event: ControllerTelemetry) => void;
|
|
35
|
+
}
|
|
36
|
+
/** The slice of a capture handle the controller needs (so tests can fake it). */
|
|
37
|
+
export interface FakeCapture {
|
|
38
|
+
context?: AudioContext;
|
|
39
|
+
micSource?: MediaStreamAudioSourceNode;
|
|
40
|
+
track?: MediaStreamTrack;
|
|
41
|
+
stop(): void;
|
|
42
|
+
}
|
|
43
|
+
export type ControllerTelemetry = {
|
|
44
|
+
type: "onset";
|
|
45
|
+
plan: string;
|
|
46
|
+
atFrame: number;
|
|
47
|
+
playbackSource: PlaybackSource;
|
|
48
|
+
gate: string;
|
|
49
|
+
calibration: {
|
|
50
|
+
lagMs: number;
|
|
51
|
+
corr: number;
|
|
52
|
+
} | null;
|
|
53
|
+
} | {
|
|
54
|
+
type: "stopped-playback";
|
|
55
|
+
frame: number;
|
|
56
|
+
} | {
|
|
57
|
+
type: "stale-transcript-dropped";
|
|
58
|
+
epoch: number;
|
|
59
|
+
current: number;
|
|
60
|
+
} | {
|
|
61
|
+
type: "fallback";
|
|
62
|
+
reason: FallbackReason;
|
|
63
|
+
} | {
|
|
64
|
+
type: "nothing-heard";
|
|
65
|
+
};
|
|
66
|
+
export interface HandsFreeController {
|
|
67
|
+
start(): Promise<void>;
|
|
68
|
+
stop(): void;
|
|
69
|
+
/** Frames consumed so far (for tests and telemetry). */
|
|
70
|
+
readonly frames: number;
|
|
71
|
+
/** Test seam: feed a frame as the worklet would. */
|
|
72
|
+
feed(frame: CaptureFrameMessage): void;
|
|
73
|
+
readonly epoch: EpochGuard;
|
|
74
|
+
readonly running: boolean;
|
|
75
|
+
}
|
|
76
|
+
export declare function createHandsFreeController(deps: ControllerDeps): HandsFreeController;
|
|
77
|
+
//# sourceMappingURL=handsFreeController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handsFreeController.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/handsFreeController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { NOTHING_HEARD_MS as e, createEpochGuard as t, planOnset as n, shouldFallBackToTap as r } from "./bargeIn.js";
|
|
2
|
+
import "./captureWorklet.js";
|
|
3
|
+
import { EchoGate as i } from "./echoGate.js";
|
|
4
|
+
import { MicCaptureError as a } from "./micCapture.js";
|
|
5
|
+
import { PreRollRing as o } from "./preRollRing.js";
|
|
6
|
+
import { DEFAULT_VAD_PARAMS as s, createVad as c } from "./vad.js";
|
|
7
|
+
//#region src/shared/assistant/voice/handsfree/handsFreeController.ts
|
|
8
|
+
var l = {
|
|
9
|
+
unavailable: "transport-unavailable",
|
|
10
|
+
auth: "transport-auth",
|
|
11
|
+
quota: "transport-quota",
|
|
12
|
+
upstream: "transport-upstream",
|
|
13
|
+
closed: "transport-upstream",
|
|
14
|
+
"not-allowed": "mic-denied"
|
|
15
|
+
};
|
|
16
|
+
function u(u) {
|
|
17
|
+
let d = u.setTimer ?? ((e, t) => setTimeout(e, t)), f = u.clearTimer ?? ((e) => clearTimeout(e)), p = new i(), m = c(), h = new o(u.prerollMs ?? 700, 20), g = t(), _ = null, v = !1, y = 0, b = null, x = null, S = 0, C = null, w = 0, T = null, E = !1, D = (e) => u.onTelemetry?.(e), O = (e) => {
|
|
18
|
+
E || (E = !0, D({
|
|
19
|
+
type: "fallback",
|
|
20
|
+
reason: e
|
|
21
|
+
}), P(), u.onFallback(e));
|
|
22
|
+
}, k = () => {
|
|
23
|
+
T !== null && f(T), T = null;
|
|
24
|
+
}, A = (e) => {
|
|
25
|
+
if (e === C) return;
|
|
26
|
+
let t = C;
|
|
27
|
+
C = e, e === null ? p.playbackStopped() : (t === null || t !== e) && p.playbackStarted(e === "hosted"), m.setOnsetFrames(e === "device" ? 6 : s.onsetFrames);
|
|
28
|
+
}, j = () => {
|
|
29
|
+
b &&= (u.transport.closeUtterance(b.id), null);
|
|
30
|
+
}, M = (t) => {
|
|
31
|
+
let i = u.getSession(), a = n({
|
|
32
|
+
enabled: u.isEnabled(),
|
|
33
|
+
muted: i.muted,
|
|
34
|
+
phase: i.phase,
|
|
35
|
+
playbackAudible: C !== null
|
|
36
|
+
});
|
|
37
|
+
if (D({
|
|
38
|
+
type: "onset",
|
|
39
|
+
plan: a.kind,
|
|
40
|
+
atFrame: y,
|
|
41
|
+
playbackSource: C,
|
|
42
|
+
gate: t,
|
|
43
|
+
calibration: p.calibration
|
|
44
|
+
}), a.kind === "ignore") return;
|
|
45
|
+
a.kind === "barge-in" && (u.onBargeIn(), D({
|
|
46
|
+
type: "stopped-playback",
|
|
47
|
+
frame: y
|
|
48
|
+
}), p.playbackStopped(), C = null, k(), u.transport.recognitionOwner === "transport" && (T = d(() => {
|
|
49
|
+
T = null, w += 1, D({ type: "nothing-heard" }), u.onNothingHeard?.(), r(w) && O("phantom-barge-ins");
|
|
50
|
+
}, e))), x && u.transport.cancelUtterance(x);
|
|
51
|
+
let o = g.open();
|
|
52
|
+
S += 1, b = {
|
|
53
|
+
id: `u${S}`,
|
|
54
|
+
epoch: o
|
|
55
|
+
}, x = b.id, u.transport.openUtterance({
|
|
56
|
+
utteranceId: b.id,
|
|
57
|
+
epoch: o,
|
|
58
|
+
preRoll: h.snapshot()
|
|
59
|
+
});
|
|
60
|
+
}, N = (e) => {
|
|
61
|
+
if (!v) return;
|
|
62
|
+
y += 1, A(u.getPlaybackSource()), u.getHeadsetHint && p.setHeadset(u.getHeadsetHint());
|
|
63
|
+
let t = p.pushFrame(e.rmsDb, e.refDb), n = new Int16Array(e.pcm);
|
|
64
|
+
h.push(n);
|
|
65
|
+
let r = m.push({
|
|
66
|
+
rmsDb: e.rmsDb,
|
|
67
|
+
zcr: e.zcr
|
|
68
|
+
}, t.pass);
|
|
69
|
+
r.event === "onset" ? M(t.reason) : b && r.inSegment && u.transport.pushFrame(n), r.event === "end" && j();
|
|
70
|
+
}, P = () => {
|
|
71
|
+
if (!v && !_) return;
|
|
72
|
+
v = !1, k(), b && u.transport.cancelUtterance(b.id), b = null, g.invalidate(), u.transport.stop(), h.clear(), p.reset(), m.reset();
|
|
73
|
+
let e = _;
|
|
74
|
+
_ = null, e?.stop();
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
async start() {
|
|
78
|
+
if (v || E) return;
|
|
79
|
+
let e = u.getSession();
|
|
80
|
+
if (!u.isEnabled() || e.muted || e.phase === "ended" || e.phase === "idle") return;
|
|
81
|
+
v = !0;
|
|
82
|
+
try {
|
|
83
|
+
_ = await u.startCapture(N);
|
|
84
|
+
} catch (e) {
|
|
85
|
+
v = !1, O(e instanceof a && e.reason === "not-allowed" ? "mic-denied" : "mic-unavailable");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (!v) {
|
|
89
|
+
_.stop(), _ = null;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let t = _ && "context" in _ && _.context && _.micSource && _.track ? {
|
|
93
|
+
context: _.context,
|
|
94
|
+
micSource: _.micSource,
|
|
95
|
+
track: _.track
|
|
96
|
+
} : null;
|
|
97
|
+
await u.transport.start(t, u.language(), {
|
|
98
|
+
onTranscript(e) {
|
|
99
|
+
if (!g.accepts(e.epoch)) {
|
|
100
|
+
D({
|
|
101
|
+
type: "stale-transcript-dropped",
|
|
102
|
+
epoch: e.epoch,
|
|
103
|
+
current: g.current()
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
k(), u.onTranscript(e.text, e.final, e.language);
|
|
108
|
+
},
|
|
109
|
+
onError(e) {
|
|
110
|
+
O(l[e.code]);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
stop: P,
|
|
115
|
+
get frames() {
|
|
116
|
+
return y;
|
|
117
|
+
},
|
|
118
|
+
feed: N,
|
|
119
|
+
epoch: g,
|
|
120
|
+
get running() {
|
|
121
|
+
return v;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
export { u as createHandsFreeController };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SttTransport, SttTransportKind, TransportChoice, TransportEnvironment } from './sttTransport';
|
|
2
|
+
/** Feature flag + endpoint for the backend stream. Unset by default: never selected. */
|
|
3
|
+
export interface StreamingConfig {
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
ticketUrl: string;
|
|
6
|
+
getAuthorization: () => string | null;
|
|
7
|
+
}
|
|
8
|
+
/** Configure (or, with `null`, clear) the backend-stream route. Nothing calls this today. */
|
|
9
|
+
export declare function configureHandsFreeStreaming(config: StreamingConfig | null): void;
|
|
10
|
+
export declare function readTransportEnvironment(): TransportEnvironment;
|
|
11
|
+
/** Phones: the OS recogniser and a getUserMedia stream contend for the one microphone. */
|
|
12
|
+
export declare function isMobileUserAgent(userAgent: string): boolean;
|
|
13
|
+
export declare function chooseTransport(env?: TransportEnvironment): TransportChoice;
|
|
14
|
+
export declare function createRuntimeTransport(kind: SttTransportKind): SttTransport;
|
|
15
|
+
//# sourceMappingURL=handsFreeRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handsFreeRuntime.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/handsFreeRuntime.ts"],"names":[],"mappings":"AAiBA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AAOxB,wFAAwF;AACxF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACvC;AAID,6FAA6F;AAC7F,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,eAAe,GAAG,IAAI,GAC7B,IAAI,CAEN;AAaD,wBAAgB,wBAAwB,IAAI,oBAAoB,CAS/D;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,eAAe,CAC7B,GAAG,GAAE,oBAAiD,GACrD,eAAe,CAIjB;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CA0D3E"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readTransportOverride as e } from "./handsFreeSetting.js";
|
|
2
|
+
import { createAudioTrackTransport as t } from "./audioTrackTransport.js";
|
|
3
|
+
import { createBackendStreamTransport as n } from "./backendStreamTransport.js";
|
|
4
|
+
import { isMicCaptureSupported as r } from "./micCapture.js";
|
|
5
|
+
import { selectSttTransport as i } from "./sttTransport.js";
|
|
6
|
+
import { createWebSpeechTransport as a } from "./webSpeechTransport.js";
|
|
7
|
+
//#region src/shared/assistant/voice/handsfree/handsFreeRuntime.ts
|
|
8
|
+
var o = null;
|
|
9
|
+
function s(e) {
|
|
10
|
+
o = e;
|
|
11
|
+
}
|
|
12
|
+
function c() {
|
|
13
|
+
if (typeof window > "u") return null;
|
|
14
|
+
let e = window.SpeechRecognition ?? window.webkitSpeechRecognition;
|
|
15
|
+
return typeof e == "function" ? e : null;
|
|
16
|
+
}
|
|
17
|
+
function l() {
|
|
18
|
+
return {
|
|
19
|
+
userAgent: typeof navigator > "u" ? "" : navigator.userAgent,
|
|
20
|
+
hasSpeechRecognition: c() !== null,
|
|
21
|
+
hasAudioWorklet: r(),
|
|
22
|
+
backendStreamEnabled: o?.enabled === !0,
|
|
23
|
+
backendStreamConfigured: o !== null && o.ticketUrl !== ""
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function u(e) {
|
|
27
|
+
return /Android|iPhone|iPad|iPod|Mobile/.test(e);
|
|
28
|
+
}
|
|
29
|
+
function d(t = l()) {
|
|
30
|
+
let n = e();
|
|
31
|
+
return n ? {
|
|
32
|
+
kind: n,
|
|
33
|
+
because: "test-override"
|
|
34
|
+
} : i(t);
|
|
35
|
+
}
|
|
36
|
+
function f(e) {
|
|
37
|
+
if (e === "audio-track") return t({ createRecognition: () => {
|
|
38
|
+
let e = c();
|
|
39
|
+
return e ? new e() : null;
|
|
40
|
+
} });
|
|
41
|
+
if (e === "backend-stream") {
|
|
42
|
+
let e = o;
|
|
43
|
+
return n({
|
|
44
|
+
fetchTicket: async () => {
|
|
45
|
+
if (!e) throw Error("streaming not configured");
|
|
46
|
+
let t = e.getAuthorization(), n = await fetch(e.ticketUrl, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: t ? { authorization: t } : {},
|
|
49
|
+
credentials: "include"
|
|
50
|
+
});
|
|
51
|
+
if (!n.ok) throw Error(`ticket ${n.status}`);
|
|
52
|
+
let r = await n.json(), i = typeof r == "object" && r ? r : {};
|
|
53
|
+
if (typeof i.ticket != "string" || typeof i.wsUrl != "string") throw Error("bad ticket response");
|
|
54
|
+
return {
|
|
55
|
+
ticket: i.ticket,
|
|
56
|
+
wsUrl: i.wsUrl
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
createSocket: (e, t) => {
|
|
60
|
+
let n = new WebSocket(e, t);
|
|
61
|
+
return n.binaryType = "arraybuffer", {
|
|
62
|
+
get readyState() {
|
|
63
|
+
return n.readyState;
|
|
64
|
+
},
|
|
65
|
+
send: (e) => n.send(e),
|
|
66
|
+
close: (e) => n.close(e),
|
|
67
|
+
listen(e) {
|
|
68
|
+
n.onopen = () => e.open(), n.onerror = () => e.error(), n.onclose = (t) => e.close(t.code), n.onmessage = (t) => e.message(t.data);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
languages: (e) => e.toLowerCase().startsWith("en") ? [e] : [e, "en-IN"]
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return a();
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { d as chooseTransport, s as configureHandsFreeStreaming, f as createRuntimeTransport, u as isMobileUserAgent, l as readTransportEnvironment };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The "Hands-free interrupt (beta)" setting (BOFF-8613, H3).
|
|
3
|
+
*
|
|
4
|
+
* Default OFF. The viewer's choice is persisted in the assistant store
|
|
5
|
+
* (`handsFreeInterrupt`) next to the grace preference; this file is the pure
|
|
6
|
+
* part - how a stored value and the test-only override resolve to a decision.
|
|
7
|
+
*
|
|
8
|
+
* ★ OFF means OFF. With the setting off nothing in this directory runs: no
|
|
9
|
+
* `getUserMedia`, no worklet, no transport, no listener, and the Web Speech
|
|
10
|
+
* path behaves exactly as it did before this change. That is what makes the
|
|
11
|
+
* feature reversible by a toggle.
|
|
12
|
+
*
|
|
13
|
+
* The TEST-ONLY override is a global the headless-browser tests set before the
|
|
14
|
+
* page loads (`globalThis.__boffHandsFreeInterrupt = "on"`), so a test does not
|
|
15
|
+
* have to click through settings. It can only affect the client that set it.
|
|
16
|
+
*/
|
|
17
|
+
export type HandsFreeOverride = "on" | "off";
|
|
18
|
+
export declare const HANDS_FREE_OVERRIDE_KEY = "__boffHandsFreeInterrupt";
|
|
19
|
+
export declare const HANDS_FREE_TRANSPORT_OVERRIDE_KEY = "__boffHandsFreeTransport";
|
|
20
|
+
/** The stored value is trusted only if it is exactly `true`; anything else is OFF. */
|
|
21
|
+
export declare function resolveStoredHandsFree(value: unknown): boolean;
|
|
22
|
+
export declare function resolveHandsFreeEnabled(stored: unknown, override: unknown): boolean;
|
|
23
|
+
export declare function readHandsFreeOverride(): HandsFreeOverride | undefined;
|
|
24
|
+
export type TransportOverride = "web-speech" | "audio-track" | "backend-stream";
|
|
25
|
+
export declare function readTransportOverride(): TransportOverride | undefined;
|
|
26
|
+
//# sourceMappingURL=handsFreeSetting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handsFreeSetting.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/handsFreeSetting.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,KAAK,CAAC;AAE7C,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAClE,eAAO,MAAM,iCAAiC,6BAA6B,CAAC;AAE5E,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE9D;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,OAAO,GAChB,OAAO,CAIT;AAWD,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,SAAS,CAGrE;AAED,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEhF,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,SAAS,CAOrE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/shared/assistant/voice/handsfree/handsFreeSetting.ts
|
|
2
|
+
var e = "__boffHandsFreeInterrupt", t = "__boffHandsFreeTransport";
|
|
3
|
+
function n(e) {
|
|
4
|
+
return e === !0;
|
|
5
|
+
}
|
|
6
|
+
function r(e, t) {
|
|
7
|
+
return t === "on" ? !0 : t === "off" ? !1 : n(e);
|
|
8
|
+
}
|
|
9
|
+
function i(e) {
|
|
10
|
+
try {
|
|
11
|
+
return globalThis[e];
|
|
12
|
+
} catch {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function a() {
|
|
17
|
+
let t = i(e);
|
|
18
|
+
return t === "on" || t === "off" ? t : void 0;
|
|
19
|
+
}
|
|
20
|
+
function o() {
|
|
21
|
+
let e = i(t);
|
|
22
|
+
return e === "web-speech" || e === "audio-track" || e === "backend-stream" ? e : void 0;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { e as HANDS_FREE_OVERRIDE_KEY, t as HANDS_FREE_TRANSPORT_OVERRIDE_KEY, a as readHandsFreeOverride, o as readTransportOverride, r as resolveHandsFreeEnabled, n as resolveStoredHandsFree };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CaptureFrameMessage } from './captureWorklet';
|
|
2
|
+
export interface MicCaptureHandle {
|
|
3
|
+
context: AudioContext;
|
|
4
|
+
micSource: MediaStreamAudioSourceNode;
|
|
5
|
+
track: MediaStreamTrack;
|
|
6
|
+
/** What the browser reports it applied. */
|
|
7
|
+
settings: MediaTrackSettings;
|
|
8
|
+
/** Stop everything and release the microphone. */
|
|
9
|
+
stop(): void;
|
|
10
|
+
}
|
|
11
|
+
export type MicCaptureFailure = "unsupported" | "not-allowed" | "unavailable";
|
|
12
|
+
export declare class MicCaptureError extends Error {
|
|
13
|
+
readonly reason: MicCaptureFailure;
|
|
14
|
+
constructor(reason: MicCaptureFailure);
|
|
15
|
+
}
|
|
16
|
+
export declare const CAPTURE_CONSTRAINTS: MediaStreamConstraints;
|
|
17
|
+
export declare function isMicCaptureSupported(): boolean;
|
|
18
|
+
/** Labels of output devices that suggest headphones. A HINT only. */
|
|
19
|
+
export declare function looksLikeHeadset(outputLabels: readonly string[]): boolean;
|
|
20
|
+
export declare function startMicCapture(onFrame: (frame: CaptureFrameMessage) => void): Promise<MicCaptureHandle>;
|
|
21
|
+
//# sourceMappingURL=micCapture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"micCapture.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/voice/handsfree/micCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,0BAA0B,CAAC;IACtC,KAAK,EAAE,gBAAgB,CAAC;IACxB,2CAA2C;IAC3C,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,kDAAkD;IAClD,IAAI,IAAI,IAAI,CAAC;CACd;AAED,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,CAAC;AAE9E,qBAAa,eAAgB,SAAQ,KAAK;IAC5B,QAAQ,CAAC,MAAM,EAAE,iBAAiB;gBAAzB,MAAM,EAAE,iBAAiB;CAI/C;AAED,eAAO,MAAM,mBAAmB,EAAE,sBAOjC,CAAC;AAEF,wBAAgB,qBAAqB,IAAI,OAAO,CAO/C;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAIzE;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GAC5C,OAAO,CAAC,gBAAgB,CAAC,CA8E3B"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { attachPlaybackReference as e, detachPlaybackReference as t } from "./playbackReference.js";
|
|
2
|
+
import { CAPTURE_PROCESSOR_NAME as n, CAPTURE_WORKLET_SOURCE as r } from "./captureWorklet.js";
|
|
3
|
+
//#region src/shared/assistant/voice/handsfree/micCapture.ts
|
|
4
|
+
var i = class extends Error {
|
|
5
|
+
reason;
|
|
6
|
+
constructor(e) {
|
|
7
|
+
super(`mic capture failed: ${e}`), this.reason = e, this.name = "MicCaptureError";
|
|
8
|
+
}
|
|
9
|
+
}, a = { audio: {
|
|
10
|
+
echoCancellation: !0,
|
|
11
|
+
noiseSuppression: !0,
|
|
12
|
+
autoGainControl: !0,
|
|
13
|
+
channelCount: 1
|
|
14
|
+
} };
|
|
15
|
+
function o() {
|
|
16
|
+
return typeof navigator < "u" && typeof navigator.mediaDevices?.getUserMedia == "function" && typeof AudioContext < "u" && typeof AudioWorkletNode < "u";
|
|
17
|
+
}
|
|
18
|
+
function s(e) {
|
|
19
|
+
return e.some((e) => /head(phone|set)|earbud|earphone|airpods|buds|bluetooth/i.test(e));
|
|
20
|
+
}
|
|
21
|
+
async function c(s) {
|
|
22
|
+
if (!o()) throw new i("unsupported");
|
|
23
|
+
let c;
|
|
24
|
+
try {
|
|
25
|
+
c = await navigator.mediaDevices.getUserMedia(a);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
let t = e instanceof DOMException ? e.name : "";
|
|
28
|
+
throw new i(t === "NotAllowedError" || t === "SecurityError" ? "not-allowed" : "unavailable");
|
|
29
|
+
}
|
|
30
|
+
let l = c.getAudioTracks()[0];
|
|
31
|
+
if (!l) throw c.getTracks().forEach((e) => e.stop()), new i("unavailable");
|
|
32
|
+
let u = new AudioContext({ latencyHint: "interactive" }), d = () => {
|
|
33
|
+
c.getTracks().forEach((e) => e.stop());
|
|
34
|
+
};
|
|
35
|
+
try {
|
|
36
|
+
await u.resume();
|
|
37
|
+
let i = URL.createObjectURL(new Blob([r], { type: "text/javascript" }));
|
|
38
|
+
try {
|
|
39
|
+
await u.audioWorklet.addModule(i);
|
|
40
|
+
} finally {
|
|
41
|
+
URL.revokeObjectURL(i);
|
|
42
|
+
}
|
|
43
|
+
let a = new AudioWorkletNode(u, n, {
|
|
44
|
+
numberOfInputs: 2,
|
|
45
|
+
numberOfOutputs: 0
|
|
46
|
+
}), o = u.createGain();
|
|
47
|
+
o.connect(a, 0, 1), a.port.onmessage = (e) => s(e.data);
|
|
48
|
+
let f = u.createMediaStreamSource(c);
|
|
49
|
+
f.connect(a, 0, 0), e(u, o);
|
|
50
|
+
let p = !1, m = () => h.stop(), h = {
|
|
51
|
+
context: u,
|
|
52
|
+
micSource: f,
|
|
53
|
+
track: l,
|
|
54
|
+
settings: l.getSettings(),
|
|
55
|
+
stop() {
|
|
56
|
+
if (!p) {
|
|
57
|
+
p = !0, window.removeEventListener("pagehide", m), a.port.onmessage = null;
|
|
58
|
+
try {
|
|
59
|
+
a.port.postMessage({ type: "stop" }), f.disconnect();
|
|
60
|
+
} catch {}
|
|
61
|
+
d(), t(() => {
|
|
62
|
+
u.close().catch(() => void 0);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return window.addEventListener("pagehide", m), h;
|
|
68
|
+
} catch (e) {
|
|
69
|
+
throw d(), u.close().catch(() => void 0), e instanceof i ? e : new i("unavailable");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { a as CAPTURE_CONSTRAINTS, i as MicCaptureError, o as isMicCaptureSupported, s as looksLikeHeadset, c as startMicCapture };
|