
    q	h                         S SK r S SKrS SKrS SKJr  S SKJrJr  SSKJ	r	  SSK
Jr  SSKJr  SSKJr  \R                   " \5      r " S	 S
5      r " S S5      rg)    N)deque)OptionalUnion   )
VideoFrame)
AudioFrame)AudioSource)VideoSourcec                       \ rS rSrSrSSS.S\S\S\S	\S
\4
S jjr SS\	\
\4   S\\   SS4S jjrSS jrSS jrSS jrSS jrSS jr\S\4S j5       r\S\4S j5       r\S\4S j5       rSrg)AVSynchronizer   a@  Synchronize audio and video capture.

Usage:
    av_sync = AVSynchronizer(
        audio_source=audio_source,
        video_source=video_source,
        video_fps=video_fps,
    )

    async for video_frame, audio_frame in video_generator:
        await av_sync.push(video_frame)
        await av_sync.push(audio_frame)
d   ,  )video_queue_size_ms_max_delay_tolerance_msaudio_sourcevideo_source	video_fpsr   r   c                (   Xl         X l        X0l        X@l        XPl        SU l        SU l        SU l        [        U R                  U R                  -  S-  5      U l	        U R                  S:  a  [        SU R                  5      U l	        [        R                  [        [        [        [            4      " U R                  S9U l        [%        U R                  U R                  S9U l        [        R(                  " U R+                  5       5      U l        g )NFr     r   )maxsize)expected_fpsmax_delay_tolerance_ms)_audio_source_video_source
_video_fps_video_queue_size_msr   _stopped_last_video_time_last_audio_timeint_video_queue_max_sizemaxasyncioQueuetupler   r   float_video_queue_FPSController_fps_controllercreate_task_capture_video_capture_video_task)selfr   r   r   r   r   s         J/var/www/html/env/lib/python3.13/site-packages/livekit/rtc/synchronizer.py__init__AVSynchronizer.__init__   s     *)#$7!'>$'('(%(4;T;T)TW[)[%\"$$q(),Q0J0J)KD&#MM%
HUO0K*LM..
  .#'#?#? 
 $+#6#6t7J7J7L#M     Nframe	timestampreturnc                    #    [        U[        5      (       a-  U R                  R                  U5      I Sh  vN   Ub  X l        gU R
                  R                  X45      I Sh  vN   g N3 N7f)zPush a frame to the synchronizer

Args:
    frame: The video or audio frame to push.
    timestamp: (optional) The timestamp of the frame, for logging purposes for now.
        For AudioFrame, it should be the end time of the frame.
N)
isinstancer   r   capture_framer    r(   putr.   r3   r4   s      r/   pushAVSynchronizer.pushA   sd      eZ(($$225999$(1%##U$6777 :
 	8s!   4A.A*-A.$A,%A.,A.c                 >  #    U R                   R                  5         U R                  R                  5       (       d^  U R                  R	                  5       I S h  vN   U R                  R                  5         U R                  R                  5       (       d  M]  g g  NA7fN)r   clear_queuer(   emptyget	task_doner.   s    r/   r?   AVSynchronizer.clear_queueS   sp     &&(##))++##'')))'') ##))++)s   ABB=BBc                    #    [         R                  " U R                  R                  5       U R                  R                  5       5      I Sh  vN   g N7f)z5Wait until all video and audio frames are played out.N)r$   gatherr   wait_for_playoutr(   joinrC   s    r/   rG   AVSynchronizer.wait_for_playoutY   s?     nn//1""$
 	
 	
s   AAAAc                 8    U R                   R                  5         g r>   )r*   resetrC   s    r/   rK   AVSynchronizer.reset`   s    ""$r2   c                   #    U R                   (       d  U R                  R                  5       I S h  vN u  pU R                   IS h  vN   U R                  R                  U5        Ub  X l        S S S 5      IS h  vN   U R                  R                  5         U R                   (       d  M  g g  N~ Ni N7! , IS h  vN  (       d  f       NL= f7fr>   )r   r(   rA   r*   r   r8   r   rB   r:   s      r/   r,   AVSynchronizer._capture_videoc   s     --%)%6%6%:%:%<<E+++""007(,5) ,+ '') ---<++++s]   /CB0CB2	C%B61C<B4=/C.C2C4C6C<B?=C	Cc                 r   #    SU l         U R                  (       a  U R                  R                  5         g g 7f)NT)r   r-   cancelrC   s    r/   acloseAVSynchronizer.aclosel   s,     ##$$++- $s   57c                 .    U R                   R                  $ r>   )r*   
actual_fpsrC   s    r/   rT   AVSynchronizer.actual_fpsq   s    ##...r2   c                     U R                   $ )z)The time of the last video frame captured)r   rC   s    r/   last_video_timeAVSynchronizer.last_video_timeu   s     $$$r2   c                 H    U R                   U R                  R                  -
  $ )z+The time of the last audio frame played out)r    r   queued_durationrC   s    r/   last_audio_timeAVSynchronizer.last_audio_timez   s!     $$t'9'9'I'IIIr2   )r   r-   r*   r    r   r   r   r   r(   r"   r   r   r>   r5   N)__name__
__module____qualname____firstlineno____doc__r	   r
   r'   r0   r   r   r   r   r;   r?   rG   rK   r,   rQ   propertyrT   rW   r[   __static_attributes__ r2   r/   r   r      s    ( &)), N " N "	 N
  N # N "' NF RV8:z128?G8	8$*
%*.
 /E / / % % % J J Jr2   r   c                       \ rS rSrSS.S\S\SS4S jjrSS	 jrSS
 jrSS jrSS jr	SS jr
\S\4S j5       r\S\4S j5       rSrg)r)      r   )r   r   r   r5   Nc                    Xl         SU-  U l        US-  U l        SU l        [	        S[        SU-  5      5      U l        [        U R                  S9U l        g)a  Controls frame rate by adjusting sleep time based on actual FPS.

Usage:
    async with _FPSController(expected_fps=30):
        # process frame
        pass

Args:
    expected_fps: Target frames per second
    max_delay_tolerance_ms: Maximum delay tolerance in milliseconds
g      ?r   N   )maxlen)	_expected_fps_frame_interval_max_delay_tolerance_secs_next_frame_timer#   r!   _fps_calc_winsizer   _send_timestamps)r.   r   r   s      r/   r0   _FPSController.__init__   sX     *"\1)?$)F&15!$QC,,>(?!@.34;Q;Q.Rr2   c                 @   #    U R                  5       I S h  vN   g  N7fr>   )wait_next_processrC   s    r/   
__aenter___FPSController.__aenter__   s     $$&&&s   c                 ,   #    U R                  5         g 7fr>   )after_process)r.   exc_typeexc_valexc_tbs       r/   	__aexit___FPSController.__aexit__   s     s   c                 F    S U l         U R                  R                  5         g r>   )rn   rp   clearrC   s    r/   rK   _FPSController.reset   s     $##%r2   c                 \  #    [         R                  " 5       nU R                  c  Xl        U R                  U-
  nUS:  a  [        R                  " U5      I Sh  vN   gU* U R
                  :  a9  [        R                  SU* S-  S S35        [         R                  " 5       U l        gg NP7f)zjWait until it's time for the next frame.

Adjusts sleep time based on actual FPS to maintain target rate.
Nr   z&Frame capture was behind schedule for r   z.2fz ms)timeperf_counterrn   r$   sleeprm   loggerwarning)r.   current_time
sleep_times      r/   rs    _FPSController.wait_next_process   s     
 ((*   ($0! **\9
>--
+++ {T;;;!GVZHZ[^G__bcd(,(9(9(;% < ,s   AB,B*AB,c                     U R                   c   S5       eU R                  R                  [        R                  " 5       5        U =R                   U R
                  -  sl         g)z3Update timing information after processing a frame.Nz&wait_next_process must be called first)rn   rp   appendr   r   rl   rC   s    r/   rw   _FPSController.after_process   sR    $$0Z2ZZ0 	$$T%6%6%89 	!5!55r2   c                     U R                   $ r>   )rk   rC   s    r/   r   _FPSController.expected_fps   s    !!!r2   c                     [        U R                  5      S:  a  g[        U R                  5      S-
  U R                  S   U R                  S   -
  -  $ )zGet current average FPS.ri   r   r   )lenrp   rC   s    r/   rT   _FPSController.actual_fps   sU     t$$%)D))*Q.!!"%(=(=a(@@
 	
r2   )rk   ro   rl   rm   rn   rp   r]   )r^   r_   r`   ra   r'   r0   rt   r{   rK   rs   rw   rc   r   rT   rd   re   r2   r/   r)   r)      ss    OR S Su SW[ S('&<*6 "e " " 
E 
 
r2   r)   )r$   loggingr   collectionsr   typingr   r   video_framer   audio_framer   r   r	   r   r
   	getLoggerr^   r   r   r)   re   r2   r/   <module>r      sM        " # # % % 
		8	$mJ mJ`J
 J
r2   