
    /jB                       S SK Jr  S SKrS SKrS SKrS SKrS SKrS SKJrJ	r	J
r
  S SKJrJr  S SKJrJr  S SKrS SKJr  SSKJr  SS	KJr  SS
KJr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&  \RN                  " 5       r(\RR                  " \(RT                  5         " S S\RV                  5      r,\	\RZ                     \.-  \,-  r/ " S S\5      r0Sr1 " S S5      r2 " S S5      r3SS jr4g)    )annotationsN)AsyncGeneratorAsyncIterator	Generator)as_filefiles)Any
NamedTuple)rtc   )get_job_contextlogger)	NOT_GIVEN
NotGivenOr)is_givenlog_exceptions)cancel_and_waitaudio_frames_from_file   )AgentSession)AgentStateChangedEventc                  :    \ rS rSrSrSrSrSrSrSr	Sr
SS	 jrS
rg)BuiltinAudioClip   zcity-ambience.oggzforest-ambience.oggzoffice-ambience.oggzcrowded-room.oggzkeyboard-typing.oggzkeyboard-typing2.oggzhold_music.oggc                    [        S5      U R                  -  n[        [        R	                  [        U5      5      5      $ )Nzlivekit.agents.resources)r   valuestr_resource_stackenter_contextr   )self	file_paths     V/app/agent/.venv/lib/python3.13/site-packages/livekit/agents/voice/background_audio.pypathBuiltinAudioClip.path&   s1    45

B	?001CDEE     N)returnr   )__name__
__module____qualname____firstlineno__CITY_AMBIENCEFOREST_AMBIENCEOFFICE_AMBIENCECROWDED_ROOMKEYBOARD_TYPINGKEYBOARD_TYPING2
HOLD_MUSICr%   __static_attributes__r(   r'   r$   r   r      s,    'M+O+O%L+O-!JFr'   r   c                  @    \ rS rSr% SrS\S'   SrS\S'   SrS\S'   S	rg
)AudioConfig.   z
Definition for the audio to be played in the background

Args:
    volume: The volume of the audio (0.0-1.0)
    probability: The probability of the audio being played, when multiple
        AudioConfigs are provided (0.0-1.0)
AudioSourcesource      ?floatvolumeprobabilityr(   N)	r*   r+   r,   r-   __doc____annotations__r=   r>   r5   r(   r'   r$   r7   r7   .   s#     FEKr'   r7   i  c                  ,   \ rS rSr\\SS.       SS jjrSS jr    SS jrSS jrSS	.     SS
 jjr	\\S.       SS jjr
SS jrSS jrSS jr\" \S9          SS j5       r\" \S9SS j5       rSS jr\" \S9SS j5       rSrg) BackgroundAudioPlayerD      )ambient_soundthinking_soundstream_timeout_msc               h   [        U5      (       a  UOSU l        [        U5      (       a  UOSU l        [        R                  " SS[
        S9U l        [        R                  " SSSSUS9U l        SU l	        [        R                  " 5       U l        SU l        SU l        / U l        SU l        SU l        g)uk  
Initializes the BackgroundAudio component with optional ambient and thinking sounds.

This component creates and publishes a continuous audio track to a LiveKit room while managing
the playback of ambient and agent “thinking” sounds. It supports three types of audio sources:
- A BuiltinAudioClip enum value, which will use a pre-defined sound from the package resources
- A file path (string) pointing to an audio file, which can be looped.
- An AsyncIterator that yields rtc.AudioFrame

When a list (or AudioConfig) is supplied, the component considers each sound’s volume and probability:
- The probability value determines the chance that a particular sound is selected for playback.
- A total probability below 1.0 means there is a chance no sound will be selected (resulting in silence).

Args:
    ambient_sound (NotGivenOr[Union[AudioSource, AudioConfig, List[AudioConfig], None]], optional):
        The ambient sound to be played continuously. For file paths, the sound will be looped.
        For AsyncIterator sources, ensure the iterator is infinite or looped.

    thinking_sound (NotGivenOr[Union[AudioSource, AudioConfig, List[AudioConfig], None]], optional):
        The sound to be played when the associated agent enters a “thinking” state. This can be a single
        sound source or a list of AudioConfig objects (with volume and probability settings).

Ni  r   )queue_size_msi  )	blocksizecapacityrG   )r   _ambient_sound_thinking_soundr   r9   _AUDIO_SOURCE_BUFFER_MS_audio_source
AudioMixer_audio_mixerpublicationasyncioLock_lock_republish_task_mixer_atask_play_tasks_ambient_handle_thinking_handle)r"   rE   rF   rG   s       r$   __init__BackgroundAudioPlayer.__init__E   s    B 08/F/FmD19.1I1I~t __UAE\]NN1qDU
 >B\\^
:>7;572637r'   c                H   [        S U 5       5      nUS::  a  gUS:  a  [        R                  " 5       U:  a  gUS::  a  SOUn[        R                  " 5       [        US5      -  nSnU H1  nUR                  S::  a  M  UR                  U-  nXW-  nXE::  d  M/  Us  $    US   $ )z
Selects a sound from a list of BackgroundSound based on their probabilities.
Returns None if no sound is selected (when sum of probabilities < 1.0).
c              3  8   #    U  H  oR                   v   M     g 7fN)r>   ).0sounds     r$   	<genexpr>@BackgroundAudioPlayer._select_sound_from_list.<locals>.<genexpr>}   s     Fve 1 1vs   r   Nr;   g        )sumrandomminr>   )r"   soundstotal_probabilitynormalize_factorr
cumulativera   	norm_probs           r$   _select_sound_from_list-BackgroundAudioPlayer._select_sound_from_listx   s    
  FvFF!s"v}}9J'J"3s":3@QMMOc"3S99
E  A%)),<<I#J  bzr'   c                ^   Uc  g [        U[        5      (       a  U R                  U5      S4$ [        U[        5      (       a-  U R	                  U5      nUc  g UR
                  UR                  4$ [        U[        5      (       a'  U R                  UR
                  5      UR                  4$ US4$ )Nr;   )
isinstancer   _normalize_builtin_audiolistrn   r:   r=   r7   )r"   r:   selecteds      r$   _normalize_sound_source-BackgroundAudioPlayer._normalize_sound_source   s     >f.//008#==%%33F;H??HOO33,,00?NNs{r'   c                P    [        U[        5      (       a  UR                  5       $ U$ r_   )rq   r   r%   )r"   r:   s     r$   rr   .BackgroundAudioPlayer._normalize_builtin_audio   s!    f.//;;= Mr'   Floopc                 ^ ^^ T R                   (       d  [        S5      eT R                  U5      nUc  [        5       mTR	                  5         T$ Uu  pEU(       a   [        U[        5      (       a  [        S5      e[        5       m[        R                  " T R                  TXEU5      5      mTR                  U U4S j5        TR                  U4S j5        T R                  R                  T5        T$ )aQ  
Plays an audio once or in a loop.

Args:
    audio (Union[AudioSource, AudioConfig, List[AudioConfig]]):
        The audio to play. Can be:
        - A string pointing to a file path
        - An AsyncIterator that yields `rtc.AudioFrame`
        - An AudioConfig object with volume and probability
        - A list of AudioConfig objects, where one will be selected based on probability

        If a string is provided and `loop` is True, the sound will be looped.
        If an AsyncIterator is provided, it is played until exhaustion (and cannot be looped
        automatically).
    loop (bool, optional):
        Whether to loop the audio. Only applicable if `audio` is a string or contains strings.
        Defaults to False.

Returns:
    PlayHandle: An object representing the playback handle. This can be
    awaited or stopped manually.
