
    qi)                         d Z ddl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 ddlmZmZ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?Twilio Media Streams WebSocket protocol serializer for Pipecat.    N)Optional)logger)KeypadEntry)create_stream_resamplerpcm_to_ulawulaw_to_pcm)
AudioRawFrameCancelFrameEndFrameFrameInputAudioRawFrameInputDTMFFrameInterruptionFrameOutputTransportMessageFrame!OutputTransportMessageUrgentFrame
StartFrame)FrameSerializerc                        e Zd ZdZ G d dej
                        Z	 	 	 	 	 	 ddedee   dee   dee   d	ee   d
ee   dee   f 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 xZS )TwilioFrameSerializera  Serializer for Twilio Media Streams WebSocket protocol.

    This serializer handles converting between Pipecat frames and Twilio'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 Twilio call when an EndFrame or CancelFrame is processed, but requires Twilio
    credentials to be provided.
    c                   B    e Zd ZU dZdZeed<   dZee   ed<   dZ	e
ed<   y)!TwilioFrameSerializer.InputParamsa  Configuration parameters for TwilioFrameSerializer.

        Parameters:
            twilio_sample_rate: Sample rate used by Twilio, defaults to 8000 Hz.
            sample_rate: Optional override for pipeline input sample rate.
            auto_hang_up: Whether to automatically terminate call on EndFrame.
            ignore_rtvi_messages: Inherited from base FrameSerializer, defaults to True.
        i@  twilio_sample_rateNsample_rateTauto_hang_up)__name__
__module____qualname____doc__r   int__annotations__r   r   r   bool     L/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/serializers/twilio.pyInputParamsr   ,   s,    	 #'C&%)Xc])!d!r#   r%   N
stream_sidcall_sidaccount_sid
auth_tokenregionedgeparamsc                 F   t         	|   |xs t        j                                | j                  j
                  rtg }|s|j                  d       |s|j                  d       |s|j                  d       |rt        ddj                  |             |r|r|r|st        d| d| d      || _	        || _
        || _        || _        || _        || _        | j                  j                  | _        d	| _        t%               | _        t%               | _        d
| _        y)aG  Initialize the TwilioFrameSerializer.

        Args:
            stream_sid: The Twilio Media Stream SID.
            call_sid: The associated Twilio Call SID (optional, but required for auto hang-up).
            account_sid: Twilio account SID (required for auto hang-up).
            auth_token: Twilio auth token (required for auto hang-up).
            region: Twilio region (e.g., "au1", "ie1"). Must be specified with edge.
            edge: Twilio edge location (e.g., "sydney", "dublin"). Must be specified with region.
            params: Configuration parameters.
        r'   r(   r)   z9auto_hang_up is enabled but missing required parameters: z, zBoth edge and region parameters are required if one is set. Twilio's FQDN format requires both: api.{edge}.{region}.twilio.com. Got: region='z	', edge=''r   FN)super__init__r   r%   _paramsr   append
ValueErrorjoin_stream_sid	_call_sid_account_sid_auth_token_region_edger   _twilio_sample_rate_sample_rater   _input_resampler_output_resampler_hangup_attempted)
selfr&   r'   r(   r)   r*   r+   r,   missing_credentials	__class__s
            r$   r0   zTwilioFrameSerializer.__init__:   s'   * 	F#8#D#D#FG <<$$"$#**:6#**=9#**<8" OPTPYPYZmPnOop 
 tf $$*89TF!=  &!'%
#'<<#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)r1   r   audio_in_sample_rater<   )r@   rC   s     r$   setupzTwilioFrameSerializer.setupw   s%      !LL44R8R8Rs   +-returnc                   K   | j                   j                  rB| j                  s6t        |t        t
        f      r d| _        | j                          d{    yt        |t              r$d| j                  d}t        j                  |      S t        |t              r|j                  }t        ||j                  | j                  | j                          d{   }|t#        |      dk(  ryt%        j&                  |      j)                  d      }d| j                  d|id	}t        j                  |      S t        |t*        t,        f      r1| j/                  |      ryt        j                  |j0                        S y7 .7 w)
a  Serializes a Pipecat frame to Twilio WebSocket format.

        Handles conversion of various frame types to Twilio WebSocket messages.
        For EndFrames, 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.
        TNclear)event	streamSidr   zutf-8mediapayload)rJ   rK   rL   )r1   r   r?   
