diff --git a/src/robot_interface/endpoints/actuation_receiver.py b/src/robot_interface/endpoints/actuation_receiver.py index 7fe16b7..b9435f6 100644 --- a/src/robot_interface/endpoints/actuation_receiver.py +++ b/src/robot_interface/endpoints/actuation_receiver.py @@ -21,6 +21,7 @@ class ActuationReceiver(ReceiverBase): self.create_socket(zmq_context, zmq.SUB, port) self.socket.setsockopt_string(zmq.SUBSCRIBE, u"") # Causes block if given in options self._tts_service = None + self._al_memory = None def _handle_speech(self, message): text = message.get("data") @@ -40,10 +41,26 @@ class ActuationReceiver(ReceiverBase): if not self._tts_service: self._tts_service = state.qi_session.service("ALTextToSpeech") + if not self._al_memory: + self._al_memory = state.qi_session.service("ALMemory") + + # Subscribe to speech end event + self.status_subscriber = self._al_memory.subscriber("ALTextToSpeech/Status") # self because garbage collect + self.status_subscriber.signal.connect(self._on_status_changed) # Returns instantly. Messages received while speaking will be queued. qi.async(self._tts_service.say, text) + @staticmethod + def _on_status_changed(value): # value will contain either 'enqueued', 'started' or 'done' depending on the status + """Callback function for when the speaking status changes. Will change the is_speaking value of the state.""" + if "started" in value: + logging.debug("Started speaking.") + state.is_speaking = True + if "done" in value: + logging.debug("Done speaking.") + state.is_speaking = False + def handle_message(self, message): if message["endpoint"] == "actuate/speech": self._handle_speech(message) diff --git a/src/robot_interface/endpoints/audio_sender.py b/src/robot_interface/endpoints/audio_sender.py index 5cd5a6b..822bd5c 100644 --- a/src/robot_interface/endpoints/audio_sender.py +++ b/src/robot_interface/endpoints/audio_sender.py @@ -57,6 +57,13 @@ class AudioSender(SocketBase): try: while not state.exit_event.is_set(): + # Don't send audio if Pepper is speaking + if state.is_speaking: + if stream.is_active(): stream.stop_stream() + continue + + if stream.is_stopped(): stream.start_stream() + data = stream.read(chunk) self.socket.send(data) except IOError as e: diff --git a/src/robot_interface/main.py b/src/robot_interface/main.py index 8874f7d..669cb82 100644 --- a/src/robot_interface/main.py +++ b/src/robot_interface/main.py @@ -43,8 +43,19 @@ def main_loop(context): logging.debug("Starting main loop.") + import schedule + test_speaking_message = {"data": "Hi, my name is Pepper, and this is quite a long message."} + def test_speak(): + logging.debug("Testing speech.") + actuation_receiver._handle_speech(test_speaking_message) + + schedule.every(10).seconds.do(test_speak) + while True: if state.exit_event.is_set(): break + + schedule.run_pending() + socks = dict(poller.poll(100)) for receiver in receivers: diff --git a/src/robot_interface/state.py b/src/robot_interface/state.py index b6f8ce1..d6e4610 100644 --- a/src/robot_interface/state.py +++ b/src/robot_interface/state.py @@ -18,6 +18,7 @@ class State(object): self.exit_event = None self.sockets = [] # type: List[SocketBase] self.qi_session = None # type: None | ssl.SSLSession + self.is_speaking = False # type: Boolean def initialize(self): if self.is_initialized: