
    iv                    h   S r 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rSSK	r	SSK
r
SSKrSSKJr  SSKJr  SSKJrJr  SSKrSSKJr  SS	KJrJrJr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$J%r%J&r&  SSK'J(r(  SSK)J*r*J+r+J,r,J-r-J.r.J/r/  SSK0J1r1  SSK2J3r3J4r4  Sr5Sr6Sr7Sr8Sr9Sr:Sr;Sr<Sr=Sr>Sr?Sr@SrA " S S\B5      rCS/S  jrD S0     S1S! jjrE\" S"S#9 " S$ S%5      5       rF\" S"S#9 " S& S'5      5       rG " S( S)\R                  5      rI " S* S+\
R                  \%5      rK " S, S-\5      rLS2S. jrMg)3a  
Module to interact with the ChromeCast via protobuf-over-socket.

Big thanks goes out to Fred Clift <fred@clift.org> who build the first
version of this code: https://github.com/minektur/chromecast-python-poc.
Without him this would not have been possible.
    )annotationsN)defaultdict)	dataclass)packunpack   )APP_AUDIBLE)MESSAGE_TYPEPLATFORM_DESTINATION_ID
REQUEST_ID
SESSION_ID)BaseControllerCallbackType)NS_HEARTBEATHeartbeatController)MediaController)
CastStatusCastStatusListenerReceiverController)get_host_from_service)ChromecastConnectionErrorChromecastConnectionClosedControllerNotRegisteredNotConnectedPyChromecastStoppedUnsupportedNamespace)CastMessage)HostServiceInfoMDNSServiceInfoz(urn:x-cast:com.google.cast.tp.connectionCONNECTCLOSELOAD
CONNECTING	CONNECTEDDISCONNECTEDFAILEDFAILED_RESOLVELOSTg      @g      >@c                      \ rS rSrSrSrg)InterruptLoopG   z)The chromecast has been manually stopped. N)__name__
__module____qualname____firstlineno____doc____static_attributes__r,       Q/home/sebas/venvs/catt/lib/python3.13/site-packages/pychromecast/socket_client.pyr*   r*   G   s    3r3   r*   c                    [         R                  " U R                  5      n[        U[        5      (       dC  [
        R                  " [        5      nUR                  SU R                  U R                  5        0 $ U$ ! [         aF    [
        R                  " [        5      nUR                  SU R                  U R                  5        0 s $ f = f)z$Parses a PB2 message as a JSON dict.z#Non dict json in namespace %s: '%s'z"Invalid json in namespace %s: '%s')jsonloadspayload_utf8
isinstancedictlogging	getLoggerr-   debug	namespace
ValueError)messagedataloggers      r4   _dict_from_message_payloadrC   K   s    zz'../$%%&&x0FLL5!!$$
 I ""8,0  	

 	s   A7A< :A< <ACCc           	         Uc  [        U 5      nSU R                   SU R                   SU R                   SU=(       d    U R                   3$ )z/Gives a string representation of a PB2 message.zMessage z from z to z: )rC   r>   	source_iddestination_idr8   )r@   rA   s     r4   _message_to_stringrG   b   s[    
 |)'2 7$$%VG,=,=+>d!!
""T%AW-A-A$B	Dr3   T)frozenc                  .    \ rS rSr% SrS\S'   S\S'   Srg)	NetworkAddressp   zNetwork address container.straddress
int | Noneportr,   Nr-   r.   r/   r0   r1   __annotations__r2   r,   r3   r4   rJ   rJ   p   s    $L
r3   rJ   c                  8    \ rS rSr% SrS\S'   S\S'   S\S'   S	rg
)ConnectionStatusx   zConnection status container.rL   statuszNetworkAddress | NonerM   z(HostServiceInfo | MDNSServiceInfo | Noneservicer,   NrP   r,   r3   r4   rS   rS   x   s    &K""55r3   rS   c                  @    \ rS rSrSr\R                  SS j5       rSrg)ConnectionStatusListener   z0Listener for receiving connection status events.c                    g)zUpdated connection status.Nr,   )selfrU   s     r4   new_connection_status.ConnectionStatusListener.new_connection_status   s    r3   r,   NrU   rS   returnNone)	r-   r.   r/   r0   r1   abcabstractmethodr\   r2   r,   r3   r4   rX   rX      s    :) )r3   rX   c                    ^  \ rS rSrSr              S U 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$S	 jr\S%S
 j5       r\S%S j5       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(S jrS)S jrSSSSS.               S*S jjrSSSS.           S+S jjrSSSS.           S+S jjrS,S jrS-S jrS-S jrS!S jrSrU =r$ ).SocketClient   a  
