[Bug 59749] New: sapi: ISpVoice::SetPriority and GetStatus return E_NOTIMPL, breaking Overwatch 2 Audio Captions (and likely any SAPI app that polls status or checks SetPriority's HRESULT)
http://bugs.winehq.org/show_bug.cgi?id=59749 Bug ID: 59749 Summary: sapi: ISpVoice::SetPriority and GetStatus return E_NOTIMPL, breaking Overwatch 2 Audio Captions (and likely any SAPI app that polls status or checks SetPriority's HRESULT) Product: Wine Version: 11.8 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: sapi Assignee: wine-bugs@list.winehq.org Reporter: bohdan@tkachenko.dev Distribution: --- dlls/sapi/tts.c has three ISpVoice methods still stubbed out with FIXME(...stub...); return E_NOTIMPL; - spvoice_SetPriority (line 1231) - spvoice_GetPriority (line 1238) - spvoice_GetStatus (line 1212) SetPriority and GetStatus are both on the hot path for Overwatch 2's "Audio Captions" accessibility TTS feature (Steam AppID 2357570, runs under Proton - which ships unmodified upstream Wine SAPI). They cause two distinct failure modes: 1. During voice setup, OW2 calls ISpVoice::SetPriority(SPVPRI_NORMAL) and checks the HRESULT. E_NOTIMPL makes it abort TTS init entirely - PLAY SAMPLE produces silence and the in-game UI gives no error. 2. If SetPriority is forced to return S_OK (verified by binary-patching the stub), the engine successfully synthesizes the first sample. The game then calls ISpVoice::Speak(text, SPF_ASYNC, ...) and tight-polls ISpVoice::GetStatus waiting for SPVOICESTATUS.dwRunningState == SPRS_DONE. Stock GetStatus returns E_NOTIMPL and writes nothing into the status struct, so the game polls forever and subsequent PLAY SAMPLE clicks silently do nothing. Other SAPI apps that use Speak(SPF_DEFAULT) or Speak(SPF_ASYNC) + WaitUntilDone(INFINITE) never hit these methods and work fine on stock Wine, which is why this hasn't been reported before despite the stubs being old. OW2's accessibility code is unusually defensive. Steps to reproduce ================== 1. Install Wine 11.8+ (or any current Proton - same upstream code: ValveSoftware/wine branch proton_11.0 dlls/sapi/tts.c is byte-identical to wine-mirror/wine master, MD5 verified). 2. Install Overwatch 2 (free-to-play, Steam AppID 2357570) - or any SAPI app that checks SetPriority's HRESULT. 3. In game settings -> Accessibility, enable Audio Captions and select a Proton voice (e.g. "Proton Voice - English (United States) - LIBRITTS-R 14"). 4. Click PLAY SAMPLE. Actual: silence; in-game UI gives no error. With WINEDEBUG=+sapi: spvoice_SetVoice -> picks ProtonTTS_libritts-r_3 spvoice_SetOutput(NULL) -> default audio out spvoice_SetRate(3) -> S_OK spvoice_SetVolume(100) -> S_OK spvoice_SetPriority(0) -> STUB -> E_NOTIMPL [BUG #1] spvoice_Release -> game gives up here After binary-patching SetPriority to return S_OK: spvoice_Speak(text, SPF_ASYNC=1) -> audio plays once loop: spvoice_GetStatus(&status, NULL) -> STUB -> E_NOTIMPL, status untouched ... [BUG #2 - tight poll forever] Expected: PLAY SAMPLE plays the voice sample, and the button works again on every subsequent click. Workaround: binary-patch the two E_NOTIMPLs, or use a locally-built Wine with the patches below. Fix === A patch is being prepared for wine-devel implementing all three methods plus tests. Sketch: - SetPriority/GetPriority: store value on struct speech_voice, validate against SPVPRI_NORMAL/ALERT/OVER. - GetStatus: populate SPVOICESTATUS from cur_stream_num (last queued), a new last_stream_num/last_hr updated in speak_proc, and async_wait_queue_empty(&queue, 0) for dwRunningState. Patch verified against Wine's existing dlls/sapi/tests/ suite (new tests added) and end-to-end in OW2: both PLAY SAMPLE clicks play correctly with no wedge. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
participants (1)
-
WineHQ Bugzilla