Overview

DailyTransport provides real-time audio and video communication capabilities using Daily’s hosted WebRTC platform. It supports bidirectional audio/video streams, transcription, voice activity detection, participant management, and advanced features like dial-in/out and recording without requiring your own WebRTC infrastructure.

Installation

To use DailyTransport, install the required dependencies:
pip install "pipecat-ai[daily]"
You’ll also need to set up your Daily API key as an environment variable: DAILY_API_KEY.
Get your API key by signing up at Daily Dashboard.

Frames

Input

  • InputAudioRawFrame - Audio data from room participants
  • UserImageRawFrame - Video frames from participant cameras
  • TranscriptionFrame - Final speech transcriptions
  • InterimTranscriptionFrame - Real-time transcription updates
  • TransportMessageUrgentFrame - Application messages from participants

Output

  • OutputAudioRawFrame - Audio data to room participants
  • OutputImageRawFrame - Video frames to participants
  • OutputDTMFFrame - DTMF tones for phone calls
  • TransportMessageFrame - Application messages to participants
  • TransportMessageUrgentFrame - Urgent messages to participants

Key Features

  • Hosted WebRTC: No infrastructure setup required - Daily handles all WebRTC complexity
  • Multi-participant Support: Handle multiple participants with individual audio/video tracks
  • Built-in Transcription: Real-time speech-to-text with Deepgram integration
  • Dial-in/Dial-out: Connect to phone numbers via SIP/PSTN
  • Recording & Streaming: Built-in call recording and live streaming capabilities
  • Advanced Controls: Participant management, permissions, and media routing

Usage Example

import os
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.pipeline.pipeline import Pipeline
from pipecat.transports.services.daily import DailyTransport, DailyParams

async def main():
    # Create or get a Daily room (see Room Creation section below)
    room_url = "https://your-domain.daily.co/room-name"
    token = "your-meeting-token"  # Created via Daily API

    # Configure the transport
    transport = DailyTransport(
        room_url=room_url,
        token=token,
        bot_name="AI Assistant",
        params=DailyParams(
            audio_in_enabled=True,
            audio_out_enabled=True,
            transcription_enabled=True,  # Enable real-time transcription
            vad_analyzer=SileroVADAnalyzer(),
        ),
    )

    # Your services (STT, LLM, TTS, etc.)
    # ...

    # Create pipeline
    pipeline = Pipeline([
        transport.input(),              # Receive audio/video from participants
        # ... your processing chain
        transport.output(),             # Send audio/video to participants
    ])

    # Event handlers
    @transport.event_handler("on_client_connected")
    async def on_client_connected(transport, client):
        logger.info(f"Client connected")
         # Enable transcription for the participant
        await transport.capture_participant_transcription(participant["id"])
        # Start the conversation
        messages.append({"role": "system", "content": "Please introduce yourself to the user."})
        await task.queue_frames([context_aggregator.user().get_context_frame()])

    @transport.event_handler("on_client_disconnected")
    async def on_client_disconnected(transport, client):
        logger.info(f"Client disconnected")
        await task.cancel()  # End the session

    # Run the pipeline
    # ...

Room Creation

Daily rooms must be created before connecting. Pipecat’s development runner provides a helper function to create room URL, token, and room name:
import aiohttp
from pipecat.runner.daily import configure

async def create_room():
    async with aiohttp.ClientSession() as session:
        # This helper creates a room and token automatically
        room_url, token = await configure(session)
        return room_url, token
Or manually via Daily REST API:
import aiohttp
from pipecat.transports.services.helpers.daily_rest import DailyRESTHelper

async def create_room_manual():
    daily_helper = DailyRESTHelper(
        daily_api_key=os.getenv("DAILY_API_KEY"),
        aiohttp_session=session
    )

    # Create room
    room = await daily_helper.create_room()
    room_url = room["url"]

    # Create token with permissions
    token = await daily_helper.get_token(room_url, expiry_time=3600)

    return room_url, token

Methods

