feat: fix CallerID dinamico su PBX e aggiunto AGC audio bidirezionale
This commit is contained in:
@@ -199,7 +199,6 @@ class SessionManager:
|
|||||||
sess = self.sessioni[call_id]
|
sess = self.sessioni[call_id]
|
||||||
if sess.ptt_attivo and self.openbridge:
|
if sess.ptt_attivo and self.openbridge:
|
||||||
self.openbridge.chiudi_flusso_chiamata(sess)
|
self.openbridge.chiudi_flusso_chiamata(sess)
|
||||||
# Rilascia la porta del pool associata a questa chiamata
|
|
||||||
self.vocoder.rilascia_porta(f"SIP_{call_id}")
|
self.vocoder.rilascia_porta(f"SIP_{call_id}")
|
||||||
del self.sessioni[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"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"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"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"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:000@127.0.0.1>\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}")
|
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)
|
self.sip_transport.sendto(sip_reinvite.encode('utf-8'), sess.sip_client_addr)
|
||||||
|
|
||||||
@@ -256,7 +255,7 @@ class SessionManager:
|
|||||||
for sess in ascoltatori:
|
for sess in ascoltatori:
|
||||||
if sess.ultimo_src_id != src_id:
|
if sess.ultimo_src_id != src_id:
|
||||||
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))
|
asyncio.create_task(self.processa_audio_dmr(ambe_frames, ascoltatori))
|
||||||
|
|
||||||
async def processa_audio_dmr(self, ambe_27_bytes, ascoltatori):
|
async def processa_audio_dmr(self, ambe_27_bytes, ascoltatori):
|
||||||
@@ -264,7 +263,6 @@ class SessionManager:
|
|||||||
tg_arrivo = ascoltatori[0].tg_destinazione
|
tg_arrivo = ascoltatori[0].tg_destinazione
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 1. Decodifichiamo prima tutti e 3 i frame del superframe DMR
|
|
||||||
frames_pcm = []
|
frames_pcm = []
|
||||||
for i in range(0, len(ambe_27_bytes), 9):
|
for i in range(0, len(ambe_27_bytes), 9):
|
||||||
frame_9 = ambe_27_bytes[i:i+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)
|
pcm_data = await self.vocoder.converti_ambe_in_pcm(f"TG_{tg_arrivo}", frame_7)
|
||||||
if pcm_data and len(pcm_data) >= 2:
|
if pcm_data and len(pcm_data) >= 2:
|
||||||
if len(pcm_data) % 2 != 0: pcm_data = pcm_data[:-1]
|
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)
|
pcma_data = audioop.lin2alaw(pcm_data, 2)
|
||||||
frames_pcm.append(pcma_data)
|
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 idx, pcma_data in enumerate(frames_pcm):
|
||||||
for sess in ascoltatori:
|
for sess in ascoltatori:
|
||||||
header = bytearray(12)
|
header = bytearray(12)
|
||||||
@@ -298,7 +306,6 @@ class SessionManager:
|
|||||||
sess.rtp_seq = (sess.rtp_seq + 1) % 65536
|
sess.rtp_seq = (sess.rtp_seq + 1) % 65536
|
||||||
sess.rtp_timestamp = (sess.rtp_timestamp + 160) % 4294967296
|
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:
|
if idx < len(frames_pcm) - 1:
|
||||||
await asyncio.sleep(0.019)
|
await asyncio.sleep(0.019)
|
||||||
|
|
||||||
@@ -307,7 +314,26 @@ class SessionManager:
|
|||||||
async def processa_audio_rtp(self, sess, rtp_payload):
|
async def processa_audio_rtp(self, sess, rtp_payload):
|
||||||
if not sess.ptt_attivo: return
|
if not sess.ptt_attivo: return
|
||||||
try:
|
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(
|
ambe_bytes = await asyncio.wait_for(
|
||||||
self.vocoder.converti_rtp_in_ambe(f"SIP_{sess.call_id}", rtp_payload), timeout=0.1
|
self.vocoder.converti_rtp_in_ambe(f"SIP_{sess.call_id}", rtp_payload), timeout=0.1
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user