# Rust Quickstart

> Create a live input, push a broadcast, async Rust + Tokio.

## 1. Install

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

## 2. Create a live input + mint a playback URL

```rust
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

```rust
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

```rust
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](/modalities/voice/details)** — `voice::Voice::new` + `calls().originate` + `audio_bridge().attach`
  - **[Robotics](/modalities/robotics/details)** — `robotics::Robotics::new` + `publish_telemetry` / `subscribe_command`
  - **[Games](/modalities/games/details)** — `games::Games::new` + `publish_state` / `subscribe_inputs`
  - **[Data](/modalities/data/details)** — `data::Data::new` + `publish` / `subscribe`
