# Rust Reference

> Every modality, every method, every option.

The Rust SDK ships **five modality modules** plus a raw MoQT client.

```rust
use clutchcall::{voice, streams, robotics, games, data, moqt};
```

All modality clients are `async` and use `tokio`. They share the same
underlying client (`clutchcall::Client`) when constructed against the
same relay.

## Voice

```rust
let v = voice::Voice::new(voice::Config {
    base_url: "https://app.clutchcall.dev".into(),
    api_key:  std::env::var("CLUTCHCALL_API_KEY")?,
    org_id:   Some("org_abc".into()),
})?;
```

### Calls

```rust
let call = v.calls().originate(voice::OriginateArgs {
    to:       "+15551234567",
    from:     Some("+15558675309"),
    trunk_id: Some("trunk_main"),
    agent:    Some("healthcare-assistant"),
}).await?;

v.calls().get(sid).await?;
v.calls().list(org_id, cursor, limit).await?;
v.calls().transfer(sid, voice::TransferArgs { to: "...", agent: "..." }).await?;
v.calls().hangup(sid).await?;
v.calls().terminate(sid).await?;
```

`Call`:

```rust
call.sid:    String
call.status: String
call.from:   String
call.to:     String

call.refresh().await? -> CallData
call.hangup().await?
call.transfer(args).await? -> Call
call.on_status(cb) -> Unsubscribe
```

### AudioBridge

```rust
let bridge = v.audio_bridge().attach(call.sid, voice::AudioBridgeOpts {
    codec:     voice::Codec::Opus,
    on_uplink: Some(Box::new(|frame, ts_us| { /* ... */ })),
})?;

bridge.publish_uplink(frame);
bridge.publish_downlink(frame);
bridge.on_uplink(cb);
bridge.on_downlink(cb);
bridge.close();
```

`Codec`: `Opus`, `Pcm16`, `G711ULaw`, `G711ALaw`.

## Streams

```rust
let s = streams::Streams::new(streams::Config {
    base_url: "https://app.clutchcall.dev".into(),
    api_key:  key,
    org_id:   "org_abc".into(),
})?;
```

### Control plane

```rust
let (input, stream_key) = s.live_inputs().create(streams::CreateArgs {
    name: "My Show".into(), codecs: None, recording_profile: None,
}).await?;                       // stream_key returned ONCE

s.live_inputs().get(id).await?;
s.live_inputs().list(org_id, cursor, limit).await?;
s.live_inputs().rotate_stream_key(id).await?;
s.live_inputs().delete(id).await?;

s.signing_keys().create(org_id, label).await?;
s.signing_keys().list(org_id).await?;
s.signing_keys().retire(id).await?;

s.api_keys().create(org_id, label, scopes).await?;
s.api_keys().list(org_id).await?;
s.api_keys().revoke(id).await?;

s.webhooks().create(org_id, url, events).await?;
s.webhooks().list(org_id).await?;
s.webhooks().delete(id).await?;
s.events().list_deliveries(webhook_id, cursor, limit).await?;

s.analytics().viewer_minutes(org_id, from, to, group_by).await?;
s.analytics().pop_cache(org_id, from, to).await?;
```

`LiveInput`:

```rust
input.external_input_id: String
input.signed_playback_url(ttl_seconds, scopes).await? -> SignedPlaybackUrl
```

### Data plane

```rust
let pub_ = streams::BroadcastPublisher::open(streams::PublisherArgs {
    input_id, stream_key, codecs,
}).await?;
pub_.write(chunk);
pub_.close(reason).await?;

let viewer = streams::BroadcastViewer::open(signed_url, streams::ViewerOpts {
    on_chunk: Box::new(|init, chunk| { /* ... */ }),
    on_close: Box::new(|reason| { /* ... */ }),
}).await?;
viewer.close().await?;
```

## Robotics

```rust
let r = robotics::Robotics::new(robotics::Config {
    relay_host: "relay.clutchcall.dev".into(),
    token:      std::env::var("CLUTCHCALL_RELAY_TOKEN")?,
    robot_id:   "turtlebot-7".into(),
})?;
```

```rust
let pub_ = r.publish_telemetry(robotics::PublishArgs {
    topic:     "odom",
    type_name: "nav_msgs/msg/Odometry",
    qos:       Some(robotics::QoSProfile {
        reliability: robotics::Reliability::Reliable,
        depth:       Some(10),
        ..Default::default()
    }),
}).await?;
pub_.write(cdr_bytes);
pub_.close();

let sub = r.subscribe_telemetry(
    robotics::SubscribeArgs { topic: "odom", qos: None },
    |payload, type_name| { /* ... */ },
).await?;
sub.close();
```

`QoSProfile`:

```rust
pub struct QoSProfile {
    pub reliability: Reliability,  // BestEffort | Reliable
    pub durability:  Durability,   // Volatile  | TransientLocal
    pub depth:       Option<u32>,
}
```

## Games

```rust
let g = games::Games::new(games::Config {
    relay_host: "relay.clutchcall.dev".into(),
    token,
    room_id:    "duel-42".into(),
    player_id:  Some("alice".into()),  // None = authority
})?;
```

### Player

```rust
let sub = g.subscribe_state(|bytes| render(bytes)).await?;
let input = g.publish_input().await?;
input.write(serialize_input(local_input));

let events = g.publish_event().await?;
events.send(serde_json::json!({"kind": "chat", "text": "gg"}));
g.subscribe_events(|evt, from_player_id| dispatch(evt)).await?;
```

### Authority (player_id: None)

```rust
let state = g.publish_state(games::StateOpts { tick_hz: 30 }).await?;
state.write(serialize_state(&world));

g.subscribe_inputs(|player_id, payload| apply_input(player_id, payload)).await?;
g.subscribe_events(|evt, from_player_id| { /* ... */ }).await?;
```

## Data

```rust
let d = data::Data::new(data::Config {
    relay_host: "relay.clutchcall.dev".into(),
    token:      std::env::var("CLUTCHCALL_DATA_TOKEN")?,
    client_id:  "device-7".into(),
})?;
```

```rust
d.publish(data::PublishArgs {
    topic:    "sensors/room1/temperature",
    payload:  b"23.5".to_vec(),
    reliable: false,
    retain:   false,
}).await?;

let sub = d.subscribe(data::SubscribeArgs {
    topic_filter: "sensors/+/temperature".into(),
}, |msg: data::Message| {
    println!("{} ← {} = {:?}", msg.topic, msg.from_client_id, msg.payload);
}).await?;
sub.close();
```

`Message`:

```rust
pub struct Message {
    pub topic:          String,
    pub payload:        Vec<u8>,
    pub from_client_id: String,
    pub retain:         bool,
    pub ts_us:          u64,
}
```

## Realtime Tracks

See [Realtime Tracks](/concepts/realtime-tracks). Common methods:

```rust
let client = moqt::MoqtClient::connect("quic://relay.clutchcall.dev", token).await?;

client.publish_frame(namespace, name, opts).await?;
client.subscribe_frame(namespace, name, |ts_us, prio, data| { /* ... */ }).await?;
client.publish_audio(...)  / client.subscribe_audio(...)
client.publish_video(...)  / client.subscribe_video(...)
client.publish_text(...)   / client.subscribe_text(...)

client.subscribe_namespace(prefix, |suffix, active| { /* ... */ }).await?;
client.connection_rtt_us() -> u64
client.max_datagram_size() -> usize
client.close();
```

## Legacy RPC

The root `clutchcall::Client` (`dial`, `originate_bulk`, `hangup`,
`barge`, `push_audio`, …) remains for backwards compat. New code should
prefer the [voice modality](#voice).
