@tencentcloud/trtc-cloud-wx 0.0.20-beta.3 → 0.0.20-beta.5

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 (56) hide show
  1. package/.babelrc +6 -0
  2. package/.eslintrc.json +129 -0
  3. package/build/chokidar.js +19 -0
  4. package/build/clear.js +24 -0
  5. package/build/copy.js +24 -0
  6. package/build/copy_to_roomkit.js +19 -0
  7. package/dist/package.json +15 -0
  8. package/{trtc-cloud-wx.js → dist/trtc-cloud-wx.js} +13 -4
  9. package/docs/API/TRTCCloud.html +4353 -0
  10. package/docs/API/index.html +98 -0
  11. package/docs/API/scripts/add-toc.js +57 -0
  12. package/docs/API/scripts/collapse.js +20 -0
  13. package/docs/API/scripts/highlight/highlight.min.js +1282 -0
  14. package/docs/API/scripts/highlight/highlightjs-line-numbers.min.js +1 -0
  15. package/docs/API/scripts/linenumber.js +25 -0
  16. package/docs/API/scripts/nav.js +12 -0
  17. package/docs/API/scripts/polyfill.js +4 -0
  18. package/docs/API/scripts/prettify/Apache-License-2.0.txt +202 -0
  19. package/docs/API/scripts/prettify/lang-css.js +2 -0
  20. package/docs/API/scripts/prettify/prettify.js +28 -0
  21. package/docs/API/scripts/search.js +83 -0
  22. package/docs/API/styles/font.css +81 -0
  23. package/docs/API/styles/fonts/JTURjIg1_i6t8kCHKm45_dJE3g3D_vx3rCubqg.woff2 +0 -0
  24. package/docs/API/styles/fonts/JTURjIg1_i6t8kCHKm45_dJE3gTD_vx3rCubqg.woff2 +0 -0
  25. package/docs/API/styles/fonts/JTURjIg1_i6t8kCHKm45_dJE3gbD_vx3rCubqg.woff2 +0 -0
  26. package/docs/API/styles/fonts/JTURjIg1_i6t8kCHKm45_dJE3gfD_vx3rCubqg.woff2 +0 -0
  27. package/docs/API/styles/fonts/JTURjIg1_i6t8kCHKm45_dJE3gnD_vx3rCs.woff2 +0 -0
  28. package/docs/API/styles/fonts/JTUSjIg1_i6t8kCHKm459W1hyyTh89ZNpQ.woff2 +0 -0
  29. package/docs/API/styles/fonts/JTUSjIg1_i6t8kCHKm459WRhyyTh89ZNpQ.woff2 +0 -0
  30. package/docs/API/styles/fonts/JTUSjIg1_i6t8kCHKm459WZhyyTh89ZNpQ.woff2 +0 -0
  31. package/docs/API/styles/fonts/JTUSjIg1_i6t8kCHKm459WdhyyTh89ZNpQ.woff2 +0 -0
  32. package/docs/API/styles/fonts/JTUSjIg1_i6t8kCHKm459WlhyyTh89Y.woff2 +0 -0
  33. package/docs/API/styles/highlight/highlight.min.css +26 -0
  34. package/docs/API/styles/highlight/rainbow.min.css +1 -0
  35. package/docs/API/styles/jsdoc.css +684 -0
  36. package/docs/API/styles/prettify.css +79 -0
  37. package/docs/API/styles/toc.css +44 -0
  38. package/docs/API/tutorial-00-guideline.html +81 -0
  39. package/docs/doc-src/home.md +7 -0
  40. package/docs/doc-src/tutorials/00-guideline.md +1 -0
  41. package/docs/doc-src/tutorials/tutorials.json +5 -0
  42. package/jsdoc.json +43 -0
  43. package/package.json +44 -3
  44. package/rollup.config.js +19 -0
  45. package/sdk_publish.bash +5 -0
  46. package/src/TaskMachine.ts +372 -0
  47. package/src/index.ts +1067 -0
  48. package/src/interface/index.ts +44 -0
  49. package/src/interface/types.ts +85 -0
  50. package/src/log/logger.ts +103 -0
  51. package/src/types.d.ts +1 -0
  52. package/src/utils/common.ts +50 -0
  53. package/src/utils/index.ts +2 -0
  54. package/src/utils/translate.ts +125 -0
  55. package/tsconfig.json +15 -0
  56. package/typedoc.json +21 -0