DailyTransport provides comprehensive methods for controlling calls and participants:

Room Management

  • participants() - Get current participants in the room
  • participant_counts() - Get participant count statistics
  • send_message() - Send messages to participants

Media Control

  • send_image() - Send image frames to the room
  • send_audio() - Send audio frames to the room
  • capture_participant_video() - Capture video from specific participants
  • capture_participant_audio() - Capture audio from specific participants

Transcription Control

  • capture_participant_transcription() - Enable transcription for participants
  • start_transcription() - Start room-wide transcription
  • stop_transcription() - Stop transcription
  • update_transcription() - Update transcription settings

Recording Control

  • start_recording() - Start recording the call
  • stop_recording() - Stop active recordings

Dial Control

  • start_dialout() - Initiate dial-out calls
  • stop_dialout() - Stop dial-out calls
  • send_dtmf() - Send DTMF tones
  • sip_call_transfer() - Transfer SIP calls
  • sip_refer() - Send SIP REFER requests

Participant Management

  • update_remote_participants() - Control participant permissions and settings
  • update_subscriptions() - Manage media subscriptions
  • update_publishing() - Control media publishing settings

Chat & Messaging

  • send_prebuilt_chat_message() - Send messages to Daily Prebuilt chat
For complete method signatures, parameters, and examples, see the DailyTransport API reference.

Example Usage

# Capture participant media
await transport.capture_participant_transcription("participant-123")
await transport.capture_participant_video("participant-123", framerate=30)

# Control participant permissions
await transport.update_remote_participants({
    "participant-123": {
        "inputsEnabled": {"microphone": False}
    }
})

# Start recording
await transport.start_recording({
    "rtmpUrl": "rtmp://your-server.com/live/stream"
})

Event Handling

DailyTransport provides comprehensive event callbacks organized by category. Register callbacks using the @transport.event_handler() decorator:

Connection Events

  • on_joined - Bot successfully joined the room
  • on_left - Bot left the room
  • on_call_state_updated - Call state changes
  • on_error - Transport errors occur

Participant Events

  • on_first_participant_joined - First participant joins (useful for starting conversations)
  • on_participant_joined - Any participant joins
  • on_participant_left - Participant leaves
  • on_participant_updated - Participant information changes
  • on_client_connected - Client (participant) connects
  • on_client_disconnected - Client (participant) disconnects
  • on_active_speaker_changed - Active speaker changes

Communication Events

  • on_app_message - Application messages received
  • on_transcription_message - Speech transcription received

Dial Events

  • on_dialin_* - Dial-in connection events (ready, connected, stopped, error, warning)
  • on_dialout_* - Dial-out call events (answered, connected, stopped, error, warning)

Recording Events

  • on_recording_started - Recording begins
  • on_recording_stopped - Recording ends
  • on_recording_error - Recording errors
For complete event details, parameters, and examples, see the DailyTransport API reference.

Example Usage

@transport.event_handler("on_transcription_message")
async def on_transcription(transport, message):
    text = message["text"]
    participant_id = message["participantId"]
    is_final = message["rawResponse"]["is_final"]
    print(f"Transcription from {participant_id}: {text}")

@transport.event_handler("on_recording_started")
async def on_recording_started(transport, status):
    print(f"Recording started: {status}")

@transport.event_handler("on_dialout_answered")
async def on_dialout_answered(transport, data):
    print(f"Dial-out call answered: {data}")

Additional Notes

  • Scalability: Daily handles the WebRTC infrastructure, supporting many concurrent rooms
  • Global Infrastructure: Daily’s global edge network ensures low latency worldwide
  • Enterprise Features: Advanced routing, analytics, and compliance features available
  • Browser Compatibility: Works with all modern browsers via Daily’s client SDKs
  • Mobile Support: Native iOS and Android SDKs available for mobile applications
  • SIP Integration: Enterprise-grade phone system integration with dial-in/out capabilities
The hosted nature of Daily makes it ideal for production applications where you want professional WebRTC infrastructure without the operational complexity.