Skip to main content

streamcore (Python)

English | 简体中文

Python SDK for connecting to a streamcore server via WebRTC + WHIP, powered by aiortc.

Requirements

  • Python 3.10+

Installation

pip install streamcore

Or install from source:

cd python-sdk
pip install -e .

Quick Start

import asyncio
import numpy as np
import streamcore


async def main():
    def on_transcript(entry, all_entries):
        print(f"[{entry.role}] {entry.text}")

    client = streamcore.Client(
        config=streamcore.Config(whip_endpoint="http://localhost:8080/whip"),
        events=streamcore.EventHandler(
            on_transcript=on_transcript,
            on_error=lambda err: print(f"Error: {err}"),
        ),
    )

    await client.connect()

    # Send a 20 ms frame of silence
    pcm = np.zeros(streamcore.FRAME_SIZE, dtype=np.int16)
    await client.send_pcm(pcm)

    # Receive decoded audio from the agent
    audio = await client.recv_pcm()  # numpy int16 array

    await client.disconnect()


asyncio.run(main())

API

Client(config?, events?)

Creates a new voice agent client.

Config

Field Type Default Description
whip_endpoint str "http://localhost:8080/whip" WHIP signaling endpoint URL
token str "" JWT sent as Authorization: Bearer on the WHIP request
token_url str "" Token endpoint; when set, a JWT is fetched before each connection (overrides token)
api_key str "" Sent as Authorization: Bearer when fetching from token_url
ice_servers list[str] ["stun:stun.l.google.com:19302"] ICE server URLs

EventHandler

All callbacks are optional.

Callback Signature Description
on_status_change (status: ConnectionStatus) -> None Fired when connection status changes
on_transcript (entry: TranscriptEntry, all: list[TranscriptEntry]) -> None Fired on new or updated transcript
on_agent_state_change (state: AgentState) -> None Fired when the agent starts listening, thinking, or speaking
on_timing (event: TimingEvent) -> None Fired with server-side pipeline timing info
on_error (error: Exception) -> None Fired on connection or server errors
on_data_channel_message (msg: DataChannelMessage) -> None Fired for every raw DC message

Methods

Method Description
await client.connect(track?) Connect via WHIP. Optionally pass an aiortc audio track.
await client.disconnect() Tear down connection and free resources.
await client.send_pcm(pcm) Send a numpy int16 PCM buffer (mono 48 kHz) to the agent.
await client.recv_pcm() Receive decoded PCM audio as a numpy int16 array.
client.status Current ConnectionStatus.
client.transcript Current conversation as list[TranscriptEntry].
client.remote_track Inbound audio track from the agent (available after connect).

Audio Constants

Constant Value Description
SAMPLE_RATE 48000 Audio sample rate in Hz
CHANNELS 1 Number of channels (mono)
FRAME_SIZE 960 Samples per 20 ms frame

Reconnection

A network change mid-call is recovered automatically, and the conversation survives it: the agent still knows who you are and does not replay its greeting.

The mechanism differs from the other SDKs. They keep the transport alive with an ICE restart; aiortc cannot do that (RTCPeerConnection.createOffer() takes no options, aioice fixes its ICE credentials at construction, and aiortc has no disconnected state to act on — it goes straight from connected to failed). So Python recovers by redialling with a resume token: a brand new peer connection, reattached server-side to the session it was already running. The transport is new; the conversation is not.

Status goes connectedreconnectingconnected:

import streamcore

client = streamcore.Client(
    streamcore.Config(
        whip_endpoint="http://localhost:8080/whip",
        reconnect_attempts=3,
        reconnect_delay=2.0,
    ),
    streamcore.EventHandler(
        on_reconnect=lambda e: print(f"redial {e.attempt}/{e.max_attempts}: {e.outcome}"),
    ),
)

One outcome deserves handling rather than logging:

  • RECOVERED — reattached; history intact.
  • RECOVERED_WITHOUT_HISTORYthe call works but the agent has forgotten everything. The server had already reaped the session, so the redial started a fresh conversation. Surface this to the user rather than letting them discover it by being asked their name again.
  • FAILED — every attempt failed; status becomes disconnected.

The window is the server's session_grace_ms (30s by default), measured from when the connection dropped — not the ~25s ICE deadline the other SDKs work against. Keep reconnect_attempts × reconnect_delay (doubling each retry) inside it. Set reconnect_attempts=0 to disable and handle drops yourself.

Two caveats specific to this stack:

  • Realtime (speech-to-speech) sessions cannot be resumed. Their history lives inside the provider, so the server issues no token and a redial starts a new conversation.
  • A caller-supplied user_track is reused across the redial. The built-in track (the send_pcm path) is rebuilt automatically; if you pass your own track to connect(), make sure it is still live, or reconnect yourself.

The wire-format helpers for ICE restart still ship in streamcore.icerestart for callers driving another WebRTC stack:

from streamcore import whip_restart_ice, ice_fragment_from_sdp, apply_ice_fragment

Audio I/O

The SDK handles aiortc track management, av.AudioFrame construction, and resampling internally. Callers only deal with raw PCM data as numpy int16 arrays:

# Send microphone audio (960 samples = 20 ms at 48 kHz)
await client.send_pcm(pcm_int16)

# Receive agent audio
audio = await client.recv_pcm()

If you need direct track access (e.g. for a custom aiortc pipeline), pass your own AudioStreamTrack via client.connect(user_track=my_track).

Dependencies

Package Purpose
aiortc WebRTC stack
aiohttp HTTP client for WHIP signaling
av Audio frame encoding/decoding
numpy PCM audio buffers

License

Apache-2.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

streamcore-0.1.3.tar.gz (22.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

streamcore-0.1.3-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file streamcore-0.1.3.tar.gz.

File metadata

  • Download URL: streamcore-0.1.3.tar.gz
  • Upload date:
  • Size: 22.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for streamcore-0.1.3.tar.gz
Algorithm Hash digest
SHA256 798c38952a21b8d966e9c0235c92817e5d04c02dcb2622cc5f862de241319315
MD5 7a94baa8dde6d49997454bb8161c714e
BLAKE2b-256 dcc4e6f37199ff4b712162ac4634631b198790e032a55bebb1e709515fb492dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for streamcore-0.1.3.tar.gz:

Publisher: publish.yml on streamcoreai/python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file streamcore-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: streamcore-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 21.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for streamcore-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 6588c40ef14c6f34ed4587c0e0c6ef4351245aede8ffbb97a50d48f1ae83bc75
MD5 3ea6028fe77f2adfc9128b5db36391f0
BLAKE2b-256 d56f8c7855b995e8d0c74398b396ece39cf6ce493d86fd6456558bae53831116

See more details on using hashes here.

Provenance

The following attestation bundles were made for streamcore-0.1.3-py3-none-any.whl:

Publisher: publish.yml on streamcoreai/python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.4

2 files

This release

0.1.3 This release

2 files

0.1.2

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page