
    qiq)                         d Z ddlZddlZddlmZ ddlZddlmZ ddlm	Z	 ddl
mZ ddlmZmZmZmZmZ ddlmZmZmZmZmZmZmZmZ dd	lmZ  G d
 de      Zy)z.Telnyx WebSocket frame serializer for Pipecat.    N)Optional)logger)	BaseModel)KeypadEntry)alaw_to_pcmcreate_stream_resamplerpcm_to_alawpcm_to_ulawulaw_to_pcm)AudioRawFrameCancelFrameEndFrameFrameInputAudioRawFrameInputDTMFFrameInterruptionFrame
StartFrame)FrameSerializerc                       e Zd ZdZ G d de      Z	 	 	 ddedededee   d	ee   d
ee   fdZde	fdZ
dedeez  dz  fdZd Zdeez  dedz  fdZy)TelnyxFrameSerializera  Serializer for Telnyx WebSocket protocol.

    This serializer handles converting between Pipecat frames and Telnyx's WebSocket
    media streams protocol. It supports audio conversion, DTMF events, and automatic
    call termination.

    When auto_hang_up is enabled (default), the serializer will automatically terminate
    the Telnyx call when an EndFrame or CancelFrame is processed, but requires Telnyx
    credentials to be provided.
    c                   ^    e Zd ZU dZdZeed<   dZee   ed<   dZ	e
ed<   dZe
ed<   d	Zeed
<   y)!TelnyxFrameSerializer.InputParamsa  Configuration parameters for TelnyxFrameSerializer.

        Parameters:
            telnyx_sample_rate: Sample rate used by Telnyx, defaults to 8000 Hz.
            sample_rate: Optional override for pipeline input sample rate.
            inbound_encoding: Audio encoding for data sent to Telnyx (e.g., "PCMU").
            outbound_encoding: Audio encoding for data received from Telnyx (e.g., "PCMU").
            auto_hang_up: Whether to automatically terminate call on EndFrame.
        i@  telnyx_sample_rateNsample_ratePCMUinbound_encodingoutbound_encodingTauto_hang_up)__name__
__module____qualname____doc__r   int__annotations__r   r   r   strr   r   bool     L/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/serializers/telnyx.pyInputParamsr   2   sB    	 #'C&%)Xc]) &#&!'3'!d!r(   r*   N	stream_idr   r   call_control_idapi_keyparamsc                 :   || _         || _        || _        |xs t        j	                         | _        || j
                  _        || j
                  _        | j
                  j                  | _	        d| _
        t               | _        t               | _        d| _        y)a  Initialize the TelnyxFrameSerializer.

        Args:
            stream_id: The Stream ID for Telnyx.
            outbound_encoding: The encoding type for outbound audio (e.g., "PCMU").
            inbound_encoding: The encoding type for inbound audio (e.g., "PCMU").
            call_control_id: The Call Control ID for the Telnyx call (optional, but required for auto hang-up).
            api_key: Your Telnyx API key (required for auto hang-up).
            params: Configuration parameters.
        r   FN)
_stream_id_call_control_id_api_keyr   r*   _paramsr   r   r   _telnyx_sample_rate_sample_rater   _input_resampler_output_resampler_hangup_attempted)selfr+   r   r   r,   r-   r.   s          r)   __init__zTelnyxFrameSerializer.__init__C   s    & $ /D!6!B!B!D):&(8%#'<<#B#B  7 9!8!:!&r(   framec                 ^   K   | j                   j                  xs |j                  | _        yw)zSets up the serializer with pipeline configuration.

        Args:
            frame: The StartFrame containing pipeline configuration.
        N)r3   r   audio_in_sample_rater5   )r9   r;   s     r)   setupzTelnyxFrameSerializer.setupd   s%      !LL44R8R8Rs   +-returnc                 t  K   | j                   j                  rB| j                  s6t        |t        t
        f      r d| _        | j                          d{    yt        |t              rddi}t        j                  |      S t        |t              r|j                  }| j                   j                  dk(  r5t        ||j                  | j                  | j                          d{   }np| j                   j                  dk(  r5t#        ||j                  | j                  | j                          d{   }n"t%        d| j                   j                         |t'        |      dk(  ryt)        j*                  |      j-                  d	      }d
d|id}t        j                  |      S y7 \7 7 ~w)a  Serializes a Pipecat frame to Telnyx WebSocket format.

        Handles conversion of various frame types to Telnyx WebSocket messages.
        For EndFrames and CancelFrames, initiates call termination if auto_hang_up is enabled.

        Args:
            frame: The Pipecat frame to serialize.

        Returns:
            Serialized data as string or bytes, or None if the frame isn't handled.

        Raises:
            ValueError: If an unsupported encoding is specified.
        TNeventclearr   PCMAUnsupported encoding: r   zutf-8mediapayload)rA   rE   )r3   r   r8   
isinstancer   r   _hang_up_callr   jsondumpsr   audior   r
   r   r4   r7   r	   
