@burdenoff/website-sdk 2026.1105.3 → 2026.1106.1
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/README.md +79 -0
- package/dist/avatar-live-view/index.d.mts +1 -1
- package/dist/avatar-live-view/index.d.ts +1 -1
- package/dist/avatar-live-view/index.js +850 -175
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +843 -168
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/avatar-mic/index.d.mts +54 -60
- package/dist/avatar-mic/index.d.ts +54 -60
- package/dist/avatar-mic/index.js +283 -23
- package/dist/avatar-mic/index.js.map +1 -1
- package/dist/avatar-mic/index.mjs +283 -23
- package/dist/avatar-mic/index.mjs.map +1 -1
- package/dist/{chunk-JGU6JW4N.mjs → chunk-BHEHF3Y5.mjs} +2 -2
- package/dist/{chunk-JGU6JW4N.mjs.map → chunk-BHEHF3Y5.mjs.map} +1 -1
- package/dist/{chunk-3AIAJ2L4.js → chunk-Z2UP22GV.js} +2 -2
- package/dist/{chunk-3AIAJ2L4.js.map → chunk-Z2UP22GV.js.map} +1 -1
- package/dist/{explore-avatar-live-config-1zeXdMer.d.ts → explore-avatar-live-config-CJstiSAN.d.ts} +5 -1
- package/dist/{explore-avatar-live-config-BxiE66Im.d.mts → explore-avatar-live-config-D2PGF8fG.d.mts} +5 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -5
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,145 @@
|
|
|
1
1
|
import { __publicField } from '../chunk-VNS5WDWO.mjs';
|
|
2
2
|
|
|
3
|
+
// src/avatar-mic/speech-words.ts
|
|
4
|
+
var FILLERS = /* @__PURE__ */ new Set([
|
|
5
|
+
"uh",
|
|
6
|
+
"um",
|
|
7
|
+
"uhm",
|
|
8
|
+
"umm",
|
|
9
|
+
"er",
|
|
10
|
+
"erm",
|
|
11
|
+
"eh",
|
|
12
|
+
"ah",
|
|
13
|
+
"hm",
|
|
14
|
+
"hmm",
|
|
15
|
+
"hmmm",
|
|
16
|
+
"mm",
|
|
17
|
+
"mmm",
|
|
18
|
+
"mhm",
|
|
19
|
+
"huh",
|
|
20
|
+
"oh",
|
|
21
|
+
"so",
|
|
22
|
+
"well",
|
|
23
|
+
"okay",
|
|
24
|
+
"ok",
|
|
25
|
+
"and",
|
|
26
|
+
"like",
|
|
27
|
+
"hey",
|
|
28
|
+
"hi",
|
|
29
|
+
"hello",
|
|
30
|
+
"actually"
|
|
31
|
+
]);
|
|
32
|
+
var OPEN_ENDINGS = /* @__PURE__ */ new Set([
|
|
33
|
+
"the",
|
|
34
|
+
"a",
|
|
35
|
+
"an",
|
|
36
|
+
"of",
|
|
37
|
+
"to",
|
|
38
|
+
"for",
|
|
39
|
+
"about",
|
|
40
|
+
"and",
|
|
41
|
+
"or",
|
|
42
|
+
"but",
|
|
43
|
+
"what",
|
|
44
|
+
"how",
|
|
45
|
+
"which",
|
|
46
|
+
"is",
|
|
47
|
+
"are",
|
|
48
|
+
"can"
|
|
49
|
+
]);
|
|
50
|
+
var PRONOUNS = /* @__PURE__ */ new Set([
|
|
51
|
+
"i",
|
|
52
|
+
"me",
|
|
53
|
+
"you",
|
|
54
|
+
"it",
|
|
55
|
+
"we",
|
|
56
|
+
"us",
|
|
57
|
+
"they",
|
|
58
|
+
"them",
|
|
59
|
+
"he",
|
|
60
|
+
"him",
|
|
61
|
+
"she",
|
|
62
|
+
"her",
|
|
63
|
+
"this",
|
|
64
|
+
"that",
|
|
65
|
+
"these",
|
|
66
|
+
"those"
|
|
67
|
+
]);
|
|
68
|
+
var ECHO_MIN_WORDS = 3;
|
|
69
|
+
var SELF_CONTAINED_SCRIPT = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
|
70
|
+
function tidyWords(text) {
|
|
71
|
+
return text.replace(/\s+/g, " ").trim();
|
|
72
|
+
}
|
|
73
|
+
function speechWords(text) {
|
|
74
|
+
const flat = text.toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, " ").trim();
|
|
75
|
+
return flat === "" ? [] : flat.split(" ");
|
|
76
|
+
}
|
|
77
|
+
function startsWithWords(whole, head) {
|
|
78
|
+
return head.length <= whole.length && head.every((word, index) => whole[index] === word);
|
|
79
|
+
}
|
|
80
|
+
function endsWithWords(whole, tail) {
|
|
81
|
+
return tail.length <= whole.length && tail.every(
|
|
82
|
+
(word, index) => whole[whole.length - tail.length + index] === word
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
function startsWithWordsOf(text, head) {
|
|
86
|
+
return startsWithWords(speechWords(text), speechWords(head));
|
|
87
|
+
}
|
|
88
|
+
function mergeTurnPhrase(turn, phrase) {
|
|
89
|
+
const heard = speechWords(turn);
|
|
90
|
+
const incoming = speechWords(phrase);
|
|
91
|
+
if (incoming.length === 0) return turn;
|
|
92
|
+
if (heard.length === 0) return tidyWords(phrase);
|
|
93
|
+
if (startsWithWords(incoming, heard)) {
|
|
94
|
+
return incoming.length === heard.length ? turn : tidyWords(phrase);
|
|
95
|
+
}
|
|
96
|
+
if (incoming.length >= 2 && endsWithWords(heard, incoming)) return turn;
|
|
97
|
+
return tidyWords(`${turn} ${phrase}`);
|
|
98
|
+
}
|
|
99
|
+
function mergeInterim(turn, interim) {
|
|
100
|
+
const said = tidyWords(interim);
|
|
101
|
+
if (said === "") return turn;
|
|
102
|
+
const head = speechWords(turn);
|
|
103
|
+
if (head.length === 0) return said;
|
|
104
|
+
const tokens = said.split(" ");
|
|
105
|
+
let matched = 0;
|
|
106
|
+
for (let at = 0; at < tokens.length; at += 1) {
|
|
107
|
+
const words = speechWords(tokens[at] ?? "");
|
|
108
|
+
for (const word of words) {
|
|
109
|
+
if (word !== head[matched]) return tidyWords(`${turn} ${said}`);
|
|
110
|
+
matched += 1;
|
|
111
|
+
if (matched === head.length) {
|
|
112
|
+
return tidyWords(`${turn} ${tokens.slice(at + 1).join(" ")}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return tidyWords(`${turn} ${said}`);
|
|
117
|
+
}
|
|
118
|
+
function saidWords(words) {
|
|
119
|
+
return words.filter((word) => !FILLERS.has(word));
|
|
120
|
+
}
|
|
121
|
+
function isGenuineSpeech(text) {
|
|
122
|
+
const said = saidWords(speechWords(text));
|
|
123
|
+
if (said.length === 1 && PRONOUNS.has(said[0] ?? "")) return false;
|
|
124
|
+
const content = said.filter((word) => !OPEN_ENDINGS.has(word));
|
|
125
|
+
if (content.length === 0) return false;
|
|
126
|
+
const letters = [...content.join("")];
|
|
127
|
+
if (letters.length >= 2) return true;
|
|
128
|
+
return letters.length === 1 && SELF_CONTAINED_SCRIPT.test(letters[0] ?? "");
|
|
129
|
+
}
|
|
130
|
+
function waitsLonger(text) {
|
|
131
|
+
const words = speechWords(text);
|
|
132
|
+
const last = words[words.length - 1];
|
|
133
|
+
if (last === void 0) return false;
|
|
134
|
+
return saidWords(words).length <= 1 || OPEN_ENDINGS.has(last) || FILLERS.has(last);
|
|
135
|
+
}
|
|
136
|
+
function isEchoOf(text, spoken) {
|
|
137
|
+
if (spoken === null) return false;
|
|
138
|
+
const heard = speechWords(text);
|
|
139
|
+
if (heard.length < ECHO_MIN_WORDS) return false;
|
|
140
|
+
return ` ${speechWords(spoken).join(" ")} `.includes(` ${heard.join(" ")} `);
|
|
141
|
+
}
|
|
142
|
+
|
|
3
143
|
// src/avatar-mic/browser-press.ts
|
|
4
144
|
var BROWSER_START_WAIT_MS = 15e3;
|
|
5
145
|
var BROWSER_FINAL_WAIT_MS = 3e3;
|
|
@@ -9,6 +149,11 @@ var BROWSER_MAX_QUICK_ENDS = 8;
|
|
|
9
149
|
var BROWSER_MAX_RESTARTS = 60;
|
|
10
150
|
var BROWSER_PRIME_SETTLE_MS = 250;
|
|
11
151
|
var BROWSER_GRANT_RETRY_MS = 350;
|
|
152
|
+
var BROWSER_PAUSE_MIN_MS = 2e3;
|
|
153
|
+
var BROWSER_PAUSE_MAX_MS = 2500;
|
|
154
|
+
var BROWSER_PAUSE_AFTER_START_MS = 1500;
|
|
155
|
+
var BROWSER_PAUSE_SHOWN_MS = 800;
|
|
156
|
+
var BROWSER_ECHO_WINDOW_MS = 2500;
|
|
12
157
|
var QUICK_END_MS = 1e3;
|
|
13
158
|
var NETWORK_FAILURES_FOR_GOOD = 2;
|
|
14
159
|
var IDLE = { name: "idle" };
|
|
@@ -80,8 +225,7 @@ function readRecognitionResults(results) {
|
|
|
80
225
|
continue;
|
|
81
226
|
}
|
|
82
227
|
const last = finals.length > 0 ? finals[finals.length - 1] : void 0;
|
|
83
|
-
|
|
84
|
-
if (last !== void 0 && (lower === last.toLowerCase() || lower.startsWith(`${last.toLowerCase()} `))) {
|
|
228
|
+
if (last !== void 0 && startsWithWordsOf(text, last)) {
|
|
85
229
|
finals[finals.length - 1] = text;
|
|
86
230
|
} else {
|
|
87
231
|
finals.push(text);
|
|
@@ -91,6 +235,11 @@ function readRecognitionResults(results) {
|
|
|
91
235
|
}
|
|
92
236
|
function createBrowserAvatarMic(options, seams = {}) {
|
|
93
237
|
const { createRecognition, now, primeMicrophone, watchMicPermission, touch } = { ...BROWSER, ...seams };
|
|
238
|
+
const { endpoint } = options;
|
|
239
|
+
const pauseMs = endpoint === void 0 || !Number.isFinite(endpoint.pauseMs) ? BROWSER_PAUSE_MIN_MS : Math.min(
|
|
240
|
+
BROWSER_PAUSE_MAX_MS,
|
|
241
|
+
Math.max(BROWSER_PAUSE_MIN_MS, endpoint.pauseMs)
|
|
242
|
+
);
|
|
94
243
|
let press = null;
|
|
95
244
|
let epoch = 0;
|
|
96
245
|
let state = IDLE;
|
|
@@ -104,14 +253,23 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
104
253
|
state = next;
|
|
105
254
|
options.onState(next);
|
|
106
255
|
};
|
|
107
|
-
const
|
|
256
|
+
const turnOf = (earlier, instance) => {
|
|
257
|
+
let turn = earlier;
|
|
258
|
+
for (const final of instance?.finals ?? []) {
|
|
259
|
+
turn = mergeTurnPhrase(turn, final);
|
|
260
|
+
}
|
|
261
|
+
return mergeInterim(turn, instance?.interim ?? "");
|
|
262
|
+
};
|
|
263
|
+
const heard = (p) => turnOf(p.earlier, p.instance);
|
|
108
264
|
const show = (p) => {
|
|
109
265
|
if (p.stage === "listening") {
|
|
266
|
+
const text = heard(p);
|
|
110
267
|
report({
|
|
111
268
|
name: "listening",
|
|
112
269
|
epoch: p.epoch,
|
|
113
270
|
startedAt: p.startedAt,
|
|
114
|
-
text
|
|
271
|
+
text,
|
|
272
|
+
...endpoint === void 0 ? {} : { genuine: isGenuineSpeech(text), pausing: p.pausing }
|
|
115
273
|
});
|
|
116
274
|
} else if (p.stage === "finishing") {
|
|
117
275
|
report({
|
|
@@ -138,7 +296,9 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
138
296
|
p.startTimer,
|
|
139
297
|
p.limitTimer,
|
|
140
298
|
p.finalTimer,
|
|
141
|
-
p.launchTimer
|
|
299
|
+
p.launchTimer,
|
|
300
|
+
p.pauseTimer,
|
|
301
|
+
p.pausingTimer
|
|
142
302
|
]) {
|
|
143
303
|
if (timer !== null) clearTimeout(timer);
|
|
144
304
|
}
|
|
@@ -146,6 +306,14 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
146
306
|
p.limitTimer = null;
|
|
147
307
|
p.finalTimer = null;
|
|
148
308
|
p.launchTimer = null;
|
|
309
|
+
p.pauseTimer = null;
|
|
310
|
+
p.pausingTimer = null;
|
|
311
|
+
};
|
|
312
|
+
const clearPause = (p) => {
|
|
313
|
+
if (p.pauseTimer !== null) clearTimeout(p.pauseTimer);
|
|
314
|
+
if (p.pausingTimer !== null) clearTimeout(p.pausingTimer);
|
|
315
|
+
p.pauseTimer = null;
|
|
316
|
+
p.pausingTimer = null;
|
|
149
317
|
};
|
|
150
318
|
const settle = (p, next) => {
|
|
151
319
|
if (p.stage === "ended") return;
|
|
@@ -160,23 +328,104 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
160
328
|
const complete = (p) => {
|
|
161
329
|
const text = heard(p);
|
|
162
330
|
if (text !== "") networkFailures = 0;
|
|
163
|
-
|
|
331
|
+
if (endpoint === void 0) {
|
|
332
|
+
settle(p, { name: "done", epoch: p.epoch, text, limit: p.limit });
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const by = p.stage === "finishing" ? p.by ?? "tap" : p.stage === "starting" ? "silence" : "failed";
|
|
336
|
+
const echo = by === "pause" && p.speechAt !== null && p.speechAt - p.listenedAt <= BROWSER_ECHO_WINDOW_MS && isEchoOf(text, endpoint.echoOf());
|
|
337
|
+
settle(p, {
|
|
338
|
+
name: "done",
|
|
339
|
+
epoch: p.epoch,
|
|
340
|
+
text,
|
|
341
|
+
limit: p.limit,
|
|
342
|
+
by,
|
|
343
|
+
echo
|
|
344
|
+
});
|
|
164
345
|
};
|
|
165
346
|
const fail = (p, reason) => settle(p, { name: "failed", epoch: p.epoch, reason, text: heard(p) });
|
|
166
347
|
const current = (p, instance) => press === p && p.stage !== "ended" && p.instance === instance;
|
|
348
|
+
const armPause = (p, turn, speech) => {
|
|
349
|
+
clearPause(p);
|
|
350
|
+
if (!speech) return;
|
|
351
|
+
const at = now();
|
|
352
|
+
if (!p.pausing) {
|
|
353
|
+
p.pausingTimer = setTimeout(
|
|
354
|
+
() => {
|
|
355
|
+
p.pausingTimer = null;
|
|
356
|
+
if (press !== p || p.stage !== "listening") return;
|
|
357
|
+
p.pausing = true;
|
|
358
|
+
show(p);
|
|
359
|
+
},
|
|
360
|
+
Math.max(0, p.wordsAt + BROWSER_PAUSE_SHOWN_MS - at)
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
const instance = p.instance;
|
|
364
|
+
if (instance === null || !instance.started) return;
|
|
365
|
+
const wait = waitsLonger(turn) ? 2 * pauseMs : pauseMs;
|
|
366
|
+
const due = Math.max(
|
|
367
|
+
p.wordsAt + wait,
|
|
368
|
+
instance.startedAt + BROWSER_PAUSE_AFTER_START_MS
|
|
369
|
+
);
|
|
370
|
+
p.pauseTimer = setTimeout(
|
|
371
|
+
() => {
|
|
372
|
+
p.pauseTimer = null;
|
|
373
|
+
if (press === p && p.stage === "listening" && p.instance === instance) {
|
|
374
|
+
stopRecording(p, "pause");
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
Math.max(0, due - at)
|
|
378
|
+
);
|
|
379
|
+
};
|
|
380
|
+
const listenOn = (p) => {
|
|
381
|
+
if (endpoint === void 0 || p.stage !== "listening") return;
|
|
382
|
+
const turn = heard(p);
|
|
383
|
+
const words = speechWords(turn).join(" ");
|
|
384
|
+
const at = now();
|
|
385
|
+
if (words !== p.words) {
|
|
386
|
+
p.words = words;
|
|
387
|
+
p.wordsAt = at;
|
|
388
|
+
p.pausing = false;
|
|
389
|
+
}
|
|
390
|
+
const speech = isGenuineSpeech(turn);
|
|
391
|
+
if (speech && p.speechAt === null) {
|
|
392
|
+
p.speechAt = at;
|
|
393
|
+
if (p.limitTimer !== null) clearTimeout(p.limitTimer);
|
|
394
|
+
p.limitTimer = setTimeout(() => {
|
|
395
|
+
p.limitTimer = null;
|
|
396
|
+
if (press === p) stopRecording(p, "limit");
|
|
397
|
+
}, options.maxPressMs);
|
|
398
|
+
}
|
|
399
|
+
armPause(p, turn, speech);
|
|
400
|
+
};
|
|
167
401
|
const began = (p, instance) => {
|
|
168
402
|
instance.started = true;
|
|
169
403
|
instance.startedAt = now();
|
|
170
404
|
hadMicrophone = true;
|
|
171
|
-
if (p.stage
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
p.limitTimer =
|
|
178
|
-
|
|
179
|
-
|
|
405
|
+
if (p.stage === "starting") {
|
|
406
|
+
if (p.startTimer !== null) clearTimeout(p.startTimer);
|
|
407
|
+
p.startTimer = null;
|
|
408
|
+
p.stage = "listening";
|
|
409
|
+
p.startedAt = Date.now();
|
|
410
|
+
p.listenedAt = instance.startedAt;
|
|
411
|
+
p.limitTimer = setTimeout(() => {
|
|
412
|
+
p.limitTimer = null;
|
|
413
|
+
if (press !== p) return;
|
|
414
|
+
if (endpoint === void 0) {
|
|
415
|
+
stopRecording(p, "limit");
|
|
416
|
+
} else if (p.stage === "listening" && p.speechAt === null) {
|
|
417
|
+
settle(p, {
|
|
418
|
+
name: "done",
|
|
419
|
+
epoch: p.epoch,
|
|
420
|
+
text: "",
|
|
421
|
+
limit: false,
|
|
422
|
+
by: "silence",
|
|
423
|
+
echo: false
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}, options.maxPressMs);
|
|
427
|
+
}
|
|
428
|
+
listenOn(p);
|
|
180
429
|
};
|
|
181
430
|
const launchIn = (p, delay) => {
|
|
182
431
|
if (delay <= 0) {
|
|
@@ -202,9 +451,7 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
202
451
|
);
|
|
203
452
|
};
|
|
204
453
|
const keep = (p, instance) => {
|
|
205
|
-
|
|
206
|
-
if (text !== "") p.earlier.push(text);
|
|
207
|
-
}
|
|
454
|
+
p.earlier = turnOf(p.earlier, instance);
|
|
208
455
|
};
|
|
209
456
|
const onError = (p, instance, code) => {
|
|
210
457
|
if (code === "no-speech") {
|
|
@@ -270,6 +517,8 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
270
517
|
else fail(p, "failed");
|
|
271
518
|
return;
|
|
272
519
|
case "listening": {
|
|
520
|
+
if (p.pauseTimer !== null) clearTimeout(p.pauseTimer);
|
|
521
|
+
p.pauseTimer = null;
|
|
273
522
|
const quick = !instance.started || now() - instance.startedAt < QUICK_END_MS && instance.finals.length === 0 && instance.interim === "";
|
|
274
523
|
restart(p, quick ? "quick" : "listened");
|
|
275
524
|
return;
|
|
@@ -316,6 +565,7 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
316
565
|
const read = readRecognitionResults(event.results);
|
|
317
566
|
instance.finals = read.finals;
|
|
318
567
|
instance.interim = read.interim;
|
|
568
|
+
listenOn(p);
|
|
319
569
|
show(p);
|
|
320
570
|
};
|
|
321
571
|
recognition.onerror = (event) => {
|
|
@@ -359,14 +609,16 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
359
609
|
}
|
|
360
610
|
);
|
|
361
611
|
}
|
|
362
|
-
function stopRecording(p,
|
|
612
|
+
function stopRecording(p, by) {
|
|
363
613
|
if (p.stage !== "listening") return;
|
|
364
614
|
if (p.limitTimer !== null) clearTimeout(p.limitTimer);
|
|
365
615
|
if (p.launchTimer !== null) clearTimeout(p.launchTimer);
|
|
366
616
|
p.limitTimer = null;
|
|
367
617
|
p.launchTimer = null;
|
|
618
|
+
clearPause(p);
|
|
368
619
|
p.stage = "finishing";
|
|
369
|
-
p.limit = limit;
|
|
620
|
+
p.limit = by === "limit";
|
|
621
|
+
p.by = by;
|
|
370
622
|
const instance = p.instance;
|
|
371
623
|
if (instance === null || !instance.started) {
|
|
372
624
|
complete(p);
|
|
@@ -414,7 +666,7 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
414
666
|
epoch,
|
|
415
667
|
stage: "starting",
|
|
416
668
|
instance: null,
|
|
417
|
-
earlier:
|
|
669
|
+
earlier: "",
|
|
418
670
|
lang: options.lang,
|
|
419
671
|
langRetried: false,
|
|
420
672
|
restarts: 0,
|
|
@@ -427,7 +679,15 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
427
679
|
startTimer: null,
|
|
428
680
|
limitTimer: null,
|
|
429
681
|
finalTimer: null,
|
|
430
|
-
launchTimer: null
|
|
682
|
+
launchTimer: null,
|
|
683
|
+
by: null,
|
|
684
|
+
words: "",
|
|
685
|
+
wordsAt: 0,
|
|
686
|
+
speechAt: null,
|
|
687
|
+
listenedAt: 0,
|
|
688
|
+
pausing: false,
|
|
689
|
+
pauseTimer: null,
|
|
690
|
+
pausingTimer: null
|
|
431
691
|
};
|
|
432
692
|
press = p;
|
|
433
693
|
report({ name: "starting", epoch });
|
|
@@ -444,7 +704,7 @@ function createBrowserAvatarMic(options, seams = {}) {
|
|
|
444
704
|
const p = press;
|
|
445
705
|
if (p === null) return;
|
|
446
706
|
if (p.stage === "starting") cancel();
|
|
447
|
-
else stopRecording(p,
|
|
707
|
+
else stopRecording(p, "tap");
|
|
448
708
|
},
|
|
449
709
|
cancel,
|
|
450
710
|
state: () => state
|