1. Install

Cargo.toml
[dependencies]
clutchcall = "0.1"
tokio = { version = "1", features = ["full"] }

2. Create a live input + mint a playback URL

use clutchcall::streams::{Streams, Config, CreateArgs};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let s = Streams::new(Config {
        base_url: "https://app.clutchcall.dev".into(),
        api_key:  std::env::var("CLUTCHCALL_API_KEY")?,
        org_id:   "org_abc".into(),
    })?;

    let (input, stream_key) = s.live_inputs().create(CreateArgs {
        name: "My First Stream".into(),
        codecs: None, recording_profile: None,
    }).await?;
    println!("inputId: {}  streamKey: {}", input.external_input_id, stream_key);

    let signed = input.signed_playback_url(3600, None).await?;
    println!("playback URL: {}", signed.url);
    Ok(())
}

3. Push a broadcast

use clutchcall::streams::{BroadcastPublisher, PublisherArgs};

let pub_ = BroadcastPublisher::open(PublisherArgs {
    input_id: input.external_input_id.clone(),
    stream_key,
    codecs: ("avc1.42E01F".into(), "opus".into()),
}).await?;
pub_.write(chunk);          // for every fMP4 segment
pub_.close("finished").await?;

4. Subscribe

use clutchcall::streams::{BroadcastViewer, ViewerOpts};

let viewer = BroadcastViewer::open(signed.url, ViewerOpts {
    on_chunk: Box::new(|_init, chunk| out.write_all(&chunk).unwrap()),
    on_close: Box::new(|reason| eprintln!("closed: {reason}")),
}).await?;

Other modalities

Voice

voice::Voice::new + calls().originate + audio_bridge().attach

Robotics

robotics::Robotics::new + publish_telemetry / subscribe_command

Games

games::Games::new + publish_state / subscribe_inputs

Data

data::Data::new + publish / subscribe