import (
"github.com/clutchcall/clutchcall-sdk/go/pkg/voice"
"github.com/clutchcall/clutchcall-sdk/go/pkg/streams"
"github.com/clutchcall/clutchcall-sdk/go/pkg/robotics"
"github.com/clutchcall/clutchcall-sdk/go/pkg/games"
"github.com/clutchcall/clutchcall-sdk/go/pkg/data"
"github.com/clutchcall/clutchcall-sdk/go/pkg/moqt"
)
Voice
v, err := voice.New(voice.Config{
BaseURL: "https://app.clutchcall.dev",
APIKey: os.Getenv("CLUTCHCALL_API_KEY"),
OrgID: "org_abc",
})
defer v.Close()
Calls
call, err := v.Calls.Originate(ctx, voice.OriginateArgs{
To: "+15551234567",
From: "+15558675309",
TrunkID: "trunk_main",
Agent: "healthcare-assistant",
})
v.Calls.Get(ctx, sid) // → *Call
v.Calls.List(ctx, voice.ListArgs{OrgID, Cursor, Limit}) // → ([]Call, cursor)
v.Calls.Transfer(ctx, sid, voice.TransferArgs{To: "..."})
v.Calls.Hangup(ctx, sid)
v.Calls.Terminate(ctx, sid)
Call exposes:
call.SID: string
call.Status: string
call.From: string
call.To: string
call.Refresh(ctx) (*CallData, error)
call.Hangup(ctx) error
call.Transfer(ctx, args) (*Call, error)
call.OnStatus(cb) Unsubscribe
AudioBridge
bridge, err := v.AudioBridge.Attach(ctx, call.SID, voice.AudioBridgeOpts{
Codec: voice.CodecOpus,
OnUplink: func(frame []byte, tsUs uint64) { myASR.Feed(frame) },
})
bridge.PublishUplink(frame []byte)
bridge.PublishDownlink(frame []byte)
bridge.OnUplink(cb)
bridge.OnDownlink(cb)
bridge.Close()
voice.CodecOpus, CodecPCM16, CodecG711ULaw, CodecG711ALaw.
Streams
s, err := streams.New(streams.Config{
BaseURL: "https://app.clutchcall.dev",
APIKey: KEY,
OrgID: "org_abc",
})
Control plane
input, streamKey, err := s.LiveInputs.Create(ctx, streams.CreateLiveInput{
Name: "My Show",
}) // streamKey returned ONCE
s.LiveInputs.Get(ctx, id)
s.LiveInputs.List(ctx, orgID, cursor, limit)
s.LiveInputs.RotateStreamKey(ctx, id)
s.LiveInputs.Delete(ctx, id)
s.SigningKeys.Create(ctx, orgID, label)
s.SigningKeys.List(ctx, orgID)
s.SigningKeys.Retire(ctx, id)
s.APIKeys.Create(ctx, orgID, label, scopes)
s.APIKeys.List(ctx, orgID)
s.APIKeys.Revoke(ctx, id)
s.Webhooks.Create(ctx, orgID, url, events)
s.Webhooks.List(ctx, orgID)
s.Webhooks.Delete(ctx, id)
s.Events.ListDeliveries(ctx, webhookID, cursor, limit)
s.Analytics.ViewerMinutes(ctx, orgID, from, to, groupBy)
s.Analytics.PopCache(ctx, orgID, from, to)
LiveInput exposes:
input.ExternalInputID: string
input.SignedPlaybackURL(ctx, ttlSeconds, scopes) (*SignedPlaybackURL, error)
Data plane
pub, err := streams.OpenBroadcastPublisher(ctx, streams.PublisherArgs{
InputID: input.ExternalInputID,
StreamKey: streamKey,
Codecs: streams.Codecs{Video: "avc1.42E01F", Audio: "opus"},
})
pub.Write(chunk []byte)
pub.Close(reason)
viewer, err := streams.OpenBroadcastViewer(ctx, signedURL, streams.ViewerOpts{
OnChunk: func(init, chunk []byte) { /* ... */ },
OnClose: func(reason string) { /* ... */ },
})
viewer.Close()
Robotics
r, err := robotics.New(robotics.Config{
RelayHost: "relay.clutchcall.dev",
Token: os.Getenv("CLUTCHCALL_RELAY_TOKEN"),
RobotID: "turtlebot-7",
})
pub, err := r.PublishTelemetry(ctx, robotics.PublishArgs{
Topic: "odom",
TypeName: "nav_msgs/msg/Odometry",
QoS: robotics.QoSProfile{Reliability: robotics.Reliable, Depth: 10},
})
pub.Write(cdrBytes []byte)
pub.Close()
pub2, err := r.PublishCommand(ctx, robotics.PublishArgs{
Topic: "cmd_vel", TypeName: "geometry_msgs/msg/Twist",
})
sub, err := r.SubscribeTelemetry(ctx, robotics.SubscribeArgs{Topic: "odom"},
func(payload []byte, typeName string) { /* ... */ })
sub, err := r.SubscribeCommand(ctx, robotics.SubscribeArgs{Topic: "cmd_vel"},
func(payload []byte, typeName string) { /* ... */ })
sub.Close()
QoSProfile:
type QoSProfile struct {
Reliability Reliability // BestEffort | Reliable
Durability Durability // Volatile | TransientLocal
Depth int
}
Games
g, err := games.New(games.Config{
RelayHost: "relay.clutchcall.dev",
Token: token,
RoomID: "duel-42",
PlayerID: "alice", // omit for authority
})
Player
sub, _ := g.SubscribeState(ctx, func(bytes []byte) { render(bytes) })
input, _ := g.PublishInput(ctx)
input.Write(serializeInput(localInput))
events, _ := g.PublishEvent(ctx)
events.Send(map[string]any{"kind": "chat", "text": "gg"})
g.SubscribeEvents(ctx, func(evt any, fromPlayerID string) { /* ... */ })
Authority
state, _ := g.PublishState(ctx, games.StateOpts{TickHZ: 30})
state.Write(serializeState(world))
g.SubscribeInputs(ctx, func(playerID string, payload []byte) {
applyInput(playerID, payload)
})
g.SubscribeEvents(ctx, func(evt any, fromPlayerID string) { /* ... */ })
Data
d, err := data.New(data.Config{
RelayHost: "relay.clutchcall.dev",
Token: os.Getenv("CLUTCHCALL_DATA_TOKEN"),
ClientID: "device-7",
})
d.Publish(ctx, data.PublishArgs{
Topic: "sensors/room1/temperature",
Payload: []byte("23.5"),
Reliable: false,
Retain: false,
})
sub, _ := d.Subscribe(ctx,
data.SubscribeArgs{TopicFilter: "sensors/+/temperature"},
func(msg data.Message) {
fmt.Println(msg.Topic, msg.FromClientID, string(msg.Payload))
})
sub.Close()
Realtime Tracks
See Realtime Tracks. Common methods:client, _ := moqt.Connect(ctx, "quic://relay.clutchcall.dev", token)
client.PublishFrame(ctx, namespace, name, moqt.FrameOpts{...})
client.SubscribeFrame(ctx, namespace, name, func(tsUs uint64, prio uint8, data []byte) {...})
client.PublishAudio(...) / client.SubscribeAudio(...)
client.PublishVideo(...) / client.SubscribeVideo(...)
client.PublishText(...) / client.SubscribeText(...)
client.SubscribeNamespace(ctx, prefix []string,
func(suffix string, active bool) {...})
client.ConnectionRTTUs() uint64
client.MaxDatagramSize() int
client.Close()
Legacy RPC
The rootclutchcall.Client (Dial, OriginateBulk, Hangup, Barge,
PushAudio, …) remains for backwards compat. New code should prefer the
voice modality.
