trtc-cloud-js-sdk 1.0.13 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/.eslintrc.js +88 -0
  2. package/.prettierrc +5 -0
  3. package/CHANGELOG.md +58 -0
  4. package/build/jsdoc/clean-doc.js +12 -0
  5. package/build/jsdoc/fix-doc.js +141 -0
  6. package/build/jsdoc/jsdoc.json +42 -0
  7. package/build/package-bundle.js +29 -0
  8. package/build/rollup.config.dev.js +88 -0
  9. package/build/rollup.config.prod.js +93 -0
  10. package/build/rollup.js +359 -0
  11. package/build/template/npm-package/package.json +24 -0
  12. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/base.css +213 -0
  13. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/index.html +80 -0
  14. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/prettify.css +1 -0
  15. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/prettify.js +1 -0
  16. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/sort-arrow-sprite.png +0 -0
  17. package/coverage/Chrome 103.0.5060 (Mac OS X 10.15.7)/sorter.js +158 -0
  18. package/examples/apiExample/.env +2 -0
  19. package/examples/apiExample/README.md +70 -0
  20. package/examples/apiExample/package-lock.json +30915 -0
  21. package/examples/apiExample/package.json +51 -0
  22. package/examples/apiExample/public/audio.js +195 -0
  23. package/examples/apiExample/public/audio.js.map +7 -0
  24. package/examples/apiExample/public/av_processing.js +1 -0
  25. package/examples/apiExample/public/basic/av_processing.wasm +0 -0
  26. package/examples/apiExample/public/basic/worker.js +10434 -0
  27. package/examples/apiExample/public/favicon.ico +0 -0
  28. package/examples/apiExample/public/index.html +47 -0
  29. package/examples/apiExample/public/logo192.png +0 -0
  30. package/examples/apiExample/public/logo512.png +0 -0
  31. package/examples/apiExample/public/manifest.json +25 -0
  32. package/examples/apiExample/public/robots.txt +3 -0
  33. package/examples/apiExample/src/App.css +37 -0
  34. package/examples/apiExample/src/App.js +25 -0
  35. package/examples/apiExample/src/api/http.js +127 -0
  36. package/examples/apiExample/src/api/nav.js +44 -0
  37. package/examples/apiExample/src/components/BasicInfoComponent.css +16 -0
  38. package/examples/apiExample/src/components/BasicInfoComponent.js +27 -0
  39. package/examples/apiExample/src/config/gen-test-user-sig.js +64 -0
  40. package/examples/apiExample/src/config/lib-generate-test-usersig.min.js +7052 -0
  41. package/examples/apiExample/src/config/nav.js +136 -0
  42. package/examples/apiExample/src/home.js +16 -0
  43. package/examples/apiExample/src/index.css +21 -0
  44. package/examples/apiExample/src/index.js +12 -0
  45. package/examples/apiExample/src/logo.svg +1 -0
  46. package/examples/apiExample/src/page/basic/screen-share/index.css +52 -0
  47. package/examples/apiExample/src/page/basic/screen-share/index.js +223 -0
  48. package/examples/apiExample/src/page/basic/setDevice/index.js +262 -0
  49. package/examples/apiExample/src/page/basic/setDevice/index.scss +93 -0
  50. package/examples/apiExample/src/page/basic/video-call/index.js +521 -0
  51. package/examples/apiExample/src/page/basic/video-call/index.scss +93 -0
  52. package/examples/apiExample/src/page/basic/video-call-init/index.js +382 -0
  53. package/examples/apiExample/src/page/basic/video-call-init/index.scss +93 -0
  54. package/examples/apiExample/src/page/basic/video-live/index.css +37 -0
  55. package/examples/apiExample/src/page/basic/video-live/index.js +188 -0
  56. package/examples/apiExample/src/page/layout.js +22 -0
  57. package/examples/apiExample/src/page/layout.scss +76 -0
  58. package/examples/apiExample/src/utils/utils.js +35 -0
  59. package/examples/jsExample/assets/css/bootstrap-material-design.css +12169 -0
  60. package/examples/jsExample/assets/css/bootstrap-material-design.min.css +8 -0
  61. package/examples/jsExample/assets/css/common.css +48 -0
  62. package/examples/jsExample/assets/icon/iconfont.js +1 -0
  63. package/examples/jsExample/assets/js/bootstrap-material-design.js +6939 -0
  64. package/examples/jsExample/assets/js/bootstrap-material-design.js.map +1 -0
  65. package/examples/jsExample/assets/js/bootstrap-material-design.min.js +1 -0
  66. package/examples/jsExample/assets/js/graph.js +695 -0
  67. package/examples/jsExample/assets/js/jquery-3.2.1.min.js +4 -0
  68. package/examples/jsExample/assets/js/jquery-3.2.1.slim.min.js +4 -0
  69. package/examples/jsExample/assets/js/lib-generate-test-usersig.min.js +2 -0
  70. package/examples/jsExample/assets/js/popper.js +2442 -0
  71. package/examples/jsExample/index.html +57 -0
  72. package/examples/jsExample/rtc/css/common.css +82 -0
  73. package/examples/jsExample/rtc/index.html +107 -0
  74. package/examples/jsExample/rtc/js/index.js +142 -0
  75. package/examples/vueDemo/LICENSE +21 -0
  76. package/examples/vueDemo/README.md +144 -0
  77. package/examples/vueDemo/README_EN.md +136 -0
  78. package/examples/vueDemo/av_processing.wasm +0 -0
  79. package/examples/vueDemo/index.html +23 -0
  80. package/examples/vueDemo/package-lock.json +1375 -0
  81. package/examples/vueDemo/package.json +36 -0
  82. package/examples/vueDemo/src/App.vue +12 -0
  83. package/examples/vueDemo/src/api/index.js +59 -0
  84. package/examples/vueDemo/src/assets/css/color-dark.css +28 -0
  85. package/examples/vueDemo/src/assets/css/icon.css +4 -0
  86. package/examples/vueDemo/src/assets/css/main.css +177 -0
  87. package/examples/vueDemo/src/assets/img/img.jpg +0 -0
  88. package/examples/vueDemo/src/assets/img/login-bg.jpg +0 -0
  89. package/examples/vueDemo/src/components/Header.vue +172 -0
  90. package/examples/vueDemo/src/components/Sidebar.vue +117 -0
  91. package/examples/vueDemo/src/components/Tags.vue +174 -0
  92. package/examples/vueDemo/src/components/tendency.vue +206 -0
  93. package/examples/vueDemo/src/components/trtc/main-menu.vue +50 -0
  94. package/examples/vueDemo/src/components/trtc/nav-bar.vue +53 -0
  95. package/examples/vueDemo/src/components/trtc/show-screen-capture.vue +118 -0
  96. package/examples/vueDemo/src/components/trtc/trtc-state-check.vue +117 -0
  97. package/examples/vueDemo/src/config/gen-test-user-sig.js +67 -0
  98. package/examples/vueDemo/src/config/lib-generate-test-usersig.min.js +7052 -0
  99. package/examples/vueDemo/src/main.js +11 -0
  100. package/examples/vueDemo/src/plugins/element.js +17 -0
  101. package/examples/vueDemo/src/router/index.js +73 -0
  102. package/examples/vueDemo/src/store/sidebar.js +17 -0
  103. package/examples/vueDemo/src/store/tags.js +48 -0
  104. package/examples/vueDemo/src/utils/i18n.js +24 -0
  105. package/examples/vueDemo/src/utils/request.js +34 -0
  106. package/examples/vueDemo/src/utils/utils.js +35 -0
  107. package/examples/vueDemo/src/views/Home.vue +46 -0
  108. package/examples/vueDemo/src/views/I18n.vue +40 -0
  109. package/examples/vueDemo/src/views/Icon.vue +229 -0
  110. package/examples/vueDemo/src/views/basic/trtc.vue +194 -0
  111. package/examples/vueDemo/src/views/feature/index.vue +259 -0
  112. package/examples/vueDemo/src/views/github/index.vue +243 -0
  113. package/examples/vueDemo/src/views/improve/live-index.vue +256 -0
  114. package/examples/vueDemo/src/views/improve/live-room-anchor.vue +689 -0
  115. package/examples/vueDemo/src/views/improve/live-room-audience.vue +383 -0
  116. package/examples/vueDemo/src/views/sdkAppId/index.vue +284 -0
  117. package/examples/vueDemo/vite.config.js +18 -0
  118. package/examples/vueDemo/worker.js +22 -0
  119. package/karma.conf.js +99 -0
  120. package/package.json +57 -7
  121. package/scripts/publish.js +86 -0
  122. package/src/Camera.ts +80 -0
  123. package/src/Mic.ts +145 -0
  124. package/src/common/IError.ts +6 -0
  125. package/src/common/ITRTCCloud.ts +68 -0
  126. package/src/common/constants.ts +116 -0
  127. package/src/common/trtc-code.ts +43 -0
  128. package/src/common/trtc-define.ts +1007 -0
  129. package/src/common/trtc-event.ts +29 -0
  130. package/src/index.ts +1672 -0
  131. package/src/utils/environment.js +297 -0
  132. package/src/utils/raf.js +131 -0
  133. package/src/utils/time.js +22 -0
  134. package/src/utils/utils.ts +71 -0
  135. package/src/utils/uuid.js +12 -0
  136. package/test/unit/env.test.js +25 -0
  137. package/test/unit/get-user-media.test.js +40 -0
  138. package/test/unit/ice-parser.test.js +23 -0
  139. package/test/unit/sdp.test.js +45 -0
  140. package/test/unit/signal.test.js +78 -0
  141. package/tsconfig.json +32 -0
  142. package/trtc-cloud-js-sdk.js +0 -1
  143. /package/{README.md → build/template/npm-package/README.md} +0 -0
