Mobile (iOS Safari): no audio at all — autoplay policy or webkit-specific issue #56

Closed
opened 2026-06-21 15:46:10 +02:00 by bosun · 1 comment
Owner

Symptom (operator playtest, 2026-06-21, iPhone)

Operator: "No sound at all" — neither BGM nor SFX played on iPhone (Safari assumed). Desktop browsers work fine after PR #34 BGM gain fix; iOS audio entirely silent.

Likely root causes (need investigation)

iOS Safari has stricter Web Audio policy than desktop browsers:

  1. Autoplay restrictions are stricter on iOS: Even after user gesture, AudioContext.resume() may need to be called inside the gesture handler synchronously. If our code creates the context outside the gesture and resumes it asynchronously, iOS Safari blocks audio.
  2. WebKit-specific AudioContext quirks: webkitAudioContext may need different lifecycle handling than standard AudioContext. The unprefixed standard works in most modern Safari but some edge cases remain.
  3. iOS silent mode (mute switch): physical mute switch on iPhone silences Web Audio entirely. Worth confirming the operator wasn't in silent mode (but even unmuted, the underlying audio policy might still block).
  4. Sample rate mismatch: iOS default AudioContext sample rate is 44.1kHz; if our oscillators or buffer scheduling assume 48kHz they may fail silently on iOS.

Diagnostic suggestion

  1. Open the deployed site on an iPhone
  2. Open Safari Web Inspector via macOS Safari developer menu (need a Mac for full debug)
  3. Check console for AudioContext warnings
  4. Inspect AudioContext.state — should be "running" after first tap, not "suspended"
  5. Verify that the SOLO button click handler does audioContext.resume() synchronously

If no Mac available for inspector: try adding a debug overlay that prints audioContext.state to the canvas after first tap, deploy, retest.

Lane

Shipwright — audio.ts + mobile audio policy investigation.

Effort

Size/M — diagnostic + fix. Fix may be one line (sync resume() in click handler) or more substantial (webkit-prefixed fallback paths).

Note: BGM round-2 fix worked on desktop

PR #34 raised MUSIC_GAIN 0.035→0.12 (fixed inaudible-but-running). Operator confirmed BGM round-2 was audible on desktop. So the issue isn't the gain; it's iOS-specific audio-context-policy blocking everything at the substrate level.

## Symptom (operator playtest, 2026-06-21, iPhone) Operator: *"No sound at all"* — neither BGM nor SFX played on iPhone (Safari assumed). Desktop browsers work fine after PR #34 BGM gain fix; iOS audio entirely silent. ## Likely root causes (need investigation) iOS Safari has stricter Web Audio policy than desktop browsers: 1. **Autoplay restrictions are stricter on iOS**: Even after user gesture, `AudioContext.resume()` may need to be called *inside* the gesture handler synchronously. If our code creates the context outside the gesture and resumes it asynchronously, iOS Safari blocks audio. 2. **WebKit-specific AudioContext quirks**: `webkitAudioContext` may need different lifecycle handling than standard `AudioContext`. The unprefixed standard works in most modern Safari but some edge cases remain. 3. **iOS silent mode (mute switch)**: physical mute switch on iPhone silences Web Audio entirely. Worth confirming the operator wasn't in silent mode (but even unmuted, the underlying audio policy might still block). 4. **Sample rate mismatch**: iOS default AudioContext sample rate is 44.1kHz; if our oscillators or buffer scheduling assume 48kHz they may fail silently on iOS. ## Diagnostic suggestion 1. Open the deployed site on an iPhone 2. Open Safari Web Inspector via macOS Safari developer menu (need a Mac for full debug) 3. Check console for AudioContext warnings 4. Inspect AudioContext.state — should be "running" after first tap, not "suspended" 5. Verify that the SOLO button click handler does `audioContext.resume()` synchronously If no Mac available for inspector: try adding a debug overlay that prints `audioContext.state` to the canvas after first tap, deploy, retest. ## Lane Shipwright — audio.ts + mobile audio policy investigation. ## Effort Size/M — diagnostic + fix. Fix may be one line (sync `resume()` in click handler) or more substantial (webkit-prefixed fallback paths). ## Note: BGM round-2 fix worked on desktop PR #34 raised MUSIC_GAIN 0.035→0.12 (fixed inaudible-but-running). Operator confirmed BGM round-2 was audible on desktop. So the issue isn't the gain; it's iOS-specific audio-context-policy blocking everything at the substrate level.
bosun closed this issue 2026-06-21 16:55:02 +02:00
Author
Owner

Resolved by diagnostic instrument — root cause was operator-state (iPhone silent-mode physical switch), not a code bug. Operator confirmed via PR #58 debug-overlay iteration cycle: with silent mode OFF, audio works fine (and probably worked before PR #58 too — Shipwright already had synchronous AudioContext.resume() in the gesture handler from earlier work).

PR #58 (silent-buffer-kick + re-arm-on-iOS-suspend) ships net-positive defensive substrate-hardening regardless — handles real iOS-autoplay-policy edge cases (background/foreground cycles, context-creation-timing) that the original code might not have. Plus the ?debug=audio diagnostic overlay remains available for any future iOS audio issue (URL-gated, never affects normal users).

Bank-instance: the diagnostic instrument worked as designed — surfaced environment-vs-code distinction in a single device-iteration cycle. Without the overlay, the iteration loop might have spent multiple cycles assuming code conditions before reaching the silent-mode hypothesis. The instrument-merge-as-iteration-enablement pattern (Surveyor + Bosun banked earlier in this cycle) validated empirically.

Closing as resolved.

**Resolved by diagnostic instrument** — root cause was operator-state (iPhone silent-mode physical switch), not a code bug. Operator confirmed via PR #58 debug-overlay iteration cycle: with silent mode OFF, audio works fine (and probably worked before PR #58 too — Shipwright already had synchronous AudioContext.resume() in the gesture handler from earlier work). PR #58 (silent-buffer-kick + re-arm-on-iOS-suspend) ships net-positive defensive substrate-hardening regardless — handles real iOS-autoplay-policy edge cases (background/foreground cycles, context-creation-timing) that the original code might not have. Plus the ?debug=audio diagnostic overlay remains available for any future iOS audio issue (URL-gated, never affects normal users). **Bank-instance**: the diagnostic instrument worked as designed — surfaced environment-vs-code distinction in a single device-iteration cycle. Without the overlay, the iteration loop might have spent multiple cycles assuming code conditions before reaching the silent-mode hypothesis. The instrument-merge-as-iteration-enablement pattern (Surveyor + Bosun banked earlier in this cycle) validated empirically. Closing as resolved.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/cellblock#56
No description provided.