{"version":3,"file":"lib.cjs","sources":["../src/utils/audio.ts","../src/utils/rawAudioProcessor.ts","../src/utils/input.ts","../src/utils/audioConcatProcessor.ts","../src/utils/output.ts","../src/utils/events.ts","../src/utils/connection.ts","../src/index.ts"],"sourcesContent":["export function arrayBufferToBase64(b: ArrayBufferLike) {\n  const buffer = new Uint8Array(b);\n  // @ts-ignore\n  const base64Data = window.btoa(String.fromCharCode(...buffer));\n  return base64Data;\n}\n\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n  const binaryString = window.atob(base64);\n  const len = binaryString.length;\n  const bytes = new Uint8Array(len);\n  for (let i = 0; i < len; i++) {\n    bytes[i] = binaryString.charCodeAt(i);\n  }\n  return bytes.buffer;\n}\n","/*\n * ulaw encoding logic taken from the wavefile library\n * https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js\n */\n\nconst blob = new Blob(\n  [\n    // language=JavaScript\n    `\n      const BIAS = 0x84;\n      const CLIP = 32635;\n      const encodeTable = [\n        0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,\n        4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,\n        5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,\n        5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,\n        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,\n        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,\n        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,\n        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7\n      ];\n      \n      function encodeSample(sample) {\n        let sign;\n        let exponent;\n        let mantissa;\n        let muLawSample;\n        sign = (sample >> 8) & 0x80;\n        if (sign !== 0) sample = -sample;\n        sample = sample + BIAS;\n        if (sample > CLIP) sample = CLIP;\n        exponent = encodeTable[(sample>>7) & 0xFF];\n        mantissa = (sample >> (exponent+3)) & 0x0F;\n        muLawSample = ~(sign | (exponent << 4) | mantissa);\n        \n        return muLawSample;\n      }\n    \n      class RawAudioProcessor extends AudioWorkletProcessor {\n        constructor() {\n          super();\n                    \n          this.port.onmessage = ({ data }) => {\n            this.buffer = []; // Initialize an empty buffer\n            this.bufferSize = data.sampleRate / 4;\n            \n            if (globalThis.LibSampleRate && sampleRate !== data.sampleRate) {\n              globalThis.LibSampleRate.create(1, sampleRate, data.sampleRate).then(resampler => {\n                this.resampler = resampler;\n              });\n            } \n          };\n        }\n        process(inputs) {\n          if (!this.buffer) {\n            return true;\n          }\n          \n          const input = inputs[0]; // Get the first input node\n          if (input.length > 0) {\n            let channelData = input[0]; // Get the first channel's data\n\n            // Resample the audio if necessary\n            if (this.resampler) {\n              channelData = this.resampler.full(channelData);\n            }\n\n            // Add channel data to the buffer\n            this.buffer.push(...channelData);\n            // Get max volume \n            let sum = 0.0;\n            for (let i = 0; i < channelData.length; i++) {\n              sum += channelData[i] * channelData[i];\n            }\n            const maxVolume = Math.sqrt(sum / channelData.length);\n            // Check if buffer size has reached or exceeded the threshold\n            if (this.buffer.length >= this.bufferSize) {\n              const float32Array = new Float32Array(this.buffer)\n              let encodedArray = this.format === \"ulaw\"\n                ? new Uint8Array(float32Array.length)\n                : new Int16Array(float32Array.length);\n\n              // Iterate through the Float32Array and convert each sample to PCM16\n              for (let i = 0; i < float32Array.length; i++) {\n                // Clamp the value to the range [-1, 1]\n                let sample = Math.max(-1, Math.min(1, float32Array[i]));\n\n                // Scale the sample to the range [-32768, 32767]\n                let value = sample < 0 ? sample * 32768 : sample * 32767;\n                if (this.format === \"ulaw\") {\n                  value = encodeSample(Math.round(value));\n                }\n\n                encodedArray[i] = value;\n              }\n\n              // Send the buffered data to the main script\n              this.port.postMessage([encodedArray, maxVolume]);\n\n              // Clear the buffer after sending\n              this.buffer = [];\n            }\n          }\n          return true; // Continue processing\n        }\n      }\n      registerProcessor(\"raw-audio-processor\", RawAudioProcessor);\n  `,\n  ],\n  { type: \"application/javascript\" }\n);\n\nexport const rawAudioProcessor = URL.createObjectURL(blob);\n","import { rawAudioProcessor } from \"./rawAudioProcessor\";\nimport { FormatConfig } from \"./connection\";\n\nexport type InputConfig = {\n  preferHeadphonesForIosDevices?: boolean;\n};\n\nconst LIBSAMPLERATE_JS =\n  \"https://cdn.jsdelivr.net/npm/@alexanderolsen/libsamplerate-js@2.1.2/dist/libsamplerate.worklet.js\";\n\nfunction isIosDevice() {\n  return (\n    [\n      \"iPad Simulator\",\n      \"iPhone Simulator\",\n      \"iPod Simulator\",\n      \"iPad\",\n      \"iPhone\",\n      \"iPod\",\n    ].includes(navigator.platform) ||\n    // iPad on iOS 13 detection\n    (navigator.userAgent.includes(\"Mac\") && \"ontouchend\" in document)\n  );\n}\n\nexport class Input {\n  public static async create({\n    sampleRate,\n    format,\n    preferHeadphonesForIosDevices,\n  }: FormatConfig & InputConfig): Promise<Input> {\n    let context: AudioContext | null = null;\n    let inputStream: MediaStream | null = null;\n\n    try {\n      const options: MediaTrackConstraints = {\n        sampleRate: { ideal: sampleRate },\n        echoCancellation: { ideal: true },\n        noiseSuppression: { ideal: true },\n      };\n\n      // some browsers won't allow calling getSupportedConstraints or enumerateDevices\n      // before getting approval for microphone access\n      const preliminaryInputStream = await navigator.mediaDevices.getUserMedia({\n        audio: true,\n      });\n      preliminaryInputStream?.getTracks().forEach(track => track.stop());\n\n      if (isIosDevice() && preferHeadphonesForIosDevices) {\n        const availableDevices =\n          await window.navigator.mediaDevices.enumerateDevices();\n        const idealDevice = availableDevices.find(\n          d =>\n            // cautious to include \"bluetooth\" in the search\n            // as might trigger bluetooth speakers\n            d.kind === \"audioinput\" &&\n            [\"airpod\", \"headphone\", \"earphone\"].find(keyword =>\n              d.label.toLowerCase().includes(keyword)\n            )\n        );\n        if (idealDevice) {\n          options.deviceId = { ideal: idealDevice.deviceId };\n        }\n      }\n\n      const supportsSampleRateConstraint =\n        navigator.mediaDevices.getSupportedConstraints().sampleRate;\n\n      context = new window.AudioContext(\n        supportsSampleRateConstraint ? { sampleRate } : {}\n      );\n      const analyser = context.createAnalyser();\n      if (!supportsSampleRateConstraint) {\n        await context.audioWorklet.addModule(LIBSAMPLERATE_JS);\n      }\n      await context.audioWorklet.addModule(rawAudioProcessor);\n\n      inputStream = await navigator.mediaDevices.getUserMedia({\n        audio: options,\n      });\n\n      const source = context.createMediaStreamSource(inputStream);\n      const worklet = new AudioWorkletNode(context, \"raw-audio-processor\");\n      worklet.port.postMessage({ type: \"setFormat\", format, sampleRate });\n\n      source.connect(analyser);\n      analyser.connect(worklet);\n\n      return new Input(context, analyser, worklet, inputStream);\n    } catch (error) {\n      inputStream?.getTracks().forEach(track => track.stop());\n      context?.close();\n      throw error;\n    }\n  }\n\n  private constructor(\n    public readonly context: AudioContext,\n    public readonly analyser: AnalyserNode,\n    public readonly worklet: AudioWorkletNode,\n    public readonly inputStream: MediaStream\n  ) {}\n\n  public async close() {\n    this.inputStream.getTracks().forEach(track => track.stop());\n    await this.context.close();\n  }\n}\n","/*\n * ulaw decoding logic taken from the wavefile library\n * https://github.com/rochars/wavefile/blob/master/lib/codecs/mulaw.js\n */\n\nconst blob = new Blob(\n  [\n    // language=JavaScript\n    `\n      const decodeTable = [0,132,396,924,1980,4092,8316,16764];\n      \n      export function decodeSample(muLawSample) {\n        let sign;\n        let exponent;\n        let mantissa;\n        let sample;\n        muLawSample = ~muLawSample;\n        sign = (muLawSample & 0x80);\n        exponent = (muLawSample >> 4) & 0x07;\n        mantissa = muLawSample & 0x0F;\n        sample = decodeTable[exponent] + (mantissa << (exponent+3));\n        if (sign !== 0) sample = -sample;\n\n        return sample;\n      }\n      \n      class AudioConcatProcessor extends AudioWorkletProcessor {\n        constructor() {\n          super();\n          this.buffers = []; // Initialize an empty buffer\n          this.cursor = 0;\n          this.currentBuffer = null;\n          this.wasInterrupted = false;\n          this.finished = false;\n          \n          this.port.onmessage = ({ data }) => {\n            switch (data.type) {\n              case \"setFormat\":\n                this.format = data.format;\n                break;\n              case \"buffer\":\n                this.wasInterrupted = false;\n                this.buffers.push(\n                  this.format === \"ulaw\"\n                    ? new Uint8Array(data.buffer)\n                    : new Int16Array(data.buffer)\n                );\n                break;\n              case \"interrupt\":\n                this.wasInterrupted = true;\n                break;\n              case \"clearInterrupted\":\n                if (this.wasInterrupted) {\n                  this.wasInterrupted = false;\n                  this.buffers = [];\n                  this.currentBuffer = null;\n                }\n            }\n          };\n        }\n        process(_, outputs) {\n          let finished = false;\n          const output = outputs[0][0];\n          for (let i = 0; i < output.length; i++) {\n            if (!this.currentBuffer) {\n              if (this.buffers.length === 0) {\n                finished = true;\n                break;\n              }\n              this.currentBuffer = this.buffers.shift();\n              this.cursor = 0;\n            }\n\n            let value = this.currentBuffer[this.cursor];\n            if (this.format === \"ulaw\") {\n              value = decodeSample(value);\n            }\n            output[i] = value / 32768;\n            this.cursor++;\n\n            if (this.cursor >= this.currentBuffer.length) {\n              this.currentBuffer = null;\n            }\n          }\n\n          if (this.finished !== finished) {\n            this.finished = finished;\n            this.port.postMessage({ type: \"process\", finished });\n          }\n\n          return true; // Continue processing\n        }\n      }\n\n      registerProcessor(\"audio-concat-processor\", AudioConcatProcessor);\n    `,\n  ],\n  { type: \"application/javascript\" }\n);\n\nexport const audioConcatProcessor = URL.createObjectURL(blob);\n","import { audioConcatProcessor } from \"./audioConcatProcessor\";\nimport { FormatConfig } from \"./connection\";\n\nexport class Output {\n  public static async create({\n    sampleRate,\n    format,\n  }: FormatConfig): Promise<Output> {\n    let context: AudioContext | null = null;\n    try {\n      context = new AudioContext({ sampleRate });\n      const analyser = context.createAnalyser();\n      const gain = context.createGain();\n      gain.connect(analyser);\n      analyser.connect(context.destination);\n      await context.audioWorklet.addModule(audioConcatProcessor);\n      const worklet = new AudioWorkletNode(context, \"audio-concat-processor\");\n      worklet.port.postMessage({ type: \"setFormat\", format });\n      worklet.connect(gain);\n\n      return new Output(context, analyser, gain, worklet);\n    } catch (error) {\n      context?.close();\n      throw error;\n    }\n  }\n\n  private constructor(\n    public readonly context: AudioContext,\n    public readonly analyser: AnalyserNode,\n    public readonly gain: GainNode,\n    public readonly worklet: AudioWorkletNode\n  ) {}\n\n  public async close() {\n    await this.context.close();\n  }\n}\n","import { Language } from \"./connection\";\n\nexport type UserTranscriptionEvent = {\n  type: \"user_transcript\";\n  user_transcription_event: { user_transcript: string };\n};\nexport type AgentResponseEvent = {\n  type: \"agent_response\";\n  agent_response_event: { agent_response: string };\n};\nexport type AgentAudioEvent = {\n  type: \"audio\";\n  audio_event: {\n    audio_base_64: string;\n    event_id: number;\n  };\n};\nexport type InterruptionEvent = {\n  type: \"interruption\";\n  interruption_event: {\n    event_id: number;\n  };\n};\nexport type InternalTentativeAgentResponseEvent = {\n  type: \"internal_tentative_agent_response\";\n  tentative_agent_response_internal_event: {\n    tentative_agent_response: string;\n  };\n};\nexport type ConfigEvent = {\n  type: \"conversation_initiation_metadata\";\n  conversation_initiation_metadata_event: {\n    conversation_id: string;\n    agent_output_audio_format: string;\n    user_input_audio_format?: string;\n  };\n};\nexport type PingEvent = {\n  type: \"ping\";\n  ping_event: {\n    event_id: number;\n    ping_ms?: number;\n  };\n};\nexport type ClientToolCallEvent = {\n  type: \"client_tool_call\";\n  client_tool_call: {\n    tool_name: string;\n    tool_call_id: string;\n    parameters: any;\n    expects_response: boolean;\n  };\n};\n\n// TODO correction missing\nexport type IncomingSocketEvent =\n  | UserTranscriptionEvent\n  | AgentResponseEvent\n  | AgentAudioEvent\n  | InterruptionEvent\n  | InternalTentativeAgentResponseEvent\n  | ConfigEvent\n  | PingEvent\n  | ClientToolCallEvent;\n\nexport type PongEvent = {\n  type: \"pong\";\n  event_id: number;\n};\nexport type UserAudioEvent = {\n  user_audio_chunk: string;\n};\nexport type UserFeedbackEvent = {\n  type: \"feedback\";\n  score: \"like\" | \"dislike\";\n  event_id: number;\n};\nexport type ClientToolResultEvent = {\n  type: \"client_tool_result\";\n  tool_call_id: string;\n  result: any;\n  is_error: boolean;\n};\nexport type InitiationClientDataEvent = {\n  type: \"conversation_initiation_client_data\";\n  conversation_config_override?: {\n    agent?: {\n      prompt?: {\n        prompt?: string;\n      };\n      first_message?: string;\n      language?: Language;\n    };\n    tts?: {\n      voice_id?: string;\n    };\n  };\n  custom_llm_extra_body?: any;\n  dynamic_variables?: Record<string, string | number | boolean>;\n};\nexport type OutgoingSocketEvent =\n  | PongEvent\n  | UserAudioEvent\n  | InitiationClientDataEvent\n  | UserFeedbackEvent\n  | ClientToolResultEvent;\n\nexport function isValidSocketEvent(event: any): event is IncomingSocketEvent {\n  return !!event.type;\n}\n","import {\n  InitiationClientDataEvent,\n  ConfigEvent,\n  isValidSocketEvent,\n  OutgoingSocketEvent,\n} from \"./events\";\n\nconst MAIN_PROTOCOL = \"convai\";\n\nexport type Language =\n  | \"en\"\n  | \"ja\"\n  | \"zh\"\n  | \"de\"\n  | \"hi\"\n  | \"fr\"\n  | \"ko\"\n  | \"pt\"\n  | \"it\"\n  | \"es\"\n  | \"id\"\n  | \"nl\"\n  | \"tr\"\n  | \"pl\"\n  | \"sv\"\n  | \"bg\"\n  | \"ro\"\n  | \"ar\"\n  | \"cs\"\n  | \"el\"\n  | \"fi\"\n  | \"ms\"\n  | \"da\"\n  | \"ta\"\n  | \"uk\"\n  | \"ru\"\n  | \"hu\"\n  | \"no\"\n  | \"vi\";\nexport type SessionConfig = {\n  origin?: string;\n  authorization?: string;\n  overrides?: {\n    agent?: {\n      prompt?: {\n        prompt?: string;\n      };\n      firstMessage?: string;\n      language?: Language;\n    };\n    tts?: {\n      voiceId?: string;\n    };\n  };\n  customLlmExtraBody?: any;\n  dynamicVariables?: Record<string, string | number | boolean>;\n} & (\n  | { signedUrl: string; agentId?: undefined }\n  | { agentId: string; signedUrl?: undefined }\n);\nexport type FormatConfig = {\n  format: \"pcm\" | \"ulaw\";\n  sampleRate: number;\n};\n\nconst WSS_API_ORIGIN = \"wss://api.elevenlabs.io\";\nconst WSS_API_PATHNAME = \"/v1/convai/conversation?agent_id=\";\n\nexport class Connection {\n  public static async create(config: SessionConfig): Promise<Connection> {\n    let socket: WebSocket | null = null;\n\n    try {\n      const origin = config.origin ?? WSS_API_ORIGIN;\n      const url = config.signedUrl\n        ? config.signedUrl\n        : origin + WSS_API_PATHNAME + config.agentId;\n\n      const protocols = [MAIN_PROTOCOL];\n      if (config.authorization) {\n        protocols.push(`bearer.${config.authorization}`);\n      }\n      socket = new WebSocket(url, protocols);\n      const conversationConfig = await new Promise<\n        ConfigEvent[\"conversation_initiation_metadata_event\"]\n      >((resolve, reject) => {\n        socket!.addEventListener(\n          \"open\",\n          () => {\n            const overridesEvent: InitiationClientDataEvent = {\n              type: \"conversation_initiation_client_data\",\n            };\n\n            if (config.overrides) {\n              overridesEvent.conversation_config_override = {\n                agent: {\n                  prompt: config.overrides.agent?.prompt,\n                  first_message: config.overrides.agent?.firstMessage,\n                  language: config.overrides.agent?.language,\n                },\n                tts: {\n                  voice_id: config.overrides.tts?.voiceId,\n                },\n              };\n            }\n\n            if (config.customLlmExtraBody) {\n              overridesEvent.custom_llm_extra_body = config.customLlmExtraBody;\n            }\n\n            if (config.dynamicVariables) {\n              overridesEvent.dynamic_variables = config.dynamicVariables;\n            }\n\n            socket?.send(JSON.stringify(overridesEvent));\n          },\n          { once: true }\n        );\n        socket!.addEventListener(\"error\", reject);\n        socket!.addEventListener(\"close\", reject);\n        socket!.addEventListener(\n          \"message\",\n          (event: MessageEvent) => {\n            const message = JSON.parse(event.data);\n\n            if (!isValidSocketEvent(message)) {\n              return;\n            }\n\n            if (message.type === \"conversation_initiation_metadata\") {\n              resolve(message.conversation_initiation_metadata_event);\n            } else {\n              console.warn(\n                \"First received message is not conversation metadata.\"\n              );\n            }\n          },\n          { once: true }\n        );\n      });\n\n      const {\n        conversation_id,\n        agent_output_audio_format,\n        user_input_audio_format,\n      } = conversationConfig;\n\n      const inputFormat = parseFormat(user_input_audio_format ?? \"pcm_16000\");\n      const outputFormat = parseFormat(agent_output_audio_format);\n\n      return new Connection(socket, conversation_id, inputFormat, outputFormat);\n    } catch (error) {\n      socket?.close();\n      throw error;\n    }\n  }\n\n  private constructor(\n    public readonly socket: WebSocket,\n    public readonly conversationId: string,\n    public readonly inputFormat: FormatConfig,\n    public readonly outputFormat: FormatConfig\n  ) {}\n\n  public close() {\n    this.socket.close();\n  }\n\n  public sendMessage(message: OutgoingSocketEvent) {\n    this.socket.send(JSON.stringify(message));\n  }\n}\n\nfunction parseFormat(format: string): FormatConfig {\n  const [formatPart, sampleRatePart] = format.split(\"_\");\n  if (![\"pcm\", \"ulaw\"].includes(formatPart)) {\n    throw new Error(`Invalid format: ${format}`);\n  }\n\n  const sampleRate = parseInt(sampleRatePart);\n  if (isNaN(sampleRate)) {\n    throw new Error(`Invalid sample rate: ${sampleRatePart}`);\n  }\n\n  return {\n    format: formatPart as FormatConfig[\"format\"],\n    sampleRate,\n  };\n}\n","import { arrayBufferToBase64, base64ToArrayBuffer } from \"./utils/audio\";\nimport { Input, InputConfig } from \"./utils/input\";\nimport { Output } from \"./utils/output\";\nimport { Connection, SessionConfig } from \"./utils/connection\";\nimport {\n  ClientToolCallEvent,\n  isValidSocketEvent,\n  PingEvent,\n} from \"./utils/events\";\n\nexport type { IncomingSocketEvent } from \"./utils/events\";\nexport type { SessionConfig } from \"./utils/connection\";\n\nexport type Role = \"user\" | \"ai\";\nexport type Mode = \"speaking\" | \"listening\";\nexport type Status =\n  | \"connecting\"\n  | \"connected\"\n  | \"disconnecting\"\n  | \"disconnected\";\nexport type Options = SessionConfig &\n  Callbacks &\n  ClientToolsConfig &\n  InputConfig;\nexport type ClientToolsConfig = {\n  clientTools: Record<\n    string,\n    (\n      parameters: any\n    ) => Promise<string | number | void> | string | number | void\n  >;\n};\nexport type Callbacks = {\n  onConnect: (props: { conversationId: string }) => void;\n  // internal debug events, not to be used\n  onDebug: (props: any) => void;\n  onDisconnect: () => void;\n  onError: (message: string, context?: any) => void;\n  onMessage: (props: { message: string; source: Role }) => void;\n  onModeChange: (prop: { mode: Mode }) => void;\n  onStatusChange: (prop: { status: Status }) => void;\n  onCanSendFeedbackChange: (prop: { canSendFeedback: boolean }) => void;\n  onUnhandledClientToolCall?: (\n    params: ClientToolCallEvent[\"client_tool_call\"]\n  ) => void;\n};\n\nconst defaultClientTools = { clientTools: {} };\nconst defaultCallbacks: Callbacks = {\n  onConnect: () => {},\n  onDebug: () => {},\n  onDisconnect: () => {},\n  onError: () => {},\n  onMessage: () => {},\n  onModeChange: () => {},\n  onStatusChange: () => {},\n  onCanSendFeedbackChange: () => {},\n};\n\nconst HTTPS_API_ORIGIN = \"https://api.elevenlabs.io\";\n\nexport class Conversation {\n  public static async startSession(\n    options: SessionConfig &\n      Partial<Callbacks> &\n      Partial<ClientToolsConfig> &\n      Partial<InputConfig>\n  ): Promise<Conversation> {\n    const fullOptions: Options = {\n      ...defaultClientTools,\n      ...defaultCallbacks,\n      ...options,\n    };\n\n    fullOptions.onStatusChange({ status: \"connecting\" });\n    fullOptions.onCanSendFeedbackChange({ canSendFeedback: false });\n\n    let input: Input | null = null;\n    let connection: Connection | null = null;\n    let output: Output | null = null;\n\n    try {\n      connection = await Connection.create(options);\n      [input, output] = await Promise.all([\n        Input.create({\n          ...connection.inputFormat,\n          preferHeadphonesForIosDevices: options.preferHeadphonesForIosDevices,\n        }),\n        Output.create(connection.outputFormat),\n      ]);\n\n      return new Conversation(fullOptions, connection, input, output);\n    } catch (error) {\n      fullOptions.onStatusChange({ status: \"disconnected\" });\n      connection?.close();\n      await input?.close();\n      await output?.close();\n      throw error;\n    }\n  }\n\n  private lastInterruptTimestamp: number = 0;\n  private mode: Mode = \"listening\";\n  private status: Status = \"connecting\";\n  private inputFrequencyData?: Uint8Array;\n  private outputFrequencyData?: Uint8Array;\n  private volume: number = 1;\n  private currentEventId: number = 1;\n  private lastFeedbackEventId: number = 1;\n  private canSendFeedback: boolean = false;\n  private isMuted: boolean = false;\n\n  private constructor(\n    private readonly options: Options,\n    private readonly connection: Connection,\n    public readonly input: Input,\n    public readonly output: Output\n  ) {\n    this.options.onConnect({ conversationId: connection.conversationId });\n\n    this.connection.socket.addEventListener(\"message\", event => {\n      this.onEvent(event);\n    });\n    this.connection.socket.addEventListener(\"error\", event => {\n      this.updateStatus(\"disconnected\");\n      this.onError(\"Socket error\", event);\n    });\n    this.connection.socket.addEventListener(\"close\", () => {\n      this.updateStatus(\"disconnected\");\n      this.options.onDisconnect();\n    });\n\n    this.input.worklet.port.onmessage = this.onInputWorkletMessage;\n    this.output.worklet.port.onmessage = this.onOutputWorkletMessage;\n    this.updateStatus(\"connected\");\n  }\n\n  public muteMicrophone = () => {\n    this.isMuted = true;\n  }\n\n  public unmuteMicrophone = () => {\n    this.isMuted = false;\n  }\n\n  public endSession = async () => {\n    if (this.status !== \"connected\") return;\n    this.updateStatus(\"disconnecting\");\n\n    this.connection.close();\n    await this.input.close();\n    await this.output.close();\n\n    this.updateStatus(\"disconnected\");\n  };\n\n  private updateMode = (mode: Mode) => {\n    if (mode !== this.mode) {\n      this.mode = mode;\n      this.options.onModeChange({ mode });\n    }\n  };\n\n  private updateStatus = (status: Status) => {\n    if (status !== this.status) {\n      this.status = status;\n      this.options.onStatusChange({ status });\n    }\n  };\n\n  private updateCanSendFeedback = () => {\n    const canSendFeedback = this.currentEventId !== this.lastFeedbackEventId;\n    if (this.canSendFeedback !== canSendFeedback) {\n      this.canSendFeedback = canSendFeedback;\n      this.options.onCanSendFeedbackChange({ canSendFeedback });\n    }\n  };\n\n  private onEvent = async (event: MessageEvent) => {\n    try {\n      const parsedEvent = JSON.parse(event.data);\n\n      if (!isValidSocketEvent(parsedEvent)) {\n        return;\n      }\n\n      switch (parsedEvent.type) {\n        case \"interruption\": {\n          if (parsedEvent.interruption_event) {\n            this.lastInterruptTimestamp =\n              parsedEvent.interruption_event.event_id;\n          }\n          this.fadeOutAudio();\n          break;\n        }\n\n        case \"agent_response\": {\n          this.options.onMessage({\n            source: \"ai\",\n            message: parsedEvent.agent_response_event.agent_response,\n          });\n          break;\n        }\n\n        case \"user_transcript\": {\n          this.options.onMessage({\n            source: \"user\",\n            message: parsedEvent.user_transcription_event.user_transcript,\n          });\n          break;\n        }\n\n        case \"internal_tentative_agent_response\": {\n          this.options.onDebug({\n            type: \"tentative_agent_response\",\n            response:\n              parsedEvent.tentative_agent_response_internal_event\n                .tentative_agent_response,\n          });\n          break;\n        }\n\n        case \"client_tool_call\": {\n          if (\n            this.options.clientTools.hasOwnProperty(\n              parsedEvent.client_tool_call.tool_name\n            )\n          ) {\n            try {\n              const result =\n                (await this.options.clientTools[\n                  parsedEvent.client_tool_call.tool_name\n                ](parsedEvent.client_tool_call.parameters)) ??\n                \"Client tool execution successful.\"; // default client-tool call response\n\n              this.connection.sendMessage({\n                type: \"client_tool_result\",\n                tool_call_id: parsedEvent.client_tool_call.tool_call_id,\n                result: result,\n                is_error: false,\n              });\n            } catch (e) {\n              this.onError(\n                \"Client tool execution failed with following error: \" +\n                  (e as Error)?.message,\n                {\n                  clientToolName: parsedEvent.client_tool_call.tool_name,\n                }\n              );\n              this.connection.sendMessage({\n                type: \"client_tool_result\",\n                tool_call_id: parsedEvent.client_tool_call.tool_call_id,\n                result:\n                  \"Client tool execution failed: \" + (e as Error)?.message,\n                is_error: true,\n              });\n            }\n\n            break;\n          }\n\n          if (this.options.onUnhandledClientToolCall) {\n            this.options.onUnhandledClientToolCall(\n              parsedEvent.client_tool_call\n            );\n\n            break;\n          }\n\n          this.onError(\n            `Client tool with name ${parsedEvent.client_tool_call.tool_name} is not defined on client`,\n            {\n              clientToolName: parsedEvent.client_tool_call.tool_name,\n            }\n          );\n          this.connection.sendMessage({\n            type: \"client_tool_result\",\n            tool_call_id: parsedEvent.client_tool_call.tool_call_id,\n            result: `Client tool with name ${parsedEvent.client_tool_call.tool_name} is not defined on client`,\n            is_error: true,\n          });\n\n          break;\n        }\n\n        case \"audio\": {\n          if (this.lastInterruptTimestamp <= parsedEvent.audio_event.event_id) {\n            this.addAudioBase64Chunk(parsedEvent.audio_event.audio_base_64);\n            this.currentEventId = parsedEvent.audio_event.event_id;\n            this.updateCanSendFeedback();\n            this.updateMode(\"speaking\");\n          }\n          break;\n        }\n\n        case \"ping\": {\n          this.connection.sendMessage({\n            type: \"pong\",\n            event_id: (parsedEvent as PingEvent).ping_event.event_id,\n          });\n          // parsedEvent.ping_event.ping_ms can be used on client side, for example\n          // to warn if ping is too high that experience might be degraded.\n          break;\n        }\n\n        // unhandled events are expected to be internal events\n        default: {\n          this.options.onDebug(parsedEvent);\n          break;\n        }\n      }\n    } catch {\n      this.onError(\"Failed to parse event data\", { event });\n      return;\n    }\n  };\n\n  private onInputWorkletMessage = (event: MessageEvent): void => {\n    const rawAudioPcmData = event.data[0];\n    const maxVolume = event.data[1];\n\n    // check if the sound was loud enough, so we don't send unnecessary chunks\n    // then forward audio to websocket\n    //if (maxVolume > 0.001) {\n    if (this.status === \"connected\" && !this.isMuted) {\n      this.connection.sendMessage({\n        user_audio_chunk: arrayBufferToBase64(rawAudioPcmData.buffer),\n        //sample_rate: this.inputAudioContext?.inputSampleRate || this.inputSampleRate,\n      });\n    }\n    //}\n  };\n\n  private onOutputWorkletMessage = ({ data }: MessageEvent): void => {\n    if (data.type === \"process\") {\n      this.updateMode(data.finished ? \"listening\" : \"speaking\");\n    }\n  };\n\n  private addAudioBase64Chunk = async (chunk: string) => {\n    this.output.gain.gain.value = this.volume;\n    this.output.worklet.port.postMessage({ type: \"clearInterrupted\" });\n    this.output.worklet.port.postMessage({\n      type: \"buffer\",\n      buffer: base64ToArrayBuffer(chunk),\n    });\n  };\n\n  private fadeOutAudio = async () => {\n    // mute agent\n    this.updateMode(\"listening\");\n    this.output.worklet.port.postMessage({ type: \"interrupt\" });\n    this.output.gain.gain.exponentialRampToValueAtTime(\n      0.0001,\n      this.output.context.currentTime + 2\n    );\n\n    // reset volume back\n    setTimeout(() => {\n      this.output.gain.gain.value = this.volume;\n      this.output.worklet.port.postMessage({ type: \"clearInterrupted\" });\n    }, 2000); // Adjust the duration as needed\n  };\n\n  private onError = (message: string, context?: any) => {\n    console.error(message, context);\n    this.options.onError(message, context);\n  };\n\n  private calculateVolume = (frequencyData: Uint8Array) => {\n    if (frequencyData.length === 0) {\n      return 0;\n    }\n\n    // TODO: Currently this averages all frequencies, but we should probably\n    // bias towards the frequencies that are more typical for human voice\n    let volume = 0;\n    for (let i = 0; i < frequencyData.length; i++) {\n      volume += frequencyData[i] / 255;\n    }\n    volume /= frequencyData.length;\n\n    return volume < 0 ? 0 : volume > 1 ? 1 : volume;\n  };\n\n  public getId = () => this.connection.conversationId;\n\n  public setVolume = ({ volume }: { volume: number }) => {\n    this.volume = volume;\n  };\n\n  public getInputByteFrequencyData = () => {\n    this.inputFrequencyData ??= new Uint8Array(\n      this.input.analyser.frequencyBinCount\n    );\n    this.input.analyser.getByteFrequencyData(this.inputFrequencyData);\n    return this.inputFrequencyData;\n  };\n\n  public getOutputByteFrequencyData = () => {\n    this.outputFrequencyData ??= new Uint8Array(\n      this.output.analyser.frequencyBinCount\n    );\n    this.output.analyser.getByteFrequencyData(this.outputFrequencyData);\n    return this.outputFrequencyData;\n  };\n\n  public getInputVolume = () => {\n    return this.calculateVolume(this.getInputByteFrequencyData());\n  };\n\n  public getOutputVolume = () => {\n    return this.calculateVolume(this.getOutputByteFrequencyData());\n  };\n\n  public sendFeedback = (like: boolean) => {\n    if (!this.canSendFeedback) {\n      console.warn(\n        this.lastFeedbackEventId === 0\n          ? \"Cannot send feedback: the conversation has not started yet.\"\n          : \"Cannot send feedback: feedback has already been sent for the current response.\"\n      );\n      return;\n    }\n\n    this.connection.sendMessage({\n      type: \"feedback\",\n      score: like ? \"like\" : \"dislike\",\n      event_id: this.currentEventId,\n    });\n    this.lastFeedbackEventId = this.currentEventId;\n    this.updateCanSendFeedback();\n  };\n}\n\nexport function postOverallFeedback(\n  conversationId: string,\n  like: boolean,\n  origin: string = HTTPS_API_ORIGIN\n) {\n  return fetch(`${origin}/v1/convai/conversations/${conversationId}/feedback`, {\n    method: \"POST\",\n    body: JSON.stringify({\n      feedback: like ? \"like\" : \"dislike\",\n    }),\n    headers: {\n      \"Content-Type\": \"application/json\",\n    },\n  });\n}\n"],"names":["base64ToArrayBuffer","base64","binaryString","window","atob","len","length","bytes","Uint8Array","i","charCodeAt","buffer","blob","Blob","type","rawAudioProcessor","URL","createObjectURL","Input","context","analyser","worklet","inputStream","this","create","_ref","sampleRate","format","preferHeadphonesForIosDevices","Promise","resolve","options","ideal","echoCancellation","noiseSuppression","navigator","mediaDevices","getUserMedia","audio","then","preliminaryInputStream","_temp4","_temp2","audioWorklet","addModule","_navigator$mediaDevic","source","createMediaStreamSource","AudioWorkletNode","port","postMessage","connect","supportsSampleRateConstraint","getSupportedConstraints","AudioContext","createAnalyser","_temp","getTracks","forEach","track","stop","_temp3","isIosDevice","includes","platform","userAgent","document","enumerateDevices","availableDevices","idealDevice","find","d","kind","keyword","label","toLowerCase","deviceId","_catch","error","_inputStream","_context","close","e","reject","prototype","audioConcatProcessor","Output","gain","createGain","destination","isValidSocketEvent","event","Connection","socket","conversationId","inputFormat","outputFormat","config","origin","_config$origin","url","signedUrl","agentId","protocols","authorization","push","WebSocket","addEventListener","_socket","_config$overrides$age","_config$overrides$age2","_config$overrides$age3","_config$overrides$tts","overridesEvent","overrides","conversation_config_override","agent","prompt","first_message","firstMessage","language","tts","voice_id","voiceId","customLlmExtraBody","custom_llm_extra_body","dynamicVariables","dynamic_variables","send","JSON","stringify","once","message","parse","data","conversation_initiation_metadata_event","console","warn","conversationConfig","conversation_id","agent_output_audio_format","user_input_audio_format","parseFormat","_socket2","_proto","sendMessage","_format$split","split","formatPart","sampleRatePart","Error","parseInt","isNaN","defaultClientTools","clientTools","pact","state","value","s","_Pact","o","_settle","bind","v","observer","defaultCallbacks","onConnect","onDebug","onDisconnect","onError","onMessage","onModeChange","onStatusChange","onCanSendFeedbackChange","result","callback","onFulfilled","onRejected","_this","Conversation","connection","input","output","_this2","_this3","_this4","_this5","lastInterruptTimestamp","mode","status","inputFrequencyData","outputFrequencyData","volume","currentEventId","lastFeedbackEventId","canSendFeedback","isMuted","muteMicrophone","unmuteMicrophone","endSession","updateStatus","updateMode","updateCanSendFeedback","onEvent","_interrupt","parsedEvent","_temp5","_switch","interruption_event","event_id","fadeOutAudio","agent_response_event","agent_response","user_transcription_event","user_transcript","response","tentative_agent_response_internal_event","tentative_agent_response","onUnhandledClientToolCall","client_tool_call","tool_name","clientToolName","tool_call_id","is_error","hasOwnProperty","parameters","audio_event","addAudioBase64Chunk","audio_base_64","ping_event","onInputWorkletMessage","b","user_audio_chunk","btoa","String","fromCharCode","apply","onOutputWorkletMessage","finished","chunk","exponentialRampToValueAtTime","currentTime","setTimeout","calculateVolume","frequencyData","getId","setVolume","_ref2","getInputByteFrequencyData","frequencyBinCount","getByteFrequencyData","getOutputByteFrequencyData","_this$outputFrequency","getInputVolume","getOutputVolume","sendFeedback","like","score","onmessage","startSession","fullOptions","_extends","_Connection$create","all","_Promise$all","_connection","_input","_output","fetch","method","body","feedback","headers"],"mappings":"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"}