package/src/index.ts ADDED
@@ -0,0 +1,1067 @@
1
+ import EventEmitter from 'eventemitter3'
2
+ import TRTC from 'trtc-wx-sdk'
3
+ import {
4
+ TRTCParams,
5
+ TRTCAppScene,
6
+ TRTCRoleType,
7
+ TRTCVideoStreamType,
8
+ TRTCVideoEncParam,
9
+ TRTCRenderParams,
10
+ TRTCAudioQuality,
11
+ TRTCVolumeInfo,
12
+ TRTCBeautyStyle,
13
+ AudioMusicParam,
14
+ } from './interface'
15
+ import {
16
+ setHandle, Handletype, TaskQueueEvent, taskMachine
17
+ } from './TaskMachine'
18
+ import {
19
+ translateTRTCAppScene,
20
+ translateTRTCStreamId,
21
+ translateTRTCVideoMirrorType,
22
+ translateTRTCVideoResolution,
23
+ translateTRTCVideoRotation,
24
+ translateVideoFillMod,
25
+ uniqueFunc,
26
+ isNumber,
27
+ safelyParse
28
+ } from './utils'
29
+
30
+ import {logger} from './log/logger'
31
+
32
+ import packageJson from '../package.json' // 假设 package.json 文件在项目根目录下
33
+
34
+ export * from './interface'
35
+ export * from './utils/translate'
36
+
37
+ /**
38
+ * TRTCCloud
39
+ * @interface
40
+ */
41
+ export class TRTCCloud {
42
+ static instance;
43
+
44
+ public version = packageJson.version;
45
+
46
+ // 内部使用,用于调用接口时UI测监听,完成剩余逻辑
47
+ public InterfaceEventEmitter = new EventEmitter();
48
+
49
+ // 外部使用,用户监听回调事件
50
+ private EventEmitter = new EventEmitter();
51
+
52
+ public trtc;
53
+
54
+ public TRTC_EVENT;
55
+
56
+ private role = TRTCRoleType.TRTCRoleAnchor;
57
+
58
+ private scene: TRTCAppScene;
59
+
60
+ public userId = '';
61
+
62
+ private isEnterRoom = false;
63
+
64
+ private isVideoMuted = false;
65
+
66
+ private isOpenCamera = false;
67
+
68
+ private audioVolumeEvaluation = 0;
69
+
70
+ private allTimer: Record<string, NodeJS.Timer> = {};
71
+
72
+ private renderMap = new Map();
73
+
74
+ public logger = logger;
75
+
76
+ // private handleAudioVolumeUpdate: (userVolumes: Array<TRTCVolumeInfo>) => void;
77
+
78
+ constructor() {
79
+ this.init()
80
+ }
81
+
82
+ /**
83
+ * 获取 TRTCCloud 实例(单例模式)
84
+ * @category Base
85
+ */
86
+ static getTRTCShareInstance(): TRTCCloud {
87
+ if (!TRTCCloud.instance) {
88
+ TRTCCloud.instance = new TRTCCloud()
89
+ }
90
+ return TRTCCloud.instance
91
+ }
92
+
93
+ /**
94
+ * 销毁 TRTCCloud 实例(单例模式)
95
+ * @category Base
96
+ */
97
+ static destroyTRTCShareInstance(): void {
98
+ if (!TRTCCloud.instance) return
99
+ TRTCCloud.instance.destroy()
100
+ TRTCCloud.instance = null
101
+ }
102
+
103
+ getSDKVersion(): string {
104
+ return this.version
105
+ }
106
+
107
+ private destroy(): void {
108
+ this.offTRTCEvent()
109
+ this.EventEmitter.removeAllListeners()
110
+ this.InterfaceEventEmitter.removeAllListeners()
111
+ this.trtc.exitRoom()
112
+ }
113
+
114
+ private init(): void {
115
+ this.trtc = new TRTC(this)
116
+ this.trtc.setLogLevel(3)
117
+ this.TRTC_EVENT = this.trtc.EVENT
118
+ this.bindTRTCEvent()
119
+ this.bindComponentEvent()
120
+ this.handleNetworkQuality = this.getHandleNetworkQuality(2000)
121
+ }
122
+
123
+ private reset(): void {
124
+ this.role = TRTCRoleType.TRTCRoleAnchor
125
+ this.userId = ''
126
+ this.isEnterRoom = false
127
+ this.isVideoMuted = false
128
+ this.isOpenCamera = false
129
+ taskMachine.reset()
130
+ Object.keys(this.allTimer).forEach((key) => {
131
+ clearInterval(this.allTimer[key])
132
+ this.allTimer[key] = null
133
+ })
134
+ }
135
+
136
+ private bindComponentEvent(): void {
137
+ this.InterfaceEventEmitter.on('pusherDomReady', (isReady: boolean) => {
138
+ taskMachine.setPusherDomReady(isReady)
139
+ if (isReady) {
140
+ this.trtc.createPusher({})
141
+ taskMachine.send(TaskQueueEvent.SETPROCESS)
142
+ } else {
143
+ if (this.isEnterRoom) {
144
+ this.exitRoom()
145
+ }
146
+ taskMachine.send(TaskQueueEvent.SETDONE)
147
+ }
148
+ })
149
+
150
+ this.InterfaceEventEmitter.on('playerDomReady', ({isReady, view}) => {
151
+ taskMachine.setPlayerDomReady(view, isReady)
152
+ if (isReady) {
153
+ taskMachine.send(TaskQueueEvent.SETPROCESS, view)
154
+ } else {
155
+ taskMachine.send(TaskQueueEvent.SETDONE, view)
156
+ }
157
+ })
158
+ }
159
+
160
+ private bindTRTCEvent(): void {
161
+ this.trtc.on(this.TRTC_EVENT.LOCAL_LEAVE, (event) => {
162
+ // todo 第二个参数为进房耗时 此处调用start的时候处理
163
+ // this.emit('onEnterRoom', 0)
164
+ })
165
+ this.trtc.on(this.TRTC_EVENT.ERROR, (event) => {
166
+ const {code, message} = event.data
167
+ this.emit('onError', code, message)
168
+ })
169
+ this.trtc.on(this.TRTC_EVENT.REMOTE_USER_JOIN, (event) => {
170
+ const {userID} = event.data
171
+ this.emit('onRemoteUserEnterRoom', userID)
172
+ })
173
+ // 远端用户退出
174
+ this.trtc.on(this.TRTC_EVENT.REMOTE_USER_LEAVE, (event) => {
175
+ const {userID, playerList} = event.data
176
+ this.InterfaceEventEmitter.emit('onRemoteUserLeaveRoom', userID, 0)
177
+ this.emit('onUserVideoAvailable', userID, 0)
178
+ this.emit('onUserSubStreamAvailable', userID, 0)
179
+ this.emit('onRemoteUserLeaveRoom', userID, 0)
180
+ })
181
+ // 远端用户推送视频
182
+ this.trtc.on(this.TRTC_EVENT.REMOTE_VIDEO_ADD, (event) => {
183
+ const {player} = event.data
184
+ this.emit(player.streamType === 'aux' ? 'onUserSubStreamAvailable' : 'onUserVideoAvailable', player.userID, 1)
185
+ })
186
+ // 远端用户取消推送视频
187
+ this.trtc.on(this.TRTC_EVENT.REMOTE_VIDEO_REMOVE, (event) => {
188
+ const {player} = event.data
189
+ this.emit(player.streamType === 'aux' ? 'onUserSubStreamAvailable' : 'onUserVideoAvailable', player.userID, 0)
190
+ })
191
+ // 远端用户推送音频
192
+ this.trtc.on(this.TRTC_EVENT.REMOTE_AUDIO_ADD, (event) => {
193
+ const {player} = event.data
194
+ this.emit('onUserAudioAvailable', player.userID, 1)
195
+ })
196
+ // 远端用户取消推送音频
197
+ this.trtc.on(this.TRTC_EVENT.REMOTE_AUDIO_REMOVE, (event) => {
198
+ const {player} = event.data
199
+ this.emit('onUserAudioAvailable', player.userID, 0)
200
+ })
201
+ this.trtc.on(this.TRTC_EVENT.REMOTE_AUDIO_VOLUME_UPDATE, (event) => {
202
+ const {playerList} = event.data
203
+ const userVolumes = playerList.map((player) => ({
204
+ userId: player.userID,
205
+ volume: player.volume,
206
+ }))
207
+ this.handleAudioVolumeUpdate(userVolumes)
208
+ })
209
+ this.trtc.on(this.TRTC_EVENT.LOCAL_AUDIO_VOLUME_UPDATE, (event) => {
210
+ const {pusher} = event.data
211
+ const userVolumes = [
212
+ {
213
+ userId: pusher.userID,
214
+ volume: pusher.volume,
215
+ },
216
+ ]
217
+ this.handleAudioVolumeUpdate(userVolumes)
218
+ })
219
+ this.trtc.on(this.TRTC_EVENT.LOCAL_NET_STATE_UPDATE, (event) => {
220
+ const {pusher} = event.data
221
+ this.handleNetworkQuality({pusher})
222
+ })
223
+ this.trtc.on(this.TRTC_EVENT.REMOTE_NET_STATE_UPDATE, (event) => {
224
+ const {playerList} = event.data
225
+ this.handleNetworkQuality({playerList})
226
+ })
227
+ }
228
+
229
+ private offTRTCEvent(): void {
230
+ this.trtc.off(this.TRTC_EVENT.LOCAL_LEAVE)
231
+ this.trtc.off(this.TRTC_EVENT.ERROR)
232
+ this.trtc.off(this.TRTC_EVENT.REMOTE_USER_JOIN)
233
+ this.trtc.off(this.TRTC_EVENT.REMOTE_USER_LEAVE)
234
+ this.trtc.off(this.TRTC_EVENT.REMOTE_VIDEO_ADD)
235
+ this.trtc.off(this.TRTC_EVENT.REMOTE_VIDEO_REMOVE)
236
+ this.trtc.off(this.TRTC_EVENT.REMOTE_AUDIO_ADD)
237
+ this.trtc.off(this.TRTC_EVENT.REMOTE_AUDIO_REMOVE)
238
+ this.trtc.off(this.TRTC_EVENT.REMOTE_AUDIO_VOLUME_UPDATE)
239
+ this.trtc.off(this.TRTC_EVENT.REMOTE_NET_STATE_UPDATE)
240
+ }
241
+
242
+ private getHandleAudioVolumeUpdate(
243
+ interval: number
244
+ ): (userVolumes: Array<TRTCVolumeInfo>) => void {
245
+ if (this.allTimer?.AudioVolume) {
246
+ clearInterval(this.allTimer.AudioVolume)
247
+ this.allTimer.AudioVolume = null
248
+ }
249
+ if (interval === 0) return (): void => {}
250
+ let tempUserVolumes = []
251
+ const filterUselessItem = function (userId: string): void {
252
+ tempUserVolumes = tempUserVolumes.filter(userVolume => userVolume.userId !== userId)
253
+ }
254
+ this.InterfaceEventEmitter.off('onRemoteUserLeaveRoom') // 防止重复监听
255
+ this.InterfaceEventEmitter.on('onRemoteUserLeaveRoom', filterUselessItem, this.getHandleAudioVolumeUpdate)
256
+ return (userVolumes: Array<TRTCVolumeInfo>): void => {
257
+ tempUserVolumes = uniqueFunc(
258
+ [...userVolumes, ...tempUserVolumes],
259
+ 'userId'
260
+ )
261
+ if (this.allTimer.AudioVolume) return
262
+ const timer = setInterval(() => {
263
+ this.emit(
264
+ 'onUserVoiceVolume',
265
+ tempUserVolumes,
266
+ tempUserVolumes.length,
267
+ 0 // todo 此参数无用,暂时废弃
268
+ )
269
+ }, interval)
270
+ this.allTimer.AudioVolume = timer
271
+ }
272
+ }
273
+
274
+ private handleAudioVolumeUpdate(userVolumes: Array<TRTCVolumeInfo>): void {}
275
+
276
+ private getHandleNetworkQuality(
277
+ interval: number
278
+ ): (data: {
279
+ pusher?: Record<string, unknown>;
280
+ playerList?: Array<Record<string, unknown>>;
281
+ }) => void {
282
+ if (this.allTimer?.networkQuality) {
283
+ clearInterval(this.allTimer.networkQuality)
284
+ this.allTimer.networkQuality = null
285
+ }
286
+ if (interval === 0) return (): void => {}
287
+ const resultQuality = {localQuality: null, remoteQuality: []}
288
+ this.on('onRemoteUserLeaveRoom', (userId) => {
289
+ resultQuality.remoteQuality = resultQuality.remoteQuality.filter(quality => quality.userId !== userId)
290
+ }, this)
291
+
292
+ return (data): void => {
293
+ const {pusher, playerList} = data
294
+ if (pusher) resultQuality.localQuality = {userId: pusher.userID, quality: pusher.netStatus}
295
+ if (playerList) {
296
+ resultQuality.remoteQuality = playerList.map(player => ({
297
+ userId: player.userID,
298
+ quality: player.netStatus
299
+ }))
300
+ }
301
+ if (this.allTimer.networkQuality) return
302
+ const timer = setInterval(() => {
303
+ this.emit('onNetworkQuality', resultQuality.localQuality, resultQuality.remoteQuality)
304
+ }, interval)
305
+ this.allTimer.networkQuality = timer
306
+ }
307
+ }
308
+
309
+ private handleNetworkQuality(quality: {
310
+ pusher?: Record<string, unknown>;
311
+ playerList?: Array<Record<string, unknown>>;
312
+ }): void {}
313
+
314
+ /**
315
+ * @category Base
316
+ */
317
+ on(eventName, handler, context): void {
318
+ this.EventEmitter.on(eventName, handler, context)
319
+ }
320
+
321
+ /**
322
+ * @category Base
323
+ */
324
+ off(eventName, handler, context): void {
325
+ this.EventEmitter.off(eventName, handler, context)
326
+ }
327
+
328
+ /**
329
+ * @category Base
330
+ */
331
+ emit(eventName, ...args): void {
332
+ this.EventEmitter.emit(eventName, ...args)
333
+ }
334
+
335
+ /**
336
+ * @category 房间
337
+ */
338
+ async enterRoom(params: TRTCParams, scene: TRTCAppScene): Promise<void> {
339
+ const startTime = new Date().getTime()
340
+ const {
341
+ sdkAppId,
342
+ userId,
343
+ userSig,
344
+ roomId,
345
+ strRoomId,
346
+ role,
347
+ privateMapKey,
348
+ } = params
349
+ logger.setInfo({sdkAppId, userId, roomId: strRoomId})
350
+ logger.info('enterRoom with options: ', JSON.stringify(params), scene)
351
+ this.userId = userId
352
+ this.isEnterRoom = true
353
+ await this.setAttributes({
354
+ params: {
355
+ sdkAppID: sdkAppId, // 您的腾讯云账号
356
+ userID: userId, // 当前进房用户的userID
357
+ userSig, // 您服务端生成的userSig
358
+ roomID: roomId, // 您进房的房间号,
359
+ strRoomID: strRoomId,
360
+ role,
361
+ privateMapKey,
362
+ scene: translateTRTCAppScene(scene),
363
+ enableMic: false, // 进房默认开启音频上行
364
+ enableCamera: false, // 进房默认开启视频上行
365
+ videoPreview: false,
366
+ }
367
+ }, 'enterRoom')
368
+ this.trtc.getPusherInstance().start({
369
+ success: async () => {
370
+ logger.info('enterRoom success')
371
+ this.scene = scene
372
+ const endTime = new Date().getTime()
373
+ this.emit('onEnterRoom', endTime - startTime)
374
+ if (this.trtc.getPusherAttributes().videoPreview === true) {
375
+ // 如果进房前有打开摄像头,需要开启视频上行,并抛出 onSendFirstLocalVideoFrame 事件
376
+ await this.setAttributes(
377
+ {
378
+ params: {
379
+ videoPreview: false,
380
+ enableCamera: true,
381
+ }
382
+ },
383
+ 'other'
384
+ )
385
+ this.emit(
386
+ 'onSendFirstLocalVideoFrame',
387
+ TRTCVideoStreamType.TRTCVideoStreamTypeBig,
388
+ )
389
+ }
390
+ },
391
+ fail: () => {
392
+ this.isEnterRoom = false
393
+ logger.info('enterRoom fail')
394
+ this.emit('onEnterRoom', -1)
395
+ },
396
+ })
397
+ }
398
+
399
+ /**
400
+ * @category 房间
401
+ */
402
+ exitRoom(): void {
403
+ logger.info('exitRoom')
404
+ const {pusher} = this.trtc.exitRoom()
405
+ this.InterfaceEventEmitter.emit('pusherAttributesChange', {
406
+ pusher,
407
+ callback: () => {
408
+ logger.info('exitRoom success')
409
+ this.reset()
410
+ this.emit('onExitRoom', 0)
411
+ },
412
+ })
413
+ }
414
+
415
+ /**
416
+ * @category 房间
417
+ */
418
+ switchRoom(): void {}
419
+
420
+ /**
421
+ * 切换角色,仅适用于直播场景(TRTCAppSceneLIVE 和 TRTCAppSceneVoiceChatRoom)
422
+ * @category 房间
423
+ */
424
+ async switchRole(role: TRTCRoleType): Promise<void> {
425
+ logger.info('switchRole with options: ', role)
426
+ const tempRole = this.role
427
+ this.role = role
428
+ if (tempRole === role || role === TRTCRoleType.TRTCRoleAnchor) {
429
+ logger.info('switchRole success')
430
+ this.emit('onSwitchRole', 0, '')
431
+ return
432
+ }
433
+ await this.setAttributes({params: {enableCamera: false, enableMic: false}}, 'switchRole')
434
+ logger.info('switchRole success')
435
+ this.emit('onSwitchRole', 0, '')
436
+ }
437
+
438
+ connectOtherRoom(): void {}
439
+
440
+ disconnectOtherRoom(): void {}
441
+
442
+ setDefaultStreamRecvMode(): void {}
443
+
444
+ /**
445
+ * 启动本地摄像头采集和预览
446
+ * @category 视频
447
+ */
448
+ async startLocalPreview(frontCamera = true): Promise<void> {
449
+ logger.info('startLocalPreview with options: ', frontCamera)
450
+ if (this.role !== TRTCRoleType.TRTCRoleAnchor) {
451
+ return
452
+ }
453
+ const pusher = await this.setAttributes({
454
+ params: () => ({
455
+ videoPreview: this.isEnterRoom ? this.isVideoMuted : true,
456
+ enableCamera: this.isEnterRoom ? !this.isVideoMuted : false,
457
+ frontCamera: frontCamera ? 'front' : 'back',
458
+ })
459
+ }, 'startLocalPreview')
460
+ logger.info('startLocalPreview success')
461
+ this.emit(
462
+ 'onFirstVideoFrame',
463
+ '',
464
+ TRTCVideoStreamType.TRTCVideoStreamTypeBig,
465
+ pusher.videoWidth,
466
+ pusher.videoHeight
467
+ )
468
+ if (this.isEnterRoom) {
469
+ this.emit(
470
+ 'onSendFirstLocalVideoFrame',
471
+ TRTCVideoStreamType.TRTCVideoStreamTypeBig,
472
+ )
473
+ }
474
+ this.isOpenCamera = true
475
+ }
476
+
477
+ /**
478
+ * 停止本地摄像头采集和预览
479
+ * @category 视频
480
+ */
481
+ async stopLocalPreview(): Promise<void> {
482
+ logger.info('stopLocalPreview')
483
+ await this.setAttributes({
484
+ params: {
485
+ videoPreview: false,
486
+ enableCamera: false,
487
+ }
488
+ }, 'stopLocalPreview')
489
+ logger.info('stopLocalPreview success')
490
+ this.isOpenCamera = false
491
+ this.emit('onUserVideoAvailable', this.userId, 0)
492
+ }
493
+
494
+ /**
495
+ * 修改本地摄像头预览的 HTML 元素,小程序不支持
496
+ * @category 视频
497
+ */
498
+ updateLocalView(view: string | null): void {
499
+ logger.info('updateLocalView with options: ', view)
500
+ if (view !== null) {
501
+ this.startLocalPreview()
502
+ return
503
+ }
504
+ this.stopLocalPreview()
505
+ }
506
+
507
+ /**
508
+ * 暂停/恢复发布本地的视频流
509
+ * @category 视频
510
+ * @param {boolean} mute true:屏蔽;false:开启,默认值:false
511
+ * @param {TRTCVideoStreamType} streamType 要暂停/恢复的视频流类型, 仅支持 TRTCVideoStreamTypeBig 和 TRTCVideoStreamTypeSub
512
+ */
513
+ async muteLocalVideo(
514
+ mute: boolean,
515
+ streamType: TRTCVideoStreamType
516
+ ): Promise<void> {
517
+ logger.info('muteLocalVideo called with options: ', mute, streamType)
518
+ if (!this.isOpenCamera) {
519
+ logger.info('muteLocalVideo early exit: isOpenCamera is false')
520
+ return
521
+ }
522
+ switch (streamType) {
523
+ case TRTCVideoStreamType.TRTCVideoStreamTypeBig:
524
+ case TRTCVideoStreamType.TRTCVideoStreamTypeSub:
525
+ this.isVideoMuted = mute
526
+ logger.info('muteLocalVideo: isVideoMuted set to ', mute)
527
+ try {
528
+ await this.setAttributes({
529
+ params: {
530
+ videoPreview: mute,
531
+ enableCamera: !mute,
532
+ }
533
+ }, 'muteLocalVideo')
534
+ logger.info('muteLocalVideo: setAttributes success')
535
+ } catch (error) {
536
+ logger.error('muteLocalVideo: setAttributes failed with error ', error)
537
+ }
538
+ logger.info('muteLocalVideo success')
539
+ break
540
+ default:
541
+ logger.info('muteLocalVideo: streamType not supported ', streamType)
542
+ }
543
+ }
544
+
545
+ /**
546
+ * 开始显示远端视频画面
547
+ * @category 视频
548
+ * @param userId 对方的用户标识
549
+ * @param view 此参数无效,小程序不支持
550
+ * @param streamType 视频流类型
551
+ */
552
+ async startRemoteView(
553
+ userId: string,
554
+ view: string,
555
+ streamType: TRTCVideoStreamType
556
+ ): Promise<void> {
557
+ logger.info('startRemoteView with options: ', userId, view, streamType)
558
+ const streamId = translateTRTCStreamId(userId, streamType) // trtc
559
+ this.renderMap.set(streamId, view)
560
+ await this.setAttributes({
561
+ params: {
562
+ muteVideo: false,
563
+ stopVideo: false,
564
+ },
565
+ streamId,
566
+ view
567
+ }, 'startRemoteView')
568
+ logger.info('startRemoteView success')
569
+ this.emit('onFirstVideoFrame', userId, streamType, 0, 0)
570
+ }
571
+
572
+ /**
573
+ * 停止显示远端视频画面,同时不再拉取该远端用户的视频数据流
574
+ * @param userId 对方的用户标识
575
+ * @param streamType 视频流类型
576
+ */
577
+ async stopRemoteView(userId: string, streamType: TRTCVideoStreamType): Promise<void> {
578
+ logger.info('stopRemoteView with options: ', userId, streamType)
579
+ const streamId = translateTRTCStreamId(userId, streamType)
580
+ await this.setAttributes({
581
+ params: {
582
+ muteVideo: true,
583
+ stopVideo: true,
584
+ },
585
+ streamId,
586
+ view: this.renderMap.get(streamId),
587
+ }, 'stopRemoteView')
588
+ logger.info('stopRemoteView success')
589
+ }
590
+
591
+ /**
592
+ * 修改远端视频渲染的 HTML 元素,小程序不支持
593
+ * @param userId 远端视频流的用户 ID
594
+ * @param view
595
+ * 接受远端视频流渲染的 HTML 元素,传入 null 结束远端视频的渲染
596
+ * - 传入的 HTML 元素必须时块元素,例如:div
597
+ * @param streamType
598
+ * @returns
599
+ */
600
+ async updateRemoteView(
601
+ userId: string,
602
+ view: string,
603
+ streamType: TRTCVideoStreamType
604
+ ): Promise<void> {
605
+ logger.info('updateRemoteView with options: ', userId, view, streamType)
606
+ if (view !== null) {
607
+ await this.startRemoteView(userId, view, streamType)
608
+ return
609
+ }
610
+ await this.stopRemoteView(userId, streamType)
611
+ }
612
+
613
+
614
+ // 停止显示所有远端视频画面,同时不再拉取该远端用户的视频数据流
615
+ async stopAllRemoteView(): Promise<void> {
616
+ logger.info('stopAllRemoteView')
617
+ const playerList = this.trtc.getPlayerList()
618
+ playerList.forEach(async (player) => {
619
+ const streamId = player.streamID
620
+ await this.setAttributes({
621
+ params: {
622
+ muteVideo: true,
623
+ stopVideo: true,
624
+ },
625
+ streamId,
626
+ view: this.renderMap.get(streamId),
627
+ }, 'stopAllRemoteView')
628
+ })
629
+ logger.info('stopAllRemoteView success')
630
+ }
631
+
632
+ // 暂停接收指定的远端视频流
633
+ // 该接口仅停止接收远程用户的视频流,但并不释放显示资源,所以视频画面会冻屏在 mute 前的最后一帧。
634
+ async muteRemoteVideoStream(
635
+ userId: string,
636
+ mute: boolean,
637
+ streamType: TRTCVideoStreamType
638
+ ): Promise<void> {
639
+ logger.info('muteRemoteVideoStream')
640
+ const streamId = translateTRTCStreamId(userId, streamType)
641
+ await this.setAttributes({
642
+ params: {muteVideo: mute},
643
+ streamId,
644
+ view: this.renderMap.get(streamId),
645
+ }, 'muteRemoteVideoStream')
646
+ logger.info('muteRemoteVideoStream success')
647
+ }
648
+
649
+ async muteAllRemoteVideoStreams(mute: boolean): Promise<void> {
650
+ logger.info('muteAllRemoteVideoStreams with options: ', mute)
651
+ const playerList = this.trtc.getPlayerList()
652
+ playerList.forEach(async (player) => {
653
+ const streamId = player.streamID
654
+ await this.setAttributes({
655
+ params: {muteVideo: mute},
656
+ streamId,
657
+ view: this.renderMap.get(streamId),
658
+ }, 'muteAllRemoteVideoStreams')
659
+ })
660
+ logger.info('muteAllRemoteVideoStreams success')
661
+ }
662
+
663
+ private setTRTCPlayerAttributes(streamId, options): object {
664
+ logger.info('setTRTCPlayerAttributes with options: ', streamId, options)
665
+ this.trtc.setPlayerAttributes(streamId, options)
666
+ return this.trtc.getPlayerInstance(streamId)?.playerAttributes || {}
667
+ }
668
+
669
+ async setVideoEncoderParam(params: TRTCVideoEncParam): Promise<void> {
670
+ logger.info('setVideoEncoderParam with options: ', JSON.stringify(params))
671
+ const {
672
+ videoResolution,
673
+ resMode,
674
+ videoFps,
675
+ videoBitrate,
676
+ minVideoBitrate,
677
+ } = params
678
+ const {videoWidth, videoHeight} =
679
+ translateTRTCVideoResolution(videoResolution)
680
+ await this.setAttributes({
681
+ params: {
682
+ videoWidth,
683
+ videoHeight,
684
+ // videoOrientation,
685
+ fps: videoFps,
686
+ minBitrate: minVideoBitrate,
687
+ }
688
+ }, 'setVideoEncoderParam')
689
+ logger.info('setVideoEncoderParam success')
690
+ }
691
+
692
+ async setLocalRenderParams(params: TRTCRenderParams): Promise<void> {
693
+ logger.info('setLocalRenderParams with options: ', JSON.stringify(params))
694
+ const {rotation, fillMode, mirrorType} = params
695
+ const videoOrientation = translateTRTCVideoRotation(rotation)
696
+ const localMirror = translateTRTCVideoMirrorType(mirrorType)
697
+ await this.setAttributes({
698
+ params: {
699
+ videoOrientation,
700
+ localMirror,
701
+ }
702
+ }, 'setLocalRenderParams')
703
+ logger.info('setLocalRenderParams success')
704
+ }
705
+
706
+ /**
707
+ * 设置远端图像的渲染模式
708
+ * @param {string} userId
709
+ * @param {TRTCVideoStreamType} streamType
710
+ * @param {TRTCRenderParams} params
711
+ */
712
+ async setRemoteRenderParams(
713
+ userId: string, streamType: TRTCVideoStreamType, params: TRTCRenderParams
714
+ ): Promise<void> {
715
+ logger.info('setRemoteRenderParams with options: ', userId, streamType, JSON.stringify(params))
716
+ const {fillMode, rotation, mirrorType} = params
717
+ const streamId = translateTRTCStreamId(userId, streamType) // 音频默认都是主流
718
+ await this.setAttributes({
719
+ params: {
720
+ objectFit: translateVideoFillMod(fillMode),
721
+ orientation: translateTRTCVideoRotation(rotation)
722
+ },
723
+ streamId,
724
+ view: this.renderMap.get(streamId),
725
+ }, 'setRemoteRenderParams')
726
+ logger.info('setRemoteRenderParams success')
727
+ }
728
+
729
+ async startLocalAudio(quality: TRTCAudioQuality): Promise<void> {
730
+ logger.info('startLocalAudio with options: ', quality)
731
+ if (this.role !== TRTCRoleType.TRTCRoleAnchor) {
732
+ throw new Error('Current role is audience, unable to access mic. Call switchRole to become a host.')
733
+ }
734
+ await this.setAttributes({params: {enableMic: true}}, 'startLocalAudio')
735
+ logger.info('startLocalAudio success')
736
+ this.emit('onMicDidReady')
737
+ this.emit('onUserAudioAvailable', this.userId, 1)
738
+ if (this.enterRoom) {
739
+ this.emit('onSendFirstLocalAudioFrame')
740
+ }
741
+ }
742
+
743
+ async stopLocalAudio(): Promise<void> {
744
+ logger.info('stopLocalAudio')
745
+ await this.setAttributes({params: {enableMic: false}}, 'stopLocalAudio')
746
+ logger.info('stopLocalAudio success')
747
+ this.emit('onUserAudioAvailable', this.userId, 0)
748
+ }
749
+
750
+ async muteLocalAudio(mute: boolean): Promise<void> {
751
+ logger.info('muteLocalAudio called with options: ', mute)
752
+
753
+ try {
754
+ await this.setAttributes({params: {muted: mute}}, 'muteLocalAudio')
755
+ logger.info('setAttributes executed successfully')
756
+ } catch (error) {
757
+ logger.error('Error in setAttributes: ', error)
758
+ throw error
759
+ }
760
+
761
+ try {
762
+ this.emit('onUserAudioAvailable', this.userId, mute === true ? 0 : 1)
763
+ logger.info('onUserAudioAvailable event emitted successfully')
764
+ } catch (error) {
765
+ logger.error('Error in emitting onUserAudioAvailable event: ', error)
766
+ throw error
767
+ }
768
+
769
+ logger.info('muteLocalAudio execution finished')
770
+ }
771
+
772
+ async muteRemoteAudio(userId: string, mute: boolean): Promise<void> {
773
+ logger.info('muteRemoteAudio with options: ', userId, mute)
774
+ const streamId = translateTRTCStreamId(
775
+ userId,
776
+ TRTCVideoStreamType.TRTCVideoStreamTypeBig
777
+ ) // 音频默认都是主流
778
+ await this.setAttributes({
779
+ params: {
780
+ muteAudio: mute,
781
+ },
782
+ streamId,
783
+ view: this.renderMap.get(streamId),
784
+ }, 'muteRemoteAudio')
785
+ logger.info('muteRemoteAudio success')
786
+ }
787
+
788
+ async muteAllRemoteAudio(mute: boolean): Promise<void> {
789
+ logger.info('muteAllRemoteAudio with options: ', mute)
790
+ const playerList = this.trtc.getPlayerList()
791
+ playerList.forEach(async (player) => {
792
+ const streamId = player.streamID
793
+ await this.setAttributes({
794
+ params: {
795
+ muteAudio: mute,
796
+ },
797
+ streamId,
798
+ view: this.renderMap.get(streamId),
799
+ }, 'muteRemoteAudio')
800
+ })
801
+ logger.info('muteAllRemoteAudio success')
802
+ }
803
+
804
+ enableAudioVolumeEvaluation(interval: number): void {
805
+ logger.info('enableAudioVolumeEvaluation with options: ', interval)
806
+ this.handleAudioVolumeUpdate = this.getHandleAudioVolumeUpdate(interval)
807
+ }
808
+
809
+ /**
810
+ * 切换前后摄像头
811
+ */
812
+ switchCamera(frontCamera: boolean): Promise<any> {
813
+ logger.info('switchCamera with options: ', frontCamera)
814
+ const pusher = this.trtc.getPusherInstance()
815
+ if (frontCamera === (pusher.pusherAttributes.frontCamera === 'front')) return Promise.resolve()
816
+ return new Promise((resolve, reject) => {
817
+ wx.createLivePusherContext().switchCamera({
818
+ success: async (event) => {
819
+ await this.setAttributes({params: {frontCamera}}, 'switchCamera')
820
+ logger.info('switchCamera success')
821
+ resolve(event)
822
+ },
823
+ fail: (error) => {
824
+ logger.info('switchCamera fail')
825
+ reject(error)
826
+ },
827
+ })
828
+ })
829
+ }
830
+
831
+ async setBeautyStyle(
832
+ style: TRTCBeautyStyle,
833
+ beauty: number,
834
+ white: number,
835
+ ruddiness: number
836
+ ): Promise<void> {
837
+ logger.info('setBeautyStyle with options: ', style, beauty, white, ruddiness)
838
+ await this.setAttributes({
839
+ params: {
840
+ beautyStyle: style,
841
+ beautyLevel: beauty,
842
+ whitenessLevel: white,
843
+ }
844
+ }, 'setBeautyStyle')
845
+ logger.info('setBeautyStyle success')
846
+ }
847
+
848
+ sendSEIMsg(msg: string, repeatCount = 1): Promise<any> {
849
+ logger.info('sendSEIMsg with options: ', msg, repeatCount)
850
+ return new Promise((resolve, reject) => {
851
+ wx.createLivePusherContext().sendMessage({
852
+ msg,
853
+ success: (event) => {
854
+ logger.info('sendSEIMsg success')
855
+ resolve(event)
856
+ },
857
+ fail: (error) => {
858
+ logger.info('sendSEIMsg fail')
859
+ reject(error)
860
+ },
861
+ })
862
+ })
863
+ }
864
+
865
+ startPlayMusic(
866
+ musicParam: AudioMusicParam,
867
+ callbackMap: Record<'onStart' | 'onPlayProgress' | 'onComplete', () => void>
868
+ ): Promise<any> {
869
+ logger.info('startPlayMusic with options: ', JSON.stringify(musicParam))
870
+ return new Promise((resolve, reject) => {
871
+ const {path, startTimeMS = 0, endTimeMS = 0} = musicParam
872
+ wx.createLivePusherContext().playBGM({
873
+ url: path,
874
+ startTimeMs: startTimeMS,
875
+ endTimeMs: endTimeMS,
876
+ success: (event) => {
877
+ logger.info('startPlayMusic success')
878
+ resolve(event)
879
+ },
880
+ fail: (error) => {
881
+ logger.info('startPlayMusic fail')
882
+ reject(error)
883
+ },
884
+ })
885
+ })
886
+ }
887
+
888
+ stopPlayMusic(): Promise<any> {
889
+ logger.info('stopPlayMusic')
890
+ return new Promise((resolve, reject) => {
891
+ wx.createLivePusherContext().stopBGM({
892
+ success: (event) => {
893
+ logger.info('stopPlayMusic success')
894
+ resolve(event)
895
+ },
896
+ fail: (error) => {
897
+ logger.info('stopPlayMusic fail')
898
+ reject(error)
899
+ },
900
+ })
901
+ })
902
+ }
903
+
904
+ pausePlayMusic(): Promise<any> {
905
+ logger.info('pausePlayMusic')
906
+ return new Promise((resolve, reject) => {
907
+ wx.createLivePusherContext().pauseBGM({
908
+ success: (event) => {
909
+ logger.info('pausePlayMusic success')
910
+ resolve(event)
911
+ },
912
+ fail: (error) => {
913
+ logger.info('pausePlayMusic fail')
914
+ reject(error)
915
+ },
916
+ })
917
+ })
918
+ }
919
+
920
+ resumePlayMusic(): Promise<any> {
921
+ logger.info('resumePlayMusic')
922
+ return new Promise((resolve, reject) => {
923
+ wx.createLivePusherContext().resumeBGM({
924
+ success: (event) => {
925
+ logger.info('resumePlayMusic success')
926
+ resolve(event)
927
+ },
928
+ fail: (error) => {
929
+ logger.info('resumePlayMusic fail')
930
+ reject(error)
931
+ },
932
+ })
933
+ })
934
+ }
935
+
936
+ // 设置背景音乐的音量大小,播放背景音乐混音时使用,用来控制背景音音量大小
937
+ setAllMusicVolume(volume: number): Promise<any> {
938
+ logger.info('setAllMusicVolume with options: ', volume)
939
+ return new Promise((resolve, reject) => {
940
+ const volumeStr = (volume / 200).toString()
941
+ wx.createLivePusherContext().setBGMVolume({
942
+ volume: volumeStr,
943
+ success: (event) => {
944
+ logger.info('setAllMusicVolume success')
945
+ resolve(event)
946
+ },
947
+ fail: (error) => {
948
+ logger.info('setAllMusicVolume fail')
949
+ reject(error)
950
+ },
951
+ })
952
+ })
953
+ }
954
+
955
+ // 开启大小画面双路编码模式
956
+ enableSmallVideoStream(enable: boolean, params: TRTCVideoEncParam) {
957
+ // todo 待实现
958
+ }
959
+
960
+ /**
961
+ * 调用实验性 API 接口
962
+ *
963
+ * 注意:该接口用于调用一些实验性功能, 目前 web 端空实现
964
+ *
965
+ * @param {String} jsonStr - 接口及参数描述的 JSON 字符串
966
+ */
967
+ callExperimentalAPI(jsonStr: string): void {
968
+ logger.info('callExperimentalAPI with options: ', jsonStr)
969
+ const jsonObj = safelyParse(jsonStr)
970
+ if (jsonObj === jsonStr) {
971
+ return
972
+ }
973
+ const {api, params} = jsonObj
974
+ if (!api || !params) {
975
+ return
976
+ }
977
+ switch (api) {
978
+ case 'setFramework':
979
+ this.handleSetFrameWork(params)
980
+ break
981
+ default:
982
+ break
983
+ }
984
+ }
985
+
986
+ private handleSetFrameWork(params: any): void {
987
+ const {component} = params
988
+ if (isNumber(component)) {
989
+ try {
990
+ if (wx) {
991
+ wx.TUIScene = component
992
+ wx.setStorageSync('TUIScene', String(component))
993
+ }
994
+ } catch (err) {
995
+ throw err
996
+ }
997
+ }
998
+ }
999
+
1000
+ private pusherAttributesChange(pusher: any): Promise<any> {
1001
+ return new Promise((resolve) => {
1002
+ this.InterfaceEventEmitter.emit(
1003
+ 'pusherAttributesChange',
1004
+ {
1005
+ pusher,
1006
+ callback: () => {
1007
+ resolve(pusher)
1008
+ },
1009
+ }
1010
+ )
1011
+ })
1012
+ }
1013
+
1014
+ private playerAttributesChange(params: any): Promise<any> {
1015
+ const {streamId, playerAttributes} = params
1016
+ return new Promise((resolve) => {
1017
+ this.InterfaceEventEmitter.emit(
1018
+ 'playerAttributesChange',
1019
+ {
1020
+ streamId,
1021
+ view: this.renderMap.get(streamId),
1022
+ playerAttributes,
1023
+ callback: () => {
1024
+ resolve(playerAttributes)
1025
+ }
1026
+ }
1027
+ )
1028
+ })
1029
+ }
1030
+
1031
+ @setHandle
1032
+ private async setAttributes(options: any, funName: string, handleType?: Handletype): Promise<any> {
1033
+ // 定义一个超时时间(以毫秒为单位)
1034
+ const timeoutDuration = 2000
1035
+ const timeoutPromise = new Promise((resolve, reject) => {
1036
+ setTimeout(() => {
1037
+ reject(new Error('setAttributes timed out'))
1038
+ }, timeoutDuration)
1039
+ })
1040
+ const {params, streamId} = options
1041
+ const handleMap = {
1042
+ [Handletype.setPlayer]: async () => {
1043
+ const playerAttributes = await this.playerAttributesChange({
1044
+ playerAttributes: this.setTRTCPlayerAttributes(streamId, params),
1045
+ streamId
1046
+ })
1047
+ return playerAttributes
1048
+ },
1049
+ [Handletype.setPusher]: async () => {
1050
+ if (funName === 'enterRoom') {
1051
+ const pusher = await this.pusherAttributesChange(this.trtc.enterRoom(params))
1052
+ return pusher
1053
+ }
1054
+ const pusher = await this.pusherAttributesChange(this.trtc.setPusherAttributes(params))
1055
+ return pusher
1056
+ }
1057
+ }
1058
+
1059
+ const originalPromise = handleMap[handleType]
1060
+ ? handleMap[handleType]()
1061
+ : Promise.reject(new Error('setAttributes fail'))
1062
+
1063
+ return Promise.race([originalPromise, timeoutPromise])
1064
+ }
1065
+ }
1066
+
1067
+ export default TRTCCloud