zBackgroundAudio is not startedz}Looping sound via AsyncIterator is not supported. Use a string file path or your own 'infinite' AsyncIterator with loop=Falsec                :   > TR                   R                  T5      $ r_   )rX   remove)_r"   tasks    r$   <lambda>,BackgroundAudioPlayer.play.<locals>.<lambda>   s    )9)9)@)@)Fr'   c                $   > TR                  5       $ r_   )_mark_playout_done)r~   play_handles    r$   r   r      s    )G)G)Ir'   )rW   RuntimeErrorru   
PlayHandler   rq   r   
ValueErrorrS   create_task
_play_taskadd_done_callbackrX   append)r"   audiorz   
normalizedsound_sourcer=   r   r   s   `     @@r$   playBackgroundAudioPlayer.play   s    8   ?@@11%8
$,K**,)J|];; P  !l""4??;VZ#[\FGIJ%r'   )agent_sessiontrack_publish_optionsc                 #    U R                    ISh  vN   Xl        U=(       d    SU l        U=(       d    SU l         [	        5       nUR                  5       (       a  [        R                  " S5        U R                  5       I Sh  vN   [        R                  " U R                  5       5      U l        U R                  R                  SU R                  5        U R                  (       a&  U R                  R                  SU R                   5        U R"                  (       ar  U R%                  U R"                  5      nU(       aP  Uu  pg['        Xg5      n[)        U[*        5      (       a  U R-                  USS9U l        OU R-                  U5      U l        SSS5      ISh  vN   g GN! [         a     GNBf = f GN3 N! , ISh  vN  (       d  f       g= f7f)a  
Starts the background audio system, publishing the audio track
and beginning playback of any configured ambient sound.

If `ambient_sound` is provided (and contains file paths), they will loop
automatically. If `ambient_sound` contains AsyncIterators, they are assumed
to be already infinite or looped.

Args:
    room (rtc.Room):
        The LiveKit Room object where the audio track will be published.
    agent_session (NotGivenOr[AgentSession], optional):
        The session object used to track the agent's state (e.g., "thinking").
        Required if `thinking_sound` is provided.
    track_publish_options (NotGivenOr[rtc.TrackPublishOptions], optional):
        Options used when publishing the audio track. If not given, defaults will
        be used.
NzLBackground audio is not supported in console mode. Audio will not be played.reconnectedagent_state_changedTry   )rU   _room_agent_session_track_publish_optionsr   is_fake_jobr   warningr   _publish_trackrS   r   _run_mixer_taskrW   on_on_reconnected_agent_state_changedrL   ru   r7   rq   r   r   rY   )	r"   roomr   r   job_ctxr   r   r=   selected_sounds	            r$   startBackgroundAudioPlayer.start   s\    2 :::J"/"74D*?*G4D')+&&((NNf %%''' ' 3 3D4H4H4J KDJJMM-)=)=>""##&&'<d>W>WX""!99$:M:MN
+5(L%0%FN!,44/3yydy/S,/3yy/H,= ::    ( :::st   GF&G'F?5F)4F?F:DF?G F=!G)
F73F?6F77F?=G?GGGGc                  #    U R                    ISh  vN   U R                  (       d   SSS5      ISh  vN   g[        U R                  6 I Sh  vN   U R                  (       a  [        U R                  5      I Sh  vN   [        U R                  5      I Sh  vN   SU l        U R
                  R                  5       I Sh  vN   U R                  R                  5       I Sh  vN   U R                  (       a&  U R                  R                  SU R                  5        U R                  R                  SU R                  5        [        R                  " [        5         U R                   bA  U R                  R"                  R%                  U R                   R&                  5      I Sh  vN   SSS5        SSS5      ISh  vN   g GN GN GN GNU GN; GN N N1! , (       d  f       N5= f N,! , ISh  vN  (       d  f       g= f7f)zw
Gracefully closes the background audio system, canceling all ongoing
playback tasks and unpublishing the audio track.
Nr   r   )rU   rW   r   rX   rV   rQ   acloserO   r   offr   r   r   
contextlibsuppress	ExceptionrR   local_participantunpublish_tracksidr"   s    r$   r   BackgroundAudioPlayer.aclose  sc    
 :::$$ :: "4#3#3444##%d&:&:;;;!$"3"3444 $D##**,,,$$++---""##''(=t?X?XYJJNN=$*>*>?$$Y/##/**66FFtGWGWG[G[\\\ 0) :: 5 <4 -- ] 0/) :::s   HG
HG3HGHG3G-G3>G?G3G(G3G!G3&G'A;G3"A
G ,G-G 1G39HG1HHG3G3G3G3G3G  
G.	*G31H3H
9G<:H
Hc                    U R                   (       a  U R                   R                  5         S U l        [        R                  " U R                  5       5      U l         g r_   )rV   cancelrR   rS   r   _republish_track_taskr   s    r$   r   %BackgroundAudioPlayer._on_reconnected5  sA      '')&2243M3M3OPr'   c                b   U R                   (       d  g UR                  S:X  aa  U R                  (       a   U R                  R                  5       (       d  g U R                   c   eU R	                  U R                   5      U l        g U R                  (       a  U R                  R                  5         g g )Nthinking)rM   	new_staterZ   doner   stop)r"   evs     r$   r   *BackgroundAudioPlayer._agent_state_changed<  s    ##<<:%$$T-B-B-G-G-I-I''333$(IId.B.B$CD!""!!&&( #r'   r   c                J  ^^^^#    [        T[        5      (       a  TR                  5       m[        T[        5      (       a  U(       a  [	        T5      mO[        T5      mSmSUUUU4S jjnU" 5       n U R                  R                  U5        TR                  5       I S h  vN   U R                  R                  U5        TR                  5         [        R                  " S5      I S h  vN   TR                  R                  5       (       a>  Sm[        R                   " ["        5         UR%                  5       I S h  vN   S S S 5        g g  N Nd N! , (       d  f       g = f! U R                  R                  U5        TR                  5         [        R                  " S5      I S h  vN    TR                  R                  5       (       aP  Sm[        R                   " ["        5         UR%                  5       I S h  vN    S S S 5        f ! , (       d  f       f = ff = f7f)NFc                l  >#     T  S h  vN n T(       a    OTS:w  a  [         R                  " U R                  [         R                  S9R	                  [         R
                  5      nUS[         R                  " T5      -  -  n[         R                  " USSUS9  [        R                  " UR	                  [         R                  5      R                  5       U R                  U R                  U R                  S97v   M  U 7v   GM  TR                  5         g  GN
 N! TR                  5         f = f7f)Nr;   )dtype
   i i  )out)datasample_ratenum_channelssamples_per_channel)np
frombufferr   int16astypefloat32log10clipr   
AudioFrametobytesr   r   r   r   )framer   r   ra   stoppedr=   s     r$   _gen_wrapper6BackgroundAudioPlayer._play_task.<locals>._gen_wrapperY  s     1#( $%}!}}UZZrxxHOOPRPZPZ[rxx'7 88fe>!nn!%RXX!6!>!>!@(-(9(9).););050I0I	  $
 ..0)$5( ..0s=   D4D DDDC:D 	D4DD D11D4r   T)r)   $AsyncGenerator[rtc.AudioFrame, None])rq   r   r%   r   _loop_audio_framesr   rQ   
add_streamwait_for_playoutremove_streamr   rS   sleep	_stop_futr   r   r   r   r   )r"   r   ra   r=   rz   r   genr   s    ```   @r$   r    BackgroundAudioPlayer._play_taskJ  s     e-..JJLEeS!!*51.u5	1 	10 n	'((-..000++C0**,--"""$$))++((6**,&& 76 , 1
 #
 ' 76 ++C0**,--"""$$))++((6**,&& 766 ,s   A-H#4.E% "E#E% 'AH#+E,?H#+E?E E
