Skip to content

Streams

StreamConnector is the SDK primitive for building a Bridge. It connects two WebSockets, Teler’s call audio stream and your AI provider’s WebSocket, and relays messages between them through pluggable handlers.

Your flow_url endpoint returns a Stream flow when it wants Teler to open a WebSocket. Use CallFlow.stream() to build the JSON.

ParameterSDKDefaultNotes
ws_url / first argbothnonewss:// URL (TLS only).
chunk_size / chunkSizeboth400Audio chunk size. The SDK does not validate the value; the media pipeline expects a multiple of 20.
recordbothtrueWhether to record the streamed leg.
sampleRateboth"8k""8k" or "16k".
from teler import CallFlow
flow = CallFlow.stream(
ws_url="wss://your-domain.com/media-stream",
chunk_size=500,
sample_rate="8k",
record=True,
)

StreamConnector runs two coroutines/promises concurrently: one reading the call WebSocket, one reading the remote WebSocket. Each handler decides what to do with every message: relay it, drop it, or stop the stream.

The constructors take the same concepts but with significant differences:

  • Python uses keyword arguments (e.g., remote_url=, stream_type=)
  • Node uses positional arguments with different order: remoteUrl is first, followed by streamType, handlers, headers, and optional timeout configuration. Node also requires handlers explicitly (Python defaults to relay-all) and supports custom headers and connection timeout.
PurposePython (keyword)Node (positional order)Notes
Remote WebSocket URLremote_url1st: remoteUrlRequired. Empty/unparseable raises BadParametersException.
Teler → remote handlercall_stream_handler2nd: callStreamHandlerPython defaults to relay-all; Node requires it.
Remote → Teler handlerremote_stream_handler3rd: remoteStreamHandlerPython defaults to relay-all; Node requires it.
Stream directionstream_type4th: streamTypeDefaults to BIDIRECTIONAL. UNIDIRECTIONAL raises NotImplementedException.
Remote WS headers—5th: headersNode only. Defaults to {}. Custom headers for the remote WebSocket connection.
Connection timeout—Node only (via constructor config)Node supports connectTimeoutMs (milliseconds). Controls how long to wait for the remote WebSocket to connect before timing out. Python has no timeout configuration.
from teler import StreamConnector, StreamOp
from teler.streams import StreamType
connector = StreamConnector(
stream_type=StreamType.BIDIRECTIONAL,
remote_url="wss://your-ai-provider.example.com",
call_stream_handler=...,
remote_stream_handler=...,
)

Every handler returns (data, StreamOp). The op tells the connector what to do with data. The enum is named StreamOp in Python and StreamOP in Node.

OpEffect
RELAYForward to the other WebSocket.
PASSNot forwarded. (Effectively drops the message; only RELAY and STOP are acted on.)
STOPClose the WebSocket(s) cleanly and stop the bridge.
# Relay everything (default)
async def relay(message: str):
return (message, StreamOp.RELAY)

Handlers are async. Python takes a raw JSON string; Node takes a structured StreamData object. Both must return a 2-tuple of (data, StreamOp).

Returning the wrong shape raises BadParametersException (Python) or TelerException (Node). See Errors for the full SDK exception mapping.

from typing import Tuple
from teler import StreamOp
async def my_handler(message: str) -> Tuple[str, StreamOp]:
# `message` is the raw JSON from the WebSocket.
return (message, StreamOp.RELAY)

The connector races both directions and exits when either side completes: caller hangs up, provider closes, or a handler returns STOP.

# Inside your /media-stream WebSocket handler
await connector.bridge_stream(call_ws)

Drop-in starting point for any recipe. Single column here, full file shown.

import asyncio
from fastapi import FastAPI, WebSocket
from teler import StreamConnector, StreamOp, CallFlow
app = FastAPI()
@app.post("/flow")
async def flow():
return CallFlow.stream(
ws_url="wss://your-domain.com/media-stream",
chunk_size=400,
record=True,
)
async def relay(message: str):
return (message, StreamOp.RELAY)
@app.websocket("/media-stream")
async def media_stream(call_ws: WebSocket):
await call_ws.accept()
connector = StreamConnector(
remote_url="wss://your-ai-provider.example.com",
call_stream_handler=relay,
remote_stream_handler=relay,
)
await connector.bridge_stream(call_ws)