diff --git a/hugvey/client.py b/hugvey/client.py index f96f16e..2437fd7 100644 --- a/hugvey/client.py +++ b/hugvey/client.py @@ -38,7 +38,7 @@ class VoiceServer(object): def __init__(self, loop, hugvey, config): self.config = config - + self.input_rate = self.config['voice']['input_rate'] self.target_rate = self.config['voice']['target_rate'] self.stopped = True @@ -47,28 +47,28 @@ class VoiceServer(object): self.ctx = Context.instance() self.loop = loop self.hugvey = hugvey - + self.chunk = 4096 self.mic_prerol_sec = .2 self.prerol_frame_count = math.ceil((self.input_rate / self.chunk) * self.mic_prerol_sec) self.prerol_frames = collections.deque(maxlen = self.prerol_frame_count) - + self.p = pyaudio.PyAudio() # wait a sec for the input devices to come up logger.debug("Use a mic prerol of {} frames".format(self.prerol_frame_count)) logger.debug('wait for mic') time.sleep(3) logger.debug('done waiting for mic') - - + + self.info = self.get_card_info() - - - + + + def get_card_info(self): output_device_idx = None input_device_idx = None - + devices_count = self.p.get_device_count() for i in range(devices_count): dev = self.p.get_device_info_by_index(i) @@ -88,13 +88,13 @@ class VoiceServer(object): "< " if output_device_idx == i else "> " if input_device_idx == i else "- ", i, dev['name'], dev['maxInputChannels'], dev['maxOutputChannels'])) - + # Don't continue without pyAudio indexes if input_device_idx is None: raise Exception("Input device is not found: {}".format(self.config['voice']['input_name'])) if output_device_idx is None: raise Exception("Output device is not found: {}".format(self.config['voice']['output_name'])) - + try: # get eg: "hw:1,0" or "hw:0,3" -> used by Sox' play output_device_name = self.p.get_device_info_by_index(output_device_idx)['name'].split("(",1)[1][:-1] @@ -109,28 +109,28 @@ class VoiceServer(object): except IndexError as e: input_device_name = None input_card_name = None - + logger.debug("Output: {}, Input: {}".format(output_device_name, input_device_name)) - - + + return { 'input': { 'idx': input_device_idx, 'device': input_device_name, - 'card': input_card_name + 'card': input_card_name }, 'output': { 'idx': output_device_idx, 'device': output_device_name, - 'card': output_card_name + 'card': output_card_name } } - - -# + + +# # def get_output_idxs(self): # pass -# +# # def get_input_idx(self): # input_device_idx = None # # input_device_idx = 6 @@ -159,14 +159,14 @@ class VoiceServer(object): try: if self.hugvey.cmd_server.muteMic: - logger.log(LOG_BS, 'block recording {}' .format( - self.hugvey.cmd_server.muteMic)) - + # logger.log(LOG_BS, 'block recording {}' .format( + # self.hugvey.cmd_server.muteMic)) + # multiply by 0 to disable audio recording while playback f = audioop.mul(f, 2, 0) - - self.loop.call_soon_threadsafe(self.voice_socket.send, f) + + self.loop.call_soon_threadsafe(self.voice_socket.send, f) except Exception as e: logger.warn("Error sending to {}".format(e)) pass @@ -177,10 +177,10 @@ class VoiceServer(object): CHANNELS = 1 CHUNK = 4096 - + self.stopped = False - - + + if 'alsaaudio' in sys.modules: if self.config['voice']['input_mixer'] and self.config['voice']['input_volume'] and self.info['input']['card']: logger.info("Set input volume on {}/{} to {}".format( @@ -190,7 +190,7 @@ class VoiceServer(object): )) alsaaudio.Mixer(self.config['voice']['input_mixer'], device=self.info['input']['card']).setvolume( self.config['voice']['input_volume']) - + if self.config['voice']['output_mixer'] and self.config['voice']['output_volume'] and self.info['output']['card']: logger.info("Set output volume on {}/{} to {}".format( self.config['voice']['output_mixer'], @@ -214,6 +214,7 @@ class VoiceServer(object): try: address = "tcp://*:{}".format(self.config['voice']['port'] + self.hugvey.id) self.voice_socket = self.ctx.socket(zmq.PUB) + self.voice_socket.set_hwm(100) self.voice_socket.bind(address) logger.info( @@ -263,7 +264,7 @@ class CommandHandler(object): return logger.info("Received {}".format(cmd)) - + if cmd['action'] == 'show_yourself': self.showMyself() if cmd['action'] == 'prepare': @@ -275,7 +276,7 @@ class CommandHandler(object): 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 @@ -284,7 +285,7 @@ class CommandHandler(object): # use duration for timing the popen duration (and redo it if needed) duration = cmd['duration'] if 'duration' in cmd else None self.playingMsgId = msgId - + if self.playPopen: logger.info("Interrupting playback of {}".format(self.playingMsgId)) self.playPopen.terminate() @@ -298,7 +299,7 @@ class CommandHandler(object): file = self.file_address + "/" + file # logger.debug(['play', file]) playCmd = ['play', file] - + for param, value in params.items(): if not value: continue @@ -312,9 +313,9 @@ class CommandHandler(object): 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,)) @@ -330,10 +331,10 @@ class CommandHandler(object): returnCode = self.playPopen.returncode if self.playPopen else 0 logger.debug('finished') self.playPopen = None - + if t is not None: t.cancel() - + else: logger.info("Speak: {}".format(text)) playCmd = ['espeak', '-p', '{0}'.format(pitch), text] @@ -354,14 +355,14 @@ class CommandHandler(object): 'event': 'playbackFinish', 'msgId': msgId }) - + def checkPopen(self, msgId): if self.playingMsgId != msgId: return - + if self.playPopen is None: return - + # prevent a lock of the story, no repeat or anything for now logger.critical("Interrupting playback after timeout") self.playPopen.terminate() @@ -430,7 +431,7 @@ class CommandHandler(object): await asyncio.sleep(0.05) s.close() - + async def heartbeat(self): while True: self.showMyself() @@ -466,15 +467,15 @@ class Hugvey(object): def start(self): logger.debug('Hugvey {}, reporting'.format(self.id)) - + self.loop = asyncio.get_event_loop() - + self.voice_server = VoiceServer( loop=self.loop, hugvey=self, config=self.config ) - + self.cmd_server = CommandHandler( hugvey_id=self.id, cmd_address=self.config['events']['cmd_address'], @@ -483,7 +484,7 @@ class Hugvey(object): play_audiodev=self.voice_server.info['output']['device'], play_audiodriver=self.config['voice']['output_driver'] if 'output_driver' in self.config['voice'] else None, ) - + logger.info('start') # self.voice_server.asyncStart(loop) # loop.run_until_complete(self.voice_server.start())