trtc-cloud-js-sdk 1.0.13 → 2.0.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.
Files changed (143) hide show
  1. package/.eslintrc.js +88 -0
  2. package/.prettierrc +5 -0
  3. package/CHANGELOG.md +58 -0
  4. package/build/jsdoc/clean-doc.js +12 -0
  5. package/build/jsdoc/fix-doc.js +141 -0
  6. package/build/jsdoc/jsdoc.json +42 -0
  7. package/build/package-bundle.js +29 -0
  8. package/build/rollup.config.dev.js +88 -0
  9. package/build/rollup.config.prod.js +93 -0
  10. package/build/rollup.js +359 -0
  11. package/build/template/npm-package/package.json +24 -0
  12. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/base.css +213 -0
  13. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/index.html +80 -0
  14. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/prettify.css +1 -0
  15. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/prettify.js +1 -0
  16. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/sort-arrow-sprite.png +0 -0
  17. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/sorter.js +158 -0
  18. package/examples/apiExample/.env +2 -0
  19. package/examples/apiExample/README.md +70 -0
  20. package/examples/apiExample/package-lock.json +30915 -0
  21. package/examples/apiExample/package.json +51 -0
  22. package/examples/apiExample/public/audio.js +195 -0
  23. package/examples/apiExample/public/audio.js.map +7 -0
  24. package/examples/apiExample/public/av_processing.js +1 -0
  25. package/examples/apiExample/public/basic/av_processing.wasm +0 -0
  26. package/examples/apiExample/public/basic/worker.js +10434 -0
  27. package/examples/apiExample/public/favicon.ico +0 -0
  28. package/examples/apiExample/public/index.html +47 -0
  29. package/examples/apiExample/public/logo192.png +0 -0
  30. package/examples/apiExample/public/logo512.png +0 -0
  31. package/examples/apiExample/public/manifest.json +25 -0
  32. package/examples/apiExample/public/robots.txt +3 -0
  33. package/examples/apiExample/src/App.css +37 -0
  34. package/examples/apiExample/src/App.js +25 -0
  35. package/examples/apiExample/src/api/http.js +127 -0
  36. package/examples/apiExample/src/api/nav.js +44 -0
  37. package/examples/apiExample/src/components/BasicInfoComponent.css +16 -0
  38. package/examples/apiExample/src/components/BasicInfoComponent.js +27 -0
  39. package/examples/apiExample/src/config/gen-test-user-sig.js +64 -0
  40. package/examples/apiExample/src/config/lib-generate-test-usersig.min.js +7052 -0
  41. package/examples/apiExample/src/config/nav.js +136 -0
  42. package/examples/apiExample/src/home.js +16 -0
  43. package/examples/apiExample/src/index.css +21 -0
  44. package/examples/apiExample/src/index.js +12 -0
  45. package/examples/apiExample/src/logo.svg +1 -0
  46. package/examples/apiExample/src/page/basic/screen-share/index.css +52 -0
  47. package/examples/apiExample/src/page/basic/screen-share/index.js +223 -0
  48. package/examples/apiExample/src/page/basic/setDevice/index.js +262 -0
  49. package/examples/apiExample/src/page/basic/setDevice/index.scss +93 -0
  50. package/examples/apiExample/src/page/basic/video-call/index.js +521 -0
  51. package/examples/apiExample/src/page/basic/video-call/index.scss +93 -0
  52. package/examples/apiExample/src/page/basic/video-call-init/index.js +382 -0
  53. package/examples/apiExample/src/page/basic/video-call-init/index.scss +93 -0
  54. package/examples/apiExample/src/page/basic/video-live/index.css +37 -0
  55. package/examples/apiExample/src/page/basic/video-live/index.js +188 -0
  56. package/examples/apiExample/src/page/layout.js +22 -0
  57. package/examples/apiExample/src/page/layout.scss +76 -0
  58. package/examples/apiExample/src/utils/utils.js +35 -0
  59. package/examples/jsExample/assets/css/bootstrap-material-design.css +12169 -0
  60. package/examples/jsExample/assets/css/bootstrap-material-design.min.css +8 -0
  61. package/examples/jsExample/assets/css/common.css +48 -0
  62. package/examples/jsExample/assets/icon/iconfont.js +1 -0
  63. package/examples/jsExample/assets/js/bootstrap-material-design.js +6939 -0
  64. package/examples/jsExample/assets/js/bootstrap-material-design.js.map +1 -0
  65. package/examples/jsExample/assets/js/bootstrap-material-design.min.js +1 -0
  66. package/examples/jsExample/assets/js/graph.js +695 -0
  67. package/examples/jsExample/assets/js/jquery-3.2.1.min.js +4 -0
  68. package/examples/jsExample/assets/js/jquery-3.2.1.slim.min.js +4 -0
  69. package/examples/jsExample/assets/js/lib-generate-test-usersig.min.js +2 -0
  70. package/examples/jsExample/assets/js/popper.js +2442 -0
  71. package/examples/jsExample/index.html +57 -0
  72. package/examples/jsExample/rtc/css/common.css +82 -0
  73. package/examples/jsExample/rtc/index.html +107 -0
  74. package/examples/jsExample/rtc/js/index.js +142 -0
  75. package/examples/vueDemo/LICENSE +21 -0
  76. package/examples/vueDemo/README.md +144 -0
  77. package/examples/vueDemo/README_EN.md +136 -0
  78. package/examples/vueDemo/av_processing.wasm +0 -0
  79. package/examples/vueDemo/index.html +23 -0
  80. package/examples/vueDemo/package-lock.json +1375 -0
  81. package/examples/vueDemo/package.json +36 -0
  82. package/examples/vueDemo/src/App.vue +12 -0
  83. package/examples/vueDemo/src/api/index.js +59 -0
  84. package/examples/vueDemo/src/assets/css/color-dark.css +28 -0
  85. package/examples/vueDemo/src/assets/css/icon.css +4 -0
  86. package/examples/vueDemo/src/assets/css/main.css +177 -0
  87. package/examples/vueDemo/src/assets/img/img.jpg +0 -0
  88. package/examples/vueDemo/src/assets/img/login-bg.jpg +0 -0
  89. package/examples/vueDemo/src/components/Header.vue +172 -0
  90. package/examples/vueDemo/src/components/Sidebar.vue +117 -0
  91. package/examples/vueDemo/src/components/Tags.vue +174 -0
  92. package/examples/vueDemo/src/components/tendency.vue +206 -0
  93. package/examples/vueDemo/src/components/trtc/main-menu.vue +50 -0
  94. package/examples/vueDemo/src/components/trtc/nav-bar.vue +53 -0
  95. package/examples/vueDemo/src/components/trtc/show-screen-capture.vue +118 -0
  96. package/examples/vueDemo/src/components/trtc/trtc-state-check.vue +117 -0
  97. package/examples/vueDemo/src/config/gen-test-user-sig.js +67 -0
  98. package/examples/vueDemo/src/config/lib-generate-test-usersig.min.js +7052 -0
  99. package/examples/vueDemo/src/main.js +11 -0
  100. package/examples/vueDemo/src/plugins/element.js +17 -0
  101. package/examples/vueDemo/src/router/index.js +73 -0
  102. package/examples/vueDemo/src/store/sidebar.js +17 -0
  103. package/examples/vueDemo/src/store/tags.js +48 -0
  104. package/examples/vueDemo/src/utils/i18n.js +24 -0
  105. package/examples/vueDemo/src/utils/request.js +34 -0
  106. package/examples/vueDemo/src/utils/utils.js +35 -0
  107. package/examples/vueDemo/src/views/Home.vue +46 -0
  108. package/examples/vueDemo/src/views/I18n.vue +40 -0
  109. package/examples/vueDemo/src/views/Icon.vue +229 -0
  110. package/examples/vueDemo/src/views/basic/trtc.vue +194 -0
  111. package/examples/vueDemo/src/views/feature/index.vue +259 -0
  112. package/examples/vueDemo/src/views/github/index.vue +243 -0
  113. package/examples/vueDemo/src/views/improve/live-index.vue +256 -0
  114. package/examples/vueDemo/src/views/improve/live-room-anchor.vue +689 -0
  115. package/examples/vueDemo/src/views/improve/live-room-audience.vue +383 -0
  116. package/examples/vueDemo/src/views/sdkAppId/index.vue +284 -0
  117. package/examples/vueDemo/vite.config.js +18 -0
  118. package/examples/vueDemo/worker.js +22 -0
  119. package/karma.conf.js +99 -0
  120. package/package.json +57 -7
  121. package/scripts/publish.js +86 -0
  122. package/src/Camera.ts +80 -0
  123. package/src/Mic.ts +145 -0
  124. package/src/common/IError.ts +6 -0
  125. package/src/common/ITRTCCloud.ts +68 -0
  126. package/src/common/constants.ts +116 -0
  127. package/src/common/trtc-code.ts +43 -0
  128. package/src/common/trtc-define.ts +1007 -0
  129. package/src/common/trtc-event.ts +29 -0
  130. package/src/index.ts +1672 -0
  131. package/src/utils/environment.js +297 -0
  132. package/src/utils/raf.js +131 -0
  133. package/src/utils/time.js +22 -0
  134. package/src/utils/utils.ts +71 -0
  135. package/src/utils/uuid.js +12 -0
  136. package/test/unit/env.test.js +25 -0
  137. package/test/unit/get-user-media.test.js +40 -0
  138. package/test/unit/ice-parser.test.js +23 -0
  139. package/test/unit/sdp.test.js +45 -0
  140. package/test/unit/signal.test.js +78 -0
  141. package/tsconfig.json +32 -0
  142. package/trtc-cloud-js-sdk.js +0 -1
  143. /package/{README.md → build/template/npm-package/README.md} +0 -0