Class to interact with a Chromecast through a socket.

:param host: The host to connect to.
:param port: The port to use when connecting to the device, set to None to
             use the default of 8009. Special devices such as Cast Groups
             may return a different port number so we need to use that.
:param cast_type: The type of chromecast to connect to, see
                  dial.CAST_TYPE_* for types.
:param tries: Number of retries to perform if the connection fails.
              None for infinite retries.
:param timeout: A floating point number specifying the socket timeout in
                seconds. None means to use the default which is 30 seconds.
:param retry_wait: A floating point number specifying how many seconds to
                   wait between each retry. None means to use the default
                   which is 5 seconds.
:param services: A list of mDNS services to try to connect to. If present,
                 parameters host and port are ignored and host and port are
                 instead resolved through mDNS. The list of services may be
                 modified, for example if speaker group leadership is handed
                 over. SocketClient will catch modifications to the list when
                 attempting reconnect.
:param zconf: A zeroconf instance, needed if a list of services is passed.
              The zeroconf instance may be obtained from the browser returned by
              pychromecast.start_discovery().
c               p  > [         TU ]  5         SU l        [        R                  " [
        5      U l        SU l        Xl        S U l	        X l
        U=(       d    [        U l        U=(       d    [        U l        XPl        X`l        SU l        SU l        SU l        [(        R*                  " 5       U l        [.        R0                  " 5       U l        / U l        S U l        S U l        SU l        0 U l        / U l        SU l        SU l         S U l        [B        RD                  " 5       U l#        U RF                  RI                  U R0                  S   [B        RJ                  5      U l&        S U l'        [Q        [R        5      U l*        / U l+        [Y        U5      U l-        []        5       U l/        [a        5       U l1        U Re                  U Rb                  5        U Re                  [g        5       5        U Re                  U RZ                  5        U Re                  U R^                  5        U RZ                  Ri                  U 5        g )NTFunknowniI  zsender-0r   )5super__init__daemonr;   r<   r-   rB   _force_recon	cast_typefntriesTIMEOUT_TIMEtimeout
RETRY_TIME
retry_waitserviceszconfhostrO   rE   	threadingEventstopsocket
socketpairapp_namespacesrF   
session_id_request_id_request_callbacks_open_channels
connectingfirst_connection	selectorsDefaultSelectorselectorregister
EVENT_READwakeup_selector_keyremote_selector_keyr   set	_handlers_connection_listenersr   receiver_controllerr   media_controllerr   heartbeat_controllerregister_handlerConnectionControllerregister_status_listener)r[   rl   rn   rp   rr   rs   rt   	__class__s          r4   ri   SocketClient.__init__   s    	''1!""
.,$2
 
		#OO%	 ++-)+*.&*;=)+ $<@!113#'==#9#9OOA	 4 4$
  BF  :ES9IEG"#5i#@  / 1$7$9!d778245d667d334  99$?r3   c                  ^ U R                   nU R                  bM  U R                  R                  U R                  5        U R                  R	                  5         SU l        SU l        U R                  R                  5        H  nU" SS5        M     / U l        SU l	        SU l
        SU l        0 U l        / U l        SU l        U R                  R                  n0 m      SU4S jjnU R                   R#                  5       (       Gd  Ub  US:  Ga  U R$                  R'                  5        Vs0 s H  nUc  M  UT;   d  M  UTU   _M     snmU R$                  R'                  5        GH  n[(        R(                  " 5       nTR+                  X`R,                  US.5      nXxS   :  a  MA   U R                  bM  U R                  R                  U R                  5        U R                  R	                  5         SU l        SU l        [/        5       U l        U R                  R1                  U R                  [2        R4                  5      U l        U R                  R7                  U R8                  5        U R;                  [=        [>        [A        U RB                  U RD                  5      S5      5        Sn	Sn
[G        X`RH                  5      u  pnU	(       a  U
(       a  U(       a$   URJ                  S   RM                  S	5      U l'        U R                  RW                  S
U RN                  =(       d    SU RB                  U RD                  UU	U
5        Xl!        Xl"        OqU R                  RW                  SU RN                  =(       d    SU RB                  U RD                  U5        U R;                  [=        [X        SU5      5        U" Xh5        GMb  U R                  RW                  SU RN                  =(       d    SU RB                  U RD                  U RB                  U RD                  5        U R                  R[                  U RB                  U RD                  45        [\        R^                  " [\        R`                  5      nSUl1        [\        Rd                  Ul3        URi                  U R                  5      U l        SU l        SU l5        U R;                  [=        [l        [A        U RB                  U RD                  5      S5      5        U Rn                  Rq                  5         U Rr                  Ru                  5         U Rr                  Rw                  5         U Rx                  (       aM  SU l<        U R                  RW                  SU RN                  =(       d    SU RB                  U RD                  5        OEU R                  R{                  SU RN                  =(       d    SU RB                  U RD                  5          g   Ub  US:  a{  U R                  RW                  SU RN                  =(       d    SU RB                  U RD                  U R,                  U R$                  5        [(        R                  " U R,                  5        U(       a  US-  nU R                   R#                  5       (       d  Uc  GM  US:  a  GM  U R                   R                  5         U R                  R                  SU RN                  =(       d    SU RB                  U RD                  5        [        S5      es  snf ! [P        [R        [T        4 a     GN8f = f! [|        [~        4 Ga  nSU l        U R                   R#                  5       (       aR  U R                  R                  SU RN                  =(       d    SU RB                  U RD                  U5        [        S5      UeU R;                  [=        [        [A        U RB                  U RD                  5      S5      5        U" SU RN                  =(       d    SU RB                  U RD                  UUS   5        U" Xh5        U R                  RV                  n SnAGM  SnAff = f)z;Initialize a socket to a Chromecast, retrying as necessary.NFr   Tc                x   > [         R                   " 5       nX!S   -   US'   [        US   S-  S5      US'   UTU '   g)z4Exponentional backoff for service name mdns lookups.delay
next_retry   i,  N)timemin)rV   retrynowretriess      r4   mdns_backoff8SocketClient.initialize_connection.<locals>.mdns_backoff  sD    
 ))+C"%g"6E, w!!3S9E'N$GGr3   )r   r   r   s   fnzutf-8z([%s(%s):%s] Resolved service %s to %s:%s z([%s(%s):%s] Failed to resolve service %sz[%s(%s):%s] Connecting to %s:%sz[%s(%s):%s] Connected!z%[%s(%s):%s] Connection reestablished!z?[%s(%s):%s] Failed to connect: %s. aborting due to stop signal.zFailed to connectz>[%s(%s):%s] Failed to connect to service %s, retrying in %.1fsr   r   z;[%s(%s):%s] Not connected, sleeping for %.1fs. Services: %sz*[%s(%s):%s] Failed to connect. No retries.)rV   z!HostServiceInfo | MDNSServiceInfor   zdict[str, float]r_   r`   )Drn   ry   r   
unregistercloser   r~   valuesr{   rF   r|   r}   r   r   rB   errorrx   is_setrs   copyr   getrr   
new_socketr   r   r   
settimeoutrp   _report_connection_statusrS   CONNECTION_STATUS_CONNECTINGrJ   ru   rO   r   rt   
propertiesdecoderm   AttributeErrorKeyErrorUnicodeErrorr=    CONNECTION_STATUS_FAILED_RESOLVEconnectssl
SSLContextPROTOCOL_TLS_CLIENTcheck_hostname	CERT_NONEverify_modewrap_socketrk   CONNECTION_STATUS_CONNECTEDr   update_statusr   pingresetr   infoOSErrorr   r   CONNECTION_STATUS_FAILEDsleepr   )r[   rn   callback_functionretry_log_funr   keyrV   r   r   ru   rO   service_infocontexterrr   s                 @r4   initialize_connection"SocketClient.initialize_connection   s    

;;"MM$$T[[1KKDK'+D$ "&!8!8!?!?!AeT* "B !""$ )) NP	%6	%#	% 	% ))""$$%-519  ==--//C "(+w "WS\!/G  ==--/iikcJ |,,J6{{.00=))+&*370",,DK/3}}/E/EY%9%90D, KK**4<<822(8*499dii@   DD/D0,D '%*6*A*A%*H*O*OPW*X ))F GGMr II II#   %)	$(	))F GGMr II II# 66, @ $ ' %W4 !KK%%92								 KK''DII(>?!nnS-D-DEG-2G**---G'")"5"5dkk"BDK&+DO(-D%22(7*499dii@  ,,::<--224--335,,05-))4 GGMr II II	 ((C GGMr II II	 a 0h }	!!QGGMrIIIIOOMM 

4??+
Q ))""$$%-519T 			8GGMrIIII		
 ((;<<_X %3Hl#K % $%^  . 6&*DOyy''))))] GGMr II II 88KLRUU22(4*499dii@  "X2				g !0$(KK$5$5M96sX   /\ :\ 
\ +D6]"#\%C]H)]%\>:]=\>>]a)Da$$a)c                    U R                   R                  5          U R                  S   R                  S5        g! [        R
                   a     gf = f)z1Disconnect socket connection to Chromecast devicer      xN)rx   r   rz   sendry   r   r[   s    r4   
disconnectSocketClient.disconnect  sA    			OOA##D)|| 		s   ; AAc                v    U R                   UR                     R                  U5        UR                  U 5        gz!Register a new namespace handler.N)r   r>   add
registeredr[   handlers     r4   r   SocketClient.register_handler  s-    w(()--g64 r3   c                    UR                   U R                  ;   aD  XR                  UR                      ;   a(  U R                  UR                      R                  U5        UR                  5         gr   )r>   r   removeunregisteredr   s     r4   unregister_handlerSocketClient.unregister_handler  sT     />>'*;*;<<NN7,,-44W=r3   c                  ^  T R                   UR                  :g  nU(       a(  T R                   b  T R                  T R                   5        UR                  T l        UR                  T l         UR
                  T l        U(       Ga  T R                   b  [        U 4S jT R                   5       5      (       a_  T R                   T R                  ;  aE  UR                  [        :X  a1  T R                  R                  S5        [        R                  " S5        T R                   H_  nUT R                  ;   d  M  T R                  T R                   5        [!        T R                  U   5       H  nUR#                  5         M     Ma     ggg)z0Called when a new cast status has been received.Nc              3  @   >#    U  H  oTR                   ;   v   M     g 7fN)r   ).0r>   r[   s     r4   	<genexpr>/SocketClient.new_cast_status.<locals>.<genexpr>  s     UATI/ATs   z,Detected Audible connection. Sleeping for 1sr   )rF   transport_iddisconnect_channel
namespacesr{   r|   anyr   app_idr	   rB   r=   r   r   r   _ensure_channel_connectedr   channel_connected)r[   rU   new_channelr>   r   s   `    r4   new_cast_statusSocketClient.new_cast_status  s'   ))V-@-@@4..:##D$7$78$//$11 ++4..:
 UATATUUU''t/B/BBMM[0!!"PQ

1 "00	.2243F3FG#&t~~i'@#A113 $B 1 ;;r3   c                D    U =R                   S-  sl         U R                   $ )zGenerates a unique request id.r   )r}   r   s    r4   _gen_request_idSocketClient._gen_request_id  s    Ar3   c                $    U R                   (       + $ )zY
Returns True if the client is connected, False if it is stopped
(or trying to connect).
)r   r   s    r4   is_connectedSocketClient.is_connected  s     ??""r3   c                6    U R                   R                  5       $ )zJ
Returns True if the connection has been stopped, False if it is
running.
)rx   r   r   s    r4   
is_stoppedSocketClient.is_stopped	  s     yy!!r3   c           
         U R                  5         U R                  R                  5         U R                  R                  S5        U R                  R                  5       (       d8   U R                  5       S:X  a  O" U R                  R                  5       (       d  M8  U R                  R                  S5        U R'                  5         g! [         aA    U R                  [        [        [        U R                  U R                  5      S5      5         gf = f! [         aO    SU l        U R                  R#                  SU R$                  =(       d    SU R                  U R                  5         Nf = f)z1Connect to the cast and start polling the socket.NzThread started...r   TzF[%s(%s):%s] Unhandled exception in worker thread, attempting reconnectr   zThread done...)r   r   r   rS   CONNECTION_STATUS_DISCONNECTEDrJ   ru   rO   r   r   rB   r=   rx   r   	_run_once	Exceptionrk   	exceptionrm   _cleanupr   s    r4   runSocketClient.run  s&   
	&&( 	!!'')-.))""$$
>>#q( ) ))""$$ 	*+7 ) 	** 2"499dii8 	   $(!%%\GGMrIIII	s%   C
 'D 
ADDAE10E1c                j    U R                  5       (       d  g U R                  c   e U R                  R	                  [
        5      nU VVs1 s H  u  p4UiM	     nnnSnU R                  U;   a"  U R                  (       d   U R                  5       nU R4                  U;   a  U R6                  S   R9                  S5        U R"                  R%                  5       (       a  gU(       d  g[;        U5      nU R=                  Xg5        [>        U;   a@  U[>           U R@                  ;   a)  U R@                  RC                  U[>           5      " SU5        g! [         a     gf = f! [        [        4 aW  nU R                  R                  SU R                  =(       d    SU R                  U R                  U5        SU l         SnAgSnAff = fs  snnf ! [          a  nU R"                  R%                  5       (       aF  U R                  R'                  SU R                  =(       d    SU R                  U R                  5        OFU R                  R                  SU R                  =(       d    SU R                  U R                  U5         SnAgSnAf[(        R*                   aH  nUR,                  [(        R.                  :X  a$  U R"                  R%                  5       (       a   SnAge SnAf[0         aX  nSU l        U R                  R3                  S	U R                  =(       d    SU R                  U R                  U5         SnAGNSnAf[        R                   aX  nSU l        U R                  R                  S
U R                  =(       d    SU R                  U R                  U5         SnAGNSnAff = f)z(Receive from the socket and handle data.r   r   Nz$[%s(%s):%s] Error in select call: %sr   Tz9[%s(%s):%s] Stopped while reading message, disconnecting.z9[%s(%s):%s] Interruption caught without being stopped: %sz[%s(%s):%s] %sz)[%s(%s):%s] Error reading from socket: %s   )"_check_connectionr   ry   r   selectSELECT_TIMEOUTr?   r   rB   r   rm   ru   rO   rk   r   _read_messager*   rx   r   r   r   SSLErrorerrnoSSL_ERROR_EOFr   r=   r   rz   recvrC   _route_messager   r~   pop)r[   readyexcr   _can_readr@   rA   s           r4   r   SocketClient._run_once2  s   	))++ , {{&&&	MM((8E ',,eFCCe,##x/8I8I),,.T ##x/OOA##C( 99 *'2G*$z"2d6M6M"M##''Z(89$Eu ) 		 G$ 		KK62				 !%D		 - ! 99##%%KK$$S2					 KK%%S2				 << 99 1 11yy'')) - $(!!!$GGMrIIII  << $(!!!?GGMrIIII st   E E G	G 
EEG/AGG
N2B+J		N2 =K#"K##N20AMN2AN--N2c           	        SnU R                   (       aH  U R                  R                  SU R                  =(       d    SU R                  U R
                  5        SnOfU R                  R                  5       (       aG  U R                  R                  SU R                  =(       d    SU R                  U R
                  5        SnU(       a  U R                  R                  5         U R                   H  nU R                  U5        M     U R                  [        [        [!        U R                  U R
                  5      S5      5         U R#                  5         gg! [$         a    U R&                  R)                  5          gf = f)z
Checks if the connection is active, and if not reconnect

:return: True if the connection is active, False if the connection was
         reset.
Fz[%s(%s):%s] Forced reconnectionr   Tz3[%s(%s):%s] Heartbeat timeout, resetting connectionN)rk   rB   r=   rm   ru   rO   r   
is_expiredr   r   disconnectedr   r   r   rS   CONNECTION_STATUS_LOSTrJ   r   r   rx   r   )r[   r   channels      r4   r   SocketClient._check_connection  s+    KK12					 E&&1133KKE2					 E$$113..''0 /** *N499dii,PRV
 **,  -  		 s   E $E?>E?c                j   UR                   U R                  ;   GaT  UR                   [        :w  d8  U R                  R                  R                  [        R                  5      (       aO  U R                  R                  SU R                  =(       d    SU R                  U R                  [        X5      5        [        U R                  UR                      5       H  n UR                  X5      nU(       dv  UR                  [         5      U R"                  ;  aQ  U R                  R                  SU R                  =(       d    SU R                  U R                  [        X5      5        M  M  M     gU R                  R                  SU R                  =(       d    SU R                  U R                  [        X5      5        g! [$         ah    U R                  R'                  SU R                  =(       d    SU R                  U R                  [)        U5      R*                  [        X5      5         GMX  f = f)z6Route message to any handlers on the message namespacez[%s(%s):%s] Received: %sr   z![%s(%s):%s] Message unhandled: %szG[%s(%s):%s] Exception caught while sending message to controller %s: %sz*[%s(%s):%s] Received unknown namespace: %sN)r>   r   r   r   rB   isEnabledForr;   DEBUGr=   rm   ru   rO   rG   r   receive_messager   r   r~   r   r   typer-   )r[   r@   rA   r   handleds        r4   r  SocketClient._route_message  s    . !!\1,,33@@OO!!.GGMrIIII&w5 t~~g.?.?@A%55gDG"88J/t7N7NN KK-- C $2 $		 $		 27 A O #	 B6 KK<2				"71 ! KK))0 2				W..*79
 
s   B
G  A-H21H2c           	     J   U R                    H  n U R                  U5        M     U R                  R	                  5        H&  n[        U5       H  n UR                  5         M     M(     U R                  b   U R                  R                  5         U R                  [        [         [#        U R                  U R                  5      S5      5        U R$                  S   R                  5         U R$                  S   R                  5         U R&                  R                  5         SU l        g! [         a     GM-  f = f! [         a     M  f = f! [         aI    U R                  R                  SU R                  =(       d    SU R                  U R                  5         GNf = f)z"Cleanup open channels and handlersNz[%s(%s):%s] _cleanupr   r   r   T)r   r   r   r   r   r   	tear_downry   r   rB   r   rm   ru   rO   r   rS   r   rJ   rz   r   r   )r[   r  handlersr   s       r4   r   SocketClient._cleanup  sS   **G''0 + --/Hx=%%' ) 0 ;;"!!#
 	&&.tyy$))4	
 	  "  ";   !   %%*DGGMr499diis6   D,D>8E ,
D;:D;>
EEAF"!F"c                   U R                    Hy  n U R                  R                  SU R                  =(       d    SU R                  U R
                  [        U5      [        U5      R                  U5        UR                  U5        M{     g! [         aI    U R                  R                  SU R                  =(       d    SU R                  U R
                  5         M  f = f)z9Report a change in the connection status to any listenersz+[%s(%s):%s] connection listener: %x (%s) %sr   z=[%s(%s):%s] Exception thrown when calling connection listenerN)r   rB   r=   rm   ru   rO   idr  r-   r\   r   r   )r[   rU   listeners      r4   r   &SocketClient._report_connection_status  s    22H!!AGGMrIIIIxLN++ ..v6 3  %%SGGMrIIII	s   A5BACCc                   U R                   c   e/ nSnX1:  a  U R                  R                  5       (       a  [        S5      e U R                   R	                  [        X-
  S5      5      nUS:X  a  [        S5      eUR                  U5        U[        U5      -  nX1:  a  M  SR                  U5      $ ! [         aI    U R                  R                  SU R                  =(       d    SU R                  U R                  5         M  f = f)zRead bytes from the socket.r   z!Stopped while reading from socketi   r3   zConnection was closed by remotez0[%s(%s):%s] timeout in : _read_bytes_from_socketr   )ry   rx   r   r*   r  r   r   appendlenTimeoutErrorrB   r=   rm   ru   rO   join)r[   msglenchunks
bytes_recdchunks        r4   _read_bytes_from_socket$SocketClient._read_bytes_from_socket/  s     {{&&&
!yy!!#$GHH((V-@$)GHC<45VWWe$c%j(
 !" xx   !!FGGMrIIII	 s   AB3 3ADDc                    U R                  S5      n[        SU5      S   nU R                  U5      n[        5       nUR                  U5        U$ )z=Reads a message from the socket and converts it to a message.   >Ir   )r,  r   r   ParseFromString)r[   payload_inforead_lenpayloadr@   s        r4   r  SocketClient._read_messageI  sQ     33A6$-a0 ..x8-(r3   FN)inc_session_idr   no_add_request_idforcec          
        U R                  U5        U(       d  U R                  5       nX[        '   U(       a  U R                  U[        '   [        5       n	U	R                  U	l        U R                  U	l        Xl	        [
        R                  U	l        X)l        [        R                  " USS9U	l        [!        SU	R#                  5       5      n
U	R                  [$        :w  d8  U R&                  R(                  R+                  [,        R.                  5      (       aO  U R(                  R1                  SU R2                  =(       d    SU R4                  U R6                  [9        X5      5        U(       d:  U R:                  R=                  5       (       a  U(       a	  U" SS5        [?        S5      eU R@                  (       ds  U RB                  (       db  U RD                  c   e U(       a  U(       d  XPRF                  W'   O	U" SS5        U RD                  RI                  XRK                  5       -   5        gU(       a	  U" SS5        [S        S
U R4                   SU R6                   S35      e! [D        RL                   a  nU(       a	  U" SS5        U(       d  U RF                  RO                  WS5        SU l!        U R(                  RQ                  S	U R2                  =(       d    SU R4                  U R6                  U5         SnAgSnAff = f)z!Send a message to the Chromecast.F)ensure_asciir0  z[%s(%s):%s] Sending: %sr   Nz"Socket client's thread is stopped.Tz'[%s(%s):%s] Error writing to socket: %szChromecast :z is connecting...)*r   r   r   r|   r   r   
CASTV2_1_0protocol_versionrE   rF   STRINGpayload_typer>   r6   dumpsr8   r   ByteSizer   r   rB   r  r;   r  r=   rm   ru   rO   rG   rx   r   r   r   rk   ry   r~   sendallSerializeToStringr   r  warningr   )r[   rF   r>   rA   r6  r   r7  r8  
request_idmsgbe_sizer
  s               r4   send_messageSocketClient.send_messageX  s;   $ 	&&~6 --/J)#Dm"~~+&--!::d? tS\\^, MM\)((//<<W]]KKKK)2				"3- ))++ !%.%&JKKt'8'8;;***$,>O//
;)$5##G.C.C.E$EF !!%.TYYKqCTUVV! << $%eT2(++//
DA$(!##=GGMrIIII s   AI" "L 6B K;;L r6  r   r7  c          	     2    U R                  [        UUUUUS9$ )z0Helper method to send a message to the platform.rJ  )rH  r   r[   r>   r@   r6  r   r7  s         r4   send_platform_message"SocketClient.send_platform_message  s.       #)// ! 
 	
r3   c          	         XR                   ;  a:  U(       a	  U" SS5        [        SU SSR                  U R                   5       35      eU R                  c  U(       a	  U" SS5        [	        S5      eU R                  U R                  UUUUUS9$ )z7Helper method to send a message to current running app.FNz
Namespace z0 is not supported by current app. Supported are z, z8Attempting send a message when destination_id is not setrJ  )r{   r   r'  rF   r   rH  rL  s         r4   send_app_messageSocketClient.send_app_message  s     /// !%.&YK (!!%4+>+>!? @B 
 & !%.J    )// ! 
 	
r3   c                :    U R                   R                  U5        g)zRegister a connection listener for when the socket connection
changes. Listeners will be called with
listener.new_connection_status(status)N)r   r$  )r[   r!  s     r4   register_connection_listener)SocketClient.register_connection_listener  s     	""))(3r3   c                    XR                   ;  aI  U R                   R                  U5        U R                  U[        [        [
        S0 SSSSSSSS	S
S.0SS9  gg)z-Ensure we opened a channel to destination_id.origin	userAgentPyChromecast
senderInfor   z
15.605.1.3z44.0.2403.30r/  z Macintosh; Intel Mac OS X10_10_3r   )sdkTypeversionbrowserVersionplatformsystemVersionconnectionTypeT)r7  N)r   r$  rH  NS_CONNECTIONr
   TYPE_CONNECTr[   rF   s     r4   r   &SocketClient._ensure_channel_connected  ss    !4!44&&~6 ,b #$#/*8$%)K*+#	 #'!   5r3   c                   XR                   ;   aP   U R                  U[        [        [        S0 0SSS9  U R                   R                  U5        U R                  5         gg! [
         a     N9[         aH    U R                  R                  SU R                  =(       d    SU R                  U R                  5         Nf = f)z)Disconnect a channel with destination_id.rV  T)r7  r8  z[%s(%s):%s] Exceptionr   N)r   rH  r`  r
   
TYPE_CLOSEr   r   rB   r   rm   ru   rO   r   handle_channel_disconnectedrb  s     r4   r   SocketClient.disconnect_channel   s    000!!"!!:x<&* "  &&~6,,.% 1    %%+TWW]DIItyys   #A! !
B>-AB>=B>c                    U R                    HC  nXR                  ;   d  M  [        U R                  U   5       H  nUR                  5         M     ME     / U l         SU l        SU l        g)z%Handles a channel being disconnected.N)r{   r   r   channel_disconnectedrF   r|   )r[   r>   r   s      r4   rf  (SocketClient.handle_channel_disconnected  sY    ,,INN*"4>>)#<=G002  > -
 !"r3   ) r   rk   r   r   r~   r}   r{   rl   r   rj   rF   r   rm   r   ru   rB   r   rO   r   r   rr   r   rs   r|   ry   rz   rE   rx   rp   rn   r   rt   )rl   rL   rn   rN   rp   float | Nonerr   rk  rs   z&set[HostServiceInfo | MDNSServiceInfo]rt   zzeroconf.Zeroconf | Noner_   r`   r_   r`   )r   r   r_   r`   )rU   r   r_   r`   )r_   int)r_   bool)r@   r   rA   r:   r_   r`   r^   )r(  rm  r_   bytes)r_   r   )rF   rL   r>   rL   rA   r:   r6  rn  r   CallbackType | Noner7  rn  r8  rn  r_   r`   )r>   rL   r@   r:   r6  rn  r   rp  r7  rn  r_   r`   )r!  rX   r_   r`   )rF   rL   r_   r`   ) r-   r.   r/   r0   r1   ri   r   r   r   r   r   r   propertyr   r   r   r   r   r  r   r   r,  r  rH  rM  rP  rS  r   r   rf  r2   __classcell__r   s   @r4   rd   rd      s   8?@ ?@ 	?@
 ?@ !?@ 9?@ (?@ 
?@BX=	X=t!4>  # # " "BaF)V3j"H, 4*  %15"'SWSW SW 	SW SW /SW  SW SW 
SWt  %15"'

 

 
 /
  
 

0  %15"' 
 
  

  
 / 
   
 
 
D40/,	 	r3   rd   c                  :   ^  \ rS rSrSrSU 4S jjrSS jrSrU =r$ )r   i"  z-Controller to respond to connection messages.c                ,   > [         TU ]  [        5        g r   )rh   ri   r`  )r[   r   s    r4   ri   ConnectionController.__init__%  s    'r3   c                   U R                   c  [        eU R                   R                  (       a  gU[           [        :X  aJ  U R                   R                  UR                  5        U R                   R                  R                  5         gg)z^
Called when a message is received.

data is message.payload_utf8 interpreted as a JSON dict.
TF)	_socket_clientr   r   r
   re  r   rE   r   r   )r[   r@   rA   s      r4   r  $ConnectionController.receive_message(  so     &))))+2273D3DE 33AACr3   r,   rl  )r@   r   rA   r:   r_   rn  )	r-   r.   r/   r0   r1   ri   r  r2   rr  rs  s   @r4   r   r   "  s    7( r3   r   c                    [         R                   " [         R                  [         R                  5      n U R                  [         R                  [         R
                  S5         [         R                  n U R                  [         R                  US5        U $ ! [        [         R                  4 a*  nUR                  [        R                  :w  a  e  SnAU $ SnAff = f! [         a     U $ f = f)z
Create a new socket with OS-specific parameters

Try to set SO_REUSEPORT for BSD-flavored systems if it's an option.
Catches errors if not.
r   N)ry   AF_INETSOCK_STREAM
setsockopt
SOL_SOCKETSO_REUSEADDRSO_REUSEPORTr   r   r  ENOPROTOOPTr   )new_sock	reuseportr   s      r4   r   r   @  s     }}V^^V-?-?@H))6+>+>B''		 1 19a@ O & 	yyE--- . O	   Os*   $C 5!B C2CC
C-,C-)r@   r   r_   r:   r   )r@   r   rA   zdict | Noner_   rL   )r_   zsocket.socket)Nr1   
__future__r   ra   r  r6   r;   r   ry   r   rv   r   collectionsr   dataclassesr   structr   r   zeroconfconfigr	   constr
   r   r   r   controllersr   r   controllers.heartbeatr   r   controllers.mediar   controllers.receiverr   r   r   dialr   r   r   r   r   r   r   r   generated.cast_channel_pb2r   modelsr   r   r`  ra  re  	TYPE_LOADr   r   r   r   r   r  r  ro   rq   r   r*   rC   rG   rJ   rS   ABCrX   Threadrd   r   r   r,   r3   r4   <module>r     sV   # 
      
   # !    P P 5 D . T T '  4 4:
	  , ) !/ # #3   
4I 42 
 	 $   $6 6 6)sww )U9##%7 Up> <r3   