nateshmbhat / pyttsx3

Offline Text To Speech synthesis for python
Mozilla Public License 2.0
2.08k stars 327 forks source link

Voice is not played when running under Windows Task Scheduler #263

Open ran-peled opened 1 year ago

ran-peled commented 1 year ago

I have a script using pyttx3 working fine when run regularly. When run under Windows Task Scheduler, no voice is heard, although no errors are thrown. I also notice that engine.runAndWait() returns immediately, indicating it is not playing the voice (as opposed to playing but the voice is not heard).

I debugged and verified SAPI5Driver._tts is initialized with a proper system voice (in my case "Headphones (Realtek(R) Audio)").

Suspecting that Windows Scheduled Task might be blocking sound, I tested playing voice-to-text using Windows API from a task, which works fine. The command used was: powershell.exe -Command "Add-Type -AssemblyName System.Speech; $synthesizer = New-Object -TypeName System.Speech.Synthesis.SpeechSynthesizer; $synthesizer.Speak('Hello, world!')"

I would assume this is not directly a pyttsx3 issue, but some missing setting on the driver maybe. I hope you have some clue or advice.

Attaching the small script for reference:

import sys
import time
import pyttsx3

logging.basicConfig(stream=sys.stdout)
file_handler = logging.FileHandler('C:/temp/speak.log')
file_handler.setLevel(logging.DEBUG)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(file_handler)

class Speaker(object):

    def __init__(self) -> None:
        self.engine = pyttsx3.init(debug=True)
        self.voices = self.engine.getProperty('voices')
        self.rate = self.engine.getProperty('rate')
        self.voice_num = 0
        logger.info("current rate: {}".format(self.rate))

    def speak(self, text, rate_factor = 1.0):
        self.engine.setProperty('rate', self.rate * rate_factor)
        self.engine.setProperty('voice', self.voices[self.voice_num].id)
        self.engine.say(text)
        self.engine.runAndWait()

    def set_voice(self, num):
        self.voice_num = num
        logger.info("Voice {}: {}".format(num, str(self.voices[num])))

if __name__ == '__main__':

    speaker = Speaker()

    logger.info("{} voices, {}".format(len(speaker.voices), str(speaker.voices)))

    for rate in [0.8, 1.0, 1.2]:
        for i in range(len(speaker.voices)):
            speaker.set_voice(i)
            speaker.speak("This is a test", rate)
            time.sleep(0.2)
Jiangshan00001 commented 1 year ago

sorry, i have no idea