# Java Reference

> Every modality, every method, every option.

The Java SDK ships **five modality packages** plus a raw MoQT client.

```java
import com.clutchcall.sdk.voice.Voice;
import com.clutchcall.sdk.streams.Streams;
import com.clutchcall.sdk.robotics.Robotics;
import com.clutchcall.sdk.games.Games;
import com.clutchcall.sdk.data.Data;
import com.clutchcall.sdk.Moqt;
```

Each modality is an `AutoCloseable` final class with public nested types
(`Voice.Calls`, `Voice.Call`, `Voice.AudioBridge`, etc).

## Voice

```java
Voice v = new Voice(
    "https://app.clutchcall.dev",       // baseUrl
    System.getenv("CLUTCHCALL_API_KEY"),
    "org_abc"
);
```

### Calls

```java
Voice.Call call = v.calls().originate(new Voice.OriginateArgs()
    .to("+15551234567")
    .from("+15558675309")
    .trunkId("trunk_main")
    .agent("healthcare-assistant"));

v.calls().get(sid);
v.calls().list(orgId, cursor, limit);
v.calls().transfer(sid, new Voice.TransferArgs().to("+1..."));
v.calls().hangup(sid);
v.calls().terminate(sid);
```

`Call` exposes:

```java
call.sid()    : String
call.status() : String
call.from()   : String
call.to()     : String

call.refresh()              // → CallData
call.hangup()
call.transfer(args)         // → Call
call.onStatus(consumer)     // → Unsubscribe
```

### AudioBridge

```java
Voice.AudioBridge bridge = v.audioBridge().attach(call.sid(),
    new Voice.AudioBridgeOpts()
        .codec(Voice.Codec.OPUS)
        .onUplink((frame, tsUs) -> myAsr.feed(frame)));

bridge.publishUplink(frame);
bridge.publishDownlink(frame);
bridge.onUplink(cb);
bridge.onDownlink(cb);
bridge.close();
```

`Codec`: `OPUS`, `PCM16`, `G711_ULAW`, `G711_ALAW`.

## Streams

```java
Streams s = new Streams("https://app.clutchcall.dev", apiKey, "org_abc");
```

### Control plane

```java
Streams.LiveInputWithSecret created =
    s.liveInputs().create("My Show", null /* codecs */, null /* recordingProfile */);
String streamKey = created.streamKey();         // returned ONCE

s.liveInputs().get(id);
s.liveInputs().list(orgId, cursor, limit);
s.liveInputs().rotateStreamKey(id);
s.liveInputs().delete(id);

s.signingKeys().create(orgId, label);
s.signingKeys().list(orgId);
s.signingKeys().retire(id);

s.apiKeys().create(orgId, label, scopes);
s.apiKeys().list(orgId);
s.apiKeys().revoke(id);

s.webhooks().create(orgId, url, events);
s.webhooks().list(orgId);
s.webhooks().delete(id);
s.events().listDeliveries(webhookId, cursor, limit);

s.analytics().viewerMinutes(orgId, from, to, groupBy);
s.analytics().popCache(orgId, from, to);
```

`LiveInput`:

```java
input.externalInputId(): String
input.signedPlaybackUrl(ttlSeconds, scopes): Streams.SignedPlaybackUrl
```

### Data plane

The publisher and viewer classes live in `Streams.BroadcastPublisher` and
`Streams.BroadcastViewer`:

```java
Streams.BroadcastPublisher pub = Streams.BroadcastPublisher.open(
    inputId, streamKey, codecs);
pub.write(chunk);
pub.close(Streams.CloseReason.COMPLETE);

Streams.BroadcastViewer viewer = Streams.BroadcastViewer.open(signedUrl,
    (init, chunk) -> { /* ... */ },
    reason -> { /* ... */ });
viewer.close();
```

## Robotics

```java
Robotics r = new Robotics(
    "relay.clutchcall.dev",
    System.getenv("CLUTCHCALL_RELAY_TOKEN"),
    "turtlebot-7"
);
```

```java
Robotics.QoSProfile qos = new Robotics.QoSProfile()
    .reliability(Robotics.Reliability.RELIABLE)
    .depth(10);

Robotics.Publication pub = r.publishTelemetry("odom",
    "nav_msgs/msg/Odometry", qos);
pub.write(cdrBytes);
pub.close();

Robotics.Publication cmd = r.publishCommand("cmd_vel",
    "geometry_msgs/msg/Twist", null);

Robotics.Subscription sub = r.subscribeTelemetry("odom", null,
    (payload, typeName) -> { /* ... */ });
sub.close();
```

`Reliability`: `BEST_EFFORT`, `RELIABLE`.
`Durability`: `VOLATILE`, `TRANSIENT_LOCAL`.

## Games

```java
Games g = new Games(
    "relay.clutchcall.dev",
    token,
    "duel-42",
    "alice"  // null for authority
);
```

### Player

```java
Games.Subscription stateSub = g.subscribeState(bytes -> render(bytes));
Games.FromPublisher input = g.publishInput();
input.write(serializeInput(localInput));

Games.FromPublisher events = g.publishEvent();
events.send(Map.of("kind", "chat", "text", "gg"));
g.subscribeEvents((evt, fromPlayerId) -> dispatch(evt));
```

### Authority (playerId: null)

```java
Games.StatePublisher state = g.publishState(new Games.StateOpts().tickHz(30));
state.write(serializeState(world));

g.subscribeInputs((playerId, payload) -> applyInput(playerId, payload));
g.subscribeEvents((evt, fromPlayerId) -> { /* ... */ });
```

## Data

```java
Data d = new Data(
    "relay.clutchcall.dev",
    System.getenv("CLUTCHCALL_DATA_TOKEN"),
    "device-7"
);
```

```java
d.publish("sensors/room1/temperature", "23.5".getBytes(), false, false);

Data.Subscription sub = d.subscribe("sensors/+/temperature",
    msg -> System.out.println(msg.topic() + " ← " + msg.fromClientId() +
                              " = " + new String(msg.payload())));
sub.close();
```

`Data.Message`:

```java
msg.topic()        : String
msg.payload()      : byte[]
msg.fromClientId() : String
msg.retain()       : boolean
msg.tsUs()         : long
```

## Realtime Tracks

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

```java
Moqt.Client client = Moqt.connect("quic://relay.clutchcall.dev", token);

client.publishFrame(namespace, name, opts);
client.subscribeFrame(namespace, name, (tsUs, prio, data) -> {...});
client.publishAudio(...)  / client.subscribeAudio(...)
client.publishVideo(...)  / client.subscribeVideo(...)
client.publishText(...)   / client.subscribeText(...)

client.subscribeNamespace(prefix, (suffix, active) -> {...});
client.connectionRttUs(): long
client.maxDatagramSize(): int
client.close();
```

## Legacy RPC

The root `com.clutchcall.sdk.ClutchCallClient` (`dial`, `originateBulk`,
`hangup`, `barge`, `pushAudio`, …) remains for backwards compat. New code
should prefer the [voice modality](#voice).
