# # Copyright (c) 2024, Daily # # SPDX-License-Identifier: BSD 2-Clause License # import base64 import json from pipecat.frames.frames import AudioRawFrame, Frame from pipecat.serializers.base_serializer import FrameSerializer from pipecat.utils.audio import ulaw_8000_to_pcm_16000, pcm_16000_to_ulaw_8000 class TwilioFrameSerializer(FrameSerializer): SERIALIZABLE_TYPES = { AudioRawFrame: "audio", } def __init__(self, stream_sid: str): self._stream_sid = stream_sid def serialize(self, frame: Frame) -> str | bytes | None: if not isinstance(frame, AudioRawFrame): return None data = frame.audio serialized_data = pcm_16000_to_ulaw_8000(data) payload = base64.b64encode(serialized_data).decode("utf-8") answer = { "event": "media", "streamSid": self._stream_sid, "media": { "payload": payload } } return json.dumps(answer) def deserialize(self, data: str | bytes) -> Frame | None: message = json.loads(data) if message["event"] != "media": return None else: payload_base64 = message["media"]["payload"] payload = base64.b64decode(payload_base64) deserialized_data = ulaw_8000_to_pcm_16000(payload) audio_frame = AudioRawFrame(audio=deserialized_data, num_channels=1, sample_rate=16000) return audio_frame