Skip to content

js: report AudioWorklet module loading failures - #305

Open
kumagi wants to merge 1 commit into
ebitengine:mainfrom
kumagi:codex/js-worklet-load-error
Open

kumagi wants to merge 1 commit into
ebitengine:mainfrom
kumagi:codex/js-worklet-load-error

Conversation

@kumagi

@kumagi kumagi commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

What issue is this addressing?

None

What type of issue is this addressing?

bug

What this PR does | solves

If AudioWorklet.addModule rejects (for example, when CSP blocks the Blob script), Oto currently leaves Context.Err() nil. A subsequent user gesture even closes the ready channel although no output node was connected.

Record the rejection and close the ready channel on failure without requiring user interaction. On success, wait for both the module connection and audio resume before closing it. Revoke the Blob URL and release the module callbacks in either case.

Initialization also removes the gesture listeners when it fails. Resume callbacks remain alive until their own promise settles, so a late resume cannot call a released function or close the ready channel twice. Pending resume requests are coalesced; a rejected resume leaves the next gesture able to retry.

Validation

Built a small js/wasm program that calls NewContext and observes the ready channel and Context.Err(), then ran it in headless Chrome 153.0.8010.52 with its real Web Audio implementation.

  • Served with script-src 'self' 'wasm-unsafe-eval'; worker-src 'none' to reject the Blob worklet. Before this change, Chrome reports an unhandled rejection and Oto reports readiness after a click with a nil error. Afterward, readiness closes with the load error even before a click, and the Blob URL is revoked.
  • Held the settlement of the real module/resume promises to check rejection before resume, after resume, and while resume is pending. All complete with the load error and no unhandled rejection or released-function call.
  • Checked successful initialization in both completion orders, including worklet port communication, and the ScriptProcessor fallback with audioWorklet hidden by the harness.
  • Injected one resume rejection, then verified that a subsequent gesture succeeds.
  • GOOS=js GOARCH=wasm go build and go vet ./... pass.

The timing gates and fallback/error injection were confined to the browser harness; the CSP rejection and normal worklet loading used the browser APIs. Firefox and Safari were not tested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant