zbzt-live-sdk 0.0.2

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 (80) hide show
  1. package/.babelrc +8 -0
  2. package/.editorconfig +13 -0
  3. package/.eslintrc.js +29 -0
  4. package/CHANGELOG.md +16 -0
  5. package/README.md +32 -0
  6. package/dist/zbzt-live-sdk.cjs.js +51 -0
  7. package/dist/zbzt-live-sdk.esm.js +51 -0
  8. package/dist/zbzt-live-sdk.umd.js +52 -0
  9. package/dist/zbzt-live-sdk.umd.js.map +1 -0
  10. package/example/app.js +133 -0
  11. package/example/bootstrap-3.4.1/css/bootstrap-theme.css +587 -0
  12. package/example/bootstrap-3.4.1/css/bootstrap-theme.css.map +1 -0
  13. package/example/bootstrap-3.4.1/css/bootstrap-theme.min.css +6 -0
  14. package/example/bootstrap-3.4.1/css/bootstrap-theme.min.css.map +1 -0
  15. package/example/bootstrap-3.4.1/css/bootstrap.css +6834 -0
  16. package/example/bootstrap-3.4.1/css/bootstrap.css.map +1 -0
  17. package/example/bootstrap-3.4.1/css/bootstrap.min.css +6 -0
  18. package/example/bootstrap-3.4.1/css/bootstrap.min.css.map +1 -0
  19. package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.eot +0 -0
  20. package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.svg +288 -0
  21. package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.ttf +0 -0
  22. package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.woff +0 -0
  23. package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.woff2 +0 -0
  24. package/example/bootstrap-3.4.1/js/bootstrap.js +2580 -0
  25. package/example/bootstrap-3.4.1/js/bootstrap.min.js +6 -0
  26. package/example/bootstrap-3.4.1/js/npm.js +13 -0
  27. package/example/css/style.css +18 -0
  28. package/example/index.html +59 -0
  29. package/example/js/jquery-3.7.1.min.js +2 -0
  30. package/example/js/utils.js +25 -0
  31. package/example/js/variables.js +14 -0
  32. package/example/js/zegoApi.js +229 -0
  33. package/example/style.css +25 -0
  34. package/example/test.html +100 -0
  35. package/package.json +60 -0
  36. package/release.js +33 -0
  37. package/rollup-plugin-http.js +49 -0
  38. package/src/channel/getSendMsgParams.js +66 -0
  39. package/src/channel/index.js +135 -0
  40. package/src/channel/pomelo/index.js +182 -0
  41. package/src/channel/pomelo/latestQueue.js +150 -0
  42. package/src/channel/pomelo/polemo.js +730 -0
  43. package/src/channel/pomelo/util.js +54 -0
  44. package/src/channel/sdk-cb.js +73 -0
  45. package/src/channel/stream-msg.js +97 -0
  46. package/src/channel/zbzt/index.js +74 -0
  47. package/src/channel/zbzt/interactWithChannel.js +4 -0
  48. package/src/channel/zbzt/interactWithChannelControl.js +1568 -0
  49. package/src/channel/zbzt/interactWithChannelEntry.js +318 -0
  50. package/src/config/config.js +226 -0
  51. package/src/default/base.js +71 -0
  52. package/src/default/extend.js +36 -0
  53. package/src/default/index.js +10 -0
  54. package/src/live/base.js +43 -0
  55. package/src/live/call-method.js +10 -0
  56. package/src/live/extend.js +53 -0
  57. package/src/live/index.js +10 -0
  58. package/src/network/api.js +56 -0
  59. package/src/network/commonFetch.js +66 -0
  60. package/src/network/dataReport.js +448 -0
  61. package/src/notice.js +418 -0
  62. package/src/tool/base.js +74 -0
  63. package/src/tool/call-method.js +10 -0
  64. package/src/tool/extend.js +42 -0
  65. package/src/tool/index.js +10 -0
  66. package/src/util/bridge.js +87 -0
  67. package/src/util/bridge1.js +46 -0
  68. package/src/util/dict.js +51 -0
  69. package/src/util/sessionStorage.js +29 -0
  70. package/src/util/sha256.js +483 -0
  71. package/src/util/util.js +329 -0
  72. package/src/zbzt-av-sdk/default-sdk.js +192 -0
  73. package/src/zbzt-av-sdk/device.js +86 -0
  74. package/src/zbzt-av-sdk/rtc-sdk.js +2854 -0
  75. package/src/zbzt-av-sdk/talrtc-sdk.js +2620 -0
  76. package/src/zbzt-av-sdk/trtc-sdk.js +1802 -0
  77. package/src/zbzt-av-sdk/zbzt-av-sdk.js +2121 -0
  78. package/src/zbzt-av-sdk/zego-sdk.js +1718 -0
  79. package/src/zbzt-av-sdk/zego-sdk.js.bak +3133 -0
  80. package/src/zbzt-live-sdk.js +1484 -0
