siyuan-note/siyuan · error · Error
AudioContext is not supported
Error message
AudioContext is not supported
What it means
RecordMedia constructor checks that either the global AudioContext or the legacy webkitAudioContext exists; if neither is defined it throws 'AudioContext is not supported'. This is a hard environment feature-detect failure for the Web Audio API before any recording can begin.
Source
Thrown at app/src/protyle/util/RecordMedia.ts:95
private worker: Worker;
private chunks: ArrayBuffer[] = [];
private readyPromise: Promise<void>;
private resolveReady: () => void;
private rejectReady: (error: Error) => void;
private stopPromise: Promise<Blob>;
private resolveStop: (blob: Blob) => void;
private rejectStop: (error: Error) => void;
private disposed = false;
private failure: Error;
private readonly handleTrackEnded = () => {
this.handleWorkerError(new RecordMediaInputEndedError());
};
constructor(mediaStream: MediaStream) {
this.mediaStream = mediaStream;
const AudioContextConstructor = typeof AudioContext !== "undefined" ? AudioContext : webkitAudioContext;
if (!AudioContextConstructor) {
throw new Error("AudioContext is not supported");
}
const contextOptions = {} as AudioContextOptions & { sinkId?: { type: "none" } };
if ((isInAndroid() || isInHarmony()) && "setSinkId" in AudioContextConstructor.prototype) {
contextOptions.sinkId = {type: "none"};
}
this.context = new AudioContextConstructor(contextOptions);
if (!this.context.audioWorklet || typeof AudioWorkletNode === "undefined") {
throw new Error("AudioWorklet is not supported");
}
this.audioInput = this.context.createMediaStreamSource(mediaStream);
this.mediaStream.getAudioTracks().forEach((track) => {
track.addEventListener("ended", this.handleTrackEnded);
});
}
public async startRecording() {
if (this.disposed) {View on GitHub (pinned to 251596fc0d)
Solutions
- Feature-detect AudioContext/webkitAudioContext before instantiating RecordMedia and disable the record button if missing.
- Ensure the page is served in a secure context (https or localhost) so the browser does not gate Web Audio.
- Update the host browser/webview to a version that ships Web Audio.
- In tests, polyfill AudioContext (standardized-audio-context mock).
Example fix
// before
const rec = new RecordMedia(stream);
// after
const Ctor = typeof AudioContext !== 'undefined' ? AudioContext : (window as any).webkitAudioContext;
if (!Ctor) { showMessage('Audio recording is not supported in this browser'); return; }
const rec = new RecordMedia(stream); Defensive patterns
Strategy: type-guard
Validate before calling
const Ctor = typeof AudioContext !== 'undefined' ? AudioContext : (window as any).webkitAudioContext;
if (!Ctor) { disableRecordButton(); return; } Type guard
function audioContextSupported(): boolean {
return typeof AudioContext !== 'undefined' || typeof (window as any).webkitAudioContext !== 'undefined';
} Try / catch
try { recorder = new RecordMedia(stream); }
catch (e) { if (/AudioContext/i.test(e.message)) showMessage('Voice recording unsupported in this browser'); } Prevention
- Feature-detect AudioContext before showing the record button.
- Serve the app over https or localhost (insecure contexts block Web Audio).
- Keep the host browser/webview up to date.
- Polyfill Web Audio in tests.
When it happens
Trigger: Constructing RecordMedia in a browser/webview that does not implement Web Audio (very old or stripped-down webview), in an insecure context where AudioContext is gated, or in a test environment (jsdom) without a Web Audio polyfill.
Common situations: Old Android System WebView; an iframe served over http (not localhost) where AudioContext is blocked; headless test runner; an enterprise policy disabling Web Audio.
Related errors
- AudioWorklet is not supported
- Recorder has been disposed
- MP3 encoder is not initialized
- Canvas 2D is unavailable
- WebGL2 is unavailable
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/8f9decceb9010b7e.
Report an issue: GitHub.