@@ -0,0 +1,689 @@
1
+ <template name="liveRoomAnchor">
2
+ <div id="live-room">
3
+ <nav-bar :title="'房间号:' + roomId+';主播:'+userId"></nav-bar>
4
+
5
+ <!-- 视频容器 -->
6
+ <div id="video-container"></div>
7
+ <!-- 控制条 -->
8
+ <div id="controll-bar">
9
+ <!-- 开始/停止推流,会弹出模态框 -->
10
+ <b-button variant="link" @click="showConfirmPushModal">
11
+ <b-iconstack font-scale="1">
12
+ <b-icon icon="stop-fill" color="red" v-if="isPushing"></b-icon>
13
+ <b-icon icon="caret-right-fill" color="white" v-else></b-icon>
14
+ </b-iconstack>
15
+ </b-button>
16
+
17
+ <!-- 开启/关闭麦克风 -->
18
+ <b-button variant="link" @click="toggleMic">
19
+ <b-iconstack font-scale="1">
20
+ <b-icon icon="mic-fill" color="white"></b-icon>
21
+ <b-icon icon="slash" variant="danger" v-if="isMuteMic"></b-icon>
22
+ </b-iconstack>
23
+ </b-button>
24
+
25
+ <!-- 开房/关闭摄像头 -->
26
+ <b-button variant="link" @click="toggleCamera">
27
+ <b-iconstack font-scale="1">
28
+ <b-icon icon="camera-video-fill" color="white"></b-icon>
29
+ <b-icon icon="slash" variant="danger" v-if="isDisableCamara"></b-icon>
30
+ </b-iconstack>
31
+ </b-button>
32
+
33
+ <!-- 屏幕分享控制 -->
34
+ <b-button variant="link">
35
+ <b-iconstack
36
+ font-scale="1"
37
+ id="screen-sharing-controll"
38
+ @click="toggleScreenSharing"
39
+ v-if="isPushing"
40
+ >
41
+ <b-icon icon="tv-fill" color="yellow" v-if="isScreenSharing"></b-icon>
42
+ <b-icon icon="tv-fill" color="white" v-else></b-icon>
43
+ </b-iconstack>
44
+ <b-iconstack font-scale="1" id v-else>
45
+ <b-icon icon="tv-fill" color="gray"></b-icon>
46
+ </b-iconstack>
47
+ </b-button>
48
+
49
+ <!-- 退出房间 -->
50
+ <b-button variant="link" @click="exitRoom">
51
+ <b-iconstack font-scale="1">
52
+ <b-icon icon="power" variant="warning"></b-icon>
53
+ </b-iconstack>
54
+ </b-button>
55
+ </div>
56
+
57
+ <!-- 模态框、浮层 -->
58
+ <div>
59
+ <b-modal id="screens-list-modal" size="lg" title="选择一个窗口" v-model="screensListVisiable">
60
+ <show-screen-capture v-bind:list="screensList" v-bind:onClick="chooseWindowCapture"></show-screen-capture>
61
+ </b-modal>
62
+ <b-modal id="start-push-confirm" size="lg" title="即将直播推流,是否确认?" centered @ok="startLive">
63
+ <p class="my-4">如果您对预览的效果感到满意,请点击“OK”开始直播推流。</p>
64
+ </b-modal>
65
+
66
+ <b-modal id="stop-push-confirm" size="lg" title="正在关闭直播,是否确认?" centered @ok="stopLive">
67
+ <p class="my-4">请确认是否关闭直播?</p>
68
+ </b-modal>
69
+
70
+ <div id="count-down-layer" v-if="countDown > 0">{{countDown}} 秒后开始直播</div>
71
+ </div>
72
+ </div>
73
+ </template>
74
+
75
+ <script>
76
+ import TRTCCloud from 'trtc-js-sdk';
77
+ import showScreenCpature from '../../components/show-screen-capture.vue';
78
+ import trtcState from '../../common/trtc-state';
79
+ import {
80
+ TRTCAppScene,
81
+ TRTCVideoStreamType,
82
+ TRTCVideoFillMode,
83
+ TRTCRoleType,
84
+ TRTCParams,
85
+ TRTCVideoEncParam,
86
+ TRTCVideoResolution,
87
+ TRTCVideoResolutionMode,
88
+ TRTCBeautyStyle,
89
+ Rect,
90
+ } from "@trtc/cloud-sdk-types";
91
+ import genTestUserSig from '../../debug/gen-test-user-sig';
92
+ import Log from '../../common/log';
93
+ import {BDVideoEncode, BDBeauty} from '../../common/bd-tools';
94
+ const logger = new Log(`trtcRoom`);
95
+ let trtcCloud = null; // 用于TRTCQcloud 实例, mounted 时实体化
96
+
97
+
98
+
99
+
100
+
101
+ export default {
102
+ components: {
103
+ 'show-screen-capture': showScreenCpature
104
+ },
105
+ data() {
106
+ return {
107
+ roomId: 0,
108
+ userId: '',
109
+ cameraId: '',
110
+ videosList: [],
111
+ streamType: TRTCVideoStreamType.TRTCVideoStreamTypeBig,
112
+ isMuteMic: false,
113
+ isDisableCamara : false,
114
+ getScreensTaskID: 0,
115
+ screensList: [],
116
+ screensListVisiable: false,
117
+ videoContainer: null,
118
+ isPushing: false,
119
+ isScreenSharing: false,
120
+ isScreenSharingPlaying: false,
121
+ countDown: 0, // 倒计时开播,单位:秒
122
+ countDownMax: 3, // 倒计时最大值
123
+ countDownVisiable: false,
124
+ loadingProgess: 100,
125
+ sdkInfo: null,
126
+ // 存放远程用户视频列表
127
+ remoteVideos: {},
128
+ isRemoteScreenSharing: false, // 远程用户是否正在分享屏幕
129
+
130
+ };
131
+ },
132
+
133
+ computed: {
134
+ subStreamWidth() {
135
+ return Math.floor(this.videoContainer.clientWidth * 0.2);
136
+ },
137
+
138
+ subStreamHeight () {
139
+ return Math.floor(this.videoContainer.clientHeight * 0.2);
140
+ }
141
+ },
142
+
143
+ methods: {
144
+
145
+ /**
146
+ * 推流状态切换确认
147
+ */
148
+ showConfirmPushModal() {
149
+ let modalId = this.isPushing === false ? 'start-push-confirm' : 'stop-push-confirm';
150
+ this.$bvModal.show(modalId);
151
+ },
152
+
153
+ /**
154
+ * 倒计时3秒开始直播
155
+ */
156
+ startLiveCountDown() {
157
+ let gap = 1000;
158
+ this.countDown = this.countDownMax;
159
+ let intervalID = setInterval(()=>{
160
+ this.countDown -= gap / 1000;
161
+ logger.log('startLiveCountDown: ', this.countDown);
162
+ if (this.countDown <= 0 ) {
163
+ this.startLive();
164
+ clearInterval(intervalID);
165
+ }
166
+ }, gap);
167
+ },
168
+
169
+ /**
170
+ * 开始直播,注意:进入房间会开始推流
171
+ */
172
+ startLive() {
173
+ this.isPushing = true;
174
+ // 进入房间便会开始推流
175
+ // TRTCParams 详细说明,请查看文档:https://web.sdk.qcloud.com/trtc/electron/doc/zh-cn/trtc_electron_sdk/TRTCParams.html
176
+ let param = new TRTCParams();
177
+ param.sdkAppId = this.sdkInfo.sdkappid;
178
+ param.userSig = this.sdkInfo.userSig;
179
+ param.roomId = this.roomId;
180
+ param.userId = this.userId;
181
+ param.privateMapKey = ''; // 房间签名(非必填)7.1.157 版本以上(含),可以忽略此参数,7.1.157 之前的版本建议赋值为空字符串
182
+ param.businessInfo = ''; // 业务数据(非必填)7.1.157 版本以上(含),可以忽略此参数,7.1.157 之前的版本建议赋值为空字符串
183
+ param.role = TRTCRoleType.TRTCRoleAnchor; // 直播场景下的角色,仅适用于直播场景(TRTCAppSceneLIVE 和 TRTCAppSceneVoiceChatRoom),视频通话场景下指定无效。默认值:主播(TRTCRoleAnchor)
184
+ trtcCloud.enterRoom(param, TRTCAppScene.TRTCAppSceneLIVE);
185
+ },
186
+
187
+ /**
188
+ * 停止直播
189
+ */
190
+ stopLive() {
191
+ this.isPushing = false;
192
+ trtcCloud.stopScreenCapture(); // 停止屏幕分享
193
+ trtcCloud.exitRoom(); // 退出房间
194
+ setTimeout(()=>{
195
+ // 推流结束后,继续观看本地画面
196
+ this.startCameraAndMic();
197
+ }, 0);
198
+ },
199
+
200
+ /**
201
+ * 当进入房间时触发,显示摄像头画面,设置填充模式
202
+ * @param {number} result - 进房结果, 大于 0 时,为进房间消耗的时间,这表示进进房成功。如果为 -1 ,则表示进房失败。
203
+ **/
204
+ onEnterRoom(result) {
205
+ if ( result > 0 ) {
206
+ logger.log(`onEnterRoom,进房成功,使用了 ${result} 毫秒`);
207
+ } else {
208
+ logger.warn(`onEnterRoom: 进房失败 ${result}`);
209
+ }
210
+ },
211
+
212
+ /**
213
+ * 当退出房间时触发
214
+ */
215
+ onExitRoom(reason) {
216
+ logger.warn(`onExitRoom, reason: ${reason}`);
217
+ },
218
+
219
+ /**
220
+ * 远程用户视频流的状态发生变更时触发。
221
+ * @param {number} uid - 用户标识
222
+ * @param {boolean} available - 画面是否开启
223
+ **/
224
+ onUserVideoAvailable(uid, available) {
225
+ logger.log(`onUserVideoAvailable: uid: ${uid}, available ${available}`);
226
+ if (available === 1) {
227
+ this.$bvToast.toast(`主播 ${uid} 进入房间`, {
228
+ variant: 'success'
229
+ });
230
+ this.showVideo(uid);
231
+ } else {
232
+ this.$bvToast.toast(`主播 ${uid} 退出房间`, {
233
+ variant: 'warning'
234
+ });
235
+ this.closeVideo(uid);
236
+ }
237
+ },
238
+
239
+ /***
240
+ * 显示其他用户的视频
241
+ * @param {number} uid - 用户ID
242
+ */
243
+ showVideo(uid){
244
+ let id = `${uid}-${this.roomId}-${TRTCVideoStreamType.TRTCVideoStreamTypeBig}`;
245
+ logger.log(`showVideo: uid: ${uid}; style:${this.remoteVideoStyle}`);
246
+ let view = document.getElementById(id);
247
+ if (!view) {
248
+ view = document.createElement('div');
249
+ view.id = id;
250
+ this.videoContainer.appendChild(view);
251
+ }
252
+ view.style.width = `${this.subStreamWidth}px`;
253
+ view.style.height = `${this.subStreamHeight}px`;
254
+ this.remoteVideos[id] = view;
255
+ trtcCloud.startRemoteView(uid, view);
256
+ trtcCloud.setRemoteViewFillMode(uid, TRTCVideoFillMode.TRTCVideoFillMode_Fill);
257
+ this.videoTypeSetting();
258
+ },
259
+
260
+ /**
261
+ * 关闭其他用户的视频
262
+ * @param {number} uid
263
+ */
264
+ closeVideo(uid) {
265
+ let id = `${uid}-${this.roomId}-${TRTCVideoStreamType.TRTCVideoStreamTypeBig}`;
266
+ let view = document.getElementById(id);
267
+ if (view) {
268
+ this.videoContainer.removeChild(view);
269
+ }
270
+ delete this.remoteVideos[id];
271
+ },
272
+
273
+
274
+ /**
275
+ * 对视频元素进行排版
276
+ */
277
+ videoTypeSetting() {
278
+ let marginTop = 80 ;
279
+ let margin = 5;
280
+ let H = this.subStreamHeight;
281
+ let m = 0;
282
+ let topIndex = 0;
283
+ let remoteVideos = this.remoteVideos;
284
+ let typeClassName = '';
285
+ let top = 0;
286
+ let i = 0;
287
+ for (let id in remoteVideos) {
288
+ topIndex = Math.floor( i / 2 );
289
+ typeClassName = i % 2 ===0 ? 'right' : 'left';
290
+ top = (topIndex * H + (topIndex+1) * margin )+ marginTop;
291
+ remoteVideos[id].className = `user-video-container ${typeClassName}`;
292
+ remoteVideos[id].style.top = `${top}px`;
293
+ logger.log(`videoTypeSetting: i:${i}, ti: ${topIndex}, top ${top}, H: ${H}, m: ${m}, id:${id},` );
294
+ i++;
295
+ }
296
+ },
297
+
298
+ /**
299
+ * 当远端用户进入本房间,显示出此用户的画面
300
+ */
301
+ onRemoteUserEnterRoom(uid) {
302
+ logger.warn('onRemoteUserEnterRoom', uid);
303
+ this.$bvToast.toast(`主播 ${uid} 进入房间`, {
304
+ variant: 'primary'
305
+ });
306
+ },
307
+
308
+ /**
309
+ * 当远程用户离开房间,关闭此用户的画面
310
+ */
311
+ onRemoteUserLeaveRoom(uid) {
312
+ this.$bvToast.toast(`主播 ${uid} 离开房间`);
313
+ logger.warn('onRemoteUserLeaveRoom', uid );
314
+ },
315
+
316
+ /**
317
+ * 当远程用户屏幕分享的状态发生变化,会根据 available 参数打开或关闭画面
318
+ **/
319
+ onUserSubStreamAvailable(uid, available) {
320
+ logger.log(`onUserSubStreamAvailable ${uid}, ${available}`);
321
+ if (available) {
322
+ this.showRemoteScreenSharing(uid);
323
+ this.isRemoteScreenSharing = true;
324
+ } else {
325
+ this.closeRemoteScreenSharing(uid);
326
+ this.isRemoteScreenSharing = false;
327
+ }
328
+ },
329
+
330
+ /**
331
+ * 显示远程用户的屏幕分享
332
+ */
333
+ showRemoteScreenSharing(uid) {
334
+ let id = `${uid}-${this.roomId}-${TRTCVideoStreamType.TRTCVideoStreamTypeSub}`;
335
+ logger.log(`showRemoteScreenSharing: uid: ${id}`);
336
+ let W = this.subStreamWidth;
337
+ let H = this.subStreamHeight;
338
+ let el = document.getElementById(id);
339
+ if (!el) {
340
+ el = document.createElement('div');
341
+ el.id = id;
342
+ el.style.width = `${W}px`;
343
+ el.style.height = `${H}px`;
344
+ this.videoContainer.appendChild(el);
345
+ }
346
+ this.remoteVideos[id] = el;
347
+ trtcCloud.startRemoteSubStreamView(uid, el);
348
+ trtcCloud.setRemoteSubStreamViewFillMode(uid, TRTCVideoFillMode.TRTCVideoFillMode_Fill);
349
+ this.videoTypeSetting();
350
+ },
351
+
352
+ /**
353
+ * 关闭远程用户的屏幕分享
354
+ *
355
+ * @param {*} uid
356
+ */
357
+ closeRemoteScreenSharing (uid) {
358
+ let id = `${uid}-${this.roomId}-${TRTCVideoStreamType.TRTCVideoStreamTypeSub}`;
359
+ let el = document.getElementById(id);
360
+ if (el) {
361
+ this.videoContainer.removeChild(el);
362
+ }
363
+ delete this.remoteVideos[id];
364
+ this.videoTypeSetting();
365
+ },
366
+
367
+ /**
368
+ * 开启/关闭麦克风
369
+ */
370
+ toggleMic(event) {
371
+ this.isMuteMic = !this.isMuteMic;
372
+ trtcCloud.muteLocalAudio(this.isMuteMic);
373
+ logger.log('toggleMic', this.isMuteMic, event);
374
+ },
375
+
376
+ /**
377
+ * 开启/关闭摄像头
378
+ */
379
+ toggleCamera(event) {
380
+ this.isDisableCamara = !this.isDisableCamara;
381
+ if (this.isDisableCamara === true) {
382
+ this.hideLocalCameraVideoDom();
383
+ } else {
384
+ this.showLocalCameraVideoDom();
385
+ }
386
+ trtcCloud.muteLocalVideo(this.isDisableCamara);
387
+ logger.log('toggleCamera', this.isDisableCamara, event);
388
+ },
389
+
390
+ /**
391
+ * 显示/隐藏屏幕分享控制条
392
+ */
393
+ toggleCreenShareControlBar(){
394
+ if (this.isPushing===false) {
395
+ this.$bvToast.show('开启推流后,才能分享屏幕');
396
+ return;
397
+ }
398
+ this.screenSharingControllerBarVisiable = !this.screenSharingControllerBarVisiable;
399
+
400
+ },
401
+
402
+ /**
403
+ * 开启 / 关闭屏幕分享,开启时会弹出窗口选择列表
404
+ */
405
+ toggleScreenSharing() {
406
+ logger.log('toggleScreenSharing');
407
+ if (this.isRemoteScreenSharing === true) {
408
+ logger.log('toggleScreenSharing, ignore');
409
+ this.$bvToast.toast(`其他主播正在分享屏幕,您现在无法分享。`, {
410
+ variant: 'warning',
411
+ });
412
+ return;
413
+ }
414
+ if (this.isScreenSharing === false) {
415
+ this.getScreensList();
416
+ logger.log('toggleScreenSharing, getScreenList');
417
+ return;
418
+ }
419
+ this.isScreenSharing = false;
420
+ this.stopScreenShare();
421
+ },
422
+
423
+ /**
424
+ * 获取窗口列表,用于屏幕分享
425
+ */
426
+ getScreensList() {
427
+ // 获取窗口快照,这是资源消耗很高的函数,做个防抖,防频繁点击。
428
+ clearTimeout(this.getScreensTaskID);
429
+ let my = this;
430
+ this.getScreensTaskID = setTimeout(()=>{
431
+ logger.log('getScreensList');
432
+ my.screensList = trtcCloud.getScreenCaptureSources(200, 160, 0, 0);
433
+ my.screensListVisiable = true;
434
+ }, 200);
435
+ },
436
+
437
+ /**
438
+ * 当在show-screen-capture 组件中选择了一个窗口快照后,会开始屏幕分享
439
+ */
440
+ chooseWindowCapture(event) {
441
+ let source = {
442
+ sourceId: event.currentTarget.dataset.id,
443
+ sourceName: event.currentTarget.dataset.name,
444
+ type: parseInt(event.currentTarget.dataset.type),
445
+ };
446
+ logger.log('chooseWindowCapture:', source);
447
+ this.startScreenShare(source);
448
+ this.screensListVisiable = false;
449
+ this.isScreenSharing = true;
450
+ },
451
+
452
+ /**
453
+ * 开始屏幕分享
454
+ */
455
+ startScreenShare(source) {
456
+ logger.log('startScreenShare');
457
+ let rect = new Rect();
458
+ rect.top = 0; // 左坐标
459
+ rect.left = 0; // 上坐标
460
+ rect.width = 0; // 宽度
461
+ rect.height = 0; // 高度
462
+ trtcCloud.selectScreenCaptureTarget(source.type, source.sourceId, source.sourceName, rect, true, true);
463
+ trtcCloud.startScreenCapture();
464
+ },
465
+
466
+ /**
467
+ * 暂停屏幕分享
468
+ */
469
+ pauseScreenShare(){
470
+ logger.log('pauseScreenShare');
471
+ trtcCloud.pauseScreenCapture();
472
+ },
473
+
474
+ /**
475
+ * 恢复屏幕分享
476
+ */
477
+ resumeScreenShare() {
478
+ logger.log('resumeScreenShare');
479
+ trtcCloud.resumeScreenCapture();
480
+ this.isScreenSharingPlaying = true;
481
+ },
482
+
483
+
484
+ /**
485
+ * 停止屏幕分享
486
+ */
487
+ stopScreenShare() {
488
+ logger.log('stopScreenShare');
489
+ trtcCloud.stopScreenCapture();
490
+ this.isScreenSharing = false;
491
+ this.videoTypeSetting();
492
+ },
493
+
494
+ /**
495
+ * 离开房间
496
+ */
497
+ exitRoom(event) {
498
+ logger.log('exitRoom', event);
499
+ trtcCloud.exitRoom();
500
+ let my = this;
501
+ setTimeout(()=>{
502
+ my.$router.push('/live-index/anchor');
503
+ }, 0 );
504
+ },
505
+
506
+ /**
507
+ * 隐藏本地视频的DOM元素
508
+ */
509
+ hideLocalCameraVideoDom() {
510
+ document.querySelector('div.local-video-container').style.display = 'none';
511
+ },
512
+
513
+ /**
514
+ * 显示本地视频的DOM元素
515
+ */
516
+ showLocalCameraVideoDom() {
517
+ document.querySelector('div.local-video-container').style.display = 'inline-block';
518
+ },
519
+
520
+ /**
521
+ * 启动摄像头、麦克风,显示本地画面
522
+ */
523
+ startCameraAndMic() {
524
+ let id = `local_video-${this.roomId}-${TRTCVideoStreamType.TRTCVideoStreamTypeBig}`;
525
+ logger.log(`startCameraAndMic: ${id}`);
526
+ let view = document.getElementById(id);
527
+ if (!view) {
528
+ view = document.createElement('div');
529
+ view.id = id;
530
+ view.className = 'local-video-container';
531
+ this.videoContainer.appendChild(view);
532
+ }
533
+ trtcCloud.startLocalPreview(view);
534
+ trtcCloud.startLocalAudio();
535
+ trtcCloud.setLocalViewFillMode(TRTCVideoFillMode.TRTCVideoFillMode_Fill);
536
+ },
537
+ warn(message) {
538
+ logger.warn(message);
539
+ this.$bvToast.toast(message, {
540
+ title: '警告',
541
+ variant: 'warning',
542
+ solid: true
543
+ });
544
+ }
545
+ },
546
+
547
+ mounted() {
548
+ // 没有摄像头,有麦克风,可以音频
549
+ if (trtcState.isCameraReady() === false) {
550
+ this.warn('找不到可用的摄像头,观众将无法看到您的画面。');
551
+ }
552
+ // 有摄像头,没有麦克风,可以视频
553
+ if (trtcState.isMicReady() === false) {
554
+ this.warn('找不到可用的麦克风,观众将无法听到您的声音。');
555
+ }
556
+ // 1. 获取用于承载视频的 HTMLElement;
557
+ this.videoContainer = document.querySelector('#video-container');
558
+ logger.log(`mounted: `, this.$route.params);
559
+
560
+ // 获取 vue-router 传参:userId 和 roomId
561
+ this.roomId = parseInt(this.$route.params.roomId); // roomId 为整数类型
562
+ this.userId = this.$route.params.userId.toString(); // userId 为字符串类型
563
+ this.cameraId = decodeURIComponent(this.$route.params.cameraId.toString()); // 摄像头ID
564
+
565
+ if (!this.roomId || !this.userId) {
566
+ this.$bvToast.toast('roomId 或 userId 为空,请填写后再试。');
567
+ this.$router.push('live-index/anchor');
568
+ return;
569
+ }
570
+
571
+ // 2. 计算签名
572
+ this.sdkInfo = genTestUserSig(this.userId);
573
+
574
+ // 3. 实例化一个 TRTCCloud (包装了 TRTCCloud的类)
575
+ trtcCloud = new TRTCCloud();
576
+ logger.warn(`sdk version: ${trtcCloud.getSDKVersion()}`);
577
+
578
+ // 4. 配置基本的事件订阅
579
+ trtcCloud.on('onError',(err)=>{logger.error(err)});
580
+ trtcCloud.on('onEnterRoom', this.onEnterRoom.bind(this));
581
+ trtcCloud.on('onExitRoom', this.onExitRoom.bind(this));
582
+ trtcCloud.on('onUserVideoAvailable', this.onUserVideoAvailable.bind(this));
583
+ trtcCloud.on('onRemoteUserEnterRoom', this.onRemoteUserEnterRoom.bind(this));
584
+ trtcCloud.on('onRemoteUserLeaveRoom', this.onRemoteUserLeaveRoom.bind(this));
585
+ trtcCloud.on('onUserSubStreamAvailable', this.onUserSubStreamAvailable.bind(this));
586
+ logger.log(`mounted, setCurrentCameraDevice('${this.cameraId}')`);
587
+ trtcCloud.setCurrentCameraDevice(this.cameraId);
588
+ // 5. 设置编码参数
589
+ // TRTCVideoEncParam 的详细说明,请参考: https://web.sdk.qcloud.com/trtc/electron/doc/zh-cn/trtc_electron_sdk/TRTCVideoEncParam.html
590
+ let encParam = new TRTCVideoEncParam();
591
+
592
+ /**
593
+ * videoResolution
594
+ * 【字段含义】 视频分辨率
595
+ * 【推荐取值】 : Window 和 iMac 建议选择 640 × 360 及以上分辨率,resMode 选择 TRTCVideoResolutionModeLandscape
596
+ * 【特别说明】 TRTCVideoResolution 默认只能横屏模式的分辨率,例如640 × 360。
597
+ */
598
+ encParam.videoResolution = TRTCVideoResolution.TRTCVideoResolution_640_360;
599
+
600
+ /**
601
+ * TRTCVideoResolutionMode
602
+ *【字段含义】分辨率模式(横屏分辨率 - 竖屏分辨率)
603
+ *【推荐取值】Window 和 Mac 建议选择 TRTCVideoResolutionModeLandscape
604
+ *【特别说明】如果 videoResolution 指定分辨率 640 × 360,resMode 指定模式为 Portrait,则最终编码出的分辨率为360 × 640。
605
+ */
606
+ encParam.resMode = TRTCVideoResolutionMode.TRTCVideoResolutionModeLandscape;
607
+ encParam.videoFps = 25;
608
+ encParam.videoBitrate = 800;
609
+ encParam.enableAdjustRes = true;
610
+ trtcCloud.setVideoEncoderParam(encParam);
611
+
612
+ // 6. 开启美颜
613
+ // setBeautyStyle 详细信息,请参考:https://web.sdk.qcloud.com/trtc/electron/doc/zh-cn/trtc_electron_sdk/TRTCCloud.html#setBeautyStyle
614
+ trtcCloud.setBeautyStyle(TRTCBeautyStyle.TRTCBeautyStyleNature, 9, 9, 9);
615
+
616
+ // 7. 显示摄像头画面和开房麦克风
617
+ this.startCameraAndMic();
618
+
619
+ // 执行倒计时
620
+ this.startLiveCountDown();
621
+
622
+ // 挂到 windows BOM 下,方便调试。
623
+ window.trtc = trtcCloud;
624
+ window.videoEncode = new BDVideoEncode(trtcCloud);
625
+ window.beauty = new BDBeauty(trtcCloud);
626
+ },
627
+
628
+ beforeDestroy() {
629
+ this.isScreenSharing = false;
630
+ }
631
+ };
632
+
633
+ </script>
634
+
635
+ <style scoped>
636
+ #controll-bar {
637
+ position: fixed;
638
+ width: 100%;
639
+ height: 10vh;
640
+ bottom: 0;
641
+ left: 0;
642
+ text-align: center;
643
+ background-color: rgba(0, 0, 0, 0.3);
644
+ padding-top: 0.9em;
645
+ }
646
+
647
+ #controll-bar > button {
648
+ margin: 0 2em;
649
+ border: none;
650
+ }
651
+
652
+ #controll-bar > button > .b-icon {
653
+ width: 2.5;
654
+ }
655
+ .close-bt {
656
+ position: relative;
657
+ top: -0.5vh;
658
+ right: -1vw;
659
+ }
660
+ #count-down-layer {
661
+ position: absolute;
662
+ top: 50%;
663
+ left: 50%;
664
+ width: 66vw;
665
+ height: 14vh;
666
+ font-size: 7vh;
667
+ border: 0.5vw #3f3 solid;
668
+ color: #3f3;
669
+ margin-top: -7vh;
670
+ margin-left: -33vw;
671
+ text-align: center;
672
+ line-height: 14vh;
673
+ overflow: hidden;
674
+ }
675
+ #audience-list {
676
+ position: absolute;
677
+ top: 10vh;
678
+ left: 1vw;
679
+ color: #fff;
680
+ text-shadow: #000 0 0 2px;
681
+ }
682
+ #loading {
683
+ position: absolute;
684
+ width: 30vw;
685
+ top: 60%;
686
+ left: 50%;
687
+ margin-left: -15vw;
688
+ }
689
+ </style>