2021-03-04 13:57:30 +00:00
|
|
|
__filename__ = "speaker_client.py"
|
|
|
|
__author__ = "Bob Mottram"
|
|
|
|
__license__ = "AGPL3+"
|
|
|
|
__version__ = "1.2.0"
|
|
|
|
__maintainer__ = "Bob Mottram"
|
|
|
|
__email__ = "bob@freedombone.net"
|
|
|
|
__status__ = "Production"
|
|
|
|
|
|
|
|
import os
|
|
|
|
import html
|
|
|
|
import time
|
|
|
|
from session import createSession
|
|
|
|
from speaker import getSpeakerFromServer
|
|
|
|
from speaker import getSpeakerPitch
|
|
|
|
from speaker import getSpeakerRate
|
|
|
|
from speaker import getSpeakerRange
|
2021-03-04 14:36:24 +00:00
|
|
|
import signal
|
|
|
|
|
|
|
|
|
|
|
|
def _waitForKeypress(timeout: int, debug: bool) -> str:
|
|
|
|
"""Waits for a keypress with a timeout
|
|
|
|
Returns the key pressed, or None on timeout
|
|
|
|
"""
|
|
|
|
def _nothing(sig, frame): pass
|
|
|
|
signal.signal(signal.SIGALRM, _nothing)
|
|
|
|
signal.alarm(timeout)
|
|
|
|
keyPress = None
|
|
|
|
try:
|
|
|
|
keyPress = input()
|
|
|
|
signal.alarm(0)
|
|
|
|
except (IOError, EOFError):
|
|
|
|
if debug:
|
|
|
|
print('Keypress Timeout')
|
|
|
|
return None
|
2021-03-04 14:37:48 +00:00
|
|
|
return keyPress
|
2021-03-04 13:57:30 +00:00
|
|
|
|
|
|
|
|
2021-03-04 14:54:30 +00:00
|
|
|
def _speakerEspeak(espeak, pitch: int, rate: int, srange: int,
|
|
|
|
sayText: str) -> None:
|
|
|
|
"""Speaks the given text with espeak
|
|
|
|
"""
|
|
|
|
espeak.set_parameter(espeak.Parameter.Pitch, pitch)
|
|
|
|
espeak.set_parameter(espeak.Parameter.Rate, rate)
|
|
|
|
espeak.set_parameter(espeak.Parameter.Range, srange)
|
|
|
|
espeak.synth(html.unescape(sayText))
|
|
|
|
|
|
|
|
|
|
|
|
def _speakerPicospeaker(pitch: int, rate: int, systemLanguage: str,
|
|
|
|
sayText: str) -> None:
|
|
|
|
speakerLang = 'en-GB'
|
|
|
|
if systemLanguage:
|
|
|
|
if systemLanguage.startswith('fr'):
|
|
|
|
speakerLang = 'fr-FR'
|
|
|
|
elif systemLanguage.startswith('es'):
|
|
|
|
speakerLang = 'es-ES'
|
|
|
|
elif systemLanguage.startswith('de'):
|
|
|
|
speakerLang = 'de-DE'
|
|
|
|
elif systemLanguage.startswith('it'):
|
|
|
|
speakerLang = 'it-IT'
|
|
|
|
speakerCmd = 'picospeaker ' + \
|
|
|
|
'-l ' + speakerLang + \
|
|
|
|
' -r ' + str(rate) + \
|
|
|
|
' -p ' + str(pitch) + ' "' + \
|
|
|
|
html.unescape(sayText) + '"'
|
|
|
|
# print(speakerCmd)
|
|
|
|
os.system(speakerCmd)
|
|
|
|
|
|
|
|
|
2021-03-04 13:59:39 +00:00
|
|
|
def runSpeakerClient(baseDir: str, proxyType: str, httpPrefix: str,
|
2021-03-04 13:57:30 +00:00
|
|
|
nickname: str, domain: str, port: int, password: str,
|
|
|
|
screenreader: str, systemLanguage: str,
|
|
|
|
debug: bool) -> None:
|
|
|
|
"""Runs the screen reader client, which announces new inbox items via TTS
|
|
|
|
"""
|
|
|
|
if screenreader == 'espeak':
|
|
|
|
print('Setting up espeak')
|
|
|
|
from espeak import espeak
|
|
|
|
elif screenreader != 'picospeaker':
|
|
|
|
print(screenreader + ' is not a supported TTS system')
|
|
|
|
return
|
|
|
|
|
|
|
|
print('Running ' + screenreader + ' for ' + nickname + '@' + domain)
|
|
|
|
|
|
|
|
prevSay = ''
|
|
|
|
while (1):
|
|
|
|
session = createSession(proxyType)
|
|
|
|
speakerJson = \
|
|
|
|
getSpeakerFromServer(baseDir, session, nickname, password,
|
|
|
|
domain, port, httpPrefix, True, __version__)
|
|
|
|
if speakerJson:
|
|
|
|
if speakerJson['say'] != prevSay:
|
|
|
|
if speakerJson.get('name'):
|
|
|
|
nameStr = speakerJson['name']
|
|
|
|
gender = 'They/Them'
|
|
|
|
if speakerJson.get('gender'):
|
|
|
|
gender = speakerJson['gender']
|
|
|
|
|
|
|
|
# get the speech parameters
|
|
|
|
pitch = getSpeakerPitch(nameStr, screenreader, gender)
|
|
|
|
rate = getSpeakerRate(nameStr, screenreader)
|
|
|
|
srange = getSpeakerRange(nameStr)
|
|
|
|
|
|
|
|
# say the speaker's name
|
|
|
|
if screenreader == 'espeak':
|
2021-03-04 14:54:30 +00:00
|
|
|
_speakerEspeak(espeak, pitch, rate, srange, nameStr)
|
2021-03-04 13:57:30 +00:00
|
|
|
elif screenreader == 'picospeaker':
|
2021-03-04 14:54:30 +00:00
|
|
|
_speakerPicospeaker(pitch, rate,
|
|
|
|
systemLanguage, nameStr)
|
2021-03-04 13:57:30 +00:00
|
|
|
time.sleep(2)
|
|
|
|
|
|
|
|
# append image description if needed
|
|
|
|
if not speakerJson.get('imageDescription'):
|
|
|
|
sayStr = speakerJson['say']
|
|
|
|
# echo spoken text to the screen
|
|
|
|
print(html.unescape(nameStr) + ': ' +
|
|
|
|
html.unescape(speakerJson['say']) + '\n')
|
|
|
|
else:
|
|
|
|
sayStr = speakerJson['say'] + '. ' + \
|
|
|
|
speakerJson['imageDescription']
|
|
|
|
# echo spoken text to the screen
|
|
|
|
print(html.unescape(nameStr) + ': ' +
|
|
|
|
html.unescape(speakerJson['say']) + '\n' +
|
|
|
|
html.unescape(speakerJson['imageDescription']))
|
|
|
|
|
|
|
|
# speak the post content
|
|
|
|
if screenreader == 'espeak':
|
2021-03-04 14:54:30 +00:00
|
|
|
_speakerEspeak(espeak, pitch, rate, srange, sayStr)
|
2021-03-04 13:57:30 +00:00
|
|
|
elif screenreader == 'picospeaker':
|
2021-03-04 14:54:30 +00:00
|
|
|
_speakerPicospeaker(pitch, rate,
|
|
|
|
systemLanguage, sayStr)
|
2021-03-04 13:57:30 +00:00
|
|
|
|
|
|
|
prevSay = speakerJson['say']
|
|
|
|
|
|
|
|
# wait for a while, or until a key is pressed
|
2021-03-04 14:36:24 +00:00
|
|
|
if _waitForKeypress(30, debug):
|
2021-03-04 13:57:30 +00:00
|
|
|
break
|