From ab60d7a1cf04a7cd499dcbf35985eb4965ff7bc2 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Wed, 13 Nov 2019 11:19:21 +0100 Subject: [PATCH] Change playback code to not buffer --- hugvey/client.py | 135 +++++++++++++++++++++++++++-------------------- hugvey_client.py | 1 + 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/hugvey/client.py b/hugvey/client.py index f1abd85..7c850b6 100644 --- a/hugvey/client.py +++ b/hugvey/client.py @@ -14,6 +14,8 @@ from hugvey.communication import LOG_BS import os import collections import math +import urllib.request +import io try: import alsaaudio @@ -258,29 +260,34 @@ class CommandHandler(object): # self.showMyself() # queue message for connection request def handle(self, cmd): - print('handle', cmd) - # self.sendMessage({'reply':'test'}) - if not 'action' in cmd: - logger.critical("Invalid command: {}".format(cmd)) - return - - logger.info("Received {}".format(cmd)) - - if cmd['action'] == 'show_yourself': - self.showMyself() - if cmd['action'] == 'prepare': - self.muteMic = True - if cmd['action'] == 'play': - self.cmdPlay(cmd) - if cmd['action'] == 'stop': - self.cmdStop(cmd['id']) + try: + + print('handle', cmd) + # self.sendMessage({'reply':'test'}) + if not 'action' in cmd: + logger.critical("Invalid command: {}".format(cmd)) + return + + logger.info("Received {}".format(cmd)) + + if cmd['action'] == 'show_yourself': + self.showMyself() + if cmd['action'] == 'prepare': + self.muteMic = True + if cmd['action'] == 'play': + 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): self.muteMic = True msgId = cmd['id'] 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 params = cmd['params'] if 'params' in cmd else {} # use duration for timing the popen duration (and redo it if needed) @@ -292,49 +299,63 @@ class CommandHandler(object): self.playPopen.kill() 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)) else: - if file is not None: - logger.info("Play: {}".format(file)) - file = self.file_address + "/" + file -# logger.debug(['play', file]) - playCmd = ['play', file] + if filepath is not None: + file = self.file_address + "/" + filepath + logger.debug("Fetch to play: {}".format(filepath)) + start = time.time() + #: 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(): - 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 - - logger.debug(playCmd) - - t = None - if duration is not None: - t = threading.Timer(duration+3, self.checkPopen, (msgId,duration+3)) - t.start() - - self.playPopen = subprocess.Popen( - playCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=environment_vars) - self.sendMessage({ - 'event': 'playbackStart', - '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: - t.cancel() + # logger.debug(['play', file]) + playCmd = ['play', '-'] + + 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 + + logger.debug(playCmd) + + t = None + if duration is not None: + t = threading.Timer(duration+3, self.checkPopen, (msgId,duration+3)) + t.start() + + self.playPopen = subprocess.Popen( + 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: logger.info("Speak: {}".format(text)) diff --git a/hugvey_client.py b/hugvey_client.py index ead8c63..02ee298 100644 --- a/hugvey_client.py +++ b/hugvey_client.py @@ -48,6 +48,7 @@ if __name__ == '__main__': host = urlparse(hv.config['events']['cmd_address']).hostname logger.info("Connect to logger on {}".format(host)) socket_handler = logging.handlers.SocketHandler(host, 19996) # default listening address +# socket_handler.setLevel(logging.DEBUG) # always debug logger.addHandler(socket_handler); hv.start()