Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 38 additions & 13 deletions source/synthDrivers/sapi5.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

from ctypes import POINTER, c_ubyte, c_wchar_p, cast, windll, _Pointer
from ctypes import POINTER, c_ubyte, c_ulong, c_wchar_p, cast, windll, _Pointer
from enum import IntEnum
import locale
from collections import OrderedDict
from typing import TYPE_CHECKING
from comInterfaces.SpeechLib import ISpEventSource, ISpNotifySource, ISpNotifySink
import comtypes.client
from comtypes import COMError, COMObject, IUnknown, hresult, ReturnHRESULT
from comtypes import COMError, COMObject, IUnknown, hresult
import winreg
import nvwave
from objidl import _LARGE_INTEGER, _ULARGE_INTEGER, IStream
Expand Down Expand Up @@ -50,8 +50,12 @@ class SpeechVoiceEvents(IntEnum):

if TYPE_CHECKING:
LP_c_ubyte = _Pointer[c_ubyte]
LP_c_ulong = _Pointer[c_ulong]
LP__ULARGE_INTEGER = _Pointer[_ULARGE_INTEGER]
else:
LP_c_ubyte = POINTER(c_ubyte)
LP_c_ulong = POINTER(c_ulong)
LP__ULARGE_INTEGER = POINTER(_ULARGE_INTEGER)


class SynthDriverAudioStream(COMObject):
Expand All @@ -68,36 +72,57 @@ def __init__(self, synthRef: weakref.ReferenceType):
self.synthRef = synthRef
self._writtenBytes = 0

def ISequentialStream_RemoteWrite(self, pv: LP_c_ubyte, cb: int) -> int:
def ISequentialStream_RemoteWrite(
self,
this: int,
pv: LP_c_ubyte,
cb: int,
pcbWritten: LP_c_ulong,
) -> int:
"""This is called when SAPI wants to write (output) a wave data chunk.
:param pv: A pointer to the first wave data byte.
:param cb: The number of bytes to write.
:returns: The number of bytes written.
:param pcbWritten: A pointer to a variable where the actual number of bytes written will be stored.
Can be null.
:returns: HRESULT code.
"""
synth = self.synthRef()
if pcbWritten:
pcbWritten[0] = 0
if synth is None:
log.debugWarning("Called Write method on AudioStream while driver is dead")
return 0
return hresult.E_UNEXPECTED
if not synth.isSpeaking:
return 0
return hresult.E_FAIL
synth.player.feed(pv, cb)
if pcbWritten:
pcbWritten[0] = cb
self._writtenBytes += cb
return cb

def IStream_RemoteSeek(self, dlibMove: _LARGE_INTEGER, dwOrigin: int) -> _ULARGE_INTEGER:
return hresult.S_OK

def IStream_RemoteSeek(
self,
this: int,
dlibMove: _LARGE_INTEGER,
dwOrigin: int,
plibNewPosition: LP__ULARGE_INTEGER,
) -> int:
"""This is called when SAPI wants to get the current stream position.
Seeking to another position is not supported.
:param dlibMove: The displacement to be added to the location indicated by the dwOrigin parameter.
Only 0 is supported.
:param dwOrigin: The origin for the displacement specified in dlibMove.
Only 1 (STREAM_SEEK_CUR) is supported.
:returns: The current stream position.
:param plibNewPosition: A pointer to a ULARGE_INTEGER where the current stream position will be stored.
Can be null.
:returns: HRESULT code.
"""
if dwOrigin == 1 and dlibMove.QuadPart == 0:
# SAPI is querying the current position.
return _ULARGE_INTEGER(self._writtenBytes)
# Return E_NOTIMPL without logging an error.
raise ReturnHRESULT(hresult.E_NOTIMPL, None)
if plibNewPosition:
plibNewPosition.QuadPart = self._writtenBytes
return hresult.S_OK
return hresult.E_NOTIMPL

def IStream_Commit(self, grfCommitFlags: int):
"""This is called when MSSP wants to flush the written data.
Expand Down