@agimon-ai/po-voice 0.0.0-alpha.0

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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +13 -0
  3. package/README.md +249 -0
  4. package/dist/apiContracts.cjs +809 -0
  5. package/dist/apiContracts.cjs.map +1 -0
  6. package/dist/apiContracts.d.mts +53 -0
  7. package/dist/apiContracts.d.mts.map +1 -0
  8. package/dist/apiContracts.mjs +805 -0
  9. package/dist/apiContracts.mjs.map +1 -0
  10. package/dist/assets/browserCaptureWorklet-Droj0fW0.js +13 -0
  11. package/dist/assets/silero_vad_v6.2.1-SjbCxFXk.onnx +0 -0
  12. package/dist/clientCaptureActivity-DN4xQtmw.d.mts +234 -0
  13. package/dist/clientCaptureActivity-DN4xQtmw.d.mts.map +1 -0
  14. package/dist/clientMedia-CfTfc9_4.mjs +49 -0
  15. package/dist/clientMedia-CfTfc9_4.mjs.map +1 -0
  16. package/dist/clientMedia-DuA4aYhD.cjs +156 -0
  17. package/dist/clientMedia-DuA4aYhD.cjs.map +1 -0
  18. package/dist/clientMedia.cjs +134 -0
  19. package/dist/clientMedia.cjs.map +1 -0
  20. package/dist/clientMedia.d.mts +2 -0
  21. package/dist/clientMedia.mjs +114 -0
  22. package/dist/clientMedia.mjs.map +1 -0
  23. package/dist/extensions/server.cjs +8975 -0
  24. package/dist/extensions/server.cjs.map +1 -0
  25. package/dist/extensions/server.d.mts +5 -0
  26. package/dist/extensions/server.d.mts.map +1 -0
  27. package/dist/extensions/server.mjs +8968 -0
  28. package/dist/extensions/server.mjs.map +1 -0
  29. package/dist/extensions/web.mjs +4530 -0
  30. package/dist/extensions/web.mjs.map +1 -0
  31. package/dist/index-C95HCjmT.d.mts +212 -0
  32. package/dist/index-C95HCjmT.d.mts.map +1 -0
  33. package/dist/index.cjs +637 -0
  34. package/dist/index.cjs.map +1 -0
  35. package/dist/index.d.mts +603 -0
  36. package/dist/index.d.mts.map +1 -0
  37. package/dist/index.mjs +557 -0
  38. package/dist/index.mjs.map +1 -0
  39. package/dist/narrationBargeIn-C_Po8fgw.mjs +62 -0
  40. package/dist/narrationBargeIn-C_Po8fgw.mjs.map +1 -0
  41. package/dist/narrationBargeIn-Dje82XOm.cjs +73 -0
  42. package/dist/narrationBargeIn-Dje82XOm.cjs.map +1 -0
  43. package/dist/sileroVadWorker-D894njUe.mjs +110 -0
  44. package/dist/sileroVadWorker-D894njUe.mjs.map +1 -0
  45. package/dist/vad-DDe4RIdW.mjs +315 -0
  46. package/dist/vad-DDe4RIdW.mjs.map +1 -0
  47. package/dist/vad-n2RlruzB.cjs +332 -0
  48. package/dist/vad-n2RlruzB.cjs.map +1 -0
  49. package/dist/voiceReloadHandoff.cjs +9 -0
  50. package/dist/voiceReloadHandoff.d.mts +1 -0
  51. package/dist/voiceReloadHandoff.mjs +2 -0
  52. package/dist/voiceTools-CRQHK_Uc.cjs +616 -0
  53. package/dist/voiceTools-CRQHK_Uc.cjs.map +1 -0
  54. package/dist/voiceTools-aCCREMjS.mjs +611 -0
  55. package/dist/voiceTools-aCCREMjS.mjs.map +1 -0
  56. package/dist/voiceTools.cjs +12 -0
  57. package/dist/voiceTools.d.mts +7 -0
  58. package/dist/voiceTools.d.mts.map +1 -0
  59. package/dist/voiceTools.mjs +3 -0
  60. package/dist/voiceWorker.cjs +1929 -0
  61. package/dist/voiceWorker.cjs.map +1 -0
  62. package/dist/voiceWorker.d.mts +200 -0
  63. package/dist/voiceWorker.d.mts.map +1 -0
  64. package/dist/voiceWorker.mjs +1925 -0
  65. package/dist/voiceWorker.mjs.map +1 -0
  66. package/dist/voiceWorkerProtocol-0H3czPjt.cjs +2385 -0
  67. package/dist/voiceWorkerProtocol-0H3czPjt.cjs.map +1 -0
  68. package/dist/voiceWorkerProtocol-B_4B2_fR.mjs +2085 -0
  69. package/dist/voiceWorkerProtocol-B_4B2_fR.mjs.map +1 -0
  70. package/dist/voiceWorkerSessionController-DaYemiL3.cjs +1800 -0
  71. package/dist/voiceWorkerSessionController-DaYemiL3.cjs.map +1 -0
  72. package/dist/voiceWorkerSessionController-GB3SJ6YE.mjs +1734 -0
  73. package/dist/voiceWorkerSessionController-GB3SJ6YE.mjs.map +1 -0
  74. package/licenses/Codex-Apache-2.0.txt +201 -0
  75. package/llms.txt +9 -0
  76. package/package.json +153 -0
  77. package/src/extensions/workspaces/sessions/(frontend)/lifecycle/_lib/models/README.md +11 -0
  78. package/src/extensions/workspaces/sessions/(frontend)/lifecycle/_lib/models/SILERO-LICENSE +21 -0
  79. package/src/prompts/po-use-voice/SKILL.md +35 -0
  80. package/src/types/clientCaptureActivity.ts +155 -0
  81. package/src/types/clientMedia.ts +226 -0
  82. package/src/types/manualTranscription.ts +53 -0
  83. package/src/types/realtime.ts +107 -0
  84. package/src/types/voiceOwnership.ts +315 -0