@@ -0,0 +1,382 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import React, { useState, useEffect } from 'react';
3
+ import { Button } from '@material-ui/core';
4
+ import './index.scss';
5
+ import BasicInfoComponent from '../../../components/BasicInfoComponent';
6
+ import TRTC_Cloud from 'trtc-cloud-js-sdk';
7
+ // import TRTC_Cloud, { TRTCAppScene, TRTCParams, TRTCVideoStreamType } from 'trtc-cloud';
8
+ import genTestUserSig from '../../../config/gen-test-user-sig';
9
+ import { validParams, getUrlParam } from '../../../utils/utils';
10
+ const trtcCloud = TRTC_Cloud.getTRTCShareInstance();
11
+ let preRemoteUserIdList = [];
12
+
13
+ export default function VideoCall() {
14
+ const [userId, setUserId] = useState(getUrlParam('userId') ? getUrlParam('userId') : 'TRTCCloud_' + parseInt(Math.random() * 100000));
15
+ const [roomId, setRoomId] = useState(getUrlParam('roomId') ? getUrlParam('roomId') : parseInt(Math.random() * 100000) + '');
16
+ const [remoteUserIdList, setRemoteUserIdList] = useState([]);
17
+ const [isMuteAllRemoteAudio, setIsMuteAllRemoteAudio] = useState(false);
18
+ const [isStopRemote, setIsStopRemote] = useState(false);
19
+ const [cameraList, setCameraList] = useState([]);
20
+ const [micList, setMicList] = useState([]);
21
+ const [speakerList, setSpeakerList] = useState([]);
22
+ let info = {};
23
+ let sdkAppId = 0 || info.sdkAppId;
24
+ let userSignature = '';
25
+ let shareUserId = 'share_' + userId;
26
+ let shareUserSig = '';
27
+ const LOG_PREFIX = '[Video Call]';
28
+
29
+ useEffect(() => {
30
+ console.warn(`${LOG_PREFIX} TRTC version:`, trtcCloud.getSDKVersion());
31
+ subscribeEvents();
32
+
33
+ async function getDeviceList() {
34
+ const tempCameraList = await trtcCloud.getCameraDevicesList();
35
+ const tempMicList = await trtcCloud.getMicDevicesList();
36
+ const tempSpeakerList = await trtcCloud.getSpeakerDevicesList();
37
+ console.warn('==== camera list = ', tempCameraList);
38
+ console.warn('==== mic list = ', tempMicList);
39
+ console.warn('==== speaker list = ', tempSpeakerList);
40
+
41
+ setCameraList(tempCameraList);
42
+ setMicList(tempMicList);
43
+ setSpeakerList(tempSpeakerList);
44
+ }
45
+ getDeviceList();
46
+ }, []);
47
+
48
+ useEffect(() => {
49
+ try {
50
+ remoteUserIdList.forEach(async (userId) => {
51
+ const domElement = document.getElementById(userId);
52
+ await trtcCloud.startRemoteView(userId, domElement, TRTCVideoStreamType.TRTCVideoStreamTypeBig);
53
+ });
54
+ } catch (error) {
55
+ console.error(`${LOG_PREFIX} remoteUserIdList useEffect error: ${JSON.stringify(error)}`);
56
+ }
57
+ }, [remoteUserIdList]);
58
+
59
+ // 进房
60
+ const enterRoom = async () => {
61
+ const trtcParams = new TRTCParams();
62
+ trtcParams.userId = userId;
63
+ trtcParams.sdkAppId = sdkAppId;
64
+ trtcParams.userSig = userSignature;
65
+ trtcParams.roomId = +roomId;
66
+ await trtcCloud.enterRoom(trtcParams, TRTCAppScene.TRTCAppSceneVideoCall);
67
+ };
68
+ // 退房
69
+ const exitRoom = async () => {
70
+ setRemoteUserIdList([]);
71
+ preRemoteUserIdList = [];
72
+ await stopLocalPreview();
73
+ await stopLocalAudio();
74
+ await trtcCloud.exitRoom();
75
+ unsubscribeEvents();
76
+ };
77
+ // input 输入框内容改变处理
78
+ const handleInputChange = (event, type) => {
79
+ if (type === 'USERID') {
80
+ setUserId(event.target.value);
81
+ }
82
+ if (type === 'ROOMID') {
83
+ setRoomId(event.target.value);
84
+ }
85
+ };
86
+ const handleStart = () => {
87
+ info = genTestUserSig(userId);
88
+ sdkAppId = info.sdkAppId;
89
+ userSignature = info.userSig;
90
+ shareUserSig = genTestUserSig(shareUserId).userSig;
91
+ if (!validParams(userId, +roomId, sdkAppId, userSignature)) {
92
+ return;
93
+ }
94
+ enterRoom();
95
+ };
96
+ const handleStop = () => exitRoom();
97
+ // 打开本地视频
98
+ const startLocalPreview = async () => {
99
+ try {
100
+ const localVideoWrapper = document.getElementById('localVideoWrapper');
101
+ await trtcCloud.startLocalPreview('localVideoWrapper');
102
+ console.warn('startLocalPreview 预览 ---> ');
103
+ } catch (error) {
104
+ console.warn('startLocalPreview error ---> ', error);
105
+ }
106
+ };
107
+ // 关闭本地视频
108
+ const stopLocalPreview = () => trtcCloud.stopLocalPreview();
109
+ // mute/unmute video 操作
110
+ const muteVideo = (mute) => {
111
+ console.warn(`${LOG_PREFIX} local video mute state = ${mute}`);
112
+ trtcCloud.muteLocalVideo(mute);
113
+ };
114
+ // 开启本地音频
115
+ const startLocalAudio = async () => await trtcCloud.startLocalAudio();
116
+ // 关闭本地音频
117
+ const stopLocalAudio = async () => await trtcCloud.stopLocalAudio();
118
+ // 静音掉远端所有用户 audio
119
+ const muteAllRemoteAudio = async () => {
120
+ trtcCloud.muteAllRemoteAudio();
121
+ setIsMuteAllRemoteAudio(!isMuteAllRemoteAudio);
122
+ };
123
+ // 打开音量回调,这用可从 onUserVoiceVolume 事件中获取相应用户的音量
124
+ const handleEnableAudioVolumeEvaluation = async () => {
125
+ await trtcCloud.enableAudioVolumeEvaluation(500);
126
+ };
127
+ // 关闭音量回调
128
+ const handleDisableAudioVolumeEvaluation = async () => {
129
+ await trtcCloud.enableAudioVolumeEvaluation(-1);
130
+ };
131
+ // 切换设备
132
+ const handleChangeDevice = async (e, type) => {
133
+ const deviceId = e.target.value;
134
+ console.warn(' select device id: ', deviceId);
135
+ if (type === 'CAMERA') {
136
+ await trtcCloud.setCurrentCameraDevice(deviceId);
137
+ } else if (type === 'MIC') {
138
+ let currentMicDevice = trtcCloud.getCurrentMicDevice();
139
+ console.warn(`${LOG_PREFIX} current Mic deviceId before :`, currentMicDevice);
140
+
141
+ await trtcCloud.setCurrentMicDevice(deviceId);
142
+
143
+ currentMicDevice = trtcCloud.getCurrentMicDevice();
144
+ console.warn(`${LOG_PREFIX} current Mic deviceId after :`, currentMicDevice);
145
+ } else if (type === 'SPEAKER') {
146
+ await trtcCloud.setCurrentSpeakerDevice(deviceId);
147
+ console.warn('---- 切换 speaker ');
148
+ }
149
+ };
150
+ // 开始屏幕分享
151
+ const handleStartScreenShare = async () => {
152
+ const options = { shareUserId, shareUserSig };
153
+ console.warn(' 屏幕分享 = ', options);
154
+ await trtcCloud.startScreenShare(options);
155
+ };
156
+ // 停止屏幕分享
157
+ const handleStopScreenShare = async () => {
158
+ await trtcCloud.stopScreenShare();
159
+ };
160
+
161
+ // 操作第一个远端用户
162
+ const operateFirstRemote = async () => {
163
+ if (isStopRemote) {
164
+ const userId = remoteUserIdList[0];
165
+ const domElement = document.getElementById(userId);
166
+ await trtcCloud.startRemoteView(userId, domElement, TRTCVideoStreamType.TRTCVideoStreamTypeBig);
167
+ } else {
168
+ trtcCloud.stopRemoteView(remoteUserIdList[0], TRTCVideoStreamType.TRTCVideoStreamTypeBig);
169
+ }
170
+ setIsStopRemote(!isStopRemote);
171
+ };
172
+
173
+ // ============================【所有需要监听事件的回调】============================
174
+ // 错误回调
175
+ const onError = (errCode, errMsg) => {
176
+ console.warn(`${LOG_PREFIX} onError: errCode: ${errCode}, errMsg: ${errMsg}`);
177
+ };
178
+ // 进房回调
179
+ const onEnterRoom = (elapsed) => {
180
+ if (elapsed > 0) {
181
+ console.warn(`${LOG_PREFIX} onEnterRoom: elapsed: ${elapsed}`);
182
+ } else {
183
+ console.warn(`${LOG_PREFIX} onEnterRoom failed: elapsed: ${elapsed}`);
184
+ }
185
+ };
186
+ // 退房回调
187
+ const onExitRoom = (reason) => {
188
+ console.warn(`${LOG_PREFIX} onExitRoom: reason: ${reason}`);
189
+ };
190
+ // 远端用户进房事件
191
+ const onRemoteUserEnterRoom = (userId) => {
192
+ console.warn(`${LOG_PREFIX} onRemoteUserEnterRoom: userId: ${userId}`);
193
+ };
194
+ // 远端用户退房事件
195
+ const onRemoteUserLeaveRoom = (userId, reason) => {
196
+ console.warn(`${LOG_PREFIX} onRemoteUserLeaveRoom: userId: ${userId}, ${reason}`);
197
+ };
198
+ // 远端用户 video 可用事件
199
+ const onUserVideoAvailable = (userId, available) => {
200
+ console.warn(`${LOG_PREFIX} onUserVideoAvailable: userId: ${userId}, available: ${available}`);
201
+ if (available) {
202
+ if (preRemoteUserIdList.indexOf(userId) === -1) {
203
+ preRemoteUserIdList = [...preRemoteUserIdList, userId];
204
+ }
205
+ } else {
206
+ preRemoteUserIdList = preRemoteUserIdList.filter((str) => str !== userId);
207
+ }
208
+ setRemoteUserIdList(preRemoteUserIdList);
209
+ };
210
+ // 开启音量大小回调
211
+ const handleUserVoiceVolume = (userVolumes, userVolumesCount) => {
212
+ console.warn(`${LOG_PREFIX} onUserVoiceVolume result = `, userVolumes, userVolumesCount);
213
+ };
214
+ // audio available
215
+ const handleUserAudioAvailable = (userId, available) => {
216
+ console.warn(`${LOG_PREFIX} onUserAudioAvailable: userId: ${userId}, available: ${available}`);
217
+ };
218
+ // 远端屏幕分享流 onUserSubStreamAvailable 事件
219
+ const handleUserSubStreamAvailable = (userId, available) => {
220
+ console.warn('【1】onUserSubStreamAvailable ', userId, available);
221
+ if (available) {
222
+ trtcCloud.startRemoteView(userId, document.getElementById('remote-screen-share-container'), TRTCVideoStreamType.TRTCVideoStreamTypeSub);
223
+ }
224
+ };
225
+ // 网络质量统计数据事件
226
+ const handleOnNetworkQuality = (localQuality) => {
227
+ // console.warn(`${LOG_PREFIX} onNetworkQuality: `, localQuality);
228
+ };
229
+ // 设备变化:设备切换、设备插拔 事件
230
+ const handleOnDeviceChange = (deviceId, type, state) => {
231
+ console.warn(`${LOG_PREFIX} onDeviceChange: `, deviceId, type, state);
232
+ };
233
+ // 注册所有的事件监听
234
+ const subscribeEvents = () => {
235
+ trtcCloud.on('onError', onError);
236
+ trtcCloud.on('onEnterRoom', onEnterRoom);
237
+ trtcCloud.on('onExitRoom', onExitRoom);
238
+ trtcCloud.on('onRemoteUserEnterRoom', onRemoteUserEnterRoom);
239
+ trtcCloud.on('onRemoteUserLeaveRoom', onRemoteUserLeaveRoom);
240
+ trtcCloud.on('onUserVideoAvailable', onUserVideoAvailable);
241
+ trtcCloud.on('onUserAudioAvailable', handleUserAudioAvailable);
242
+ trtcCloud.on('onUserVoiceVolume', handleUserVoiceVolume);
243
+ trtcCloud.on('onUserSubStreamAvailable', handleUserSubStreamAvailable);
244
+ trtcCloud.on('onNetworkQuality', handleOnNetworkQuality);
245
+ trtcCloud.on('onDeviceChange', handleOnDeviceChange);
246
+ };
247
+ // 注销所有的事件监听
248
+ const unsubscribeEvents = () => {
249
+ // trtcCloud.off('*');
250
+ trtcCloud.off('onError', onError);
251
+ trtcCloud.off('onEnterRoom', onEnterRoom);
252
+ trtcCloud.off('onExitRoom', onExitRoom);
253
+ trtcCloud.off('onRemoteUserEnterRoom', onRemoteUserEnterRoom);
254
+ trtcCloud.off('onRemoteUserLeaveRoom', onRemoteUserLeaveRoom);
255
+ trtcCloud.off('onUserVideoAvailable', onUserVideoAvailable);
256
+ trtcCloud.off('onUserAudioAvailable', handleUserAudioAvailable);
257
+ trtcCloud.off('onUserVoiceVolume', handleUserVoiceVolume);
258
+ trtcCloud.off('onUserSubStreamAvailable', handleUserSubStreamAvailable);
259
+ trtcCloud.off('onNetworkQuality', handleOnNetworkQuality);
260
+ trtcCloud.off('onDeviceChange', handleOnDeviceChange);
261
+ };
262
+
263
+ return (
264
+ <div className="content-container">
265
+ <div className="operate-container">
266
+ <BasicInfoComponent userId={userId} roomId={roomId} handleInputChange={handleInputChange} handleStart={handleStart} handleStop={handleStop}></BasicInfoComponent>
267
+ {/* 摄像头选择 */}
268
+ <div className="select-container">
269
+ <label htmlFor="camera-select" className="select-item-label">
270
+ 摄像头:
271
+ </label>
272
+ <select id="camera-select" className="select-item" onChange={(e) => handleChangeDevice(e, 'CAMERA')}>
273
+ {cameraList.map((obj, idx) => (
274
+ <option key={obj.deviceId} value={obj.deviceId}>
275
+ {obj.deviceName}
276
+ </option>
277
+ ))}
278
+ </select>
279
+ </div>
280
+ {/* 麦克风选择 */}
281
+ <div className="select-container">
282
+ <label htmlFor="mic-select" className="select-item-label">
283
+ 麦克风:
284
+ </label>
285
+ <select id="mic-select" className="select-item" onChange={(e) => handleChangeDevice(e, 'MIC')}>
286
+ {micList.map((obj, idx) => (
287
+ <option key={obj.deviceId} value={obj.deviceId}>
288
+ {obj.deviceName}
289
+ </option>
290
+ ))}
291
+ </select>
292
+ </div>
293
+ {/* Speaker */}
294
+ <div className="select-container">
295
+ <label htmlFor="speaker-select" className="select-item-label">
296
+ 外放:
297
+ </label>
298
+ <select id="speaker-select" className="select-item" onChange={(e) => handleChangeDevice(e, 'SPEAKER')}>
299
+ {speakerList.map((obj, idx) => (
300
+ <option key={obj.deviceId} value={obj.deviceId}>
301
+ {obj.deviceName}
302
+ </option>
303
+ ))}
304
+ </select>
305
+ </div>
306
+ {/* 额外操作 */}
307
+ <div className="external-operate-container">
308
+ <div className="btn-operate-group">
309
+ <Button variant="contained" color="primary" onClick={() => startLocalPreview()}>
310
+ 打开视频
311
+ </Button>
312
+ <Button variant="contained" color="primary" onClick={() => stopLocalPreview()}>
313
+ 关闭视频
314
+ </Button>
315
+ </div>
316
+ <div className="btn-operate-group">
317
+ <Button variant="contained" color="primary" onClick={() => muteVideo(true)}>
318
+ Mute 视频
319
+ </Button>
320
+ <Button variant="contained" color="primary" onClick={() => muteVideo(false)}>
321
+ UnMute 视频
322
+ </Button>
323
+ </div>
324
+ <div className="btn-operate-group">
325
+ <Button variant="contained" color="primary" onClick={() => startLocalAudio()}>
326
+ 打开音频
327
+ </Button>
328
+ <Button variant="contained" color="primary" onClick={() => stopLocalAudio()}>
329
+ 关闭音频
330
+ </Button>
331
+ </div>
332
+ <div className="btn-operate-group">
333
+ <Button variant="contained" color="primary" onClick={() => handleEnableAudioVolumeEvaluation()}>
334
+ 开启音量回调
335
+ </Button>
336
+ <Button variant="contained" color="primary" onClick={() => handleDisableAudioVolumeEvaluation()}>
337
+ 关闭音量回调
338
+ </Button>
339
+ </div>
340
+ <div className="btn-operate-group">
341
+ <Button variant="contained" color="primary" onClick={() => handleStartScreenShare()}>
342
+ 开启屏幕分享
343
+ </Button>
344
+ <Button variant="contained" color="primary" onClick={() => handleStopScreenShare()}>
345
+ 关闭屏幕分享
346
+ </Button>
347
+ </div>
348
+ {/* <Button variant="contained" color="primary" onClick={() => operateFirstRemote()} style={{ marginTop: '8px' }}>
349
+ {isStopRemote ? 'start' : 'stop'}第一个远端用户
350
+ </Button> */}
351
+ {/*
352
+ <Button variant="contained" color="primary" onClick={() => disableAudioVolumeEvaluation()} style={{ marginTop: '8px' }}>关闭音量采集</Button>
353
+ <Button variant="contained" color="primary" onClick={() => muteAllRemoteAudio()} style={{ marginTop: '8px' }}>{isMuteAllRemoteAudio ? '开启' : '关闭'}远端所有音频</Button> */}
354
+ </div>
355
+ </div>
356
+
357
+ <div className="video-view-preview">
358
+ <div className="video-wrapper local-user">
359
+ <div className="user-desc">
360
+ <span className="user-type">本地用户</span>
361
+ <span className="user-role" id="localUserRole"></span>
362
+ </div>
363
+ <div id="localVideoWrapper"></div>
364
+ </div>
365
+ <div className="video-wrapper remote-user">
366
+ <div className="user-desc">
367
+ <span className="user-type">远程用户</span>
368
+ <span className="user-role" id="remoteUserRole"></span>
369
+ </div>
370
+ <div className="video-wrapper-container">
371
+ <div className="remoteVideoWrapper" id="remote-screen-share-container">
372
+ <div className="remote-share-text">远端屏幕分享</div>
373
+ </div>
374
+ {remoteUserIdList.map((userId, index) => (
375
+ <div id={userId} key={userId + '_' + index} className="remoteVideoWrapper"></div>
376
+ ))}
377
+ </div>
378
+ </div>
379
+ </div>
380
+ </div>
381
+ );
382
+ }
@@ -0,0 +1,93 @@
1
+ .content-container {
2
+ display: flex;
3
+ .operate-container {
4
+ display: flex;
5
+ flex-direction: column;
6
+ width: 330px;
7
+ .external-operate-container {
8
+ display: flex;
9
+ justify-content: center;
10
+ flex-direction: column;
11
+ .btn-operate-group {
12
+ display: flex;
13
+ justify-content: space-between;
14
+ margin-top: 6px;
15
+ }
16
+ }
17
+ .select-container {
18
+ display: flex;
19
+ margin-top: 8px;
20
+ .select-item-label {
21
+ flex: 1;
22
+ }
23
+ .select-item {
24
+ height: 28px;
25
+ width: 200px;
26
+ }
27
+ }
28
+ }
29
+ .video-view-preview {
30
+ margin-left: 12px;
31
+ }
32
+ }
33
+ .video-view-preview {
34
+ /* padding: 1rem 2rem; */
35
+ display: flex;
36
+ flex-direction: column;
37
+ justify-content: center;
38
+ }
39
+
40
+ .video-wrapper {
41
+ flex: 0 0 auto;
42
+ padding: 0 0.5rem;
43
+ }
44
+
45
+ .user-desc {
46
+ margin: 0.5rem 0rem;
47
+ }
48
+ .user-type {
49
+ font-weight: bold;
50
+ }
51
+ .video-wrapper-container {
52
+ display: flex;
53
+ flex-wrap: wrap;
54
+ margin-bottom: 1rem;
55
+ }
56
+ #localVideoWrapper,
57
+ .remoteVideoWrapper {
58
+ position: relative;
59
+ width: 320px;
60
+ height: 184px;
61
+ box-shadow: 2px 2px 18px 4px #c0c0c0;
62
+ background-color: lightblue;
63
+ margin-right: 20px;
64
+ border-radius: 8px;
65
+ }
66
+ .remote-share-text {
67
+ position: absolute;
68
+ background-color: white;
69
+ color: black;
70
+ opacity: 0.7;
71
+ border-radius: 6px;
72
+ bottom: 0rem;
73
+ display: flex;
74
+ justify-content: center;
75
+ align-items: center;
76
+ padding: 0rem 0.5rem;
77
+ z-index: 100;
78
+ }
79
+
80
+ .local-statistic,
81
+ .remote-statistic {
82
+ margin-top: 1rem;
83
+ }
84
+
85
+ .config-form {
86
+ margin: 1rem 0;
87
+ }
88
+
89
+ .form-line {
90
+ padding: 0.5rem 0.25rem;
91
+ }
92
+
93
+
@@ -0,0 +1,37 @@
1
+ .video-view-preview {
2
+ /* padding: 1rem 2rem; */
3
+ display: flex;
4
+ flex-direction: column;
5
+ justify-content: space-around;
6
+ }
7
+
8
+ .video-wrapper {
9
+ flex: 0 0 auto;
10
+ padding: 0 0.5rem;
11
+ }
12
+
13
+ .user-desc {
14
+ margin-bottom: 1rem;
15
+ }
16
+
17
+ #localVideoWrapper,
18
+ #remoteVideoWrapper {
19
+ width: 320px;
20
+ height: 184px;
21
+ box-shadow: 2px 2px 18px 4px #c0c0c0;
22
+ background-color: lightblue;
23
+ }
24
+
25
+ .local-statistic,
26
+ .remote-statistic {
27
+ margin-top: 1rem;
28
+ }
29
+
30
+ .config-form {
31
+ margin: 1rem 0;
32
+ }
33
+
34
+ .form-line {
35
+ padding: 0.5rem 0.25rem;
36
+ }
37
+
@@ -0,0 +1,188 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import a18n from 'a18n';
3
+ import React, { useState } from 'react';
4
+ import './index.css';
5
+ import TRTC_Cloud, {
6
+ TRTCAppScene,
7
+ TRTCParams,
8
+ TRTCVideoStreamType,
9
+ TRTCRoleType,
10
+ } from 'trtc-cloud-js-sdk';
11
+ import genTestUserSig from '../../../config/gen-test-user-sig';
12
+ import { validParams } from '../../../utils/utils';
13
+ import BasicInfoComponent from '../../../components/BasicInfoComponent';
14
+
15
+ function VideoCall(props) {
16
+ const [userId, setUserId] = useState('test');
17
+ const [roomId, setRoomId] = useState(14432);
18
+ let info = {};
19
+ let sdkAppId = 0 || info.sdkAppId;
20
+ let userSignature = '';
21
+ const LOG_PREFIX = '[Video Live]';
22
+ const trtc = new TRTC_Cloud();
23
+ console.log(`${LOG_PREFIX} TRTC version:`, trtc.getSDKVersion());
24
+
25
+ function onEnterRoom(elapsed) {
26
+ console.info(`${LOG_PREFIX} onEnterRoom: elapsed: ${elapsed}`);
27
+ }
28
+
29
+ function onExitRoom(reason) {
30
+ console.info(`${LOG_PREFIX} onExitRoom: reason: ${reason}`);
31
+ }
32
+
33
+ function onError(errCode, errMsg) {
34
+ console.info(`${LOG_PREFIX} onError: errCode: ${errCode}, errMsg: ${errMsg}`);
35
+ }
36
+
37
+ const anchorSet = new Set();
38
+ function onRemoteUserEnterRoom(userId) {
39
+ console.info(`${LOG_PREFIX} onRemoteUserEnterRoom: userId: ${userId}`);
40
+ anchorSet.add(userId);
41
+ }
42
+
43
+ function onRemoteUserLeaveRoom(userId, reason) {
44
+ console.info(`${LOG_PREFIX} onRemoteUserLeaveRoom: userId: ${userId}, ${reason}`);
45
+ anchorSet.delete(userId);
46
+ }
47
+
48
+ function onUserVideoAvailable(userId, available) {
49
+ console.info(`${LOG_PREFIX} onUserVideoAvailable: userId: ${userId}, available: ${available}`);
50
+ if (available) {
51
+ const remoteVideoWrapper = document.getElementById('remoteVideoWrapper');
52
+ trtc.startRemoteView(userId, remoteVideoWrapper, TRTCVideoStreamType.TRTCVideoStreamTypeBig);
53
+
54
+ const remoteUserRoleHTML = document.getElementById('remoteUserRole');
55
+ if (anchorSet.has(userId)) {
56
+ remoteUserRoleHTML && (remoteUserRoleHTML.innerText = ` - ${a18n('主播')}`);
57
+ }
58
+ } else {
59
+ const remoteUserRoleHTML = document.getElementById('remoteUserRole');
60
+ remoteUserRoleHTML && (remoteUserRoleHTML.innerText = '');
61
+ }
62
+ }
63
+
64
+ function onFirstVideoFrame(userId, streamType, width, height) {
65
+ console.info(`${LOG_PREFIX} onFirstVideoFrame: userId: ${userId} streamType: ${streamType} width: ${width} height: ${height}`);
66
+ if (userId) {
67
+ // 远程用户(remote user)
68
+ } else {
69
+ // 本地用户(local user)
70
+ }
71
+ }
72
+ function handleOnSwitchRole(code, message) {
73
+ console.warn('--- code ', code, message);
74
+ }
75
+
76
+ const subscribeEvents = () => {
77
+ trtc.on('onError', onError);
78
+ trtc.on('onEnterRoom', onEnterRoom);
79
+ trtc.on('onExitRoom', onExitRoom);
80
+ trtc.on('onRemoteUserEnterRoom', onRemoteUserEnterRoom);
81
+ trtc.on('onRemoteUserLeaveRoom', onRemoteUserLeaveRoom);
82
+ trtc.on('onUserVideoAvailable', onUserVideoAvailable);
83
+ trtc.on('onFirstVideoFrame', onFirstVideoFrame);
84
+ trtc.on('onSwitchRole', handleOnSwitchRole);
85
+ };
86
+
87
+ const unsubscribeEvents = () => {
88
+ trtc.off('onError', onError);
89
+ trtc.off('onEnterRoom', onEnterRoom);
90
+ trtc.off('onExitRoom', onExitRoom);
91
+ trtc.off('onRemoteUserEnterRoom', onRemoteUserEnterRoom);
92
+ trtc.off('onRemoteUserLeaveRoom', onRemoteUserLeaveRoom);
93
+ trtc.off('onUserVideoAvailable', onUserVideoAvailable);
94
+ trtc.off('onFirstVideoFrame', onFirstVideoFrame);
95
+ trtc.off('onSwitchRole', handleOnSwitchRole);
96
+ };
97
+
98
+ function enterRoom() {
99
+ const localVideoWrapper = document.getElementById('localVideoWrapper');
100
+ trtc.startLocalPreview(localVideoWrapper);
101
+
102
+ trtc.startLocalAudio();
103
+
104
+ const trtcParams = new TRTCParams();
105
+ trtcParams.userId = userId;
106
+ trtcParams.sdkAppId = sdkAppId;
107
+ trtcParams.userSig = userSignature;
108
+ trtcParams.roomId = roomId;
109
+ // trtcParams.role = TRTCRoleType.TRTCRoleAudience; // default role is 'TRTCRoleType.TRTCRoleAnchor'
110
+ trtcParams.role = parseInt(document.forms.roleSelectForm.roleType.value, 10);
111
+
112
+ trtc.enterRoom(trtcParams, TRTCAppScene.TRTCAppSceneLIVE);
113
+
114
+ const localUserRoleHTML = document.getElementById('localUserRole');
115
+ localUserRoleHTML.innerText = ` - ${trtcParams.role === TRTCRoleType.TRTCRoleAudience ? a18n('观众(音视频不上传)') : a18n('主播')}`;
116
+ }
117
+
118
+ function exitRoom() {
119
+ trtc.stopLocalPreview();
120
+ trtc.stopLocalAudio();
121
+ trtc.exitRoom();
122
+ }
123
+
124
+ const handleInputChange = (event, type) => {
125
+ if (type === 'USERID') {
126
+ setUserId(event.target.value);
127
+ }
128
+ if (type === 'ROOMID') {
129
+ setRoomId(event.target.value);
130
+ }
131
+ };
132
+ const handleStart = () => {
133
+ info = genTestUserSig(userId);
134
+ sdkAppId = info.sdkAppId;
135
+ userSignature = info.userSig;
136
+
137
+ if (!validParams(userId, roomId, sdkAppId, userSignature)) {
138
+ return;
139
+ }
140
+
141
+ subscribeEvents();
142
+ enterRoom();
143
+ };
144
+ const handleStop = () => {
145
+ exitRoom();
146
+ };
147
+ // 角色切换
148
+ const handleRadioChange = (e, value) => {
149
+ trtc.switchRole(12);
150
+ };
151
+
152
+ return (
153
+ <div className="basic-scene basic-video-live">
154
+ <form name="roleSelectForm" className="role-select-form">
155
+ <span>{a18n('选择角色:')}</span>
156
+ <input type="radio" id="roleTypeAnchor" name="roleType" value={TRTCRoleType.TRTCRoleAnchor} defaultChecked onChange={e => handleRadioChange(e, TRTCRoleType.TRTCRoleAnchor)} /><label htmlFor="roleTypeAnchor">{a18n('主播')}</label>
157
+ <input type="radio" id="roleTypeAudience" name="roleType" value={TRTCRoleType.TRTCRoleAudience} onChange={e => handleRadioChange(e, TRTCRoleType.TRTCRoleAudience)} /><label htmlFor="roleTypeAudience">{a18n('观众')}</label>
158
+ </form>
159
+
160
+ <BasicInfoComponent
161
+ userId={userId}
162
+ roomId={roomId}
163
+ handleInputChange={handleInputChange}
164
+ handleStart={handleStart}
165
+ handleStop={handleStop}
166
+ ></BasicInfoComponent>
167
+
168
+ <div className="video-view-preview">
169
+ <div className="video-wrapper local-user">
170
+ <div className="user-desc">
171
+ <span className="user-type">{a18n('本地用户')}</span>
172
+ <span className="user-role" id="localUserRole"></span>
173
+ </div>
174
+ <div id="localVideoWrapper"></div>
175
+ </div>
176
+ <div className="video-wrapper remote-user">
177
+ <div className="user-desc">
178
+ <span className="user-type">{a18n('远程用户')}</span>
179
+ <span className="user-role" id="remoteUserRole"></span>
180
+ </div>
181
+ <div id="remoteVideoWrapper"></div>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ );
186
+ }
187
+
188
+ export default VideoCall;