Skip to content

feat(voice): Safari support — software resampler for WebAudioBridge AudioContext #233

@mmogr

Description

@mmogr

WebAudioBridge.isSupported() returns false on Safari (non-Chromium) and voice
audio is blocked entirely. The reason is that Safari silently ignores the
sampleRate option passed to new AudioContext({ sampleRate }), instead using the
hardware native rate (44.1 kHz or 48 kHz). This causes:

  • Capture: mic audio arrives at the wrong sample rate → whisper STT
    transcription quality is severely degraded (input is pitched/stretched).
  • Playback: 24 kHz kokoro TTS PCM plays at the hardware rate →
    wrong speed and pitch.

The guard in WebAudioBridge.isSupported() and the validation throw in connect()
both detect this and prevent a broken mid-call experience, but the result is that
Safari users cannot use voice mode at all.

Goal

Add a software resampler AudioWorklet so the bridge operates correctly regardless
of the browser's hardware sample rate, enabling Safari support.

Proposed approach

Replace the hard UA-block with a runtime sample-rate check and inject resamplers
when needed:

  1. Capture path: if captureCtx.sampleRate !== 16_000, insert a resampling
    AudioWorklet node between the mic source and the CaptureProcessor. A
    polyphase or linear-interpolation resampler in pure JS (or a small WASM module)
    is sufficient for 16 kHz STT input.

  2. Playback path: if playbackCtx.sampleRate !== 24_000, resample the
    incoming 24 kHz PCM to the hardware rate before feeding the ring buffer.
    The resampler can run inside PlaybackProcessor or as a separate upstream
    node.

  3. Remove the Safari UA guard from isSupported() once both paths are covered.
    Keep the sampleRate mismatch throw in connect() as a last-resort fallback
    until validated across device/browser combinations.

Acceptance criteria

  • WebAudioBridge.isSupported() returns true on Safari (macOS/iOS).
  • Voice mode (PTT + TTS playback) works correctly on Safari 17+ (macOS) and
    Safari on iOS 17+.
  • No regression on Chrome/Firefox/Tauri.
  • cargo test --workspace and TypeScript build pass.

Affected files

  • src/services/transport/audio/WebAudioBridge.ts
  • src/services/transport/audio/index.ts (isAudioSupported comment)

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions