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,297 @@
1
+ // import logger from './log/logger';
2
+ import { isUndefined } from './utils';
3
+
4
+ export const USER_AGENT = (window.navigator && window.navigator.userAgent) || '';
5
+ const webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT);
6
+ const appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null;
7
+ /*
8
+ * Device is an iPhone
9
+ *
10
+ * @type {Boolean}
11
+ * @constant
12
+ * @private
13
+ */
14
+ export const IS_IPAD = /iPad/i.test(USER_AGENT);
15
+
16
+ // The Facebook app's UIWebView identifies as both an iPhone and iPad, so
17
+ // to identify iPhones, we need to exclude iPads.
18
+ // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
19
+ export const IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD;
20
+ export const IS_IPOD = /iPod/i.test(USER_AGENT);
21
+ export const IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;
22
+
23
+ export const IOS_VERSION = IS_IOS
24
+ && (function () {
25
+ const match = USER_AGENT.match(/OS (\d+)_/i);
26
+
27
+ if (match && match[1]) {
28
+ return match[1];
29
+ }
30
+ return null;
31
+ }());
32
+
33
+ export const IS_ANDROID = /Android/i.test(USER_AGENT);
34
+ export const ANDROID_VERSION = IS_ANDROID
35
+ && (function () {
36
+ // This matches Android Major.Minor.Patch versions
37
+ // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
38
+ const match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
39
+
40
+ if (!match) {
41
+ return null;
42
+ }
43
+
44
+ const major = match[1] && parseFloat(match[1]);
45
+ const minor = match[2] && parseFloat(match[2]);
46
+
47
+ if (major && minor) {
48
+ return parseFloat(`${match[1]}.${match[2]}`);
49
+ } if (major) {
50
+ return major;
51
+ }
52
+ return null;
53
+ }());
54
+
55
+ // Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser
56
+ export const IS_OLD_ANDROID = IS_ANDROID && /webkit/i.test(USER_AGENT) && ANDROID_VERSION < 2.3;
57
+ export const IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
58
+
59
+ // Firefox
60
+ export const IS_FIREFOX = /Firefox/i.test(USER_AGENT);
61
+ export const FIREFOX_VERSION = IS_FIREFOX
62
+ && (function () {
63
+ const match = USER_AGENT.match(/Firefox\/(\d+)/);
64
+ if (match && match[1]) {
65
+ return parseFloat(match[1]);
66
+ }
67
+ return null;
68
+ }());
69
+
70
+ // old Edge
71
+ export const IS_EDGE = /Edge\//i.test(USER_AGENT);
72
+ export const EDGE_VERSION = IS_EDGE
73
+ && (function () {
74
+ const match = USER_AGENT.match(/Edge\/(\d+)/i);
75
+ if (match && match[1]) {
76
+ return match[1];
77
+ }
78
+ }());
79
+ // new Edge
80
+ export const IS_EDG = /Edg\//i.test(USER_AGENT);
81
+ export const EDG_VERSION = IS_EDG
82
+ && (function () {
83
+ const match = USER_AGENT.match(/Edg\/(\d+)/);
84
+ if (match && match[1]) {
85
+ return parseFloat(match[1]);
86
+ }
87
+ return null;
88
+ }());
89
+
90
+ // sogou mobile
91
+ export const IS_SOGOUM = /SogouMobileBrowser\//i.test(USER_AGENT);
92
+ export const SOGOUM_VERSION = IS_SOGOUM
93
+ && (function () {
94
+ const match = USER_AGENT.match(/SogouMobileBrowser\/(\d+)/);
95
+ if (match && match[1]) {
96
+ return parseFloat(match[1]);
97
+ }
98
+ return null;
99
+ }());
100
+
101
+ // sogou desktop
102
+ export const IS_SOGOU = /MetaSr\s/i.test(USER_AGENT);
103
+ export const SOGOU_VERSION = IS_SOGOU
104
+ && (function () {
105
+ const match = USER_AGENT.match(/MetaSr(\s\d+(\.\d+)+)/);
106
+ if (match && match[1]) {
107
+ return parseFloat(match[1]);
108
+ }
109
+ return null;
110
+ }());
111
+
112
+ export const IS_TBS = /TBS\/\d+/i.test(USER_AGENT); // 仅X5内核,QQ浏览器默认x5内核,但是agent没有TBS
113
+ export const TBS_VERSION = IS_TBS
114
+ && (function () {
115
+ const match = USER_AGENT.match(/TBS\/(\d+)/i);
116
+ if (match && match[1]) {
117
+ return match[1];
118
+ }
119
+ }()); // TBS内核版本
120
+
121
+ export const IS_XWEB = /XWEB\/\d+/i.test(USER_AGENT);
122
+ export const XWEB_VERSION = IS_XWEB
123
+ && (function () {
124
+ const match = USER_AGENT.match(/XWEB\/(\d+)/i);
125
+ if (match && match[1]) {
126
+ return match[1];
127
+ }
128
+ }()); // XWEB内核版本
129
+
130
+ // IE
131
+ export const IS_IE8 = /MSIE\s8\.0/.test(USER_AGENT);
132
+ export const IS_IE = /MSIE\/\d+/i.test(USER_AGENT);
133
+ export const IE_VERSION = IS_IE
134
+ && (function () {
135
+ const result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT);
136
+ let version = result && parseFloat(result[1]);
137
+
138
+ if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) {
139
+ // IE 11 has a different user agent string than other IE versions
140
+ version = 11.0;
141
+ }
142
+
143
+ return version;
144
+ }());
145
+
146
+ export const IS_WECHAT = /(micromessenger|webbrowser)/i.test(USER_AGENT);
147
+ export const WECHAT_VERSION = IS_WECHAT
148
+ && (function () {
149
+ const match = USER_AGENT.match(/MicroMessenger\/(\d+)/i);
150
+ if (match && match[1]) {
151
+ return match[1];
152
+ }
153
+ }());
154
+
155
+ export const IS_X5MQQB = !IS_TBS && /MQQBrowser\/\d+/i.test(USER_AGENT) && /COVC\/\d+/i.test(USER_AGENT); // 移动端 QQ X5 内核浏览器
156
+ export const IS_MQQB = !IS_TBS && /MQQBrowser\/\d+/i.test(USER_AGENT) && !/COVC\/\d+/i.test(USER_AGENT); // 移动端 QQ 浏览器
157
+ export const MQQB_VERSION = (IS_MQQB || IS_X5MQQB)
158
+ && (function () {
159
+ const match = USER_AGENT.match(/ MQQBrowser\/([\d.]+)/);
160
+ if (match && match[1]) return match[1];
161
+ return null;
162
+ }());
163
+
164
+ export const IS_WQQB = !IS_TBS && / QQBrowser\/\d+/i.test(USER_AGENT); // windows端QQ浏览器
165
+ export const WQQB_VERSION = IS_WQQB
166
+ && (function () {
167
+ const match = USER_AGENT.match(/ QQBrowser\/([\d.]+)/);
168
+ if (match && match[1]) return match[1];
169
+ return null;
170
+ }());
171
+
172
+ export const IS_MACQQB = !IS_TBS && /QQBrowserLite\/\d+/i.test(USER_AGENT); // Mac端QQ浏览器
173
+ export const MACQQB_VERSION = IS_MACQQB
174
+ && (function () {
175
+ const match = USER_AGENT.match(/QQBrowserLite\/([\d.]+)/);
176
+ if (match && match[1]) return match[1];
177
+ return null;
178
+ }());
179
+
180
+ export const IS_IPADQQB = !IS_TBS && /MQBHD\/\d+/i.test(USER_AGENT); // iPad端QQ浏览器
181
+ export const IPADQQB_VERSION = IS_IPADQQB
182
+ && (function () {
183
+ const match = USER_AGENT.match(/MQBHD\/([\d.]+)/);
184
+ if (match && match[1]) return match[1];
185
+ return null;
186
+ }());
187
+
188
+ export const IS_WIN = /Windows/i.test(USER_AGENT); // window系统
189
+ export const IS_MAC = !IS_IOS && /MAC OS X/i.test(USER_AGENT); // MAC系统,先检查IOS
190
+ export const IS_LINUX = !IS_ANDROID && /Linux/i.test(USER_AGENT);
191
+ export const IS_WX = /MicroMessenger/i.test(USER_AGENT); // 是否为微信环境
192
+ export const IS_UCBROWSER = /UCBrowser/i.test(USER_AGENT);
193
+ export const IS_ELECTRON = /Electron/i.test(USER_AGENT); // 是否为 electron
194
+
195
+ export const IS_MIBROWSER = /MiuiBrowser/i.test(USER_AGENT); // 小米浏览器
196
+ export const MI_VERSION = IS_MIBROWSER
197
+ && (function () {
198
+ const match = USER_AGENT.match(/MiuiBrowser\/([\d.]+)/);
199
+ if (match && match[1]) return match[1];
200
+ return null;
201
+ }());
202
+ export const IS_HUAWEIBROWSER = /HuaweiBrowser/i.test(USER_AGENT); // 华为浏览器
203
+ export const IS_HUAWEI = /Huawei/i.test(USER_AGENT); // 华为设备
204
+ export const HUAWEI_VERSION = IS_HUAWEIBROWSER
205
+ && (function () {
206
+ const match = USER_AGENT.match(/HuaweiBrowser\/([\d.]+)/);
207
+ if (match && match[1]) return match[1];
208
+ return null;
209
+ }());
210
+
211
+ export const IS_SAMSUNGBROWSER = /SamsungBrowser/i.test(USER_AGENT); // 三星浏览器
212
+ export const SAMSUNG_VERSION = IS_SAMSUNGBROWSER
213
+ && (function () {
214
+ const match = USER_AGENT.match(/SamsungBrowser\/([\d.]+)/);
215
+ if (match && match[1]) return match[1];
216
+ return null;
217
+ }());
218
+ export const IS_OPPOBROWSER = /HeyTapBrowser/i.test(USER_AGENT); // OPPO浏览器
219
+ export const OPPO_VERSION = IS_OPPOBROWSER
220
+ && (function () {
221
+ const match = USER_AGENT.match(/HeyTapBrowser\/([\d.]+)/);
222
+ if (match && match[1]) return match[1];
223
+ return null;
224
+ }());
225
+ export const IS_VIVOBROWSER = /VivoBrowser/i.test(USER_AGENT); // OPPO浏览器
226
+ export const VIVO_VERSION = IS_VIVOBROWSER
227
+ && (function () {
228
+ const match = USER_AGENT.match(/VivoBrowser\/([\d.]+)/);
229
+ if (match && match[1]) return match[1];
230
+ return null;
231
+ }());
232
+
233
+ // Chrome
234
+ export const IS_CHROME_ONLY = /Chrome/i.test(USER_AGENT);
235
+ export const IS_CHROME = !IS_EDGE
236
+ && !IS_SOGOU
237
+ && !IS_SOGOUM
238
+ && !IS_TBS
239
+ && !IS_XWEB
240
+ && !IS_EDG
241
+ && !IS_WQQB
242
+ && !IS_MIBROWSER
243
+ && !IS_HUAWEIBROWSER
244
+ && !IS_SAMSUNGBROWSER
245
+ && !IS_OPPOBROWSER
246
+ && !IS_VIVOBROWSER
247
+ && /Chrome/i.test(USER_AGENT);
248
+ export const CHROME_MAJOR_VERSION = IS_CHROME
249
+ && (function () {
250
+ const match = USER_AGENT.match(/Chrome\/(\d+)/);
251
+
252
+ if (match && match[1]) {
253
+ return parseFloat(match[1]);
254
+ }
255
+ return null;
256
+ }());
257
+ export const CHROME_VERSION = IS_CHROME
258
+ && (function () {
259
+ const match = USER_AGENT.match(/Chrome\/([\d.]+)/);
260
+ if (match && match[1]) return match[1];
261
+ return null;
262
+ }());
263
+
264
+ // Safari
265
+ export const IS_SAFARI = !IS_CHROME_ONLY && !IS_MQQB && !IS_X5MQQB && !IS_MACQQB && !IS_IPADQQB && /Safari/i.test(USER_AGENT);
266
+ export const IS_ANY_SAFARI = IS_SAFARI || IS_IOS;
267
+ export const SAFARI_VERSION = IS_SAFARI
268
+ && (function () {
269
+ const match = USER_AGENT.match(/Version\/([\d.]+)/);
270
+ if (match && match[1]) return match[1];
271
+ return null;
272
+ }());
273
+
274
+ //
275
+ export const BROWSER_VERSION = IS_CHROME ? `Chrome/${CHROME_VERSION}` : IS_SAFARI ? `Safari/${SAFARI_VERSION}` : 'NotSupportedBrowser';
276
+
277
+ // 是否本地环境 file, localhost, ip 地址
278
+ export const IS_LOCAL = location.protocol === 'file:' || location.hostname === 'localhost' || /^\d+\.\d+\.\d+\.\d+$/.test(location.hostname);
279
+
280
+ /**
281
+ * 检测 LocalStorage 是否可用
282
+ * @export
283
+ * @return {Boolean}
284
+ */
285
+ export const isLocalStorageEnabled = (() => {
286
+ let result;
287
+ return () => {
288
+ if (isUndefined(result)) {
289
+ try {
290
+ result = window.localStorage;
291
+ } catch (error) {
292
+ result = false;
293
+ }
294
+ }
295
+ return result;
296
+ };
297
+ })();
@@ -0,0 +1,131 @@
1
+ /* eslint-disable no-underscore-dangle */
2
+ import generateUUID from './uuid';
3
+ import { performanceNow } from './utils';
4
+
5
+ /**
6
+ * 基于 requestAnimationFrame 实现类 setInterval 的功能
7
+ * @class RAF
8
+ */
9
+ class RAF {
10
+ constructor() {
11
+ // Map<intervalId, { rafId, timeoutId, onVisibilityChange}>
12
+ // rafId: requestAnimationFrame 返回的 id
13
+ // timeoutId: setTimeout 返回的 id。在页面隐藏时,使用 setTimeout 作为 requestAnimationFrame 的 backup
14
+ // onVisibilityChange: 监听页面可视性变更的回调,保存该回调是用于在结束 interval 时注销监听。
15
+ this.intervalMap_ = new Map();
16
+ }
17
+
18
+ /**
19
+ * 基于 requestAnimationFrame 实现类 setInterval 的功能
20
+ * 当页面隐藏时,会用 setTimeout 作为 backup
21
+ * @param {function} fn
22
+ * @param {number} interval 时间间隔
23
+ * @param {boolean} [enableInBackground=true] 当页面切换到后台时,是否执行 interval
24
+ * @return {string} intervalId
25
+ * @memberof RAF
26
+ */
27
+ setInterval(fn, interval, enableInBackground = true) {
28
+ const intervalId = generateUUID();
29
+ let startTime = performanceNow();
30
+ let endTime = startTime;
31
+
32
+ this.intervalMap_.set(intervalId, {
33
+ rafId: null,
34
+ timeoutId: null,
35
+ onVisibilityChange: null,
36
+ });
37
+
38
+ const rafLoop = () => {
39
+ // 当页面隐藏时,用 setTimeout 作为 backup
40
+ if (enableInBackground && document.hidden) {
41
+ fn();
42
+ const timeoutId = setTimeout(rafLoop, interval);
43
+ this.setTimeoutId(intervalId, timeoutId);
44
+ startTime = performanceNow();
45
+ endTime = startTime;
46
+ } else {
47
+ endTime = performanceNow();
48
+ if (endTime - startTime >= interval) {
49
+ startTime = endTime;
50
+ fn();
51
+ }
52
+ const rafId = requestAnimationFrame(rafLoop);
53
+
54
+ this.setRafId(intervalId, rafId);
55
+ }
56
+ };
57
+ const rafId = requestAnimationFrame(rafLoop);
58
+ this.setRafId(intervalId, rafId);
59
+
60
+ // 当页面隐藏时,用 setTimeout 作为 backup
61
+ if (enableInBackground) {
62
+ const onVisibilityChange = () => {
63
+ if (document.hidden) {
64
+ const span = performanceNow() - startTime;
65
+ // 页面隐藏时,距离上次回调执行完的间隔超过 interval,则立即执行 rafLoop
66
+ if (span >= interval) {
67
+ rafLoop();
68
+ } else {
69
+ // 页面隐藏时,未达 interval,则在 interval - span 后执行 rafLoop
70
+ const timeoutId = setTimeout(rafLoop, interval - span);
71
+ this.setTimeoutId(intervalId, timeoutId);
72
+ }
73
+ }
74
+ };
75
+ document.addEventListener('visibilitychange', onVisibilityChange);
76
+ this.setOnVisibilityChange(intervalId, onVisibilityChange);
77
+ }
78
+
79
+ return intervalId;
80
+ }
81
+
82
+ /**
83
+ * 清除 interval
84
+ * @param {string} intervalId
85
+ * @memberof RAF
86
+ */
87
+ clearInterval(intervalId) {
88
+ if (this.intervalMap_.has(intervalId)) {
89
+ const { rafId, timeoutId, onVisibilityChange } = this.intervalMap_.get(intervalId);
90
+ cancelAnimationFrame(rafId);
91
+ clearTimeout(timeoutId);
92
+ document.removeEventListener('visibilitychange', onVisibilityChange);
93
+ this.intervalMap_.delete(intervalId);
94
+ }
95
+ }
96
+
97
+ setTimeoutId(intervalId, timeoutId) {
98
+ if (this.intervalMap_.has(intervalId)) {
99
+ const value = this.intervalMap_.get(intervalId);
100
+ // 在设置新的 timeout 之前,需清理先前的 timeout
101
+ // 避免来回切换 tab 时,重复设置
102
+ if (value.timeoutId) {
103
+ clearTimeout(value.timeoutId);
104
+ }
105
+ value.timeoutId = timeoutId;
106
+ }
107
+ }
108
+
109
+ setRafId(intervalId, rafId) {
110
+ if (this.intervalMap_.has(intervalId)) {
111
+ const value = this.intervalMap_.get(intervalId);
112
+ // 在设置新的 requestAnimationFrame 之前,需清理先前设置的 raf
113
+ // 避免来回切换 tab 时,重复设置
114
+ if (value.rafId) {
115
+ cancelAnimationFrame(value.rafId);
116
+ }
117
+ value.rafId = rafId;
118
+ }
119
+ }
120
+
121
+ setOnVisibilityChange(intervalId, onVisibilityChange) {
122
+ if (this.intervalMap_.has(intervalId)) {
123
+ const value = this.intervalMap_.get(intervalId);
124
+ value.onVisibilityChange = onVisibilityChange;
125
+ }
126
+ }
127
+ }
128
+
129
+ const raf = new RAF();
130
+
131
+ export default raf;
@@ -0,0 +1,22 @@
1
+ // user system clock may be inaccurate, so we need to adjust the timestamp
2
+ // based on the baseTime received from remote server
3
+
4
+ let baseTime = new Date().getTime();
5
+ let offset = 0;
6
+
7
+ export const setBaseTime = function (time) {
8
+ baseTime = time;
9
+ offset = baseTime - new Date().getTime();
10
+ const base = new Date();
11
+ base.setTime(time);
12
+ };
13
+
14
+ export const getCurrentTime = function () {
15
+ return new Date().getTime() + offset;
16
+ };
17
+
18
+ export const getTimestamp = function () {
19
+ const now = new Date();
20
+ now.setTime(getCurrentTime());
21
+ return now.toLocaleString();
22
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * 获取向下取整的 performance.now() 值
3
+ * @export
4
+ * @return {Number}
5
+ */
6
+ // eslint-disable-next-line require-jsdoc
7
+ export function performanceNow() {
8
+ return Math.floor(performance.now());
9
+ }
10
+
11
+ export const isFunction = (param: any) => typeof param === 'function';
12
+ export const isUndefined = (param: any) => typeof param === 'undefined';
13
+ export const isString = (param: any) => typeof param === 'string';
14
+ export const isNumber = (param: any) => typeof param === 'number';
15
+ export const isBoolean = (param: any) => typeof param === 'boolean';
16
+
17
+ /**
18
+ * mixins class
19
+ */
20
+ export function MixinsClass(...mixins: any[]): any {
21
+ class MixClass {
22
+ constructor() {
23
+ // eslint-disable-next-line no-restricted-syntax
24
+ for (const Mixin of mixins) {
25
+ copyProperties(this, new Mixin(this)); // 拷贝实例属性 同时执行内部初始化
26
+ }
27
+ }
28
+ }
29
+ const proto = MixClass.prototype;
30
+ // eslint-disable-next-line no-restricted-syntax
31
+ for (const mixin of mixins) {
32
+ copyProperties(MixClass, mixin); // 拷贝静态属性
33
+ copyProperties(proto, mixin.prototype); // 拷贝原型属性
34
+ }
35
+ return MixClass;
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @param target
41
+ * @param source
42
+ */
43
+ function copyProperties(target: any, source: any) {
44
+ // eslint-disable-next-line no-restricted-syntax
45
+ for (const key of Reflect.ownKeys(source)) {
46
+ if (key !== 'constructor' && key !== 'prototype' && key !== 'name') {
47
+ const desc = Object.getOwnPropertyDescriptor(source, key) || '';
48
+ Object.defineProperty(target, key, desc);
49
+ }
50
+ }
51
+ }
52
+
53
+ /**
54
+ * 防抖函数
55
+ * @param {Function} fn 要执行的函数
56
+ * @param {Number} delay 间隔时间, 毫秒
57
+ * @returns function
58
+ */
59
+ // eslint-disable-next-line no-unused-vars
60
+ export function debounce(fn: { apply: (arg0: any, arg1: any) => void; }, delay: number | undefined) {
61
+ let timer: number;
62
+ return function (this:any, ...args: any) {
63
+ if (timer > 0) {
64
+ clearTimeout(timer);
65
+ }
66
+ timer = window.setTimeout(() => {
67
+ fn.apply(this, args);
68
+ timer = -1;
69
+ }, delay);
70
+ };
71
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * UUID generator - RFC4122 version 4 compliant solution
3
+ */
4
+ const generateUUID = function () {
5
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
6
+ const r = (Math.random() * 16) | 0;
7
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
8
+ return v.toString(16);
9
+ });
10
+ };
11
+
12
+ export default generateUUID;
@@ -0,0 +1,25 @@
1
+ import log from '../../src/utils/log/logger';
2
+ import * as env from '../../src/utils/environment';
3
+ import * as rtcDetection from '../../src/rtc/rtc-detection';
4
+
5
+ describe('environment & rtc-detection unit test', () => {
6
+ it('environment works as expected', () => {
7
+ const isChrome = env.IS_CHROME;
8
+ log.debug(`isChrome:${isChrome} Version: ${env.CHROME_VERSION}`);
9
+ expect(isChrome).toBe(true);
10
+ });
11
+
12
+ it('rtc-detection works as expected', done => {
13
+ const isWebRTCSupported = rtcDetection.isWebRTCSupported();
14
+ expect(isWebRTCSupported).toBe(true);
15
+ const isUnifiedPlanDefault = rtcDetection.isUnifiedPlanDefault();
16
+ expect(isUnifiedPlanDefault).toBe(true);
17
+ const isScreenCaptureApiAvailable = rtcDetection.isScreenCaptureApiAvailable();
18
+ expect(isScreenCaptureApiAvailable).toBe(true);
19
+ rtcDetection.checkH264Support(supported => {
20
+ log.debug('h264Supported: ' + supported);
21
+ expect(supported).toBe(true);
22
+ done();
23
+ });
24
+ });
25
+ });
@@ -0,0 +1,40 @@
1
+ import log from '../../src/utils/log/logger';
2
+ import GetUserMedia from '../../src/rtc/get-user-media';
3
+
4
+ describe('get-user-media.js: ', () => {
5
+ it('GetUserMedia works as expected', done => {
6
+ log.debug('testing GetUserMedia');
7
+ const gum = new GetUserMedia();
8
+ gum.getUserMedia(
9
+ { audio: true, video: true },
10
+ stream => {
11
+ log.debug('getUserMedia got stream success');
12
+ expect(true).toBe(true);
13
+ done();
14
+ },
15
+ () => {
16
+ log.error('getUserMedia failed!');
17
+ expect(false).toBe(false);
18
+ done();
19
+ }
20
+ );
21
+ });
22
+
23
+ it('GetUserMedia with video attributes works as expected', done => {
24
+ log.debug('testing GetUserMedia');
25
+ const gum = new GetUserMedia();
26
+ gum.getUserMedia(
27
+ { audio: true, video: true, width: 640, height: 480, frameRate: 15 },
28
+ stream => {
29
+ log.debug('getUserMedia got stream success');
30
+ expect(true).toBe(true);
31
+ done();
32
+ },
33
+ () => {
34
+ log.error('getUserMedia failed!');
35
+ expect(false).toBe(false);
36
+ done();
37
+ }
38
+ );
39
+ });
40
+ });
@@ -0,0 +1,23 @@
1
+ import log from '../../src/utils/log/logger';
2
+ import * as iceParser from '../../src/rtc/ice-candidate-parser';
3
+
4
+ describe('ice-candidate-parser: ', () => {
5
+ it('iceParser works', () => {
6
+ log.debug('testing iceParser');
7
+ const hostCandidate =
8
+ 'candidate:4211169504 1 udp 2122260223 10.73.47.64 56520 typ host generation 0 ufrag ulxL network-id 1 network-cost 10';
9
+ const srflxCandidate =
10
+ 'candidate:1381947189 1 udp 1686052607 180.153.219.16 15826 typ srflx raddr 10.73.47.64 rport 56520 generation 0 ufrag ulxL network-id 1 network-cost 10';
11
+ const tcpCandidate =
12
+ 'candidate:3045237776 1 tcp 1518280447 10.73.47.64 9 typ host tcptype active generation 0 ufrag ulxL network-id 1 network-cost 10';
13
+ const host = iceParser.parseIceCandidate(hostCandidate);
14
+ log.debug('host.type: ' + host.type);
15
+ expect(host.type).toBe(iceParser.IceType.HOST);
16
+ const srflx = iceParser.parseIceCandidate(srflxCandidate);
17
+ log.debug('srflx.type: ' + srflx.type);
18
+ expect(srflx.type).toBe(iceParser.IceType.SRFLX);
19
+ const tcp = iceParser.parseIceCandidate(tcpCandidate);
20
+ log.debug('tcp.transport: ' + tcp.transport);
21
+ expect(tcp.transport).toBe(iceParser.IceTransport.TCP);
22
+ });
23
+ });