ValueErrorlenbase64	b64encodedecode)r9   r;   answerdataserialized_datarF   s         r)   	serializezTelnyxFrameSerializer.serializel   s      LL%%**58["9:%)D"$$&&&01w'F::f%%}-;;D ||,,6(3%++T-E-EtG]G]) # ..&8(3%++T-E-EtG]G]) # !#9$,,:W:W9X!YZZ&#o*>!*C&&7>>wGG #W-F
 ::f%% C '##s9   AF8F1BF8)F4*AF87F68A:F84F86F8c           
        K   	 | j                   }| j                  }|r|st        j                  d       yd| d}dd| d}t	        j
                         4 d{   }|j                  ||      4 d{   }|j                  d	k(  rt        j                  d
|        n|j                  dk(  r	 |j                          d{   }t        d |j                  dg       D              r;t        j                  d| d       	 ddd      d{    ddd      d{    y	 |j                          d{   }t        j                  d| d|j                   d|        n@|j                          d{   }t        j                  d| d|j                   d|        ddd      d{    ddd      d{    y7 r7 Y7 7 7 # t        $ r Y w xY w7 7 k7 5# 1 d{  7  sw Y   ExY w7 <# 1 d{  7  sw Y   yxY w# t        $ r"}	t        j                  d|	        Y d}	~	yd}	~	ww xY ww)z0Hang up the Telnyx call using Telnyx's REST API.zHCannot hang up Telnyx call: call_control_id and api_key must be providedNz https://api.telnyx.com/v2/calls/z/actions/hangupzapplication/jsonzBearer )zContent-TypeAuthorization)headers   z$Successfully terminated Telnyx call i  c              3   D   K   | ]  }|j                  d       dk(    yw)code90018N)get).0errors     r)   	<genexpr>z6TelnyxFrameSerializer._hang_up_call.<locals>.<genexpr>   s&      #$) !&		& 1W <#s    errorszTelnyx call z was already terminatedz Failed to terminate Telnyx call z	: Status z, Response: zFailed to hang up Telnyx call: )r1   r2   r   warningaiohttpClientSessionpoststatusinforI   anyr\   debug	Exceptiontextr^   )
r9   r,   r-   endpointrW   sessionresponse
error_data
error_textes
             r)   rH   z#TelnyxFrameSerializer._hang_up_call   s[    5	@"33OmmG"'^  :/9J/ZH (:gV]U^L_`G ,,. ! !'"<<'<B    h#-&J?J[$\]!C/!/7}})>J" #-7^^Hb-I#   !'&2?2CCZ$[!" !'!   ! ! !  ,4==?%:
>>O P&&.oo%6l:,P ,4==?%:
>>O P&&.oo%6l:,P;   ! ! !  *? !$  ) ! ! &; &;9       ! ! ! !F  	@LL:1#>??	@s_  I
1H I
&H GH  H8G9H<9G06G	G
?G
HGHH %G&H *I
+G0?G* A G0 G,,G0-H8G.9H=H H	H I
H HGHH 	G'$G0&G''G0,G0.H0H	6G97H	>HH HHHH I
H 	I%I=I
II
rR   c                   K   t        j                  |      }|d   dk(  r|d   d   }t        j                  |      }| j                  j
                  dk(  r5t        || j                  | j                  | j                         d{   }np| j                  j
                  dk(  r5t        || j                  | j                  | j                         d{   }n"t        d| j                  j
                         |t        |      dk(  ryt        |d	| j                  
      }|S |d   dk(  r6|j                  di       j                  d      }	 t        t!        |            S y7 7 # t        $ r
}Y d}~yd}~ww xY ww)a  Deserializes Telnyx WebSocket data to Pipecat frames.

        Handles conversion of Telnyx media events to appropriate Pipecat frames,
        including audio data and DTMF keypresses.

        Args:
            data: The raw WebSocket data from Telnyx.

        Returns:
            A Pipecat frame corresponding to the Telnyx event, or None if unhandled.

        Raises:
            ValueError: If an unsupported encoding is specified.
        rA   rE   rF   r   NrC   rD   r      )rK   num_channelsr   dtmfdigit)rI   loadsrN   	b64decoder3   r   r   r4   r5   r6   r   rL   rM   r   r\   r   r   )	r9   rR   messagepayload_base64rF   deserialized_dataaudio_frameru   rp   s	            r)   deserializez!TelnyxFrameSerializer.deserialize   s}     **T"7w&$W-i8N&&~6G ||--7*5,,%%))	+ %! //69*5,,%%))	+ %! !#9$,,:X:X9Y!Z[[ (C0A,Ba,G,'aTEVEVK W'KK+//8E%k%&899
 C%%,  sJ   BF E&AF E(A;F E* $F (F *	E=3F 8E==F )NNN)r   r    r!   r"   r   r*   r%   r   r:   r   r>   r   bytesrT   rH   r|   r'   r(   r)   r   r   &   s    	"i ", *.!%(,'' ' 	'
 "#' #' %'BS S6U 6sU{T/A 6p7@r8cEk 8edl 8r(   r   )r"   rN   rI   typingr   rb   logurur   pydanticr   pipecat.audio.dtmf.typesr   pipecat.audio.utilsr   r   r	   r
   r   pipecat.frames.framesr   r   r   r   r   r   r   r   #pipecat.serializers.base_serializerr   r   r'   r(   r)   <module>r      sL    5       0 	 	 	 @oO or(   