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.
- package/.babelrc +8 -0
- package/.editorconfig +13 -0
- package/.eslintrc.js +29 -0
- package/CHANGELOG.md +16 -0
- package/README.md +32 -0
- package/dist/zbzt-live-sdk.cjs.js +51 -0
- package/dist/zbzt-live-sdk.esm.js +51 -0
- package/dist/zbzt-live-sdk.umd.js +52 -0
- package/dist/zbzt-live-sdk.umd.js.map +1 -0
- package/example/app.js +133 -0
- package/example/bootstrap-3.4.1/css/bootstrap-theme.css +587 -0
- package/example/bootstrap-3.4.1/css/bootstrap-theme.css.map +1 -0
- package/example/bootstrap-3.4.1/css/bootstrap-theme.min.css +6 -0
- package/example/bootstrap-3.4.1/css/bootstrap-theme.min.css.map +1 -0
- package/example/bootstrap-3.4.1/css/bootstrap.css +6834 -0
- package/example/bootstrap-3.4.1/css/bootstrap.css.map +1 -0
- package/example/bootstrap-3.4.1/css/bootstrap.min.css +6 -0
- package/example/bootstrap-3.4.1/css/bootstrap.min.css.map +1 -0
- package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.eot +0 -0
- package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.svg +288 -0
- package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.ttf +0 -0
- package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.woff +0 -0
- package/example/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.woff2 +0 -0
- package/example/bootstrap-3.4.1/js/bootstrap.js +2580 -0
- package/example/bootstrap-3.4.1/js/bootstrap.min.js +6 -0
- package/example/bootstrap-3.4.1/js/npm.js +13 -0
- package/example/css/style.css +18 -0
- package/example/index.html +59 -0
- package/example/js/jquery-3.7.1.min.js +2 -0
- package/example/js/utils.js +25 -0
- package/example/js/variables.js +14 -0
- package/example/js/zegoApi.js +229 -0
- package/example/style.css +25 -0
- package/example/test.html +100 -0
- package/package.json +60 -0
- package/release.js +33 -0
- package/rollup-plugin-http.js +49 -0
- package/src/channel/getSendMsgParams.js +66 -0
- package/src/channel/index.js +135 -0
- package/src/channel/pomelo/index.js +182 -0
- package/src/channel/pomelo/latestQueue.js +150 -0
- package/src/channel/pomelo/polemo.js +730 -0
- package/src/channel/pomelo/util.js +54 -0
- package/src/channel/sdk-cb.js +73 -0
- package/src/channel/stream-msg.js +97 -0
- package/src/channel/zbzt/index.js +74 -0
- package/src/channel/zbzt/interactWithChannel.js +4 -0
- package/src/channel/zbzt/interactWithChannelControl.js +1568 -0
- package/src/channel/zbzt/interactWithChannelEntry.js +318 -0
- package/src/config/config.js +226 -0
- package/src/default/base.js +71 -0
- package/src/default/extend.js +36 -0
- package/src/default/index.js +10 -0
- package/src/live/base.js +43 -0
- package/src/live/call-method.js +10 -0
- package/src/live/extend.js +53 -0
- package/src/live/index.js +10 -0
- package/src/network/api.js +56 -0
- package/src/network/commonFetch.js +66 -0
- package/src/network/dataReport.js +448 -0
- package/src/notice.js +418 -0
- package/src/tool/base.js +74 -0
- package/src/tool/call-method.js +10 -0
- package/src/tool/extend.js +42 -0
- package/src/tool/index.js +10 -0
- package/src/util/bridge.js +87 -0
- package/src/util/bridge1.js +46 -0
- package/src/util/dict.js +51 -0
- package/src/util/sessionStorage.js +29 -0
- package/src/util/sha256.js +483 -0
- package/src/util/util.js +329 -0
- package/src/zbzt-av-sdk/default-sdk.js +192 -0
- package/src/zbzt-av-sdk/device.js +86 -0
- package/src/zbzt-av-sdk/rtc-sdk.js +2854 -0
- package/src/zbzt-av-sdk/talrtc-sdk.js +2620 -0
- package/src/zbzt-av-sdk/trtc-sdk.js +1802 -0
- package/src/zbzt-av-sdk/zbzt-av-sdk.js +2121 -0
- package/src/zbzt-av-sdk/zego-sdk.js +1718 -0
- package/src/zbzt-av-sdk/zego-sdk.js.bak +3133 -0
- package/src/zbzt-live-sdk.js +1484 -0
|
@@ -0,0 +1,1718 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @File: Zego 音视频 SDK
|
|
3
|
+
* @Author: xuyuanrui
|
|
4
|
+
* @Email: raywhbxyr@163.com
|
|
5
|
+
* @Date: 2024-01-26 10:14:41
|
|
6
|
+
**/
|
|
7
|
+
import ZegoExpressEngine from 'zego-express-engine-webrtc';
|
|
8
|
+
|
|
9
|
+
import dataReport from '../network/dataReport.js';
|
|
10
|
+
import defaultApi from '../default';
|
|
11
|
+
import util from '../util/util';
|
|
12
|
+
import NOTICE from '../notice';
|
|
13
|
+
import { deviceListReport } from './device.js';
|
|
14
|
+
import { getZegoGateway } from '../config/config.js';
|
|
15
|
+
import commonFetch from '../network/commonFetch.js';
|
|
16
|
+
|
|
17
|
+
// 留存初始化参数 initParams;
|
|
18
|
+
let initParams = {};
|
|
19
|
+
// 创摄像头流的参数, 维持原相关set约束的调用方式
|
|
20
|
+
let cameraConstraints = {
|
|
21
|
+
camera: {
|
|
22
|
+
audio: {
|
|
23
|
+
// input,
|
|
24
|
+
// ANS, 降噪
|
|
25
|
+
// AGC, 增益
|
|
26
|
+
// AEC, 回声消除
|
|
27
|
+
},
|
|
28
|
+
video: {
|
|
29
|
+
// input, // 采集设备id
|
|
30
|
+
quality: 4,
|
|
31
|
+
width: initParams.encodedResolutionWidth,
|
|
32
|
+
height: initParams.encodedResolutionHeight,
|
|
33
|
+
frameRate: initParams.encodeCaptureFps,
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
videoBitrate: initParams.encodeCaptureBitrate/1000,
|
|
37
|
+
audioBitrate: 48,
|
|
38
|
+
captureView: null,
|
|
39
|
+
// autoPlay: true,
|
|
40
|
+
};
|
|
41
|
+
let screenConstraints = {
|
|
42
|
+
videoBitrate: 800,
|
|
43
|
+
captureView: null,
|
|
44
|
+
// autoPlay: true,
|
|
45
|
+
screen: {
|
|
46
|
+
audio: false,
|
|
47
|
+
video: {
|
|
48
|
+
quality: 4,
|
|
49
|
+
frameRate: 15,
|
|
50
|
+
width: 960,
|
|
51
|
+
height: 540
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
// enableCamera、enableMic
|
|
56
|
+
let hasCamera = true;
|
|
57
|
+
let hasMicrophone = true;
|
|
58
|
+
/**
|
|
59
|
+
* zegoWebExpressEngine 实例
|
|
60
|
+
* @type { ZegoExpressEngine.ZegoExpressEngine | null }
|
|
61
|
+
*/
|
|
62
|
+
let zg = null;
|
|
63
|
+
// 声浪回调周期
|
|
64
|
+
let soundLevelMonitorCycle = 1000;
|
|
65
|
+
// 推流id
|
|
66
|
+
let localStreamId;
|
|
67
|
+
/**
|
|
68
|
+
* @type { import('zego-express-engine-webrtc/sdk/code/zh/ZegoLocalStream.web').default | null }
|
|
69
|
+
*/
|
|
70
|
+
let localStream;
|
|
71
|
+
let screenStreamId = '';
|
|
72
|
+
/**
|
|
73
|
+
* @type { import('zego-express-engine-webrtc/sdk/code/zh/ZegoLocalStream.web').default | null }
|
|
74
|
+
*/
|
|
75
|
+
let screenStream;
|
|
76
|
+
//记录当前角色
|
|
77
|
+
let currentRole = '';
|
|
78
|
+
//记录当前课态类型:小组课=0/小班课=1
|
|
79
|
+
let currentClassMode = null;
|
|
80
|
+
//记录当前rtmp推流sdk类型
|
|
81
|
+
let currentGroupSdkType = ''; // ???
|
|
82
|
+
// 维护的一份当前正在使用的音频设备的 deviceId 的列表
|
|
83
|
+
let usingAudioDeviceId = {
|
|
84
|
+
speaker: '',
|
|
85
|
+
microphone: ''
|
|
86
|
+
};
|
|
87
|
+
// // 维护的一份拉流的 streamId 与本地预览通道的映射表
|
|
88
|
+
let streamIdToPreviewId = {};
|
|
89
|
+
let previewIdToStreamId = {};
|
|
90
|
+
let streamIdToStream = {}; // 维护一份流id跟播放器的映射关系type: { streamId: stream }
|
|
91
|
+
let streamIdToStreamView = {}; // 维护一份流id跟播放器的映射关系type: { streamid: remoteview }
|
|
92
|
+
// 拉流的播放通道初始化从 0 开始依次递增至44(共45路流),-1 为推流的本地视频预览
|
|
93
|
+
const uiChnIndexs = new Array(48).fill(0).map((a, b) => b).reverse();
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
// WEB没有获取系统音量,维护麦克风音量、
|
|
97
|
+
let microphoneVolume = 100;
|
|
98
|
+
let speakerVolume = 100;
|
|
99
|
+
|
|
100
|
+
//静音推流时,音量值是否上抛上层标志 false=没有声音不往上层通知/true=有声音有上层通知
|
|
101
|
+
let isNoticeMicVolumeZego = false;
|
|
102
|
+
// 心跳
|
|
103
|
+
let heartBeatDataReportObj = {};
|
|
104
|
+
let heartBeatDataReportTimer = null;
|
|
105
|
+
let isFirstHeartBeatReport = false;
|
|
106
|
+
let streamIdRtcPlayerInfo = {}; // 埋点数据格式
|
|
107
|
+
let streamIdRtcPlayerInfo1 = {}; // 埋点数据格式
|
|
108
|
+
let currStreamIdRtcPlayerInfo;
|
|
109
|
+
const heartBeatRealKeys = ['video_fps', 'video_bitrate', 'audio_fps', 'audio_bitrate'];
|
|
110
|
+
|
|
111
|
+
//记录底层推流回调的值
|
|
112
|
+
let dataZegoCapture = {};
|
|
113
|
+
|
|
114
|
+
let hasLoginChannel = 0;
|
|
115
|
+
// TODO 测试代码,token接入完成后删除
|
|
116
|
+
async function getToken(appId, userId) {
|
|
117
|
+
const querys = {
|
|
118
|
+
appId,
|
|
119
|
+
userId,
|
|
120
|
+
};
|
|
121
|
+
return commonFetch('https://dev-webrtc.weclassroom.com/webrtc/zegotoken', querys, 'GET');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function init(args) {
|
|
125
|
+
// args.appId = 1739272706;
|
|
126
|
+
// args.server = 'wss://webliveroom-test.zego.im/ws';
|
|
127
|
+
// args.appKey = 'eyJ2ZXIiOjEsImhhc2giOiI3ZGRmMjMwZjRiYzYxNTNlNGViN2U2Zjc4M2Q1N2Y0NiIsIm5vbmNlIjoiMjgyMWEyYWE5YWU0NDM3MWY1NGI2NWYzMDk0OWNmYWYiLCJleHBpcmVkIjoxNzA5NDMxODkwfQ==';
|
|
128
|
+
args.server = getZegoGateway();
|
|
129
|
+
args.appKey = await getToken(args.appId, args.userId);
|
|
130
|
+
console.warn('[初始化]', args);
|
|
131
|
+
// NOTE 1. 参数保留
|
|
132
|
+
initParams = Object.assign({}, args);
|
|
133
|
+
localStreamId = initParams.streamId;
|
|
134
|
+
screenStreamId = `${args.institutionId}_${args.roomId}_${args.userId}_${args.live_id}_1`;
|
|
135
|
+
currentRole = initParams.role;
|
|
136
|
+
currentClassMode = initParams.classMode;
|
|
137
|
+
currentGroupSdkType = initParams.sdkTypeGroup;
|
|
138
|
+
// NOTE 2. 加载扩展插件
|
|
139
|
+
// NOTE 此处没用到Web拓展能力
|
|
140
|
+
// NOTE 3. 初始化ZegoWebExpressEngine & 登录房间
|
|
141
|
+
await startEngine(initParams);
|
|
142
|
+
// NOTE 4. 注册回调 注意: 渲染相关的事件在streamView上管理
|
|
143
|
+
addListener();
|
|
144
|
+
// NOTE 5. 实例化zego实例之后的动作
|
|
145
|
+
await afterInitSDK(initParams);
|
|
146
|
+
// NOTE 6. 创流参数保留
|
|
147
|
+
if (initParams.noiseSuppressMode == -2) {
|
|
148
|
+
defaultApi.writeLog(`noiseSuppressMode 关闭噪声消除 ${initParams.noiseSuppressMod}`);
|
|
149
|
+
await setEnableNoiseSuppress(false);
|
|
150
|
+
} else if (initParams.noiseSuppressMode == -1) {
|
|
151
|
+
defaultApi.writeLog(`noiseSuppressMode 由底层进行配置,js层不进行配置 ${initParams.noiseSuppressMode}`);
|
|
152
|
+
} else {
|
|
153
|
+
await setEnableNoiseSuppress(true);
|
|
154
|
+
};
|
|
155
|
+
//aecMode为-1是关闭回音消除,云控下传
|
|
156
|
+
if (initParams.aecMode == -2) {
|
|
157
|
+
defaultApi.writeLog(`aecMode 关闭回音消除 ${initParams.aecMode}`);
|
|
158
|
+
await setEnableAEC(false);
|
|
159
|
+
} else if (initParams.aecMode == -1) {
|
|
160
|
+
defaultApi.writeLog(`aecMode 由底层进行配置,js层不进行配置 ${initParams.aecMode}`);
|
|
161
|
+
} else {
|
|
162
|
+
defaultApi.writeLog(`aecMode 启动回音消除,模式为: ${initParams.aecMode}`);
|
|
163
|
+
await setEnableAEC(true);
|
|
164
|
+
};
|
|
165
|
+
await setVideoBitrate(initParams.encodeCaptureBitrate);
|
|
166
|
+
await setAudioBitrate(initParams.encodeCaptureBitrate);
|
|
167
|
+
await setVideoFPS(initParams.encodeCaptureFps);
|
|
168
|
+
// NOTE WEB没有分开设置
|
|
169
|
+
// await setVideoCaptureResolution(initParams.previewResolutionWidth, initParams.previewResolutionHeight);
|
|
170
|
+
await setVideoEncodeResolution(initParams.encodedResolutionWidth, initParams.encodedResolutionHeight);
|
|
171
|
+
window.current_sdk_type = 'zego';
|
|
172
|
+
defaultApi.writeLog('zego init finished current_sdk_type : zego');
|
|
173
|
+
}
|
|
174
|
+
async function startEngine(args) {
|
|
175
|
+
if(!zg){
|
|
176
|
+
zg = new ZegoExpressEngine.ZegoExpressEngine(args.appId, args.server);
|
|
177
|
+
}
|
|
178
|
+
zg.setDebugVerbose(false);
|
|
179
|
+
zg.setLogConfig({ logLevel: 'disable' });
|
|
180
|
+
// NOTE 开启多房间
|
|
181
|
+
// zg.enableMultiRoom(true); // 开多房间,推流需要指定房间号
|
|
182
|
+
// NOTE web没有onInitSDK, 登录房间放在注册事件之后
|
|
183
|
+
// deviceCheckerInitSDK 区别设备检测
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function afterInitSDK(args) {
|
|
187
|
+
// NOTE 1. 设置默认设备
|
|
188
|
+
const usedDevices = window.zbyAVSDK_device_checker_init;
|
|
189
|
+
const { devices } = args;
|
|
190
|
+
const _devices = {
|
|
191
|
+
camera: (devices && devices.camera) || (usedDevices && usedDevices.camera && usedDevices.camera.use) || '',
|
|
192
|
+
microphone: (devices && devices.microphone) || (usedDevices && usedDevices.microphone && usedDevices.microphone.use) || '',
|
|
193
|
+
speaker: (devices && devices.speaker) || (usedDevices && usedDevices.speaker && usedDevices.speaker.use) || ''
|
|
194
|
+
};
|
|
195
|
+
await setDefaultDevice(_devices, 'default');
|
|
196
|
+
// NOTE 2. 登录房间
|
|
197
|
+
const { roomId, appKey, userId, userName } = args;
|
|
198
|
+
await zg.loginRoom(roomId, appKey, { userID: userId, userName }, { userUpdate: true });
|
|
199
|
+
// NOTE 3. 设置质量回调周期 web 无此接口,回调周期写死3s
|
|
200
|
+
// NOTE 4. 设置声浪回调周期;
|
|
201
|
+
setSoundLevelMonitorCycle(1000);
|
|
202
|
+
// NOTE 5. 设置SEI开关
|
|
203
|
+
setMediaSideFlags();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function destroyEngine() {
|
|
207
|
+
zg.destroyEngine();
|
|
208
|
+
}
|
|
209
|
+
function setMediaSideFlags() {
|
|
210
|
+
// SEI开关 web跟native模式不一样,此接口需调整
|
|
211
|
+
// NOTE 当前需求不用此功能
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* @function 设置默认的硬件设备,包括摄像头、麦克风以及扬声器
|
|
215
|
+
* @return Promise
|
|
216
|
+
*/
|
|
217
|
+
async function setDefaultDevice(devices, operationType) {
|
|
218
|
+
console.warn('[设置默认设备]', devices, operationType);
|
|
219
|
+
// 设置默认的摄像头
|
|
220
|
+
if (devices && devices.camera) {
|
|
221
|
+
if (zbyAVSDK_device_checker_init.camera.list.length == 0) {
|
|
222
|
+
await getVideoDeviceList();
|
|
223
|
+
}
|
|
224
|
+
await setVideoDevice({ deviceId: devices.camera, operationType: `${operationType}_1` });
|
|
225
|
+
} else {
|
|
226
|
+
const cameraData = await getVideoDeviceList();
|
|
227
|
+
if (cameraData.length) {
|
|
228
|
+
let hasSetCamera = false;
|
|
229
|
+
for (let item of cameraData) {
|
|
230
|
+
if (item.isDefault) {
|
|
231
|
+
await setVideoDevice({ deviceId: item.deviceId, operationType: `${operationType}_2` });
|
|
232
|
+
hasSetCamera = true;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!hasSetCamera) {
|
|
237
|
+
await setVideoDevice({ deviceId: cameraData[0].deviceId, operationType: `${operationType}_3` });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// 设置默认的麦克风
|
|
242
|
+
if (devices && devices.microphone) {
|
|
243
|
+
if (zbyAVSDK_device_checker_init.microphone.list.length == 0) {
|
|
244
|
+
await getMicrophoneDeviceList();
|
|
245
|
+
}
|
|
246
|
+
await setMicrophoneDevice({ deviceId: devices.microphone, operationType: `${operationType}_1` });
|
|
247
|
+
} else {
|
|
248
|
+
const microPhoneData = await getMicrophoneDeviceList();
|
|
249
|
+
if (microPhoneData.length) {
|
|
250
|
+
let hasSetMicrophone = false;
|
|
251
|
+
for (let item of microPhoneData) {
|
|
252
|
+
if (item.isDefault) {
|
|
253
|
+
await setMicrophoneDevice({ deviceId: item.deviceId, operationType: `${operationType}_2` });
|
|
254
|
+
hasSetMicrophone = true;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (!hasSetMicrophone) {
|
|
259
|
+
await setMicrophoneDevice({ deviceId: microPhoneData[0].deviceId, operationType: `${operationType}_3` });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// 设置默认的扬声器
|
|
264
|
+
if (devices && devices.speaker) {
|
|
265
|
+
await setSpeakerDevice({ deviceId: devices.speaker, operationType: `${operationType}_1` });
|
|
266
|
+
} else {
|
|
267
|
+
const speakerData = await getSpeakerDeviceList();
|
|
268
|
+
if (speakerData.length) {
|
|
269
|
+
let hasSetSpeaker = false;
|
|
270
|
+
for (let item of speakerData) {
|
|
271
|
+
if (item.isDefault) {
|
|
272
|
+
await setSpeakerDevice({ deviceId: item.deviceId, operationType: `${operationType}_2` });
|
|
273
|
+
hasSetSpeaker = true;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (!hasSetSpeaker) {
|
|
278
|
+
await setSpeakerDevice({ deviceId: speakerData[0].deviceId, operationType: `${operationType}_3` });
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async function getVideoDeviceList() {
|
|
284
|
+
if(!zg) {
|
|
285
|
+
return Promise.resolve([]);
|
|
286
|
+
}
|
|
287
|
+
let videoListArr = await zg.getCameras();
|
|
288
|
+
let videoList = [];
|
|
289
|
+
for (let i = 0, len = videoListArr.length; i < len; i++) {
|
|
290
|
+
videoList.push({
|
|
291
|
+
deviceId: videoListArr[i].deviceID,
|
|
292
|
+
deviceName: videoListArr[i].deviceName,
|
|
293
|
+
isDefault: i === 0
|
|
294
|
+
});
|
|
295
|
+
deviceListReport.cameraList[videoListArr[i].deviceID] = videoListArr[i].deviceName;
|
|
296
|
+
}
|
|
297
|
+
if (!window.zbyAVSDK_device_checker_init) {
|
|
298
|
+
window.zbyAVSDK_device_checker_init = {};
|
|
299
|
+
}
|
|
300
|
+
if (!window.zbyAVSDK_device_checker_init.camera) {
|
|
301
|
+
window.zbyAVSDK_device_checker_init.camera = {};
|
|
302
|
+
}
|
|
303
|
+
window.zbyAVSDK_device_checker_init.camera.hasTest = true;
|
|
304
|
+
window.zbyAVSDK_device_checker_init.camera.list = videoList;
|
|
305
|
+
return videoList;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
async function setVideoDevice(args) {
|
|
309
|
+
let { deviceId, idx, operationType, deviceState, code, changedDeviceId } = args;
|
|
310
|
+
let deviceName = '';
|
|
311
|
+
let cameraData;
|
|
312
|
+
// NOTE 1. 没传deviceId, 设置默认设备
|
|
313
|
+
if (!deviceId) {
|
|
314
|
+
cameraData = await getVideoDeviceList();
|
|
315
|
+
if (cameraData.length) {
|
|
316
|
+
let hasGetCamare = false;
|
|
317
|
+
for (let item of cameraData) {
|
|
318
|
+
if (item.isDefault) {
|
|
319
|
+
deviceId = item.deviceId;
|
|
320
|
+
deviceName = item.deviceName;
|
|
321
|
+
hasGetCamare = true;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (!hasGetCamare) {
|
|
326
|
+
deviceId = cameraData[0].deviceId;
|
|
327
|
+
deviceName = cameraData[0].deviceName;
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
deviceId = '';
|
|
331
|
+
}
|
|
332
|
+
if (deviceId === '') {
|
|
333
|
+
NOTICE.noDevice({
|
|
334
|
+
deviceType: 'camera'
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
window.zbyAVSDK_device_checker_init.camera.use = deviceId;
|
|
339
|
+
window.zbyAVSDK_device_checker_init.camera.name = deviceListReport.cameraList[deviceId];
|
|
340
|
+
// NOTE 2. ???
|
|
341
|
+
try {
|
|
342
|
+
dataReport.setDevice({
|
|
343
|
+
device_type: 1,
|
|
344
|
+
device_id: deviceId,
|
|
345
|
+
device_name: deviceListReport.cameraList[deviceId],
|
|
346
|
+
operationType,
|
|
347
|
+
fore_state: operationType == 'hotPlug' ? deviceState + 1 : '-'
|
|
348
|
+
});
|
|
349
|
+
} catch (e) { };
|
|
350
|
+
// NOTE 3. 切摄像头
|
|
351
|
+
if(localStream && deviceId) {
|
|
352
|
+
await zg.useVideoDevice(localStream, deviceId);
|
|
353
|
+
}
|
|
354
|
+
// NOTE 4. 热插拔
|
|
355
|
+
if (operationType == 'hotPlug' || operationType == 'deviceError') {
|
|
356
|
+
if (!cameraData) {
|
|
357
|
+
cameraData = await getVideoDeviceList();
|
|
358
|
+
deviceName = deviceListReport.cameraList[deviceId];
|
|
359
|
+
}
|
|
360
|
+
NOTICE[operationType]({
|
|
361
|
+
deviceType: 'camera',
|
|
362
|
+
useDeviceId: deviceId,
|
|
363
|
+
useDeviceName: deviceName,
|
|
364
|
+
deviceList: cameraData,
|
|
365
|
+
messge: code,
|
|
366
|
+
deviceState,
|
|
367
|
+
changedDeviceId
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
NOTICE.useredCamera({
|
|
372
|
+
deviceId,
|
|
373
|
+
deviceName
|
|
374
|
+
});
|
|
375
|
+
} catch (e) { };
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* @function 开/关摄像头
|
|
379
|
+
* @param enable:Boolean false -> 关闭,true -> 打开,必选
|
|
380
|
+
* @param idx:Number 推流通道,可选,默认为 0
|
|
381
|
+
* @return Promise | void
|
|
382
|
+
*/
|
|
383
|
+
async function enableCamera(enable) {
|
|
384
|
+
defaultApi.writeLog(`avsdk ZEGO::enableCamera ${enable}`);
|
|
385
|
+
// NOTE WEB无预设接口,此接口可能在创流之前调用,所以增加保存字段
|
|
386
|
+
hasCamera = enable;
|
|
387
|
+
|
|
388
|
+
if(!localStream) {
|
|
389
|
+
await startPreview();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if(enable) {
|
|
393
|
+
await localStream.startCaptureCamera(cameraConstraints.camera.video);
|
|
394
|
+
await zg.updatePublishingStream(localStream, 0); // 更新类型,0为视频,1为音频,2为音视频
|
|
395
|
+
}else {
|
|
396
|
+
await localStream.stopCaptureVideo();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async function enableMic(enable) {
|
|
400
|
+
defaultApi.writeLog(`avsdk ZEGO::enableMic ${enable}`);
|
|
401
|
+
// NOTE WEB无预设接口,此接口可能在创流之前调用,所以增加保存字段
|
|
402
|
+
// NOTE 关联地方:创流渲染前
|
|
403
|
+
hasMicrophone = enable;
|
|
404
|
+
isNoticeMicVolumeZego = enable;
|
|
405
|
+
|
|
406
|
+
if(!localStream) {
|
|
407
|
+
await startPreview();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if(enable) {
|
|
411
|
+
await localStream.startCaptureMicrophone(cameraConstraints.camera.audio);
|
|
412
|
+
await zg.updatePublishingStream(localStream, 1); // 更新类型,0为视频,1为音频,2为音视频
|
|
413
|
+
}else {
|
|
414
|
+
await localStream.stopCaptureAudio();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
//设置采集声音
|
|
418
|
+
async function setAudioSpeakerCapture(bEnable) {
|
|
419
|
+
// NOTE native接口enableMixSystemPlayout是开启/关闭采集的
|
|
420
|
+
if(!localStream) { return; }
|
|
421
|
+
if(bEnable) {
|
|
422
|
+
localStream.startCaptureMicrophone();
|
|
423
|
+
// NOTE 用于更新处于推流中的ZegoLocalStream实例的音视轨
|
|
424
|
+
await zg.updatePublishingStream(localStream, 1); // 更新类型,0为视频,1为音频,2为音视频
|
|
425
|
+
}else {
|
|
426
|
+
localStream.stopCaptureAudio(); // 停止采集音频
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* @function 获取音频设备
|
|
432
|
+
* @param deviceType:Number 音频设备类型,0 -> 麦克风,1 -> 扬声器,必选
|
|
433
|
+
* @return Promise | void
|
|
434
|
+
*/
|
|
435
|
+
async function getAudioDeviceList(deviceType) {
|
|
436
|
+
if(deviceType) {
|
|
437
|
+
return await getSpeakerDeviceList();
|
|
438
|
+
}else {
|
|
439
|
+
return await getMicrophoneDeviceList();
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* @function 指定音频设备
|
|
444
|
+
* @param deviceType:Number 音频设备类型,0 -> 麦克风,1 -> 扬声器,必选
|
|
445
|
+
* @param deviceId:String 音频设备 id,必选
|
|
446
|
+
* @return Promise | void
|
|
447
|
+
*/
|
|
448
|
+
async function setAudioDevice(deviceType, deviceId) {
|
|
449
|
+
if (deviceType == 0) {
|
|
450
|
+
// NOTE 1. 设置麦克风设备
|
|
451
|
+
window.zbyAVSDK_device_checker_init.microphone.use = deviceId;
|
|
452
|
+
zg.useAudioDevice(localStream, deviceId);
|
|
453
|
+
} else {
|
|
454
|
+
// NOTE 2. 设置扬声器设备
|
|
455
|
+
window.zbyAVSDK_device_checker_init.speaker.use = deviceId;
|
|
456
|
+
Object.keys(streamIdToStreamView).forEach(streamId=> {
|
|
457
|
+
streamIdToStreamView[streamId].useAudioOutputDevice(deviceId);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async function getSpeakerDeviceList() {
|
|
463
|
+
if(!zg) {
|
|
464
|
+
return Promise.resolve([]);
|
|
465
|
+
}
|
|
466
|
+
let speakerListArr = await zg.getSpeakers();
|
|
467
|
+
let speakerList = [];
|
|
468
|
+
for (let i = 0, len = speakerListArr.length; i < len; i++) {
|
|
469
|
+
speakerList.push({
|
|
470
|
+
deviceId: speakerListArr[i].deviceID,
|
|
471
|
+
deviceName: speakerListArr[i].deviceName,
|
|
472
|
+
isDefault: i === 0
|
|
473
|
+
});
|
|
474
|
+
deviceListReport.speakerList[speakerListArr[i].deviceID] = speakerListArr[i].deviceName;
|
|
475
|
+
}
|
|
476
|
+
if (!window.zbyAVSDK_device_checker_init) {
|
|
477
|
+
window.zbyAVSDK_device_checker_init = {};
|
|
478
|
+
}
|
|
479
|
+
if (!window.zbyAVSDK_device_checker_init.speaker) {
|
|
480
|
+
window.zbyAVSDK_device_checker_init.speaker = {};
|
|
481
|
+
}
|
|
482
|
+
window.zbyAVSDK_device_checker_init.speaker.hasTest = true;
|
|
483
|
+
window.zbyAVSDK_device_checker_init.speaker.list = speakerList;
|
|
484
|
+
return speakerList;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* @function 指定扬声器
|
|
488
|
+
* @param deviceId:String 扬声器 id,必选
|
|
489
|
+
* @param operationType:String 操作类型,可选
|
|
490
|
+
* 'device_error' -> 设备出错处理,'plug_and_unplug' -> 热插拔处理,
|
|
491
|
+
* 不传即是普通的设置扬声器设备的行为
|
|
492
|
+
* @return Promise | void
|
|
493
|
+
*/
|
|
494
|
+
async function setSpeakerDevice(args) {
|
|
495
|
+
// NOTE 1. 没传deviceId则用默认设备
|
|
496
|
+
defaultApi.writeLog(`${JSON.stringify(args)}----setSpeakerDevice-zego----`);
|
|
497
|
+
let { deviceId, operationType, deviceState, code, changedDeviceId } = args;
|
|
498
|
+
let deviceName = '';
|
|
499
|
+
let speakerData;
|
|
500
|
+
if (!deviceId) {
|
|
501
|
+
speakerData = await getSpeakerDeviceList();
|
|
502
|
+
if (speakerData.length) {
|
|
503
|
+
let hasGetSpeaker = false;
|
|
504
|
+
for (let item of speakerData) {
|
|
505
|
+
if (item.isDefault) {
|
|
506
|
+
deviceId = item.deviceId;
|
|
507
|
+
deviceName = item.deviceName;
|
|
508
|
+
hasGetSpeaker = true;
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (!hasGetSpeaker) {
|
|
513
|
+
deviceId = speakerData[0].deviceId;
|
|
514
|
+
deviceName = speakerData[0].deviceName;
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
deviceId = '';
|
|
518
|
+
}
|
|
519
|
+
if (deviceId === '') {
|
|
520
|
+
NOTICE.noDevice({
|
|
521
|
+
deviceType: 'speaker'
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// NOTE 2. ???
|
|
526
|
+
try {
|
|
527
|
+
dataReport.setDevice({
|
|
528
|
+
device_type: 3,
|
|
529
|
+
device_id: deviceId,
|
|
530
|
+
device_name: deviceListReport.speakerList[deviceId],
|
|
531
|
+
operationType,
|
|
532
|
+
fore_state: operationType == 'hotPlug' ? deviceState + 1 : '-'
|
|
533
|
+
});
|
|
534
|
+
window.zbyAVSDK_device_checker_init.speaker.name = deviceListReport.speakerList[deviceId];
|
|
535
|
+
} catch (e) { };
|
|
536
|
+
// NOTE 3. 设置扬声器
|
|
537
|
+
usingAudioDeviceId.speaker = deviceId;
|
|
538
|
+
await setAudioDevice(1, deviceId);
|
|
539
|
+
// NOTE 4. 热插拔处理逻辑
|
|
540
|
+
if (operationType == 'hotPlug' || operationType == 'deviceError') {
|
|
541
|
+
if (!speakerData) {
|
|
542
|
+
speakerData = await getSpeakerDeviceList();
|
|
543
|
+
deviceName = deviceListReport.speakerList[deviceId];
|
|
544
|
+
}
|
|
545
|
+
NOTICE[operationType]({
|
|
546
|
+
deviceType: 'speaker',
|
|
547
|
+
useDeviceId: deviceId,
|
|
548
|
+
useDeviceName: deviceName,
|
|
549
|
+
deviceList: speakerData,
|
|
550
|
+
message: code,
|
|
551
|
+
deviceState,
|
|
552
|
+
changedDeviceId
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* 获取当前扬声器设备id
|
|
558
|
+
* @return {String} 当前扬声器设备id
|
|
559
|
+
*/
|
|
560
|
+
function getCurrentSpeakerDevice() {
|
|
561
|
+
defaultApi.writeLog(`avsdk ZEGO::getSpeakerDevice ${usingAudioDeviceId.speaker}`);
|
|
562
|
+
return usingAudioDeviceId.speaker;
|
|
563
|
+
}
|
|
564
|
+
function getSpeakerDeviceVolume() {
|
|
565
|
+
return speakerVolume;
|
|
566
|
+
}
|
|
567
|
+
function setSpeakerDeviceVolume(volume) {
|
|
568
|
+
speakerVolume = volume;
|
|
569
|
+
// NOTE 1. 遍历所有播放器,全部设置
|
|
570
|
+
Object.keys(streamIdToStreamView).forEach(streamId=> {
|
|
571
|
+
streamIdToStreamView[streamId].setVolume(speakerVolume);
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* @function 设置扬声器静音
|
|
576
|
+
* @param mute:Boolean 必选
|
|
577
|
+
* @return Promise | void
|
|
578
|
+
*/
|
|
579
|
+
function setSpeakerDeviceMute(mute) {
|
|
580
|
+
// NOTE 1. 遍历所有播放器,全部设置
|
|
581
|
+
Object.keys(streamIdToStreamView).forEach(streamId=> {
|
|
582
|
+
const streamView = streamIdToStreamView[streamId];
|
|
583
|
+
streamView.setAudioMuted(mute);
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @function 获取麦克风列表
|
|
589
|
+
* @return Promise | void
|
|
590
|
+
*/
|
|
591
|
+
async function getMicrophoneDeviceList() {
|
|
592
|
+
if(!zg) {
|
|
593
|
+
return Promise.resolve([]);
|
|
594
|
+
}
|
|
595
|
+
let microphoneListArr = await zg.getMicrophones();
|
|
596
|
+
let microphoneList = [];
|
|
597
|
+
for (let i = 0, len = microphoneListArr.length; i < len; i++) {
|
|
598
|
+
microphoneList.push({
|
|
599
|
+
deviceId: microphoneListArr[i].deviceID,
|
|
600
|
+
deviceName: microphoneListArr[i].deviceName,
|
|
601
|
+
isDefault: i === 0,
|
|
602
|
+
});
|
|
603
|
+
deviceListReport.micList[microphoneListArr[i].deviceID] = microphoneListArr[i].deviceName;
|
|
604
|
+
}
|
|
605
|
+
if (!window.zbyAVSDK_device_checker_init) {
|
|
606
|
+
window.zbyAVSDK_device_checker_init = {};
|
|
607
|
+
}
|
|
608
|
+
if (!window.zbyAVSDK_device_checker_init.microphone) {
|
|
609
|
+
window.zbyAVSDK_device_checker_init.microphone = {};
|
|
610
|
+
}
|
|
611
|
+
window.zbyAVSDK_device_checker_init.microphone.hasTest = true;
|
|
612
|
+
window.zbyAVSDK_device_checker_init.microphone.list = microphoneList;
|
|
613
|
+
return microphoneList;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* @function 指定麦克风
|
|
617
|
+
* @param deviceId:String 麦克风 id,必选
|
|
618
|
+
* @param operationType:String 操作类型,可选
|
|
619
|
+
* 'device_error' -> 设备出错处理,'plug_and_unplug' -> 热插拔处理,
|
|
620
|
+
* 不传即是普通的设置麦克风设备的行为
|
|
621
|
+
* @return Promise | void
|
|
622
|
+
*/
|
|
623
|
+
async function setMicrophoneDevice(args) {
|
|
624
|
+
defaultApi.writeLog(`${JSON.stringify(args)}----setMicrophoneDevice-zego----`);
|
|
625
|
+
let { deviceId, operationType, deviceState, code, changedDeviceId } = args;
|
|
626
|
+
let deviceName = '';
|
|
627
|
+
let microPhoneData;
|
|
628
|
+
// NOTE 1. 没设备就用默认设备
|
|
629
|
+
if (!deviceId) {
|
|
630
|
+
microPhoneData = await getMicrophoneDeviceList();
|
|
631
|
+
if (microPhoneData.length) {
|
|
632
|
+
let hasGetMicrophone = false;
|
|
633
|
+
for (let item of microPhoneData) {
|
|
634
|
+
if (item.isDefault) {
|
|
635
|
+
deviceId = item.deviceId;
|
|
636
|
+
deviceName = item.deviceName;
|
|
637
|
+
hasGetMicrophone = true;
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (!hasGetMicrophone) {
|
|
642
|
+
deviceId = microPhoneData[0].deviceId;
|
|
643
|
+
deviceName = microPhoneData[0].deviceName;
|
|
644
|
+
}
|
|
645
|
+
} else {
|
|
646
|
+
deviceId = '';
|
|
647
|
+
}
|
|
648
|
+
if (deviceId === '') {
|
|
649
|
+
NOTICE.noDevice({
|
|
650
|
+
deviceType: 'microphone'
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
// NOTE 2. ???
|
|
655
|
+
try {
|
|
656
|
+
dataReport.setDevice({
|
|
657
|
+
device_type: 2,
|
|
658
|
+
device_id: deviceId,
|
|
659
|
+
device_name: deviceListReport.micList[deviceId],
|
|
660
|
+
operationType,
|
|
661
|
+
fore_state: operationType == 'hotPlug' ? deviceState + 1 : '-'
|
|
662
|
+
});
|
|
663
|
+
window.zbyAVSDK_device_checker_init.microphone.name = deviceListReport.micList[deviceId];
|
|
664
|
+
} catch (e) { };
|
|
665
|
+
usingAudioDeviceId.microphone = deviceId;
|
|
666
|
+
// NOTE 3. 设置麦克风
|
|
667
|
+
await setAudioDevice(0, deviceId);
|
|
668
|
+
// NOTE WEB无此功能,native 此接口是音量变化事件的开关。
|
|
669
|
+
// await setAudioVolumeNotify(0, deviceId);
|
|
670
|
+
if (operationType == 'hotPlug' || operationType == 'deviceError') {
|
|
671
|
+
if (!microPhoneData) {
|
|
672
|
+
microPhoneData = await getMicrophoneDeviceList();
|
|
673
|
+
deviceName = deviceListReport.micList[deviceId];
|
|
674
|
+
}
|
|
675
|
+
NOTICE[operationType]({
|
|
676
|
+
deviceType: 'microphone',
|
|
677
|
+
useDeviceId: deviceId,
|
|
678
|
+
useDeviceName: deviceName,
|
|
679
|
+
deviceList: microPhoneData,
|
|
680
|
+
message: code,
|
|
681
|
+
deviceState,
|
|
682
|
+
changedDeviceId
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function getMicDeviceVolume() {
|
|
687
|
+
return microphoneVolume;
|
|
688
|
+
}
|
|
689
|
+
function setMicDeviceVolume(volume) {
|
|
690
|
+
microphoneVolume = volume;
|
|
691
|
+
return localStream.setVolume(volume);
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* @function 设置麦克风静音
|
|
695
|
+
* @param mute:Boolean 必选
|
|
696
|
+
* @return Promise | void
|
|
697
|
+
*/
|
|
698
|
+
function setMicDeviceMute(mute) {
|
|
699
|
+
if(localStream) {
|
|
700
|
+
return zg.mutePublishStreamAudio(localStream, mute);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* @function 获取当前应用程序音量
|
|
705
|
+
* @return Promise | void
|
|
706
|
+
*/
|
|
707
|
+
function getSpeakerSimpleVolume() {
|
|
708
|
+
// NOTE native端是设置扬声器的程序音量
|
|
709
|
+
return speakerVolume;
|
|
710
|
+
}
|
|
711
|
+
function setSpeakerSimpleVolume(volume) {
|
|
712
|
+
speakerVolume = volume;
|
|
713
|
+
// NOTE 遍历播放器,分别设置
|
|
714
|
+
// NOTE TODO ...
|
|
715
|
+
Object.keys(streamIdToStreamView).forEach(streamId=> {
|
|
716
|
+
const streamView = streamIdToStreamView[streamId];
|
|
717
|
+
streamView.setVolume(volume);
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
function setSpeakerSimpleMute(mute) {
|
|
721
|
+
// NOTE 遍历所有的拉流播放器,设置mute
|
|
722
|
+
// 用setAudioMuted,因为禁流轨道有active接口
|
|
723
|
+
setSpeakerDeviceMute(mute);
|
|
724
|
+
}
|
|
725
|
+
function setPreviewView() {
|
|
726
|
+
// NOTE WEB无此功能
|
|
727
|
+
}
|
|
728
|
+
async function startPreview(viewElement) {
|
|
729
|
+
if(!localStream) {
|
|
730
|
+
cameraConstraints.captureView = viewElement;
|
|
731
|
+
cameraConstraints.camera.audio.input = window.zbyAVSDK_device_checker_init.microphone.use;
|
|
732
|
+
cameraConstraints.camera.video.input = window.zbyAVSDK_device_checker_init.camera.use;
|
|
733
|
+
const constraints = Object.assign({}, cameraConstraints);
|
|
734
|
+
if(!hasCamera) {
|
|
735
|
+
constraints.camera.video = false;
|
|
736
|
+
}
|
|
737
|
+
if(!hasMicrophone) {
|
|
738
|
+
constraints.camera.audio = false;
|
|
739
|
+
}
|
|
740
|
+
localStream = await zg.createZegoStream(constraints);
|
|
741
|
+
localStream.on('canPlayCaptureVideo', function(){
|
|
742
|
+
console.warn('[采集首帧]', localStream);
|
|
743
|
+
// 大班数据上报 TODO ...
|
|
744
|
+
// dabanDataReport({
|
|
745
|
+
// action: 'open_camera',
|
|
746
|
+
// camera_status: 1,
|
|
747
|
+
// uid: window.zbyAVSDK_init_params.zego.userId // zbyAVSDK_init_params这个对象在上层没被定义
|
|
748
|
+
// });
|
|
749
|
+
});
|
|
750
|
+
setMicDeviceVolume(microphoneVolume);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
if(viewElement) {
|
|
754
|
+
localStream.playVideo(viewElement); // NOTE 渲染
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
async function startLocalOrRemotePreview(isLocal, streamId, domId) {
|
|
758
|
+
if(!domId) { return; }
|
|
759
|
+
// NOTE 1. 预览流渲染
|
|
760
|
+
if(isLocal) {
|
|
761
|
+
if (streamId === localStreamId) {
|
|
762
|
+
return startPreview(document.querySelector(`#${domId}`));
|
|
763
|
+
}
|
|
764
|
+
if (streamId === screenStreamId) {
|
|
765
|
+
return startScreenPreview(document.querySelector(`#${domId}`));
|
|
766
|
+
}
|
|
767
|
+
defaultApi.writeLog(`ZEGO: startLocalOrRemotePreview wrong streamId: ${streamId} domId: ${domId}`, null, error);
|
|
768
|
+
}else {
|
|
769
|
+
// NOTE 拉流渲染前,先读取activate预置的参数
|
|
770
|
+
const playInfo1 = streamIdRtcPlayerInfo1[streamId];//true -> 拉取,false -> 不拉取,必选
|
|
771
|
+
if(!playInfo1.video_type) {
|
|
772
|
+
try {
|
|
773
|
+
zg.mutePlayStreamVideo(streamId, !playInfo1.video_type); // NOTE 没视轨会报错
|
|
774
|
+
} catch (error) { }
|
|
775
|
+
}
|
|
776
|
+
if(!playInfo1.audio_type) {
|
|
777
|
+
try {
|
|
778
|
+
zg.mutePlayStreamAudio(streamId, !playInfo1.audio_type); // NOTE 没音轨会报错
|
|
779
|
+
} catch (error) { }
|
|
780
|
+
|
|
781
|
+
}
|
|
782
|
+
const remoteStream = streamIdToStream[streamId];
|
|
783
|
+
const remoteView = zg.createRemoteStreamView(remoteStream);
|
|
784
|
+
streamIdToStreamView[streamId] = remoteView;
|
|
785
|
+
remoteView.setVolume(speakerVolume);
|
|
786
|
+
remoteView.useAudioOutputDevice(window.zbyAVSDK_device_checker_init.speaker.use);
|
|
787
|
+
remoteView.on('canPlayVideo', function() {
|
|
788
|
+
console.warn('[拉流视频首帧]', streamId, remoteView);
|
|
789
|
+
// TODO
|
|
790
|
+
// if (window.zbyAVSDK_init_params.zego.role === 'student') {
|
|
791
|
+
// dabanDataReport({
|
|
792
|
+
// action: 'interact_play',
|
|
793
|
+
// teammate_streamid: _data.pszStreamID,
|
|
794
|
+
// uid: window.zbyAVSDK_init_params.zego.userId // NOTE zbyAVSDK_init_params这个对象在上层没被定义
|
|
795
|
+
// });
|
|
796
|
+
// }
|
|
797
|
+
try {
|
|
798
|
+
NOTICE.firstVideoSize({
|
|
799
|
+
streamId: streamId,
|
|
800
|
+
userId: util.getUidByStreamId(streamId)
|
|
801
|
+
});
|
|
802
|
+
dataReport.firstVideoSize({
|
|
803
|
+
pull_streamid: streamId,
|
|
804
|
+
pull_uid: util.getUidByStreamIdDr(streamId),
|
|
805
|
+
code: '0'
|
|
806
|
+
});
|
|
807
|
+
} catch (e) { };
|
|
808
|
+
defaultApi.writeLog(`ZEGO: pullStream success & haveFirstVideoSize streamId: ${streamId}`);
|
|
809
|
+
});
|
|
810
|
+
remoteView.on('canPlayAudio', function() {
|
|
811
|
+
console.warn('[拉流音频首帧]', streamId);
|
|
812
|
+
try {
|
|
813
|
+
NOTICE.firstAudioSize({
|
|
814
|
+
streamId: streamId,
|
|
815
|
+
userId: util.getUidByStreamId(streamId)
|
|
816
|
+
});
|
|
817
|
+
dataReport.firstAudioSize({
|
|
818
|
+
pull_streamid: streamId,
|
|
819
|
+
pull_uid: util.getUidByStreamIdDr(streamId),
|
|
820
|
+
code: '0'
|
|
821
|
+
});
|
|
822
|
+
} catch (e) { };
|
|
823
|
+
});
|
|
824
|
+
remoteView.on('autoplayFailed', function() {
|
|
825
|
+
console.error('自动播放音频失败');
|
|
826
|
+
});
|
|
827
|
+
remoteView.play(domId);
|
|
828
|
+
try {
|
|
829
|
+
// NOTE 防止二次拉流,业务侧创重名播放容器
|
|
830
|
+
document.querySelectorAll('#' + domId)[1].remove();
|
|
831
|
+
} catch (error) {}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
async function setEnableNoiseSuppress(ANS) { // 降噪
|
|
835
|
+
// NOTE 1. 保存设置
|
|
836
|
+
cameraConstraints.camera.audio['ANS'] = ANS;
|
|
837
|
+
// NOTE 2. 已创建流了, 更新
|
|
838
|
+
if(localStream) {
|
|
839
|
+
return zg.setAudioConfig(localStream, { ANS });
|
|
840
|
+
}
|
|
841
|
+
return Promise.resolve(true);
|
|
842
|
+
}
|
|
843
|
+
async function setEnableAEC(AEC) { // 回声消除
|
|
844
|
+
// NOTE 1. 保存设置
|
|
845
|
+
cameraConstraints.camera.audio['AEC'] = AEC;
|
|
846
|
+
// NOTE 2. 已创建流了, 更新
|
|
847
|
+
if(localStream) {
|
|
848
|
+
return zg.setAudioConfig(localStream, { AEC });
|
|
849
|
+
}
|
|
850
|
+
return Promise.resolve(true);
|
|
851
|
+
}
|
|
852
|
+
async function setVideoFPS(frameRate) {
|
|
853
|
+
// NOTE 1. 保存设置
|
|
854
|
+
cameraConstraints.camera.video.frameRate = frameRate;
|
|
855
|
+
// NOTE 2. 已创建流了, 更新
|
|
856
|
+
if(localStream) {
|
|
857
|
+
return zg.setVideoConfig(localStream, { frameRate });
|
|
858
|
+
}
|
|
859
|
+
return Promise.resolve(true);
|
|
860
|
+
}
|
|
861
|
+
async function setVideoBitrate(maxBitrate) {
|
|
862
|
+
// NOTE 1. 保存设置
|
|
863
|
+
cameraConstraints.videoBitrate = maxBitrate/1000;
|
|
864
|
+
// NOTE 2. 已创建流了, 更新
|
|
865
|
+
if(localStream) {
|
|
866
|
+
return zg.setVideoConfig(localStream, { maxBitrate });
|
|
867
|
+
}
|
|
868
|
+
return Promise.resolve(true);
|
|
869
|
+
}
|
|
870
|
+
async function setAudioBitrate(maxBitrate) {
|
|
871
|
+
// NOTE 1. 保存设置
|
|
872
|
+
cameraConstraints.audioBitrate = maxBitrate/1000;
|
|
873
|
+
// NOTE 2. WEB 不支持动态改音频码率,非要改的话需要销毁音频重新创建
|
|
874
|
+
return Promise.resolve(true);
|
|
875
|
+
}
|
|
876
|
+
async function setVideoCaptureResolution(width, height) {
|
|
877
|
+
// NOTE 1. 保存设置
|
|
878
|
+
cameraConstraints.camera.video.width = width;
|
|
879
|
+
cameraConstraints.camera.video.height = height;
|
|
880
|
+
// NOTE 2. 已创建流了, 更新
|
|
881
|
+
if(localStream) {
|
|
882
|
+
console.warn(localStream, { width, height });
|
|
883
|
+
return zg.setVideoConfig(localStream, { width, height });
|
|
884
|
+
}
|
|
885
|
+
// NOTE 3. setCapturePipelineScaleMode WEB无缩放时机
|
|
886
|
+
return Promise.resolve(true);
|
|
887
|
+
}
|
|
888
|
+
async function setCameraParam(width, height) {
|
|
889
|
+
// NOTE WEB没有采集、编码分辨率,只是提供一个目标值,采多少编多少浏览器动态调控
|
|
890
|
+
return setVideoCaptureResolution(width, height);
|
|
891
|
+
}
|
|
892
|
+
async function setVideoEncodeResolution(width, height) {
|
|
893
|
+
// NOTE WEB没有采集、编码分辨率,只是提供一个目标值,采多少编多少浏览器动态调控
|
|
894
|
+
return setVideoCaptureResolution(width, height);
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* 开始推流
|
|
898
|
+
* @param {string} streamId 流唯一标识
|
|
899
|
+
* @param {0 | 1} idx 0: 启动摄像头 1: 启动屏幕共享
|
|
900
|
+
* @returns
|
|
901
|
+
*/
|
|
902
|
+
async function startPublish2(streamId, idx) {
|
|
903
|
+
if (!streamId) {
|
|
904
|
+
streamId = localStreamId;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
if (streamId === localStreamId) {
|
|
908
|
+
// NOTE 初始化推流埋点数据
|
|
909
|
+
resetHeartBeatDataReportObj();
|
|
910
|
+
const publisRes = zg.startPublishingStream(streamId, localStream);
|
|
911
|
+
if(!publisRes) {
|
|
912
|
+
NOTICE.pushStreamError({
|
|
913
|
+
streamId,
|
|
914
|
+
});
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
} else if (streamId === screenStreamId) {
|
|
918
|
+
screenStream = await startScreenPreview();
|
|
919
|
+
const publisRes = zg.startPublishingStream(streamId, screenStream);
|
|
920
|
+
if(!publisRes) {
|
|
921
|
+
NOTICE.pushStreamError({
|
|
922
|
+
streamId,
|
|
923
|
+
});
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
} else {
|
|
927
|
+
defaultApi.writeLog(`ZEGO:: startPublish2 streamId:${streamId} is not exist[${localStreamId}, ${screenStreamId}]`, null, 'error');
|
|
928
|
+
NOTICE.pushStreamError({
|
|
929
|
+
streamId,
|
|
930
|
+
msg: `streamId:${streamId} is not exist[${localStreamId}, ${screenStreamId}]`
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
function stopPublish(idx) {
|
|
936
|
+
console.log('[停止推流]', localStreamId);
|
|
937
|
+
if (idx !== 0 || idx !== 1) {
|
|
938
|
+
defaultApi.writeLog(`ZEGO:: stopPublish idx:${idx} is not exist[${localStreamId}, ${screenStreamId}]`, null, 'error');
|
|
939
|
+
}
|
|
940
|
+
return zg.stopPublishingStream(idx === 0 ? localStreamId : screenStreamId);
|
|
941
|
+
}
|
|
942
|
+
async function startScreenPreview(captureView) {
|
|
943
|
+
if (!screenStream) {
|
|
944
|
+
screenConstraints.videoBitrate = initParams.screenSameBitrate / 1000;
|
|
945
|
+
screenConstraints.captureView = captureView;
|
|
946
|
+
screenConstraints.screen.video.frameRate = initParams.screenSameFps;
|
|
947
|
+
screenConstraints.screen.width = initParams.screenSameResolutionWidth;
|
|
948
|
+
screenConstraints.screen.height = initParams.screenSameResolutionHeight;
|
|
949
|
+
screenConstraints.screen.audio = false;
|
|
950
|
+
console.warn('[创建屏幕共享流]', screenConstraints);
|
|
951
|
+
screenStream = await zg.createZegoStream(screenConstraints);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
if (captureView) {
|
|
955
|
+
screenStream.playVideo(captureView);
|
|
956
|
+
}
|
|
957
|
+
return screenStream;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
async function initPullFlow(streamId, domId, mute, pInfo, notAutoPlay, audioOnly) {
|
|
961
|
+
defaultApi.writeLog(`ZEGO:: initPullFlow_start ,streamId :${streamId}, domId: ${domId}, mute: ${mute}, pInfo: ${pInfo}, notAutoPlay: ${notAutoPlay}, audioOnly: ${audioOnly}`);
|
|
962
|
+
// NOTE 1. 重置埋点数据
|
|
963
|
+
let playChannel = _initPullData(streamId);
|
|
964
|
+
// NOTE 5. 配置拉流参数
|
|
965
|
+
//是否拉取声音
|
|
966
|
+
await activateAudioPlayStream(streamId, !mute);
|
|
967
|
+
//是否拉取画面
|
|
968
|
+
await activateVideoPlayStream(streamId, !audioOnly);
|
|
969
|
+
// NOTE 6. 拉流
|
|
970
|
+
// if (!notAutoPlay) { // NOTE 此处不自动播放,什么地方拉流?
|
|
971
|
+
// await playStream(streamId, playChannel, pInfo);
|
|
972
|
+
// }
|
|
973
|
+
const remoteStream = await playStream(streamId, playChannel, pInfo);
|
|
974
|
+
streamIdToStream[streamId] = remoteStream;
|
|
975
|
+
// 创建视图
|
|
976
|
+
await startLocalOrRemotePreview(false, streamId, domId);
|
|
977
|
+
return {
|
|
978
|
+
videoSrc: '',
|
|
979
|
+
playerId: playChannel
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function _initPullData(streamId) {
|
|
984
|
+
let playChannel;
|
|
985
|
+
// NOTE 1. 重置埋点数据
|
|
986
|
+
resetStreamIdRtcPlayerInfo1(streamId);
|
|
987
|
+
resetStreamIdRtcPlayerInfo(streamId);
|
|
988
|
+
// NOTE 2. 首次拉流,启动埋点上报程序
|
|
989
|
+
try {
|
|
990
|
+
if (!isFirstHeartBeatReport) {
|
|
991
|
+
isFirstHeartBeatReport = true;
|
|
992
|
+
heartBeatDataReport('start');
|
|
993
|
+
}
|
|
994
|
+
} catch (error) { }
|
|
995
|
+
// NOTE 3. 程序限制了拉流49条,给每条拉流设置一个编号
|
|
996
|
+
if (streamIdToPreviewId[streamId] == undefined) {
|
|
997
|
+
defaultApi.writeLog(`ZEGO:: The streamId queue does not contain this streamId ${uiChnIndexs}`);
|
|
998
|
+
// NOTE 3.1 超50条,不能再拉流了
|
|
999
|
+
if (uiChnIndexs.length === 0) {
|
|
1000
|
+
NOTICE.overMaxConnect();
|
|
1001
|
+
defaultApi.writeLog('error', `ZEGO:: all uiChnIndexs are used ${uiChnIndexs}`);
|
|
1002
|
+
return {
|
|
1003
|
+
videoSrc: '',
|
|
1004
|
+
playerId: -2
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
playChannel = uiChnIndexs.pop();
|
|
1008
|
+
streamIdToPreviewId[streamId] = playChannel;
|
|
1009
|
+
defaultApi.writeLog(`streamIdIsNoExited ${playChannel} ${uiChnIndexs}`);
|
|
1010
|
+
} else {
|
|
1011
|
+
// NOTE 3.2 已存在,停拉重拉
|
|
1012
|
+
playChannel = streamIdToPreviewId[streamId];
|
|
1013
|
+
defaultApi.writeLog(`ZEGO:: The streamId queue contains this streamId ${playChannel} ${uiChnIndexs}`);
|
|
1014
|
+
stopPlayStream(streamId);
|
|
1015
|
+
resetStreamIdRtcPlayerInfo(streamId);
|
|
1016
|
+
}
|
|
1017
|
+
// NOTE 4. 判断是否创建或者获取播放编号成功,不成功就删掉重试
|
|
1018
|
+
if (playChannel == undefined) {
|
|
1019
|
+
delete streamIdToPreviewId[streamId];
|
|
1020
|
+
defaultApi.writeLog('error', 'ZEGO:: uiChnIndex is not exist');
|
|
1021
|
+
return initPullFlow(streamId);
|
|
1022
|
+
}
|
|
1023
|
+
previewIdToStreamId[playChannel] = streamId;
|
|
1024
|
+
return playChannel;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* @function 恢复拉指定的流
|
|
1029
|
+
* @param streamId:String 被拉取的流的 id,必选
|
|
1030
|
+
* @param uiChnIndex:Number 播放通道,可选
|
|
1031
|
+
* @param pInfo:String 多媒体流附加信息,可选,默认为 'none'
|
|
1032
|
+
* @return Promise | void
|
|
1033
|
+
*/
|
|
1034
|
+
async function playStream(streamId, uiChnIndex, pInfo) {
|
|
1035
|
+
if (typeof pInfo === 'undefined') { // SEI
|
|
1036
|
+
pInfo = 'none';
|
|
1037
|
+
}
|
|
1038
|
+
const streamInfo = streamIdRtcPlayerInfo1[streamId];
|
|
1039
|
+
defaultApi.writeLog(`avsdk ZEGO::PlayStream streamId: ${streamId} streamInfo: ${JSON.stringify(streamInfo)}`);
|
|
1040
|
+
return zg.startPlayingStream(streamId, {
|
|
1041
|
+
// TODO 拉流参数配置
|
|
1042
|
+
// video: !!!audioOnly,
|
|
1043
|
+
video: streamInfo.video_type,
|
|
1044
|
+
audio: streamInfo.audio_type,
|
|
1045
|
+
isSEIStart: pInfo != 'none'? true: false,
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
async function stopPlayStream(streamId, recovery) {
|
|
1049
|
+
console.warn('[停止拉流]', streamId);
|
|
1050
|
+
delete streamIdRtcPlayerInfo[streamId];
|
|
1051
|
+
// if (recovery && id && !uiChnIndexs.includes(id)) {
|
|
1052
|
+
// uiChnIndexs.push(id);
|
|
1053
|
+
// defaultApi.writeLog(`avsdk ZEGO::stopPlayStream streamId: ${streamId} id: ${id} uiChnIndexs: ${uiChnIndexs}`);
|
|
1054
|
+
delete streamIdToPreviewId[streamId];
|
|
1055
|
+
// }
|
|
1056
|
+
delete streamIdToStream[streamId];
|
|
1057
|
+
delete streamIdToStreamView[streamId];
|
|
1058
|
+
zg.stopPlayingStream(streamId);
|
|
1059
|
+
// NOTE 清除渲染节点 拉纯音频,渲染节点直接挂在body上
|
|
1060
|
+
try {
|
|
1061
|
+
const dom = document.querySelector('#' + streamId); // id不存在会抛错
|
|
1062
|
+
if(dom) { dom.remove(); }
|
|
1063
|
+
} catch (error) { }
|
|
1064
|
+
|
|
1065
|
+
}
|
|
1066
|
+
function stopAllPlayStream() {
|
|
1067
|
+
Object.keys(streamIdToPreviewId).forEach(streamId=> {
|
|
1068
|
+
const id = streamIdToPreviewId[streamId];
|
|
1069
|
+
if (id !==void(0) && !uiChnIndexs.includes(id)) {
|
|
1070
|
+
uiChnIndexs.push(id);
|
|
1071
|
+
stopPlayStream(streamId);
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
streamIdToPreviewId = {};
|
|
1075
|
+
streamIdToStream = {};
|
|
1076
|
+
streamIdToStreamView = {};
|
|
1077
|
+
}
|
|
1078
|
+
async function leaveRoom(type) {
|
|
1079
|
+
// NOTE 1. 停止声浪监听 WEB端无需单独停止
|
|
1080
|
+
// NOTE 2. 停拉
|
|
1081
|
+
for (let key in streamIdToPreviewId) {
|
|
1082
|
+
stopPlayStream(key, true);
|
|
1083
|
+
}
|
|
1084
|
+
// NOTE 3. 停推
|
|
1085
|
+
zg.stopPublishingStream(localStreamId);
|
|
1086
|
+
// NOTE 4. 停事件监听
|
|
1087
|
+
removerListener();
|
|
1088
|
+
// NOTE 5. 刷新按钮
|
|
1089
|
+
if(type == 'reload') {
|
|
1090
|
+
// TODO ...
|
|
1091
|
+
}else {
|
|
1092
|
+
// 停预览
|
|
1093
|
+
zg.destroyStream(localStream);
|
|
1094
|
+
// 销毁引擎
|
|
1095
|
+
zg.destroyEngine();
|
|
1096
|
+
}
|
|
1097
|
+
// NOTE 6. 其它业务逻辑
|
|
1098
|
+
heartBeatDataReport('stop');
|
|
1099
|
+
isFirstHeartBeatReport = false;
|
|
1100
|
+
streamIdToPreviewId = {};
|
|
1101
|
+
previewIdToStreamId = {};
|
|
1102
|
+
streamIdRtcPlayerInfo = {};
|
|
1103
|
+
streamIdRtcPlayerInfo1 = {};
|
|
1104
|
+
// heartBeatDataReportObj = {};
|
|
1105
|
+
hasLoginChannel = 0;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
async function playerSnapShot(streamId) {
|
|
1109
|
+
defaultApi.writeLog(`avsdk ZEGO::playerSnapShot streamId: ${streamId}`);
|
|
1110
|
+
let uri;
|
|
1111
|
+
if (streamId === localStreamId) {
|
|
1112
|
+
uri = localStream.takeStreamSnapshot();
|
|
1113
|
+
} else {
|
|
1114
|
+
uri = screenStream.takeStreamSnapshot();
|
|
1115
|
+
}
|
|
1116
|
+
defaultApi.writeLog(`avsdk ZEGO::playerSnapShot uri: ${uri}`);
|
|
1117
|
+
return util.getImageDataFromURL(uri);
|
|
1118
|
+
}
|
|
1119
|
+
async function activateAudioPlayStream(streamId, bActive) {
|
|
1120
|
+
// NOTE WEB无此接口,此处业务侧应该是想达到是否渲染音视频的目的。所以web端先拉流,再按此设置值渲染
|
|
1121
|
+
// NOTE 关联代码 streamview.play()
|
|
1122
|
+
if(!streamIdRtcPlayerInfo1[streamId]) {
|
|
1123
|
+
resetStreamIdRtcPlayerInfo1(streamId);
|
|
1124
|
+
}
|
|
1125
|
+
streamIdRtcPlayerInfo1[streamId].audio_type = bActive;
|
|
1126
|
+
if(streamIdToStream[streamId]) { // 流已存在
|
|
1127
|
+
await zg.mutePlayStreamAudio(streamId, !bActive);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* @function 拉取音频流
|
|
1132
|
+
* @param operation:Boolean true/不拉音频,false/拉音频,必选
|
|
1133
|
+
* @param streamid:String 被拉取的流的 id,必选
|
|
1134
|
+
*/
|
|
1135
|
+
async function pullAudioFlow(streamId, operation) {
|
|
1136
|
+
// NOTE 1. 数据埋点、上报
|
|
1137
|
+
defaultApi.writeLog(`pullAudioFlow -- operation ${operation} streamId ${streamId}`);
|
|
1138
|
+
if (!streamId) {
|
|
1139
|
+
throw new Error('pullAudioFlow -- streamId is not allowed to be empty');
|
|
1140
|
+
}
|
|
1141
|
+
if (streamIdToPreviewId[streamId] == undefined) {
|
|
1142
|
+
// NOTICE.pullAudioFlowError({ streamid })
|
|
1143
|
+
_initPullData(streamId); // 启动
|
|
1144
|
+
}
|
|
1145
|
+
try {
|
|
1146
|
+
streamIdRtcPlayerInfo1[streamId].audio_type = operation;
|
|
1147
|
+
} catch (e) {
|
|
1148
|
+
defaultApi.writeLog(`pullAudioFlow ${streamId} --error ${JSON.stringify(e)}`, null, 'error');
|
|
1149
|
+
}
|
|
1150
|
+
try {
|
|
1151
|
+
dataReport.setPullVoice({
|
|
1152
|
+
code: +operation,
|
|
1153
|
+
pull_uid: util.getUidByStreamId(streamId),
|
|
1154
|
+
pull_streamid: streamId,
|
|
1155
|
+
playerId
|
|
1156
|
+
// operator:'client'
|
|
1157
|
+
});
|
|
1158
|
+
} catch (e) { };
|
|
1159
|
+
// NOTE 2. 正式拉流;
|
|
1160
|
+
if (!streamIdToStream[streamId]) {
|
|
1161
|
+
streamIdToStream[streamId] = await zg.startPlayingStream(streamId, { video: false });
|
|
1162
|
+
};
|
|
1163
|
+
// NOTE 3. 流挂载到body上
|
|
1164
|
+
if (!operation) {
|
|
1165
|
+
try {
|
|
1166
|
+
const dom = document.querySelector('#' + streamId); // id不存在会抛错
|
|
1167
|
+
if(dom) { dom.remove(); }
|
|
1168
|
+
} catch (error) { }
|
|
1169
|
+
const div = document.createElement('div');
|
|
1170
|
+
div.style.display = 'none';
|
|
1171
|
+
div.id = streamId;
|
|
1172
|
+
document.body.appendChild(div);
|
|
1173
|
+
await startLocalOrRemotePreview(false, streamId, streamId);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
await zg.mutePlayStreamAudio(streamId, operation);
|
|
1177
|
+
}
|
|
1178
|
+
async function activateVideoPlayStream(streamId, bActive) {
|
|
1179
|
+
// NOTE WEB无此接口,此处业务侧应该是想达到是否渲染音视频的目的。所以web端先拉流,再按此设置值渲染
|
|
1180
|
+
if(!streamIdRtcPlayerInfo1[streamId]) {
|
|
1181
|
+
resetStreamIdRtcPlayerInfo1(streamId);
|
|
1182
|
+
}
|
|
1183
|
+
streamIdRtcPlayerInfo1[streamId].video_type = bActive;
|
|
1184
|
+
if(streamIdToStream[streamId]) { // 流已拉取
|
|
1185
|
+
await zg.mutePlayStreamVideo(streamId, !bActive);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
function setAudioVolumeNotify() {
|
|
1190
|
+
// NOTE WEB无此功能
|
|
1191
|
+
}
|
|
1192
|
+
function stopAudioVolumeNotify() {
|
|
1193
|
+
// NOTE WEB无此功能
|
|
1194
|
+
}
|
|
1195
|
+
function openMicVolumeCb() {}
|
|
1196
|
+
// 声浪开关
|
|
1197
|
+
function startSoundLevelMonitor() {
|
|
1198
|
+
zg.setSoundLevelDelegate(true, soundLevelMonitorCycle);
|
|
1199
|
+
}
|
|
1200
|
+
function stopSoundLevelMonitor() {
|
|
1201
|
+
zg.setSoundLevelDelegate(false);
|
|
1202
|
+
}
|
|
1203
|
+
// 设置声浪回调周期
|
|
1204
|
+
function setSoundLevelMonitorCycle(interval) {
|
|
1205
|
+
console.warn('[声浪周期]', interval);
|
|
1206
|
+
soundLevelMonitorCycle = interval;
|
|
1207
|
+
zg.setSoundLevelDelegate(true, soundLevelMonitorCycle);
|
|
1208
|
+
}
|
|
1209
|
+
function setMirrorStatus(mirror) {
|
|
1210
|
+
setVideoMirrorMode(mirror);
|
|
1211
|
+
}
|
|
1212
|
+
function getStreamType() {
|
|
1213
|
+
// NOTE 此接口 外层未被使用
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* @function 设置拉流镜像状态
|
|
1217
|
+
* @param { boolean } type true=开启 false=关闭
|
|
1218
|
+
* @return: Promise
|
|
1219
|
+
*/
|
|
1220
|
+
function setPlayViewMirror(mirror) {
|
|
1221
|
+
// 遍历所有的拉流streamview,逐个镜像
|
|
1222
|
+
Object.keys(streamIdToStreamView).forEach(streamId=> {
|
|
1223
|
+
try {
|
|
1224
|
+
const streamView = streamIdToStreamView[streamId];
|
|
1225
|
+
streamView.play(streamView.v.container, { mirror });
|
|
1226
|
+
} catch (error) { }
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* @function 是否推声音
|
|
1231
|
+
* @param mute:Boolean true/不推声音,false/推声音,必选
|
|
1232
|
+
* @return Promise | void
|
|
1233
|
+
*/
|
|
1234
|
+
function setMuteStreamAudio(mute) {
|
|
1235
|
+
if(localStream) {
|
|
1236
|
+
return zg.mutePublishStreamAudio(localStream, mute);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* @function 是否推画面
|
|
1241
|
+
* @param mute:Boolean true/不推画面,false/推画面,必选
|
|
1242
|
+
* @return Promise | void
|
|
1243
|
+
*/
|
|
1244
|
+
function setMuteStreamVideo() {
|
|
1245
|
+
if(localStream) {
|
|
1246
|
+
return zg.mutePublishStreamVideo(localStream, mute);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
function teacherStartLinkMic() {
|
|
1250
|
+
// NOTE 此接口 暂时不用实现
|
|
1251
|
+
}
|
|
1252
|
+
function teacherStopLinkMic() {
|
|
1253
|
+
// NOTE 此接口 暂时不用实现
|
|
1254
|
+
}
|
|
1255
|
+
function getSDKVersion() {
|
|
1256
|
+
return zg.getVersion();
|
|
1257
|
+
}
|
|
1258
|
+
function getCameraSupportedRes() {
|
|
1259
|
+
// TODO WEB需要创建流去确认,能创成则支持
|
|
1260
|
+
}
|
|
1261
|
+
function setVideoMirrorMode(mirror) {
|
|
1262
|
+
// localStream.stopVideo();
|
|
1263
|
+
localStream.playVideo(cameraConstraints.captureView, {mirror});
|
|
1264
|
+
}
|
|
1265
|
+
function startMultiScreen() {}
|
|
1266
|
+
function addListener() {
|
|
1267
|
+
console.warn('[注册监听]');
|
|
1268
|
+
// OnInitSDK
|
|
1269
|
+
// NOTE WEB没有此事件
|
|
1270
|
+
// OnLoginChannel
|
|
1271
|
+
zg.on('roomStateChanged', _onRoomStateChanged);
|
|
1272
|
+
// OnPublishStateUpdate
|
|
1273
|
+
zg.on('publisherStateUpdate', _onPublisherStateUpdate);
|
|
1274
|
+
// OnPublishQualityUpdate
|
|
1275
|
+
zg.on('publishQualityUpdate', _onPublishQualityUpdate); // 重要
|
|
1276
|
+
// OnCaptureSoundLevelUpdate
|
|
1277
|
+
zg.on('capturedSoundLevelUpdate', _onCapturedSoundLevelUpdate);
|
|
1278
|
+
// OnSoundLevelUpdate
|
|
1279
|
+
zg.on('soundLevelUpdate', _onSoundLevelUpdate); // 重要
|
|
1280
|
+
// OnPlayStateUpdate
|
|
1281
|
+
zg.on('playerStateUpdate', _onPlayerStateUpdate);
|
|
1282
|
+
// OnPlayQulityUpdate
|
|
1283
|
+
zg.on('playQualityUpdate', _onPlayQualityUpdate); // 重要
|
|
1284
|
+
// OnVideoDeviceStateChanged
|
|
1285
|
+
zg.on('videoDeviceStateChanged', _onVideoDeviceStateChanged);
|
|
1286
|
+
// OnAudioDeviceStateChanged
|
|
1287
|
+
zg.on('audioDeviceStateChanged', _onAudioDeviceStateChanged);
|
|
1288
|
+
// OnDeviceError
|
|
1289
|
+
zg.on('deviceError', _onDeviceError);
|
|
1290
|
+
// screenSharingEnded
|
|
1291
|
+
zg.on('screenSharingEnded', _onScreenSharingEnded);
|
|
1292
|
+
// OnAVKitEvent
|
|
1293
|
+
// OnAVEngineStop
|
|
1294
|
+
// OnMixStream
|
|
1295
|
+
// OnRenderRemoteVideoFirstFrame 渲染相关的事件在streamView上管理
|
|
1296
|
+
// OnRecvRemoteAudioFirstFrame 渲染相关的事件在streamView上管理
|
|
1297
|
+
// onRecvMediaSideInfo
|
|
1298
|
+
// zego_recovery_start
|
|
1299
|
+
// OnRelayCDNStateUpdate
|
|
1300
|
+
// OnCaptureVideoFirstFrame 渲染相关的事件在streamView上管理
|
|
1301
|
+
// OnKaDunEvent
|
|
1302
|
+
|
|
1303
|
+
// NOTE 原native代码里缺少流更新事件监听
|
|
1304
|
+
zg.on('roomStreamUpdate', _onRoomStreamUpdate);
|
|
1305
|
+
}
|
|
1306
|
+
function removerListener() {
|
|
1307
|
+
console.warn('[注销监听]');
|
|
1308
|
+
// OnInitSDK
|
|
1309
|
+
// NOTE WEB没有此事件
|
|
1310
|
+
// OnLoginChannel
|
|
1311
|
+
zg.off('roomStateChanged');
|
|
1312
|
+
// OnPublishStateUpdate
|
|
1313
|
+
zg.off('publisherStateUpdate');
|
|
1314
|
+
// OnPublishQualityUpdate
|
|
1315
|
+
zg.off('publishQualityUpdate'); // 重要
|
|
1316
|
+
// OnCaptureSoundLevelUpdate
|
|
1317
|
+
zg.off('capturedSoundLevelUpdate'); // 重要
|
|
1318
|
+
// OnSoundLevelUpdate
|
|
1319
|
+
zg.off('soundLevelUpdate'); // 重要
|
|
1320
|
+
// OnPlayStateUpdate
|
|
1321
|
+
zg.off('playerStateUpdate');
|
|
1322
|
+
// OnPlayQulityUpdate
|
|
1323
|
+
zg.off('playQualityUpdate'); // 重要
|
|
1324
|
+
// OnVideoDeviceStateChanged
|
|
1325
|
+
zg.off('videoDeviceStateChanged');
|
|
1326
|
+
// OnAudioDeviceStateChanged
|
|
1327
|
+
zg.off('audioDeviceStateChanged');
|
|
1328
|
+
// OnDeviceError
|
|
1329
|
+
zg.off('deviceError');
|
|
1330
|
+
// screenSharingEnded
|
|
1331
|
+
zg.off('screenSharingEnded');
|
|
1332
|
+
// OnAVKitEvent
|
|
1333
|
+
// OnAVEngineStop
|
|
1334
|
+
// OnMixStream
|
|
1335
|
+
// OnRenderRemoteVideoFirstFrame 渲染相关的事件在streamView上管理 重要
|
|
1336
|
+
// OnRecvRemoteAudioFirstFrame 渲染相关的事件在streamView上管理 重要
|
|
1337
|
+
// onRecvMediaSideInfo
|
|
1338
|
+
// zego_recovery_start
|
|
1339
|
+
// OnRelayCDNStateUpdate
|
|
1340
|
+
// OnCaptureVideoFirstFrame 渲染相关的事件在streamView上管理
|
|
1341
|
+
// OnKaDunEvent
|
|
1342
|
+
|
|
1343
|
+
// NOTE 原native代码里缺少流更新事件监听
|
|
1344
|
+
zg.off('roomStreamUpdate');
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
function _onRoomStateChanged(roomID, reason, errorCode, extendData) {
|
|
1348
|
+
console.warn('[房间状态回调]', roomID, reason, errorCode, extendData);
|
|
1349
|
+
if (reason == 'LOGINED') {
|
|
1350
|
+
hasLoginChannel = 1;
|
|
1351
|
+
}
|
|
1352
|
+
if (errorCode >= 1002050 && errorCode < 1002060) {
|
|
1353
|
+
defaultApi.writeLog('ZEGO::leaveRoom-- trigger by roomStateChange');
|
|
1354
|
+
window.zbztsdk.leaveRoom();
|
|
1355
|
+
}
|
|
1356
|
+
defaultApi.writeLog(`ZEGO::addListener-- OnLoginChannel: ${errorCode}`);
|
|
1357
|
+
}
|
|
1358
|
+
function _onPublisherStateUpdate(result) {
|
|
1359
|
+
const { state, streamID, errorCode, extendedData } = result;
|
|
1360
|
+
console.log('[推流状态回调]', result);
|
|
1361
|
+
// NOTE 状态码变化相关日志 待补充
|
|
1362
|
+
// NOTE 1. hasPushFlow: 推流成功后启动数据上报; window.zegoHasPushFlow: 加学生端加入房间消息; 当前都用不着
|
|
1363
|
+
if (state == 'PUBLISHING') {
|
|
1364
|
+
// 心跳开始
|
|
1365
|
+
if (!isFirstHeartBeatReport) {
|
|
1366
|
+
isFirstHeartBeatReport = true;
|
|
1367
|
+
heartBeatDataReport('start');
|
|
1368
|
+
}
|
|
1369
|
+
NOTICE.pushFlowSuccess({ code: 0, publish_streamid: streamID });
|
|
1370
|
+
}
|
|
1371
|
+
//
|
|
1372
|
+
let ReportArgs = { publish_rtc_streamid: streamID };
|
|
1373
|
+
dataReport.publishResult({
|
|
1374
|
+
code: errorCode,
|
|
1375
|
+
...ReportArgs
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
function _onPublishQualityUpdate(streamId, stats) {
|
|
1379
|
+
console.log('推流质量回调', streamId, stats);
|
|
1380
|
+
NOTICE.pushQuality({
|
|
1381
|
+
video: {
|
|
1382
|
+
streamId,
|
|
1383
|
+
bitrate: Math.round(stats.video.videoBitrate),
|
|
1384
|
+
fps: Math.round(stats.video.videoFPS)
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
NOTICE.pushLossAndDelay({
|
|
1388
|
+
userId: util.getUidByStreamId(streamId),
|
|
1389
|
+
delay: stats.currentRoundTripTime,
|
|
1390
|
+
lostrate: stats.video.videoPacketsLostRate
|
|
1391
|
+
});
|
|
1392
|
+
heartBeatDataReportCalc('onPublishQualityUpdate', stats, streamId);
|
|
1393
|
+
}
|
|
1394
|
+
function _onCapturedSoundLevelUpdate(soundLevel) {
|
|
1395
|
+
if (isNoticeMicVolumeZego) {
|
|
1396
|
+
NOTICE.captureMicVolumeChanged({
|
|
1397
|
+
volume: Math.round(soundLevel)
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
heartBeatDataReportObj.volume = heartBeatDataReportObj.volume + Math.round(soundLevel) + ',';
|
|
1401
|
+
}
|
|
1402
|
+
function _onSoundLevelUpdate(soundLevelList) {
|
|
1403
|
+
soundLevelList.forEach(item => {
|
|
1404
|
+
const cbData = {
|
|
1405
|
+
streamid: item.streamID,
|
|
1406
|
+
userId: util.getUidByStreamId(item.streamID),
|
|
1407
|
+
volume: Math.round(item.soundLevel)
|
|
1408
|
+
};
|
|
1409
|
+
NOTICE.playerVolumeChanged(cbData);
|
|
1410
|
+
NOTICE.volumeChange(cbData);
|
|
1411
|
+
if (streamIdRtcPlayerInfo[item.streamID]) {
|
|
1412
|
+
streamIdRtcPlayerInfo[item.streamID].volume = streamIdRtcPlayerInfo[item.streamID].volume + Math.round(item.soundLevel) + ',';
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
function _onPlayerStateUpdate(result) {
|
|
1417
|
+
// TODO
|
|
1418
|
+
const { state, streamID, errorCode, extendedData } = result;
|
|
1419
|
+
if (state == 'PLAYING') {
|
|
1420
|
+
console.log('成功拉取音视频流:', streamID);
|
|
1421
|
+
} else if (state == 'NO_PLAY') {
|
|
1422
|
+
console.log('未拉取音视频流');
|
|
1423
|
+
} else if (state == 'PLAY_REQUESTING') {
|
|
1424
|
+
console.log('请求拉取音视频流:', streamID);
|
|
1425
|
+
}
|
|
1426
|
+
console.log('错误码:', errorCode,' 额外信息:', extendedData);
|
|
1427
|
+
}
|
|
1428
|
+
function _onPlayQualityUpdate(streamID,stats) {
|
|
1429
|
+
console.log('拉流质量回调', streamID, stats);
|
|
1430
|
+
NOTICE.pullQuality({
|
|
1431
|
+
video: {
|
|
1432
|
+
streamId: streamID,
|
|
1433
|
+
userId: util.getUidByStreamId(streamID),
|
|
1434
|
+
bitrate: stats.video.videoBitrate,
|
|
1435
|
+
fps: stats.video.videoFPS,
|
|
1436
|
+
volume: stats.audio.audioLevel * 100 >> 0,
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
// console.log('拉流延迟丢包zego',_data);
|
|
1440
|
+
NOTICE.playLossAndDelay({
|
|
1441
|
+
userId: util.getUidByStreamId(streamID),
|
|
1442
|
+
delay: stats.currentRoundTripTime,
|
|
1443
|
+
lostrate: stats.video.videoPacketsLostRate
|
|
1444
|
+
});
|
|
1445
|
+
currStreamIdRtcPlayerInfo = streamIdRtcPlayerInfo[streamID]; // ???
|
|
1446
|
+
heartBeatDataReportCalc('onPlayQualityUpdate', stats, streamID);
|
|
1447
|
+
}
|
|
1448
|
+
function _onRoomStreamUpdate(roomID, updateType, streamList, extendedData) {
|
|
1449
|
+
console.warn('[房间流回调]', roomID, updateType, streamList, extendedData);
|
|
1450
|
+
}
|
|
1451
|
+
function _onVideoDeviceStateChanged(updateType, deviceInfo) {
|
|
1452
|
+
// NOTE 1. state 0=添加设备 1=移除设备
|
|
1453
|
+
const state = updateType == 'ADD'? 0: 1;
|
|
1454
|
+
const agrs = {
|
|
1455
|
+
// NOTE 2. 插设备,用新设备;拔设备,用默认设备
|
|
1456
|
+
deviceId: updateType == 'DELETE' ? '' : deviceInfo.deviceID,
|
|
1457
|
+
idx: 0,
|
|
1458
|
+
operationType: 'hotPlug',
|
|
1459
|
+
deviceState: state,
|
|
1460
|
+
changedDeviceId: deviceInfo.deviceID
|
|
1461
|
+
};
|
|
1462
|
+
setVideoDevice(agrs);
|
|
1463
|
+
}
|
|
1464
|
+
function _onAudioDeviceStateChanged(updateType, deviceType, deviceInfo) {
|
|
1465
|
+
const state = updateType == 'ADD'? 0: 1;
|
|
1466
|
+
const agrs = {
|
|
1467
|
+
// NOTE 2. 插设备,用新设备;拔设备,用默认设备
|
|
1468
|
+
deviceId: updateType == 'DELETE' ? '' : deviceInfo.deviceID,
|
|
1469
|
+
idx: 0,
|
|
1470
|
+
operationType: 'hotPlug',
|
|
1471
|
+
deviceState: state,
|
|
1472
|
+
changedDeviceId: deviceInfo.deviceID
|
|
1473
|
+
};
|
|
1474
|
+
if(deviceType == 'Input') { // microphone
|
|
1475
|
+
setMicrophoneDevice(agrs);
|
|
1476
|
+
}else { // speaker
|
|
1477
|
+
setSpeakerDevice(agrs);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
function _onDeviceError(errorCode, deviceName) {
|
|
1482
|
+
defaultApi.writeLog(`avsdk ZEGO:: OnDeviceError ${deviceName} ${errorCode}`);
|
|
1483
|
+
dataReport.deviceError({ deviceName, errorCode });
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
function _onScreenSharingEnded() {
|
|
1487
|
+
defaultApi.writeLog('avsdk ZEGO:: _onScreenSharingEnded');
|
|
1488
|
+
zg.stopPublishingStream(screenStreamId);
|
|
1489
|
+
zg.destroyStream(screenStream);
|
|
1490
|
+
NOTICE.screenShareEnded();
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
function loadZego() {}
|
|
1494
|
+
|
|
1495
|
+
//推流字段
|
|
1496
|
+
function resetHeartBeatDataReportObj() {
|
|
1497
|
+
heartBeatDataReportObj = {
|
|
1498
|
+
ctime: [],
|
|
1499
|
+
push_type: 'none',
|
|
1500
|
+
// video_fps: 0,
|
|
1501
|
+
// video_bitrate: 0,
|
|
1502
|
+
// audio_fps: 0,
|
|
1503
|
+
// audio_bitrate: 0,
|
|
1504
|
+
video_fps: [],
|
|
1505
|
+
video_bitrate: [],
|
|
1506
|
+
audio_fps: [],
|
|
1507
|
+
audio_bitrate: [],
|
|
1508
|
+
push_loss: [],
|
|
1509
|
+
push_delay: [],
|
|
1510
|
+
// count: 0,
|
|
1511
|
+
volume: ''
|
|
1512
|
+
};
|
|
1513
|
+
};
|
|
1514
|
+
//记录拉流类型,用作数据上报
|
|
1515
|
+
function resetStreamIdRtcPlayerInfo1(streamId) {
|
|
1516
|
+
streamIdRtcPlayerInfo1[streamId] = {
|
|
1517
|
+
audio_type: false,
|
|
1518
|
+
video_type: false,
|
|
1519
|
+
stream_type: 'none'
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
//拉流字段
|
|
1523
|
+
function resetStreamIdRtcPlayerInfo(streamId) {
|
|
1524
|
+
streamIdRtcPlayerInfo[streamId] = {
|
|
1525
|
+
pull_uid: util.getUidByStreamId(streamId),
|
|
1526
|
+
streamid: streamId,
|
|
1527
|
+
ctime: [],
|
|
1528
|
+
pull_type: streamIdRtcPlayerInfo1[streamId].stream_type,
|
|
1529
|
+
volume: '',
|
|
1530
|
+
// 平均值
|
|
1531
|
+
video_fps: [],
|
|
1532
|
+
video_bitrate: [],
|
|
1533
|
+
audio_fps: [],
|
|
1534
|
+
audio_bitrate: [],
|
|
1535
|
+
pull_loss: [],
|
|
1536
|
+
pull_delay: [],
|
|
1537
|
+
//音画不同步字段
|
|
1538
|
+
avtimestampdiff: [],
|
|
1539
|
+
// 累加
|
|
1540
|
+
audio_ifg: 0,
|
|
1541
|
+
video_ifg: 0
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
function heartBeatDataReport(type) {
|
|
1545
|
+
try {
|
|
1546
|
+
if (type === 'start' && !heartBeatDataReportTimer) {
|
|
1547
|
+
_heartBeatDataReport();
|
|
1548
|
+
heartBeatDataReportTimer = setInterval(() => {
|
|
1549
|
+
_heartBeatDataReport();
|
|
1550
|
+
}, 30 * 1000);
|
|
1551
|
+
}
|
|
1552
|
+
if (type === 'stop') {
|
|
1553
|
+
clearInterval(heartBeatDataReportTimer);
|
|
1554
|
+
heartBeatDataReportTimer = null;
|
|
1555
|
+
}
|
|
1556
|
+
} catch (error) {
|
|
1557
|
+
console.log(error);
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1560
|
+
|
|
1561
|
+
function _heartBeatDataReport() {
|
|
1562
|
+
let rateCount = 0;
|
|
1563
|
+
let rateTimer = setInterval(async () => {
|
|
1564
|
+
rateCount++;
|
|
1565
|
+
// NOTE 30s后上报?
|
|
1566
|
+
if (rateCount >= 3) {
|
|
1567
|
+
const pullInfo = [];
|
|
1568
|
+
Object.keys(streamIdRtcPlayerInfo).forEach(streamid => {
|
|
1569
|
+
heartBeatRealKeys.forEach(realKey => {
|
|
1570
|
+
if (!streamIdRtcPlayerInfo[streamid].hasOwnProperty(realKey)) {
|
|
1571
|
+
streamIdRtcPlayerInfo[streamid][realKey] = [];
|
|
1572
|
+
}
|
|
1573
|
+
});
|
|
1574
|
+
|
|
1575
|
+
//获取拉流类型,后期可写为函数提出去
|
|
1576
|
+
if (streamIdRtcPlayerInfo1[streamid].audio_type && streamIdRtcPlayerInfo1[streamid].video_type) {
|
|
1577
|
+
streamIdRtcPlayerInfo1[streamid].stream_type = 'both';
|
|
1578
|
+
} else if (!streamIdRtcPlayerInfo1[streamid].audio_type && streamIdRtcPlayerInfo1[streamid].video_type) {
|
|
1579
|
+
streamIdRtcPlayerInfo1[streamid].stream_type = 'video';
|
|
1580
|
+
} else if (streamIdRtcPlayerInfo1[streamid].audio_type && !streamIdRtcPlayerInfo1[streamid].video_type) {
|
|
1581
|
+
streamIdRtcPlayerInfo1[streamid].stream_type = 'audio';
|
|
1582
|
+
} else {
|
|
1583
|
+
streamIdRtcPlayerInfo1[streamid].stream_type = 'none';
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
pullInfo.push({
|
|
1587
|
+
streamid,
|
|
1588
|
+
...streamIdRtcPlayerInfo[streamid],
|
|
1589
|
+
pull_type: streamIdRtcPlayerInfo1[streamid].stream_type,
|
|
1590
|
+
volume: streamIdRtcPlayerInfo[streamid].volume.slice(0, streamIdRtcPlayerInfo[streamid].volume.length - 1)
|
|
1591
|
+
});
|
|
1592
|
+
resetStreamIdRtcPlayerInfo(streamid);
|
|
1593
|
+
});
|
|
1594
|
+
if (isFirstHeartBeatReport && rateCount > 0) {
|
|
1595
|
+
try {
|
|
1596
|
+
//静音推流时过滤掉音频帧率和码率,上报为0;
|
|
1597
|
+
|
|
1598
|
+
//获取推流类型,后期可写为函数提出去
|
|
1599
|
+
// TODO
|
|
1600
|
+
// if (zbysdk.deviceStatus.camera && zbysdk.deviceStatus.microphone) {
|
|
1601
|
+
// zbysdk.deviceStatus.stream_type = 'both';
|
|
1602
|
+
// } else if (!zbysdk.deviceStatus.camera && zbysdk.deviceStatus.microphone) {
|
|
1603
|
+
// zbysdk.deviceStatus.stream_type = 'audio';
|
|
1604
|
+
// } else if (zbysdk.deviceStatus.camera && !zbysdk.deviceStatus.microphone) {
|
|
1605
|
+
// zbysdk.deviceStatus.stream_type = 'video';
|
|
1606
|
+
// } else {
|
|
1607
|
+
// zbysdk.deviceStatus.stream_type = 'none';
|
|
1608
|
+
// };
|
|
1609
|
+
// defaultApi.writeLog(`push_type_zego,camera: ${zbysdk.deviceStatus.camera},microphone: ${zbysdk.deviceStatus.microphone},type: ${zbysdk.deviceStatus.stream_type},a_fps: ${dataZegoCapture.afps}, a_bit: ${dataZegoCapture.akbps}, v_fps: ${dataZegoCapture.fps}, v_bit: ${dataZegoCapture.kbps}`);
|
|
1610
|
+
|
|
1611
|
+
// dataReport.heartbeat({
|
|
1612
|
+
// ...{ ...heartBeatDataReportObj, push_type: zbysdk.deviceStatus.stream_type, volume: heartBeatDataReportObj.volume.slice(0, heartBeatDataReportObj.volume.length - 1) },
|
|
1613
|
+
// pull_info: pullInfo,
|
|
1614
|
+
// });
|
|
1615
|
+
} catch (e) {
|
|
1616
|
+
console.log(e);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
resetHeartBeatDataReportObj();
|
|
1620
|
+
rateCount = 0;
|
|
1621
|
+
|
|
1622
|
+
clearInterval(rateTimer);
|
|
1623
|
+
}
|
|
1624
|
+
}, 10 * 1000);
|
|
1625
|
+
};
|
|
1626
|
+
|
|
1627
|
+
function heartBeatDataReportCalc(name, stats, streamId) {
|
|
1628
|
+
const audioFPS = parseFloat(parseInt(stats.audio.audioFPS));
|
|
1629
|
+
const audioBitrate = parseFloat(parseInt(stats.audio.audioBitrate));
|
|
1630
|
+
const videoFPS = parseFloat(parseInt(stats.video.videoFPS));
|
|
1631
|
+
const videoBitrate = parseFloat(parseInt(stats.video.videoBitrate));
|
|
1632
|
+
let info = {};
|
|
1633
|
+
if(name == 'onPublishQualityUpdate') {
|
|
1634
|
+
info = heartBeatDataReportObj;
|
|
1635
|
+
dataZegoCapture = stats;
|
|
1636
|
+
info.push_loss.push(stats.video.videoPacketsLostRate);
|
|
1637
|
+
info.push_delay.push(stats.currentRoundTripTime);
|
|
1638
|
+
} else if(name == 'onPlayQualityUpdate') {
|
|
1639
|
+
info = streamIdRtcPlayerInfo[streamId];
|
|
1640
|
+
// streamIdRtcPlayerInfo[streamId].avtimestampdiff.push(_d.avTimestampDiff); // 时间差??? TODO
|
|
1641
|
+
info.pull_loss.push(stats.video.videoPacketsLostRate);
|
|
1642
|
+
info.pull_delay.push(stats.currentRoundTripTime);
|
|
1643
|
+
}
|
|
1644
|
+
info.audio_fps.push(audioFPS);
|
|
1645
|
+
info.audio_bitrate.push(audioBitrate);
|
|
1646
|
+
info.video_fps.push(videoFPS);
|
|
1647
|
+
info.video_bitrate.push(videoBitrate);
|
|
1648
|
+
|
|
1649
|
+
info.ctime.push(Math.round((new Date().getTime() + dataReport.timestamp) / 1000));
|
|
1650
|
+
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
export default {
|
|
1654
|
+
startEngine,
|
|
1655
|
+
destroyEngine,
|
|
1656
|
+
setDefaultDevice,
|
|
1657
|
+
getVideoDeviceList,
|
|
1658
|
+
setVideoDevice,
|
|
1659
|
+
enableCamera,
|
|
1660
|
+
enableMic,
|
|
1661
|
+
setAudioSpeakerCapture, // done
|
|
1662
|
+
getAudioDeviceList,
|
|
1663
|
+
setAudioDevice,
|
|
1664
|
+
getSpeakerDeviceList,
|
|
1665
|
+
setSpeakerDevice,
|
|
1666
|
+
getCurrentSpeakerDevice,
|
|
1667
|
+
getSpeakerDeviceVolume,
|
|
1668
|
+
setSpeakerDeviceVolume,
|
|
1669
|
+
setSpeakerDeviceMute,
|
|
1670
|
+
getMicrophoneDeviceList,
|
|
1671
|
+
setMicrophoneDevice,
|
|
1672
|
+
getMicDeviceVolume,
|
|
1673
|
+
setMicDeviceVolume,
|
|
1674
|
+
setMicDeviceMute,
|
|
1675
|
+
getSpeakerSimpleVolume,
|
|
1676
|
+
setSpeakerSimpleVolume,
|
|
1677
|
+
setSpeakerSimpleMute,
|
|
1678
|
+
setPreviewView, // native端是先设置视图再预览,WEB不需要设置视图,无此功能
|
|
1679
|
+
startPreview,
|
|
1680
|
+
startLocalOrRemotePreview,
|
|
1681
|
+
setVideoFPS,
|
|
1682
|
+
setVideoBitrate,
|
|
1683
|
+
setAudioBitrate,
|
|
1684
|
+
setVideoCaptureResolution,
|
|
1685
|
+
setCameraParam,
|
|
1686
|
+
setVideoEncodeResolution,
|
|
1687
|
+
init,
|
|
1688
|
+
startPublish2,
|
|
1689
|
+
stopPublish,
|
|
1690
|
+
initPullFlow,
|
|
1691
|
+
playStream,
|
|
1692
|
+
stopPlayStream,
|
|
1693
|
+
stopAllPlayStream,
|
|
1694
|
+
leaveRoom,
|
|
1695
|
+
playerSnapShot,
|
|
1696
|
+
activateAudioPlayStream,
|
|
1697
|
+
pullAudioFlow,
|
|
1698
|
+
activateVideoPlayStream,
|
|
1699
|
+
setAudioVolumeNotify, // native 监听系统设备音量变化开关,WEB无此接口
|
|
1700
|
+
stopAudioVolumeNotify,
|
|
1701
|
+
openMicVolumeCb,
|
|
1702
|
+
startSoundLevelMonitor,
|
|
1703
|
+
stopSoundLevelMonitor,
|
|
1704
|
+
setSoundLevelMonitorCycle,
|
|
1705
|
+
setMirrorStatus,
|
|
1706
|
+
getStreamType,
|
|
1707
|
+
setPlayViewMirror,
|
|
1708
|
+
setMuteStreamAudio,
|
|
1709
|
+
setMuteStreamVideo,
|
|
1710
|
+
teacherStartLinkMic,
|
|
1711
|
+
teacherStopLinkMic, // 不要
|
|
1712
|
+
getSDKVersion,
|
|
1713
|
+
getCameraSupportedRes,
|
|
1714
|
+
setVideoMirrorMode,
|
|
1715
|
+
startMultiScreen,
|
|
1716
|
+
addListener,
|
|
1717
|
+
};
|
|
1718
|
+
|