H#E% H#E
E"H#%AH *F-+A H +H?H
 H	H 
HH  H#c                   #    U R                     S h  vN nU R                  R                  U5      I S h  vN   M.   N) N
 g 7fr_   )rQ   rO   capture_frame)r"   r   s     r$   r   %BackgroundAudioPlayer._run_mixer_task  s<     ,, 	:%$$225999	:9 -s1   AA=AA?AAAAc                0  #    U R                   b  g [        R                  R                  SU R                  5      nU R
                  R                  R                  XR                  =(       d    [        R                  " 5       5      I S h  vN U l         g  N
7f)Nbackground_audio)
rR   r   LocalAudioTrackcreate_audio_trackrO   r   r   publish_trackr   TrackPublishOptions)r"   tracks     r$   r   $BackgroundAudioPlayer._publish_track  sq     '##667I4K]K]^!%!=!=!K!K..K#2I2I2K"
 
 
s   BB	B
Bc                   #    U R                    IS h  vN   U R                  5       I S h  vN   S S S 5      IS h  vN   g  N- N N	! , IS h  vN  (       d  f       g = f7fr_   )rU   r   r   s    r$   r   +BackgroundAudioPlayer._republish_track_task  s9      :::%%''' ::' :::sQ   A!AA!AAAA!AA!AA!AAAA!)r   rY   rL   rQ   rO   rU   rW   rX   rV   r   rZ   rM   r   rR   N)rE   @NotGivenOr[AudioSource | AudioConfig | list[AudioConfig] | None]rF   r   rG   intr)   None)rh   zlist[AudioConfig]r)   zAudioConfig | None)r:   z4AudioSource | AudioConfig | list[AudioConfig] | Noner)   z tuple[AudioSource, float] | None)r:   r9   r)   z#AsyncIterator[rtc.AudioFrame] | str)r   z-AudioSource | AudioConfig | list[AudioConfig]rz   boolr)   r   )r   zrtc.Roomr   zNotGivenOr[AgentSession]r   z#NotGivenOr[rtc.TrackPublishOptions]r)   r   r)   r   )r   r   r)   r   )
r   r   ra   r9   r=   r<   rz   r   r)   r   )r*   r+   r,   r-   r   r[   rn   ru   rr   r   r   r   r   r   r   r   r   r   r   r   r5   r(   r'   r$   rB   rB   D   sL    [d !$18 X18
	18 18 
18f8J	)$ 	1<1 	1
 
1n 3<EN7I 7I 0	7I
  C7I 
7Ir]:Q) 6"3'%3'.93'CH3'PT3'	3' #3'j 6": #:
 6"( #(r'   rB   c                  P    \ rS rSrS
