o
    mju#                     @  s   d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZmZ dd	lmZ eeZG d
d dZdS )u>   Gestión de sesiones externalMedia + WebRTC / bot por llamada.    )annotationsN)Any)	AriClient)	CallState)CallRegistry)Settingsget_settings)
RtpSessionc                   @  s   e Zd Zd=d>ddZed?d	d
Zd@ddZdAddZdBddZdCddZ	dDddZ
dEddZdddFd&d'ZdGd*d+ZdHd,d-ZdHd.d/ZdId3d4ZdJd9d:ZdDd;d<ZdS )KMediaManagerNsettingsSettings | NonereturnNonec                 C  s   |pt  | _i | _i | _d S N)r   r   	_sessions_rtp_sessions)selfr    r   7/var/www/html/bot-asterisk-ari/backend/media/manager.py__init__   s   
zMediaManager.__init__boolc                 C  s   | j jS r   )r   webrtc_enabled)r   r   r   r   enabled   s   zMediaManager.enabledcall_idstrc                 C  s
   || j v S r   )r   r   r   r   r   r   has_session   s   
zMediaManager.has_sessionRtpSession | Nonec                 C  s   | j |S r   )r   getr   r   r   r   get_rtp_session   s   zMediaManager.get_rtp_sessionlist[dict[str, Any]]c                 C  s"   g }| j jr|d| j ji |S )Nurls)r   webrtc_stun_urlappend)r   serversr   r   r   ice_servers!   s   zMediaManager.ice_serversr	   c                   s   | j |}|r|jr|jstd||j |S | j |d}|r&|  t }|j	| j
jddI dH }|| j |< td|| |S )u0   Socket RTP únicamente (bot o base para WebRTC).z'Reutilizando RTP call_id=%s (puerto %s)Nr   )	bind_hostportu,   Sesión RTP preparada call_id=%s (puerto %s))r   r   
local_port	is_closedloggerinfopopcloser	   startr   external_media_bind_host)r   r   existingold_rtprtpr'   r   r   r   prepare_rtp_session'   s(   
z MediaManager.prepare_rtp_sessionc              
     s   || j v r || jv r | j| }|js |jr td||j dS | j |d}|r0| I dH  | j|d}|r=|  | |I dH }zddl	m
} W n tyi } z|  | j|d td|d}~ww ||||  d| j |< td||j dS )zDUn socket RTP + WebRTC por llamada (mismo puerto que externalMedia).u6   Reutilizando sesión WebRTC call_id=%s (RTP puerto %s)Nr   )WebRtcBridgeSessionu7   WebRTC requiere aiortc. Ejecutá: pip install aiortc av)r%   u3   Sesión WebRTC preparada call_id=%s (RTP puerto %s))r   r   r)   r(   r*   r+   r,   r-   r3   media.webrtc_sessionr4   ImportErrorRuntimeErrorr%   )r   r   r2   oldr1   r4   excr   r   r   prepare_session?   sN   
zMediaManager.prepare_session
int | Nonec                 C  s   | j |}|r|jS d S r   )r   r   r(   )r   r   r2   r   r   r   rtp_portj   s   zMediaManager.rtp_portFrequire_bridgecallr   arir   registryr   r>   c             
     sV  |j rtd|j|j  d S | j|j}|d u s|jd u r#td| jj	}| d|j }td|j|| jj
 z[|j||jdg| jjdI d H }|d }	|||	 |	|_ | ||	|I d H  |jr||j|	I d H  d|_td	|	||j|j W d S |rtd
|j td|	||j W d S  ty }
 z	td|j|
  d }
~
ww )Nz$externalMedia ya existe para %s (%s)zPuerto RTP no disponible:u9   Creando externalMedia call=%s Asterisk→RTP %s (bind=%s)media)external_hostapp_argsfmtidTu1   externalMedia %s → %s en puente %s (llamada %s)z#Bot sin puente mixing para llamada u9   externalMedia %s → %s para llamada %s (sin puente aún)z*No se pudo crear externalMedia para %s: %s)external_media_channel_idr*   r+   r   r   r   r(   r7   r   external_media_advertise_hostr/   create_external_mediaexternal_media_formatlink_channel_prime_rtp_remote_from_asterisk	bridge_idadd_to_bridgeexternal_media_attached	Exceptionerror)r   r?   r@   rA   r>   r2   	advertiserD   channel
channel_idr9   r   r   r   _create_external_media_channeln   st   


z+MediaManager._create_external_media_channelrU   r2   c                   s   | |dI dH }| |dI dH }|r|s!td||| dS zt|}W n ty8   td|| Y dS w ||| dS )u   Usa UNICASTRTP_LOCAL_* para poder enviar TTS sin esperar RTP del caller.

        WebRTC suele mandar silencio continuo; muchos softphones UDP no envían
        nada hasta que hay audio (VAD). Sin destino prearmado el bot hace timeout.
        UNICASTRTP_LOCAL_ADDRESSNUNICASTRTP_LOCAL_PORTz9externalMedia %s sin UNICASTRTP_LOCAL_* (host=%s port=%s)u)   UNICASTRTP_LOCAL_PORT inválido en %s: %s)get_channel_variabler*   warningint
ValueError
set_remote)r   r@   rU   r2   hostport_rawr'   r   r   r   rM      s,   z,MediaManager._prime_rtp_remote_from_asteriskc                   s6   | j sdS | |jI dH  | |||I dH  dS )u'   WebRTC operador: RTP + sesión browser.N)r   r:   r   rV   r   r?   r@   rA   r   r   r   attach_external_media   s
   z"MediaManager.attach_external_mediac                   s0   |  |jI dH  | j|||ddI dH  dS )u+   Bot IA: solo RTP ↔ Asterisk (sin WebRTC).NTr=   )r3   r   rV   r`   r   r   r   attach_bot_external_media   s
   z&MediaManager.attach_bot_external_mediasdp
offer_typedict[str, str]c                   s.   |  |I d H  | j| }|||I d H S r   )r:   r   apply_offer)r   r   rc   rd   sessionr   r   r   rf      s   
zMediaManager.apply_offer	candidate
str | Nonesdp_midsdp_mline_indexc                   s2   || j vrd S | j | }||||I d H  d S r   )r   add_ice_candidate)r   r   rh   rj   rk   rg   r   r   r   rl      s   

zMediaManager.add_ice_candidatec                   sd   | j |d }| j|d }|r| I d H  td| |r.|  |s0td| d S d S d S )Nu!   Sesión WebRTC cerrada call_id=%su$   Sesión RTP (bot) cerrada call_id=%s)r   r,   r   r-   r*   r+   )r   r   rg   r2   r   r   r   close_session   s   zMediaManager.close_sessionr   )r   r   r   r   )r   r   )r   r   r   r   )r   r   r   r   )r   r    )r   r   r   r	   )r   r   r   r   )r   r   r   r;   )
r?   r   r@   r   rA   r   r>   r   r   r   )r@   r   rU   r   r2   r	   r   r   )r?   r   r@   r   rA   r   r   r   )r   r   rc   r   rd   r   r   re   )
r   r   rh   ri   rj   ri   rk   r;   r   r   )__name__
__module____qualname__r   propertyr   r   r   r%   r3   r:   r<   rV   rM   ra   rb   rf   rl   rm   r   r   r   r   r
      s$    





+

D
 


r
   )__doc__
__future__r   loggingtypingr   
ari.clientr   calls.modelsr   calls.registryr   configr   r   media.rtp_sessionr	   	getLoggerrn   r*   r
   r   r   r   r   <module>   s    