@@ -0,0 +1,2620 @@
1
+ import dataReport from '../network/dataReport.js';
2
+ import defaultApi from '../default/index.js';
3
+ import NOTICE from '../notice.js';
4
+ import zbztsdk from '../zbzt-live-sdk.js';
5
+ import { deviceListReport } from './device.js';
6
+ import util from '../util/util.js';
7
+ import getRTCInstance from 'omnirtc-web';
8
+ import * as defaultsdk from './default-sdk.js';
9
+
10
+ // 扩展标识
11
+ const extensionId = 'talrtc_ext';
12
+ // 端提供的 API 入口
13
+ const EM = window.EM;
14
+ // 是否执行过 TALRTC 的 AddListener 的标志
15
+ let hasAddListener = false;
16
+ // 监听id
17
+ let EMListenerId = 0;
18
+ // rtc小班课=0;rtc大班课=1
19
+ const classType = 0;
20
+ // 0: 小组课 1: 小班课 2: 新小班课
21
+ let classMode = 0;
22
+ // 心跳
23
+ let heartBeatDataReportObj = {};
24
+ let isFirstHeartBeatReport = false;
25
+ // 维护的一份拉流的 streamId 与本地预览通道的映射表
26
+ let streamIdToPreviewId = {};
27
+ let previewIdToStreamId = {};
28
+ let heartBeatDataReportTimer = null;
29
+ let streamIdRtcPlayerInfo = {};
30
+ let streamIdRtcPlayerInfo1 = {};
31
+ // 拉流的播放通道初始化从 0 开始依次递增至44(共45路流),-1 为推流的本地视频预览
32
+ const uiChnIndexs = new Array(100).fill(0).map((a, b) => b).reverse();
33
+ // 维护的一份当前正在使用的音频设备的 deviceId 的列表
34
+ let usingAudioDeviceId = {
35
+ speaker: '',
36
+ microphone: ''
37
+ };
38
+ let localStreamId = '';
39
+ let screenStreamId = '';
40
+ let isScreenSharing = false;
41
+ let isSpeakerCapturing = false;
42
+ let sdkVersion = null;
43
+ const streamMuteStatus = {};
44
+ const localStreamMuteStatus = {
45
+ video: false,
46
+ audio: false,
47
+ };
48
+ //记录底层推流回调的值
49
+ let dataTalrtcCapture = {};
50
+ let qualityLocalArr = [];
51
+ let qualityRemoteArr = [];
52
+ let localRoomId = null;
53
+ let userId = null;
54
+ let isNoticeMicVolume = false;
55
+ let enableLocalCapture = true; // 本地摄像头采集,默认允许
56
+ let teacherId = null;
57
+ let qualityLocal = 0;
58
+ let qualityRemote = 0;
59
+
60
+ const BUSI_USER_ROLE = {
61
+ student: 0,
62
+ teacher: 1,
63
+ assistant: 2,
64
+ };
65
+ const ENGINE_TYPE = {
66
+ talrtc: 7,
67
+ nertc: 8,
68
+ volcrtc: 9
69
+ };
70
+ // /**
71
+ // * 过滤直播云sdk中deviceId前缀
72
+ // * @param {string} deviceId
73
+ // * @returns {string}
74
+ // */
75
+ // const formatDeviceId = (deviceId) => {
76
+ // return deviceId.replace(/^@device:\w+:/, '');
77
+ // };
78
+ const getStreamMuteStatus = (streamId, type) => {
79
+ const streamStatus = streamMuteStatus[streamId] || {};
80
+ return streamStatus[type] || false;
81
+ };
82
+ const setStreamMuteStatus = (streamId, type, status) => {
83
+ const streamStatus = streamMuteStatus[streamId];
84
+ if (streamStatus) {
85
+ streamStatus[type] = status;
86
+ return;
87
+ }
88
+ switch (type) {
89
+ case 'video':
90
+ streamMuteStatus[streamId] = {
91
+ video: status,
92
+ audio: false,
93
+ };
94
+ break;
95
+ case 'audio':
96
+ streamMuteStatus[streamId] = {
97
+ video: false,
98
+ audio: status,
99
+ };
100
+ break;
101
+ default:break;
102
+ }
103
+ };
104
+ /**
105
+ * 判断主流还是辅流
106
+ * @param {string} streamId
107
+ * @returns {boolean} true: 主流 false: 辅流
108
+ */
109
+ const isMainStream = (streamId) => {
110
+ return streamId.split('_').length === 4;
111
+ };
112
+
113
+ const callMethod = (name, args) => {
114
+ // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测
115
+ if (EM) {
116
+ return new Promise((resolve, reject) => {
117
+ // let noneCamera = (name === 'SetCameraDevice' && !args.pszDeviceID);
118
+ // let noneMicrophone = (name === 'SetAudioDevice' && args.deviceType === 0 && !args.pszDeviceID);
119
+ // let noneSpeaker = (name === 'SetAudioDevice' && args.deviceType === 1 && !args.pszDeviceID);
120
+ // if (noneCamera || noneMicrophone || noneSpeaker) {
121
+ // return resolve();
122
+ // }
123
+ EM.CallMethod(
124
+ extensionId,
125
+ name,
126
+ JSON.stringify({ ...args, classType }),
127
+ (code, msg) => {
128
+ defaultApi.writeLog(`${name} Code: ${code} Message: ${msg} Params: ${JSON.stringify({ ...args, classType })}`);
129
+ resolve({
130
+ code,
131
+ msg
132
+ });
133
+ }
134
+ );
135
+ });
136
+ }
137
+ };
138
+
139
+ const loadTalrtc = (extensionVersion) => {
140
+ // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测
141
+ if (EM) {
142
+ return new Promise((resolve, reject) => {
143
+ removerListener();
144
+ defaultApi.writeLog(`-> load tal rtc sdk ${extensionId}, ${extensionVersion}`);
145
+ EM.Load(
146
+ extensionId,
147
+ extensionVersion,
148
+ false,
149
+ (code, msg) => {
150
+ defaultApi.writeLog(`loadTalrtc Code: ${code}\nMessage: ${msg}`);
151
+ addListener();
152
+ resolve();
153
+ }
154
+ );
155
+ });
156
+ }
157
+ };
158
+
159
+ //卸载监听
160
+ const removerListener = () => {
161
+ hasAddListener = false;
162
+ defaultApi.writeLog(`TALRTC::action--removerListener EMListenerId:${EMListenerId}`);
163
+ EM.RemoverListener(extensionId, EMListenerId, (ec, content) => {
164
+ });
165
+ EMListenerId = 0;
166
+ };
167
+
168
+ //加载监听
169
+
170
+ /**
171
+ * @function 添加扩展监听机制
172
+ * @param userId:Number 用户 id,必选
173
+ * @param userName:String 用户名,必选
174
+ * @param roomId:String 频道(房间) id,必选
175
+ * @param nNetType:Number 网络类型,可选,默认为 1
176
+ * @return void
177
+ */
178
+ // const addListener = () => {
179
+ // // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测
180
+ // if (EM && !hasAddListener) {
181
+ // hasAddListener = true;
182
+ // EM.AddListener(extensionId, (event, data) => {
183
+ // if (zbztsdk.openListenerLog) {
184
+ // console.log(`avsdk TALRTC::Listener:: start event: ${event}, data: ${JSON.stringify(data)}`);
185
+ // }
186
+ // if (data && data.indexOf(extensionId) > -1) {
187
+ // try {
188
+ // EMListenerId = JSON.parse(data)[extensionId];
189
+ // defaultApi.writeLog(`TALRTC::addListener-- EMListenerId: ${EMListenerId}`);
190
+ // } catch (error) {
191
+ // }
192
+ // }
193
+ // if (!event || !data) {
194
+ // return;
195
+ // }
196
+ // let _data = JSON.parse(data);
197
+ // // defaultApi.writeLog(`TALRTC: event:: ${event} : ${data}`);
198
+ // switch (event) {
199
+ // // 推流器出现错误
200
+ // case 'onLocalError':
201
+ // defaultApi.writeLog(`TALRTC::addListener-- onLocalError: ${data}`);
202
+ // NOTICE.pushStreamError({
203
+ // errorStreamType:_data.streamType,
204
+ // code: _data.code,
205
+ // errorMsg: _data
206
+ // });
207
+ // dataReport.pushStreamError({
208
+ // errorStreamType:_data.streamType,
209
+ // code: _data.code
210
+ // });
211
+ // // defaultApi.writeLog(`TALRTC: event:: onLocalError: ${_data}`);
212
+ // break;
213
+ // // 直播推流器警告通知
214
+ // case 'onLocalWarning':
215
+ // defaultApi.writeLog(`TALRTC::addListener-- onLocalWarning: ${data}`);
216
+ // NOTICE.pushStreamWarning({
217
+ // warnStreamType:_data.streamType,
218
+ // code: _data.code
219
+ // });
220
+ // dataReport.pushStreamWarning({
221
+ // warnStreamType:_data.streamType,
222
+ // code: _data.code
223
+ // });
224
+ // break;
225
+ // // 首帧音频推送完成的回调通知
226
+ // case 'onSendLocalFirstAudioFrame':
227
+ // defaultApi.writeLog(`TALRTC: event:: onSendLocalFirstAudioFrame: ${data}`);
228
+ // break;
229
+ // // 采集首帧事件
230
+ // case 'OnCaptureVideoFirstFrame':
231
+ // defaultApi.writeLog(`TALRTC: event:: OnCaptureVideoFirstFrame: ${data}`);
232
+ // NOTICE.pushFlowSuccess({code:0,publish_streamid: _data.pszStreamID});
233
+ // dataReport.publishResult({
234
+ // code: '0',
235
+ // });
236
+ // break;
237
+ // // 本地音量
238
+ // case 'onLocalMicrophoneVolumeUpdate':
239
+ // // defaultApi.writeLog(`TALRTC: event:: onLocalMicrophoneVolumeUpdate: ${data}`);
240
+ // if (isNoticeMicVolume) {
241
+ // NOTICE.captureMicVolumeChanged({
242
+ // volume: Math.round(_data.volume)
243
+ // });
244
+ // }
245
+ // heartBeatDataReportObj.volume = heartBeatDataReportObj.volume + Math.round(_data.volume) + ',';
246
+ // break;
247
+ // // 推流器连接状态回调通知。推流器连接状态 1与服务器断开连接/2 正在连接服务器/3 连接服务器成功/4 重连服务器中 5
248
+ // case 'onLocalConnectStatusUpdate':
249
+ // defaultApi.writeLog(`TALRTC: event:: onLocalConnectStatusUpdate: ${data}`);
250
+ // dataReport.localConnectStatus({
251
+ // connectStatuStreamType:_data.streamType,
252
+ // state: _data.state
253
+ // });
254
+ // if (_data.state === 2 || _data.state === 1) {
255
+ // NOTICE.networkError();
256
+ // } else if (_data.state === 3) {
257
+ // NOTICE.networkRecovery();
258
+ // }
259
+ // break;
260
+ // // 网络质量的实时统计回调
261
+ // case 'onLocalNetworkQuality':
262
+ // // defaultApi.writeLog(`TALRTC: event:: onLocalNetworkQuality: ${data}`);
263
+ // if(_data.quality == 4 || _data.quality == 5 || _data.quality == 6) {
264
+ // NOTICE.localNetworkQuality({code: _data.quality});
265
+ // // dataReport.localNetworkQuality({
266
+ // // code: _data.quality,
267
+ // // });
268
+ // }
269
+ // qualityLocal = _data.quality;
270
+ // // qualityLocalArr.push(_data.quality);
271
+ // break;
272
+
273
+ // // 远端流错误通知,拉流出现错误时,会回调该通知
274
+ // case 'onRemoteError':
275
+ // defaultApi.writeLog(`TALRTC: event:: onRemoteError: ${data}`);
276
+ // NOTICE.pullStreamError({
277
+ // strErrorStreamId: _data.streamId,
278
+ // code:_data.code
279
+ // });
280
+ // break;
281
+ // // 远端流警告通知,拉流出现警告时,会回调该通知
282
+ // case 'onRemoteWarning':
283
+ // defaultApi.writeLog(`TALRTC: event:: onRemoteWarning: ${data}`);
284
+ // NOTICE.pullStreamWarning({
285
+ // strWarnStreamId: _data.streamId,
286
+ // code:_data.code
287
+ // });
288
+ // break;
289
+ // // 卡顿事件,用于事件上报
290
+ // case 'stuckevent':
291
+ // defaultApi.writeLog(`TALRTC: event:: stuckevent: ${data}`);
292
+ // break;
293
+ // // 远端音频首帧
294
+ // case 'onRecvRemoteAudioFirstFrame':
295
+ // try{
296
+ // NOTICE.firstAudioSize({
297
+ // streamId: _data.streamId,
298
+ // userId: util.getUidByStreamId(_data.streamId)
299
+ // });
300
+ // dataReport.firstAudioSize({
301
+ // pull_streamid: _data.streamId,
302
+ // pull_uid: util.getUidByStreamIdDr(_data.streamId),
303
+ // code:'0'
304
+ // });
305
+ // } catch (e) { };
306
+ // defaultApi.writeLog(`TALRTC: event:: OnRecvRemoteAudioFirstFrame: ${data}`);
307
+ // break;
308
+ // // 远端流音量大小
309
+ // case 'onRemoteAudioVolume':
310
+ // // defaultApi.writeLog(`TALRTC: event:: onRemoteAudioVolume: ${data}}`);
311
+ // let cbData = {
312
+ // streamid: _data.streamId,
313
+ // streamId: _data.streamId,
314
+ // userId: util.getUidByStreamId(_data.streamId),
315
+ // volume: _data.volume
316
+ // };
317
+ // NOTICE.playerVolumeChanged(cbData);
318
+ // NOTICE.volumeChange(cbData);
319
+ // if(streamIdRtcPlayerInfo[_data.streamId]) {
320
+ // streamIdRtcPlayerInfo[_data.streamId].volume = streamIdRtcPlayerInfo[_data.streamId].volume + Math.round(_data.volume)+ ',';
321
+ // }
322
+ // break;
323
+ // case 'onUserEnableAudio':
324
+ // try {
325
+ // if (
326
+ // teacherId &&
327
+ // _data.streamId.match(teacherId) &&
328
+ // isMainStream(_data.streamId) &&
329
+ // _data.inuse
330
+ // ) {
331
+ // setChiefAudioStream(_data.streamId, util.getUidByStreamIdDr(_data.streamId));
332
+ // }
333
+ // } catch (e) {
334
+ // defaultApi.writeLog(`TALRTC: event:: onUserEnableAudio: ${e}`);
335
+ // }
336
+ // defaultApi.writeLog(`TALRTC: event:: onUserEnableAudio: ${data}`);
337
+ // break;
338
+ // // 远端视频首帧
339
+ // case 'onRenderRemoteVideoFirstFrame':
340
+ // try{
341
+ // // Test Code: 临时增加
342
+ // setTimeout(() => {
343
+ // NOTICE.pullFlowResult({code:0,pull_streamid: _data.streamId});
344
+ // NOTICE.firstVideoSize({
345
+ // streamId: _data.streamId,
346
+ // userId: util.getUidByStreamId(_data.streamId)
347
+ // });
348
+ // dataReport.firstVideoSize({
349
+ // pull_streamid: _data.streamId,
350
+ // pull_uid: util.getUidByStreamIdDr(_data.streamId),
351
+ // code:'0'
352
+ // });
353
+ // }, 100);
354
+ // } catch (e) { };
355
+ // defaultApi.writeLog(`TALRTC: event:: OnRenderRemoteVideoFirstFrame: ${data}`);
356
+ // break;
357
+ // // SEI消息
358
+ // case 'onRecvSEIMsg':
359
+ // defaultApi.writeLog(`TALRTC: event:: onRecvSEIMsg: ${data}`);
360
+ // break;
361
+ // // 网络质量的实时统计回调
362
+ // case 'onRemoteNetworkQuality':
363
+ // // defaultApi.writeLog(`TALRTC: event:: onRemoteNetworkQuality: ${data}`);
364
+ // if(_data.quality == 4 || _data.quality == 5 || _data.quality == 6) {
365
+ // NOTICE.remoteNetworkQuality({code: _data.quality});
366
+ // // dataReport.remoteNetworkQuality({
367
+ // // code: _data.quality,
368
+ // // });
369
+ // }
370
+ // qualityRemote = _data.quality;
371
+ // // qualityRemoteArr.push(_data.quality);
372
+ // break;
373
+
374
+ // // 转推 CDN 上发布音视频流的事件回调
375
+ // case 'onRtmpStreamingStateChanged':
376
+ // defaultApi.writeLog(`TALRTC: event:: onRtmpStreamingStateChanged: ${data}`);
377
+ // break;
378
+ // // 设备异常
379
+ // case 'onDeviceError':
380
+ // defaultApi.writeLog(`TALRTC: event:: OnDeviceError: ${data}`);
381
+ // break;
382
+ // // 拉流的结果通知
383
+ // case 'onPlayStateUpdate':
384
+ // defaultApi.writeLog(`TALRTC: event:: onPlayStateUpdate: ${data}`);
385
+ // break;
386
+ // // 推流的结果通知
387
+ // case 'onPushStateUpdate':
388
+ // defaultApi.writeLog(`TALRTC: event:: onPushStateUpdate: ${data}`);
389
+ // if (_data.state === 3) {
390
+ // NOTICE.pushFlowSuccess({code:0,publish_streamid: _data.streamId});
391
+ // }
392
+ // break;
393
+ // // 推、拉流的统计数据。
394
+ // case 'onLocalStatistics':
395
+ // try {
396
+ // NOTICE.playLossAndDelay({
397
+ // userId,
398
+ // delay:_data.rtt,
399
+ // lostrate:_data.packetLoss
400
+ // });
401
+ // }catch(e){}
402
+ // heartBeatDataReportCalc('onLocalStatistics', _data);
403
+ // // defaultApi.writeLog(`TALRTC: event:: onStatisticsUpdate: ${_data}`);
404
+ // break;
405
+ // // 本地摄像头设备的通断状态发生变化
406
+ // case 'onRemoteStatistics':
407
+ // try {
408
+ // const _d = JSON.parse(_data.stats);
409
+ // NOTICE.pullQuality({
410
+ // video: {
411
+ // streamId: _d.streamId,
412
+ // userId: util.getUidByStreamId(_d.streamId),
413
+ // bitrate: _d.videoBitrate,
414
+ // fps: _d.fps,
415
+ // }
416
+ // });
417
+ // NOTICE.playLossAndDelay({
418
+ // userId: util.getUidByStreamId(_d.streamId),
419
+ // delay:_d.rtt,
420
+ // lostrate:_d.packetLoss
421
+ // });
422
+ // }catch(e){}
423
+ // heartBeatDataReportCalc('onRemoteStatistics', _data);
424
+ // // defaultApi.writeLog(`TALRTC: event:: onStatisticsUpdate: ${_data}`);
425
+ // break;
426
+ // // 本地摄像头设备的通断状态发生变化
427
+ // case 'onVideoDeviceChanged':
428
+ // defaultApi.writeLog(`TALRTC: event:: onVideoDeviceChanged: ${data}`);
429
+ // setCameraDevice({deviceId: _data.state == 1 ? _data.deviceId : '', operationType: 'hotPlug', deviceState: _data.state == 1 ? 0 : 1, changedDeviceId: _data.deviceId});
430
+ // break;
431
+ // /* 本地麦克风设备的通断状态发生变化
432
+ // * state:1:使用中 2:被禁用 4:一开始就没有?(我也不懂) 8:设备移除
433
+ // * deviceType:-1:未知 0:播放器 1:麦克风 2:视频显示设备 3:摄像头
434
+ // */
435
+ // case 'onAudioDeviceChanged':
436
+ // defaultApi.writeLog(`TALRTC: event:: onAudioDeviceChanged: ${data}`);
437
+ // if (_data.deviceType === 0) {
438
+ // setSpeakerDevice({deviceId: _data.state == 1 ? _data.deviceId : '', operationType: 'hotPlug', deviceState: _data.state == 1 ? 0 : 1, changedDeviceId: _data.deviceId});
439
+ // }
440
+ // if (_data.deviceType === 1) {
441
+ // setMicrophoneDevice({deviceId: _data.state == 1 ? _data.deviceId : '', operationType: 'hotPlug', deviceState: _data.state == 1 ? 0 : 1, changedDeviceId: _data.deviceId});
442
+ // }
443
+ // break;
444
+
445
+ // // mute 视频状态,true:远端开始推流,并拉流收到首帧;false:远端停止推流。
446
+ // case 'onRemoteVideoStatus':
447
+ // defaultApi.writeLog(`TALRTC: event:: onRemoteVideoStatus: ${data}`);
448
+ // break;
449
+
450
+ // // mute 音频状态,true:远端开始推流,并拉流收到首帧;false:远端停止推流。
451
+ // case 'onRemoteAudioStatus':
452
+ // defaultApi.writeLog(`TALRTC: event:: onRemoteAudioStatus: ${data}`);
453
+ // break;
454
+ // // 首帧视频推送完成的回调通知
455
+ // case 'onSendLocalFirstVideoFrame':
456
+ // defaultApi.writeLog(`TALRTC: event:: onSendLocalFirstVideoFrame: ${data}`);
457
+ // break;
458
+ // case 'updateRet':
459
+ // defaultApi.writeLog(`TALRTC: event:: updateRet: ${data}`);
460
+ // break;
461
+ // default:
462
+ // console.warn('warning: uncaught listener:', event);
463
+ // }
464
+ // });
465
+ // }
466
+ // };
467
+
468
+ class Clients extends Map {
469
+ constructor() {
470
+ super(arguments);
471
+ }
472
+ /**
473
+ * @param {string} roomId
474
+ * @param {import('omnirtc-web').IOmniRTCClient} client
475
+ */
476
+ set(roomId, client) {
477
+ return super.set(roomId, client);
478
+ }
479
+ /**
480
+ *
481
+ * @param {string} roomId
482
+ * @returns {import('omnirtc-web').IOmniRTCClient | null}
483
+ */
484
+ get(roomId) {
485
+ return super.get(roomId);
486
+ }
487
+ /**
488
+ *
489
+ * @param {string} roomId
490
+ * @returns
491
+ */
492
+ delete(roomId) {
493
+ const client = super.get(roomId);
494
+ if (client) {
495
+ client.leave();
496
+ }
497
+ return super.delete(roomId);
498
+ }
499
+ clear() {
500
+ super.forEach((client) => {
501
+ client.leave();
502
+ });
503
+ return super.clear();
504
+ }
505
+ }
506
+ /**
507
+ * @type {import('omnirtc-web').IOmniRTC | null}
508
+ */
509
+ let talrtc = null;
510
+
511
+ /**
512
+ * @type {import('omnirtc-web').IMicrophoneAudioTrack | null}
513
+ */
514
+ let audioTrack = null;
515
+
516
+ /**
517
+ * @type {import('omnirtc-web').ICameraVideoTrack | null}
518
+ */
519
+ let videoTrack = null;
520
+
521
+ /**
522
+ * @type {import('omnirtc-web').ILocalVideoTrack | null}
523
+ */
524
+ let screenTrack = null;
525
+
526
+ /**
527
+ * @type {Map<string, import('omnirtc-web').IOmniRTCClient>}
528
+ */
529
+ const clients = new Clients();
530
+ /**
531
+ * @type {Map<string, import('omnirtc-web').IRemoteVideoTrack | import('omnirtc-web').IRemoteAudioTrack | true>}
532
+ */
533
+ const remoteTracks = new Map();
534
+
535
+ /**
536
+ *
537
+ * @param {import('omnirtc-web').IOmniRTCClient} client
538
+ */
539
+ const addListener = (client) => {
540
+ client.on('user-join', (uid) => {});
541
+ client.on('user-left', (uid) => {});
542
+ client.on('user-published', (user, mediaType) => {});
543
+ client.on('user-unpublished', (user, mediaType) => {});
544
+ client.on('user-info-updated', (uid, info) => {});
545
+ client.on('volume-indicator', (result) => {});
546
+ };
547
+
548
+ // 初始化相关
549
+ const init = async (args) => {
550
+ defaultApi.writeLog(`avsdk TALRTC::init ${JSON.stringify(args)}`);
551
+ const usedDevices = window.zbztAVSDK_device_checker_init;
552
+ const { devices } = args;
553
+ const sdkType = window.zbztAVSDK_init_sdk_type || 'talrtc';
554
+ localStreamId = args.streamId;
555
+ screenStreamId = `${args.institutionId}_${args.roomId}_${args.userId}_${args.live_id}_1`;
556
+ teacherId = args.teacherId;
557
+ const _devices = {
558
+ camera: (devices && devices.camera) || (usedDevices && usedDevices.camera && usedDevices.camera.use) || '',
559
+ microphone: (devices && devices.microphone) || (usedDevices && usedDevices.microphone && usedDevices.microphone.use) || '',
560
+ speaker: (devices && devices.speaker) || (usedDevices && usedDevices.speaker && usedDevices.speaker.use) || ''
561
+ };
562
+
563
+ talrtc = getRTCInstance(args.token);
564
+ const client = talrtc.createClient({codec: 'h264', mode: 'rtc'});
565
+ await client.join();
566
+ clients.set(String(args.roomId), client);
567
+ // await startEngine(args.appId, localRoomId, args.userId, args.usersign || '67890', ENGINE_TYPE[sdkType] || 7, args.live_id, BUSI_USER_ROLE[args.role] || 0);
568
+
569
+ // classMode = args.classMode >> 0;
570
+ // // 0: 小组课 1: 小班课 2: 新小班课
571
+ // if (classMode === 1 || classMode === 2){
572
+ // if(args.role === 'teacher') {
573
+ // //小班课 需要加载采集插件的输入数据,为了拼接talrtc头像
574
+ // await loadCollectionInputEntry();
575
+
576
+ // //屏幕流通道
577
+ // screenStreamId = `${window.zbzt_sdk_init_params.institutionId}_${localRoomId}_${userId}_${args.live_id}_1`;
578
+ // await enableExternalVideoSource(true, screenStreamId);
579
+ // await setCameraEncodeFps(args.screenSameFps, screenStreamId);
580
+ // await setCameraCaptureResolution(args.screenSameResolutionWidth, args.screenSameResolutionHeight, screenStreamId);
581
+ // await setCameraEncodeResolution(args.screenSameResolutionWidth, args.screenSameResolutionHeight, screenStreamId);
582
+ // await setCameraEncodeBitrate(args.screenSameBitrate, screenStreamId);
583
+
584
+ // //rtc同屏以及高光时刻,都开启音频外部采集,默认传1
585
+ // await setAudioAuxSource(1);
586
+ // teacherId = undefined;
587
+ // }
588
+
589
+ // if(args.noiseSuppressMode == -2) {
590
+ // defaultApi.writeLog(`noiseSuppressMode 关闭噪声消除 ${args.noiseSuppressMode}`);
591
+ // await setEnableNoiseSuppress(false);
592
+ // } else if(args.noiseSuppressMode == -1) {
593
+ // defaultApi.writeLog(`noiseSuppressMode 由底层进行配置,js层不进行配置 ${args.noiseSuppressMode}`);
594
+ // } else {
595
+ // defaultApi.writeLog(`noiseSuppressMode 启动噪音消除,模式为:${args.noiseSuppressMode}`);
596
+ // await setEnableNoiseSuppress(true);
597
+ // await setNoiseSuppressMode(args.noiseSuppressMode >> 0);
598
+ // await enableTransientNoiseSuppress(true);
599
+ // };
600
+ // //aecMode为-1是关闭回音消除,云控下传
601
+ // if(args.aecMode == -2) {
602
+ // defaultApi.writeLog(`aecMode 关闭回音消除 ${args.aecMode}`);
603
+ // await setEnableAEC(false);
604
+ // } else if(args.aecMode == -1) {
605
+ // defaultApi.writeLog(`aecMode 由底层进行配置,js层不进行配置 ${args.aecMode}`);
606
+ // } else {
607
+ // defaultApi.writeLog(`aecMode 启动回音消除,模式为:${args.aecMode}`);
608
+ // await setEnableAEC(true);
609
+ // await setAECMode(args.aecMode >> 0);
610
+ // };
611
+ // };
612
+
613
+ // if((args.role === 'teacher' || args.role === 'assistant') && classMode === 0){
614
+ // //坐立模式开启外部采集器,站立关闭外部采集器,只有小组课坐立模式才会调用,通过这个把rtmp数据给到talrtc(头像),开启了外部采集,talrtc不会再本地采集数据
615
+ // // V2 不区分坐立站立,老师和辅导老师都启动外部视频源
616
+ // await enableExternalVideoSource(true, localStreamId);
617
+ // enableLocalCapture = false; // 禁用本地摄像头采集,防止与其他进程抢占摄像头
618
+ // } else {
619
+ // await setDefaultDevice(_devices, 'default');
620
+ // }
621
+ // 主通道
622
+ // await setCameraEncodeFps(args.encodeCaptureFps, localStreamId);
623
+ // await setCameraCaptureResolution(args.previewResolutionWidth, args.previewResolutionHeight, localStreamId);
624
+ // await setCameraEncodeResolution(args.encodedResolutionWidth, args.encodedResolutionHeight, localStreamId);
625
+ // await setCameraEncodeBitrate(args.encodeCaptureBitrate, localStreamId);
626
+
627
+ setMicphoneVolumInterval(1000);
628
+ // await setMediaSideFlags();
629
+ window.current_sdk_type = sdkType;
630
+ defaultApi.writeLog('avsdk TALRTC::init finished current_sdk_type: ' + sdkType);
631
+ };
632
+
633
+
634
+ /**
635
+ * @function 初始化引擎
636
+ * @param {string} appid TalRTC 秘钥,必选
637
+ * @param {string} userid
638
+ * @param {string} usersign
639
+ * @param {1 | 7} type 直播中台SDK底层引擎类型 7: 自研引擎
640
+ * @param {string} liveID
641
+ * @param {0 | 1 | 2} businessRole 0: student 1: teacher 2: tutor
642
+ * @return Promise | void
643
+ */
644
+ const startEngine = (appid, roomId, userid, usersign, type, liveID, businessRole) => {
645
+ defaultApi.writeLog(`avsdk TALRTC::StartEngine appid: ${appid} roomId:${roomId} userid: ${userid} usersign: ${usersign}, liveID: ${liveID}, businessRole: ${businessRole}`);
646
+ return callMethod('StartEngine', {
647
+ appid,
648
+ roomId,
649
+ userid,
650
+ usersign,
651
+ type,
652
+ liveID: '' + liveID,
653
+ businessRole,
654
+ institutionId: '' + window.zbzt_sdk_init_params.institutionId,
655
+ });
656
+ };
657
+
658
+ //开启消除回声
659
+ export const setEnableAEC = (enable) => {
660
+ return callMethod('EnableAEC', {enable});
661
+ };
662
+
663
+ //设置回声消除模式 mode :激进模式 =0/中等模式 =1/轻度模式 =2
664
+ export const setAECMode = (mode) => {
665
+ return callMethod('SetAECMode', {mode});
666
+ };
667
+
668
+ //开启噪音消除
669
+ export const setEnableNoiseSuppress = (enable) => {
670
+ return callMethod('EnableNoiseSuppress', {enable});
671
+ };
672
+
673
+ //设置噪音消除模式 mode :0:低 1:中 2高
674
+ export const setNoiseSuppressMode = (mode) => {
675
+ return callMethod('SetNoiseSuppressMode', {mode});
676
+ };
677
+
678
+ //新增瞬时降噪接口 瞬时降噪 可以处理掉 敲键盘、敲桌子、敲门等瞬态噪声。非瞬态噪声,此接口无法处理,比如划桌子等摩擦噪音。
679
+ export const enableTransientNoiseSuppress = (enable) => {
680
+ return callMethod('EnableTransientNoiseSuppress',{enable});
681
+ };
682
+
683
+ /**
684
+ * 加载采集插件的输入数据 //调用后,talrtc 可以向采集插件传送摄像头数据,用于拼接
685
+ * @return {Promise}
686
+ */
687
+ export const loadCollectionInputEntry = () => {
688
+ return callMethod('LoadCollectionInputEntry', {});
689
+ };
690
+
691
+ /**
692
+ * 1、设置需要拼接的学生头像流id,按数组顺序拼接
693
+ * 2、加载截屏插件,获取截屏插件设置拉流头像回调函数
694
+ * @param {Array} stream_ids 拉流id数组,最大有效数量7个
695
+ * @returns {Promise}
696
+ */
697
+ export const loadCollectionInputEntry2 = (stream_ids) => {
698
+ return callMethod('LoadCollectionInputEntry2', {stream_ids});
699
+ };
700
+ //设置是否发送sei
701
+ const setMediaSideFlags = (start = true, onlyAudioPublish = false, mediaInfoType = 2, seiSendType = 1, idx = 0) => {
702
+ return callMethod('SetMediaSideFlags',{start,onlyAudioPublish, mediaInfoType, seiSendType, idx});
703
+ };
704
+
705
+ /**
706
+ * @function 销毁引擎
707
+ * @return Promise | void
708
+ */
709
+ const destroyEngine = () => {
710
+ defaultApi.writeLog('avsdk TALRTC::destroyEngine');
711
+ audioTrack && audioTrack.close();
712
+ videoTrack && videoTrack.close();
713
+ screenTrack && screenTrack.close();
714
+ clients.forEach((client) => {
715
+ client.leave();
716
+ });
717
+ clients.clear();
718
+ audioTrack = null;
719
+ videoTrack = null;
720
+ screenTrack = null;
721
+ remoteTracks.clear();
722
+ };
723
+
724
+ // 设置采集分辨率
725
+ const setCameraCaptureResolution = (width, height, streamId = localStreamId) => {
726
+ return callMethod('SetCameraCaptureResolution', { width, height, streamId });
727
+ };
728
+
729
+ // 设置编码分辨率
730
+ const setCameraEncodeResolution = (width, height, streamId = localStreamId) => {
731
+ return callMethod('SetCameraEncodeResolution', { width, height, streamId });
732
+ };
733
+
734
+ // 设置编码帧率
735
+ const setCameraEncodeFps = (fps, streamId = localStreamId) => {
736
+ return callMethod('SetCameraEncodeFps', { fps, streamId });
737
+ };
738
+
739
+ // 设置编码码率
740
+ const setCameraEncodeBitrate = (bitrate, streamId = localStreamId) => {
741
+ return callMethod('SetCameraEncodeBitrate', { bitrate, streamId });
742
+ };
743
+
744
+ // 获取指定摄像头的支持的分辨率
745
+ const getCameraResolution = async (deviceId) => {
746
+ const resp = await callMethod('GetCameraResolution', { deviceId });
747
+ const cameraArr = JSON.parse(resp.msg || '{}').SupportedResolution;
748
+ return {
749
+ code: resp.code,
750
+ msg: JSON.stringify(cameraArr)
751
+ };
752
+ };
753
+
754
+ // 获取 rtc_sdk.dll 版本号
755
+ const getSDKVersion = async () => {
756
+ if (sdkVersion) {
757
+ return sdkVersion;
758
+ }
759
+ return callMethod('GetSDKVersion', {}).then((e) => {
760
+ sdkVersion = e;
761
+ });
762
+ };
763
+
764
+ /**
765
+ * @function 设置默认的硬件设备,包括摄像头、麦克风以及扬声器
766
+ * @return Promise
767
+ */
768
+ export const setDefaultDevice = async (devices, operationType) => {
769
+ // 设置默认的摄像头
770
+ if (devices && devices.camera) {
771
+ if (zbztAVSDK_device_checker_init.camera.list.length == 0) {
772
+ await getCameraDeviceList();
773
+ }
774
+ await setCameraDevice({ deviceId: devices.camera, operationType: `${operationType}_1` });
775
+ } else {
776
+ const cameraData = await getCameraDeviceList();
777
+ if (cameraData.length) {
778
+ let hasSetCamera = false;
779
+ for (let item of cameraData) {
780
+ if (item.isDefault) {
781
+ await setCameraDevice({ deviceId: item.deviceId, operationType: `${operationType}_2` });
782
+ hasSetCamera = true;
783
+ break;
784
+ }
785
+ }
786
+ if (!hasSetCamera) {
787
+ await setCameraDevice({ deviceId: cameraData[0].deviceId, operationType: `${operationType}_3` });
788
+ }
789
+ }
790
+ }
791
+ // 设置默认的麦克风
792
+ if (devices && devices.microphone) {
793
+ if (zbztAVSDK_device_checker_init.microphone.list.length == 0) {
794
+ await getMicrophoneDeviceList();
795
+ }
796
+ await setMicrophoneDevice({ deviceId: devices.microphone, operationType: `${operationType}_1` });
797
+ } else {
798
+ const microPhoneData = await getMicrophoneDeviceList();
799
+ try {
800
+ if (microPhoneData.length) {
801
+ let hasSetMicrophone = false;
802
+ for (let item of microPhoneData) {
803
+ if (item.isDefault) {
804
+ await setMicrophoneDevice({ deviceId: item.deviceId, operationType: `${operationType}_2` });
805
+ hasSetMicrophone = true;
806
+ break;
807
+ }
808
+ }
809
+ if (!hasSetMicrophone) {
810
+ await setMicrophoneDevice({ deviceId: microPhoneData[0].deviceId, operationType: `${operationType}_3` });
811
+ }
812
+ }
813
+ } catch (e) {
814
+ console.log(e);
815
+ }
816
+
817
+ }
818
+ // 设置默认的扬声器
819
+ if (devices && devices.speaker) {
820
+ await setSpeakerDevice({ deviceId: devices.speaker, operationType: `${operationType}_1` });
821
+ } else {
822
+ const speakerData = await getSpeakerDeviceListInternal();
823
+ if (speakerData.length) {
824
+ let hasSetSpeaker = false;
825
+ for (let item of speakerData) {
826
+ if (item.isDefault) {
827
+ await setSpeakerDevice({ deviceId: item.deviceId, operationType: `${operationType}_2` });
828
+ hasSetSpeaker = true;
829
+ break;
830
+ }
831
+ }
832
+ if (!hasSetSpeaker) {
833
+ await setSpeakerDevice({ deviceId: speakerData[0].deviceId, operationType: `${operationType}_3` });
834
+ }
835
+ }
836
+ }
837
+ };
838
+
839
+ // 麦克风相关
840
+ /**
841
+ * @function 开启麦克风
842
+ * @param intervalMs: Number
843
+ * @return Promise | void
844
+ */
845
+ const startMicrophone = async (intervalMs = 500) => {
846
+ defaultApi.writeLog('avsdk TALRTC::startMicrophone');
847
+ isNoticeMicVolume = true;
848
+ audioTrack = await talrtc.createMicrophoneAudioTrack({
849
+ microphoneId: window.zbztAVSDK_device_checker_init.microphone.use,
850
+ });
851
+
852
+ audioTrack.on('track-ended', () => {
853
+ defaultApi.writeLog('avsdk TALRTC::startMicrophone track-ended');
854
+ audioTrack.removeAllListeners();
855
+ audioTrack = null;
856
+ });
857
+ // return callMethod('StartMicrophone', { intervalMs });
858
+ };
859
+
860
+ /**
861
+ * @function 关闭麦克风
862
+ * @return Promise | void
863
+ */
864
+ const stopMicrophone = async () => {
865
+ defaultApi.writeLog('avsdk TALRTC::stopMicrophone');
866
+ isNoticeMicVolume = false;
867
+ if (audioTrack) {
868
+ audioTrack.close();
869
+ }
870
+ // return callMethod('StopMicrophone', {});
871
+ };
872
+
873
+ const openOrCloseMicrophone = async (operation) => {
874
+ if (operation) {
875
+ await startMicrophone();
876
+ } else {
877
+ await stopMicrophone();
878
+ }
879
+ };
880
+
881
+ let micVolTimer;
882
+ /**
883
+ * @function 设置麦克风音量大小回调周期
884
+ * @param intervalMs: Number
885
+ * @return Promise | void
886
+ */
887
+ const setMicphoneVolumInterval = (intervalMs = 1000) => {
888
+ if (typeof intervalMs !== 'number' || intervalMs < 0) {
889
+ defaultApi.writeLog('avsdk TALRTC::setMicphoneVolumInterval intervalMs is not a number or less than 0', null, 'error');
890
+ throw new Error('[setMicphoneVolumInterval] intervalMs is not a number or less than 0');
891
+ }
892
+ micVolTimer = setInterval(async () => {
893
+ if (audioTrack) {
894
+ const volume = audioTrack.getVolumeLevel();
895
+ NOTICE.captureMicVolumeChanged({
896
+ volume: Math.round(volume)
897
+ });
898
+ }
899
+ }, intervalMs);
900
+ };
901
+
902
+ /**
903
+ * @function 获取麦克风设备列表
904
+ * @return Promise | void
905
+ */
906
+ const getMicrophoneDeviceListInternal = () => {
907
+ return callMethod('GetMicrophoneDeviceList', {});
908
+ };
909
+
910
+ /**
911
+ * @function 获取麦克风列表
912
+ * @return Promise | void
913
+ */
914
+ const getMicrophoneDeviceList = async () => {
915
+ defaultApi.writeLog('avsdk TALRTC::getMicrophoneDeviceList');
916
+ return defaultsdk.getMicrophoneDeviceList();
917
+
918
+ // const defaultMicrophoneId = JSON.parse((await getDefaultMicrophone()).msg).deviceId;
919
+ // const resp = await getMicrophoneDeviceListInternal();
920
+ // let microphoneListArr = JSON.parse(JSON.parse(resp.msg).DeviceList) || [];
921
+ // let microphoneList = [];
922
+ // for (let i = 0, len = microphoneListArr.length; i < len; i++) {
923
+ // microphoneList.push({
924
+ // deviceId: microphoneListArr[i].id,
925
+ // deviceName: microphoneListArr[i].name,
926
+ // isDefault: defaultMicrophoneId === microphoneListArr[i].id
927
+ // });
928
+ // deviceListReport.micList[microphoneListArr[i].szDeviceId] = microphoneListArr[i].szDeviceName;
929
+ // }
930
+ // if (!window.zbztAVSDK_device_checker_init) {
931
+ // window.zbztAVSDK_device_checker_init = {};
932
+ // }
933
+ // if (!window.zbztAVSDK_device_checker_init.microphone) {
934
+ // window.zbztAVSDK_device_checker_init.microphone = {};
935
+ // }
936
+ // window.zbztAVSDK_device_checker_init.microphone.hasTest = true;
937
+ // window.zbztAVSDK_device_checker_init.microphone.list = microphoneList;
938
+ // defaultApi.writeLog(`getMicrophoneDeviceList ${JSON.stringify(microphoneList)}`);
939
+ // return microphoneList;
940
+ };
941
+
942
+ /**
943
+ * @function 设置指定音频(当前麦克风)设备
944
+ * @param deviceId: String 音频设备 id,必选
945
+ * @return Promise | void
946
+ */
947
+ const setCurrentMicrophoneDevice = (deviceId) => {
948
+ window.zbztAVSDK_device_checker_init.microphone.use = deviceId;
949
+ return callMethod('SetCurrentMicrophoneDevice', {
950
+ deviceId
951
+ });
952
+ };
953
+
954
+ /**
955
+ * @function 指定麦克风设备
956
+ * @param deviceId: String 麦克风设备 id,必选
957
+ * @param operationType: String 操作类型,可选
958
+ * @return Promise | void
959
+ */
960
+ const setMicrophoneDevice = async (args) => {
961
+ defaultApi.writeLog('-> getMicrophoneDeviceList_microphoneListArr_tal_rtc_i');
962
+ let { deviceId, operationType, deviceState, changedDeviceId } = args;
963
+ let deviceName = '';
964
+ let microPhoneData;
965
+ if (!deviceId) {
966
+ microPhoneData = await getMicrophoneDeviceList();
967
+ if (microPhoneData.length) {
968
+ let hasGetMicrophone = false;
969
+ for (let item of microPhoneData) {
970
+ if (item.isDefault) {
971
+ deviceId = item.deviceId;
972
+ deviceName = item.deviceName;
973
+ hasGetMicrophone = true;
974
+ break;
975
+ }
976
+ }
977
+ if (!hasGetMicrophone) {
978
+ deviceId = microPhoneData[0].deviceId;
979
+ deviceName = microPhoneData[0].deviceName;
980
+ }
981
+ } else {
982
+ deviceId = '';
983
+ }
984
+ if (deviceId === '') {
985
+ NOTICE.noDevice({
986
+ deviceType: 'microphone'
987
+ });
988
+ }
989
+ }
990
+
991
+ window.zbztAVSDK_device_checker_init.microphone.use = deviceId;
992
+ window.zbztAVSDK_device_checker_init.microphone.name = deviceListReport.micList[deviceId];
993
+
994
+ try {
995
+ dataReport.setDevice({
996
+ device_type: 2,
997
+ device_id: deviceId,
998
+ device_name: deviceListReport.micList[deviceId],
999
+ operationType,
1000
+ fore_state: operationType == 'hotPlug' ? +deviceState + 1 : '-'
1001
+ });
1002
+ } catch (e) {
1003
+ };
1004
+ if (audioTrack) {
1005
+ audioTrack.setDevice(deviceId);
1006
+ }
1007
+ if (operationType == 'hotPlug' || operationType == 'deviceError') {
1008
+ if (!microPhoneData) {
1009
+ microPhoneData = await getMicrophoneDeviceList();
1010
+ deviceName = deviceListReport.micList[deviceId];
1011
+ }
1012
+ NOTICE[operationType]({
1013
+ deviceType: 'microphone',
1014
+ useDeviceId: deviceId,
1015
+ useDeviceName: deviceName,
1016
+ deviceList: microPhoneData,
1017
+ deviceState,
1018
+ changedDeviceId
1019
+ });
1020
+ }
1021
+ };
1022
+
1023
+ /**
1024
+ * @function 获取当前麦克风的音量
1025
+ * @return Promise | void
1026
+ */
1027
+ const getCurrentMicrophoneVolume = () => {
1028
+ return callMethod('GetCurrentMicrophoneVolume', {}).then(ret => {
1029
+ let volume = 0;
1030
+ try {
1031
+ volume = Math.round(JSON.parse(ret.msg).microphoneVolume / 255 * 100);
1032
+ } catch (e) {
1033
+ console.error(`zbzt-live-sdk: getCurrentMicrophoneVolume ret: ${ret}. error: ${e}`);
1034
+ }
1035
+ return volume;
1036
+ });
1037
+ };
1038
+
1039
+ /**
1040
+ * @function 设置当前麦克风的音量
1041
+ * @param volume: number 音量值
1042
+ * @return Promise | void
1043
+ */
1044
+ const setCurrentMicrophoneVolume = (volume) => {
1045
+ return callMethod('SetCurrentMicrophoneVolume', {
1046
+ volume: Math.round(volume / 100 * 255)
1047
+ });
1048
+ };
1049
+
1050
+ /**
1051
+ * @function 获取当前麦克风ID
1052
+ * @return Promise | void
1053
+ */
1054
+ const getCurrentMicrophoneId = (volume) => {
1055
+ return callMethod('GetCurrentMicrophoneId', { volume });
1056
+ };
1057
+
1058
+ // 摄像头相关
1059
+ /**
1060
+ * @function 打开摄像头
1061
+ * @param width: Number
1062
+ * @param height: Number
1063
+ * @return Promise | void
1064
+ */
1065
+ const startCamera = async (width, height) => {
1066
+ defaultApi.writeLog('avsdk TALRTC::startCamera');
1067
+ videoTrack = await talrtc.createCameraVideoTrack({
1068
+ cameraId: window.zbztAVSDK_device_checker_init.camera.use,
1069
+ });
1070
+
1071
+ videoTrack.on('track-ended', () => {
1072
+ defaultApi.writeLog('avsdk TALRTC::startCamera track-ended');
1073
+ videoTrack.removeAllListeners();
1074
+ videoTrack = null;
1075
+ });
1076
+ // return callMethod('StartCamera', { width, height, streamId: localStreamId });
1077
+ };
1078
+
1079
+ /**
1080
+ * @function 关闭摄像头
1081
+ * @return Promise | void
1082
+ */
1083
+ const stopCamera = () => {
1084
+ defaultApi.writeLog('avsdk TALRTC::stopCamera');
1085
+ videoTrack && videoTrack.close();
1086
+ // return callMethod('StopCamera', { streamId: localStreamId });
1087
+ };
1088
+
1089
+ const openOrCloseCamera = async (operation) => {
1090
+ if (operation) {
1091
+ await startCamera();
1092
+ } else {
1093
+ stopCamera();
1094
+ }
1095
+ };
1096
+
1097
+ /**
1098
+ * @function 获取摄像头列表
1099
+ * @return Promise | void
1100
+ */
1101
+ const getCameraDeviceListInternal = () => {
1102
+ return callMethod('GetCameraDeviceList', {});
1103
+ };
1104
+
1105
+ /**
1106
+ * @function 获取摄像头列表
1107
+ * @return Promise | void
1108
+ */
1109
+ export const getCameraDeviceList = async () => {
1110
+ defaultApi.writeLog('avsdk TALRTC::getCameraDeviceList');
1111
+ return defaultsdk.getCameraDeviceList();
1112
+ // const resp = await getCameraDeviceListInternal();
1113
+ // let videoListArr = JSON.parse(JSON.parse(resp.msg).DeviceList) || [];
1114
+ // let videoList = [];
1115
+ // for (let i = 0, len = videoListArr.length; i < len; i++) {
1116
+ // let nameForChecking = videoListArr[i].name.toLowerCase();
1117
+ // let checkIfIsDefaultFromName = (nameForChecking.indexOf('built-in') >= 0) ||
1118
+ // (nameForChecking.indexOf('builtin') >= 0) ||
1119
+ // (nameForChecking.indexOf('default') >= 0) ||
1120
+ // (nameForChecking.indexOf('默认') >= 0) ||
1121
+ // (nameForChecking.indexOf('默認') >= 0);
1122
+ // videoList.push({
1123
+ // deviceId: videoListArr[i].id,
1124
+ // deviceName: videoListArr[i].name,
1125
+ // isDefault: videoListArr[i].default || checkIfIsDefaultFromName
1126
+ // });
1127
+ // deviceListReport.cameraList[videoListArr[i].szDeviceId] = videoListArr[i].szDeviceName;
1128
+ // }
1129
+ // if (!window.zbztAVSDK_device_checker_init) {
1130
+ // window.zbztAVSDK_device_checker_init = {};
1131
+ // }
1132
+ // if (!window.zbztAVSDK_device_checker_init.camera) {
1133
+ // window.zbztAVSDK_device_checker_init.camera = {};
1134
+ // }
1135
+ // window.zbztAVSDK_device_checker_init.camera.hasTest = true;
1136
+ // window.zbztAVSDK_device_checker_init.camera.list = videoList;
1137
+ // return videoList;
1138
+ };
1139
+
1140
+ /**
1141
+ * @function 设置指定视频(当前摄像头)设备
1142
+ * @param deviceId: String 视频设备 id,必选
1143
+ * @return Promise | void
1144
+ */
1145
+ const setCurrentCameraDeviceInternal = (deviceId) => {
1146
+ window.zbztAVSDK_device_checker_init.camera.use = deviceId;
1147
+ return callMethod('SetCurrentCameraDevice', {
1148
+ streamId: localStreamId,
1149
+ deviceId
1150
+ });
1151
+ };
1152
+
1153
+ /**
1154
+ * @function 指定使用的摄像头
1155
+ * @param deviceId: String 摄像头 id,必选
1156
+ * @param operationType: String 操作类型,可选
1157
+ * 'device_error' -> 设备出错处理,'plug_and_unplug' -> 热插拔处理,
1158
+ * 不传即是普通的设置摄像头设备的行为
1159
+ * @return Promise | void
1160
+ */
1161
+ const setCameraDevice = async (args) => {
1162
+ defaultApi.writeLog(`setCameraDevice ${JSON.stringify(args)}`);
1163
+ let { deviceId, operationType, deviceState, code, changedDeviceId } = args;
1164
+
1165
+ let deviceName = '';
1166
+ let cameraData;
1167
+ if (!deviceId) {
1168
+ cameraData = await getCameraDeviceList();
1169
+
1170
+ if (cameraData.length) {
1171
+ let hasGetCamare = false;
1172
+ for (let item of cameraData) {
1173
+ if (item.isDefault) {
1174
+ deviceId = item.deviceId;
1175
+ deviceName = item.deviceName;
1176
+ hasGetCamare = true;
1177
+ break;
1178
+ }
1179
+ }
1180
+ if (!hasGetCamare) {
1181
+ deviceId = cameraData[0].deviceId;
1182
+ deviceName = cameraData[0].deviceName;
1183
+ }
1184
+ } else {
1185
+ deviceId = '';
1186
+ }
1187
+
1188
+ if (deviceId === '') {
1189
+ NOTICE.noDevice({
1190
+ deviceType: 'camera'
1191
+ });
1192
+ }
1193
+ }
1194
+ // deviceId = formatDeviceId(deviceId);
1195
+
1196
+ window.zbztAVSDK_device_checker_init.camera.use = deviceId;
1197
+ window.zbztAVSDK_device_checker_init.camera.name = deviceListReport.cameraList[deviceId];
1198
+ try {
1199
+ dataReport.setDevice({
1200
+ device_type: 1,
1201
+ device_id: deviceId,
1202
+ device_name: deviceListReport.cameraList[deviceId],
1203
+ operationType,
1204
+ fore_state: operationType == 'hotPlug' ? deviceState + 1 : '-'
1205
+ });
1206
+ } catch (e) {
1207
+ };
1208
+
1209
+ if (videoTrack) {
1210
+ videoTrack.setDevice(deviceId);
1211
+ }
1212
+
1213
+ if (operationType == 'hotPlug' || operationType == 'deviceError') {
1214
+ if (!cameraData) {
1215
+ cameraData = await getCameraDeviceList();
1216
+ deviceName = deviceListReport.cameraList[deviceId];
1217
+ }
1218
+ NOTICE[operationType]({
1219
+ deviceType: 'camera',
1220
+ useDeviceId: deviceId,
1221
+ useDeviceName: deviceName,
1222
+ deviceList: cameraData,
1223
+ messge: code,
1224
+ deviceState,
1225
+ changedDeviceId
1226
+ });
1227
+ }
1228
+ try {
1229
+ NOTICE.useredCamera({
1230
+ deviceId,
1231
+ deviceName
1232
+ });
1233
+ } catch (e) {
1234
+ };
1235
+ };
1236
+
1237
+ /**
1238
+ * @function 获取当前摄像头 id
1239
+ * @return Promise | void
1240
+ */
1241
+ const GetCurrentCameraId = () => {
1242
+ return callMethod('GetCurrentCameraId', {});
1243
+ };
1244
+
1245
+ // 扬声器相关
1246
+
1247
+ /**
1248
+ * @function 获取扬声器列表
1249
+ * @return Promise | void
1250
+ */
1251
+ const getAudioDeviceList = () => {
1252
+ return callMethod('GetAudioDeviceList', {});
1253
+ };
1254
+
1255
+ /**
1256
+ * @function 获取系统默认的音频设备
1257
+ * @param deviceType: Number 音频设备类型,0 -> 麦克风,1 -> 扬声器,必选
1258
+ * @return Promise | void
1259
+ */
1260
+ const getDefaultAudioDeviceId = (deviceType) => {
1261
+ return callMethod('GetDefaultAudioDeviceId', {
1262
+ deviceType,
1263
+ // 以下两个参数仅仅是为了向下向后兼容,使用 hardcore 即可
1264
+ deviceId: '',
1265
+ deviceIdLength: 0
1266
+ });
1267
+ };
1268
+
1269
+ /**
1270
+ * @function 获取系统默认的麦克风设备 id
1271
+ * @return Promise
1272
+ */
1273
+ const getDefaultMicrophone = () => {
1274
+ return getDefaultAudioDeviceId(0);
1275
+ };
1276
+
1277
+ /**
1278
+ * @function 获取系统默认的扬声器设备 id
1279
+ * @return Promise
1280
+ */
1281
+ const getDefaultSpeaker = () => {
1282
+ return getDefaultAudioDeviceId(1);
1283
+ };
1284
+
1285
+ /**
1286
+ * @function 获取扬声器设备列表
1287
+ * @return Promise | void
1288
+ */
1289
+ const getSpeakerDeviceListInternal = () => {
1290
+ return callMethod('GetSpeakerDeviceList', {});
1291
+ };
1292
+
1293
+ /**
1294
+ * @function 获取扬声器列表
1295
+ * @return Promise | void
1296
+ */
1297
+ const getSpeakerDeviceList = async () => {
1298
+ defaultApi.writeLog('avsdk TALRTC::getSpeakerDeviceList');
1299
+ return defaultsdk.getSpeakerDeviceList();
1300
+ // const defaultSpeakerId = JSON.parse((await getDefaultSpeaker()).msg).deviceId;
1301
+ // const resp = await getSpeakerDeviceListInternal();
1302
+ // let speakerListArr = JSON.parse(JSON.parse(resp.msg).DeviceList) || [];
1303
+ // let speakerList = [];
1304
+ // for (let i = 0, len = speakerListArr.length; i < len; i++) {
1305
+ // speakerList.push({
1306
+ // deviceId: speakerListArr[i].id,
1307
+ // deviceName: speakerListArr[i].name,
1308
+ // isDefault: defaultSpeakerId === speakerListArr[i].id
1309
+ // });
1310
+ // deviceListReport.speakerList[speakerListArr[i].szDeviceId] = speakerListArr[i].szDeviceName;
1311
+ // }
1312
+ // if (!window.zbztAVSDK_device_checker_init) {
1313
+ // window.zbztAVSDK_device_checker_init = {};
1314
+ // }
1315
+ // if (!window.zbztAVSDK_device_checker_init.speaker) {
1316
+ // window.zbztAVSDK_device_checker_init.speaker = {};
1317
+ // }
1318
+ // window.zbztAVSDK_device_checker_init.speaker.hasTest = true;
1319
+ // window.zbztAVSDK_device_checker_init.speaker.list = speakerList;
1320
+ // return speakerList;
1321
+ };
1322
+
1323
+ /**
1324
+ * @function 设置指定音频(当前扬声器)设备
1325
+ * @param deviceId: String 音频设备 id,必选
1326
+ * @return Promise | void
1327
+ */
1328
+ const setCurrentSpeakerDevice = (deviceId) => {
1329
+ window.zbztAVSDK_device_checker_init.speaker.use = deviceId;
1330
+ return callMethod('SetCurrentSpeakerDevice', {
1331
+ deviceId
1332
+ }).then((result) => {
1333
+ if (result.code === 0) {
1334
+ NOTICE.speakerChanged({
1335
+ deviceId
1336
+ });
1337
+ }
1338
+ return result;
1339
+ });
1340
+ };
1341
+
1342
+ /**
1343
+ * 获取当前扬声器设备id
1344
+ * @return {String} 当前扬声器设备id
1345
+ */
1346
+ const getCurrentSpeakerDevice = () => {
1347
+ defaultApi.writeLog(`avsdk TALRTC::getSpeakerDevice ${usingAudioDeviceId.speaker}`);
1348
+ return usingAudioDeviceId.speaker;
1349
+ };
1350
+
1351
+ /**
1352
+ * @function 指定扬声器
1353
+ * @param deviceId: String 扬声器 id,必选
1354
+ * @param operationType:String 操作类型,可选
1355
+ * 'device_error' -> 设备出错处理,'plug_and_unplug' -> 热插拔处理,
1356
+ * 不传即是普通的设置扬声器设备的行为
1357
+ * @return Promise | void
1358
+ */
1359
+ const setSpeakerDevice = async (args) => {
1360
+ defaultApi.writeLog(`${JSON.stringify(args)}----setSpeakerDevice-talrtc----`);
1361
+ let { deviceId, operationType, deviceState, code, changedDeviceId } = args;
1362
+ let deviceName = '';
1363
+ let speakerData;
1364
+ if (!deviceId) {
1365
+ speakerData = await getSpeakerDeviceList();
1366
+ if (speakerData.length) {
1367
+ let hasGetSpeaker = false;
1368
+ for (let item of speakerData) {
1369
+ if (item.isDefault) {
1370
+ deviceId = item.deviceId;
1371
+ deviceName = item.deviceName;
1372
+ hasGetSpeaker = true;
1373
+ break;
1374
+ }
1375
+ }
1376
+ if (!hasGetSpeaker) {
1377
+ deviceId = speakerData[0].deviceId;
1378
+ deviceName = speakerData[0].deviceName;
1379
+ }
1380
+ } else {
1381
+ deviceId = '';
1382
+ }
1383
+ if (deviceId === '') {
1384
+ NOTICE.noDevice({
1385
+ deviceType: 'speaker'
1386
+ });
1387
+ }
1388
+ }
1389
+
1390
+ window.zbztAVSDK_device_checker_init.speaker.use = deviceId;
1391
+ window.zbztAVSDK_device_checker_init.speaker.name = deviceListReport.speakerList[deviceId];
1392
+
1393
+ try {
1394
+ dataReport.setDevice({
1395
+ device_type: 3,
1396
+ device_id: deviceId,
1397
+ device_name: deviceListReport.speakerList[deviceId],
1398
+ operationType,
1399
+ fore_state: operationType == 'hotPlug' ? deviceState + 1 : '-'
1400
+ });
1401
+ } catch (e) {
1402
+ console.log(e);
1403
+ };
1404
+ usingAudioDeviceId.speaker = deviceId;
1405
+ // await setCurrentSpeakerDevice(deviceId);
1406
+ if (operationType == 'hotPlug' || operationType == 'deviceError') {
1407
+ if (!speakerData) {
1408
+ speakerData = await getSpeakerDeviceList();
1409
+ deviceName = deviceListReport.speakerList[deviceId];
1410
+ }
1411
+ NOTICE[operationType]({
1412
+ deviceType: 'speaker',
1413
+ useDeviceId: deviceId,
1414
+ useDeviceName: deviceName,
1415
+ deviceList: speakerData,
1416
+ message: code,
1417
+ deviceState,
1418
+ changedDeviceId
1419
+ });
1420
+ }
1421
+ };
1422
+
1423
+ /**
1424
+ * @function 获取当前扬声器的音量
1425
+ * @returns {Promise<number>}
1426
+ */
1427
+ const getCurrentSpeakerVolume = () => {
1428
+ return callMethod('GetCurrentSpeakerVolume', {}).then(ret => {
1429
+ let volume = 0;
1430
+ try {
1431
+ volume = Math.round(JSON.parse(ret.msg).speakerVolume / 255 * 100);
1432
+ } catch (e) {
1433
+ console.error(`zbzt-live-sdk: getCurrentSpeakerVolume ret: ${ret}. error: ${e}`);
1434
+ }
1435
+ return volume;
1436
+ });
1437
+ };
1438
+
1439
+ /**
1440
+ * @function 获取当前扬声器ID
1441
+ * @return Promise | void
1442
+ */
1443
+ const getCurrentSpeakerId = () => {
1444
+ return callMethod('GetCurrentSpeakerId', {});
1445
+ };
1446
+
1447
+ /**
1448
+ * @function 是否存在媒体流
1449
+ * @param streamId
1450
+ * @returns {boolean}
1451
+ */
1452
+ export const hasStream = streamId => {
1453
+ return Object.keys(streamIdToPreviewId).includes(streamId);
1454
+ };
1455
+
1456
+
1457
+ /**
1458
+ * @function 获取当前视频流的通道
1459
+ * @param streamId 流 id
1460
+ * @return channelIndex
1461
+ */
1462
+ export const getChannelIndex = (streamId) => {
1463
+ defaultApi.writeLog(`avsdk TALRTC::getChannelIndex streamId: ${streamId} ${JSON.stringify(streamIdToPreviewId)}`);
1464
+ return streamIdToPreviewId[streamId];
1465
+ };
1466
+
1467
+ /**
1468
+ * @function 获取当前视频流所有的通道
1469
+ * @param streamId 流 id
1470
+ * @return channelIndex
1471
+ */
1472
+ export const getAllChannelIndex = () => {
1473
+ defaultApi.writeLog(`avsdk TALRTC::getAllChannelIndex ${JSON.stringify(streamIdToPreviewId)}`);
1474
+ return streamIdToPreviewId;
1475
+ };
1476
+
1477
+
1478
+ /**
1479
+ * @function 设置当前扬声器音量
1480
+ * @param volume: number 音量值
1481
+ * @return Promise | void
1482
+ */
1483
+ const setCurrentSpeakerVolume = (volume) => {
1484
+ return callMethod('SetCurrentSpeakerVolume', {
1485
+ volume: Math.round(volume / 100 * 255)
1486
+ });
1487
+ };
1488
+
1489
+ /**
1490
+ * @function 设置扬声器静音
1491
+ * @param mute: Boolean 必选
1492
+ * @return Promise | void
1493
+ */
1494
+ const setSpeakerDeviceMute = (mute) => {
1495
+ return callMethod('SetSpeakerDeviceMute', {
1496
+ deviceId: usingAudioDeviceId.speaker,
1497
+ mute
1498
+ });
1499
+ };
1500
+
1501
+ /**
1502
+ * @function 获取当前应用程序音量
1503
+ * @return Promise | void
1504
+ */
1505
+ const getSpeakerSimpleVolume = () => {
1506
+ return callMethod('GetSpeakerSimpleVolume', {
1507
+ deviceId: usingAudioDeviceId.speaker
1508
+ }).then(ret => {
1509
+ let volume = 0;
1510
+ try {
1511
+ volume = Math.round(JSON.parse(ret.msg).speakerVolume / 255 * 100);
1512
+ } catch (e) {
1513
+ console.error(`zbzt-live-sdk: getSpeakerSimpleVolume ret: ${ret}. error: ${e}`);
1514
+ }
1515
+ return volume;
1516
+ });
1517
+ };
1518
+
1519
+ /**
1520
+ * @function 设置当前应用程序音量
1521
+ * @param volume: Number 应用程序音量,必选
1522
+ * @return Promise | void
1523
+ */
1524
+ const setSpeakerSimpleVolume = (volume) => {
1525
+ return callMethod('SetSpeakerSimpleVolume', {
1526
+ deviceId: usingAudioDeviceId.speaker,
1527
+ volume: Math.round(volume / 100 * 255)
1528
+ });
1529
+ };
1530
+
1531
+ /**
1532
+ * @function 设置当前应用程序静音
1533
+ * @param mute: Boolean 是否静音,必选
1534
+ * @return Promise | void
1535
+ */
1536
+ const setSpeakerSimpleMute = (mute) => {
1537
+ return callMethod('SetSpeakerSimpleMute', {
1538
+ deviceId: usingAudioDeviceId.speaker,
1539
+ mute
1540
+ });
1541
+ };
1542
+
1543
+ const enableAudioSpeakerCapture = (capture) => {
1544
+ setSystemAudioLoopback(capture);
1545
+ };
1546
+
1547
+ /**
1548
+ * @function 打开系统声音采集
1549
+ * @enable true|false
1550
+ * @return Promise | void
1551
+ */
1552
+ const setSystemAudioLoopback = (enable) => {
1553
+ isSpeakerCapturing = enable;
1554
+ if (enable) {
1555
+ return setAudioType(6, localStreamId);
1556
+ } else {
1557
+ return setAudioType(1, localStreamId);
1558
+ }
1559
+ // return callMethod('SetAudioSpeakerCapture', {
1560
+ // enable,
1561
+ // });
1562
+ };
1563
+
1564
+ /**
1565
+ * @function 录制转推对外接口
1566
+ * @param type: String start/stop 必选
1567
+ * @param targetUrl: String 转推地址(支持 RTMP) 必选
1568
+ * @return Promise | void
1569
+ */
1570
+ const controlCdnStreaming = async (type) => {
1571
+ const targetUrl = 'rtmp://media-push-ali-test.livecloud.eaydu.com/testlive/210926-11?key=75c868672113df0063430e9e47fb2a60&appId=zt10001&bizId=zt10001AI&cdn=1';
1572
+ defaultApi.writeLog(`avsdk TALRTC::controlCdnStreaming targetUrl: ${targetUrl} type: ${type}`);
1573
+ if (type === 'start') {
1574
+ return addPublishRtmpStreamUrl(targetUrl);
1575
+ }
1576
+ if (type === 'stop') {
1577
+ return removePublishStreamUrl(targetUrl);
1578
+ }
1579
+ };
1580
+
1581
+ /**
1582
+ * @function SEI 消息
1583
+ * @param data: String 数据
1584
+ * @param dataSize: Number 数据长度
1585
+ * @param repeatCount: Number 重试次数
1586
+ * @return Promise | void
1587
+ */
1588
+ const sendSEIMsg = (data) => {
1589
+ return callMethod('SendSEIMsg', { data: data, dataSize: data.length, repeatCount: 3 });
1590
+ };
1591
+
1592
+ /**
1593
+ * @function 开始屏幕采集
1594
+ * @return Promise | void
1595
+ */
1596
+ const startScreenCapture = async () => {
1597
+ defaultApi.writeLog('avsdk TALRTC::startScreenCapture');
1598
+ screenTrack = await talrtc.createScreenVideoTrack({
1599
+ screenSourceType: 'application',
1600
+ }, 'disable');
1601
+
1602
+ screenTrack.on('track-ended', () => {
1603
+ defaultApi.writeLog('avsdk TALRTC::startScreenCapture track-ended');
1604
+ screenTrack.removeAllListeners();
1605
+ screenTrack = null;
1606
+ });
1607
+ // return callMethod('StartScreenCapture', {});
1608
+ };
1609
+
1610
+ /**
1611
+ * @function 停止屏幕采集
1612
+ * @return Promise | void
1613
+ */
1614
+ const stopScreenCapture = () => {
1615
+ defaultApi.writeLog('avsdk TALRTC::stopScreenCapture');
1616
+ screenTrack && screenTrack.close();
1617
+ // return callMethod('StopScreenCapture', {});
1618
+ };
1619
+
1620
+
1621
+ // 推拉流相关
1622
+ /**
1623
+ * @function 开启本地或者远程的视频视图
1624
+ * @param isLocal: Boolean 是否是本地的视频预览,必选
1625
+ * @param streamId: String 要拉取的视频流的 id,可选,只有拉取远程的视频流的时候才是必选的
1626
+ * @param domId: String <video> 标签的 id,可选
1627
+ * 如果传了 domId,就把视频绑定到对应的 <video> 标签上
1628
+ * @return Promise 可从 Promise 中获取 src,Promise.then((src) => {})
1629
+ */
1630
+ const startLocalOrRemotePreview = async (isLocal, streamId, domId) => {
1631
+ defaultApi.writeLog(`avsdk TALRTC::startLocalOrRemotePreview streamId: ${streamId}, isLocal: ${isLocal}, domId: ${domId}`);
1632
+
1633
+ if (isLocal) {
1634
+ if (streamId === localStreamId) {
1635
+ if (!videoTrack) {
1636
+ defaultApi.writeLog('avsdk TALRTC::startLocalOrRemotePreview - startCamera first', null, 'error');
1637
+ throw new Error('avsdk TALRTC::startLocalOrRemotePreview - startCamera first');
1638
+ }
1639
+
1640
+ videoTrack.play(domId);
1641
+ }
1642
+
1643
+ if (streamId === screenStreamId) {
1644
+ if (!screenTrack) {
1645
+ await startScreenCapture();
1646
+ }
1647
+
1648
+ screenTrack.play(domId);
1649
+ }
1650
+
1651
+ } else {
1652
+ if (!streamId) {
1653
+ defaultApi.writeLog('avsdk TALRTC::startLocalOrRemotePreview - streamId is required', null, 'error');
1654
+ return;
1655
+ }
1656
+ if (!remoteTracks.has(streamId)) {
1657
+ defaultApi.writeLog(`avsdk TALRTC::startLocalOrRemotePreview - ${streamId} is null, set it to auto play`);
1658
+ remoteTracks.set(streamId, true);
1659
+ return;
1660
+ }
1661
+ remoteTracks.get(streamId).play(domId);
1662
+ }
1663
+ };
1664
+
1665
+ /**
1666
+ * @function 开始推流
1667
+ * @param streamId: String 流 id
1668
+ * @return Promise | void
1669
+ */
1670
+ const startPush = async (streamId) => {
1671
+ if (!streamId) {
1672
+ streamId = localStreamId;
1673
+ }
1674
+ defaultApi.writeLog(`avsdk TALRTC::startPush streamId: ${streamId}`);
1675
+
1676
+ const roomId = util.getRoomIdByStreamId(streamId);
1677
+ const client = clients.get(roomId);
1678
+
1679
+ if (!client) {
1680
+ defaultApi.writeLog('avsdk TALRTC::startPush - init first', null, 'error');
1681
+ throw new Error('avsdk TALRTC::startPush - init first');
1682
+ }
1683
+
1684
+ try {
1685
+ if (!isFirstHeartBeatReport) {
1686
+ isFirstHeartBeatReport = true;
1687
+ heartBeatDataReport('start');
1688
+ }
1689
+ } catch (error) {}
1690
+ const tracks = [];
1691
+
1692
+ if (streamId === screenStreamId && screenTrack) {
1693
+ await startScreenCapture();
1694
+ tracks.push(screenTrack);
1695
+ }
1696
+ if (streamId === localStreamId && audioTrack) {
1697
+ tracks.push(audioTrack);
1698
+ }
1699
+ if (streamId === localStreamId && videoTrack) {
1700
+ tracks.push(videoTrack);
1701
+ }
1702
+ // const muteAudio = localStreamMuteStatus.audio;
1703
+ // const muteVideo = localStreamMuteStatus.video;
1704
+ return client.publish(tracks);
1705
+ };
1706
+
1707
+ /**
1708
+ * @function 停止推流
1709
+ * @param streamId: String 流 id
1710
+ * @return Promise | void
1711
+ */
1712
+ const stopPush = (streamId) => {
1713
+ if (!streamId) {
1714
+ streamId = localStreamId;
1715
+ }
1716
+
1717
+ defaultApi.writeLog(`avsdk TALRTC::stopPush streamId: ${streamId}`);
1718
+
1719
+ const roomId = util.getRoomIdByStreamId(streamId);
1720
+ const client = clients.get(roomId);
1721
+
1722
+ if (!client) {
1723
+ defaultApi.writeLog('avsdk TALRTC::stopPush - init first', null, 'error');
1724
+ throw new Error('avsdk TALRTC::stopPush - init first');
1725
+ }
1726
+
1727
+ const tracks = [];
1728
+ if (streamId === screenStreamId && screenTrack) {
1729
+ screenTrack.close();
1730
+ tracks.push(screenTrack);
1731
+ }
1732
+ if (streamId === localStreamId && audioTrack) {
1733
+ tracks.push(audioTrack);
1734
+ }
1735
+ if (streamId === localStreamId && videoTrack) {
1736
+ tracks.push(videoTrack);
1737
+ }
1738
+ return client.unpublish(tracks);
1739
+ // return callMethod('StopPush', { streamId });
1740
+ };
1741
+
1742
+ /**
1743
+ * @function 不推/推 音频
1744
+ * @param mute: bool
1745
+ * @return Promise | void
1746
+ */
1747
+ const muteLocalAudio = async (mute) => {
1748
+ defaultApi.writeLog(`avsdk TALRTC::muteLocalAudio mute: ${mute}`);
1749
+
1750
+ if (audioTrack) {
1751
+ await audioTrack.setMuted(mute);
1752
+ }
1753
+ localStreamMuteStatus.audio = mute;
1754
+ };
1755
+
1756
+ /**
1757
+ * @function 不推/推 视频
1758
+ * @param mute: bool
1759
+ * @return Promise | void
1760
+ */
1761
+ const muteLocalVideo = async (mute) => {
1762
+ defaultApi.writeLog(`avsdk TALRTC::muteLocalVideo mute: ${mute}`);
1763
+
1764
+ if (videoTrack) {
1765
+ await videoTrack.setMuted(mute);
1766
+ }
1767
+ localStreamMuteStatus.video = mute;
1768
+ };
1769
+
1770
+ /**
1771
+ * @function 开始转推本地摄像头 TALRTC 流至 RTMP。目前只支持转推 1 路
1772
+ * @return Promise | void
1773
+ */
1774
+ const addPublishRtmpStreamUrl = (url) => {
1775
+ defaultApi.writeLog(`avsdk TALRTC::addPublishRtmpStreamUrl url: ${url}`);
1776
+ return callMethod('AddPublishRtmpStreamUrl', { url });
1777
+ };
1778
+
1779
+ /**
1780
+ * @function 停止转推 RTMP
1781
+ * @return Promise | void
1782
+ */
1783
+ const removePublishStreamUrl = (url) => {
1784
+ defaultApi.writeLog(`avsdk TALRTC::removePublishStreamUrl url: ${url}`);
1785
+ return callMethod('RemovePublishStreamUrl', { url });
1786
+ };
1787
+
1788
+ /**
1789
+ * @function 开始拉流
1790
+ * @param {string} streamId 流 id
1791
+ * @return {Promise} Promise | void
1792
+ */
1793
+ const startPlay = (streamId, muteAudio, muteVideo) => {
1794
+ if (typeof muteAudio === 'undefined') {
1795
+ muteAudio = getStreamMuteStatus(streamId, 'audio');
1796
+ }
1797
+
1798
+ if (typeof muteVideo === 'undefined') {
1799
+ muteVideo = getStreamMuteStatus(streamId, 'video');
1800
+ }
1801
+ defaultApi.writeLog(`avsdk TALRTC::startPlay streamId: ${streamId}, muteAudio: ${muteAudio}, muteVideo: ${muteVideo}`);
1802
+ return callMethod('StartPlay', {
1803
+ myStreamId: localStreamId,
1804
+ streamId,
1805
+ muteAudio,
1806
+ muteVideo,
1807
+ muteDefaultAudio: classMode === 1 || classMode === 2,
1808
+ muteDefaultVideo: classMode === 1 || classMode === 2
1809
+ }).then((...args) => {
1810
+ if (args[0].code !== 0 && streamIdToPreviewId[streamId]) {
1811
+ console.log('retry startPlay----', streamId);
1812
+ return startPlay(streamId, muteAudio, muteVideo);
1813
+ }
1814
+ setStreamMuteStatus(streamId, 'audio', muteAudio);
1815
+ setStreamMuteStatus(streamId, 'video', muteVideo);
1816
+ return args;
1817
+ });
1818
+ };
1819
+
1820
+ /**
1821
+ * @function 初始化拉流
1822
+ * @param streamId:String 从传来的信道消息中获取,必选
1823
+ * @param domId:String <video> 标签的 id,可选
1824
+ * 如果传了就把视频绑定到对应的 <video> 标签上
1825
+ * @param pInfo:String 多媒体流附加信息,可选,默认为 'none'
1826
+ * @return src:String 视频预览地址
1827
+ */
1828
+ export const initPullFlow = async (streamId, domId, mute, pInfo, notAutoPlay, audioOnly) => {
1829
+ defaultApi.writeLog(`TALRTC::initPullFlow_start , streamId :${streamId}, notAutoPlay: ${notAutoPlay}, audioOnly: ${audioOnly}`);
1830
+ let playChannel;
1831
+ resetStreamIdRtcPlayerInfo1(streamId);
1832
+ resetStreamIdRtcPlayerInfo(streamId);
1833
+ try {
1834
+ if (!isFirstHeartBeatReport) {
1835
+ isFirstHeartBeatReport = true;
1836
+ heartBeatDataReport('start');
1837
+ }
1838
+ } catch (error) {}
1839
+ if (streamIdToPreviewId[streamId] == undefined) {
1840
+
1841
+ defaultApi.writeLog(`TALRTC:: The streamId queue does not contain this streamId ${uiChnIndexs}`);
1842
+ playChannel = uiChnIndexs.pop();
1843
+ streamIdToPreviewId[streamId] = playChannel;
1844
+ // console.log('streamIdIsNoExited',playChannel,streamIdToPreviewId[streamId],uiChnIndexs);
1845
+ } else {
1846
+ defaultApi.writeLog(`TALRTC::The streamId queue contains this streamId: ${streamId}`);
1847
+ playChannel = streamIdToPreviewId[streamId];
1848
+ // console.log('streamIdIsExited',playChannel,streamIdToPreviewId[streamId],uiChnIndexs);
1849
+ await stopPlay(streamId);
1850
+ resetStreamIdRtcPlayerInfo(streamId);
1851
+ }
1852
+ // 判断是否创建或者获取播放通道成功,不成功就删掉重试
1853
+ if (playChannel == undefined) {
1854
+ delete streamIdToPreviewId[streamId];
1855
+ defaultApi.writeLog('error', 'TALRTC:: uiChnIndex is not exist');
1856
+ return initPullFlow(streamId, domId, mute, pInfo, notAutoPlay, audioOnly);
1857
+ }
1858
+ previewIdToStreamId[playChannel] = streamId;
1859
+ /**
1860
+ * 将 muteRemote 参数耦合进startPlay,减少异步调用,降低黑屏概率
1861
+ */
1862
+ // 是否拉取声音
1863
+ // await muteRemoteAudio(streamId, !!mute);
1864
+ // // 是否拉取画面
1865
+ // await muteRemoteVideo(streamId, !!audioOnly);
1866
+ const videoSrc = await startLocalOrRemotePreview(false, streamId, domId);
1867
+
1868
+ if (!notAutoPlay) {
1869
+ await startPlay(streamId, !!mute, !!audioOnly);
1870
+ }
1871
+ return {
1872
+ videoSrc,
1873
+ playerId: playChannel
1874
+ };
1875
+ };
1876
+
1877
+
1878
+
1879
+ /**
1880
+ * @function 开始连麦
1881
+ * @param mode: number 采集器默认, 默认0=站立 1=坐立
1882
+ * @return Promise | void
1883
+ */
1884
+ export const teacherStartLinkMic = async (mode = 0) => {
1885
+ await startMicrophone();
1886
+ if (mode === 0) {
1887
+ await muteLocalVideo(true, localStreamId);
1888
+ await setMicrophoneDevice({});
1889
+ // await muteStreamAudio(false);
1890
+ await muteLocalAudio(false);
1891
+ } else {
1892
+ // await muteLocalVideo(false, localStreamId);
1893
+ await muteLocalAudio(false);
1894
+ }
1895
+ };
1896
+
1897
+
1898
+ /**
1899
+ * @function 结束连麦
1900
+ * @param mode:number 采集器默认, 默认0=站立 1=坐立
1901
+ * @return Promise | void
1902
+ */
1903
+ export const teacherStopLinkMic = async (mode = 0) => {
1904
+ await stopMicrophone();
1905
+ if (mode === 0) {
1906
+ await muteLocalAudio(true);
1907
+ } else {
1908
+ await setSystemAudioLoopback(false);
1909
+ }
1910
+ };
1911
+
1912
+ /**
1913
+ * @function 停止拉流
1914
+ * @param streamId: String 流 id
1915
+ * @return Promise | void
1916
+ */
1917
+ const stopPlay = (streamId, recovery) => {
1918
+ const id = streamIdToPreviewId[streamId];
1919
+ delete streamIdRtcPlayerInfo[streamId];
1920
+ if (recovery && (id || id === 0) && !uiChnIndexs.includes(id)) {
1921
+ uiChnIndexs.push(id);
1922
+ defaultApi.writeLog(`avsdk TALRTC::stopPlayStream streamId: ${streamId} id: ${id} uiChnIndexs: ${uiChnIndexs}`);
1923
+ delete streamIdToPreviewId[streamId];
1924
+ }
1925
+ return callMethod('StopPlay', { streamId });
1926
+ };
1927
+
1928
+
1929
+ /**
1930
+ * @function 停止拉所有的流
1931
+ * @return Promise | void
1932
+ */
1933
+ const stopPlayAll = () => {
1934
+ return callMethod('StopPlayAll', {});
1935
+ };
1936
+
1937
+ const playerSnapShot = (streamId) => {
1938
+ switch (streamId) {
1939
+ case localStreamId:
1940
+ return videoTrack.getCurrentFrameData();
1941
+ case screenStreamId:
1942
+ return screenTrack.getCurrentFrameData();
1943
+ case remoteTracks.has(streamId):
1944
+ return remoteTracks.get(streamId).getCurrentFrameData();
1945
+ default:
1946
+ defaultApi.writeLog('avsdk TALRTC::playerSnapShot error', null, 'error');
1947
+ throw new Error('streamId not found');
1948
+ }
1949
+ };
1950
+ /**
1951
+ * @function 切换播放流
1952
+ * @param streamId: String 需要停止流的 id,必选
1953
+ * @param toStreamId: String 被拉取的流的 id,必选
1954
+ * @param toDomId: String <video> 标签的 id,可选
1955
+ * @return Promise | void
1956
+ */
1957
+ const changePullFlow = async (streamId, toStreamId, toDomId) => {
1958
+ await stopPlay(streamId);
1959
+ return initPullFlow(toStreamId, toDomId);
1960
+ };
1961
+
1962
+ /**
1963
+ * @function 是否拉取音频流--通过播放器id控制
1964
+ * @param mute: Boolean,必选,true -> 不拉取,false -> 拉取,必选
1965
+ * @param playerId: Number,必选,播放器 id
1966
+ * @return Promise | void
1967
+ */
1968
+ const pullAudioFlow = (playerId, mute, streamid) => {
1969
+ defaultApi.writeLog(`pullAudioFlow -- playerId ${playerId} operation ${mute} streamId ${streamid}`);
1970
+ if(streamid){
1971
+ if(streamIdToPreviewId[streamid] == undefined) {
1972
+ NOTICE.pullAudioFlowError({streamid});
1973
+ return;
1974
+ }else{
1975
+ playerId = streamIdToPreviewId[streamid];
1976
+ defaultApi.writeLog(`pullAudioFlow-playerId ${playerId}, ${JSON.stringify(streamIdToPreviewId)}`);
1977
+ }
1978
+ }
1979
+ let streamId = previewIdToStreamId[playerId];
1980
+ try {
1981
+ streamIdRtcPlayerInfo1[streamId].audio_type = !mute;
1982
+ defaultApi.writeLog(
1983
+ `pullAudioFlow, ${streamId} ::previewIdToStreamId', ${JSON.stringify(previewIdToStreamId)} ::streamIdRtcPlayerInfo1 ${JSON.stringify(streamIdRtcPlayerInfo1)}`);
1984
+ } catch (e) {
1985
+ defaultApi.writeLog(`pullAudioFlow ::streamIdRtcPlayerInfo1--error ${JSON.stringify(e)}`, null, error);
1986
+ }
1987
+ try {
1988
+ dataReport.setPullVoice({
1989
+ code: +!mute,
1990
+ pull_uid: util.getUidByStreamId(streamId),
1991
+ pull_streamid: streamId,
1992
+ playerId
1993
+ // operator:'client'
1994
+ });
1995
+ } catch (e) { };
1996
+ return muteRemoteAudio(streamId, mute);
1997
+ };
1998
+
1999
+ /**
2000
+ * @function 设置镜像状态(预览)
2001
+ * @param { 0 | 1 | 2 | 3 } mode 0: 预览启用镜像,推流不启用镜像; 1: 预览启用镜像,推流启用镜像; 2: 预览不启用镜像,推流不启用镜像; 3: 预览不启用镜像,推流启用镜像
2002
+ * @return {Promise}
2003
+ */
2004
+ const setMirrorStatus = (mode) => {
2005
+ const realId = mode == 0 ? 2 : 1;
2006
+ defaultApi.writeLog(`avsdk TALRTC::setMirrorStatus, mode: ${mode}, streamId:${localStreamId}, realId:${realId}`);
2007
+ return callMethod('SetMirrorStatus', { mode: realId, streamId: localStreamId });
2008
+ };
2009
+
2010
+ /**
2011
+ * @function 设置拉流镜像状态
2012
+ * @param { boolean } type true=开启 false=关闭
2013
+ * @return: Promise
2014
+ */
2015
+ const setPlayViewMirror = (isMirror, id) => {
2016
+ return callMethod('SetPlayViewMirror', { isMirror, streamId: id });
2017
+ };
2018
+
2019
+ /**
2020
+ * @function 不拉/拉 音频
2021
+ * @param streamId: string
2022
+ * @param mute: bool
2023
+ * @return Promise | void
2024
+ */
2025
+ const muteRemoteAudio = (streamId, mute) => {
2026
+ const stream = remoteTracks.get(streamId);
2027
+ if (stream) {
2028
+ return stream.setMuted(mute);
2029
+ }
2030
+ return callMethod('MuteRemoteAudio', { streamId, mute }).then((...args) => {
2031
+ setStreamMuteStatus(streamId, 'audio', mute);
2032
+ return args;
2033
+ });
2034
+ };
2035
+
2036
+ /**
2037
+ * @function 不拉/拉 视频
2038
+ * @param streamId: string
2039
+ * @param mute: bool
2040
+ * @return Promise | void
2041
+ */
2042
+ const muteRemoteVideo = (streamId, mute) => {
2043
+ return callMethod('MuteRemoteVideo', { streamId, mute }).then((...args) => {
2044
+ setStreamMuteStatus(streamId, 'video', mute);
2045
+ return args;
2046
+ });
2047
+ };
2048
+ /**
2049
+ * @function 设置外部采集设备模块
2050
+ * @param enable 是否开启外部采集设备模块
2051
+ * @attention 必须在 InitSDK 前调用,置空必须在UninitSDK之后
2052
+ * @return Promise | void
2053
+ */
2054
+ const enableExternalVideoSource = (enable = false, streamId = localStreamId) => {
2055
+ defaultApi.writeLog('info', 'avsdk TALRTC::EnableExternalVideoSource');
2056
+ return callMethod('EnableExternalVideoSource', {enable, streamId});
2057
+ };
2058
+
2059
+ //设置音频数据来源
2060
+ const setAudioAuxSource = (source) => {
2061
+ defaultApi.writeLog('info', 'avsdk TALRTC::setAudioAuxSource');
2062
+ return callMethod('SetAudioAuxSource', {
2063
+ source
2064
+ });
2065
+ };
2066
+
2067
+ /**
2068
+ * RTC流音频类型
2069
+ * @param {number} type 音频类型 0:静音 / 1:麦克风 / 2:拉流的声音 / 3:1+2 / 4:麦克风+扬声器+2 5: 扬声器 6: 麦克风+扬声器
2070
+ * @param {string} streamId 流
2071
+ * @returns {Promise<void>}
2072
+ */
2073
+ const setAudioType = (type, streamId) => {
2074
+ defaultApi.writeLog('info', 'avsdk TALRTC::SetAudioType');
2075
+ if (!streamId) {
2076
+ streamId = screenStreamId;
2077
+ }
2078
+ return callMethod('SetAudioType', {
2079
+ streamId,
2080
+ type
2081
+ });
2082
+ };
2083
+
2084
+ //开启音频外部采集 参数:channel 参数类型:int 通道(传1使用辅通道)
2085
+ const startAudioExCapture = (channel) => {
2086
+ defaultApi.writeLog('info', 'avsdk TALRTC::startAudioExCapture');
2087
+ return callMethod('StartAudioExCapture', {
2088
+ channel
2089
+ });
2090
+ };
2091
+ /**
2092
+ * @function 加载采集插件的输出数据 //采集屏幕并且拼接了连麦学生头像的数据
2093
+ * @returns {Promise}
2094
+ */
2095
+ export const loadCollectionOutputEntry = () => {
2096
+ return callMethod('LoadCollectionOutputEntry', {
2097
+ streamId: localStreamId
2098
+ });
2099
+ };
2100
+ /**
2101
+ * @function 加载采集插件的输出数据 //只采集屏幕数据
2102
+ * @returns {Promise}
2103
+ */
2104
+ const LoadCollectionOutputEntry2 = () => {
2105
+ defaultApi.writeLog('info', 'avsdk TALRTC::LoadCollectionOutputEntry2');
2106
+ return callMethod('LoadCollectionOutputEntry2', {
2107
+ streamId: screenStreamId
2108
+ });
2109
+ };
2110
+
2111
+ //开启同屏
2112
+ const startMultiScreen = async () => {
2113
+ defaultApi.writeLog('info', 'avsdk TALRTC::startMultiScreen');
2114
+ // await enableExternalVideoSource(true,1);
2115
+ await LoadCollectionOutputEntry2();
2116
+ };
2117
+
2118
+ /**
2119
+ * 音频增强调到最高优先级
2120
+ * @param {string} streamId
2121
+ * @param {string} uid
2122
+ * @param {boolean} add
2123
+ * @returns
2124
+ */
2125
+ const setChiefAudioStream = async (streamId, uid, add = true) => {
2126
+ defaultApi.writeLog('info', 'avsdk TALRTC::SetChiefAudioStream');
2127
+ return callMethod('SetChiefAudioStream', {
2128
+ streamId,
2129
+ uid,
2130
+ add
2131
+ });
2132
+ };
2133
+
2134
+ /**
2135
+ * talrtc40路拉流混音接口
2136
+ * @param {number} mixMode //混流模式 0=关闭混流 1=开启混流
2137
+ * @param {Array<string>} streamIdArr //表示要突出声音的channel
2138
+ * @returns {Promise}
2139
+ */
2140
+ export const setAudioMixMode = async (mixMode, streamIdArr) => {
2141
+ // let channelsArr = [];
2142
+ // if(streamIdArr.length > 0){
2143
+ // streamIdArr.forEach( item => {
2144
+ // channelsArr.push(getChannelIndex(item));
2145
+ // });
2146
+ // }
2147
+ if (!Array.isArray(streamIdArr)) return;
2148
+
2149
+ // if (!streamIdArr.includes(teacherId)) {
2150
+ // streamIdArr.push(teacherId);
2151
+ // }
2152
+ return callMethod('SetAudioMixMode', {mixMode: mixMode, streamIdArr, num: streamIdArr.length});
2153
+ };
2154
+
2155
+
2156
+ /**
2157
+ * @function 离开教室
2158
+ * @return Promise | void
2159
+ */
2160
+ const leaveRoom = async () => {
2161
+ for (let key in streamIdToPreviewId) {
2162
+ stopPlay(key, true);//huishou
2163
+ }
2164
+
2165
+ if (screenStreamId) {
2166
+ screenStreamId = null;
2167
+ }
2168
+
2169
+ stopPush(localStreamId);
2170
+
2171
+ if (isSpeakerCapturing) {
2172
+ setSystemAudioLoopback(false);
2173
+ }
2174
+ if(window.zbzt_sdk_init_params.role === 'teacher' && window.zbzt_sdk_init_params.mode === 1){
2175
+ //坐立模式关闭外部采集器,站立关闭外部采集器
2176
+ enableExternalVideoSource(false);
2177
+ }
2178
+ localStreamId = null;
2179
+ removerListener();
2180
+ destroyEngine();
2181
+ heartBeatDataReport('stop');
2182
+ // isFirstHeartBeatReport = false;
2183
+ streamIdToPreviewId = {};
2184
+ previewIdToStreamId = {};
2185
+ streamIdRtcPlayerInfo = {};
2186
+ streamIdRtcPlayerInfo1 = {};
2187
+ uiChnIndexs.length = 100;
2188
+ uiChnIndexs.fill(0).forEach((value, index, array) => {
2189
+ array[index] = array.length - (index + 1);
2190
+ });
2191
+ };
2192
+
2193
+
2194
+ /**
2195
+ * @function 卸载 Talrtc 扩展
2196
+ * @return Promise | void
2197
+ */
2198
+ export const unloadTalrtc = () => {
2199
+ // EM 是寄宿于端的,浏览器中并不存在,为防止报错需要先进行能力检测
2200
+ if (EM) {
2201
+ return new Promise((resolve, reject) => {
2202
+ EM.UnLoad(
2203
+ extensionId,
2204
+ (code, msg) => {
2205
+ defaultApi.writeLog(`unloadTalrtc Code: ${code}\nMessage: ${msg}`);
2206
+ resolve();
2207
+ }
2208
+ );
2209
+ });
2210
+ }
2211
+ };
2212
+
2213
+ /**
2214
+ * @function 本地录制
2215
+ * @param {string | undefined} fileName
2216
+ * @param {number} fileType 1:flv 2:mp4
2217
+ * @param {number} idx 0:主流 1:辅流 2:RTMP流
2218
+ * @returns {Promise<any>}
2219
+ */
2220
+ export const startRecord = async (fileName, fileType, idx) => {
2221
+ const streamId = [localStreamId, screenStreamId, 'rtmp'][idx];
2222
+ defaultApi.writeLog(`avsdk TALRTC::startRecord fileName: ${fileName}, fileType: ${fileType}, idx: ${idx}, streamId: ${streamId}`);
2223
+ if (idx === 1 && !screenStreamId) {
2224
+ defaultApi.writeLog('avsdk TALRTC::startRecord screenStreamId is null', null, 'error');
2225
+ return;
2226
+ }
2227
+ if (!fileName) {
2228
+ fileName = `${streamId}-${util.currentTimeString().replace(/:/g, '-')}`;
2229
+ }
2230
+ dataReport.startRecord({fileName, fileType, idx, streamId});
2231
+ return callMethod('StartRecord', {
2232
+ streamId,
2233
+ recordType: 3, // 1:音频 2:视频 3:音视频
2234
+ fileName,
2235
+ recordFormat: fileType,
2236
+ });
2237
+ };
2238
+ /**
2239
+ * 结束音视频录制 channelIndex(number) 录制通道 0主推流通道/ 1辅助推流通道/ 2辅助推流通道
2240
+ * @param {number} idx 0 | 1 | 2
2241
+ * @returns
2242
+ */
2243
+ export const stopRecord = async (idx) => {
2244
+ const streamId = [localStreamId, screenStreamId, 'rtmp'][idx];
2245
+ defaultApi.writeLog(`avsdk TALRTC::stopRecord idx: ${idx}, streamId: ${streamId}`);
2246
+
2247
+ dataReport.stopRecord({idx, streamId});
2248
+ return callMethod('StopRecord',{streamId});
2249
+ };
2250
+ /**
2251
+ * 开启外部音频采集(通知sdk)推流前,调用此接口,publish_channel,number类型,传2代表第三路流
2252
+ * @param {number} idx 0 | 1 | 2
2253
+ * @returns
2254
+ */
2255
+ export const startCapture = async (idx) => {
2256
+ const streamId = [localStreamId, screenStreamId, 'rtmp'][idx];
2257
+ defaultApi.writeLog(`avsdk TALRTC::startCapture idx: ${idx}, streamId: ${streamId}`);
2258
+
2259
+ return callMethod('StartCapture',{streamId});
2260
+ };
2261
+ /**
2262
+ * 结束外部音频采集(通知sdk)
2263
+ * @param {number} idx 0 | 1 | 2
2264
+ * @returns
2265
+ */
2266
+ export const stopCapture = async (idx) => {
2267
+ const streamId = [localStreamId, screenStreamId, 'rtmp'][idx];
2268
+ defaultApi.writeLog(`avsdk TALRTC::stopCapture idx: ${idx}, streamId: ${streamId}`);
2269
+
2270
+ return callMethod('StopCapture',{streamId});
2271
+ };
2272
+
2273
+ const heartBeatRealKeys = ['video_fps', 'video_bitrate', 'audio_fps', 'audio_bitrate'];
2274
+
2275
+ const _heartBeatDataReport = () => {
2276
+ // let cpuRate = 0;
2277
+ // let memRate = 0;
2278
+ // let rateCount = 0;
2279
+ // let appCpuRate = 0;
2280
+ // let appMemUsed = 0;
2281
+ // let rateTimer = setInterval(async () => {
2282
+ // rateCount++;
2283
+ // let {cpu_rate, mem_rate, gpus, app_cpu_rate, app_mem_used} = (await toolApi.getCurCpuMemInfo()).msg;
2284
+ // cpu_rate = cpu_rate < 0 ? 0 : cpu_rate;
2285
+ // cpuRate += parseFloat(cpu_rate);
2286
+ // memRate += parseFloat(mem_rate);
2287
+ // if (window.zbztAVSDK_init_params.zego.role === 'student') {
2288
+ // appCpuRate += parseFloat(app_cpu_rate);
2289
+ // appMemUsed += parseFloat(app_mem_used);
2290
+ // }
2291
+
2292
+ // if (rateCount >= 3) {
2293
+ // heartBeatRealKeys.forEach(realKey => {
2294
+ // if (heartBeatDataReportObj.hasOwnProperty(realKey) && heartBeatDataReportObj.count > 0) {
2295
+ // heartBeatDataReportObj[realKey] = util.toFixed(heartBeatDataReportObj[realKey]/heartBeatDataReportObj.count);
2296
+ // }
2297
+ // });
2298
+ const pullInfo = [];
2299
+ console.log('拉流的类型1',streamIdRtcPlayerInfo);
2300
+ Object.keys(streamIdRtcPlayerInfo).forEach(streamid => {
2301
+ heartBeatRealKeys.forEach(realKey => {
2302
+ if (!streamIdRtcPlayerInfo[streamid].hasOwnProperty(realKey)) {
2303
+ streamIdRtcPlayerInfo[streamid][realKey] = [];
2304
+ }
2305
+ // if (streamIdRtcPlayerInfo[streamid].count > 0) {
2306
+ // streamIdRtcPlayerInfo[streamid][realKey] = util.toFixed(streamIdRtcPlayerInfo[streamid][realKey]/streamIdRtcPlayerInfo[streamid].count);
2307
+ // }
2308
+ });
2309
+ //获取拉流类型,后期可写为函数提出去
2310
+ if(streamIdRtcPlayerInfo1[streamid].audio_type && streamIdRtcPlayerInfo1[streamid].video_type) {
2311
+ streamIdRtcPlayerInfo1[streamid].stream_type = 'both';
2312
+ } else if(!streamIdRtcPlayerInfo1[streamid].audio_type && streamIdRtcPlayerInfo1[streamid].video_type) {
2313
+ streamIdRtcPlayerInfo1[streamid].stream_type = 'video';
2314
+ } else if(streamIdRtcPlayerInfo1[streamid].audio_type && !streamIdRtcPlayerInfo1[streamid].video_type) {
2315
+ streamIdRtcPlayerInfo1[streamid].stream_type = 'audio';
2316
+ } else {
2317
+ streamIdRtcPlayerInfo1[streamid].stream_type = 'none';
2318
+ }
2319
+ // console.log('hsghsghsg_type_type', streamIdRtcPlayerInfo1[streamid].stream_type);
2320
+
2321
+ pullInfo.push({
2322
+ streamid,
2323
+ // uid: util.getUidByStreamId(streamid),
2324
+ ...streamIdRtcPlayerInfo[streamid],
2325
+ pull_type: streamIdRtcPlayerInfo1[streamid].stream_type,
2326
+ volume: streamIdRtcPlayerInfo[streamid].volume.slice(0,streamIdRtcPlayerInfo[streamid].volume.length-1)
2327
+ });
2328
+ resetStreamIdRtcPlayerInfo(streamid);
2329
+ });
2330
+ if (isFirstHeartBeatReport) {
2331
+ try {
2332
+ //静音推流时过滤掉音频帧率和码率,上报为0;
2333
+ // if (!isNoticeMicVolumeZego) {
2334
+ // heartBeatDataReportObj['audio_fps'] = [];
2335
+ // heartBeatDataReportObj['audio_bitrate'] = [];
2336
+ // }
2337
+
2338
+ //获取推流类型,后期可写为函数提出去
2339
+ if(zbztsdk.deviceStatus.camera && zbztsdk.deviceStatus.microphone) {
2340
+ zbztsdk.deviceStatus.stream_type = 'both';
2341
+ } else if(!zbztsdk.deviceStatus.camera && zbztsdk.deviceStatus.microphone) {
2342
+ zbztsdk.deviceStatus.stream_type = 'audio';
2343
+ } else if(zbztsdk.deviceStatus.camera && !zbztsdk.deviceStatus.microphone) {
2344
+ zbztsdk.deviceStatus.stream_type = 'video';
2345
+ } else {
2346
+ zbztsdk.deviceStatus.stream_type = 'none';
2347
+ };
2348
+ // console.log('push_type222',zbztsdk.deviceStatus,zbztsdk.deviceStatus.stream_type);
2349
+ defaultApi.writeLog(`push_type_talrtc,camera: ${zbztsdk.deviceStatus.camera},microphone: ${zbztsdk.deviceStatus.microphone},type: ${zbztsdk.deviceStatus.stream_type},a_fps: ${dataTalrtcCapture.fps}, a_bit: ${dataTalrtcCapture.audioBitrate}, v_fps: ${dataTalrtcCapture.fps}, v_bit: ${dataTalrtcCapture.videoBitrate}`);
2350
+ // if (window.zbztAVSDK_init_params.zego.role === 'teacher') {
2351
+ dataReport.heartbeat({
2352
+ ...{...heartBeatDataReportObj, push_type: zbztsdk.deviceStatus.stream_type, volume: heartBeatDataReportObj.volume.slice(0,heartBeatDataReportObj.volume.length-1)},
2353
+ // pull_info: JSON.stringify(pullInfo),
2354
+ pull_info: pullInfo,
2355
+ // cpu_rate: util.toFixed(cpuRate/rateCount),
2356
+ // mem_rate: util.toFixed(memRate/rateCount),
2357
+ });
2358
+ // } else {
2359
+ // dataReport.heartbeat({
2360
+ // ...heartBeatDataReportObj,
2361
+ // pull_info: JSON.stringify(pullInfo),
2362
+ // cpu_rate: util.toFixed(cpuRate/rateCount),
2363
+ // mem_rate: util.toFixed(memRate/rateCount),
2364
+ // app_cpu: util.toFixed(appCpuRate/rateCount),
2365
+ // app_mem: util.toFixed(appMemUsed/rateCount),
2366
+ // video_mem: gpus
2367
+ // });
2368
+ // }
2369
+ dataReport.localNetworkQuality({
2370
+ code: qualityLocal,
2371
+ });
2372
+ dataReport.remoteNetworkQuality({
2373
+ code: qualityRemote,
2374
+ });
2375
+ } catch (e) {
2376
+ console.log(e);
2377
+ }
2378
+ }
2379
+ resetHeartBeatDataReportObj();
2380
+ // cpuRate = 0;
2381
+ // memRate = 0;
2382
+ // appCpuRate = 0;
2383
+ // appMemUsed = 0;
2384
+
2385
+ // clearInterval(rateTimer);
2386
+ // }
2387
+ // }, 10 * 1000);
2388
+ };
2389
+
2390
+ const heartBeatDataReport = (type) => {
2391
+ try {
2392
+ if (type === 'start' && !heartBeatDataReportTimer) {
2393
+ console.log('start heart beat report');
2394
+ _heartBeatDataReport();
2395
+ heartBeatDataReportTimer = setInterval(() => {
2396
+ _heartBeatDataReport();
2397
+ }, 30 * 1000);
2398
+ }
2399
+ if (type === 'stop') {
2400
+ clearInterval(heartBeatDataReportTimer);
2401
+ heartBeatDataReportTimer = null;
2402
+ }
2403
+ } catch (error) {
2404
+ console.log(error);
2405
+ }
2406
+ };
2407
+ const lastStreamReportTimestamps = {};
2408
+
2409
+ const heartBeatDataReportCalc = (name, _data) => {
2410
+ let _d = JSON.parse(_data.stats);
2411
+
2412
+ if (lastStreamReportTimestamps[_d.streamId] && Date.now() - lastStreamReportTimestamps[_d.streamId] < 4999) {
2413
+ return;
2414
+ } else {
2415
+ lastStreamReportTimestamps[_d.streamId] = Date.now();
2416
+ }
2417
+ // 拉流
2418
+ const pullKeys = ['fps', 'videoBitrate', 'afps', 'audioBitrate'];
2419
+ if (name === 'onRemoteStatistics') {
2420
+ if (streamIdRtcPlayerInfo && streamIdRtcPlayerInfo.hasOwnProperty(_d.streamId)) {
2421
+ let streamid = _d.streamId;
2422
+ let isReport = true;
2423
+ // streamIdRtcPlayerInfo[streamid].count++;
2424
+ heartBeatRealKeys.forEach((realKey, index) => {
2425
+ if (_d.hasOwnProperty(pullKeys[index])) {
2426
+ if (streamIdRtcPlayerInfo[streamid][realKey] === undefined) {
2427
+ streamIdRtcPlayerInfo[streamid][realKey] = [];
2428
+ isReport = false;
2429
+ }
2430
+ // streamIdRtcPlayerInfo[streamid][realKey].push(parseFloat(parseInt(item[pullKeys[index]])));
2431
+ }
2432
+ });
2433
+ if (isReport) {
2434
+ let audio_fps_talrtc_pull = 0;
2435
+ let audio_bitrate_talrtc_pull = 0;
2436
+ let video_fps_talrtc_pull = 0;
2437
+ let video_bitrate_talrtc_pull = 0;
2438
+ if(streamIdRtcPlayerInfo1[streamid].audio_type && streamIdRtcPlayerInfo1[streamid].video_type) {
2439
+ audio_fps_talrtc_pull = parseFloat(parseInt(_d.afps));
2440
+ audio_bitrate_talrtc_pull = parseFloat(parseInt(_d.audioBitrate));
2441
+ video_fps_talrtc_pull = parseFloat(parseInt(_d.fps));
2442
+ video_bitrate_talrtc_pull = parseFloat(parseInt(_d.videoBitrate));
2443
+ } else if(!streamIdRtcPlayerInfo1[streamid].audio_type && streamIdRtcPlayerInfo1[streamid].video_type) {
2444
+ video_fps_talrtc_pull = parseFloat(parseInt(_d.fps));
2445
+ video_bitrate_talrtc_pull = parseFloat(parseInt(_d.videoBitrate));
2446
+ } else if(streamIdRtcPlayerInfo1[streamid].audio_type && !streamIdRtcPlayerInfo1[streamid].video_type) {
2447
+ audio_fps_talrtc_pull = parseFloat(parseInt(_d.afps));
2448
+ audio_bitrate_talrtc_pull = parseFloat(parseInt(_d.audioBitrate));
2449
+ }
2450
+ streamIdRtcPlayerInfo[streamid].audio_fps.push(audio_fps_talrtc_pull);
2451
+ streamIdRtcPlayerInfo[streamid].audio_bitrate.push(audio_bitrate_talrtc_pull);
2452
+ streamIdRtcPlayerInfo[streamid].video_fps.push(video_fps_talrtc_pull);
2453
+ streamIdRtcPlayerInfo[streamid].video_bitrate.push(video_bitrate_talrtc_pull);
2454
+ streamIdRtcPlayerInfo[streamid].pull_loss.push(_d.packetLoss);
2455
+ streamIdRtcPlayerInfo[streamid].pull_delay.push(_d.rtt);
2456
+
2457
+ streamIdRtcPlayerInfo[streamid].ctime.push(Math.round((new Date().getTime()+dataReport.timestamp)/1000));
2458
+ streamIdRtcPlayerInfo[streamid].video_ifg += _d.videoBlockRate;
2459
+ streamIdRtcPlayerInfo[streamid].audio_ifg += _d.audioBlockRate;
2460
+ // console.log('hsg_tpull_keys',JSON.parse(JSON.stringify(streamIdRtcPlayerInfo[streamid])),_d.avTimestampDiff);
2461
+ }
2462
+ }
2463
+ }
2464
+ // 推流
2465
+ const pushKeys = ['fps', 'videoBitrate', 'afps', 'audioBitrate'];
2466
+ if (name === 'onLocalStatistics') {
2467
+ // console.log('hsgmzk',_d);
2468
+ // heartBeatDataReportObj.count++;
2469
+ // heartBeatRealKeys.forEach((realKey, index) => {
2470
+ // if (heartBeatDataReportObj.hasOwnProperty(realKey) && _d.hasOwnProperty(pushKeys[index])) {
2471
+ // heartBeatDataReportObj[realKey].push(parseFloat(parseInt(_d[pushKeys[index]])));
2472
+ // }
2473
+ // });
2474
+ let audio_fps_talrtc_push = 0;
2475
+ let audio_bitrate_talrtc_push = 0;
2476
+ let video_fps_talrtc_push = 0;
2477
+ let video_bitrate_talrtc_push = 0;
2478
+ dataTalrtcCapture =_d;
2479
+
2480
+ if(zbztsdk.deviceStatus.camera && zbztsdk.deviceStatus.microphone) {
2481
+ audio_fps_talrtc_push = parseFloat(parseInt(_d.afps));
2482
+ audio_bitrate_talrtc_push = parseFloat(parseInt(_d.audioBitrate));
2483
+ video_fps_talrtc_push = parseFloat(parseInt(_d.fps));
2484
+ video_bitrate_talrtc_push= parseFloat(parseInt(_d.videoBitrate));
2485
+ } else if(!zbztsdk.deviceStatus.camera && zbztsdk.deviceStatus.microphone) {
2486
+ audio_fps_talrtc_push = parseFloat(parseInt(_d.afps));
2487
+ audio_bitrate_talrtc_push = parseFloat(parseInt(_d.audioBitrate));
2488
+ } else if(zbztsdk.deviceStatus.camera && !zbztsdk.deviceStatus.microphone) {
2489
+ video_fps_talrtc_push = parseFloat(parseInt(_d.fps));
2490
+ video_bitrate_talrtc_push = parseFloat(parseInt(_d.videoBitrate));
2491
+ }
2492
+ heartBeatDataReportObj.audio_fps.push(audio_fps_talrtc_push);
2493
+ heartBeatDataReportObj.audio_bitrate.push(audio_bitrate_talrtc_push);
2494
+ heartBeatDataReportObj.video_fps.push(video_fps_talrtc_push);
2495
+ heartBeatDataReportObj.video_bitrate.push(video_bitrate_talrtc_push);
2496
+ heartBeatDataReportObj.push_loss.push(_d.packetLoss);
2497
+ heartBeatDataReportObj.push_delay.push(_d.rtt);
2498
+ heartBeatDataReportObj.ctime.push(Math.round((new Date().getTime()+dataReport.timestamp)/1000));
2499
+ }
2500
+ };
2501
+
2502
+ //推流字段
2503
+ const resetHeartBeatDataReportObj = () => {
2504
+ console.log('resetHeartBeatDataReportObj重置');
2505
+ heartBeatDataReportObj = {
2506
+ ctime: [],
2507
+ push_type: 'none',
2508
+ video_fps: [],
2509
+ video_bitrate: [],
2510
+ audio_fps: [],
2511
+ audio_bitrate: [],
2512
+ push_loss: [],
2513
+ push_delay: [],
2514
+ volume: ''
2515
+ };
2516
+ };
2517
+
2518
+ resetHeartBeatDataReportObj();
2519
+ //记录拉流类型,用作数据上报
2520
+ const resetStreamIdRtcPlayerInfo1 = (streamId) => {
2521
+ streamIdRtcPlayerInfo1[streamId] = {
2522
+ audio_type: false,
2523
+ video_type: false,
2524
+ stream_type: 'none'
2525
+ };
2526
+ // console.log('hsgshgs_heartbeat',streamIdRtcPlayerInfo1);
2527
+ };
2528
+ //拉流字段
2529
+ const resetStreamIdRtcPlayerInfo = (streamId) => {
2530
+ console.log('reset stream info ----------', streamId);
2531
+ streamIdRtcPlayerInfo[streamId] = {
2532
+ pull_uid: util.getUidByStreamId(streamId),
2533
+ streamid: streamId,
2534
+ ctime: [],
2535
+ pull_type: streamIdRtcPlayerInfo1[streamId].stream_type,
2536
+ volume: '',
2537
+ // 平均值
2538
+ // count: 0,
2539
+ // video_fps: 0,
2540
+ // video_bitrate: 0,
2541
+ // audio_fps: 0,
2542
+ // audio_bitrate: 0,
2543
+ video_fps: [],
2544
+ video_bitrate: [],
2545
+ audio_fps: [],
2546
+ audio_bitrate: [],
2547
+ pull_loss: [],
2548
+ pull_delay: [],
2549
+ //音画不同步字段
2550
+ avtimestampdiff: [],
2551
+ // 累加
2552
+ audio_ifg: 0,
2553
+ video_ifg: 0
2554
+ };
2555
+
2556
+ console.log('reset stream info ----------', streamId, streamIdRtcPlayerInfo[streamId]);
2557
+ };
2558
+
2559
+ export default {
2560
+ init,
2561
+ setCameraCaptureResolution,
2562
+ setCameraEncodeResolution,
2563
+ setCameraEncodeFps, // 未实现调用
2564
+ setCameraEncodeBitrate,
2565
+ getCameraResolution,
2566
+ getMicrophoneDeviceList,
2567
+ setMicrophoneDevice,
2568
+ openOrCloseMicrophone,
2569
+ getCurrentMicrophoneVolume,
2570
+ setCurrentMicrophoneVolume,
2571
+ getCameraDeviceList,
2572
+ setCameraDevice,
2573
+ openOrCloseCamera,
2574
+ getSpeakerDeviceList,
2575
+ setSpeakerDevice,
2576
+ getCurrentSpeakerDevice,
2577
+ getCurrentSpeakerVolume,
2578
+ setCurrentSpeakerVolume,
2579
+ setSpeakerDeviceMute,
2580
+ muteRemoteAudio,
2581
+ muteRemoteVideo,
2582
+ getSpeakerSimpleVolume,
2583
+ setSpeakerSimpleVolume,
2584
+ setSpeakerSimpleMute,
2585
+ startLocalOrRemotePreview,
2586
+ enableAudioSpeakerCapture,
2587
+ startPush,
2588
+ stopPush,
2589
+ startPlay,
2590
+ stopPlay,
2591
+ initPullFlow,
2592
+ stopPlayAll,
2593
+ playerSnapShot,
2594
+ changePullFlow,
2595
+ sendSEIMsg,
2596
+ loadCollectionInputEntry2,
2597
+ controlCdnStreaming, // addPublishRtmpStreamUrl or removePublishStreamUrl
2598
+ leaveRoom,
2599
+ destroyEngine,
2600
+ unloadTalrtc,
2601
+ muteLocalVideo,
2602
+ muteLocalAudio,
2603
+ pullAudioFlow,
2604
+ hasStream,
2605
+ teacherStartLinkMic,
2606
+ teacherStopLinkMic,
2607
+ setMirrorStatus,
2608
+ setPlayViewMirror,
2609
+ setAudioAuxSource,
2610
+ setAudioType,
2611
+ startAudioExCapture,
2612
+ startMultiScreen,
2613
+ setAudioMixMode,
2614
+ startRecord,
2615
+ stopRecord,
2616
+ startCapture,
2617
+ stopCapture,
2618
+ getChannelIndex,
2619
+ getSDKVersion
2620
+ };