o
    ìcj                     @  s   d Z ddlmZ ddlZddlZddlZddlmZ ddlZddl	m
Z
mZmZmZ ddlmZ ddlmZmZ eeZdddZG dd deZG dd dZdS )uG   Puente WebRTC (navegador) ↔ RTP (Asterisk externalMedia) vía aiortc.    )annotationsN)Any)RTCConfigurationRTCIceServerRTCPeerConnectionRTCSessionDescription)MediaStreamTrack)
RtpSessionSAMPLES_PER_PACKETice_serverslist[dict[str, Any]]returnRTCConfiguration | Nonec                 C  s>   g }| D ]}| d}|r|t|d q|sd S t|dS )Nurls)r   )
iceServers)getappendr   r   )r   serversentryr    r   >/var/www/html/bot-asterisk-ari/backend/media/webrtc_session.py_rtc_configuration   s   

r   c                      s0   e Zd ZdZdZd fddZdd
dZ  ZS )AsteriskAudioTrackz%Audio de Asterisk hacia el navegador.audiortpr	   r   Nonec                   s   t    || _d| _d S )Nr   )super__init___rtp_pts)selfr   	__class__r   r   r   (   s   

zAsteriskAudioTrack.__init__av.AudioFramec                   s   	 | j jddI d H }|rn	tdI d H  qt|}t|d }tjdd|d}|j	d	 
| d
|_| j|_tdd
|_|  j|7  _|S )NTg?timeoutg{Gz?   s16mono)formatlayoutsamplesr   @     )r   recv_ulaw_frameasynciosleepr	   ulaw_to_pcmlenav
AudioFrameplanesupdatesample_rater   pts	fractionsFraction	time_base)r    ulawpcmr+   framer   r   r   recv-   s    
zAsteriskAudioTrack.recv)r   r	   r   r   )r   r#   )__name__
__module____qualname____doc__kindr   r?   __classcell__r   r   r!   r   r   #   s
    r   c                   @  sT   e Zd Zd%d	d
Zd&ddZd'ddZd(ddZd)d*ddZd+d d!Zd'd"d#Z	d$S ),WebRtcBridgeSessioncall_idstrr   r	   r   r   r   r   c                 C  s8   || _ || _|| _d | _t|| _d | _d| _g | _d S )NF)	rG   r   _ice_serverspcr   asterisk_track_browser_task_closed_pending_ice)r    rG   r   r   r   r   r   r   @   s   

zWebRtcBridgeSession.__init__sdp
offer_typedict[str, str]c           	        sZ   j rtd jr* jjr* jj}|dv r* jj}td j| |j|j	dS  jr= j
 I d H  d  _ j  tt jd _ j j  jdd fd
d} jdd fdd}t||d} j|I d H    I d H   j I d H } j|I d H    I d H   jj}|stdtd j |j|j	dS )Nu   Sesión WebRTC cerrada)	connected
connectingnewz/Offer duplicado ignorado call_id=%s (estado=%s))rO   type)configurationtrackr   r   r   c                   s0   | j dkrtj | d j d _d S d S )Nr   zbrowser-audio-)name)rD   r/   create_task_consume_browser_audiorG   rL   )rW   r    r   r   on_tracka   s   

z1WebRtcBridgeSession.apply_offer.<locals>.on_trackconnectionstatechangec                     s4    j r j jdv rtd j j j d S d S d S )N)failedclosedz$WebRTC call_id=%s connectionState=%s)rJ   connectionStateloggerwarningrG   r   r[   r   r   on_connectionstatechangei   s   zAWebRtcBridgeSession.apply_offer.<locals>.on_connectionstatechangezSin SDP local tras createAnswerz WebRTC negociado para llamada %srW   r   r   r   r   r   )rM   RuntimeErrorrJ   localDescriptionr`   ra   inforG   rO   rU   closerN   clearr   r   rI   addTrackrK   onr   setRemoteDescription_flush_pending_icecreateAnswersetLocalDescription_wait_ice_gathering)	r    rO   rP   statelocalr\   rc   offeranswerr   r[   r   apply_offerJ   sD   


zWebRtcBridgeSession.apply_offerc                   sj   | j r| js	d S ddlm} | jD ]\}}}|sq||}||_||_| j |I d H  q| j  d S Nr   )candidate_from_sdp)rJ   rN   
aiortc.sdprx   sdpMidsdpMLineIndexaddIceCandidaterj   )r    rx   	candidatesdp_midsdp_mline_indexicer   r   r   rn      s   z&WebRtcBridgeSession._flush_pending_icer}   
str | Noner~   r   
int | Nonec                   sd   |sd S | j r| j js| j|||f d S ddlm} ||}||_||_| j |I d H  d S rw   )	rJ   remoteDescriptionrN   r   ry   rx   rz   r{   r|   )r    r}   r~   r   rx   r   r   r   r   add_ice_candidate   s   z%WebRtcBridgeSession.add_ice_candidate      $@r%   floatc                   s   j sd S j jdkrd S t   j dd	 fdd}ztj |dI d H  W d S  tjyA   t	dj
 Y d S w )
Ncompleteicegatheringstatechanger   r   c                     s4   j rj jdkr  s d  d S d S d S d S )Nr   )rJ   iceGatheringStatedone
set_resultr   r   r    r   r   on_gathering_change   s   zDWebRtcBridgeSession._wait_ice_gathering.<locals>.on_gathering_changer$   z ICE gathering timeout call_id=%sre   )rJ   r   r/   get_running_loopcreate_futurerl   wait_forTimeoutErrorra   rb   rG   )r    r%   r   r   r   r   rq      s   
z'WebRtcBridgeSession._wait_ice_gatheringrW   r   c           	   
     s   t d| j zF| jsL| I d H }t|jd }|jpd}t	||d}t
|}tdt|tD ]}|||t  }|rE| j| q3| jrW d S W d S  tys } z| jsht d| j| W Y d }~d S W Y d }~d S d }~ww )Nz*Consumiendo audio del navegador call_id=%sr   i  r,   z"Fin audio navegador call_id=%s: %s)ra   rh   rG   rM   r?   bytesr5   r7   r	   resample_pcmpcm_to_ulawranger2   r
   r   	send_ulaw	Exception)	r    rW   r>   r=   rater<   offsetchunkexcr   r   r   rZ      s*   


z*WebRtcBridgeSession._consume_browser_audioc                   sh   d| _ | jr| j  z| jI d H  W n
 tjy   Y nw | jr-| j I d H  d | _| j  d S )NT)rM   rL   cancelr/   CancelledErrorrJ   ri   r   r[   r   r   r   ri      s   
zWebRtcBridgeSession.closeN)rG   rH   r   r	   r   r   r   r   )rO   rH   rP   rH   r   rQ   re   )r}   r   r~   r   r   r   r   r   )r   )r%   r   r   r   rd   )
r@   rA   rB   r   rv   rn   r   rq   rZ   ri   r   r   r   r   rF   ?   s    



5

rF   )r   r   r   r   )rC   
__future__r   r/   r9   loggingtypingr   r3   aiortcr   r   r   r   aiortc.mediastreamsr   media.rtp_sessionr	   r
   	getLoggerr@   ra   r   r   rF   r   r   r   r   <module>   s    

