Change playback code to not buffer

This commit is contained in:
Ruben van de Ven 2019-11-13 11:19:21 +01:00
parent 76ad34be99
commit ab60d7a1cf
2 changed files with 79 additions and 57 deletions

View file

@ -14,6 +14,8 @@ from hugvey.communication import LOG_BS
import os import os
import collections import collections
import math import math
import urllib.request
import io
try: try:
import alsaaudio import alsaaudio
@ -258,29 +260,34 @@ class CommandHandler(object):
# self.showMyself() # queue message for connection request # self.showMyself() # queue message for connection request
def handle(self, cmd): def handle(self, cmd):
print('handle', cmd) try:
# self.sendMessage({'reply':'test'})
if not 'action' in cmd:
logger.critical("Invalid command: {}".format(cmd))
return
logger.info("Received {}".format(cmd)) print('handle', cmd)
# self.sendMessage({'reply':'test'})
if not 'action' in cmd:
logger.critical("Invalid command: {}".format(cmd))
return
if cmd['action'] == 'show_yourself': logger.info("Received {}".format(cmd))
self.showMyself()
if cmd['action'] == 'prepare': if cmd['action'] == 'show_yourself':
self.muteMic = True self.showMyself()
if cmd['action'] == 'play': if cmd['action'] == 'prepare':
self.cmdPlay(cmd) self.muteMic = True
if cmd['action'] == 'stop': if cmd['action'] == 'play':
self.cmdStop(cmd['id']) self.cmdPlay(cmd)
if cmd['action'] == 'stop':
self.cmdStop(cmd['id'])
except Exception as e:
logger.critical("Exception during handling command: {}".format(cmd))
logger.exception(e)
def cmdPlay(self, cmd): def cmdPlay(self, cmd):
self.muteMic = True self.muteMic = True
msgId = cmd['id'] msgId = cmd['id']
pitch = cmd['pitch'] if 'pitch' in cmd else 50 pitch = cmd['pitch'] if 'pitch' in cmd else 50
file = cmd['file'] if 'file' in cmd else None filepath = cmd['file'] if 'file' in cmd else None
text = cmd['msg'] if 'msg' in cmd else None text = cmd['msg'] if 'msg' in cmd else None
params = cmd['params'] if 'params' in cmd else {} params = cmd['params'] if 'params' in cmd else {}
# use duration for timing the popen duration (and redo it if needed) # use duration for timing the popen duration (and redo it if needed)
@ -292,49 +299,63 @@ class CommandHandler(object):
self.playPopen.kill() self.playPopen.kill()
err = None err = None
if file is None and text is None: if filepath is None and text is None:
logger.critical("No file nor text given: {}".format(cmd)) logger.critical("No file nor text given: {}".format(cmd))
else: else:
if file is not None: if filepath is not None:
logger.info("Play: {}".format(file)) file = self.file_address + "/" + filepath
file = self.file_address + "/" + file logger.debug("Fetch to play: {}".format(filepath))
# logger.debug(['play', file]) start = time.time()
playCmd = ['play', file] #: var response: http.client.HTTPResponse
response = urllib.request.urlopen(file, timeout=4)
fetchend = time.time()
logger.info("Fetched {} in {}s".format(file, fetchend-start))
if fetchend-start > 1:
logger.warning("Super slow fetching of {} in {}s".format(file, fetchend-start))
if response.getcode() != 200:
logger.critical("Error fetching: {} - {}".format(file, response))
else:
audioFile = io.BytesIO(response.read())
logger.info("Play: {}".format(filepath))
for param, value in params.items(): # logger.debug(['play', file])
if not value: playCmd = ['play', '-']
continue
playCmd.append(param)
print(param, value)
if value is True:
continue
playCmd.append(str(value))
environment_vars = dict(os.environ)
if self.play_audiodriver is not None:
environment_vars['AUDIODRIVER'] = self.play_audiodriver
elif self.play_audiodev is not None:
environment_vars['AUDIODEV'] = self.play_audiodev
logger.debug(playCmd) for param, value in params.items():
if not value:
continue
playCmd.append(param)
print(param, value)
if value is True:
continue
playCmd.append(str(value))
environment_vars = dict(os.environ)
if self.play_audiodriver is not None:
environment_vars['AUDIODRIVER'] = self.play_audiodriver
elif self.play_audiodev is not None:
environment_vars['AUDIODEV'] = self.play_audiodev
t = None logger.debug(playCmd)
if duration is not None:
t = threading.Timer(duration+3, self.checkPopen, (msgId,duration+3))
t.start()
self.playPopen = subprocess.Popen( t = None
playCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=environment_vars) if duration is not None:
self.sendMessage({ t = threading.Timer(duration+3, self.checkPopen, (msgId,duration+3))
'event': 'playbackStart', t.start()
'msgId': msgId
})
out, err = self.playPopen.communicate()
returnCode = self.playPopen.returncode if self.playPopen else 0
logger.debug('finished')
self.playPopen = None
if t is not None: self.playPopen = subprocess.Popen(
t.cancel() playCmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=environment_vars)
self.sendMessage({
'event': 'playbackStart',
'msgId': msgId
})
out, err = self.playPopen.communicate(input=audioFile.getvalue())
playend = time.time()
returnCode = self.playPopen.returncode if self.playPopen else 0
logger.info('finished playing {} in {:.4f}s (duration: {}s)'.format(filepath, playend-fetchend, duration))
self.playPopen = None
if t is not None:
t.cancel()
else: else:
logger.info("Speak: {}".format(text)) logger.info("Speak: {}".format(text))

View file

@ -48,6 +48,7 @@ if __name__ == '__main__':
host = urlparse(hv.config['events']['cmd_address']).hostname host = urlparse(hv.config['events']['cmd_address']).hostname
logger.info("Connect to logger on {}".format(host)) logger.info("Connect to logger on {}".format(host))
socket_handler = logging.handlers.SocketHandler(host, 19996) # default listening address socket_handler = logging.handlers.SocketHandler(host, 19996) # default listening address
# socket_handler.setLevel(logging.DEBUG) # always debug
logger.addHandler(socket_handler); logger.addHandler(socket_handler);
hv.start() hv.start()