mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-03-22 06:11:27 -07:00
update skills
This commit is contained in:
158
.agents/skills/cloudflare-deploy/references/realtime-sfu/api.md
Normal file
158
.agents/skills/cloudflare-deploy/references/realtime-sfu/api.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# API Reference
|
||||
|
||||
## Authentication
|
||||
|
||||
```bash
|
||||
curl -X POST 'https://rtc.live/v1/apps/${CALLS_APP_ID}/sessions/new' \
|
||||
-H "Authorization: Bearer ${CALLS_APP_SECRET}"
|
||||
```
|
||||
|
||||
## Core Concepts
|
||||
|
||||
**Sessions:** PeerConnection to Cloudflare edge
|
||||
**Tracks:** Media/data channels (audio/video/datachannel)
|
||||
**No rooms:** Build presence via track sharing
|
||||
|
||||
## Client Libraries
|
||||
|
||||
**PartyTracks (Recommended):** Observable-based client library for production use. Handles device changes, network switches, ICE restarts automatically. Push/pull API with React hooks. See patterns.md for full examples.
|
||||
|
||||
```bash
|
||||
npm install partytracks @cloudflare/calls
|
||||
```
|
||||
|
||||
**Raw API:** Direct HTTP + WebRTC for custom requirements (documented below).
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Create Session
|
||||
```http
|
||||
POST /v1/apps/{appId}/sessions/new
|
||||
→ {sessionId, sessionDescription}
|
||||
```
|
||||
|
||||
### Add Track (Publish)
|
||||
```http
|
||||
POST /v1/apps/{appId}/sessions/{sessionId}/tracks/new
|
||||
Body: {
|
||||
sessionDescription: {sdp, type: "offer"},
|
||||
tracks: [{location: "local", trackName: "my-video"}]
|
||||
}
|
||||
→ {sessionDescription, tracks: [{trackName}]}
|
||||
```
|
||||
|
||||
### Add Track (Subscribe)
|
||||
```http
|
||||
POST /v1/apps/{appId}/sessions/{sessionId}/tracks/new
|
||||
Body: {
|
||||
tracks: [{
|
||||
location: "remote",
|
||||
trackName: "remote-track-id",
|
||||
sessionId: "other-session-id"
|
||||
}]
|
||||
}
|
||||
→ {sessionDescription} (server offer)
|
||||
```
|
||||
|
||||
### Renegotiate
|
||||
```http
|
||||
PUT /v1/apps/{appId}/sessions/{sessionId}/renegotiate
|
||||
Body: {sessionDescription: {sdp, type: "answer"}}
|
||||
```
|
||||
|
||||
### Close Tracks
|
||||
```http
|
||||
PUT /v1/apps/{appId}/sessions/{sessionId}/tracks/close
|
||||
Body: {tracks: [{trackName}]}
|
||||
→ {requiresImmediateRenegotiation: boolean}
|
||||
```
|
||||
|
||||
### Get Session
|
||||
```http
|
||||
GET /v1/apps/{appId}/sessions/{sessionId}
|
||||
→ {sessionId, tracks: TrackMetadata[]}
|
||||
```
|
||||
|
||||
## TypeScript Types
|
||||
|
||||
```typescript
|
||||
interface TrackMetadata {
|
||||
trackName: string;
|
||||
location: "local" | "remote";
|
||||
sessionId?: string; // For remote tracks
|
||||
mid?: string; // WebRTC mid
|
||||
}
|
||||
```
|
||||
|
||||
## WebRTC Flow
|
||||
|
||||
```typescript
|
||||
// 1. Create PeerConnection
|
||||
const pc = new RTCPeerConnection({
|
||||
iceServers: [{urls: 'stun:stun.cloudflare.com:3478'}]
|
||||
});
|
||||
|
||||
// 2. Add tracks
|
||||
const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
|
||||
stream.getTracks().forEach(track => pc.addTrack(track, stream));
|
||||
|
||||
// 3. Create offer
|
||||
const offer = await pc.createOffer();
|
||||
await pc.setLocalDescription(offer);
|
||||
|
||||
// 4. Send to backend → Cloudflare API
|
||||
const response = await fetch('/api/new-session', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({sdp: offer.sdp})
|
||||
});
|
||||
|
||||
// 5. Set remote answer
|
||||
const {sessionDescription} = await response.json();
|
||||
await pc.setRemoteDescription(sessionDescription);
|
||||
```
|
||||
|
||||
## Publishing
|
||||
|
||||
```typescript
|
||||
const offer = await pc.createOffer();
|
||||
await pc.setLocalDescription(offer);
|
||||
|
||||
const res = await fetch(`/api/sessions/${sessionId}/tracks`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
sdp: offer.sdp,
|
||||
tracks: [{location: 'local', trackName: 'my-video'}]
|
||||
})
|
||||
});
|
||||
|
||||
const {sessionDescription, tracks} = await res.json();
|
||||
await pc.setRemoteDescription(sessionDescription);
|
||||
const publishedTrackId = tracks[0].trackName; // Share with others
|
||||
```
|
||||
|
||||
## Subscribing
|
||||
|
||||
```typescript
|
||||
const res = await fetch(`/api/sessions/${sessionId}/tracks`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
tracks: [{location: 'remote', trackName: remoteTrackId, sessionId: remoteSessionId}]
|
||||
})
|
||||
});
|
||||
|
||||
const {sessionDescription} = await res.json();
|
||||
await pc.setRemoteDescription(sessionDescription);
|
||||
|
||||
const answer = await pc.createAnswer();
|
||||
await pc.setLocalDescription(answer);
|
||||
|
||||
await fetch(`/api/sessions/${sessionId}/renegotiate`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({sdp: answer.sdp})
|
||||
});
|
||||
|
||||
pc.ontrack = (event) => {
|
||||
const [remoteStream] = event.streams;
|
||||
videoElement.srcObject = remoteStream;
|
||||
};
|
||||
```
|
||||
Reference in New Issue
Block a user