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,266 @@
|
|
|
1
|
+
# Agora RTC React Native SDK
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Installation](#installation)
|
|
6
|
+
- [Engine Initialization](#engine-initialization)
|
|
7
|
+
- [Joining a Channel](#joining-a-channel)
|
|
8
|
+
- [Video Setup](#video-setup)
|
|
9
|
+
- [Audio Setup](#audio-setup)
|
|
10
|
+
- [Event Handling](#event-handling)
|
|
11
|
+
- [Leaving and Cleanup](#leaving-and-cleanup)
|
|
12
|
+
- [Complete Example](#complete-example)
|
|
13
|
+
|
|
14
|
+
API Reference: <https://api-ref.agora.io/en/video-sdk/react-native/4.x/API/rtc_api_overview.html>
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install react-native-agora
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For iOS, run `pod install` in the `ios/` directory. Android requires no extra steps beyond Gradle sync.
|
|
23
|
+
|
|
24
|
+
Add permissions to `AndroidManifest.xml`:
|
|
25
|
+
|
|
26
|
+
```xml
|
|
27
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
28
|
+
<uses-permission android:name="android.permission.CAMERA" />
|
|
29
|
+
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
30
|
+
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
|
31
|
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
32
|
+
<uses-permission android:name="android.permission.BLUETOOTH" />
|
|
33
|
+
<!-- Android 12+ (API 31+): required for Bluetooth audio headsets -->
|
|
34
|
+
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Add to `Info.plist` (iOS):
|
|
38
|
+
|
|
39
|
+
```xml
|
|
40
|
+
<key>NSCameraUsageDescription</key>
|
|
41
|
+
<string>Camera access for video calls</string>
|
|
42
|
+
<key>NSMicrophoneUsageDescription</key>
|
|
43
|
+
<string>Microphone access for audio calls</string>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Request runtime permissions before initializing (use `react-native-permissions` or the built-in `PermissionsAndroid`).
|
|
47
|
+
|
|
48
|
+
## Engine Initialization
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import {
|
|
52
|
+
createAgoraRtcEngine,
|
|
53
|
+
IRtcEngine,
|
|
54
|
+
ChannelProfileType,
|
|
55
|
+
ClientRoleType,
|
|
56
|
+
} from 'react-native-agora'
|
|
57
|
+
|
|
58
|
+
let agoraEngine: IRtcEngine
|
|
59
|
+
|
|
60
|
+
function initializeAgora() {
|
|
61
|
+
agoraEngine = createAgoraRtcEngine()
|
|
62
|
+
agoraEngine.initialize({
|
|
63
|
+
appId: 'your-app-id',
|
|
64
|
+
channelProfile: ChannelProfileType.ChannelProfileCommunication,
|
|
65
|
+
})
|
|
66
|
+
agoraEngine.enableVideo()
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Joining a Channel
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { ChannelMediaOptions, ClientRoleType } from 'react-native-agora'
|
|
74
|
+
|
|
75
|
+
function joinChannel() {
|
|
76
|
+
const options: ChannelMediaOptions = {
|
|
77
|
+
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
|
|
78
|
+
publishMicrophoneTrack: true,
|
|
79
|
+
publishCameraTrack: true,
|
|
80
|
+
autoSubscribeAudio: true,
|
|
81
|
+
autoSubscribeVideo: true,
|
|
82
|
+
}
|
|
83
|
+
agoraEngine.joinChannel(token, 'channel-name', uid, options)
|
|
84
|
+
// token: null for testing, uid: 0 for auto-assignment
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Video Setup
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { RtcSurfaceView, VideoCanvas, RenderModeType } from 'react-native-agora'
|
|
92
|
+
|
|
93
|
+
// Local preview — use uid=0
|
|
94
|
+
<RtcSurfaceView
|
|
95
|
+
canvas={{ uid: 0, renderMode: RenderModeType.RenderModeHidden }}
|
|
96
|
+
style={{ width: 320, height: 240 }}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
// Remote video — use the remote user's uid
|
|
100
|
+
<RtcSurfaceView
|
|
101
|
+
canvas={{ uid: remoteUid, renderMode: RenderModeType.RenderModeHidden }}
|
|
102
|
+
style={{ width: 320, height: 240 }}
|
|
103
|
+
/>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Audio Setup
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { AudioProfileType, AudioScenarioType } from 'react-native-agora'
|
|
110
|
+
|
|
111
|
+
// Mute/unmute local audio
|
|
112
|
+
agoraEngine.muteLocalAudioStream(true) // mute
|
|
113
|
+
agoraEngine.muteLocalAudioStream(false) // unmute
|
|
114
|
+
|
|
115
|
+
// Mute/unmute local video
|
|
116
|
+
agoraEngine.muteLocalVideoStream(true) // video off
|
|
117
|
+
agoraEngine.muteLocalVideoStream(false) // video on
|
|
118
|
+
|
|
119
|
+
// Speaker vs earpiece (Android/iOS)
|
|
120
|
+
agoraEngine.setEnableSpeakerphone(true) // speaker
|
|
121
|
+
agoraEngine.setEnableSpeakerphone(false) // earpiece
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Event Handling
|
|
125
|
+
|
|
126
|
+
Register event handlers **before** joining the channel.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { IRtcEngineEventHandler } from 'react-native-agora'
|
|
130
|
+
|
|
131
|
+
const eventHandler: IRtcEngineEventHandler = {
|
|
132
|
+
onJoinChannelSuccess: (connection, elapsed) => {
|
|
133
|
+
console.log('Joined channel:', connection.channelId, 'uid:', connection.localUid)
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
onUserJoined: (connection, remoteUid, elapsed) => {
|
|
137
|
+
console.log('Remote user joined:', remoteUid)
|
|
138
|
+
// Update state to render <RtcSurfaceView canvas={{ uid: remoteUid }} />
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
onUserOffline: (connection, remoteUid, reason) => {
|
|
142
|
+
console.log('Remote user left:', remoteUid)
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
onTokenPrivilegeWillExpire: (connection, token) => {
|
|
146
|
+
// Fetch new token and renew
|
|
147
|
+
fetchNewToken().then(newToken => {
|
|
148
|
+
agoraEngine.renewToken(newToken)
|
|
149
|
+
})
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
onError: (err, msg) => {
|
|
153
|
+
console.error('Agora error:', err, msg)
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
agoraEngine.registerEventHandler(eventHandler)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Leaving and Cleanup
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
function leaveChannel() {
|
|
164
|
+
agoraEngine.leaveChannel()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Full cleanup when component unmounts
|
|
168
|
+
function destroyAgora() {
|
|
169
|
+
agoraEngine.leaveChannel()
|
|
170
|
+
agoraEngine.unregisterEventHandler(eventHandler)
|
|
171
|
+
agoraEngine.release()
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Always call `release()` when the engine is no longer needed to free native resources.
|
|
176
|
+
|
|
177
|
+
## Complete Example
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import React, { useEffect, useState } from 'react'
|
|
181
|
+
import { View, Button } from 'react-native'
|
|
182
|
+
import {
|
|
183
|
+
createAgoraRtcEngine,
|
|
184
|
+
IRtcEngine,
|
|
185
|
+
IRtcEngineEventHandler,
|
|
186
|
+
ChannelProfileType,
|
|
187
|
+
ClientRoleType,
|
|
188
|
+
RtcSurfaceView,
|
|
189
|
+
RenderModeType,
|
|
190
|
+
} from 'react-native-agora'
|
|
191
|
+
|
|
192
|
+
const APP_ID = 'your-app-id'
|
|
193
|
+
const TOKEN = null // null for testing
|
|
194
|
+
const CHANNEL = 'test'
|
|
195
|
+
const UID = 0
|
|
196
|
+
|
|
197
|
+
export default function VideoCall() {
|
|
198
|
+
const [engine, setEngine] = useState<IRtcEngine | null>(null)
|
|
199
|
+
const [joined, setJoined] = useState(false)
|
|
200
|
+
const [remoteUid, setRemoteUid] = useState<number | null>(null)
|
|
201
|
+
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
const rtcEngine = createAgoraRtcEngine()
|
|
204
|
+
rtcEngine.initialize({
|
|
205
|
+
appId: APP_ID,
|
|
206
|
+
channelProfile: ChannelProfileType.ChannelProfileCommunication,
|
|
207
|
+
})
|
|
208
|
+
rtcEngine.enableVideo()
|
|
209
|
+
|
|
210
|
+
const handler: IRtcEngineEventHandler = {
|
|
211
|
+
onJoinChannelSuccess: () => setJoined(true),
|
|
212
|
+
onUserJoined: (_, uid) => setRemoteUid(uid),
|
|
213
|
+
onUserOffline: () => setRemoteUid(null),
|
|
214
|
+
}
|
|
215
|
+
rtcEngine.registerEventHandler(handler)
|
|
216
|
+
setEngine(rtcEngine)
|
|
217
|
+
|
|
218
|
+
return () => {
|
|
219
|
+
rtcEngine.leaveChannel()
|
|
220
|
+
rtcEngine.unregisterEventHandler(handler)
|
|
221
|
+
rtcEngine.release()
|
|
222
|
+
}
|
|
223
|
+
}, [])
|
|
224
|
+
|
|
225
|
+
const join = () => {
|
|
226
|
+
engine?.joinChannel(TOKEN, CHANNEL, UID, {
|
|
227
|
+
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
|
|
228
|
+
publishMicrophoneTrack: true,
|
|
229
|
+
publishCameraTrack: true,
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const leave = () => {
|
|
234
|
+
engine?.leaveChannel()
|
|
235
|
+
setJoined(false)
|
|
236
|
+
setRemoteUid(null)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<View style={{ flex: 1 }}>
|
|
241
|
+
{joined && (
|
|
242
|
+
<RtcSurfaceView
|
|
243
|
+
canvas={{ uid: 0, renderMode: RenderModeType.RenderModeHidden }}
|
|
244
|
+
style={{ width: '100%', height: 240 }}
|
|
245
|
+
/>
|
|
246
|
+
)}
|
|
247
|
+
{remoteUid !== null && (
|
|
248
|
+
<RtcSurfaceView
|
|
249
|
+
canvas={{ uid: remoteUid, renderMode: RenderModeType.RenderModeHidden }}
|
|
250
|
+
style={{ width: '100%', height: 240 }}
|
|
251
|
+
/>
|
|
252
|
+
)}
|
|
253
|
+
<Button title={joined ? 'Leave' : 'Join'} onPress={joined ? leave : join} />
|
|
254
|
+
</View>
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
For test setup and mocking patterns, see [references/testing-guidance/SKILL.md](../testing-guidance/SKILL.md).
|
|
260
|
+
|
|
261
|
+
## Official Documentation
|
|
262
|
+
|
|
263
|
+
For APIs or features not covered above:
|
|
264
|
+
|
|
265
|
+
- Quick-start guide: <https://docs-md.agora.io/en/video-calling/get-started/get-started-sdk.md?platform=react-native>
|
|
266
|
+
- API Reference: <https://api-ref.agora.io/en/video-sdk/react-native/4.x/API/rtc_api_overview.html>
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Agora RTC — React
|
|
2
|
+
|
|
3
|
+
Uses the `agora-rtc-react` package, which wraps `agora-rtc-sdk-ng` with React hooks and components.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install agora-rtc-react
|
|
9
|
+
# Since agora-rtc-react 2.x, you do not need to add agora-rtc-sdk-ng
|
|
10
|
+
# to your app's package.json manually.
|
|
11
|
+
# agora-rtc-react re-exports all agora-rtc-sdk-ng types and classes,
|
|
12
|
+
# so you can import AgoraRTC and its types from either package.
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
Create the client once outside your component tree, then wrap with `AgoraRTCProvider`:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import AgoraRTC, { AgoraRTCProvider } from 'agora-rtc-react';
|
|
21
|
+
import { useMemo } from 'react';
|
|
22
|
+
|
|
23
|
+
const client = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp8' });
|
|
24
|
+
|
|
25
|
+
function App() {
|
|
26
|
+
return (
|
|
27
|
+
<AgoraRTCProvider client={client}>
|
|
28
|
+
<VideoCall channel="test" token={null} />
|
|
29
|
+
</AgoraRTCProvider>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
> For live streaming (host/audience), use `mode: "live"` instead.
|
|
35
|
+
|
|
36
|
+
> **Codec interop**: `'vp8'` and `'vp9'` scale better in multi-user calls. `'h264'` does not scale well beyond small groups. If codecs differ between Web and native clients, Agora's server transcodes transparently (works but adds latency). See [cross-platform-coordination.md](cross-platform-coordination.md) for full interop notes.
|
|
37
|
+
|
|
38
|
+
> **UID constraints**: If you pass `uid` into `useJoin`, numeric UIDs must be `0` to `2^32 - 1`; string UIDs must be ASCII and at most `255` characters. Keep UID type consistent per channel.
|
|
39
|
+
|
|
40
|
+
## Video Call Component
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import {
|
|
44
|
+
LocalUser,
|
|
45
|
+
RemoteUser,
|
|
46
|
+
useIsConnected,
|
|
47
|
+
useJoin,
|
|
48
|
+
useLocalCameraTrack,
|
|
49
|
+
useLocalMicrophoneTrack,
|
|
50
|
+
usePublish,
|
|
51
|
+
useRemoteUsers,
|
|
52
|
+
} from 'agora-rtc-react';
|
|
53
|
+
import { useState } from 'react';
|
|
54
|
+
|
|
55
|
+
function VideoCall({
|
|
56
|
+
appId,
|
|
57
|
+
channel,
|
|
58
|
+
token,
|
|
59
|
+
}: {
|
|
60
|
+
appId: string;
|
|
61
|
+
channel: string;
|
|
62
|
+
token: string | null;
|
|
63
|
+
}) {
|
|
64
|
+
const [calling, setCalling] = useState(false);
|
|
65
|
+
const isConnected = useIsConnected();
|
|
66
|
+
|
|
67
|
+
const [micOn, setMicOn] = useState(true);
|
|
68
|
+
const [cameraOn, setCameraOn] = useState(true);
|
|
69
|
+
|
|
70
|
+
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
|
|
71
|
+
const { localCameraTrack } = useLocalCameraTrack(cameraOn);
|
|
72
|
+
|
|
73
|
+
useJoin({ appid: appId, channel, token: token ?? null }, calling);
|
|
74
|
+
usePublish([localMicrophoneTrack, localCameraTrack]);
|
|
75
|
+
|
|
76
|
+
const remoteUsers = useRemoteUsers();
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div>
|
|
80
|
+
{isConnected ? (
|
|
81
|
+
<>
|
|
82
|
+
<LocalUser
|
|
83
|
+
audioTrack={localMicrophoneTrack}
|
|
84
|
+
videoTrack={localCameraTrack}
|
|
85
|
+
cameraOn={cameraOn}
|
|
86
|
+
micOn={micOn}
|
|
87
|
+
playAudio={false}
|
|
88
|
+
/>
|
|
89
|
+
{remoteUsers.map((user) => (
|
|
90
|
+
<RemoteUser key={user.uid} user={user} />
|
|
91
|
+
))}
|
|
92
|
+
<button onClick={() => setMicOn((v) => !v)}>
|
|
93
|
+
{micOn ? 'Mute' : 'Unmute'}
|
|
94
|
+
</button>
|
|
95
|
+
<button onClick={() => setCameraOn((v) => !v)}>
|
|
96
|
+
{cameraOn ? 'Hide camera' : 'Show camera'}
|
|
97
|
+
</button>
|
|
98
|
+
<button onClick={() => setCalling(false)}>Leave</button>
|
|
99
|
+
</>
|
|
100
|
+
) : (
|
|
101
|
+
<button onClick={() => setCalling(true)}>Join</button>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Voice-Only (Audio Call)
|
|
109
|
+
|
|
110
|
+
Drop `useLocalCameraTrack` and remove `videoTrack` / `cameraOn` props:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import {
|
|
114
|
+
LocalUser,
|
|
115
|
+
RemoteUser,
|
|
116
|
+
useIsConnected,
|
|
117
|
+
useJoin,
|
|
118
|
+
useLocalMicrophoneTrack,
|
|
119
|
+
usePublish,
|
|
120
|
+
useRemoteUsers,
|
|
121
|
+
} from 'agora-rtc-react';
|
|
122
|
+
|
|
123
|
+
function VoiceCall({
|
|
124
|
+
appId,
|
|
125
|
+
channel,
|
|
126
|
+
token,
|
|
127
|
+
}: {
|
|
128
|
+
appId: string;
|
|
129
|
+
channel: string;
|
|
130
|
+
token: string | null;
|
|
131
|
+
}) {
|
|
132
|
+
const [calling, setCalling] = useState(false);
|
|
133
|
+
const isConnected = useIsConnected();
|
|
134
|
+
const [micOn, setMicOn] = useState(true);
|
|
135
|
+
|
|
136
|
+
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
|
|
137
|
+
useJoin({ appid: appId, channel, token: token ?? null }, calling);
|
|
138
|
+
usePublish([localMicrophoneTrack]);
|
|
139
|
+
|
|
140
|
+
const remoteUsers = useRemoteUsers();
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div>
|
|
144
|
+
{isConnected ? (
|
|
145
|
+
<>
|
|
146
|
+
<LocalUser
|
|
147
|
+
audioTrack={localMicrophoneTrack}
|
|
148
|
+
micOn={micOn}
|
|
149
|
+
playAudio={false}
|
|
150
|
+
/>
|
|
151
|
+
{remoteUsers.map((user) => (
|
|
152
|
+
<RemoteUser key={user.uid} user={user} />
|
|
153
|
+
))}
|
|
154
|
+
<button onClick={() => setMicOn((v) => !v)}>
|
|
155
|
+
{micOn ? 'Mute' : 'Unmute'}
|
|
156
|
+
</button>
|
|
157
|
+
<button onClick={() => setCalling(false)}>Leave</button>
|
|
158
|
+
</>
|
|
159
|
+
) : (
|
|
160
|
+
<button onClick={() => setCalling(true)}>Join</button>
|
|
161
|
+
)}
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Next.js / SSR
|
|
168
|
+
|
|
169
|
+
`agora-rtc-react` is browser-only. See **[nextjs.md](nextjs.md)** for the required dynamic import pattern — `next/dynamic` with `ssr: false` does not work in Next.js 14+ Server Components without extra steps.
|
|
170
|
+
|
|
171
|
+
## How the React SDK Differs from the Web SDK
|
|
172
|
+
|
|
173
|
+
The React SDK builds on `agora-rtc-sdk-ng` and handles several things automatically that require manual management in the raw Web SDK:
|
|
174
|
+
|
|
175
|
+
- **Track cleanup** — `useLocalMicrophoneTrack` and `useLocalCameraTrack` call `stop()` and `close()` automatically when the component unmounts or the track is disabled. No manual cleanup needed.
|
|
176
|
+
- **Channel leave** — `useJoin` leaves the channel when the second argument (`calling`) becomes `false` or the component unmounts.
|
|
177
|
+
- **Publish/unpublish** — `usePublish` publishes tracks when they become ready and unpublishes when they are disabled or null.
|
|
178
|
+
- **Remote audio playback** — `RemoteUser` plays remote audio automatically. No need to call `user.audioTrack.play()` manually.
|
|
179
|
+
- **Mute without stopping device** — pass `micOn={false}` / `cameraOn={false}` to `useLocalMicrophoneTrack` / `useLocalCameraTrack` to mute while keeping the device active. The hooks handle `setEnabled()` internally.
|
|
180
|
+
|
|
181
|
+
Prefer hooks and components over direct `client.*` calls in React. Drop down to the underlying `agora-rtc-sdk-ng` client (via `useRTCClient()`) only for advanced operations not exposed by the React layer.
|
|
182
|
+
|
|
183
|
+
## Official Documentation
|
|
184
|
+
|
|
185
|
+
- React Quickstart: <https://docs.agora.io/en/video-calling/get-started/get-started-sdk?platform=react-js>
|
|
186
|
+
- API Reference: <https://api-ref.agora.io/en/video-sdk/reactjs/2.x/>
|