feat: fix CallerID dinamico su PBX e aggiunto AGC audio bidirezionale

This commit is contained in:
2026-08-14 13:33:50 +02:00
parent 26d419ec49
commit 21b25d303e
+34 -8
View File
@@ -199,7 +199,6 @@ class SessionManager:
sess = self.sessioni[call_id]
if sess.ptt_attivo and self.openbridge:
self.openbridge.chiudi_flusso_chiamata(sess)
# Rilascia la porta del pool associata a questa chiamata
self.vocoder.rilascia_porta(f"SIP_{call_id}")
del self.sessioni[call_id]
@@ -245,8 +244,8 @@ class SessionManager:
f"Max-Forwards: 70\r\nFrom: {sess.dialog_from}\r\nTo: {sess.dialog_to}\r\n"
f"Call-ID: {sess.call_id}\r\nCSeq: {sess.local_cseq} INVITE\r\n"
f"Contact: <sip:gateway@127.0.0.1:{SIP_PORT}>\r\n"
f"Remote-Party-ID: \"{testo_display}\" <sip:000@127.0.0.1>;party=called;screen=yes;privacy=off\r\n"
f"P-Asserted-Identity: \"{testo_display}\" <sip:000@127.0.0.1>\r\n"
f"Remote-Party-ID: \"{testo_display}\" <sip:{sess.tg_destinazione}@{sess.ip_vps}>;party=called;screen=yes;privacy=off\r\n"
f"P-Asserted-Identity: \"{testo_display}\" <sip:{sess.tg_destinazione}@{sess.ip_vps}>\r\n"
f"Content-Type: application/sdp\r\nContent-Length: {len(sdp)}\r\n\r\n{sdp}")
self.sip_transport.sendto(sip_reinvite.encode('utf-8'), sess.sip_client_addr)
@@ -256,7 +255,7 @@ class SessionManager:
for sess in ascoltatori:
if sess.ultimo_src_id != src_id:
sess.ultimo_src_id = src_id
self.notifica_display(sess, f"RX: {src_id}")
self.notifica_display(sess, f"CID:{src_id}")
asyncio.create_task(self.processa_audio_dmr(ambe_frames, ascoltatori))
async def processa_audio_dmr(self, ambe_27_bytes, ascoltatori):
@@ -264,7 +263,6 @@ class SessionManager:
tg_arrivo = ascoltatori[0].tg_destinazione
try:
# 1. Decodifichiamo prima tutti e 3 i frame del superframe DMR
frames_pcm = []
for i in range(0, len(ambe_27_bytes), 9):
frame_9 = ambe_27_bytes[i:i+9]
@@ -279,10 +277,20 @@ class SessionManager:
pcm_data = await self.vocoder.converti_ambe_in_pcm(f"TG_{tg_arrivo}", frame_7)
if pcm_data and len(pcm_data) >= 2:
if len(pcm_data) % 2 != 0: pcm_data = pcm_data[:-1]
# --- INIZIO AGC DMR -> SIP ---
livello_rms = audioop.rms(pcm_data, 2)
if livello_rms > 18000:
pcm_data = audioop.mul(pcm_data, 2, 0.4)
elif livello_rms > 12000:
pcm_data = audioop.mul(pcm_data, 2, 0.7)
elif livello_rms < 300:
pcm_data = audioop.mul(pcm_data, 2, 0.0)
# --- FINE AGC ---
pcma_data = audioop.lin2alaw(pcm_data, 2)
frames_pcm.append(pcma_data)
# 2. Spediamo i pacchetti RTP cadenzandoli a ritmo di 19ms (sgranatura)
for idx, pcma_data in enumerate(frames_pcm):
for sess in ascoltatori:
header = bytearray(12)
@@ -298,7 +306,6 @@ class SessionManager:
sess.rtp_seq = (sess.rtp_seq + 1) % 65536
sess.rtp_timestamp = (sess.rtp_timestamp + 160) % 4294967296
# Attesa di ~19ms tra un frame audio e il successivo (tranne l'ultimo)
if idx < len(frames_pcm) - 1:
await asyncio.sleep(0.019)
@@ -307,7 +314,26 @@ class SessionManager:
async def processa_audio_rtp(self, sess, rtp_payload):
if not sess.ptt_attivo: return
try:
# *** PASSIAMO IL CALL ID PER IL POOL ***
# --- INIZIO AGC SIP -> DMR ---
# Decodifichiamo G.711a in PCM lineare temporaneamente per calcolare il volume
pcm_lineare = audioop.alaw2lin(rtp_payload, 2)
livello_rms = audioop.rms(pcm_lineare, 2)
if livello_rms > 18000:
pcm_lineare = audioop.mul(pcm_lineare, 2, 0.4)
elif livello_rms > 12000:
pcm_lineare = audioop.mul(pcm_lineare, 2, 0.7)
elif livello_rms > 500 and livello_rms < 3000:
# Piccolo booster se il microfono SIP è basso
pcm_lineare = audioop.mul(pcm_lineare, 2, 1.5)
elif livello_rms < 150:
# Noise gate
pcm_lineare = audioop.mul(pcm_lineare, 2, 0.0)
# Ricodifichiamo in formato PCMA/A-Law prima di passarlo al vocoder
rtp_payload = audioop.lin2alaw(pcm_lineare, 2)
# --- FINE AGC ---
ambe_bytes = await asyncio.wait_for(
self.vocoder.converti_rtp_in_ambe(f"SIP_{sess.call_id}", rtp_payload), timeout=0.1
)