streamcore-rust-sdk

April 15, 2026 · View on GitHub

Rust SDK for connecting to a StreamCoreAI server via WebRTC + WHIP.

Installation

[dependencies]
streamcoreai-voice-agent-sdk = { git = "https://github.com/streamcoreai/rust-sdk" }

Or add to your Cargo.toml:

streamcore-rust-sdk = "0.1"

Quick Start

use std::sync::Arc;
use streamcore_rust_sdk::{Client, Config, EventHandler, FRAME_SIZE};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = Arc::new(Client::new(
        Config {
            whip_endpoint: "http://localhost:8080/whip".into(),
            ..Default::default()
        },
        EventHandler {
            on_status_change: Some(Box::new(|status| {
                println!("[status] {}", status);
            })),
            on_transcript: Some(Box::new(|entry, _all| {
                println!("[{}] {}", entry.role, entry.text);
            })),
            on_error: Some(Box::new(|err| {
                eprintln!("[error] {}", err);
            })),
            on_data_channel_message: None,
        },
    ));

    client.connect().await?;

    // Send microphone audio (f32 PCM, mono, 48 kHz, 960 samples per frame)
    let client_tx = Arc::clone(&client);
    tokio::spawn(async move {
        let pcm = vec![0.0f32; FRAME_SIZE]; // replace with real mic capture
        loop {
            client_tx.send_pcm(&pcm).await.unwrap();
        }
    });

    // Receive agent audio
    let client_rx = Arc::clone(&client);
    tokio::spawn(async move {
        let mut pcm = vec![0.0f32; FRAME_SIZE];
        loop {
            let n = client_rx.recv_pcm(&mut pcm).await.unwrap();
            // Play pcm[..n] through speakers
            let _ = &pcm[..n];
        }
    });

    tokio::signal::ctrl_c().await?;
    client.disconnect().await;
    Ok(())
}

API

Client::new(config, events)

Creates a new client instance.

Config

FieldTypeDefaultDescription
whip_endpointString"http://localhost:8080/whip"WHIP signaling endpoint URL
ice_serversVec<String>["stun:stun.l.google.com:19302"]ICE server URLs

EventHandler

CallbackSignatureDescription
on_status_changeOption<Box<dyn Fn(ConnectionStatus) + Send + Sync>>Fired when connection status changes
on_transcriptOption<Box<dyn Fn(TranscriptEntry, Vec<TranscriptEntry>)>>Fired on new or updated transcript
on_errorOption<Box<dyn Fn(String) + Send + Sync>>Fired on connection/server errors
on_data_channel_messageOption<Box<dyn Fn(DataChannelMessage)>>Fired for every raw DC message

Client Methods

MethodReturnsDescription
connect()Result<(), ClientError>Establish WebRTC + WHIP session
disconnect().awaitTear down connection, free resources
send_pcm(&pcm)Result<(), ClientError>Encode f32 PCM → Opus → RTP and send to server
recv_pcm(&mut pcm)Result<usize, ClientError>Receive + decode one frame of agent audio
status()ConnectionStatusCurrent connection status
transcript()Vec<TranscriptEntry>Full conversation history (copy)

Audio Constants

ConstantValueDescription
SAMPLE_RATE48000Audio sample rate in Hz (Opus)
CHANNELS1Number of audio channels (mono)
FRAME_SIZE960Samples per 20 ms frame at 48 kHz

Client Fields (after connect())

FieldTypeDescription
local_trackArc<TrackLocalStaticRTP>Write RTP packets here to send audio to server
remote_track_notifyArc<Notify>Notifies when remote_track is available
remote_trackArc<Mutex<Option<TrackRemote>>>Agent's audio track (check after notify fires)

Types

pub enum ConnectionStatus { Idle, Connecting, Connected, Error, Disconnected }

pub struct TranscriptEntry {
    pub role: String,    // "user" or "assistant"
    pub text: String,
    pub partial: bool,
}

pub struct DataChannelMessage {
    pub msg_type: String, // "transcript", "response", or "error"
    pub text: String,
    pub r#final: bool,
    pub message: String,
}

Audio I/O

The SDK handles Opus encoding/decoding and RTP packetization internally. You only work with raw PCM f32 samples:

  • Sending audio: Call client.send_pcm(&pcm) with a FRAME_SIZE-length slice of mono f32 samples
  • Receiving audio: Call client.recv_pcm(&mut pcm) to get the next decoded frame from the agent

For microphone capture and speaker playback, use a library like cpal.

Requirements

  • Rust 1.87+

Dependencies

  • webrtc 0.17 — Pion WebRTC bindings
  • audiopus — Opus audio codec
  • tokio — Async runtime
  • reqwest — HTTP client for WHIP signaling
  • serde — JSON serialization for data channel messages

License

MIT