dsh-agora 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/assets/agora/SKILL.md +113 -0
- package/assets/agora/references/cli/README.md +161 -0
- package/assets/agora/references/cli/automation.md +189 -0
- package/assets/agora/references/cli/doctor.md +129 -0
- package/assets/agora/references/cli/env.md +158 -0
- package/assets/agora/references/cli/install-auth.md +152 -0
- package/assets/agora/references/cli/projects.md +116 -0
- package/assets/agora/references/cli/quickstarts.md +117 -0
- package/assets/agora/references/cloud-recording/README.md +86 -0
- package/assets/agora/references/conversational-ai/README.md +285 -0
- package/assets/agora/references/conversational-ai/agent-client-toolkit-react.md +182 -0
- package/assets/agora/references/conversational-ai/agent-samples.md +101 -0
- package/assets/agora/references/conversational-ai/agent-toolkit-android.md +209 -0
- package/assets/agora/references/conversational-ai/agent-toolkit-ios.md +208 -0
- package/assets/agora/references/conversational-ai/agent-toolkit.md +201 -0
- package/assets/agora/references/conversational-ai/agent-ui-kit.md +63 -0
- package/assets/agora/references/conversational-ai/architecture.md +221 -0
- package/assets/agora/references/conversational-ai/auth-flow.md +154 -0
- package/assets/agora/references/conversational-ai/conversational-ai-studio.md +173 -0
- package/assets/agora/references/conversational-ai/go-sdk.md +184 -0
- package/assets/agora/references/conversational-ai/integration-from-quickstart.md +203 -0
- package/assets/agora/references/conversational-ai/python-sdk.md +122 -0
- package/assets/agora/references/conversational-ai/quickstarts.md +710 -0
- package/assets/agora/references/conversational-ai/server-custom-llm.md +45 -0
- package/assets/agora/references/conversational-ai/server-mcp.md +40 -0
- package/assets/agora/references/conversational-ai/server-sdk-rename.md +78 -0
- package/assets/agora/references/conversational-ai/server-sdks.md +128 -0
- package/assets/agora/references/doc-fetching.md +67 -0
- package/assets/agora/references/integration-patterns.md +201 -0
- package/assets/agora/references/mcp-tools.md +49 -0
- package/assets/agora/references/rtc/README.md +104 -0
- package/assets/agora/references/rtc/android.md +344 -0
- package/assets/agora/references/rtc/cross-platform-coordination.md +61 -0
- package/assets/agora/references/rtc/flutter.md +282 -0
- package/assets/agora/references/rtc/ios.md +306 -0
- package/assets/agora/references/rtc/nextjs.md +87 -0
- package/assets/agora/references/rtc/react-native.md +266 -0
- package/assets/agora/references/rtc/react.md +186 -0
- package/assets/agora/references/rtc/web.md +506 -0
- package/assets/agora/references/rtm/README.md +80 -0
- package/assets/agora/references/rtm/android.md +277 -0
- package/assets/agora/references/rtm/ios.md +231 -0
- package/assets/agora/references/rtm/web.md +348 -0
- package/assets/agora/references/server/README.md +22 -0
- package/assets/agora/references/server/tokens.md +74 -0
- package/assets/agora/references/server-gateway/README.md +80 -0
- package/assets/agora/references/server-gateway/linux-cpp.md +251 -0
- package/assets/agora/references/testing-guidance/SKILL.md +65 -0
- package/assets/agora/references/testing-guidance/completeness-gate.md +28 -0
- package/assets/agora/references/testing-guidance/convoai-rest.md +83 -0
- package/assets/agora/references/testing-guidance/mobile-rtm-and-renewal.md +109 -0
- package/assets/agora/references/testing-guidance/rtc-android.md +70 -0
- package/assets/agora/references/testing-guidance/rtc-ios.md +73 -0
- package/assets/agora/references/testing-guidance/rtc-react.md +51 -0
- package/assets/agora/references/testing-guidance/rtc-web.md +94 -0
- package/cordis.patch.yml +5 -0
- package/index.js +53 -0
- package/package.json +49 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Agora Signaling SDK — Web (RTM)
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Overview](#overview)
|
|
6
|
+
- [Installation](#installation)
|
|
7
|
+
- [RTM v2 (Web)](#rtm-v2-web)
|
|
8
|
+
- [RTM v1 (Legacy Web)](#rtm-v1-legacy-web)
|
|
9
|
+
- [Common Use Cases with RTC](#common-use-cases-with-rtc)
|
|
10
|
+
- [Stream Channels (Topics)](#stream-channels-topics)
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
RTM provides signaling, text messaging, presence, and metadata capabilities alongside RTC audio/video. RTC and RTM are **independent systems** — RTC channels and RTM channels are separate namespaces.
|
|
15
|
+
|
|
16
|
+
**When to use RTM alongside RTC:**
|
|
17
|
+
|
|
18
|
+
- Text chat during video calls
|
|
19
|
+
- Signaling (call invitations, control messages)
|
|
20
|
+
- User presence/status tracking
|
|
21
|
+
- Custom data exchange (VAD signals, resolution requests)
|
|
22
|
+
- Sending text messages to AI agents (Conversational AI)
|
|
23
|
+
|
|
24
|
+
Package: `agora-rtm` (v2.x) on npm.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install agora-rtm
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## RTM v2 (Web)
|
|
33
|
+
|
|
34
|
+
### Initialization and Login
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import AgoraRTM from "agora-rtm"
|
|
38
|
+
|
|
39
|
+
let rtmClient: AgoraRTM.RTM;
|
|
40
|
+
try {
|
|
41
|
+
rtmClient = new AgoraRTM.RTM("your-app-id", "user-id-string", {
|
|
42
|
+
logLevel: "debug", // "debug" | "info" | "warn" | "error"
|
|
43
|
+
});
|
|
44
|
+
} catch (status) {
|
|
45
|
+
console.error("RTM init failed", status);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Always login with a server-generated RTM token
|
|
49
|
+
await rtmClient.login({ token: 'YOUR_RTM_TOKEN' })
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Channel Subscription
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Subscribe to a channel to receive messages and presence
|
|
56
|
+
await rtmClient.subscribe("channel-name", {
|
|
57
|
+
withMessage: true,
|
|
58
|
+
withPresence: true,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Unsubscribe
|
|
62
|
+
await rtmClient.unsubscribe("channel-name")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Sending Messages
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Publish to channel (all subscribers receive)
|
|
69
|
+
await rtmClient.publish("channel-name", "Hello everyone!", {
|
|
70
|
+
customType: "chat.message",
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Publish JSON data
|
|
74
|
+
await rtmClient.publish("channel-name", JSON.stringify({
|
|
75
|
+
type: "control",
|
|
76
|
+
action: "mute-all",
|
|
77
|
+
}), {
|
|
78
|
+
customType: "control.message",
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// Peer-to-peer (publish to user topic)
|
|
82
|
+
await rtmClient.publish("target-user-id", JSON.stringify({
|
|
83
|
+
message: "Hello!",
|
|
84
|
+
priority: "APPEND",
|
|
85
|
+
}), {
|
|
86
|
+
customType: "user.transcription",
|
|
87
|
+
channelType: "USER",
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Receiving Messages
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
rtmClient.addEventListener("message", (event) => {
|
|
95
|
+
console.log("Message from:", event.publisher)
|
|
96
|
+
console.log("Channel:", event.channelName)
|
|
97
|
+
console.log("Content:", event.message) // string or Uint8Array
|
|
98
|
+
console.log("Type:", event.customType)
|
|
99
|
+
|
|
100
|
+
// Parse if JSON
|
|
101
|
+
if (typeof event.message === "string") {
|
|
102
|
+
try {
|
|
103
|
+
const data = JSON.parse(event.message)
|
|
104
|
+
} catch {}
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Presence Events
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
rtmClient.addEventListener("presence", (event) => {
|
|
113
|
+
// event.eventType: "SNAPSHOT" | "INTERVAL" | "JOIN" | "LEAVE" | "TIMEOUT" | "STATE_CHANGED"
|
|
114
|
+
|
|
115
|
+
switch (event.eventType) {
|
|
116
|
+
case "SNAPSHOT":
|
|
117
|
+
// Initial state on subscribe — event.snapshot is an array of {userId, states}
|
|
118
|
+
for (const user of event.snapshot) {
|
|
119
|
+
console.log("Online:", user.userId, user.states)
|
|
120
|
+
}
|
|
121
|
+
break
|
|
122
|
+
case "JOIN":
|
|
123
|
+
console.log("User joined:", event.publisher)
|
|
124
|
+
break
|
|
125
|
+
case "LEAVE":
|
|
126
|
+
case "TIMEOUT":
|
|
127
|
+
console.log("User left:", event.publisher)
|
|
128
|
+
break
|
|
129
|
+
case "INTERVAL":
|
|
130
|
+
// Periodic batch update — contains joinedUsers[], leftUsers[], timeoutUsers[]
|
|
131
|
+
for (const uid of event.joinedUsers ?? []) console.log("Joined:", uid)
|
|
132
|
+
for (const uid of event.leftUsers ?? []) console.log("Left:", uid)
|
|
133
|
+
break
|
|
134
|
+
case "STATE_CHANGED":
|
|
135
|
+
// User called setState — event.publisher, event.stateChanged (key-value pairs)
|
|
136
|
+
console.log("State changed:", event.publisher, event.stateChanged)
|
|
137
|
+
break
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Connection Status
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
rtmClient.addEventListener("status", (event) => {
|
|
146
|
+
// event.state: "CONNECTED" | "CONNECTING" | "RECONNECTING" | "DISCONNECTED"
|
|
147
|
+
console.log("RTM status:", event.state)
|
|
148
|
+
})
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Cleanup
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
async function cleanupRTM() {
|
|
155
|
+
await rtmClient.unsubscribe("channel-name")
|
|
156
|
+
await rtmClient.logout()
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
## Common Use Cases with RTC
|
|
162
|
+
|
|
163
|
+
### Text Chat During Video Call
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// RTM for chat alongside RTC video
|
|
167
|
+
rtmClient.addEventListener("message", (event) => {
|
|
168
|
+
if (event.customType === "chat.message") {
|
|
169
|
+
displayChatMessage(event.publisher, event.message)
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
function sendChatMessage(text: string) {
|
|
174
|
+
rtmClient.publish(channelName, text, { customType: "chat.message" })
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Voice Activity Detection (VAD) Signaling
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
// Notify other users when speaking (for prioritized video)
|
|
182
|
+
function notifyVAD(uid: number) {
|
|
183
|
+
rtmClient.publish(channelName, JSON.stringify({
|
|
184
|
+
type: "VAD",
|
|
185
|
+
uid: uid,
|
|
186
|
+
}), { customType: "signaling.vad" })
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Control Messages
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Request resolution change, stop screen share, etc.
|
|
194
|
+
rtmClient.publish(channelName, JSON.stringify({
|
|
195
|
+
type: "INCREASE_RESOLUTION",
|
|
196
|
+
targetUid: uid,
|
|
197
|
+
}), { customType: "signaling.control" })
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Sending Text to Conversational AI Agent
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// Send a text message to an AI agent via RTM
|
|
204
|
+
async function sendMessageToAgent(message: string, agentUid: string) {
|
|
205
|
+
const publishTarget = `${agentUid}-${channel}`
|
|
206
|
+
|
|
207
|
+
await rtmClient.publish(publishTarget, JSON.stringify({
|
|
208
|
+
message: message.trim(),
|
|
209
|
+
priority: "APPEND", // or "REPLACE"
|
|
210
|
+
}), {
|
|
211
|
+
customType: "user.transcription",
|
|
212
|
+
channelType: "USER",
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Stream Channels (Topics)
|
|
218
|
+
|
|
219
|
+
Stream channels provide structured, topic-based messaging with lower latency than message channels. Users **join** a stream channel (rather than subscribing) and publish/subscribe to **topics** within it.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// Create and join a stream channel
|
|
223
|
+
const streamChannel = await rtmClient.createStreamChannel("channel-name")
|
|
224
|
+
await streamChannel.join({
|
|
225
|
+
token: "your-rtm-token", // or null for testing
|
|
226
|
+
withPresence: true,
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
// Join a topic to publish messages
|
|
230
|
+
await streamChannel.joinTopic("chat")
|
|
231
|
+
|
|
232
|
+
// Publish to a topic
|
|
233
|
+
await streamChannel.publishTopicMessage("chat", "Hello from stream channel!")
|
|
234
|
+
|
|
235
|
+
// Subscribe to a topic to receive messages from specific publishers (or all)
|
|
236
|
+
await streamChannel.subscribeTopic("chat", {
|
|
237
|
+
users: ["user-123", "user-456"], // optional: filter by publisher
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
// Receive messages (same "message" event as message channels)
|
|
241
|
+
rtmClient.addEventListener("message", (event) => {
|
|
242
|
+
console.log("Topic:", event.topicName, "From:", event.publisher, ":", event.message)
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
// Leave topic and channel
|
|
246
|
+
await streamChannel.leaveTopic("chat")
|
|
247
|
+
await streamChannel.leave()
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**When to use stream channels over message channels:**
|
|
251
|
+
|
|
252
|
+
- Lower latency needed (0.5s heartbeat vs 5s for message channels)
|
|
253
|
+
- Topic-based message routing within a channel
|
|
254
|
+
- Fine-grained publisher filtering per topic
|
|
255
|
+
- Max 64 users per stream channel, max 50 topics per channel
|
|
256
|
+
|
|
257
|
+
## Presence State and Metadata
|
|
258
|
+
|
|
259
|
+
### User State (setState / getState)
|
|
260
|
+
|
|
261
|
+
Set temporary key-value metadata on the current user that is broadcast to all subscribers:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// Set user state (visible to all channel subscribers)
|
|
265
|
+
await rtmClient.presence.setState("channel-name", "MESSAGE", {
|
|
266
|
+
displayName: "Alice",
|
|
267
|
+
status: "available",
|
|
268
|
+
typing: "false",
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
// Get a specific user's state
|
|
272
|
+
const result = await rtmClient.presence.getState("channel-name", "MESSAGE", "target-user-id")
|
|
273
|
+
console.log(result.states) // { displayName: "Alice", status: "available", ... }
|
|
274
|
+
|
|
275
|
+
// Remove state
|
|
276
|
+
await rtmClient.presence.removeState("channel-name", "MESSAGE", ["typing"])
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
State is ephemeral — it is cleared when the user leaves or disconnects. Other users receive `STATE_CHANGED` presence events when state is updated.
|
|
280
|
+
|
|
281
|
+
### Channel Metadata (Storage)
|
|
282
|
+
|
|
283
|
+
Store persistent metadata on a channel (survives user disconnect):
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// Set channel metadata
|
|
287
|
+
const metadata = new AgoraRTM.Metadata()
|
|
288
|
+
metadata.setMetadataItem({ key: "roomTitle", value: "Team Standup" })
|
|
289
|
+
metadata.setMetadataItem({ key: "maxParticipants", value: "10" })
|
|
290
|
+
await rtmClient.storage.setChannelMetadata("channel-name", "MESSAGE", metadata, {})
|
|
291
|
+
|
|
292
|
+
// Get channel metadata
|
|
293
|
+
const result = await rtmClient.storage.getChannelMetadata("channel-name", "MESSAGE")
|
|
294
|
+
for (const item of result.metadata.items) {
|
|
295
|
+
console.log(item.key, item.value)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Subscribe to metadata updates
|
|
299
|
+
await rtmClient.storage.subscribeChannelMetadata("channel-name", "MESSAGE")
|
|
300
|
+
rtmClient.addEventListener("storage", (event) => {
|
|
301
|
+
console.log("Metadata updated:", event.data)
|
|
302
|
+
})
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Important Notes
|
|
306
|
+
|
|
307
|
+
- RTM does **not** echo published messages back to the sender. Your chat UI must add sent messages locally.
|
|
308
|
+
- RTM uses **string UIDs** while RTC uses numeric UIDs. A common mapping strategy: use `String(rtcUid)` as the RTM userId, or maintain a lookup table if usernames differ.
|
|
309
|
+
- `presenceTimeout` can be configured during RTM initialization:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
try {
|
|
313
|
+
const rtmClient = new AgoraRTM.RTM(appId, userId, {
|
|
314
|
+
presenceTimeout: 30, // seconds (5-1800), default 5
|
|
315
|
+
});
|
|
316
|
+
} catch (status) {
|
|
317
|
+
console.error("RTM init failed", status);
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Connection Management
|
|
322
|
+
|
|
323
|
+
### Heartbeat Configuration
|
|
324
|
+
|
|
325
|
+
- **MESSAGE channels**: Heartbeat interval defaults to **5 seconds**, customizable from 5–1800 seconds via `presenceTimeout` config.
|
|
326
|
+
- **STREAM channels**: Fixed heartbeat interval of **0.5 seconds** (not configurable).
|
|
327
|
+
- Set `presenceTimeout` appropriately to prevent excessive presence event floods during brief network reconnections.
|
|
328
|
+
|
|
329
|
+
### Connection Cleanup
|
|
330
|
+
|
|
331
|
+
- Always call `logout()` for MESSAGE channel connections.
|
|
332
|
+
- Always call `leave()` for STREAM channel connections before disconnecting.
|
|
333
|
+
- Failure to clean up properly causes ghost presence entries until heartbeat timeout.
|
|
334
|
+
|
|
335
|
+
### REST API Rate Limiting
|
|
336
|
+
|
|
337
|
+
When using RTM REST APIs, implement exponential back-off on rate limit responses:
|
|
338
|
+
|
|
339
|
+
- 1st retry: wait **1 second**
|
|
340
|
+
- 2nd retry: wait **3 seconds**
|
|
341
|
+
- 3rd retry: wait **6 seconds**
|
|
342
|
+
|
|
343
|
+
## Official Documentation
|
|
344
|
+
|
|
345
|
+
For APIs or features not covered above:
|
|
346
|
+
|
|
347
|
+
- API Reference: <https://docs.agora.io/en/signaling/reference/api?platform=web>
|
|
348
|
+
- Guides: <https://docs.agora.io/en/signaling/overview/product-overview>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Agora Server-Side: Token Generation
|
|
2
|
+
|
|
3
|
+
Server-side token generation for Agora authentication.
|
|
4
|
+
|
|
5
|
+
## When Tokens Are Needed
|
|
6
|
+
|
|
7
|
+
- **Production**: Always. Tokens authenticate users before they join channels.
|
|
8
|
+
- **Testing/Development**: Technically optional — token auth can be disabled in [Agora Console](https://console.agora.io), allowing `null` to be passed as the token. **Warn the user if they attempt this**: any channel can be joined by anyone without authentication. This is never acceptable for production and should be avoided even in development unless strictly necessary.
|
|
9
|
+
- **No App Certificate provided**: If the user has no App Certificate, they cannot generate tokens. Warn them explicitly that their project has no token security enabled, advise them to enable it in [Agora Console](https://console.agora.io) → Project Management → Edit → App Certificate, and do not proceed to generate code that omits token auth without this warning.
|
|
10
|
+
- **Never expose App Certificate on client**. Token generation must happen server-side.
|
|
11
|
+
|
|
12
|
+
## Token Types
|
|
13
|
+
|
|
14
|
+
- **RTC Token**: Grants access to join a specific RTC channel with a specific UID. Required for Video/Voice SDK.
|
|
15
|
+
- **RTM Token**: Grants access to RTM services for a specific user ID.
|
|
16
|
+
- **AccessToken2**: Current token format. Supports privilege expiration per service and can bundle RTC + RTM privileges in a single token.
|
|
17
|
+
|
|
18
|
+
## Reference Files
|
|
19
|
+
|
|
20
|
+
- **[tokens.md](tokens.md)** — Token generation for Node.js, Python, and Go. Express server example, security best practices.
|
|
21
|
+
- **Full token auth guide** — <https://docs-md.agora.io/en/video-calling/token-authentication/deploy-token-server.md>
|
|
22
|
+
- **Local credential export** — for development setup, use [../cli/env.md](../cli/env.md) to export or write App ID/App Certificate values with the Agora CLI. Never expose the App Certificate to client code.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Agora Server-Side: Token Generation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Tokens authenticate users before joining channels. Generated server-side from App ID + App Certificate + channel + UID + expiration.
|
|
6
|
+
|
|
7
|
+
## Quick Reference
|
|
8
|
+
|
|
9
|
+
- `onTokenPrivilegeWillExpire` fires **30 seconds** before expiry — renew proactively
|
|
10
|
+
- UID in token must match UID used to join
|
|
11
|
+
- Max token validity: 24 hours
|
|
12
|
+
- Use `RtcRole.SUBSCRIBER` for audience-only users (prevents stream bombing)
|
|
13
|
+
|
|
14
|
+
## UID / Account-Name Constraints (Token Gotcha)
|
|
15
|
+
|
|
16
|
+
- Numeric UID (`buildTokenWithUid` + RTC join with numeric uid): must be `0` to `2^32 - 1`.
|
|
17
|
+
- String UID/account name (`buildTokenWithUserAccount` or `buildTokenWithRtm` account): ASCII only, max `255` characters.
|
|
18
|
+
- **RTM / `buildTokenWithRtm` `account`**: the API expects a string. Prefer an integer user id encoded as a string of digits (for example `"12345"`), not an arbitrary alphanumeric handle, to avoid identity clashes with other services.
|
|
19
|
+
- Here, `account` means the user's RTC identity string (account name), not your Agora customer account.
|
|
20
|
+
- Identity and type must match end-to-end:
|
|
21
|
+
- If the token is minted for numeric UID `123`, join RTC with numeric `123`.
|
|
22
|
+
- If the token is minted for account `"12345"` (string carrying a numeric id — preferred), join with that exact same string identity on the client; do not substitute a different handle or assume it interchangeably maps to a numeric uid unless your SDK documents that.
|
|
23
|
+
|
|
24
|
+
## Token Generation Guides
|
|
25
|
+
|
|
26
|
+
- **[Deploy a Token Server](https://docs.agora.io/en/video-calling/token-authentication/deploy-token-server)** — Express/Flask/Go server examples
|
|
27
|
+
- **[Use Tokens](https://docs.agora.io/en/video-calling/token-authentication/authentication-workflow)** — When and how tokens are used
|
|
28
|
+
|
|
29
|
+
## Token Libraries
|
|
30
|
+
|
|
31
|
+
All implementations are in [AgoraIO/Tools — DynamicKey/AgoraDynamicKey](https://github.com/AgoraIO/Tools/tree/master/DynamicKey/AgoraDynamicKey):
|
|
32
|
+
|
|
33
|
+
| Language | Notes |
|
|
34
|
+
| -------- | ----------------------------------------------------------------------------------- |
|
|
35
|
+
| Node.js | Also available as [`agora-token`](https://www.npmjs.com/package/agora-token) on npm |
|
|
36
|
+
| Python 3 | Use `python3/` directory |
|
|
37
|
+
| Go | |
|
|
38
|
+
| Java | |
|
|
39
|
+
| C# | |
|
|
40
|
+
| Dart | |
|
|
41
|
+
| Deno | Native implementation — do NOT use the `agora-token` npm package in Deno |
|
|
42
|
+
| Rust | |
|
|
43
|
+
| PHP | |
|
|
44
|
+
| Ruby | |
|
|
45
|
+
| Lua | |
|
|
46
|
+
| Perl | |
|
|
47
|
+
|
|
48
|
+
## Token Types
|
|
49
|
+
|
|
50
|
+
- **RTC Token** — channel access for Video/Voice SDK
|
|
51
|
+
- **RTM Token** — access for Real-Time Messaging
|
|
52
|
+
- **Combined RTC + RTM Token** — bundles RTC + RTM privileges in one token via `buildTokenWithRtm`; also satisfies the `agora token=` auth header for ConvoAI REST API calls (see [conversational-ai/README.md](../conversational-ai/README.md#authentication))
|
|
53
|
+
|
|
54
|
+
> **[AccessToken2 Guide](https://docs.agora.io/en/video-calling/token-authentication/deploy-token-server)** — AccessToken2 with multi-service privileges
|
|
55
|
+
|
|
56
|
+
## buildTokenWithRtm (Node.js)
|
|
57
|
+
|
|
58
|
+
Generates a combined RTC + RTM token using `AccessToken2`. Use this when you need a single token that covers both channel access and RTM messaging — or to authenticate ConvoAI REST API calls.
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
import { RtcTokenBuilder, RtcRole } from 'agora-token';
|
|
62
|
+
|
|
63
|
+
const token = RtcTokenBuilder.buildTokenWithRtm(
|
|
64
|
+
appId, // string — your Agora App ID
|
|
65
|
+
appCertificate, // string — your App Certificate
|
|
66
|
+
channelName, // string — channel the user will join
|
|
67
|
+
account, // string — prefer integer user id as a string of digits (e.g. "12345")
|
|
68
|
+
RtcRole.PUBLISHER,
|
|
69
|
+
tokenExpire, // number — seconds until token expires (e.g. 3600)
|
|
70
|
+
privilegeExpire, // number — seconds until privileges expire (0 = same as tokenExpire)
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> **`account` vs `uid`**: `buildTokenWithRtm` takes a string `account`, not an integer type. Prefer passing the user's numeric id as a numeric string, and have the client join with that exact same string identity. If the RTC client joins with a numeric uid type instead, use `buildTokenWithUid` for RTC-only tokens.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Agora Server Gateway SDK
|
|
2
|
+
|
|
3
|
+
Self-hosted SDK for transmitting audio and video streams between server-side applications and Agora's Voice and Video SDKs via the Agora SDRTN®.
|
|
4
|
+
|
|
5
|
+
## Critical Rules
|
|
6
|
+
|
|
7
|
+
1. **Video SDK channel must use `LIVE_BROADCASTING` mode** — standard `COMMUNICATION` mode is not supported when the remote peer is a Server Gateway client.
|
|
8
|
+
2. **PCM audio must be sent in 10 ms intervals** — the SDK only accepts PCM frames of exactly 10 ms length.
|
|
9
|
+
3. **AAC audio cannot use 44.1 kHz sampling** — use 16 kHz or 48 kHz instead.
|
|
10
|
+
4. **All SDK methods are async and non-blocking** — use event callbacks and observers; do not expect synchronous results.
|
|
11
|
+
5. **Server requires internet access to `*.agora.io` and `*.agoralab.co`** — ensure firewall rules allow outbound connections to these domains.
|
|
12
|
+
6. **This is a self-hosted SDK, not a REST API** — the SDK runs as a process on your Linux server, not as a cloud service you call.
|
|
13
|
+
|
|
14
|
+
## Key Concepts
|
|
15
|
+
|
|
16
|
+
- **IAgoraService** — root object. Create once per process, initialize with audio/video config before creating any connections.
|
|
17
|
+
- **IRtcConnection** — represents a connection to one RTC channel. Create one per channel. Manages join/leave lifecycle.
|
|
18
|
+
- **IMediaNodeFactory** — factory for creating senders and receivers (audio PCM sender, video YUV sender, encoded video sender, etc.).
|
|
19
|
+
- **Local tracks** — wrap senders/receivers and get published/subscribed via the connection.
|
|
20
|
+
- **Observers** — implement `ILocalUserObserver`, `IAudioFrameObserver`, `IVideoEncodedImageReceiver` to receive incoming media frames via callbacks.
|
|
21
|
+
|
|
22
|
+
## Architecture
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
Your Server App (Server Gateway SDK)
|
|
26
|
+
↕ audio/video frames (PCM, YUV, encoded)
|
|
27
|
+
Agora SDRTN® (global real-time network)
|
|
28
|
+
↕
|
|
29
|
+
Video SDK clients (Web, iOS, Android, etc.)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Typical flow:
|
|
33
|
+
1. Initialize `IAgoraService` with audio/video support enabled
|
|
34
|
+
2. Create `IRtcConnection` and join channel
|
|
35
|
+
3. Create media senders via `IMediaNodeFactory`, wrap in local tracks, publish
|
|
36
|
+
4. Register observers to receive incoming frames via callbacks
|
|
37
|
+
5. On shutdown: unpublish → unregister observers → disconnect → release all objects (order matters)
|
|
38
|
+
|
|
39
|
+
## Supported Platforms
|
|
40
|
+
|
|
41
|
+
| Platform | Language | Min OS |
|
|
42
|
+
|----------|----------|--------|
|
|
43
|
+
| Linux x86-64 | C++ | Ubuntu 14.04+ / CentOS 7.0+ |
|
|
44
|
+
| Linux x86-64 | Java | Ubuntu 14.04+ / CentOS 7.0+ |
|
|
45
|
+
| Linux x86-64 | Go | Ubuntu 18.04+ / CentOS 7.0+ |
|
|
46
|
+
| Linux x86-64 | Python | Ubuntu 18.04+ / CentOS 7.0+ |
|
|
47
|
+
| arm64 | C++ | Ubuntu 14.04+ |
|
|
48
|
+
|
|
49
|
+
Hardware minimum: 8-core CPU 1.8 GHz, 2 GB RAM (4 GB recommended).
|
|
50
|
+
|
|
51
|
+
## Media Formats
|
|
52
|
+
|
|
53
|
+
| Type | Formats supported |
|
|
54
|
+
|------|------------------|
|
|
55
|
+
| Audio send | PCM (10 ms frames) |
|
|
56
|
+
| Audio receive | PCM |
|
|
57
|
+
| Video send | YUV, encoded (H.264, etc.) |
|
|
58
|
+
| Video receive | Encoded frames |
|
|
59
|
+
|
|
60
|
+
## Use Cases
|
|
61
|
+
|
|
62
|
+
- **Call centers** — server-side agent voice processing
|
|
63
|
+
- **AI interactive classes** — server processes audio/video for AI analysis
|
|
64
|
+
- **Network testing** — automated stream injection and validation
|
|
65
|
+
- **aPaaS** — application platform integrations that need server-side media
|
|
66
|
+
|
|
67
|
+
## Platform Reference Files
|
|
68
|
+
|
|
69
|
+
- **[linux-cpp.md](linux-cpp.md)** — C++ full implementation: init, senders, receivers, video mixing, shutdown sequence
|
|
70
|
+
- **Java, Go, Python** — Level 2 fetch required; use [../doc-fetching.md](../doc-fetching.md) or fetch directly from the links below
|
|
71
|
+
|
|
72
|
+
## When to Fetch More
|
|
73
|
+
|
|
74
|
+
Always use Level 2 fetch for Java, Go, and Python quick-starts, SDK download links, and any platform-specific method signatures. Direct fallback URLs:
|
|
75
|
+
|
|
76
|
+
- **Java** — <https://docs-md.agora.io/en/server-gateway/get-started/integrate-sdk?platform=java.md>
|
|
77
|
+
- **Go** — <https://docs-md.agora.io/en/server-gateway/get-started/integrate-sdk?platform=go.md>
|
|
78
|
+
- **Python** — <https://docs-md.agora.io/en/server-gateway/get-started/integrate-sdk?platform=python.md>
|
|
79
|
+
- **Product Overview** — <https://docs-md.agora.io/en/server-gateway/overview/product-overview.md>
|
|
80
|
+
- **SDK Downloads** — <https://docs.agora.io/en/sdks>
|