0
I have 2 Python services and an Asterisk dialplan setup:
api_server.py → exposes an HTTP API endpoint app.py → runs an AudioSocket server (accepts calls from Asterisk via TCP socket)
In my dialplan, I generate a CALL_UUID and notify the API server first, then start AudioSocket:
same => n,Set(CALL_UUID=${UUID()})
same => n,System(curl -s "http://192.168.1.6:8000/api/call-start?callerId=${CALLERID(num)}&uuid=${CALL_UUID}" >/dev/null 2>&1 || wget -q -O - "http://192.168.1.7:8000/api/call-start?callerId=${CALLERID(num)}&uuid=${CALL_UUID}" >/dev/null 2>&1)
same => n,AudioSocket(${CALL_UUID},192.168.1.6:3000)
In api_server.py I successfully receive and store callerId + uuid (currently in memory/dict, but could also store in MongoDB).
The issue is in app.py → when the AudioSocket connection is accepted, I want to access the same uuid. But when I try to use conn.uuid, it is always None. If I try to recv().decode() the first bytes from the socket, I get an error because AudioSocket is sending raw audio (binary), not text metadata:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbf in position 3: invalid start byte
My AudioSocket server looks like this:
class Audiosocket:
def __init__(self, bind_info, timeout=None):
if not isinstance(bind_info, tuple):
raise TypeError("Expected tuple (addr, port), received", type(bind_info))
self.addr, self.port = bind_info
self.initial_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.initial_sock.bind((self.addr, self.port))
self.initial_sock.settimeout(timeout)
self.initial_sock.listen(1)
self.port = self.initial_sock.getsockname()[1]
self.user_resample = None
self.asterisk_resample = None
def prepare_output(self, outrate=44000, channels=2, ulaw2lin=False):
self.asterisk_resample = audioop_struct(
rate=outrate, channels=channels, ulaw2lin=ulaw2lin, ratecv_state=None
)
def listen(self):
conn, peer_addr = self.initial_sock.accept()
connection = Connection(conn, peer_addr, self.asterisk_resample)
connection_thread = Thread(target=connection._process, args=())
connection_thread.start()
return connection
And I use it like this in app.py:
def listen_for_connections(self):
try:
conn = self.audiosocket.listen()
log.debug(f"New AudioSocket connection received: {conn.uuid}")
return conn
except Exception as e:
log.error(f"Error listening for connections: {e}")
raise
So my questions are:
-
How can I safely get the uuid from Asterisk into my app.py AudioSocket server?
-
What’s the best design to handle concurrent calls safely (so one call doesn’t pick up another call’s UUID)?