iOfficeAI/AionUi · warning · AudioWorkletUnavailableError

AudioWorkletUnavailableError

Error message

AudioWorkletUnavailableError

What it means

`createPcmRecorder` needs the Web Audio `AudioWorklet` API to capture PCM frames; on browsers/electron builds where `context.audioWorklet` is undefined it closes the AudioContext, releases the mic stream, and throws `AudioWorkletUnavailableError`. This is a feature-detection failure, not a runtime crash.

Source

Thrown at packages/desktop/src/renderer/services/speech/pcmRecorder.ts:162

}): Promise<PcmRecorderHandle> => {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  const releaseMic = () => stream.getTracks().forEach((track) => track.stop());

  // Request 24kHz directly; Chromium honors it, but some platforms ignore the
  // hint, so the actual context.sampleRate is checked below.
  let context: AudioContext;
  try {
    context = new AudioContext({ sampleRate: STREAM_SAMPLE_RATE });
  } catch (error) {
    releaseMic();
    throw error;
  }
  const closeContext = (): Promise<void> => context.close().catch((): void => undefined);

  if (!context.audioWorklet) {
    await closeContext();
    releaseMic();
    throw new AudioWorkletUnavailableError();
  }

  const workletUrl = URL.createObjectURL(new Blob([WORKLET_SOURCE], { type: 'application/javascript' }));
  try {
    await context.audioWorklet.addModule(workletUrl);
  } catch (error) {
    await closeContext();
    releaseMic();
    throw error;
  } finally {
    URL.revokeObjectURL(workletUrl);
  }

  const contextRate = context.sampleRate;
  const needsResample = contextRate !== STREAM_SAMPLE_RATE;
  // Input samples (at context rate) needed to produce one 200ms output chunk.
  const chunkInputSamples = Math.max(1, Math.round((STREAM_CHUNK_SAMPLES * contextRate) / STREAM_SAMPLE_RATE));

View on GitHub (pinned to 711aa0550e)

Solutions

  1. Upgrade the Electron/Chromium runtime to a version supporting AudioWorklet (Chrome 66+/Electron 3+)
  2. Feature-detect before starting capture and fall back to a non-worklet recorder (ScriptProcessorNode) or disable PCM speech features
  3. Verify the page is not running in a restricted context that strips WebAudio features
  4. In tests, mock AudioContext with an audioWorklet stub instead of exercising the real path

Example fix

// before
if (!context.audioWorklet) {
  await closeContext();
  releaseMic();
  throw new AudioWorkletUnavailableError();
}

// after (pre-check and show guidance)
if (!('audioWorklet' in new AudioContext())) {
  showToast(t('speech.pcmUnsupported')); // and skip the record button
}
Defensive patterns

Strategy: type-guard

Validate before calling

const ctx = new AudioContext();
if (!('audioWorklet' in ctx)) { ctx.close(); /* fall back or disable PCM UI */ }

Type guard

const supportsAudioWorklet = (): boolean =>
  typeof AudioContext !== 'undefined' && 'audioWorklet' in AudioContext.prototype;

Try / catch

catch (e) { if (e instanceof AudioWorkletUnavailableError) disablePcmFeatures(); else throw e; }

Prevention

When it happens

Trigger: Creating the PCM recorder in an environment whose AudioContext lacks the `audioWorklet` property — older Chromium/Electron versions (pre-Chrome 66), non-secure/non-standard embedding contexts, or environments with the WebAudio API partially polyfilled/stripped.

Common situations: Running the app on an old Electron/Chromium runtime; audio capture in an iframe or webview without proper feature support; test environments (jsdom) lacking real WebAudio; browser-polyfill conflicts removing audioWorklet.


AI-assisted analysis of iOfficeAI/AionUi@711aa0550e (2026-08-28). Data as JSON: /api/errors/2037e7ae67f1c379. Report an issue: GitHub.