chore: add documentation RI
Code functionality left unchanged, only added docs where missing close: N25B-298
This commit is contained in:
@@ -10,22 +10,32 @@ from robot_interface.core.config import settings
|
||||
|
||||
|
||||
class ActuationReceiver(ReceiverBase):
|
||||
"""
|
||||
The actuation receiver endpoint, responsible for handling speech and gesture requests.
|
||||
|
||||
:param zmq_context: The ZeroMQ context to use.
|
||||
:type zmq_context: zmq.Context
|
||||
|
||||
:param port: The port to use.
|
||||
:type port: int
|
||||
|
||||
:ivar _tts_service: The text-to-speech service object from the Qi session.
|
||||
:vartype _tts_service: ssl.SSLSession | None
|
||||
"""
|
||||
def __init__(self, zmq_context, port=settings.agent_settings.actuating_receiver_port):
|
||||
"""
|
||||
The actuation receiver endpoint, responsible for handling speech and gesture requests.
|
||||
|
||||
:param zmq_context: The ZeroMQ context to use.
|
||||
:type zmq_context: zmq.Context
|
||||
|
||||
:param port: The port to use.
|
||||
:type port: int
|
||||
"""
|
||||
super(ActuationReceiver, self).__init__("actuation")
|
||||
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
|
||||
|
||||
def _handle_speech(self, message):
|
||||
"""
|
||||
Handle a speech actuation request.
|
||||
|
||||
:param message: The message to handle, must contain properties "endpoint" and "data".
|
||||
:type message: dict
|
||||
"""
|
||||
text = message.get("data")
|
||||
if not text:
|
||||
logging.warn("Received message to speak, but it lacks data.")
|
||||
@@ -48,5 +58,11 @@ class ActuationReceiver(ReceiverBase):
|
||||
qi.async(self._tts_service.say, text)
|
||||
|
||||
def handle_message(self, message):
|
||||
"""
|
||||
Handle an actuation/speech message with the receiver.
|
||||
|
||||
:param message: The message to handle, must contain properties "endpoint" and "data".
|
||||
:type message: dict
|
||||
"""
|
||||
if message["endpoint"] == "actuate/speech":
|
||||
self._handle_speech(message)
|
||||
|
||||
@@ -14,6 +14,24 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AudioSender(SocketBase):
|
||||
"""
|
||||
Audio sender endpoint, responsible for sending microphone audio data.
|
||||
|
||||
:param zmq_context: The ZeroMQ context to use.
|
||||
:type zmq_context: zmq.Context
|
||||
|
||||
:param port: The port to use.
|
||||
:type port: int
|
||||
|
||||
:ivar thread: Thread used for sending audio.
|
||||
:type thread: threading.Thread | None
|
||||
|
||||
:ivar audio: PyAudio instance.
|
||||
:type audio: pyaudio.PyAudio | None
|
||||
|
||||
:ivar microphone: Selected microphone information.
|
||||
:type microphone: dict | None
|
||||
"""
|
||||
def __init__(self, zmq_context, port=settings.agent_settings.audio_sender_port):
|
||||
super(AudioSender, self).__init__(str("audio")) # Convert future's unicode_literal to str
|
||||
self.create_socket(zmq_context, zmq.PUB, port)
|
||||
@@ -30,7 +48,10 @@ class AudioSender(SocketBase):
|
||||
def start(self):
|
||||
"""
|
||||
Start sending audio in a different thread.
|
||||
|
||||
Will not start if no microphone is available.
|
||||
"""
|
||||
|
||||
if not self.microphone:
|
||||
logger.info("Not listening: no microphone available.")
|
||||
return
|
||||
@@ -41,14 +62,18 @@ class AudioSender(SocketBase):
|
||||
|
||||
def wait_until_done(self):
|
||||
"""
|
||||
Wait until the audio thread is done. Will only be done if `state.exit_event` is set, so
|
||||
make sure to set that before calling this method or it will block.
|
||||
Wait until the audio thread is done.
|
||||
|
||||
Will block until `state.exit_event` is set. If the thread is not running, does nothing.
|
||||
"""
|
||||
if not self.thread: return
|
||||
self.thread.join()
|
||||
self.thread = None
|
||||
|
||||
def _stream(self):
|
||||
"""
|
||||
Internal method to continuously read audio from the microphone and send it over the socket.
|
||||
"""
|
||||
audio_settings = settings.audio_config
|
||||
chunk = audio_settings.chunk_size # 320 at 16000 Hz is 20ms, 512 is required for Silero-VAD
|
||||
|
||||
|
||||
@@ -6,26 +6,47 @@ from robot_interface.state import state
|
||||
from robot_interface.core.config import settings
|
||||
|
||||
class MainReceiver(ReceiverBase):
|
||||
"""
|
||||
The main receiver endpoint, responsible for handling ping and negotiation requests.
|
||||
|
||||
:param zmq_context: The ZeroMQ context to use.
|
||||
:type zmq_context: zmq.Context
|
||||
|
||||
:param port: The port to use.
|
||||
:type port: int
|
||||
"""
|
||||
def __init__(self, zmq_context, port=settings.agent_settings.main_receiver_port):
|
||||
"""
|
||||
The main receiver endpoint, responsible for handling ping and negotiation requests.
|
||||
|
||||
:param zmq_context: The ZeroMQ context to use.
|
||||
:type zmq_context: zmq.Context
|
||||
|
||||
:param port: The port to use.
|
||||
:type port: int
|
||||
"""
|
||||
super(MainReceiver, self).__init__("main")
|
||||
self.create_socket(zmq_context, zmq.REP, port, bind=False)
|
||||
|
||||
@staticmethod
|
||||
def _handle_ping(message):
|
||||
"""A simple ping endpoint. Returns the provided data."""
|
||||
"""
|
||||
Handle a ping request.
|
||||
|
||||
Returns the provided data in a standardized response dictionary.
|
||||
|
||||
:param message: The ping request message.
|
||||
:type message: dict
|
||||
|
||||
:return: A response dictionary containing the original data.
|
||||
:rtype: dict[str, str | list[dict]]
|
||||
"""
|
||||
return {"endpoint": "ping", "data": message.get("data")}
|
||||
|
||||
@staticmethod
|
||||
def _handle_port_negotiation(message):
|
||||
"""
|
||||
Handle a port negotiation request.
|
||||
|
||||
Returns a list of all known endpoints and their descriptions.
|
||||
|
||||
:param message: The negotiation request message.
|
||||
:type message: dict
|
||||
|
||||
:return: A response dictionary with endpoint descriptions as data.
|
||||
:rtype: dict[str, list[dict]]
|
||||
"""
|
||||
endpoints = [socket.endpoint_description() for socket in state.sockets]
|
||||
|
||||
return {"endpoint": "negotiate/ports", "data": endpoints}
|
||||
@@ -33,13 +54,13 @@ class MainReceiver(ReceiverBase):
|
||||
@staticmethod
|
||||
def _handle_negotiation(message):
|
||||
"""
|
||||
Handle a negotiation request. Will respond with ports that can be used to connect to the robot.
|
||||
Handle a negotiation request. Responds with ports that can be used to connect to the robot.
|
||||
|
||||
:param message: The negotiation request message.
|
||||
:type message: dict
|
||||
|
||||
:return: A response dictionary with a 'ports' key containing a list of ports and their function.
|
||||
:rtype: dict[str, list[dict]]
|
||||
:return: A response dictionary with the negotiation result.
|
||||
:rtype: dict[str, str | list[dict]]
|
||||
"""
|
||||
# In the future, the sender could send information like the robot's IP address, etc.
|
||||
|
||||
@@ -49,6 +70,17 @@ class MainReceiver(ReceiverBase):
|
||||
return {"endpoint": "negotiate/error", "data": "The requested endpoint is not implemented."}
|
||||
|
||||
def handle_message(self, message):
|
||||
"""
|
||||
Main entry point for handling incoming messages.
|
||||
|
||||
Dispatches messages to the appropriate handler based on the endpoint.
|
||||
|
||||
:param message: The received message.
|
||||
:type message: dict
|
||||
|
||||
:return: A response dictionary based on the requested endpoint.
|
||||
:rtype: dict[str, str | list[dict]]
|
||||
"""
|
||||
if message["endpoint"] == "ping":
|
||||
return self._handle_ping(message)
|
||||
elif message["endpoint"].startswith("negotiate"):
|
||||
|
||||
@@ -4,7 +4,7 @@ from robot_interface.endpoints.socket_base import SocketBase
|
||||
|
||||
|
||||
class ReceiverBase(SocketBase, object):
|
||||
"""Associated with a ZeroMQ socket."""
|
||||
"""Base class for receivers associated with a ZeroMQ socket."""
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
|
||||
@@ -4,16 +4,27 @@ import zmq
|
||||
|
||||
|
||||
class SocketBase(object):
|
||||
"""
|
||||
Base class for endpoints associated with a ZeroMQ socket.
|
||||
|
||||
:ivar identifier: The identifier of the endpoint.
|
||||
:type identifier: str
|
||||
|
||||
:ivar port: The port used by the socket, set by `create_socket`.
|
||||
:type port: int | None
|
||||
|
||||
:ivar socket: The ZeroMQ socket object, set by `create_socket`.
|
||||
:type socket: zmq.Socket | None
|
||||
|
||||
:ivar bound: Whether the socket is bound or connected, set by `create_socket`.
|
||||
:type bound: bool | None
|
||||
"""
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
name = None
|
||||
socket = None
|
||||
|
||||
def __init__(self, identifier):
|
||||
"""
|
||||
:param identifier: The identifier of the endpoint.
|
||||
:type identifier: str
|
||||
"""
|
||||
self.identifier = identifier
|
||||
self.port = None # Set later by `create_socket`
|
||||
self.socket = None # Set later by `create_socket`
|
||||
|
||||
@@ -7,6 +7,15 @@ from robot_interface.state import state
|
||||
from robot_interface.core.config import settings
|
||||
|
||||
class VideoSender(SocketBase):
|
||||
"""
|
||||
Video sender endpoint, responsible for sending video frames.
|
||||
|
||||
:param zmq_context: The ZeroMQ context to use.
|
||||
:type zmq_context: zmq.Context
|
||||
|
||||
:param port: The port to use for sending video frames.
|
||||
:type port: int
|
||||
"""
|
||||
def __init__(self, zmq_context, port=settings.agent_settings.video_sender_port):
|
||||
super(VideoSender, self).__init__("video")
|
||||
self.create_socket(zmq_context, zmq.PUB, port, [(zmq.CONFLATE,1)])
|
||||
@@ -14,6 +23,8 @@ class VideoSender(SocketBase):
|
||||
def start_video_rcv(self):
|
||||
"""
|
||||
Prepares arguments for retrieving video images from Pepper and starts video loop on a separate thread.
|
||||
|
||||
Will not start of no qi session is available.
|
||||
"""
|
||||
if not state.qi_session:
|
||||
logging.info("No Qi session available. Not starting video loop.")
|
||||
|
||||
Reference in New Issue
Block a user