
    /cjN                         d Z ddlZddlZddlmZmZ dZ ej                    ZdZ	dZ
 e            Zd Zd Zdd	Zdd
Zd Zd Zd Zd Zd ZdS )u  
Audio-piece timing tracer  (ADD-ON, diagnostic only — safe to remove).

Records, per call, two timestamps for every audio piece:

    Alibaba cloud  --recv-->  THIS server  --send-->  bridge  ----->  caller
                   ^ recv gap               ^ send gap        ^ (bridge's own log)

  * record_recv() is called the moment an audio delta ARRIVES from the cloud
    model (in callbacks.py, response.audio.delta).
  * record_send() is called the moment that server SENDS a piece out to the
    phone bridge (in qwen_pipeline_server.py, _sender()).

Comparing the two gap timelines (plus the bridge's own AudioTrace receive log)
tells you WHERE a speech "freeze" is introduced:

  * a big RECV gap  ............... the cloud paused generating (Alibaba side)
  * RECV smooth but SEND gappy .... this server delayed relaying it
                                    (e.g. the event loop was blocked)
  * RECV + SEND both smooth, but
    the bridge still saw a gap ..... the network between here and the bridge

This module is a pure add-on. It touches no call logic; every public function
swallows its own errors and returns fast, so it can never disturb a live call.
View it at  /audio_timing.html  on this server's dashboard.
    N)dequeOrderedDict   (   i0u  c                    t                               |           }|t          j                    t          j                    t	          t
                    t	          t
                    d}|t           | <   t          t                     t          k    r8t                               d           t          t                     t          k    8|S )N)maxlen)started_wallstarted_monorecvsendF)last)	_CALLSgettime	monotonicr   _MAX_EVENTSlen
_MAX_CALLSpopitem)call_idbs     P/home/m1-ai/DEPLOYMENTS/AI-PHONE/ZACK-UPDATE/fixing_leaked/audio_timing_trace.py_bucketr   +   s    

7Ay IKK N,,------	
 
 w&kkJ&&NNN&&& &kkJ&&H    c                 @    t          j                    | d         z
  dz  S )Nr
        @@)r   r   )r   s    r   _rel_msr   :   s    Nq00F::r   c                     	 | sdS t           5  t          |           }|d                             t          |          t	          |          f           ddd           dS # 1 swxY w Y   dS # t
          $ r Y dS w xY w)z,An audio piece arrived from the cloud model.Nr   _LOCKr   appendr   int	Exceptionr   nbytesr   s      r   record_recvr&   >        	F 	8 	8  AfIgajj#f++6777	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8    :   A. A. AA!A. !A%%A. (A%)A. .
A<;A<c                     	 | sdS t           5  t          |           }|d                             t          |          t	          |          f           ddd           dS # 1 swxY w Y   dS # t
          $ r Y dS w xY w)z0An audio piece was sent out to the phone bridge.Nr   r   r$   s      r   record_sendr*   J   r'   r(   c                 V    g d }}| D ]!\  }}||                     ||z
             |}"|S )N)r!   )eventsoutprevt_s        r   _gapsr1   V   sF    DC  1JJq4x   Jr   c                     t          |           }d |D             }t          |           |rt          t          |          d          ndt          |          | rt          | d         d         dz  d          nddS )Nc                 (    g | ]}|t           k    |S  GAP_THRESHOLD_MS).0gs     r   
<listcomp>z_summary.<locals>.<listcomp>a   s#    
4
4
4a#3331333r              r   r   )pieces
max_gap_msgaps_over_threshspan_s)r1   r   roundmax)r,   gapsbigs      r   _summaryrE   _   s    ==D
4
4d
4
4
4Cf++-1:eCIIq)))sHH6<E%r
1.222#	  r   c                     | d         }|d         }|t           k     r|t           k     rdS |t           k    r||dz  k    rdS |t           k    r||dz  k    rdS dS )zCBest-guess of where the worst gap came from (see module docstring).r>   cleangffffff?cloudg      ?zthis-servermixedr5   )recv_summarysend_summaryrss       r   _verdictrN   j   sq    \"A\"A$4 4 4wa#gwQW}7r   c                     	 t           5  d t                                          D             } ddd           n# 1 swxY w Y   g }| D ]s\  }}}}t          |          }t          |          }|                    |t          j        dt          j        |                    ||t          ||          d           t|	                    d d           |S # t          $ r g cY S w xY w)z#Summary row per call, newest first.c                 x    g | ]7\  }}|t          |d                    t          |d                   |d         f8S )r   r   r	   )list)r7   cidr   s      r   r9   zget_calls.<locals>.<listcomp>}   sN     3 3 3a 4&	??D6OOQ~=NO 3 3 3r   N%Y-%m-%d %H:%M:%S)r   startedr   r   verdictc                     | d         S )Nr   r4   )cs    r   <lambda>zget_calls.<locals>.<lambda>   s
    q| r   T)keyreverse)r    r   itemsrE   r!   r   strftime	localtimerN   sortr#   )r[   r-   rR   r   r   rT   rssss           r   	get_callsra   y   s^    	3 	33 3#)<<>>3 3 3E	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 	3 (- 
	 
	$CtW$B$BJJ=)<)-)@)@B B#B++      	++T:::
   			s/   C $9C =C  =BC C%$C%c           
         	 t           5  t                              |           }|s	 ddd           dS t          |d                   }t          |d                   }|d         }ddd           n# 1 swxY w Y   d }t	          |          }t	          |          }| t          j        dt          j        |                    t          t          ||          || ||           ||          dS # t          $ r Y dS w xY w)z;Full per-piece timeline for one call (recv + send streams).Nr   r   r	   c                     g d }}| D ]E\  }}|||z
  nd}|                     t          |d          t          |d          |d           |}F|S )Nr;   r:   )t_msgap_msbytes)r!   rA   )r,   r-   r.   r/   nbgaps         r   rowszget_series.<locals>.rows   sv    DC  2$($4q4xx#

E!QKK&+Cmm%') ) * * * Jr   rS   )r   rT   threshold_msrU   rJ   rK   r   r   )r    r   r   rQ   rE   r   r\   r]   r6   rN   r#   )r   r   r   r   rT   ri   r_   r`   s           r   
get_seriesrk      ss     	( 	(

7##A 	( 	( 	( 	( 	( 	( 	( 	( &	??D&	??D'G	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	(	 	 	 d^^d^^}%8$.:Q:QRR,B''DJJDJJ	
 	
 		
    tts?   C3 A2C3 2A2&C3 2A66C3 9A6:A8C3 3
D D)r   )__doc__	threadingr   collectionsr   r   r6   Lockr    r   r   r   r   r   r&   r*   r1   rE   rN   ra   rk   r4   r   r   <module>rp      s   6      * * * * * * * *  	
 
  ; ; ;	 	 	 		 	 	 	        0" " " " "r   