S jrSS jrS
S jrS
S jrSS jrS
S jr	Sr
g	)r   i  c                x    [         R                  S    " 5       U l        [         R                  S    " 5       U l        g r_   )rS   Future	_done_futr   r   s    r$   r[   PlayHandle.__init__  s(     -/ -/r'   c                6    U R                   R                  5       $ )z1
Returns True if the sound has finished playing.
)r   r   r   s    r$   r   PlayHandle.done  s     ~~""$$r'   c                   U R                  5       (       a  g[        R                  " [        R                  5         U R
                  R                  S5        U R                  5         SSS5        g! , (       d  f       g= f)z
Stops the sound from playing.
N)r   r   r   rS   InvalidStateErrorr   
set_resultr   r   s    r$   r   PlayHandle.stop  sP     99;;  !:!:;NN%%d+##% <;;s   ,A00
A>c                `   #    [         R                  " U R                  5      I Sh  vN   g N7f)z(
Waits for the sound to finish playing.
N)rS   shieldr   r   s    r$   r   PlayHandle.wait_for_playout  s      nnT^^,,,s   $.,.c                >   ^  SU 4S jjnU" 5       R                  5       $ )Nc                 D   >#    T R                  5       I S h  vN   T $  N7fr_   )r   r   s   r$   _await_impl)PlayHandle.__await__.<locals>._await_impl  s"     '')))K *s     )r)   r   )	__await__)r"   r   s   ` r$   r   PlayHandle.__await__  s    	 }&&((r'   c                    [         R                  " [        R                  5         U R                  R                  S 5        S S S 5        g ! , (       d  f       g = fr_   )r   r   rS   r   r   r   r   s    r$   r   PlayHandle._mark_playout_done  s4      !:!:;NN%%d+ <;;s   A


A)r   r   Nr   )r)   r   )r)   z Generator[Any, None, PlayHandle])r*   r+   r,   r-   r[   r   r   r   r   r   r5   r(   r'   r$   r   r     s     0%	&-),r'   r   c               L   #     [        U 5        S h  vN nU7v   M   N
 M   7fr_   r   )r#   r   s     r$   r   r     s)     
1)< 	%K	< s   $!!$!$)r#   r   r)   r   )5
__future__r   rS   atexitr   enumrf   collections.abcr   r   r   importlib.resourcesr   r   typingr	   r
   numpyr   livekitr   jobr   logr   typesr   r   utilsr   r   	utils.aior   utils.audior   r   r   eventsr   	ExitStackr    registercloseEnumr   r   r   r9   r7   rN   rB   r   r   r(   r'   r$   <module>r     s    "      D D . "   !  ) , ' 0 ' *&&( %% &Ftyy F CNN+c14DD* &  N( N(b
%, %,Pr'   