- CallEmbed watchdog now SELF-HEALS: a genuine ready/joined signal arriving
after the 25s timeout clears the error and notifies subscribers with
undefined, so a slow-but-successful EC load no longer strands the user on
the recovery screen over a live call. Listener dispatch wrapped in try/catch.
- ringtones: synth notes route through a per-session master gain; stop() ramps
it to 0 so the ring is silenced instantly on answer instead of letting the
last scheduled phrase ring out over call audio.
- IncomingCallBanner: ping fires exactly once per incoming call (guarded by
refEventId) instead of re-pinging when ringtone settings change mid-banner.
- focusCameraParticipant: try multiple tile selectors (EC labels vary by
version), defer the tile click past EC's async spotlight layout switch
(rAF x2), and dev-warn when no tile matches so testers get signal.
- uploadContent: a cancelled upload (mx.cancelUpload -> AbortError) is no
longer treated as retryable — previously the retry loop could resurrect an
upload the user just cancelled. Also retry on 408.
- addRoomIdToMDirect/removeRoomIdFromMDirect: guard against a corrupt m.direct
whose values aren't arrays.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a ringtoneId setting (classic | chime | soft | retro | none) so the
incoming-call ring is no longer hardcoded to call.ogg. The three synth
styles are generated in-browser via a new utils/ringtones.ts module
(mirroring the existing callSounds.ts WebAudio pattern), so no new binary
assets are bundled; 'classic' keeps the existing call.ogg clip and 'none'
is a silent, visual-only incoming-call UI.
- ringtones.ts: startRingtone() loops until stopped; previewRingtone()
plays a single non-looping preview and auto-cancels the prior preview.
- IncomingCall: ring driven by the setting; <audio> element removed.
- Settings > Calls: Ringtone selector with on-select preview, beside the
existing Ringtone Volume slider.
- settings.ts: persisted value whitelisted back to a known id.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>