isinstancer   r
   _hang_up_callr   r5   jsondumpsr	   audior   r   r;   r>   lenbase64	b64encodedecoder   r   should_ignore_framemessage)r@   rC   answerdataserialized_datarM   s         r$   	serializezTwilioFrameSerializer.serialize   sV     LL%%**58["9:%)D"$$&&&01&T5E5EFF::f%%}-;;D %0e'')A)A4CYCY% O &#o*>!*C&&7>>wGG !--#W-F ::f%% ;=^_`''.::emm,, = 's&   AFFBFFB)FFc           
        K   	 ddl }| j                  }| j                  }| j                  }| j                  }| j
                  }|r| dnd}|r| dnd}d| | d| d| d}	|j                  ||      }
d	d
i}|j                         4 d{   }|j                  |	|
|      4 d{   }|j                  dk(  rt        j                  d|        n|j                  dk(  r	 |j                          d{   }|j                  d      dk(  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 d7 J7 7 7 # t        $ r Y w xY w7 7 j7 4# 1 d{  7  sw Y   Dx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 Twilio call using Twilio's REST API.r   N. zhttps://api.ztwilio.com/2010-04-01/Accounts/z/Calls/z.jsonStatus	completed)authrZ      z$Successfully terminated Twilio call i  codeiO  zTwilio call z was already terminatedz Failed to terminate Twilio call z	: Status z, Response: zFailed to hang up Twilio call: )aiohttpr7   r8   r6   r9   r:   	BasicAuthClientSessionpoststatusr   inforP   getdebug	Exceptiontexterror)r@   re   r(   r)   r'   r*   r+   region_prefixedge_prefixendpointrb   r,   sessionresponse
error_data
error_textes                    r$   rO   z#TwilioFrameSerializer._hang_up_call   s    5	@++K))J~~H\\F::D,2vhaLM(,TF!*"K &k]=/A`al`mmtu}t~  D  EH $$[*=D ,F ,,.  '"<<t&<I  X#-&J8*$UV!C/!/7}})>J)~~f5> &|H:E\-] ^ &     ? ,4==?%:
>xj I&&.oo%6l:,P ,4==?%:
>xj I&&.oo%6l:,P1    *?  ) ! ! &; &;/      <  	@LL:1#>??	@sV  I-B
H? G2H? H*+G5,H*/8H(G>;G8<1G>.H*9G::H*>H? 	G<
H? I-H#H$A H$H%,HH*HH*!H? ,H(-H? 1I-2H? 5H*8G>:H*<H? >	H
H	H

HHH*H%	HH%	!H*(H? *H<0H31H<8H? ;I-<H? ?	I*I% I-%I**I-rZ   c                   K   t        j                  |      }|d   dk(  r||d   d   }t        j                  |      }t	        || j
                  | j                  | j                         d{   }|t        |      dk(  ryt        |d| j                        }|S |d   dk(  r6|j                  di       j                  d	      }	 t        t        |            S y7 n# t        $ r
}Y d}~yd}~ww xY ww)
a<  Deserializes Twilio WebSocket data to Pipecat frames.

        Handles conversion of Twilio media events to appropriate Pipecat frames.

        Args:
            data: The raw WebSocket data from Twilio.

        Returns:
            A Pipecat frame corresponding to the Twilio event, or None if unhandled.
        rJ   rL   rM   Nr      )rR   num_channelsr   dtmfdigit)rP   loadsrT   	b64decoder   r;   r<   r=   rS   r   rk   r   r   r3   )	r@   rZ   rX   payload_base64rM   deserialized_dataaudio_framer|   rw   s	            r$   deserializez!TwilioFrameSerializer.deserialize   s     **T"7w&$W-i8N&&~6G '21143D3DdF[F[' ! !(C0A,Ba,G,'aTEVEVK W'KK+//8E%k%&899
 )!   s7   A*C3,C-AC3C C3	C0&C3+C00C3)NNNNNN)r   r   r   r   r   r%   strr   r0   r   rF   r   bytesr\   rO   r   __classcell__)rB   s   @r$   r   r       s    	"o11 "" #'%)$( $"(,;';' 3-;' c]	;'
 SM;' ;' sm;' %;'zS S0U 0sU{T/A 0d7@r&cEk &edl &r#   r   )r   rT   rP   typingr   logurur   pipecat.audio.dtmf.typesr   pipecat.audio.utilsr   r   r   pipecat.frames.framesr	   r
   r   r   r   r   r   r   r   r   #pipecat.serializers.base_serializerr   r   r"   r#   r$   <module>r      sC    F     0 Q Q   @pO pr#   