@elevenlabs/client 0.6.2 → 0.7.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.
@@ -1,6 +1,8 @@
1
1
  import type { IncomingSocketEvent, OutgoingSocketEvent } from "./events";
2
2
  import type { Mode } from "../BaseConversation";
3
- export type Language = "en" | "ja" | "zh" | "de" | "hi" | "fr" | "ko" | "pt" | "pt-br" | "it" | "es" | "id" | "nl" | "tr" | "pl" | "sv" | "bg" | "ro" | "ar" | "cs" | "el" | "fi" | "ms" | "da" | "ta" | "uk" | "ru" | "hu" | "hr" | "sk" | "no" | "vi" | "tl";
3
+ import type { ConversationConfigOverrideAgentLanguage as Language } from "@elevenlabs/types/generated/types/asyncapi-types";
4
+ import type { DisconnectionDetails } from "@elevenlabs/types";
5
+ export type { DisconnectionDetails, ConversationConfigOverrideAgentLanguage as Language, } from "@elevenlabs/types";
4
6
  export type DelayConfig = {
5
7
  default: number;
6
8
  android?: number;
@@ -11,16 +13,6 @@ export type FormatConfig = {
11
13
  sampleRate: number;
12
14
  outputDeviceId?: string;
13
15
  };
14
- export type DisconnectionDetails = {
15
- reason: "error";
16
- message: string;
17
- context: Event;
18
- } | {
19
- reason: "agent";
20
- context: CloseEvent;
21
- } | {
22
- reason: "user";
23
- };
24
16
  export type OnDisconnectCallback = (details: DisconnectionDetails) => void;
25
17
  export type OnMessageCallback = (event: IncomingSocketEvent) => void;
26
18
  export type BaseSessionConfig = {
@@ -1 +1 @@
1
- export declare const loadAudioConcatProcessor: (worklet: AudioWorklet) => Promise<void>;
1
+ export declare const loadAudioConcatProcessor: (worklet: AudioWorklet, path?: string) => Promise<void>;
@@ -1 +1 @@
1
- export declare function createWorkletModuleLoader(name: string, sourceCode: string): (worklet: AudioWorklet) => Promise<void>;
1
+ export declare function createWorkletModuleLoader(name: string, sourceCode: string): (worklet: AudioWorklet, path?: string) => Promise<void>;
@@ -1,161 +1,29 @@
1
- import type { Language } from "./connection";
2
- import type { CONVERSATION_INITIATION_CLIENT_DATA_TYPE } from "./overrides";
3
- export type UserTranscriptionEvent = {
4
- type: "user_transcript";
5
- user_transcription_event: {
6
- user_transcript: string;
7
- };
8
- };
9
- export type AgentResponseEvent = {
10
- type: "agent_response";
11
- agent_response_event: {
12
- agent_response: string;
13
- };
14
- };
15
- export type AgentAudioEvent = {
16
- type: "audio";
17
- audio_event: {
18
- audio_base_64: string;
19
- event_id: number;
20
- };
21
- };
22
- export type InterruptionEvent = {
23
- type: "interruption";
24
- interruption_event: {
25
- event_id: number;
26
- };
27
- };
28
- export type InternalTentativeAgentResponseEvent = {
29
- type: "internal_tentative_agent_response";
30
- tentative_agent_response_internal_event: {
31
- tentative_agent_response: string;
32
- };
33
- };
34
- export type ConfigEvent = {
35
- type: "conversation_initiation_metadata";
36
- conversation_initiation_metadata_event: {
37
- conversation_id: string;
38
- agent_output_audio_format: string;
39
- user_input_audio_format?: string;
40
- };
41
- };
42
- export type PingEvent = {
43
- type: "ping";
44
- ping_event: {
45
- event_id: number;
46
- ping_ms?: number;
47
- };
48
- };
49
- export type ClientToolCallEvent = {
50
- type: "client_tool_call";
51
- client_tool_call: {
52
- tool_name: string;
53
- tool_call_id: string;
54
- parameters: any;
55
- expects_response: boolean;
56
- };
57
- };
58
- export type VadScoreEvent = {
59
- type: "vad_score";
60
- vad_score_event: {
61
- vad_score: number;
62
- };
63
- };
64
- interface BaseMCPToolCallClientEventData {
65
- service_id: string;
66
- tool_call_id: string;
67
- tool_name: string;
68
- tool_description?: string;
69
- parameters: Record<string, any>;
70
- timestamp: string;
71
- }
72
- interface MCPToolCallClientEventLoadingData extends BaseMCPToolCallClientEventData {
73
- state: "loading";
74
- }
75
- interface MCPToolCallClientEventAwaitingApprovalData extends BaseMCPToolCallClientEventData {
76
- state: "awaiting_approval";
77
- approval_timeout_secs: number;
78
- }
79
- interface MCPToolCallClientEventSuccessData extends BaseMCPToolCallClientEventData {
80
- state: "success";
81
- result: any[];
82
- }
83
- interface MCPToolCallClientEventFailureData extends BaseMCPToolCallClientEventData {
84
- state: "failure";
85
- error_message: string;
86
- }
87
- type MCPToolCallClientEventData = MCPToolCallClientEventLoadingData | MCPToolCallClientEventAwaitingApprovalData | MCPToolCallClientEventSuccessData | MCPToolCallClientEventFailureData;
88
- export type MCPToolCallClientEvent = {
89
- type: "mcp_tool_call";
90
- mcp_tool_call: MCPToolCallClientEventData;
91
- };
92
- export type AgentResponseCorrectionEvent = {
93
- type: "agent_response_correction";
94
- agent_response_correction_event: {
95
- original_agent_response: string;
96
- corrected_agent_response: string;
97
- };
98
- };
99
- export type IncomingSocketEvent = UserTranscriptionEvent | AgentResponseEvent | AgentResponseCorrectionEvent | AgentAudioEvent | InterruptionEvent | InternalTentativeAgentResponseEvent | ConfigEvent | PingEvent | ClientToolCallEvent | VadScoreEvent | MCPToolCallClientEvent;
100
- export type PongEvent = {
101
- type: "pong";
102
- event_id: number;
103
- };
104
- export type UserAudioEvent = {
105
- user_audio_chunk: string;
106
- };
107
- export type UserFeedbackEvent = {
108
- type: "feedback";
109
- score: "like" | "dislike";
110
- event_id: number;
111
- };
112
- export type ClientToolResultEvent = {
113
- type: "client_tool_result";
114
- tool_call_id: string;
115
- result: any;
116
- is_error: boolean;
117
- };
118
- export type InitiationClientDataEvent = {
119
- type: typeof CONVERSATION_INITIATION_CLIENT_DATA_TYPE;
120
- conversation_config_override?: {
121
- agent?: {
122
- prompt?: {
123
- prompt?: string;
124
- };
125
- first_message?: string;
126
- language?: Language;
127
- };
128
- tts?: {
129
- voice_id?: string;
130
- };
131
- conversation?: {
132
- text_only?: boolean;
133
- };
134
- };
135
- custom_llm_extra_body?: any;
136
- dynamic_variables?: Record<string, string | number | boolean>;
137
- user_id?: string;
138
- source_info?: {
139
- source?: string;
140
- version?: string;
141
- };
142
- };
143
- export type ContextualUpdateEvent = {
144
- type: "contextual_update";
145
- text: string;
146
- };
147
- export type UserMessageEvent = {
148
- type: "user_message";
149
- text: string;
150
- };
151
- export type UserActivityEvent = {
152
- type: "user_activity";
153
- };
154
- export type MCPToolApprovalResultEvent = {
155
- type: "mcp_tool_approval_result";
156
- tool_call_id: string;
157
- is_approved: boolean;
158
- };
1
+ import { Outgoing } from "@elevenlabs/types";
2
+ import { AgentResponse, AgentResponseCorrection, AgentToolResponseClientEvent, AsrInitiationMetadataEvent as AsrMetadataEvent, Audio, ClientToolCallMessage, ConversationMetadata, Interruption, McpConnectionStatusClientEvent, McpToolCall, Ping, InternalTentativeAgentResponse as TentativeAgentResponseInternal, UserTranscript, VadScore } from "@elevenlabs/types/generated/types/asyncapi-types";
3
+ export type UserTranscriptionEvent = UserTranscript;
4
+ export type AgentResponseEvent = AgentResponse;
5
+ export type AgentAudioEvent = Audio;
6
+ export type InterruptionEvent = Interruption;
7
+ export type InternalTentativeAgentResponseEvent = TentativeAgentResponseInternal;
8
+ export type ConfigEvent = ConversationMetadata;
9
+ export type PingEvent = Ping;
10
+ export type ClientToolCallEvent = ClientToolCallMessage;
11
+ export type VadScoreEvent = VadScore;
12
+ export type MCPToolCallClientEvent = McpToolCall;
13
+ export type AgentResponseCorrectionEvent = AgentResponseCorrection;
14
+ export type AgentToolResponseEvent = AgentToolResponseClientEvent;
15
+ export type ConversationMetadataEvent = ConversationMetadata;
16
+ export type AsrInitiationMetadataEvent = AsrMetadataEvent;
17
+ export type MCPConnectionStatusEvent = McpConnectionStatusClientEvent;
18
+ export type IncomingSocketEvent = UserTranscriptionEvent | AgentResponseEvent | AgentResponseCorrectionEvent | AgentAudioEvent | InterruptionEvent | InternalTentativeAgentResponseEvent | ConfigEvent | PingEvent | ClientToolCallEvent | VadScoreEvent | MCPToolCallClientEvent | AgentToolResponseEvent | ConversationMetadataEvent | AsrInitiationMetadataEvent | MCPConnectionStatusEvent;
19
+ export type PongEvent = Outgoing.PongClientToOrchestratorEvent;
20
+ export type UserAudioEvent = Outgoing.UserAudio;
21
+ export type UserFeedbackEvent = Outgoing.UserFeedbackClientToOrchestratorEvent;
22
+ export type ClientToolResultEvent = Outgoing.ClientToolResultClientToOrchestratorEvent;
23
+ export type InitiationClientDataEvent = Outgoing.ConversationInitiationClientToOrchestratorEvent;
24
+ export type ContextualUpdateEvent = Outgoing.ContextualUpdateClientToOrchestratorEvent;
25
+ export type UserMessageEvent = Outgoing.UserMessageClientToOrchestratorEvent;
26
+ export type UserActivityEvent = Outgoing.UserActivityClientToOrchestratorEvent;
27
+ export type MCPToolApprovalResultEvent = Outgoing.McpToolApprovalResultClientToOrchestratorEvent;
159
28
  export type OutgoingSocketEvent = PongEvent | UserAudioEvent | InitiationClientDataEvent | UserFeedbackEvent | ClientToolResultEvent | ContextualUpdateEvent | UserMessageEvent | UserActivityEvent | MCPToolApprovalResultEvent;
160
29
  export declare function isValidSocketEvent(event: any): event is IncomingSocketEvent;
161
- export {};
@@ -1,4 +1,5 @@
1
1
  import type { FormatConfig } from "./connection";
2
+ import type { AudioWorkletConfig } from "../BaseConversation";
2
3
  export type InputConfig = {
3
4
  preferHeadphonesForIosDevices?: boolean;
4
5
  inputDeviceId?: string;
@@ -9,9 +10,9 @@ export declare class Input {
9
10
  readonly worklet: AudioWorkletNode;
10
11
  inputStream: MediaStream;
11
12
  private mediaStreamSource;
12
- static create({ sampleRate, format, preferHeadphonesForIosDevices, inputDeviceId, }: FormatConfig & InputConfig): Promise<Input>;
13
+ static create({ sampleRate, format, preferHeadphonesForIosDevices, inputDeviceId, workletPaths, libsampleratePath, }: FormatConfig & InputConfig & AudioWorkletConfig): Promise<Input>;
13
14
  private constructor();
14
15
  close(): Promise<void>;
15
16
  setMuted(isMuted: boolean): void;
16
- setInputDevice(inputDeviceId: string): Promise<void>;
17
+ setInputDevice(inputDeviceId?: string): Promise<void>;
17
18
  }
@@ -1,12 +1,16 @@
1
1
  import type { FormatConfig } from "./connection";
2
+ import type { AudioWorkletConfig } from "../BaseConversation";
3
+ export type OutputConfig = {
4
+ outputDeviceId?: string;
5
+ };
2
6
  export declare class Output {
3
7
  readonly context: AudioContext;
4
8
  readonly analyser: AnalyserNode;
5
9
  readonly gain: GainNode;
6
10
  readonly worklet: AudioWorkletNode;
7
11
  readonly audioElement: HTMLAudioElement;
8
- static create({ sampleRate, format, outputDeviceId, }: FormatConfig): Promise<Output>;
12
+ static create({ sampleRate, format, outputDeviceId, workletPaths, }: FormatConfig & OutputConfig & AudioWorkletConfig): Promise<Output>;
9
13
  private constructor();
10
- setOutputDevice(deviceId: string): Promise<void>;
14
+ setOutputDevice(deviceId?: string): Promise<void>;
11
15
  close(): Promise<void>;
12
16
  }
@@ -1 +1 @@
1
- export declare const loadRawAudioProcessor: (worklet: AudioWorklet) => Promise<void>;
1
+ export declare const loadRawAudioProcessor: (worklet: AudioWorklet, path?: string) => Promise<void>;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const PACKAGE_VERSION = "0.6.2";
1
+ export declare const PACKAGE_VERSION = "0.7.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevenlabs/client",
3
- "version": "0.6.2",
3
+ "version": "0.7.1",
4
4
  "description": "ElevenLabs JavaScript Client Library",
5
5
  "main": "./dist/lib.umd.js",
6
6
  "module": "./dist/lib.module.js",
@@ -34,15 +34,20 @@
34
34
  "url": "git+https://github.com/elevenlabs/packages.git",
35
35
  "directory": "packages/client"
36
36
  },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
37
40
  "dependencies": {
38
- "livekit-client": "^2.11.4"
41
+ "livekit-client": "^2.11.4",
42
+ "@elevenlabs/types": "0.0.1"
39
43
  },
40
44
  "scripts": {
41
45
  "generate-version": "printf \"// This file is auto-generated during build\\nexport const PACKAGE_VERSION = \\\"%s\\\";\\n\" \"$npm_package_version\" > src/version.ts",
42
- "prebuild": "pnpm run generate-version",
46
+ "generate-worklets": "node scripts/generateWorklets.js",
47
+ "prebuild": "pnpm run generate-version && pnpm run generate-worklets",
43
48
  "build": "BROWSERSLIST_ENV=modern microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react src/index.ts",
44
49
  "clean": "rm -rf ./dist",
45
- "dev": "pnpm run clean && pnpm run generate-version && BROWSERSLIST_ENV=development microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react src/index.ts -w -f modern",
50
+ "dev": "pnpm run clean && pnpm run generate-version && pnpm run generate-worklets && BROWSERSLIST_ENV=development microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react src/index.ts -w -f modern",
46
51
  "lint": "pnpm run lint:ts && pnpm run lint:es && pnpm run lint:prettier",
47
52
  "lint:ts": "tsc --noEmit --skipLibCheck",
48
53
  "lint:es": "pnpm exec eslint .",
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ const workletDir = path.join(__dirname, '../worklets');
11
+ const outputDir = path.join(__dirname, '../src/utils');
12
+
13
+ /** Creates ts versions of needed js scripts to code so that they can be exported and used during runtime. Automatically run during build */
14
+
15
+ const worklets = [
16
+ {
17
+ jsFile: 'rawAudioProcessor.js',
18
+ tsFile: 'rawAudioProcessor.generated.ts',
19
+ exportName: 'loadRawAudioProcessor',
20
+ processorName: 'rawAudioProcessor'
21
+ },
22
+ {
23
+ jsFile: 'audioConcatProcessor.js',
24
+ tsFile: 'audioConcatProcessor.generated.ts',
25
+ exportName: 'loadAudioConcatProcessor',
26
+ processorName: 'audioConcatProcessor'
27
+ }
28
+ ];
29
+
30
+ console.log('Generating TypeScript worklet files...');
31
+
32
+ worklets.forEach(({ jsFile, tsFile, exportName, processorName }) => {
33
+ const jsPath = path.join(workletDir, jsFile);
34
+ const tsPath = path.join(outputDir, tsFile);
35
+
36
+ const jsContent = fs.readFileSync(jsPath, 'utf8');
37
+
38
+ const tsContent = `// AUTO-GENERATED BY packages/client/scripts/generateWorklets.js
39
+ import { createWorkletModuleLoader } from "./createWorkletModuleLoader";
40
+
41
+ export const ${exportName} = createWorkletModuleLoader(
42
+ "${processorName}",
43
+ // language=JavaScript
44
+ \`${jsContent}\`
45
+ );
46
+ `;
47
+
48
+ // Write the TS file
49
+ fs.writeFileSync(tsPath, tsContent);
50
+ console.log(`Generated ${tsFile} from ${jsFile}`);
51
+ });
52
+
53
+ console.log('Worklet generation complete!');
@@ -0,0 +1,92 @@
1
+ /*
2
+ * ulaw decoding logic taken from the wavefile library
3
+ * https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js
4
+ * USED BY @elevenlabs/client
5
+ */
6
+
7
+ const decodeTable = [0,132,396,924,1980,4092,8316,16764];
8
+
9
+ function decodeSample(muLawSample) {
10
+ let sign;
11
+ let exponent;
12
+ let mantissa;
13
+ let sample;
14
+ muLawSample = ~muLawSample;
15
+ sign = (muLawSample & 0x80);
16
+ exponent = (muLawSample >> 4) & 0x07;
17
+ mantissa = muLawSample & 0x0F;
18
+ sample = decodeTable[exponent] + (mantissa << (exponent+3));
19
+ if (sign !== 0) sample = -sample;
20
+
21
+ return sample;
22
+ }
23
+
24
+ class AudioConcatProcessor extends AudioWorkletProcessor {
25
+ constructor() {
26
+ super();
27
+ this.buffers = []; // Initialize an empty buffer
28
+ this.cursor = 0;
29
+ this.currentBuffer = null;
30
+ this.wasInterrupted = false;
31
+ this.finished = false;
32
+
33
+ this.port.onmessage = ({ data }) => {
34
+ switch (data.type) {
35
+ case "setFormat":
36
+ this.format = data.format;
37
+ break;
38
+ case "buffer":
39
+ this.wasInterrupted = false;
40
+ this.buffers.push(
41
+ this.format === "ulaw"
42
+ ? new Uint8Array(data.buffer)
43
+ : new Int16Array(data.buffer)
44
+ );
45
+ break;
46
+ case "interrupt":
47
+ this.wasInterrupted = true;
48
+ break;
49
+ case "clearInterrupted":
50
+ if (this.wasInterrupted) {
51
+ this.wasInterrupted = false;
52
+ this.buffers = [];
53
+ this.currentBuffer = null;
54
+ }
55
+ }
56
+ };
57
+ }
58
+ process(_, outputs) {
59
+ let finished = false;
60
+ const output = outputs[0][0];
61
+ for (let i = 0; i < output.length; i++) {
62
+ if (!this.currentBuffer) {
63
+ if (this.buffers.length === 0) {
64
+ finished = true;
65
+ break;
66
+ }
67
+ this.currentBuffer = this.buffers.shift();
68
+ this.cursor = 0;
69
+ }
70
+
71
+ let value = this.currentBuffer[this.cursor];
72
+ if (this.format === "ulaw") {
73
+ value = decodeSample(value);
74
+ }
75
+ output[i] = value / 32768;
76
+ this.cursor++;
77
+
78
+ if (this.cursor >= this.currentBuffer.length) {
79
+ this.currentBuffer = null;
80
+ }
81
+ }
82
+
83
+ if (this.finished !== finished) {
84
+ this.finished = finished;
85
+ this.port.postMessage({ type: "process", finished });
86
+ }
87
+
88
+ return true; // Continue processing
89
+ }
90
+ }
91
+
92
+ registerProcessor("audioConcatProcessor", AudioConcatProcessor);
@@ -0,0 +1,124 @@
1
+ /*
2
+ * ulaw encoding logic taken from the wavefile library
3
+ * https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js
4
+ * USED BY @elevenlabs/client
5
+ */
6
+
7
+ const BIAS = 0x84;
8
+ const CLIP = 32635;
9
+ const encodeTable = [
10
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
11
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
12
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
13
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
14
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
15
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
16
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
17
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
18
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
19
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
20
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
21
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
22
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
23
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
24
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
25
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
26
+ ];
27
+
28
+ function encodeSample(sample) {
29
+ let sign;
30
+ let exponent;
31
+ let mantissa;
32
+ let muLawSample;
33
+ sign = (sample >> 8) & 0x80;
34
+ if (sign !== 0) sample = -sample;
35
+ sample = sample + BIAS;
36
+ if (sample > CLIP) sample = CLIP;
37
+ exponent = encodeTable[(sample>>7) & 0xFF];
38
+ mantissa = (sample >> (exponent+3)) & 0x0F;
39
+ muLawSample = ~(sign | (exponent << 4) | mantissa);
40
+
41
+ return muLawSample;
42
+ }
43
+
44
+ class RawAudioProcessor extends AudioWorkletProcessor {
45
+ constructor() {
46
+ super();
47
+
48
+ this.port.onmessage = ({ data }) => {
49
+ switch (data.type) {
50
+ case "setFormat":
51
+ this.isMuted = false;
52
+ this.buffer = []; // Initialize an empty buffer
53
+ this.bufferSize = data.sampleRate / 4;
54
+ this.format = data.format;
55
+
56
+ if (globalThis.LibSampleRate && sampleRate !== data.sampleRate) {
57
+ globalThis.LibSampleRate.create(1, sampleRate, data.sampleRate).then(resampler => {
58
+ this.resampler = resampler;
59
+ });
60
+ }
61
+ break;
62
+ case "setMuted":
63
+ this.isMuted = data.isMuted;
64
+ break;
65
+ }
66
+ };
67
+ }
68
+ process(inputs) {
69
+ if (!this.buffer) {
70
+ return true;
71
+ }
72
+
73
+ const input = inputs[0]; // Get the first input node
74
+ if (input.length > 0) {
75
+ let channelData = input[0]; // Get the first channel's data
76
+
77
+ // Resample the audio if necessary
78
+ if (this.resampler) {
79
+ channelData = this.resampler.full(channelData);
80
+ }
81
+
82
+ // Add channel data to the buffer
83
+ this.buffer.push(...channelData);
84
+ // Get max volume
85
+ let sum = 0.0;
86
+ for (let i = 0; i < channelData.length; i++) {
87
+ sum += channelData[i] * channelData[i];
88
+ }
89
+ const maxVolume = Math.sqrt(sum / channelData.length);
90
+ // Check if buffer size has reached or exceeded the threshold
91
+ if (this.buffer.length >= this.bufferSize) {
92
+ const float32Array = this.isMuted
93
+ ? new Float32Array(this.buffer.length)
94
+ : new Float32Array(this.buffer);
95
+
96
+ let encodedArray = this.format === "ulaw"
97
+ ? new Uint8Array(float32Array.length)
98
+ : new Int16Array(float32Array.length);
99
+
100
+ // Iterate through the Float32Array and convert each sample to PCM16
101
+ for (let i = 0; i < float32Array.length; i++) {
102
+ // Clamp the value to the range [-1, 1]
103
+ let sample = Math.max(-1, Math.min(1, float32Array[i]));
104
+
105
+ // Scale the sample to the range [-32768, 32767]
106
+ let value = sample < 0 ? sample * 32768 : sample * 32767;
107
+ if (this.format === "ulaw") {
108
+ value = encodeSample(Math.round(value));
109
+ }
110
+
111
+ encodedArray[i] = value;
112
+ }
113
+
114
+ // Send the buffered data to the main script
115
+ this.port.postMessage([encodedArray, maxVolume]);
116
+
117
+ // Clear the buffer after sending
118
+ this.buffer = [];
119
+ }
120
+ }
121
+ return true; // Continue processing
122
+ }
123
+ }
124
+ registerProcessor("rawAudioProcessor", RawAudioProcessor);