Closed Bug 2043577 Opened 4 months ago Closed 4 months ago

macOS voice list incomplete and no default voice for many users; migrate to AVSpeechSynthesizer

Categories

(Core :: Web Speech, defect)

defect

Tracking

()

RESOLVED DUPLICATE of bug 2058219

People

(Reporter: tjr, Unassigned)

References

Details

Summary

Firefox-on-macOS exposes the operating system's installed speech voices to web content via speechSynthesis.getVoices(). Today, that exposed list is incomplete (14 voices are not reported), and for a large fraction of macOS 15+ users no voice in the list is marked as the user's system-chosen default. Both behaviors share a root cause and a single fix: migrating to Apple's current speech-synthesis API.

Current misbehaviors

Population A: every Firefox-on-macOS user

The voice list Firefox exposes is missing 14 installed voices. The user cannot select these voices from JavaScript even though they are present in macOS and visible in System Settings → Accessibility → Spoken Content. On a representative macOS 15.7.7 machine the exposed list contains 177 voices, while macOS itself has 191 installed and selectable. The 14 absent voices are the "Siri-class" voices — Nicky, Aaron, Martha, Gordon, Daniel, Helena, Martin, Hattori, O-Ren, Yu-shu, Catherine, Arthur, Marie, Limu, etc.

This applies to every Firefox-on-macOS user, regardless of macOS version (the precise count and identity of Siri voices depends on macOS major version, but the absence pattern is the same).

Population B: macOS 15 (Sequoia) and later users whose system default is a Siri voice

For these users, no voice in speechSynthesis.getVoices() has .default === true. Code such as voices.find(v => v.default) returns undefined. Pages that rely on the default-voice mark — for example, to highlight it in a voice picker, or to choose it when an utterance does not specify a voice — get behavior they're not expecting (no highlight, or the page's own fallback voice).

This affects the majority of macOS 15+ users. Many fresh macOS 15 and macOS 26 installs select a Siri voice as the System Voice by default during initial setup. Users who don't go into System Settings to change it remain in this state.

Proposed fix: migrate to AVSpeechSynthesizer

Apple's current speech-synthesis API is AVSpeechSynthesizer (with AVSpeechSynthesisVoice for the voice list). Switching the Firefox-on-macOS speech path to this API addresses:

  • Population A completely. AVSpeechSynthesizer enumerates the Siri voices. They appear in getVoices() and become selectable from JavaScript.
  • Population B almost completely. With Siri voices in the enumerated list, when a Siri voice is the user's system default, the default-voice resolution succeeds and the correct voice is marked default — provided we can resolve "what is the user's chosen default" under the new API. That's the open design question; see the next section.

The change is additive from the web-content perspective. The two APIs return the same identifier string for every voice that is currently exposed (verified for all 177 currently-visible voices on Sequoia). No voiceURI Firefox already gives to the web changes value; 14 new voices appear. Pages that have persisted a user's chosen voice URI continue to work.

One open question: how to identify the user's default voice

AVSpeechSynthesizer does not provide a direct equivalent of the legacy defaultVoice API. There is AVSpeechSynthesisVoice(language:), but Apple's developer forums (radar FB9225882) document that it returns the wrong voice in many cases — for instance, returning "Albert" for users whose actually-chosen default is "Kate" or "Samantha". So a pure-AV approach has to choose how to surface the user's default.

Note: AI reported finding this bug, but I don't know how accurate or widespread it is. Worth more investigation.

Four options:

  1. Keep one legacy-API call just for the default-voice lookup. The deprecated [NSSpeechSynthesizer defaultVoice] reliably returns the identifier of the voice the user selected in System Settings (including Siri-class identifiers). Apple has not deleted this API — it is marked deprecated but remains functional. Once voices are enumerated via the new API (so Siri voices are present in the list), the identifier from defaultVoice matches an entry in the list and the default mark resolves correctly for all populations. Trade-off: a one-line dependency on a deprecated API in otherwise-modern code.

  2. Use AVSpeechSynthesisVoice(language:) against the system's preferred speech language. Pure AV, no deprecated calls. Trade-off: Apple's known bug — the returned voice frequently does not match the user's explicit choice. The displayed default would often be wrong.

  3. Use the system's preferred speech language and pick our own default voice within it. Read [AVSpeechSynthesisVoice currentLanguageCode] for the preferred language, then pick a voice (e.g., the first compact-quality match) from the enumerated list. Pure AV, deterministic. Trade-off: the user's specific System Settings choice is lost — if they explicitly chose one voice in their preferred language, Firefox may select a different one.

  4. Don't mark any voice as default. Simplest, but a regression from current behavior for Population C and leaves Population B in the same state they're in today. Web content can never determine the user's preferred voice. Not recommended; included only for completeness.

The recommended choice is Option 1: the dependency on a deprecated API is a single string read; the authoritativeness of the result is worth far more than the maintenance cost. Option 3 is the cleanest pure-AV alternative if a hard preference against deprecated APIs is in play, with the explicit "user's specific choice is lost" trade-off. Options 2 and 4 are not viable.

Other relevant information about AVSpeechSynthesizer

  • Availability. Introduced on macOS 10.14 (Mojave). Firefox's current minimum supported macOS version is 10.15 (Catalina), so AVSpeechSynthesizer is available on every macOS version Firefox runs on. No @available checks needed, no fallback code path needed, no compat shim needed.
  • Maintenance status. Apple's currently-supported speech-synthesis API. NSSpeechSynthesizer is marked deprecated and is functionally frozen — Apple has put their TTS investment (Siri voices, neural Personal Voice, etc.) into AVSpeechSynthesizer, and the feature gap between the two APIs is likely to widen over time. Each new macOS release adds more voices to the AV-only side.
  • Feature parity with current usage. AVSpeechSynthesizer supports speak / pause / resume / cancel, word-boundary callbacks, per-utterance volume / rate / pitch, error callbacks, and finish callbacks — every facility the existing Firefox code uses against NSSpeechSynthesizer. There is no functionality Firefox would lose in the migration.
  • Scope. This is not a small patch. The macOS speech path is non-trivial and is rewritten in full against the new API. The change is well-localized to one file (dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm) and adds no new build dependencies; AVFoundation is already linked into Firefox-on-macOS for other reasons.
See Also: → 2043645

The severity field is not set for this bug.
:padenot, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(padenot)

We're likely not going to use the OS facility here because we aim at shipping something on all platforms.

Status: NEW → RESOLVED
Closed: 4 months ago
Flags: needinfo?(padenot)
Resolution: --- → WONTFIX

I think this got fixed in Bug 2058219

Duplicate of bug: 2058219
Resolution: WONTFIX → DUPLICATE
You need to log in before you can comment on or make changes to this bug.