@@ -0,0 +1,134 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_clientMedia = require("./clientMedia-DuA4aYhD.cjs");
3
+ //#region src/types/clientCaptureActivity.ts
4
+ const DEFAULT_ENDPOINT_SILENCE_MS = 600;
5
+ const MINIMUM_SPEECH_SAMPLES = require_clientMedia.VOICE_MEDIA_SAMPLE_RATE * 120 / 1e3;
6
+ const SILENCE_DBFS = -120;
7
+ const PCM_VALUE_LIMIT = 32768;
8
+ const PCM_BYTES_PER_SAMPLE = 2;
9
+ const PCM_BYTES_PER_SECOND = require_clientMedia.VOICE_MEDIA_SAMPLE_RATE * 1 * PCM_BYTES_PER_SAMPLE;
10
+ function clamp(value, minimum, maximum) {
11
+ return Math.min(maximum, Math.max(minimum, value));
12
+ }
13
+ function round(value) {
14
+ return Math.round(value * 10) / 10;
15
+ }
16
+ /** Calculates the RMS level of complete little-endian PCM16 samples without environment-specific APIs. */
17
+ function calculateClientPcmDbfs(pcm) {
18
+ if (pcm.byteLength === 0 || pcm.byteLength % PCM_BYTES_PER_SAMPLE !== 0) throw new Error("PCM activity input must contain complete 16-bit samples.");
19
+ let squareSum = 0;
20
+ for (let offset = 0; offset < pcm.byteLength; offset += PCM_BYTES_PER_SAMPLE) {
21
+ const unsigned = pcm[offset] | pcm[offset + 1] << 8;
22
+ const sample = (unsigned >= 32768 ? unsigned - 65536 : unsigned) / PCM_VALUE_LIMIT;
23
+ squareSum += sample * sample;
24
+ }
25
+ const rms = Math.sqrt(squareSum / (pcm.byteLength / PCM_BYTES_PER_SAMPLE));
26
+ return rms === 0 ? SILENCE_DBFS : 20 * Math.log10(rms);
27
+ }
28
+ /** Portable lifecycle. Classifier windows are authoritative; RMS is level telemetry only. */
29
+ var ClientCaptureActivityLifecycle = class {
30
+ endpointSilenceMs;
31
+ elapsedBytes = 0;
32
+ activityEpoch = 0;
33
+ consecutiveSpeechSamples = 0;
34
+ consecutiveEchoSpeechSamples = 0;
35
+ classifiedSpeechSamples = 0;
36
+ echoDiscriminatedSpeechSamples = 0;
37
+ trailingSilenceSamples = 0;
38
+ speechStarted = false;
39
+ endpointReached = false;
40
+ previousEchoDiscriminated = false;
41
+ constructor(endpointSilenceMs = DEFAULT_ENDPOINT_SILENCE_MS) {
42
+ this.endpointSilenceMs = endpointSilenceMs;
43
+ if (!Number.isSafeInteger(endpointSilenceMs) || endpointSilenceMs < 250) throw new Error("Client endpoint silence must be an integer of at least 250 ms.");
44
+ }
45
+ push(pcm, windows = [], classification) {
46
+ const levelDbfs = calculateClientPcmDbfs(pcm);
47
+ this.elapsedBytes += pcm.byteLength;
48
+ const echoDiscriminated = classification?.echoReferenceActive === true && classification.echoDiscriminated && this.previousEchoDiscriminated;
49
+ for (const window of windows) {
50
+ if (!Number.isSafeInteger(window.sampleCount) || window.sampleCount <= 0) throw new Error("Speech-presence windows must contain a positive integer sample count.");
51
+ if (this.endpointReached) {
52
+ if (!window.speech) {
53
+ this.consecutiveSpeechSamples = 0;
54
+ this.consecutiveEchoSpeechSamples = 0;
55
+ continue;
56
+ }
57
+ this.consecutiveSpeechSamples += window.sampleCount;
58
+ if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;
59
+ if (this.consecutiveSpeechSamples < MINIMUM_SPEECH_SAMPLES) continue;
60
+ this.activityEpoch += 1;
61
+ this.classifiedSpeechSamples = this.consecutiveSpeechSamples;
62
+ this.echoDiscriminatedSpeechSamples = this.consecutiveEchoSpeechSamples;
63
+ this.consecutiveSpeechSamples = 0;
64
+ this.consecutiveEchoSpeechSamples = 0;
65
+ this.trailingSilenceSamples = 0;
66
+ this.speechStarted = true;
67
+ this.endpointReached = false;
68
+ continue;
69
+ }
70
+ if (window.speech) {
71
+ this.classifiedSpeechSamples += window.sampleCount;
72
+ if (echoDiscriminated) this.echoDiscriminatedSpeechSamples += window.sampleCount;
73
+ this.consecutiveSpeechSamples += window.sampleCount;
74
+ if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;
75
+ if (this.consecutiveSpeechSamples >= MINIMUM_SPEECH_SAMPLES) {
76
+ this.speechStarted = true;
77
+ this.consecutiveSpeechSamples = 0;
78
+ this.consecutiveEchoSpeechSamples = 0;
79
+ this.trailingSilenceSamples = 0;
80
+ }
81
+ } else {
82
+ if (this.speechStarted) this.trailingSilenceSamples += this.consecutiveSpeechSamples + window.sampleCount;
83
+ this.consecutiveSpeechSamples = 0;
84
+ this.consecutiveEchoSpeechSamples = 0;
85
+ }
86
+ const trailingSilenceMs = this.trailingSilenceSamples / require_clientMedia.VOICE_MEDIA_SAMPLE_RATE * 1e3;
87
+ if (this.speechStarted && trailingSilenceMs >= this.endpointSilenceMs) this.endpointReached = true;
88
+ }
89
+ this.previousEchoDiscriminated = classification?.echoReferenceActive === true && classification.echoDiscriminated;
90
+ return {
91
+ state: this.endpointReached ? "endpoint" : this.speechStarted ? "speech" : "listening",
92
+ levelDbfs: round(clamp(levelDbfs, SILENCE_DBFS, 0)),
93
+ elapsedMs: Math.round(this.elapsedBytes / PCM_BYTES_PER_SECOND * 1e3),
94
+ epoch: this.activityEpoch,
95
+ classifiedSpeechMs: Math.round(this.classifiedSpeechSamples / require_clientMedia.VOICE_MEDIA_SAMPLE_RATE * 1e3),
96
+ ...classification?.echoReferenceActive === true ? { echoDiscriminatedSpeechMs: Math.round(this.echoDiscriminatedSpeechSamples / require_clientMedia.VOICE_MEDIA_SAMPLE_RATE * 1e3) } : {}
97
+ };
98
+ }
99
+ /** Starts a fresh classifier phase while preserving monotonic capture time. */
100
+ resetActivity() {
101
+ this.activityEpoch += 1;
102
+ this.consecutiveSpeechSamples = 0;
103
+ this.consecutiveEchoSpeechSamples = 0;
104
+ this.classifiedSpeechSamples = 0;
105
+ this.echoDiscriminatedSpeechSamples = 0;
106
+ this.trailingSilenceSamples = 0;
107
+ this.speechStarted = false;
108
+ this.endpointReached = false;
109
+ this.previousEchoDiscriminated = false;
110
+ }
111
+ };
112
+ //#endregion
113
+ exports.ClientCaptureActivityLifecycle = ClientCaptureActivityLifecycle;
114
+ exports.VOICE_MEDIA_ACTIVITY_ECHO_SPEECH_MS_HEADER = require_clientMedia.VOICE_MEDIA_ACTIVITY_ECHO_SPEECH_MS_HEADER;
115
+ exports.VOICE_MEDIA_ACTIVITY_ELAPSED_HEADER = require_clientMedia.VOICE_MEDIA_ACTIVITY_ELAPSED_HEADER;
116
+ exports.VOICE_MEDIA_ACTIVITY_EPOCH_HEADER = require_clientMedia.VOICE_MEDIA_ACTIVITY_EPOCH_HEADER;
117
+ exports.VOICE_MEDIA_ACTIVITY_LEVEL_HEADER = require_clientMedia.VOICE_MEDIA_ACTIVITY_LEVEL_HEADER;
118
+ exports.VOICE_MEDIA_ACTIVITY_SPEECH_MS_HEADER = require_clientMedia.VOICE_MEDIA_ACTIVITY_SPEECH_MS_HEADER;
119
+ exports.VOICE_MEDIA_ACTIVITY_STATE_HEADER = require_clientMedia.VOICE_MEDIA_ACTIVITY_STATE_HEADER;
120
+ exports.VOICE_MEDIA_API_BASE_PATH = require_clientMedia.VOICE_MEDIA_API_BASE_PATH;
121
+ exports.VOICE_MEDIA_BITS_PER_SAMPLE = require_clientMedia.VOICE_MEDIA_BITS_PER_SAMPLE;
122
+ exports.VOICE_MEDIA_CHANNELS = require_clientMedia.VOICE_MEDIA_CHANNELS;
123
+ exports.VOICE_MEDIA_CONTENT_TYPE = require_clientMedia.VOICE_MEDIA_CONTENT_TYPE;
124
+ exports.VOICE_MEDIA_EVENT_WAIT_NONE = require_clientMedia.VOICE_MEDIA_EVENT_WAIT_NONE;
125
+ exports.VOICE_MEDIA_HEARTBEAT_MS = require_clientMedia.VOICE_MEDIA_HEARTBEAT_MS;
126
+ exports.VOICE_MEDIA_PLAYBACK_STATE_HEADER = require_clientMedia.VOICE_MEDIA_PLAYBACK_STATE_HEADER;
127
+ exports.VOICE_MEDIA_PROTOCOL_VERSION = require_clientMedia.VOICE_MEDIA_PROTOCOL_VERSION;
128
+ exports.VOICE_MEDIA_ROUTES = require_clientMedia.VOICE_MEDIA_ROUTES;
129
+ exports.VOICE_MEDIA_SAMPLE_RATE = require_clientMedia.VOICE_MEDIA_SAMPLE_RATE;
130
+ exports.VOICE_MEDIA_WAKE_TYPE = require_clientMedia.VOICE_MEDIA_WAKE_TYPE;
131
+ exports.calculateClientPcmDbfs = calculateClientPcmDbfs;
132
+ exports.voiceMediaClientUrl = require_clientMedia.voiceMediaClientUrl;
133
+
134
+ //# sourceMappingURL=clientMedia.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientMedia.cjs","names":["VOICE_MEDIA_SAMPLE_RATE"],"sources":["../src/types/clientCaptureActivity.ts"],"sourcesContent":["import {\n VOICE_MEDIA_BITS_PER_SAMPLE,\n VOICE_MEDIA_CHANNELS,\n VOICE_MEDIA_SAMPLE_RATE,\n type VoiceMediaCaptureActivity,\n} from './clientMedia';\n\nconst DEFAULT_ENDPOINT_SILENCE_MS = 600;\nconst MINIMUM_SPEECH_SAMPLES = (VOICE_MEDIA_SAMPLE_RATE * 120) / 1_000;\nconst SILENCE_DBFS = -120;\nconst PCM_VALUE_LIMIT = 32_768;\nconst PCM_BYTES_PER_SAMPLE = VOICE_MEDIA_BITS_PER_SAMPLE / 8;\nconst PCM_BYTES_PER_SECOND = VOICE_MEDIA_SAMPLE_RATE * VOICE_MEDIA_CHANNELS * PCM_BYTES_PER_SAMPLE;\n\nexport interface SpeechPresenceWindow {\n readonly speech: boolean;\n readonly sampleCount: number;\n}\n\n/** Platform boundary for browser workers and native speech-presence implementations. */\nexport interface SpeechPresenceDetector {\n push(pcm: Uint8Array): Promise<readonly SpeechPresenceWindow[]>;\n reset(): Promise<void>;\n close(): Promise<void>;\n}\n\nfunction clamp(value: number, minimum: number, maximum: number): number {\n return Math.min(maximum, Math.max(minimum, value));\n}\n\nfunction round(value: number): number {\n return Math.round(value * 10) / 10;\n}\n\n/** Calculates the RMS level of complete little-endian PCM16 samples without environment-specific APIs. */\nexport function calculateClientPcmDbfs(pcm: Uint8Array): number {\n if (pcm.byteLength === 0 || pcm.byteLength % PCM_BYTES_PER_SAMPLE !== 0)\n throw new Error('PCM activity input must contain complete 16-bit samples.');\n let squareSum = 0;\n for (let offset = 0; offset < pcm.byteLength; offset += PCM_BYTES_PER_SAMPLE) {\n const unsigned = pcm[offset]! | (pcm[offset + 1]! << 8);\n const sample = (unsigned >= 0x8000 ? unsigned - 0x1_0000 : unsigned) / PCM_VALUE_LIMIT;\n squareSum += sample * sample;\n }\n const rms = Math.sqrt(squareSum / (pcm.byteLength / PCM_BYTES_PER_SAMPLE));\n return rms === 0 ? SILENCE_DBFS : 20 * Math.log10(rms);\n}\n\nexport interface ClientCaptureSpeechClassification {\n readonly echoReferenceActive: boolean;\n readonly echoDiscriminated: boolean;\n}\n\n/** Portable lifecycle. Classifier windows are authoritative; RMS is level telemetry only. */\nexport class ClientCaptureActivityLifecycle {\n private elapsedBytes = 0;\n private activityEpoch = 0;\n private consecutiveSpeechSamples = 0;\n private consecutiveEchoSpeechSamples = 0;\n private classifiedSpeechSamples = 0;\n private echoDiscriminatedSpeechSamples = 0;\n private trailingSilenceSamples = 0;\n private speechStarted = false;\n private endpointReached = false;\n private previousEchoDiscriminated = false;\n\n public constructor(private readonly endpointSilenceMs = DEFAULT_ENDPOINT_SILENCE_MS) {\n if (!Number.isSafeInteger(endpointSilenceMs) || endpointSilenceMs < 250)\n throw new Error('Client endpoint silence must be an integer of at least 250 ms.');\n }\n\n public push(\n pcm: Uint8Array,\n windows: readonly SpeechPresenceWindow[] = [],\n classification?: ClientCaptureSpeechClassification,\n ): VoiceMediaCaptureActivity {\n const levelDbfs = calculateClientPcmDbfs(pcm);\n this.elapsedBytes += pcm.byteLength;\n const echoDiscriminated =\n classification?.echoReferenceActive === true &&\n classification.echoDiscriminated &&\n this.previousEchoDiscriminated;\n\n for (const window of windows) {\n if (!Number.isSafeInteger(window.sampleCount) || window.sampleCount <= 0)\n throw new Error('Speech-presence windows must contain a positive integer sample count.');\n if (this.endpointReached) {\n if (!window.speech) {\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n continue;\n }\n this.consecutiveSpeechSamples += window.sampleCount;\n if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;\n if (this.consecutiveSpeechSamples < MINIMUM_SPEECH_SAMPLES) continue;\n this.activityEpoch += 1;\n this.classifiedSpeechSamples = this.consecutiveSpeechSamples;\n this.echoDiscriminatedSpeechSamples = this.consecutiveEchoSpeechSamples;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n this.trailingSilenceSamples = 0;\n this.speechStarted = true;\n this.endpointReached = false;\n continue;\n }\n if (window.speech) {\n this.classifiedSpeechSamples += window.sampleCount;\n if (echoDiscriminated) this.echoDiscriminatedSpeechSamples += window.sampleCount;\n this.consecutiveSpeechSamples += window.sampleCount;\n if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;\n if (this.consecutiveSpeechSamples >= MINIMUM_SPEECH_SAMPLES) {\n this.speechStarted = true;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n this.trailingSilenceSamples = 0;\n }\n } else {\n if (this.speechStarted) this.trailingSilenceSamples += this.consecutiveSpeechSamples + window.sampleCount;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n }\n const trailingSilenceMs = (this.trailingSilenceSamples / VOICE_MEDIA_SAMPLE_RATE) * 1_000;\n if (this.speechStarted && trailingSilenceMs >= this.endpointSilenceMs) this.endpointReached = true;\n }\n this.previousEchoDiscriminated = classification?.echoReferenceActive === true && classification.echoDiscriminated;\n\n return {\n state: this.endpointReached ? 'endpoint' : this.speechStarted ? 'speech' : 'listening',\n levelDbfs: round(clamp(levelDbfs, SILENCE_DBFS, 0)),\n elapsedMs: Math.round((this.elapsedBytes / PCM_BYTES_PER_SECOND) * 1_000),\n epoch: this.activityEpoch,\n classifiedSpeechMs: Math.round((this.classifiedSpeechSamples / VOICE_MEDIA_SAMPLE_RATE) * 1_000),\n ...(classification?.echoReferenceActive === true\n ? {\n echoDiscriminatedSpeechMs: Math.round(\n (this.echoDiscriminatedSpeechSamples / VOICE_MEDIA_SAMPLE_RATE) * 1_000,\n ),\n }\n : {}),\n };\n }\n\n /** Starts a fresh classifier phase while preserving monotonic capture time. */\n public resetActivity(): void {\n this.activityEpoch += 1;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n this.classifiedSpeechSamples = 0;\n this.echoDiscriminatedSpeechSamples = 0;\n this.trailingSilenceSamples = 0;\n this.speechStarted = false;\n this.endpointReached = false;\n this.previousEchoDiscriminated = false;\n }\n}\n"],"mappings":";;;AAOA,MAAM,8BAA8B;AACpC,MAAM,yBAA0BA,oBAAAA,0BAA0B,MAAO;AACjE,MAAM,eAAe;AACrB,MAAM,kBAAkB;AACxB,MAAM,uBAAA;AACN,MAAM,uBAAuBA,oBAAAA,0BAAAA,IAAiD;AAc9E,SAAS,MAAM,OAAe,SAAiB,SAAyB;CACtE,OAAO,KAAK,IAAI,SAAS,KAAK,IAAI,SAAS,KAAK,CAAC;AACnD;AAEA,SAAS,MAAM,OAAuB;CACpC,OAAO,KAAK,MAAM,QAAQ,EAAE,IAAI;AAClC;;AAGA,SAAgB,uBAAuB,KAAyB;CAC9D,IAAI,IAAI,eAAe,KAAK,IAAI,aAAa,yBAAyB,GACpE,MAAM,IAAI,MAAM,0DAA0D;CAC5E,IAAI,YAAY;CAChB,KAAK,IAAI,SAAS,GAAG,SAAS,IAAI,YAAY,UAAU,sBAAsB;EAC5E,MAAM,WAAW,IAAI,UAAY,IAAI,SAAS,MAAO;EACrD,MAAM,UAAU,YAAY,QAAS,WAAW,QAAW,YAAY;EACvE,aAAa,SAAS;CACxB;CACA,MAAM,MAAM,KAAK,KAAK,aAAa,IAAI,aAAa,qBAAqB;CACzE,OAAO,QAAQ,IAAI,eAAe,KAAK,KAAK,MAAM,GAAG;AACvD;;AAQA,IAAa,iCAAb,MAA4C;CAYN;CAXpC,eAAuB;CACvB,gBAAwB;CACxB,2BAAmC;CACnC,+BAAuC;CACvC,0BAAkC;CAClC,iCAAyC;CACzC,yBAAiC;CACjC,gBAAwB;CACxB,kBAA0B;CAC1B,4BAAoC;CAEpC,YAAmB,oBAAqC,6BAA6B;EAAjD,KAAA,oBAAA;EAClC,IAAI,CAAC,OAAO,cAAc,iBAAiB,KAAK,oBAAoB,KAClE,MAAM,IAAI,MAAM,gEAAgE;CACpF;CAEA,KACE,KACA,UAA2C,CAAC,GAC5C,gBAC2B;EAC3B,MAAM,YAAY,uBAAuB,GAAG;EAC5C,KAAK,gBAAgB,IAAI;EACzB,MAAM,oBACJ,gBAAgB,wBAAwB,QACxC,eAAe,qBACf,KAAK;EAEP,KAAK,MAAM,UAAU,SAAS;GAC5B,IAAI,CAAC,OAAO,cAAc,OAAO,WAAW,KAAK,OAAO,eAAe,GACrE,MAAM,IAAI,MAAM,uEAAuE;GACzF,IAAI,KAAK,iBAAiB;IACxB,IAAI,CAAC,OAAO,QAAQ;KAClB,KAAK,2BAA2B;KAChC,KAAK,+BAA+B;KACpC;IACF;IACA,KAAK,4BAA4B,OAAO;IACxC,IAAI,mBAAmB,KAAK,gCAAgC,OAAO;IACnE,IAAI,KAAK,2BAA2B,wBAAwB;IAC5D,KAAK,iBAAiB;IACtB,KAAK,0BAA0B,KAAK;IACpC,KAAK,iCAAiC,KAAK;IAC3C,KAAK,2BAA2B;IAChC,KAAK,+BAA+B;IACpC,KAAK,yBAAyB;IAC9B,KAAK,gBAAgB;IACrB,KAAK,kBAAkB;IACvB;GACF;GACA,IAAI,OAAO,QAAQ;IACjB,KAAK,2BAA2B,OAAO;IACvC,IAAI,mBAAmB,KAAK,kCAAkC,OAAO;IACrE,KAAK,4BAA4B,OAAO;IACxC,IAAI,mBAAmB,KAAK,gCAAgC,OAAO;IACnE,IAAI,KAAK,4BAA4B,wBAAwB;KAC3D,KAAK,gBAAgB;KACrB,KAAK,2BAA2B;KAChC,KAAK,+BAA+B;KACpC,KAAK,yBAAyB;IAChC;GACF,OAAO;IACL,IAAI,KAAK,eAAe,KAAK,0BAA0B,KAAK,2BAA2B,OAAO;IAC9F,KAAK,2BAA2B;IAChC,KAAK,+BAA+B;GACtC;GACA,MAAM,oBAAqB,KAAK,yBAAyBA,oBAAAA,0BAA2B;GACpF,IAAI,KAAK,iBAAiB,qBAAqB,KAAK,mBAAmB,KAAK,kBAAkB;EAChG;EACA,KAAK,4BAA4B,gBAAgB,wBAAwB,QAAQ,eAAe;EAEhG,OAAO;GACL,OAAO,KAAK,kBAAkB,aAAa,KAAK,gBAAgB,WAAW;GAC3E,WAAW,MAAM,MAAM,WAAW,cAAc,CAAC,CAAC;GAClD,WAAW,KAAK,MAAO,KAAK,eAAe,uBAAwB,GAAK;GACxE,OAAO,KAAK;GACZ,oBAAoB,KAAK,MAAO,KAAK,0BAA0BA,oBAAAA,0BAA2B,GAAK;GAC/F,GAAI,gBAAgB,wBAAwB,OACxC,EACE,2BAA2B,KAAK,MAC7B,KAAK,iCAAiCA,oBAAAA,0BAA2B,GACpE,EACF,IACA,CAAC;EACP;CACF;;CAGA,gBAA6B;EAC3B,KAAK,iBAAiB;EACtB,KAAK,2BAA2B;EAChC,KAAK,+BAA+B;EACpC,KAAK,0BAA0B;EAC/B,KAAK,iCAAiC;EACtC,KAAK,yBAAyB;EAC9B,KAAK,gBAAgB;EACrB,KAAK,kBAAkB;EACvB,KAAK,4BAA4B;CACnC;AACF"}
@@ -0,0 +1,2 @@
1
+ import { A as VoiceMediaCaptureSpeechAnalysis, B as VoiceMediaPlaybackResult, C as VoiceClientKind, D as VoiceMediaCaptureActivityState, E as VoiceMediaCaptureActivity, F as VoiceMediaDevice, H as VoiceMediaWake, I as VoiceMediaHeartbeatResult, L as VoiceMediaPlayback, M as VoiceMediaConnectRequest, N as VoiceMediaConnectResult, O as VoiceMediaCaptureConfiguration, P as VoiceMediaControlLocation, R as VoiceMediaPlaybackDelivery, S as VOICE_MEDIA_WAKE_TYPE, T as VoiceMediaCapture, U as voiceMediaClientUrl, V as VoiceMediaTransport, _ as VOICE_MEDIA_HEARTBEAT_MS, a as calculateClientPcmDbfs, b as VOICE_MEDIA_ROUTES, c as VOICE_MEDIA_ACTIVITY_EPOCH_HEADER, d as VOICE_MEDIA_ACTIVITY_STATE_HEADER, f as VOICE_MEDIA_API_BASE_PATH, g as VOICE_MEDIA_EVENT_WAIT_NONE, h as VOICE_MEDIA_CONTENT_TYPE, i as SpeechPresenceWindow, j as VoiceMediaClientEvent, k as VoiceMediaCaptureMode, l as VOICE_MEDIA_ACTIVITY_LEVEL_HEADER, m as VOICE_MEDIA_CHANNELS, n as ClientCaptureSpeechClassification, o as VOICE_MEDIA_ACTIVITY_ECHO_SPEECH_MS_HEADER, p as VOICE_MEDIA_BITS_PER_SAMPLE, r as SpeechPresenceDetector, s as VOICE_MEDIA_ACTIVITY_ELAPSED_HEADER, t as ClientCaptureActivityLifecycle, u as VOICE_MEDIA_ACTIVITY_SPEECH_MS_HEADER, v as VOICE_MEDIA_PLAYBACK_STATE_HEADER, w as VoiceMediaCapabilities, x as VOICE_MEDIA_SAMPLE_RATE, y as VOICE_MEDIA_PROTOCOL_VERSION, z as VoiceMediaPlaybackOutcome } from "./clientCaptureActivity-DN4xQtmw.mjs";
2
+ export { ClientCaptureActivityLifecycle, type ClientCaptureSpeechClassification, type SpeechPresenceDetector, type SpeechPresenceWindow, VOICE_MEDIA_ACTIVITY_ECHO_SPEECH_MS_HEADER, VOICE_MEDIA_ACTIVITY_ELAPSED_HEADER, VOICE_MEDIA_ACTIVITY_EPOCH_HEADER, VOICE_MEDIA_ACTIVITY_LEVEL_HEADER, VOICE_MEDIA_ACTIVITY_SPEECH_MS_HEADER, VOICE_MEDIA_ACTIVITY_STATE_HEADER, VOICE_MEDIA_API_BASE_PATH, VOICE_MEDIA_BITS_PER_SAMPLE, VOICE_MEDIA_CHANNELS, VOICE_MEDIA_CONTENT_TYPE, VOICE_MEDIA_EVENT_WAIT_NONE, VOICE_MEDIA_HEARTBEAT_MS, VOICE_MEDIA_PLAYBACK_STATE_HEADER, VOICE_MEDIA_PROTOCOL_VERSION, VOICE_MEDIA_ROUTES, VOICE_MEDIA_SAMPLE_RATE, VOICE_MEDIA_WAKE_TYPE, type VoiceClientKind, type VoiceMediaCapabilities, type VoiceMediaCapture, type VoiceMediaCaptureActivity, type VoiceMediaCaptureActivityState, type VoiceMediaCaptureConfiguration, type VoiceMediaCaptureMode, type VoiceMediaCaptureSpeechAnalysis, type VoiceMediaClientEvent, type VoiceMediaConnectRequest, type VoiceMediaConnectResult, type VoiceMediaControlLocation, type VoiceMediaDevice, type VoiceMediaHeartbeatResult, type VoiceMediaPlayback, type VoiceMediaPlaybackDelivery, type VoiceMediaPlaybackOutcome, type VoiceMediaPlaybackResult, type VoiceMediaTransport, type VoiceMediaWake, calculateClientPcmDbfs, voiceMediaClientUrl };
@@ -0,0 +1,114 @@
1
+ import { _ as VOICE_MEDIA_WAKE_TYPE, a as VOICE_MEDIA_ACTIVITY_SPEECH_MS_HEADER, c as VOICE_MEDIA_BITS_PER_SAMPLE, d as VOICE_MEDIA_EVENT_WAIT_NONE, f as VOICE_MEDIA_HEARTBEAT_MS, g as VOICE_MEDIA_SAMPLE_RATE, h as VOICE_MEDIA_ROUTES, i as VOICE_MEDIA_ACTIVITY_LEVEL_HEADER, l as VOICE_MEDIA_CHANNELS, m as VOICE_MEDIA_PROTOCOL_VERSION, n as VOICE_MEDIA_ACTIVITY_ELAPSED_HEADER, o as VOICE_MEDIA_ACTIVITY_STATE_HEADER, p as VOICE_MEDIA_PLAYBACK_STATE_HEADER, r as VOICE_MEDIA_ACTIVITY_EPOCH_HEADER, s as VOICE_MEDIA_API_BASE_PATH, t as VOICE_MEDIA_ACTIVITY_ECHO_SPEECH_MS_HEADER, u as VOICE_MEDIA_CONTENT_TYPE, v as voiceMediaClientUrl } from "./clientMedia-CfTfc9_4.mjs";
2
+ //#region src/types/clientCaptureActivity.ts
3
+ const DEFAULT_ENDPOINT_SILENCE_MS = 600;
4
+ const MINIMUM_SPEECH_SAMPLES = VOICE_MEDIA_SAMPLE_RATE * 120 / 1e3;
5
+ const SILENCE_DBFS = -120;
6
+ const PCM_VALUE_LIMIT = 32768;
7
+ const PCM_BYTES_PER_SAMPLE = 2;
8
+ const PCM_BYTES_PER_SECOND = VOICE_MEDIA_SAMPLE_RATE * 1 * PCM_BYTES_PER_SAMPLE;
9
+ function clamp(value, minimum, maximum) {
10
+ return Math.min(maximum, Math.max(minimum, value));
11
+ }
12
+ function round(value) {
13
+ return Math.round(value * 10) / 10;
14
+ }
15
+ /** Calculates the RMS level of complete little-endian PCM16 samples without environment-specific APIs. */
16
+ function calculateClientPcmDbfs(pcm) {
17
+ if (pcm.byteLength === 0 || pcm.byteLength % PCM_BYTES_PER_SAMPLE !== 0) throw new Error("PCM activity input must contain complete 16-bit samples.");
18
+ let squareSum = 0;
19
+ for (let offset = 0; offset < pcm.byteLength; offset += PCM_BYTES_PER_SAMPLE) {
20
+ const unsigned = pcm[offset] | pcm[offset + 1] << 8;
21
+ const sample = (unsigned >= 32768 ? unsigned - 65536 : unsigned) / PCM_VALUE_LIMIT;
22
+ squareSum += sample * sample;
23
+ }
24
+ const rms = Math.sqrt(squareSum / (pcm.byteLength / PCM_BYTES_PER_SAMPLE));
25
+ return rms === 0 ? SILENCE_DBFS : 20 * Math.log10(rms);
26
+ }
27
+ /** Portable lifecycle. Classifier windows are authoritative; RMS is level telemetry only. */
28
+ var ClientCaptureActivityLifecycle = class {
29
+ endpointSilenceMs;
30
+ elapsedBytes = 0;
31
+ activityEpoch = 0;
32
+ consecutiveSpeechSamples = 0;
33
+ consecutiveEchoSpeechSamples = 0;
34
+ classifiedSpeechSamples = 0;
35
+ echoDiscriminatedSpeechSamples = 0;
36
+ trailingSilenceSamples = 0;
37
+ speechStarted = false;
38
+ endpointReached = false;
39
+ previousEchoDiscriminated = false;
40
+ constructor(endpointSilenceMs = DEFAULT_ENDPOINT_SILENCE_MS) {
41
+ this.endpointSilenceMs = endpointSilenceMs;
42
+ if (!Number.isSafeInteger(endpointSilenceMs) || endpointSilenceMs < 250) throw new Error("Client endpoint silence must be an integer of at least 250 ms.");
43
+ }
44
+ push(pcm, windows = [], classification) {
45
+ const levelDbfs = calculateClientPcmDbfs(pcm);
46
+ this.elapsedBytes += pcm.byteLength;
47
+ const echoDiscriminated = classification?.echoReferenceActive === true && classification.echoDiscriminated && this.previousEchoDiscriminated;
48
+ for (const window of windows) {
49
+ if (!Number.isSafeInteger(window.sampleCount) || window.sampleCount <= 0) throw new Error("Speech-presence windows must contain a positive integer sample count.");
50
+ if (this.endpointReached) {
51
+ if (!window.speech) {
52
+ this.consecutiveSpeechSamples = 0;
53
+ this.consecutiveEchoSpeechSamples = 0;
54
+ continue;
55
+ }
56
+ this.consecutiveSpeechSamples += window.sampleCount;
57
+ if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;
58
+ if (this.consecutiveSpeechSamples < MINIMUM_SPEECH_SAMPLES) continue;
59
+ this.activityEpoch += 1;
60
+ this.classifiedSpeechSamples = this.consecutiveSpeechSamples;
61
+ this.echoDiscriminatedSpeechSamples = this.consecutiveEchoSpeechSamples;
62
+ this.consecutiveSpeechSamples = 0;
63
+ this.consecutiveEchoSpeechSamples = 0;
64
+ this.trailingSilenceSamples = 0;
65
+ this.speechStarted = true;
66
+ this.endpointReached = false;
67
+ continue;
68
+ }
69
+ if (window.speech) {
70
+ this.classifiedSpeechSamples += window.sampleCount;
71
+ if (echoDiscriminated) this.echoDiscriminatedSpeechSamples += window.sampleCount;
72
+ this.consecutiveSpeechSamples += window.sampleCount;
73
+ if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;
74
+ if (this.consecutiveSpeechSamples >= MINIMUM_SPEECH_SAMPLES) {
75
+ this.speechStarted = true;
76
+ this.consecutiveSpeechSamples = 0;
77
+ this.consecutiveEchoSpeechSamples = 0;
78
+ this.trailingSilenceSamples = 0;
79
+ }
80
+ } else {
81
+ if (this.speechStarted) this.trailingSilenceSamples += this.consecutiveSpeechSamples + window.sampleCount;
82
+ this.consecutiveSpeechSamples = 0;
83
+ this.consecutiveEchoSpeechSamples = 0;
84
+ }
85
+ const trailingSilenceMs = this.trailingSilenceSamples / VOICE_MEDIA_SAMPLE_RATE * 1e3;
86
+ if (this.speechStarted && trailingSilenceMs >= this.endpointSilenceMs) this.endpointReached = true;
87
+ }
88
+ this.previousEchoDiscriminated = classification?.echoReferenceActive === true && classification.echoDiscriminated;
89
+ return {
90
+ state: this.endpointReached ? "endpoint" : this.speechStarted ? "speech" : "listening",
91
+ levelDbfs: round(clamp(levelDbfs, SILENCE_DBFS, 0)),
92
+ elapsedMs: Math.round(this.elapsedBytes / PCM_BYTES_PER_SECOND * 1e3),
93
+ epoch: this.activityEpoch,
94
+ classifiedSpeechMs: Math.round(this.classifiedSpeechSamples / VOICE_MEDIA_SAMPLE_RATE * 1e3),
95
+ ...classification?.echoReferenceActive === true ? { echoDiscriminatedSpeechMs: Math.round(this.echoDiscriminatedSpeechSamples / VOICE_MEDIA_SAMPLE_RATE * 1e3) } : {}
96
+ };
97
+ }
98
+ /** Starts a fresh classifier phase while preserving monotonic capture time. */
99
+ resetActivity() {
100
+ this.activityEpoch += 1;
101
+ this.consecutiveSpeechSamples = 0;
102
+ this.consecutiveEchoSpeechSamples = 0;
103
+ this.classifiedSpeechSamples = 0;
104
+ this.echoDiscriminatedSpeechSamples = 0;
105
+ this.trailingSilenceSamples = 0;
106
+ this.speechStarted = false;
107
+ this.endpointReached = false;
108
+ this.previousEchoDiscriminated = false;
109
+ }
110
+ };
111
+ //#endregion
112
+ export { ClientCaptureActivityLifecycle, VOICE_MEDIA_ACTIVITY_ECHO_SPEECH_MS_HEADER, VOICE_MEDIA_ACTIVITY_ELAPSED_HEADER, VOICE_MEDIA_ACTIVITY_EPOCH_HEADER, VOICE_MEDIA_ACTIVITY_LEVEL_HEADER, VOICE_MEDIA_ACTIVITY_SPEECH_MS_HEADER, VOICE_MEDIA_ACTIVITY_STATE_HEADER, VOICE_MEDIA_API_BASE_PATH, VOICE_MEDIA_BITS_PER_SAMPLE, VOICE_MEDIA_CHANNELS, VOICE_MEDIA_CONTENT_TYPE, VOICE_MEDIA_EVENT_WAIT_NONE, VOICE_MEDIA_HEARTBEAT_MS, VOICE_MEDIA_PLAYBACK_STATE_HEADER, VOICE_MEDIA_PROTOCOL_VERSION, VOICE_MEDIA_ROUTES, VOICE_MEDIA_SAMPLE_RATE, VOICE_MEDIA_WAKE_TYPE, calculateClientPcmDbfs, voiceMediaClientUrl };
113
+
114
+ //# sourceMappingURL=clientMedia.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientMedia.mjs","names":[],"sources":["../src/types/clientCaptureActivity.ts"],"sourcesContent":["import {\n VOICE_MEDIA_BITS_PER_SAMPLE,\n VOICE_MEDIA_CHANNELS,\n VOICE_MEDIA_SAMPLE_RATE,\n type VoiceMediaCaptureActivity,\n} from './clientMedia';\n\nconst DEFAULT_ENDPOINT_SILENCE_MS = 600;\nconst MINIMUM_SPEECH_SAMPLES = (VOICE_MEDIA_SAMPLE_RATE * 120) / 1_000;\nconst SILENCE_DBFS = -120;\nconst PCM_VALUE_LIMIT = 32_768;\nconst PCM_BYTES_PER_SAMPLE = VOICE_MEDIA_BITS_PER_SAMPLE / 8;\nconst PCM_BYTES_PER_SECOND = VOICE_MEDIA_SAMPLE_RATE * VOICE_MEDIA_CHANNELS * PCM_BYTES_PER_SAMPLE;\n\nexport interface SpeechPresenceWindow {\n readonly speech: boolean;\n readonly sampleCount: number;\n}\n\n/** Platform boundary for browser workers and native speech-presence implementations. */\nexport interface SpeechPresenceDetector {\n push(pcm: Uint8Array): Promise<readonly SpeechPresenceWindow[]>;\n reset(): Promise<void>;\n close(): Promise<void>;\n}\n\nfunction clamp(value: number, minimum: number, maximum: number): number {\n return Math.min(maximum, Math.max(minimum, value));\n}\n\nfunction round(value: number): number {\n return Math.round(value * 10) / 10;\n}\n\n/** Calculates the RMS level of complete little-endian PCM16 samples without environment-specific APIs. */\nexport function calculateClientPcmDbfs(pcm: Uint8Array): number {\n if (pcm.byteLength === 0 || pcm.byteLength % PCM_BYTES_PER_SAMPLE !== 0)\n throw new Error('PCM activity input must contain complete 16-bit samples.');\n let squareSum = 0;\n for (let offset = 0; offset < pcm.byteLength; offset += PCM_BYTES_PER_SAMPLE) {\n const unsigned = pcm[offset]! | (pcm[offset + 1]! << 8);\n const sample = (unsigned >= 0x8000 ? unsigned - 0x1_0000 : unsigned) / PCM_VALUE_LIMIT;\n squareSum += sample * sample;\n }\n const rms = Math.sqrt(squareSum / (pcm.byteLength / PCM_BYTES_PER_SAMPLE));\n return rms === 0 ? SILENCE_DBFS : 20 * Math.log10(rms);\n}\n\nexport interface ClientCaptureSpeechClassification {\n readonly echoReferenceActive: boolean;\n readonly echoDiscriminated: boolean;\n}\n\n/** Portable lifecycle. Classifier windows are authoritative; RMS is level telemetry only. */\nexport class ClientCaptureActivityLifecycle {\n private elapsedBytes = 0;\n private activityEpoch = 0;\n private consecutiveSpeechSamples = 0;\n private consecutiveEchoSpeechSamples = 0;\n private classifiedSpeechSamples = 0;\n private echoDiscriminatedSpeechSamples = 0;\n private trailingSilenceSamples = 0;\n private speechStarted = false;\n private endpointReached = false;\n private previousEchoDiscriminated = false;\n\n public constructor(private readonly endpointSilenceMs = DEFAULT_ENDPOINT_SILENCE_MS) {\n if (!Number.isSafeInteger(endpointSilenceMs) || endpointSilenceMs < 250)\n throw new Error('Client endpoint silence must be an integer of at least 250 ms.');\n }\n\n public push(\n pcm: Uint8Array,\n windows: readonly SpeechPresenceWindow[] = [],\n classification?: ClientCaptureSpeechClassification,\n ): VoiceMediaCaptureActivity {\n const levelDbfs = calculateClientPcmDbfs(pcm);\n this.elapsedBytes += pcm.byteLength;\n const echoDiscriminated =\n classification?.echoReferenceActive === true &&\n classification.echoDiscriminated &&\n this.previousEchoDiscriminated;\n\n for (const window of windows) {\n if (!Number.isSafeInteger(window.sampleCount) || window.sampleCount <= 0)\n throw new Error('Speech-presence windows must contain a positive integer sample count.');\n if (this.endpointReached) {\n if (!window.speech) {\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n continue;\n }\n this.consecutiveSpeechSamples += window.sampleCount;\n if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;\n if (this.consecutiveSpeechSamples < MINIMUM_SPEECH_SAMPLES) continue;\n this.activityEpoch += 1;\n this.classifiedSpeechSamples = this.consecutiveSpeechSamples;\n this.echoDiscriminatedSpeechSamples = this.consecutiveEchoSpeechSamples;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n this.trailingSilenceSamples = 0;\n this.speechStarted = true;\n this.endpointReached = false;\n continue;\n }\n if (window.speech) {\n this.classifiedSpeechSamples += window.sampleCount;\n if (echoDiscriminated) this.echoDiscriminatedSpeechSamples += window.sampleCount;\n this.consecutiveSpeechSamples += window.sampleCount;\n if (echoDiscriminated) this.consecutiveEchoSpeechSamples += window.sampleCount;\n if (this.consecutiveSpeechSamples >= MINIMUM_SPEECH_SAMPLES) {\n this.speechStarted = true;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n this.trailingSilenceSamples = 0;\n }\n } else {\n if (this.speechStarted) this.trailingSilenceSamples += this.consecutiveSpeechSamples + window.sampleCount;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n }\n const trailingSilenceMs = (this.trailingSilenceSamples / VOICE_MEDIA_SAMPLE_RATE) * 1_000;\n if (this.speechStarted && trailingSilenceMs >= this.endpointSilenceMs) this.endpointReached = true;\n }\n this.previousEchoDiscriminated = classification?.echoReferenceActive === true && classification.echoDiscriminated;\n\n return {\n state: this.endpointReached ? 'endpoint' : this.speechStarted ? 'speech' : 'listening',\n levelDbfs: round(clamp(levelDbfs, SILENCE_DBFS, 0)),\n elapsedMs: Math.round((this.elapsedBytes / PCM_BYTES_PER_SECOND) * 1_000),\n epoch: this.activityEpoch,\n classifiedSpeechMs: Math.round((this.classifiedSpeechSamples / VOICE_MEDIA_SAMPLE_RATE) * 1_000),\n ...(classification?.echoReferenceActive === true\n ? {\n echoDiscriminatedSpeechMs: Math.round(\n (this.echoDiscriminatedSpeechSamples / VOICE_MEDIA_SAMPLE_RATE) * 1_000,\n ),\n }\n : {}),\n };\n }\n\n /** Starts a fresh classifier phase while preserving monotonic capture time. */\n public resetActivity(): void {\n this.activityEpoch += 1;\n this.consecutiveSpeechSamples = 0;\n this.consecutiveEchoSpeechSamples = 0;\n this.classifiedSpeechSamples = 0;\n this.echoDiscriminatedSpeechSamples = 0;\n this.trailingSilenceSamples = 0;\n this.speechStarted = false;\n this.endpointReached = false;\n this.previousEchoDiscriminated = false;\n }\n}\n"],"mappings":"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"}