@realsee/live 0.4.0-beta.6 → 0.5.0-alpha.1

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.
@@ -1,7 +1,7 @@
1
1
  import JSBridge from '@realsee/jsbridge-x';
2
- import { DefaultModality, ConsoleLogger, LogLevel, DefaultDeviceController, MeetingSessionConfiguration, DefaultMeetingSession, MeetingSessionStatusCode } from 'amazon-chime-sdk-js';
3
2
  import TRTC from 'trtc-js-sdk';
4
- import React from 'react';
3
+ import { DefaultModality, ConsoleLogger, LogLevel as LogLevel$1, DefaultDeviceController, MeetingSessionConfiguration, DefaultMeetingSession, MeetingSessionStatusCode } from 'amazon-chime-sdk-js';
4
+ import React, { createContext, useCallback } from 'react';
5
5
 
6
6
  const EVENT_SYMBOL = Symbol('$$REALSEE_LIVE_EVENT$$');
7
7
  function __generateEventIfNotExisted(instance) {
@@ -121,6 +121,31 @@ class Subscribe {
121
121
  class CoreRTC extends Subscribe {
122
122
  }
123
123
 
124
+ /******************************************************************************
125
+ Copyright (c) Microsoft Corporation.
126
+
127
+ Permission to use, copy, modify, and/or distribute this software for any
128
+ purpose with or without fee is hereby granted.
129
+
130
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
131
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
132
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
133
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
134
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
135
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
136
+ PERFORMANCE OF THIS SOFTWARE.
137
+ ***************************************************************************** */
138
+
139
+ function __awaiter(thisArg, _arguments, P, generator) {
140
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
141
+ return new (P || (P = Promise))(function (resolve, reject) {
142
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
143
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
144
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
145
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
146
+ });
147
+ }
148
+
124
149
  /**
125
150
  * rtc 类型
126
151
  */
@@ -174,24 +199,21 @@ class BrowserRTC extends CoreRTC {
174
199
  client: null,
175
200
  stream: null,
176
201
  };
177
- this.join = async (options) => {
202
+ this.join = (options) => __awaiter(this, void 0, void 0, function* () {
178
203
  var _a;
179
204
  this.emit('joinWillStart');
180
- const createClientOptions = await this._getVoiceSign({
205
+ const createClientOptions = yield this._getVoiceSign({
181
206
  voiceId: options.voiceId,
182
207
  roomId: options.roomId,
183
208
  userId: options.userId,
184
209
  });
185
210
  // 1. 创建client
186
- this._trtc.client = TRTC.createClient({
187
- mode: 'rtc',
188
- ...createClientOptions,
189
- });
211
+ this._trtc.client = TRTC.createClient(Object.assign({ mode: 'rtc' }, createClientOptions));
190
212
  (_a = this._trtc.client) === null || _a === void 0 ? void 0 : _a.enableAudioVolumeEvaluation();
191
213
  // 2. 订阅事件
192
214
  this._registerRtcEvent();
193
215
  // 3. 加入语音房间
194
- let result = await new Promise((resolve) => {
216
+ let result = yield new Promise((resolve) => {
195
217
  var _a;
196
218
  (_a = this._trtc.client) === null || _a === void 0 ? void 0 : _a.join({ roomId: Number(options.voiceId) }).then(() => resolve(true)).catch(() => resolve(false));
197
219
  });
@@ -205,12 +227,12 @@ class BrowserRTC extends CoreRTC {
205
227
  video: false,
206
228
  });
207
229
  // 5. 初始化本地流
208
- result = await new Promise((resolve) => {
230
+ result = yield new Promise((resolve) => {
209
231
  var _a;
210
232
  (_a = this._trtc.stream) === null || _a === void 0 ? void 0 : _a.initialize().then(() => resolve(true)).catch(() => resolve(false));
211
233
  });
212
234
  // 6. 发布本地流
213
- result = await new Promise((resolve) => {
235
+ result = yield new Promise((resolve) => {
214
236
  var _a;
215
237
  (_a = this._trtc.client) === null || _a === void 0 ? void 0 : _a.publish(this._trtc.stream).then(() => resolve(true)).catch(() => resolve(false));
216
238
  });
@@ -218,7 +240,7 @@ class BrowserRTC extends CoreRTC {
218
240
  if (this.joined)
219
241
  this.emit('joined');
220
242
  return result;
221
- };
243
+ });
222
244
  this._handleStreamAdded = (event) => {
223
245
  var _a;
224
246
  const remoteStream = event.stream;
@@ -246,17 +268,17 @@ class BrowserRTC extends CoreRTC {
246
268
  document.body.appendChild(this.$dom);
247
269
  }
248
270
  quit() {
249
- return new Promise(async (resolve) => {
271
+ return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
250
272
  var _a, _b;
251
273
  this.joined = false;
252
274
  if (this._trtc.stream) {
253
- await ((_a = this._trtc.client) === null || _a === void 0 ? void 0 : _a.unpublish(this._trtc.stream));
275
+ yield ((_a = this._trtc.client) === null || _a === void 0 ? void 0 : _a.unpublish(this._trtc.stream));
254
276
  this._trtc.stream.stop();
255
277
  this._trtc.stream.close();
256
278
  this._trtc.stream = null;
257
279
  }
258
280
  (_b = this._trtc.client) === null || _b === void 0 ? void 0 : _b.leave().then(() => (this._trtc.client = null)).then(() => resolve(true)).catch(() => resolve(false));
259
- });
281
+ }));
260
282
  }
261
283
  detectMicro() {
262
284
  return new Promise((resolve) => {
@@ -419,7 +441,7 @@ class BrowserRTC4Chime extends CoreRTC {
419
441
  // 挂载签名钩子
420
442
  this._getVoiceSign = options.getVoiceSign;
421
443
  this._initDom();
422
- this.logger = new ConsoleLogger('WebRTCLogger', options.logLevel || LogLevel.OFF);
444
+ this.logger = new ConsoleLogger('WebRTCLogger', options.logLevel || LogLevel$1.OFF);
423
445
  this.deviceController = new DefaultDeviceController(this.logger);
424
446
  this.initObservers();
425
447
  }
@@ -428,65 +450,64 @@ class BrowserRTC4Chime extends CoreRTC {
428
450
  * @param options
429
451
  * @returns
430
452
  */
431
- async join(options) {
432
- return new Promise(async (success, fail) => {
433
- var _a;
434
- this.emit('joinWillStart');
435
- try {
436
- // 取签名
437
- const { sdkAppId, userId, roomId, userSig } = await this._getVoiceSign({
438
- ...options,
439
- roomId: options.roomId || 0,
440
- });
441
- this.userId = userId;
442
- const { attendence, vendor_wrapper, } = JSON.parse(decodeURIComponent(userSig));
443
- // 初始化配置
444
- const configuration = new MeetingSessionConfiguration({
445
- Meeting: vendor_wrapper,
446
- }, {
447
- Attendee: {
448
- ExternalUserId: attendence.external_user_id,
449
- AttendeeId: attendence.attendee_id,
450
- JoinToken: attendence.join_token,
451
- },
452
- });
453
- // 初始化会议会话
454
- this.meetingSession = new DefaultMeetingSession(configuration, this.logger, this.deviceController);
455
- // 注册事件
456
- this._registerRtcEvent();
457
- // 绑定监听器
458
- this.meetingSession.audioVideo.addDeviceChangeObserver(this.deviceChangeObserver);
459
- this.meetingSession.audioVideo.addObserver(this.audioVideoObserver);
460
- // 绑定播放器
461
- this.meetingSession.audioVideo.bindAudioElement(this.$audio);
462
- const observer = {
463
- audioVideoDidStart: () => {
464
- var _a;
465
- (_a = this.meetingSession) === null || _a === void 0 ? void 0 : _a.audioVideo.realtimeMuteLocalAudio();
466
- this.joined = true;
467
- this.emit('joined');
468
- success(true);
469
- },
470
- audioVideoDidStop: () => {
471
- this.joined = false;
472
- success(false);
473
- },
474
- };
475
- this.meetingSession.audioVideo.addObserver(observer);
476
- // 选择语音输入设备
477
- const audioInputDevices = await this.deviceController.listAudioInputDevices(true);
478
- const defaultAudioInput = audioInputDevices.find((device) => device.deviceId === 'default');
479
- const otherAudioInput = audioInputDevices.find((device) => device.deviceId !== '');
480
- this.audioInput = defaultAudioInput || otherAudioInput;
481
- await this.meetingSession.audioVideo.chooseVideoInputDevice(null);
482
- await this.meetingSession.audioVideo.chooseAudioInputDevice(((_a = this.audioInput) === null || _a === void 0 ? void 0 : _a.deviceId) || 'default');
483
- this.meetingSession.audioVideo.start();
484
- }
485
- catch (e) {
486
- this.emit('error', e);
487
- this.logger.error(e.message);
488
- success(false);
489
- }
453
+ join(options) {
454
+ return __awaiter(this, void 0, void 0, function* () {
455
+ return new Promise((success, fail) => __awaiter(this, void 0, void 0, function* () {
456
+ var _a;
457
+ this.emit('joinWillStart');
458
+ try {
459
+ // 取签名
460
+ const { sdkAppId, userId, roomId, userSig } = yield this._getVoiceSign(Object.assign(Object.assign({}, options), { roomId: options.roomId || 0 }));
461
+ this.userId = userId;
462
+ const { attendence, vendor_wrapper, } = JSON.parse(decodeURIComponent(userSig));
463
+ // 初始化配置
464
+ const configuration = new MeetingSessionConfiguration({
465
+ Meeting: vendor_wrapper,
466
+ }, {
467
+ Attendee: {
468
+ ExternalUserId: attendence.external_user_id,
469
+ AttendeeId: attendence.attendee_id,
470
+ JoinToken: attendence.join_token,
471
+ },
472
+ });
473
+ // 初始化会议会话
474
+ this.meetingSession = new DefaultMeetingSession(configuration, this.logger, this.deviceController);
475
+ // 注册事件
476
+ this._registerRtcEvent();
477
+ // 绑定监听器
478
+ this.meetingSession.audioVideo.addDeviceChangeObserver(this.deviceChangeObserver);
479
+ this.meetingSession.audioVideo.addObserver(this.audioVideoObserver);
480
+ // 绑定播放器
481
+ this.meetingSession.audioVideo.bindAudioElement(this.$audio);
482
+ const observer = {
483
+ audioVideoDidStart: () => {
484
+ var _a;
485
+ (_a = this.meetingSession) === null || _a === void 0 ? void 0 : _a.audioVideo.realtimeMuteLocalAudio();
486
+ this.joined = true;
487
+ this.emit('joined');
488
+ success(true);
489
+ },
490
+ audioVideoDidStop: () => {
491
+ this.joined = false;
492
+ success(false);
493
+ },
494
+ };
495
+ this.meetingSession.audioVideo.addObserver(observer);
496
+ // 选择语音输入设备
497
+ const audioInputDevices = yield this.deviceController.listAudioInputDevices(true);
498
+ const defaultAudioInput = audioInputDevices.find((device) => device.deviceId === 'default');
499
+ const otherAudioInput = audioInputDevices.find((device) => device.deviceId !== '');
500
+ this.audioInput = defaultAudioInput || otherAudioInput;
501
+ yield this.meetingSession.audioVideo.chooseVideoInputDevice(null);
502
+ yield this.meetingSession.audioVideo.chooseAudioInputDevice(((_a = this.audioInput) === null || _a === void 0 ? void 0 : _a.deviceId) || 'default');
503
+ this.meetingSession.audioVideo.start();
504
+ }
505
+ catch (e) {
506
+ this.emit('error', e);
507
+ this.logger.error(e.message);
508
+ success(false);
509
+ }
510
+ }));
490
511
  });
491
512
  }
492
513
  quit() {
@@ -516,36 +537,40 @@ class BrowserRTC4Chime extends CoreRTC {
516
537
  (_b = this.meetingSession) === null || _b === void 0 ? void 0 : _b.audioVideo.stop();
517
538
  });
518
539
  }
519
- async detectMicro() {
520
- return new Promise((resolve) => {
521
- const rule = { audio: true, video: false };
522
- try {
523
- navigator.mediaDevices
524
- .getUserMedia(rule)
525
- .then(() => resolve(true))
526
- .catch(() => resolve(false));
527
- }
528
- catch (e) {
529
- this.logger.error(e.message);
530
- resolve(false);
531
- }
540
+ detectMicro() {
541
+ return __awaiter(this, void 0, void 0, function* () {
542
+ return new Promise((resolve) => {
543
+ const rule = { audio: true, video: false };
544
+ try {
545
+ navigator.mediaDevices
546
+ .getUserMedia(rule)
547
+ .then(() => resolve(true))
548
+ .catch(() => resolve(false));
549
+ }
550
+ catch (e) {
551
+ this.logger.error(e.message);
552
+ resolve(false);
553
+ }
554
+ });
532
555
  });
533
556
  }
534
- async toggleMicro(flag) {
557
+ toggleMicro(flag) {
535
558
  var _a, _b, _c;
536
- if (flag) {
537
- (_a = this.meetingSession) === null || _a === void 0 ? void 0 : _a.audioVideo.realtimeUnmuteLocalAudio();
538
- }
539
- else {
540
- (_b = this.meetingSession) === null || _b === void 0 ? void 0 : _b.audioVideo.realtimeMuteLocalAudio();
541
- }
542
- const muted = (_c = this.meetingSession) === null || _c === void 0 ? void 0 : _c.audioVideo.realtimeIsLocalAudioMuted();
543
- if (muted !== undefined) {
544
- return flag !== muted;
545
- }
546
- else {
547
- return false;
548
- }
559
+ return __awaiter(this, void 0, void 0, function* () {
560
+ if (flag) {
561
+ (_a = this.meetingSession) === null || _a === void 0 ? void 0 : _a.audioVideo.realtimeUnmuteLocalAudio();
562
+ }
563
+ else {
564
+ (_b = this.meetingSession) === null || _b === void 0 ? void 0 : _b.audioVideo.realtimeMuteLocalAudio();
565
+ }
566
+ const muted = (_c = this.meetingSession) === null || _c === void 0 ? void 0 : _c.audioVideo.realtimeIsLocalAudioMuted();
567
+ if (muted !== undefined) {
568
+ return flag !== muted;
569
+ }
570
+ else {
571
+ return false;
572
+ }
573
+ });
549
574
  }
550
575
  shock() {
551
576
  throw new Error('Method not implemented.');
@@ -594,51 +619,59 @@ class VRWebViewRTC extends CoreRTC {
594
619
  get jsBridge() {
595
620
  return this.options.jsBridge;
596
621
  }
597
- async join(options) {
598
- this.emit('joinWillStart');
599
- const { sdkAppId, userId, userSig } = await this.options.getVoiceSign(options);
600
- this.type = options.type;
601
- const [res, error] = await this.jsBridge.callAndBackfeed(`live/join?sdkAppID=${sdkAppId}&userID=${userId}&roomID=${Number(options.voiceId)}&userSig=${userSig}`);
602
- if (!res) {
603
- this.emit('error', error ? error : new Error('加入房间失败:未知异常。'));
604
- this.joined = false;
605
- }
606
- else {
607
- if (res.code === RTCJoinedInfoCodeEnum.Success) {
608
- this.emit('joined');
609
- this.joined = true;
622
+ join(options) {
623
+ return __awaiter(this, void 0, void 0, function* () {
624
+ this.emit('joinWillStart');
625
+ const { sdkAppId, userId, userSig } = yield this.options.getVoiceSign(options);
626
+ this.type = options.type;
627
+ const [res, error] = yield this.jsBridge.callAndBackfeed(`live/join?sdkAppID=${sdkAppId}&userID=${userId}&roomID=${Number(options.voiceId)}&userSig=${userSig}`);
628
+ if (!res) {
629
+ this.emit('error', error ? error : new Error('加入房间失败:未知异常。'));
630
+ this.joined = false;
610
631
  }
611
632
  else {
612
- this.emit('error', res);
613
- this.joined = false;
633
+ if (res.code === RTCJoinedInfoCodeEnum.Success) {
634
+ this.emit('joined');
635
+ this.joined = true;
636
+ }
637
+ else {
638
+ this.emit('error', res);
639
+ this.joined = false;
640
+ }
614
641
  }
615
- }
616
- return this.joined;
642
+ return this.joined;
643
+ });
617
644
  }
618
- async quit() {
619
- const [res, error] = await this.jsBridge.callAndBackfeed('live/quit');
620
- if (res === null) {
621
- this.emit('error', error ? error : new Error('退出房间失败:未知异常。'));
622
- }
623
- this.joined = false;
624
- return !!res;
645
+ quit() {
646
+ return __awaiter(this, void 0, void 0, function* () {
647
+ const [res, error] = yield this.jsBridge.callAndBackfeed('live/quit');
648
+ if (res === null) {
649
+ this.emit('error', error ? error : new Error('退出房间失败:未知异常。'));
650
+ }
651
+ this.joined = false;
652
+ return !!res;
653
+ });
625
654
  }
626
- async detectMicro() {
627
- const [res, error] = await this.jsBridge.detectMicro();
628
- if (res === null) {
629
- this.emit('error', error ? error : new Error('麦克风监测异常!'));
630
- return false;
631
- }
632
- return res;
655
+ detectMicro() {
656
+ return __awaiter(this, void 0, void 0, function* () {
657
+ const [res, error] = yield this.jsBridge.detectMicro();
658
+ if (res === null) {
659
+ this.emit('error', error ? error : new Error('麦克风监测异常!'));
660
+ return false;
661
+ }
662
+ return res;
663
+ });
633
664
  }
634
- async toggleMicro(flag) {
635
- const [res, error] = await this.jsBridge.callAndBackfeed(`live/toggleMicro?flag=${!!flag ? 1 : 0}`);
636
- if (res === null) {
637
- this.emit('error', error ? error : new Error('麦克风监测异常!'));
638
- return false;
639
- }
640
- this.micro = res;
641
- return res;
665
+ toggleMicro(flag) {
666
+ return __awaiter(this, void 0, void 0, function* () {
667
+ const [res, error] = yield this.jsBridge.callAndBackfeed(`live/toggleMicro?flag=${!!flag ? 1 : 0}`);
668
+ if (res === null) {
669
+ this.emit('error', error ? error : new Error('麦克风监测异常!'));
670
+ return false;
671
+ }
672
+ this.micro = res;
673
+ return res;
674
+ });
642
675
  }
643
676
  shock() {
644
677
  this.jsBridge.shock(1);
@@ -881,6 +914,51 @@ function parseWSClsErr(code) {
881
914
  return WebSocketCloseError.Err_unknown;
882
915
  }
883
916
 
917
+ function getDefaultExportFromCjs (x) {
918
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
919
+ }
920
+
921
+ function createCommonjsModule(fn) {
922
+ var module = { exports: {} };
923
+ return fn(module, module.exports), module.exports;
924
+ }
925
+
926
+ var LogLevel_1 = createCommonjsModule(function (module, exports) {
927
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
928
+ // SPDX-License-Identifier: Apache-2.0
929
+ Object.defineProperty(exports, "__esModule", { value: true });
930
+ exports.LogLevel = void 0;
931
+ var LogLevel;
932
+ (function (LogLevel) {
933
+ LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
934
+ LogLevel[LogLevel["INFO"] = 1] = "INFO";
935
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
936
+ LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
937
+ LogLevel[LogLevel["OFF"] = 4] = "OFF";
938
+ })(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
939
+ exports.default = LogLevel;
940
+
941
+ });
942
+
943
+ var LogLevel = /*@__PURE__*/getDefaultExportFromCjs(LogLevel_1);
944
+
945
+ var LiveState;
946
+ (function (LiveState) {
947
+ LiveState[LiveState["NOTINITIALIZED"] = -1] = "NOTINITIALIZED";
948
+ /**
949
+ * 正在链接中
950
+ */
951
+ LiveState[LiveState["CONNECTING"] = 0] = "CONNECTING";
952
+ /**
953
+ * 已经链接并且可以通讯
954
+ */
955
+ LiveState[LiveState["OPEN"] = 1] = "OPEN";
956
+ /**
957
+ * 连接已关闭或者链接失败
958
+ */
959
+ LiveState[LiveState["CLOSED"] = 3] = "CLOSED";
960
+ })(LiveState || (LiveState = {}));
961
+
884
962
  function appendUri(uri, query) {
885
963
  const hasQuery = uri.indexOf('?') !== -1;
886
964
  const newQuery = Object.keys(query).reduce((accu, curr, idx) => `${accu}${(idx === 0 && !hasQuery) ? '?' : '&'}${curr}=${query[curr]}`, '');
@@ -1025,692 +1103,1115 @@ function equal(value, other, opt) {
1025
1103
  return isDeepEqual(value, other);
1026
1104
  }
1027
1105
 
1028
- class LiveController {
1106
+ /**
1107
+ * 输出格式化日志
1108
+ */
1109
+ // 获取当前时间
1110
+ const getTime = () => {
1111
+ const date = new Date();
1112
+ const year = date.getFullYear();
1113
+ const month = (date.getMonth() + 1).toString().padStart(2, '0'); //月份是从0开始的
1114
+ const day = date.getDate().toString().padStart(2, '0');
1115
+ const hour = date.getHours().toString().padStart(2, '0');
1116
+ const min = date.getMinutes().toString().padStart(2, '0');
1117
+ const sec = date.getSeconds().toString().padStart(2, '0');
1118
+ const ms = date.getMilliseconds();
1119
+ return `[${year}-${month}-${day} ${hour}:${min}:${sec}.${ms}]`;
1120
+ };
1121
+ var LOG_LEVEL;
1122
+ (function (LOG_LEVEL) {
1123
+ LOG_LEVEL["info"] = "INFO";
1124
+ LOG_LEVEL["log"] = "LOG";
1125
+ LOG_LEVEL["error"] = "ERROR";
1126
+ LOG_LEVEL["warn"] = "WARN";
1127
+ })(LOG_LEVEL || (LOG_LEVEL = {}));
1128
+ // 输出日志
1129
+ const echo = (logLevel, args = []) => {
1130
+ args.unshift(`Realsee Live ${getTime()} <${logLevel}> `);
1131
+ switch (logLevel) {
1132
+ case LOG_LEVEL.info:
1133
+ return console.info(...args);
1134
+ case LOG_LEVEL.error:
1135
+ return console.error(...args);
1136
+ case LOG_LEVEL.warn:
1137
+ return console.warn(...args);
1138
+ default:
1139
+ return console.log(...args);
1140
+ }
1141
+ };
1142
+ const log = (...args) => echo(LOG_LEVEL.log, args);
1143
+ const info = (...args) => echo(LOG_LEVEL.info, args);
1144
+ const error = (...args) => echo(LOG_LEVEL.error, args);
1145
+ const warn = (...args) => echo(LOG_LEVEL.warn, args);
1146
+ const logger = {
1147
+ log,
1148
+ info,
1149
+ error,
1150
+ warn,
1151
+ };
1152
+ var logger$1 = logger;
1153
+
1154
+ /**
1155
+ * 具有鲁棒性的WebSocket封装
1156
+ * 1、自动重连
1157
+ * 2、可根据网络情况进行重连
1158
+ */
1159
+ class RobustWebSocket extends Subscribe {
1029
1160
  constructor(options) {
1030
- this.readyState = WebSocketState.NOTINITIALIZED;
1031
- this.canSync = true;
1032
- this.connecting = false;
1033
- this.keyframes = {};
1161
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
1162
+ super();
1163
+ this._options = {
1164
+ timeout: 10000,
1165
+ shouldReconnect: (event, ws) => {
1166
+ if (event.code === 1008 || event.code === 1011)
1167
+ return;
1168
+ return [0, 3000, 10000][ws.attempts];
1169
+ },
1170
+ should1000Reconnect: false,
1171
+ ignoreConnectivityEvents: false,
1172
+ automaticOpen: false,
1173
+ };
1174
+ this._attempts = 0;
1175
+ this._reconnects = -1;
1176
+ this._reconnectWhenOnlineAgain = false;
1177
+ this._explicitlyClosed = false;
1178
+ this._connectivityEventsAttached = false;
1034
1179
  /**
1035
- * 检测 WebSocket.readyState 状态
1180
+ * 清理连接中的请求
1036
1181
  */
1037
- this.checkReadyState = (live) => {
1038
- do {
1039
- if (!this.webSocket) {
1040
- if (this.readyState !== WebSocketState.NOTINITIALIZED) {
1041
- this.readyState = WebSocketState.NOTINITIALIZED;
1042
- live.emit('ws.readyStateUpdate', this.readyState);
1043
- }
1044
- break;
1045
- }
1046
- const readyState = this.webSocket.readyState;
1047
- if (readyState !== this.readyState) {
1048
- this.readyState = readyState;
1049
- live.emit('ws.readyStateUpdate', this.readyState);
1050
- }
1051
- } while (false);
1052
- return this.readyState;
1182
+ this._clearPendingReconnectIfNeeded = () => {
1183
+ if (this._pendingReconnect) {
1184
+ clearTimeout(this._pendingReconnect);
1185
+ this._pendingReconnect = undefined;
1186
+ }
1053
1187
  };
1054
- this.dispose = () => {
1055
- this.disposeWebSocket();
1056
- this.connecting = false;
1057
- if (this.healthCheckId) {
1058
- clearInterval(this.healthCheckId);
1059
- this.healthCheckId = undefined;
1188
+ /**
1189
+ * 当网页连接上网络进行重连
1190
+ * @param event
1191
+ */
1192
+ this._online = (event) => {
1193
+ if (this._reconnectWhenOnlineAgain) {
1194
+ this._clearPendingReconnectIfNeeded();
1195
+ this._reconnect(event);
1060
1196
  }
1061
- return true;
1062
1197
  };
1063
1198
  /**
1064
- * 销毁WebSocket相关依赖。
1199
+ * 当网页断开网络进行关闭
1065
1200
  */
1066
- this.disposeWebSocket = () => {
1067
- if (!this.webSocket)
1068
- return;
1069
- if (this.onEvtOpnListener) {
1070
- this.webSocket.removeEventListener('open', this.onEvtOpnListener);
1071
- this.onEvtOpnListener = undefined;
1201
+ this._offline = () => {
1202
+ var _a;
1203
+ this._reconnectWhenOnlineAgain = true;
1204
+ (_a = this._realWebSocket) === null || _a === void 0 ? void 0 : _a.close(1000);
1205
+ };
1206
+ /**
1207
+ * 解除网络监听事件
1208
+ */
1209
+ this._detachConnectivityEvents = () => {
1210
+ if (this._connectivityEventsAttached) {
1211
+ globalThis === null || globalThis === void 0 ? void 0 : globalThis.removeEventListener('online', this._online);
1212
+ globalThis === null || globalThis === void 0 ? void 0 : globalThis.removeEventListener('offline', this._offline);
1213
+ this._connectivityEventsAttached = false;
1214
+ }
1215
+ };
1216
+ /**
1217
+ * 注册网络监听事件
1218
+ */
1219
+ this._attachConnectivityEvents = () => {
1220
+ if (!this._connectivityEventsAttached) {
1221
+ globalThis === null || globalThis === void 0 ? void 0 : globalThis.addEventListener('online', this._online);
1222
+ globalThis === null || globalThis === void 0 ? void 0 : globalThis.addEventListener('offline', this._offline);
1223
+ this._connectivityEventsAttached = true;
1224
+ }
1225
+ };
1226
+ /**
1227
+ * 发送消息
1228
+ * @param data
1229
+ * @returns
1230
+ */
1231
+ this.send = (data) => { var _a; return (_a = this._realWebSocket) === null || _a === void 0 ? void 0 : _a.send(data); };
1232
+ /**
1233
+ * 关闭连接
1234
+ * @param code 代码
1235
+ * @param reason 原因
1236
+ * @returns
1237
+ */
1238
+ this.close = (code, reason) => {
1239
+ var _a;
1240
+ if (typeof code !== 'number') {
1241
+ reason = code;
1242
+ code = 1000;
1072
1243
  }
1073
- if (this.onEvtMsgListener) {
1074
- this.webSocket.removeEventListener('message', this.onEvtMsgListener);
1075
- this.onEvtMsgListener = undefined;
1244
+ this._clearPendingReconnectIfNeeded();
1245
+ this._reconnectWhenOnlineAgain = false;
1246
+ this._explicitlyClosed = true;
1247
+ this._detachConnectivityEvents();
1248
+ return (_a = this._realWebSocket) === null || _a === void 0 ? void 0 : _a.close(code, reason);
1249
+ };
1250
+ /**
1251
+ * 进行ws连接
1252
+ */
1253
+ this.open = (url) => {
1254
+ var _a, _b;
1255
+ if (url) {
1256
+ this._url = url;
1076
1257
  }
1077
- if (this.onEvtErrListener) {
1078
- this.webSocket.removeEventListener('error', this.onEvtErrListener);
1079
- this.onEvtErrListener = undefined;
1258
+ if (((_a = this._realWebSocket) === null || _a === void 0 ? void 0 : _a.readyState) !== WebSocket.OPEN &&
1259
+ ((_b = this._realWebSocket) === null || _b === void 0 ? void 0 : _b.readyState) !== WebSocket.CONNECTING) {
1260
+ this._clearPendingReconnectIfNeeded();
1261
+ this._reconnectWhenOnlineAgain = false;
1262
+ this._explicitlyClosed = false;
1263
+ this._createWebSocket();
1080
1264
  }
1081
- if (this.onEvtCLEListener) {
1082
- this.webSocket.removeEventListener('close', this.onEvtCLEListener);
1083
- this.onEvtCLEListener = undefined;
1265
+ };
1266
+ /**
1267
+ * 创建ws连接
1268
+ */
1269
+ this._createWebSocket = () => {
1270
+ var _a, _b, _c;
1271
+ const newUrl = typeof this._url === 'string' ? this._url : (_a = this._url) === null || _a === void 0 ? void 0 : _a.call(this, this);
1272
+ if (!newUrl)
1273
+ return;
1274
+ this._pendingReconnect = undefined;
1275
+ this._realWebSocket = new WebSocket(newUrl, this._protocols || undefined);
1276
+ this._attempts = this._attempts + 1;
1277
+ this.emit('connecting', new CustomEvent('connecting', {
1278
+ detail: { attempts: this._attempts, reconnects: this._reconnects },
1279
+ }));
1280
+ const timeoutCallback = () => {
1281
+ this._connectTimeout = undefined;
1282
+ this._detachConnectivityEvents();
1283
+ this.emit('timeout', new CustomEvent('connecting', {
1284
+ detail: {
1285
+ attempts: this._attempts,
1286
+ reconnects: this._reconnects,
1287
+ },
1288
+ }));
1289
+ };
1290
+ this._connectTimeout = setTimeout(timeoutCallback, (_b = this._options) === null || _b === void 0 ? void 0 : _b.timeout);
1291
+ this._dispatchWebSocketEvent();
1292
+ if (!((_c = this._options) === null || _c === void 0 ? void 0 : _c.ignoreConnectivityEvents)) {
1293
+ this._attachConnectivityEvents();
1084
1294
  }
1085
- this.webSocket.close();
1086
- this.webSocket = undefined;
1087
- return true;
1088
1295
  };
1089
- this.options = Object.assign({ autoConnect: true, healthCheck: 3000 }, options);
1296
+ /**
1297
+ * 分发ws事件
1298
+ */
1299
+ this._dispatchWebSocketEvent = () => {
1300
+ var _a, _b, _c, _d;
1301
+ (_a = this._realWebSocket) === null || _a === void 0 ? void 0 : _a.addEventListener('open', this._webSocketOpenHandler);
1302
+ (_b = this._realWebSocket) === null || _b === void 0 ? void 0 : _b.addEventListener('close', this._webSocketCloseHandler);
1303
+ (_c = this._realWebSocket) === null || _c === void 0 ? void 0 : _c.addEventListener('error', this._webSocketErrorHandler);
1304
+ (_d = this._realWebSocket) === null || _d === void 0 ? void 0 : _d.addEventListener('message', this._webSocketMessageHandler);
1305
+ };
1306
+ /**
1307
+ * ws连接事件
1308
+ * @returns
1309
+ */
1310
+ this._webSocketOpenHandler = (event) => {
1311
+ if (this._connectTimeout) {
1312
+ clearTimeout(this._connectTimeout);
1313
+ this._connectTimeout = undefined;
1314
+ }
1315
+ const reconnects = ++this._reconnects;
1316
+ const attempts = this._attempts;
1317
+ this._attempts = 0;
1318
+ this._reconnectWhenOnlineAgain = false;
1319
+ return this.emit('open', Object.assign(event, { detail: { reconnects, attempts } }));
1320
+ };
1321
+ /**
1322
+ * ws 关闭事件
1323
+ * @param event
1324
+ * @returns
1325
+ */
1326
+ this._webSocketCloseHandler = (event) => {
1327
+ this._reconnect(event);
1328
+ return this.emit('close', event);
1329
+ };
1330
+ /**
1331
+ * ws 异常
1332
+ * @param event
1333
+ * @returns
1334
+ */
1335
+ this._webSocketErrorHandler = (event) => {
1336
+ return this.emit('error', new CustomEvent('error', { detail: { error: event } }));
1337
+ };
1338
+ /**
1339
+ * ws消息
1340
+ * @param event
1341
+ * @returns
1342
+ */
1343
+ this._webSocketMessageHandler = (event) => {
1344
+ return this.emit('message', event);
1345
+ };
1346
+ if (options) {
1347
+ this.setOptions(options);
1348
+ }
1349
+ }
1350
+ get attempts() {
1351
+ return this._attempts;
1352
+ }
1353
+ setOptions(options) {
1354
+ if (!options)
1355
+ return;
1356
+ this._url = options.url;
1357
+ this._protocols = options.protocols;
1358
+ const opts = Object.assign(this._options, options.robustOptions || {});
1359
+ if (typeof (opts === null || opts === void 0 ? void 0 : opts.timeout) !== 'number') {
1360
+ throw new Error('timeout must be the number of milliseconds to timeout a connection attempt');
1361
+ }
1362
+ if (typeof (opts === null || opts === void 0 ? void 0 : opts.shouldReconnect) !== 'function') {
1363
+ throw new Error('shouldReconnect must be a function that returns the number of milliseconds to wait for a reconnect attempt, or null or undefined to not reconnect.');
1364
+ }
1365
+ this._options = opts;
1366
+ if (this._options.automaticOpen) {
1367
+ this._createWebSocket();
1368
+ }
1090
1369
  }
1091
1370
  /**
1092
- * 解析数据
1093
- * @param liveMsg
1094
- * @param live
1371
+ * 进行重连
1372
+ * @param event
1373
+ * @returns
1095
1374
  */
1096
- handleMessage(liveMsg, live) {
1097
- var _a, _b, _c;
1098
- const { command, data, frontRequestId, code, message } = liveMsg;
1099
- if (code === 'SUCCESS') {
1100
- switch (command) {
1101
- /**
1102
- * 自己的状态变化
1103
- */
1104
- case Command.SelfUserInfo: {
1105
- const selfInfo = data;
1106
- if (equal(this.selfUserInfo, selfInfo, { deep: true }))
1107
- return;
1108
- this.selfUserInfo = selfInfo;
1109
- live.emit('selfInfoUpdate', this.selfUserInfo, frontRequestId);
1110
- break;
1111
- }
1112
- /**
1113
- * 房间信息变化
1114
- */
1115
- case Command.RoomInfo: {
1116
- const roomInfo = data;
1117
- this.roomInfo = Object.assign({}, roomInfo);
1118
- live.emit('readyKeyframeSync', (roomInfo.last_frame || {}));
1119
- break;
1120
- }
1121
- /**
1122
- * 语音信息变化
1123
- */
1124
- case Command.RTCInfo: {
1125
- const { voice_id: voiceId, type } = data;
1126
- /* 如果已经进入语音房间,则不重复进入 --> "RTCInfo" 指令可能会下发多次 */
1127
- if (live.$RTC.joined) {
1128
- break;
1129
- }
1130
- live.$RTC.join({
1131
- voiceId,
1132
- userId: ((_a = this.selfUserInfo) === null || _a === void 0 ? void 0 : _a.id) || '',
1133
- roomId: (_b = this.roomInfo) === null || _b === void 0 ? void 0 : _b.info.room_code,
1134
- type,
1135
- });
1136
- // 加入房间后 麦克风默认就开启了:需要发个指令。
1137
- live.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserMicroStatus, {
1138
- status: MicroStatus.OPEN,
1139
- });
1140
- break;
1141
- }
1142
- /**
1143
- * 房间用户列表变化
1144
- */
1145
- case Command.UserList: {
1146
- const userList = data;
1147
- this.userList = userList;
1148
- live.emit('userListUpdate', this.userList, frontRequestId);
1149
- break;
1150
- }
1151
- /**
1152
- * 自定义事件广播
1153
- */
1154
- case Command.CustomEvent: {
1155
- const evtMsg = data;
1156
- live.emit('broadcast', evtMsg, frontRequestId);
1157
- break;
1158
- }
1159
- /**
1160
- * 帧数据同步
1161
- */
1162
- case Command.KeyframeSync: {
1163
- const remoteKeyframes = data;
1164
- // 此处做一层 diff,仅跟本地数据不一致的情况下才广播数据。
1165
- const keyframes = Object.keys(remoteKeyframes).reduce((accu, curr) => {
1166
- if (equal(remoteKeyframes[curr], this.keyframes[curr], { deep: true })) {
1167
- return accu;
1168
- }
1169
- const params = [
1170
- remoteKeyframes[curr],
1171
- this.keyframes[curr],
1172
- frontRequestId,
1173
- ];
1174
- const evtName = curr;
1175
- live.keyframes.emit(evtName, ...params);
1176
- this.keyframes[curr] = remoteKeyframes[curr];
1177
- accu[curr] = remoteKeyframes[curr];
1178
- return accu;
1179
- }, {});
1180
- live.emit('keyframes', keyframes, frontRequestId);
1181
- break;
1182
- }
1183
- /**
1184
- * 内置消息
1185
- */
1186
- case Command.BuiltinMsg: {
1187
- const builtinMsg = data;
1188
- live.emit('builtinEvent', builtinMsg);
1189
- if (builtinMsg.event_type === BuiltinEventType.UserChange) {
1190
- live.emit('userChange', builtinMsg);
1191
- }
1192
- if (builtinMsg.event_type === BuiltinEventType.RoomChange) {
1193
- live.emit('roomChange', builtinMsg);
1194
- }
1195
- /**
1196
- * 下发指令自己操作麦克风
1197
- */
1198
- if (builtinMsg.event_type === BuiltinEventType.UserChange &&
1199
- builtinMsg.action === BuiltinActionType.UserMicroStatus) {
1200
- live.toggleMicro(builtinMsg.data.status === MicroStatus.OPEN);
1201
- }
1202
- /**
1203
- * 如果下发指令退出房间,则 关闭麦克风 及 销毁 WebSocket
1204
- */
1205
- if (builtinMsg.event_type === BuiltinEventType.RoomChange &&
1206
- builtinMsg.action === BuiltinActionType.RoomClose) {
1207
- (_c = this.options.rtc) === null || _c === void 0 ? void 0 : _c.quit();
1208
- this.disposeWebSocket();
1209
- }
1210
- break;
1211
- }
1212
- /**
1213
- * 被踢出房间
1214
- */
1215
- case Command.UserKickOut: {
1216
- live.emit('kickOut');
1217
- break;
1218
- }
1219
- /**
1220
- * 其它未知广播
1221
- */
1222
- default: {
1223
- console.warn('unknown command: ', command);
1224
- }
1225
- }
1375
+ _reconnect(event) {
1376
+ var _a, _b, _c, _d;
1377
+ if ((!((_a = this._options) === null || _a === void 0 ? void 0 : _a.should1000Reconnect) && event.code === 1000) ||
1378
+ this._explicitlyClosed) {
1379
+ this._attempts = 0;
1380
+ return;
1226
1381
  }
1227
- else {
1228
- live.emit('error', liveMsg);
1382
+ if (((_b = globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator) === null || _b === void 0 ? void 0 : _b.onLine) === false) {
1383
+ this._reconnectWhenOnlineAgain = true;
1384
+ return;
1229
1385
  }
1386
+ const delay = (_d = (_c = this._options) === null || _c === void 0 ? void 0 : _c.shouldReconnect) === null || _d === void 0 ? void 0 : _d.call(_c, event, this);
1387
+ if (typeof delay === 'number') {
1388
+ this._pendingReconnect = setTimeout(this._createWebSocket, delay);
1389
+ }
1390
+ }
1391
+ }
1392
+
1393
+ class LiveController extends Subscribe {
1394
+ constructor() {
1395
+ super();
1396
+ /**
1397
+ * ws代理器
1398
+ */
1399
+ this._ws = new RobustWebSocket();
1400
+ /**
1401
+ * 带看连接状态
1402
+ */
1403
+ this._state = LiveState.NOTINITIALIZED;
1404
+ /**
1405
+ * 添加事件监听
1406
+ */
1407
+ this._addWebSocketEventListeners = () => {
1408
+ this._ws.on('close', this._handleCloseEvent);
1409
+ this._ws.on('connecting', this._handleConnectingEvent);
1410
+ this._ws.on('error', this._handleErrorEvent);
1411
+ this._ws.on('message', this._handleMessageEvent);
1412
+ this._ws.on('open', this._handleOpenEvent);
1413
+ this._ws.on('timeout', this._handleTimeoutEvent);
1414
+ };
1415
+ /**
1416
+ * 移除事件监听
1417
+ */
1418
+ this._removeWebSocketEventListeners = () => {
1419
+ this._ws.off('close', this._handleCloseEvent);
1420
+ this._ws.off('connecting', this._handleConnectingEvent);
1421
+ this._ws.off('error', this._handleErrorEvent);
1422
+ this._ws.off('message', this._handleMessageEvent);
1423
+ this._ws.off('open', this._handleOpenEvent);
1424
+ this._ws.off('timeout', this._handleTimeoutEvent);
1425
+ };
1426
+ /**
1427
+ * 处理房间关闭事件
1428
+ * @param event
1429
+ */
1430
+ this._handleCloseEvent = (event) => {
1431
+ logger$1.info(`live room closed bacause of ${event.code}-${event.reason || parseWSClsErr(event.code)}`);
1432
+ this.state = LiveState.CLOSED;
1433
+ };
1434
+ /**
1435
+ * 连接中
1436
+ * @param event
1437
+ */
1438
+ this._handleConnectingEvent = (event) => {
1439
+ logger$1.info(`live room is connecting`, event.detail);
1440
+ this.state = LiveState.CONNECTING;
1441
+ };
1442
+ /**
1443
+ * 连接发送异常
1444
+ * @param event
1445
+ */
1446
+ this._handleErrorEvent = (event) => {
1447
+ logger$1.error(`live room error`, event);
1448
+ this.state = LiveState.CLOSED;
1449
+ };
1450
+ /**
1451
+ * 接收到消息
1452
+ * @param event
1453
+ */
1454
+ this._handleMessageEvent = (event) => {
1455
+ // logger.info('live room received message ', event.data);
1456
+ let message = (() => {
1457
+ try {
1458
+ return JSON.parse(event.data);
1459
+ }
1460
+ catch (e) {
1461
+ return event.data;
1462
+ }
1463
+ })();
1464
+ this.emit('message', message);
1465
+ };
1466
+ /**
1467
+ * 连接建立成功
1468
+ * @param event
1469
+ */
1470
+ this._handleOpenEvent = (event) => {
1471
+ logger$1.info('live room open', event.detail);
1472
+ this.state = LiveState.OPEN;
1473
+ };
1474
+ /**
1475
+ * 处理超时
1476
+ * @param event
1477
+ */
1478
+ this._handleTimeoutEvent = (event) => {
1479
+ logger$1.error('live room connect timeout!', event.detail);
1480
+ this.state = LiveState.CLOSED;
1481
+ };
1482
+ /**
1483
+ * 释放资源,释放之后需要重新实例化
1484
+ * @returns
1485
+ */
1486
+ this.dispose = () => __awaiter(this, void 0, void 0, function* () {
1487
+ this._removeWebSocketEventListeners();
1488
+ return yield this.close('live room close by controller disposed!');
1489
+ });
1490
+ /**
1491
+ * 开启房间链接
1492
+ * @param url 房间链接
1493
+ * @returns
1494
+ */
1495
+ this.open = (url) => this._ws.open(url);
1496
+ /**
1497
+ * 关闭房间
1498
+ * @param code
1499
+ * @param reason
1500
+ */
1501
+ this.close = (code, reason) => new Promise((resolve) => {
1502
+ this._ws.once('close', () => resolve(true));
1503
+ this._ws.close(code, reason);
1504
+ });
1505
+ this._addWebSocketEventListeners();
1506
+ }
1507
+ set state(state) {
1508
+ const prevState = JSON.parse(JSON.stringify(this._state));
1509
+ this._state = state;
1510
+ this.emit('stateChange', this.state, prevState);
1511
+ }
1512
+ get state() {
1513
+ return this._state;
1230
1514
  }
1231
1515
  /**
1232
1516
  * 发送数据
1233
1517
  * @param data
1234
1518
  */
1235
- sendMessage(data) {
1236
- if (!this.webSocket)
1237
- return console.warn('WebSocket has not yet been initialized!');
1238
- if (!data)
1239
- return console.warn('WebSocket messages is empty!');
1240
- this.webSocket.send(JSON.stringify(data));
1519
+ sendMessage(data = '') {
1520
+ if (data === undefined || data === null || data === '') {
1521
+ throw new Error('live message is empty!');
1522
+ }
1523
+ if (this.state === LiveState.OPEN) {
1524
+ return this._ws.send(JSON.stringify(data));
1525
+ }
1526
+ else {
1527
+ throw new Error('live has not yet been initialized!');
1528
+ }
1241
1529
  }
1242
1530
  }
1243
1531
 
1244
1532
  const unimplementedGetVoiceSign = (params) => Promise.reject('unimplemented method GetVoiceSign');
1245
- /**
1246
- * 创建 `live` 实例。
1247
- */
1248
- function createLive(options) {
1249
- const liveController = new LiveController(options);
1250
- const createLiveMsg = (command, data = {}, toUserIds) => {
1251
- toUserIds = toUserIds
1252
- ? Array.isArray(toUserIds)
1253
- ? toUserIds
1254
- : [toUserIds]
1255
- : [];
1256
- if (toUserIds)
1257
- data['to_user_ids'] = toUserIds;
1258
- return { command, front_request_id: uuid(), data };
1259
- };
1260
- class LiveTpl extends Subscribe {
1261
- constructor() {
1262
- var _a, _b;
1263
- super();
1264
- this.keyframes = new Subscribe();
1265
- const jsBridge = (() => {
1266
- if (options.jsBridge)
1267
- return options.jsBridge;
1268
- if (options.useBuiltInJsBridge)
1269
- return new JSBridge();
1270
- return undefined;
1271
- })();
1272
- liveController.options.jsBridge = jsBridge;
1273
- // 没有传rtc实例时
1274
- if (!options.rtc) {
1275
- // 取指定的内部rtc类型
1276
- if (options.rtcType) {
1277
- if (!options.getVoiceSign) {
1278
- throw new Error('GetVoiceSign method must be passed when using built-in RTC instances');
1279
- }
1280
- const getVoiceSign = (_a = options.getVoiceSign) !== null && _a !== void 0 ? _a : unimplementedGetVoiceSign;
1281
- switch (options.rtcType) {
1282
- case RTCType.RealseeVRWebViewRTC: {
1283
- // 内置的 VRWebViewRTC
1284
- if (!jsBridge) {
1285
- throw new Error('JsBridge instance must be passed when using built-in VRWebViewRTC instances');
1286
- }
1287
- liveController.options.rtc = new VRWebViewRTC({
1288
- jsBridge,
1289
- getVoiceSign,
1290
- });
1291
- break;
1292
- }
1293
- case RTCType.RealseeBrowserChimeRTC: {
1294
- // 内置的 RealseeBrowserChimeRTC
1295
- liveController.options.rtc = new BrowserRTC4Chime({
1296
- getVoiceSign,
1297
- logLevel: options.__debug__ ? LogLevel.DEBUG : LogLevel.ERROR,
1298
- });
1299
- break;
1300
- }
1301
- case RTCType.RealseeBrowserRTC: {
1302
- // 内置的 RealseeBrowserRTC
1303
- liveController.options.rtc = new BrowserRTC({
1304
- getVoiceSign,
1305
- });
1533
+ const createLiveMsg = (command, data = {}, toUserIds = []) => ({
1534
+ command,
1535
+ front_request_id: uuid(),
1536
+ data: Object.assign(Object.assign({}, data), { to_user_ids: Array.isArray(toUserIds) ? toUserIds : [toUserIds] }),
1537
+ });
1538
+ const _clearLiveInstanceIfNeed = () => {
1539
+ var _a, _b;
1540
+ if (window === null || window === void 0 ? void 0 : window.__Realsee_Live__) {
1541
+ (_b = (_a = window === null || window === void 0 ? void 0 : window.__Realsee_Live__) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
1542
+ window.__Realsee_Live__ = null;
1543
+ }
1544
+ };
1545
+ class Live extends Subscribe {
1546
+ constructor(opts) {
1547
+ var _a;
1548
+ super();
1549
+ /**
1550
+ * 带看的配置
1551
+ */
1552
+ this._options = {};
1553
+ /**
1554
+ * 帧数据监听
1555
+ */
1556
+ this.keyframes = new Subscribe();
1557
+ /**
1558
+ * 内置的一些数据
1559
+ */
1560
+ this._buildInData = {
1561
+ keyframes: {},
1562
+ };
1563
+ /**
1564
+ * 根据键值取帧数据
1565
+ * @param key 帧数据的键值
1566
+ * @returns
1567
+ */
1568
+ this.getFramesByKey = (key) => this.snapshot[key];
1569
+ /**
1570
+ * 发送帧数据(需要能够被序列化)
1571
+ * @param key 帧数据键值
1572
+ * @param frame 帧数据本体
1573
+ * @returns
1574
+ */
1575
+ this.sendKeyframe = (key, frame) => {
1576
+ if (this.state !== LiveState.OPEN)
1577
+ return false;
1578
+ this._buildInData.keyframes = Object.assign(Object.assign({}, this._buildInData.keyframes), { [key]: frame });
1579
+ const liveMsg = createLiveMsg(Command.KeyframeSync, this.snapshot);
1580
+ try {
1581
+ this._controller.sendMessage(liveMsg);
1582
+ return true;
1583
+ }
1584
+ catch (e) {
1585
+ logger$1.error(e);
1586
+ return false;
1587
+ }
1588
+ };
1589
+ /**
1590
+ * 带看控制器
1591
+ */
1592
+ this._controller = new LiveController();
1593
+ /**
1594
+ * 添加带看控制的事件监听
1595
+ */
1596
+ this._addLiveControllerEventListeners = () => {
1597
+ this._controller.on('stateChange', this._handleStateChange);
1598
+ this._controller.on('message', this._handleMessage);
1599
+ };
1600
+ /**
1601
+ * 移除带看控制的事件监听
1602
+ */
1603
+ this._removeLiveControllerEventListeners = () => {
1604
+ this._controller.off('stateChange', this._handleStateChange);
1605
+ this._controller.off('message', this._handleMessage);
1606
+ };
1607
+ /**
1608
+ * 带看状态变化
1609
+ * @param state
1610
+ * @returns
1611
+ */
1612
+ this._handleStateChange = (state, prevState) => this.emit('stateChange', state, prevState);
1613
+ this._handleMessage = (liveMsg) => __awaiter(this, void 0, void 0, function* () {
1614
+ var _b, _c, _d, _e, _f, _g;
1615
+ if (typeof liveMsg === 'object') {
1616
+ const { command, data, frontRequestId, code, message } = liveMsg;
1617
+ if (code === 'SUCCESS') {
1618
+ switch (command) {
1619
+ /**
1620
+ * 自己的状态变化
1621
+ */
1622
+ case Command.SelfUserInfo: {
1623
+ const selfInfo = data;
1624
+ if (!equal(this.selfInfo, selfInfo, { deep: true })) {
1625
+ this._buildInData.selfInfo = selfInfo;
1626
+ this.emit('selfInfoUpdate', this._buildInData.selfInfo, frontRequestId);
1627
+ }
1628
+ break;
1629
+ }
1630
+ /**
1631
+ * 房间信息变化
1632
+ */
1633
+ case Command.RoomInfo: {
1634
+ const roomInfo = data;
1635
+ this._buildInData.roomInfo = Object.assign({}, roomInfo);
1636
+ this.emit('readyKeyframeSync', (roomInfo.last_frame || {}));
1637
+ break;
1638
+ }
1639
+ /**
1640
+ * 语音信息变化
1641
+ */
1642
+ case Command.RTCInfo: {
1643
+ const { voice_id: voiceId, type } = data;
1644
+ if (!((_b = this.$RTC) === null || _b === void 0 ? void 0 : _b.joined)) {
1645
+ const result = yield ((_c = this.$RTC) === null || _c === void 0 ? void 0 : _c.join({
1646
+ voiceId,
1647
+ userId: ((_d = this.selfInfo) === null || _d === void 0 ? void 0 : _d.id) || '',
1648
+ roomId: (_e = this.roomInfo) === null || _e === void 0 ? void 0 : _e.info.room_code,
1649
+ type,
1650
+ }));
1651
+ if (result) {
1652
+ const status = (_f = this._options.initialMicroStatus) !== null && _f !== void 0 ? _f : MicroStatus.OPEN;
1653
+ yield ((_g = this.$RTC) === null || _g === void 0 ? void 0 : _g.toggleMicro(status === MicroStatus.OPEN));
1654
+ }
1655
+ else {
1656
+ logger$1.error('加入语音房间失败');
1657
+ }
1658
+ }
1659
+ else {
1660
+ logger$1.warn('已加入语音房间,无需重复加入!');
1661
+ }
1662
+ break;
1663
+ }
1664
+ /**
1665
+ * 房间用户列表变化
1666
+ */
1667
+ case Command.UserList: {
1668
+ const userList = data;
1669
+ this._buildInData.userList = userList;
1670
+ this.emit('userListUpdate', this.userList, frontRequestId);
1671
+ break;
1672
+ }
1673
+ /**
1674
+ * 自定义事件广播
1675
+ */
1676
+ case Command.CustomEvent: {
1677
+ const evtMsg = data;
1678
+ this.emit('broadcast', evtMsg, frontRequestId);
1679
+ break;
1680
+ }
1681
+ /**
1682
+ * 帧数据同步
1683
+ */
1684
+ case Command.KeyframeSync: {
1685
+ const remoteKeyframes = data;
1686
+ // 此处做一层 diff,仅跟本地数据不一致的情况下才广播数据。
1687
+ const keyframes = Object.keys(remoteKeyframes).reduce((accu, curr) => {
1688
+ if (equal(remoteKeyframes[curr], this._buildInData.keyframes[curr], {
1689
+ deep: true,
1690
+ })) {
1691
+ return accu;
1692
+ }
1693
+ const params = [
1694
+ remoteKeyframes[curr],
1695
+ this._buildInData.keyframes[curr],
1696
+ frontRequestId,
1697
+ ];
1698
+ const evtName = curr;
1699
+ this.keyframes.emit(evtName, ...params);
1700
+ this._buildInData.keyframes[curr] = remoteKeyframes[curr];
1701
+ accu[curr] = remoteKeyframes[curr];
1702
+ return accu;
1703
+ }, {});
1704
+ this.emit('keyframes', keyframes, frontRequestId);
1306
1705
  break;
1307
1706
  }
1707
+ /**
1708
+ * 内置消息
1709
+ */
1710
+ case Command.BuiltinMsg: {
1711
+ const builtinMsg = data;
1712
+ this.emit('builtinEvent', builtinMsg);
1713
+ if (builtinMsg.event_type === BuiltinEventType.UserChange) {
1714
+ this.emit('userChange', builtinMsg);
1715
+ }
1716
+ if (builtinMsg.event_type === BuiltinEventType.RoomChange) {
1717
+ this.emit('roomChange', builtinMsg);
1718
+ }
1719
+ /**
1720
+ * 下发指令自己操作麦克风
1721
+ */
1722
+ if (builtinMsg.event_type === BuiltinEventType.UserChange &&
1723
+ builtinMsg.action === BuiltinActionType.UserMicroStatus) {
1724
+ yield this.toggleMicro(builtinMsg.data.status === MicroStatus.OPEN);
1725
+ }
1726
+ /**
1727
+ * 如果下发指令退出房间,则 关闭麦克风 及 销毁 WebSocket
1728
+ */
1729
+ if (builtinMsg.event_type === BuiltinEventType.RoomChange &&
1730
+ builtinMsg.action === BuiltinActionType.RoomClose) {
1731
+ yield this.exit();
1732
+ }
1733
+ break;
1734
+ }
1735
+ /**
1736
+ * 被踢出房间
1737
+ */
1738
+ case Command.UserKickOut: {
1739
+ this.emit('kickOut');
1740
+ break;
1741
+ }
1742
+ /**
1743
+ * 其它未知广播
1744
+ */
1308
1745
  default: {
1309
- throw new Error('unknown built-in RTC type');
1746
+ console.warn('unknown command: ', command);
1310
1747
  }
1311
1748
  }
1312
1749
  }
1313
- // 都不满足时取内置
1314
- if (options.useBuiltInRTC) {
1315
- if (!options.getVoiceSign) {
1316
- throw new Error('GetVoiceSign method must be passed when using built-in RTC instances');
1317
- }
1318
- const getVoiceSign = (_b = options.getVoiceSign) !== null && _b !== void 0 ? _b : unimplementedGetVoiceSign;
1319
- if (!jsBridge) {
1320
- throw new Error('jsBridge instance must be passed when using built-in RTC instances');
1321
- }
1322
- // vrwebview 默认
1323
- if ((isRealseeVRWebview && (isAndroid || isIOS)) || isWxMiniProgram) {
1324
- liveController.options.rtc = new VRWebViewRTC({
1325
- jsBridge,
1326
- getVoiceSign,
1327
- });
1328
- }
1329
- else {
1330
- // 其它终端使用
1331
- liveController.options.rtc =
1332
- options.builtInRTCType === BuiltInRTCType.RealseeXChimeRTC
1333
- ? new BrowserRTC4Chime({ getVoiceSign })
1334
- : new BrowserRTC({ getVoiceSign });
1335
- }
1750
+ else {
1751
+ this.emit('error', liveMsg);
1336
1752
  }
1337
1753
  }
1338
- if (!liveController.options.rtc) {
1339
- console.warn('unused rtc');
1340
- }
1341
- // 默认自动连接
1342
- if (liveController.options.url && liveController.options.getTicket) {
1343
- this.connect();
1344
- }
1345
- // 健康检查:WHY --> 在某些WebView特殊场景下 WebSocket.readyState 发生变化时不会出发error\close等事件;
1346
- // 因此,开启一个定时任务监测 WebSocket.readyState 状态的更新
1347
- const healthCheck = ((healthCheck) => {
1348
- if (!healthCheck)
1349
- return 0;
1350
- if (healthCheck === true)
1351
- return 3000;
1352
- const duration = Number(healthCheck);
1353
- if (duration > 0)
1354
- return duration;
1355
- return 3000;
1356
- })(liveController.options.healthCheck);
1357
- if (healthCheck) {
1358
- liveController.healthCheckId = setInterval(() => liveController.checkReadyState(this), healthCheck);
1359
- }
1360
- }
1361
- get options() {
1362
- return Object.freeze(Object.assign({}, liveController.options));
1363
- }
1364
- get readyState() {
1365
- liveController.checkReadyState(this);
1366
- return liveController.readyState;
1367
- }
1368
- get url() {
1369
- var _a;
1370
- return ((_a = liveController.webSocket) === null || _a === void 0 ? void 0 : _a.url) || '';
1371
- }
1372
- get selfInfo() {
1373
- return liveController.selfUserInfo;
1374
- }
1375
- get userList() {
1376
- return liveController.userList || [];
1377
- }
1378
- get snapshot() {
1379
- return liveController.keyframes || {};
1380
- }
1381
- get $RTC() {
1382
- return liveController.options.rtc;
1383
- }
1384
- get jsBridge() {
1385
- return liveController.options.jsBridge;
1386
- }
1387
- async setSelfInfo(userInfo) {
1388
- if (this.readyState !== WebSocketState.OPEN) {
1389
- return new Error('The connection is not open and ready to communicate.');
1390
- }
1391
- try {
1392
- return await this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserInfo, userInfo);
1393
- }
1394
- catch (error) {
1395
- return error;
1754
+ });
1755
+ /**
1756
+ * 清理带看缓存的数据
1757
+ */
1758
+ this._clearLiveData = () => {
1759
+ this._buildInData = { keyframes: {} };
1760
+ };
1761
+ /**
1762
+ * 连接带看
1763
+ * @param options
1764
+ * @returns
1765
+ */
1766
+ this.connect = (options = {}) => __awaiter(this, void 0, void 0, function* () {
1767
+ var _h, _j, _k, _l;
1768
+ // 检查 url 和 票据获取接口实现
1769
+ this._options.url = (_j = (_h = options.url) !== null && _h !== void 0 ? _h : this._options.url) !== null && _j !== void 0 ? _j : '';
1770
+ this._options.getTicket = (_k = options.getTicket) !== null && _k !== void 0 ? _k : this._options.getTicket;
1771
+ this._options.initialMicroStatus =
1772
+ (_l = options.rtcMicStatus) !== null && _l !== void 0 ? _l : this._options.initialMicroStatus;
1773
+ if (!/^ws(s):\/\//.test(this._options.url) ||
1774
+ typeof this._options.getTicket !== 'function') {
1775
+ if (!/^ws(s):\/\//.test(this._options.url)) {
1776
+ return new Error('Illegal realsee live room link');
1777
+ }
1778
+ if (typeof this._options.getTicket !== 'function') {
1779
+ return new Error('getTicket muse be function');
1780
+ }
1781
+ return false;
1396
1782
  }
1397
- }
1398
- getFramesByKey(key) {
1399
- return liveController.keyframes[key];
1400
- }
1401
- sendKeyframe(key, frame) {
1402
- if (this.readyState !== WebSocketState.OPEN) {
1403
- return new Error('The connection is not open and ready to communicate.');
1783
+ const { force = false } = options;
1784
+ // 检查是否已有实例在使用
1785
+ const currentState = this.state;
1786
+ if (currentState === LiveState.CONNECTING ||
1787
+ currentState === LiveState.OPEN) {
1788
+ if (force) {
1789
+ try {
1790
+ yield this._controller.close('force close by connect');
1791
+ }
1792
+ catch (e) {
1793
+ console.warn(e);
1794
+ }
1795
+ }
1796
+ else {
1797
+ return new Error('已有Live实例正在连接中,请勿重复连接!');
1798
+ }
1404
1799
  }
1405
- liveController.keyframes[key] = frame;
1406
- const liveMsg = createLiveMsg(Command.KeyframeSync, this.snapshot);
1407
- liveController.sendMessage(liveMsg);
1800
+ // 建立连接
1801
+ this._clearLiveData();
1802
+ const url = appendUri(this._options.url, {
1803
+ ticket: yield this._options.getTicket(),
1804
+ force: Number(!!force),
1805
+ });
1806
+ this._controller.open(url);
1408
1807
  return true;
1409
- }
1410
- broadcast(data, toUserIds, timeout) {
1411
- if (this.readyState !== WebSocketState.OPEN) {
1412
- return new Error('The connection is not open and ready to communicate.');
1808
+ });
1809
+ /**
1810
+ * 退出带看
1811
+ * @returns
1812
+ */
1813
+ this.exit = () => __awaiter(this, void 0, void 0, function* () {
1814
+ var _m;
1815
+ this._clearLiveData();
1816
+ try {
1817
+ /** 退出强制关闭语音 */
1818
+ (_m = this.$RTC) === null || _m === void 0 ? void 0 : _m.quit();
1819
+ yield this.updateStatus(BuiltinEventType.RoomChange, BuiltinActionType.RoomClose, {});
1413
1820
  }
1414
- return new Promise((resolve, reject) => {
1415
- const customEvent = createLiveMsg(Command.CustomEvent, data, toUserIds);
1416
- const front_request_id = customEvent.front_request_id;
1417
- liveController.sendMessage(customEvent);
1418
- const timeoutId = timeout
1419
- ? setTimeout(() => {
1420
- reject(new Error('RESPONSE TIMEOUT'));
1421
- this.off('broadcast', broadcast);
1422
- }, timeout)
1423
- : undefined;
1424
- const broadcast = (data, frontRequestId) => {
1425
- if (frontRequestId !== front_request_id)
1426
- return;
1427
- this.off('broadcast', broadcast);
1428
- resolve(data);
1429
- if (timeoutId)
1430
- clearInterval(timeoutId);
1431
- };
1432
- this.on('broadcast', broadcast);
1433
- });
1434
- }
1435
- async updateStatus(evtType, atnType, status, toUserIds) {
1436
- // TODO 统一规则,不能联合类型
1437
- if (this.readyState !== WebSocketState.OPEN) {
1438
- return false;
1821
+ catch (e) {
1822
+ logger$1.warn(e);
1439
1823
  }
1440
- const data = Object.assign({ event_type: evtType, action: atnType }, { data: status });
1441
- const liveMsg = createLiveMsg(Command.BuiltinMsg, data, toUserIds);
1442
- liveController.sendMessage(liveMsg);
1443
- return true;
1444
- }
1824
+ return yield this._controller.close('user exit');
1825
+ });
1826
+ /**
1827
+ * 销毁带看
1828
+ * @returns
1829
+ */
1830
+ this.dispose = () => __awaiter(this, void 0, void 0, function* () {
1831
+ this._removeLiveControllerEventListeners();
1832
+ this._clearLiveData();
1833
+ return yield this._controller.dispose();
1834
+ });
1835
+ /**
1836
+ * 设置自己的用户信息
1837
+ * @param userInfo
1838
+ * @returns
1839
+ */
1840
+ this.setSelfInfo = (userInfo) => __awaiter(this, void 0, void 0, function* () {
1841
+ return yield this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserInfo, userInfo);
1842
+ });
1445
1843
  // 仅用于用户自己的麦克风控制
1446
- async toggleMicro(microStatus) {
1447
- var _a, _b;
1448
- if (!((_b = (_a = this.selfInfo) === null || _a === void 0 ? void 0 : _a.permission) === null || _b === void 0 ? void 0 : _b.control_own_micro))
1844
+ this.toggleMicro = (microStatus) => __awaiter(this, void 0, void 0, function* () {
1845
+ var _o, _p, _q;
1846
+ if (!((_p = (_o = this.selfInfo) === null || _o === void 0 ? void 0 : _o.permission) === null || _p === void 0 ? void 0 : _p.control_own_micro))
1449
1847
  return false;
1450
- await this.$RTC.toggleMicro(microStatus);
1451
- return await this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserMicroStatus, {
1452
- status: microStatus ? MicroStatus.OPEN : MicroStatus.CLOSE,
1453
- }, []);
1454
- }
1455
- async forbidMicro(microStatus, toUserIds) {
1456
- var _a, _b;
1457
- if (liveController.options.canForbidUserMicro &&
1458
- !liveController.options.canForbidUserMicro(toUserIds)) {
1848
+ const result = yield ((_q = this.$RTC) === null || _q === void 0 ? void 0 : _q.toggleMicro(microStatus));
1849
+ if (result) {
1850
+ yield this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserMicroStatus, {
1851
+ status: microStatus ? MicroStatus.OPEN : MicroStatus.CLOSE,
1852
+ }, []);
1853
+ }
1854
+ return result;
1855
+ });
1856
+ /**
1857
+ * 控制别人的麦
1858
+ * @param microStatus
1859
+ * @param toUserIds
1860
+ * @returns
1861
+ */
1862
+ this.forbidMicro = (microStatus, toUserIds) => __awaiter(this, void 0, void 0, function* () {
1863
+ var _r, _s;
1864
+ if (typeof this._options.canForbidUserMicro === 'function' &&
1865
+ !this._options.canForbidUserMicro(toUserIds)) {
1459
1866
  return false;
1460
1867
  }
1461
- if (!((_b = (_a = this.selfInfo) === null || _a === void 0 ? void 0 : _a.permission) === null || _b === void 0 ? void 0 : _b.control_other_micro)) {
1868
+ if (!((_s = (_r = this.selfInfo) === null || _r === void 0 ? void 0 : _r.permission) === null || _s === void 0 ? void 0 : _s.control_other_micro)) {
1462
1869
  return false;
1463
1870
  }
1464
- return await this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserMicroStatus, {
1871
+ return yield this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserMicroStatus, {
1465
1872
  status: microStatus,
1466
1873
  }, toUserIds);
1467
- }
1874
+ });
1468
1875
  /**
1469
- * @deprecated 暂不可用
1876
+ * 控制别人的同步全量帧数据权限
1877
+ * @param sync
1878
+ * @param toUserIds
1879
+ * @returns
1470
1880
  */
1471
- async forbidSync(sync, toUserIds) {
1472
- var _a, _b;
1473
- if (liveController.options.canForbidUserSync &&
1474
- !liveController.options.canForbidUserSync(toUserIds)) {
1881
+ this.forbidSync = (sync, toUserIds) => __awaiter(this, void 0, void 0, function* () {
1882
+ var _t, _u;
1883
+ if (typeof this._options.canForbidUserSync === 'function' &&
1884
+ !this._options.canForbidUserSync(toUserIds)) {
1475
1885
  return false;
1476
1886
  }
1477
- if (!((_b = (_a = this.selfInfo) === null || _a === void 0 ? void 0 : _a.permission) === null || _b === void 0 ? void 0 : _b.control_other_sync)) {
1887
+ if (!((_u = (_t = this.selfInfo) === null || _t === void 0 ? void 0 : _t.permission) === null || _u === void 0 ? void 0 : _u.control_other_sync)) {
1478
1888
  return false;
1479
1889
  }
1480
- return await this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserPermission, { sync_frame: sync }, toUserIds);
1481
- }
1482
- async kick(toUserIds) {
1483
- var _a, _b;
1484
- if (liveController.options.canForbidUserKick &&
1485
- !liveController.options.canForbidUserKick(toUserIds)) {
1890
+ return yield this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserPermission, { sync_frame: sync }, toUserIds);
1891
+ });
1892
+ /**
1893
+ * 把用户踢出带看
1894
+ * @param toUserIds
1895
+ * @returns
1896
+ */
1897
+ this.kick = (toUserIds) => __awaiter(this, void 0, void 0, function* () {
1898
+ var _v, _w;
1899
+ if (typeof this._options.canForbidUserKick === 'function' &&
1900
+ !this._options.canForbidUserKick(toUserIds)) {
1486
1901
  return false;
1487
1902
  }
1488
- if (!((_b = (_a = this.selfInfo) === null || _a === void 0 ? void 0 : _a.permission) === null || _b === void 0 ? void 0 : _b.change_other_status)) {
1903
+ if (!((_w = (_v = this.selfInfo) === null || _v === void 0 ? void 0 : _v.permission) === null || _w === void 0 ? void 0 : _w.change_other_status)) {
1489
1904
  return false;
1490
1905
  }
1491
- return await this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserStatus, {
1906
+ return yield this.updateStatus(BuiltinEventType.UserChange, BuiltinActionType.UserStatus, {
1492
1907
  status: 'KICK_OUT',
1493
1908
  }, toUserIds);
1494
- }
1495
- async exit() {
1496
- /** 退出强制关闭语音(?) */
1497
- try {
1498
- this.$RTC.quit();
1499
- await this.updateStatus(BuiltinEventType.RoomChange, BuiltinActionType.RoomClose, {});
1500
- }
1501
- catch (e) {
1502
- console.log(e);
1503
- }
1504
- return liveController.dispose();
1505
- }
1506
- async connect(options = {}) {
1507
- // 连接 WebSocket 前验证麦克风权限
1508
- const microAuth = await this.$RTC.detectMicro();
1509
- if (!microAuth) {
1510
- const error = new Error('系统监测麦克风未授权~');
1511
- this.emit('ws.error', { type: WebSocketErrorType.MicroAuth, error });
1512
- return error;
1513
- }
1514
- // WebSocket 正在连接中,规避重复连接
1515
- if (liveController.connecting) {
1516
- const error = new Error('WebSocket 正在连接中,请勿重复连接 ...');
1517
- this.emit('ws.error', {
1518
- type: WebSocketErrorType.DuplicateConnect,
1519
- error,
1520
- });
1521
- return error;
1522
- }
1523
- // 非强制连接场景下,如果已经完成 WebSocket 连接则不执行后续逻辑
1524
- const { force } = options;
1525
- if (!force) {
1526
- if (this.readyState === WebSocketState.CONNECTING ||
1527
- this.readyState === WebSocketState.OPEN) {
1528
- return true;
1909
+ });
1910
+ this._addLiveControllerEventListeners();
1911
+ this._options = Object.assign({ initialMicroStatus: MicroStatus.OPEN }, opts);
1912
+ // 第一步检查jsbridge
1913
+ this._options.jsBridge = (() => {
1914
+ if (opts.jsBridge)
1915
+ return opts.jsBridge;
1916
+ if (opts.useBuiltInJsBridge)
1917
+ return new JSBridge();
1918
+ return undefined;
1919
+ })();
1920
+ // 第二步检查getVoiceSign
1921
+ this._options.getVoiceSign = (_a = opts.getVoiceSign) !== null && _a !== void 0 ? _a : unimplementedGetVoiceSign;
1922
+ // 第二步检查rtc
1923
+ this._options.rtc = (() => {
1924
+ // 优先取rtc实例
1925
+ if (opts.rtc)
1926
+ return opts.rtc;
1927
+ // 取指定的内部rtc类型
1928
+ if (opts.rtcType) {
1929
+ if (!opts.getVoiceSign) {
1930
+ logger$1.error('GetVoiceSign method must be passed when using built-in RTC instances');
1931
+ }
1932
+ switch (opts.rtcType) {
1933
+ case RTCType.RealseeVRWebViewRTC: {
1934
+ // 内置的 VRWebViewRTC
1935
+ if (this._options.jsBridge) {
1936
+ return new VRWebViewRTC({
1937
+ jsBridge: this._options.jsBridge,
1938
+ getVoiceSign: this._options.getVoiceSign,
1939
+ });
1940
+ }
1941
+ else {
1942
+ logger$1.error('JsBridge instance must be passed when using built-in VRWebViewRTC instances');
1943
+ return undefined;
1944
+ }
1945
+ }
1946
+ case RTCType.RealseeBrowserChimeRTC: {
1947
+ // 内置的 RealseeBrowserChimeRTC
1948
+ return new BrowserRTC4Chime({
1949
+ getVoiceSign: this._options.getVoiceSign,
1950
+ logLevel: opts.__debug__ ? LogLevel.DEBUG : LogLevel.ERROR,
1951
+ });
1952
+ }
1953
+ case RTCType.RealseeBrowserRTC: {
1954
+ // 内置的 RealseeBrowserRTC
1955
+ return new BrowserRTC({
1956
+ getVoiceSign: this._options.getVoiceSign,
1957
+ });
1958
+ }
1959
+ default: {
1960
+ logger$1.error('unknown built-in RTC type');
1961
+ return undefined;
1962
+ }
1529
1963
  }
1530
1964
  }
1531
- // WebSocket URL 逻辑
1532
- if (options.url) {
1533
- liveController.options.url = options.url;
1534
- }
1535
- if (options.getTicket) {
1536
- liveController.options.getTicket = options.getTicket;
1537
- }
1538
- if (!liveController.options.url ||
1539
- !liveController.options.url.startsWith('ws')) {
1540
- const error = new Error(`WebSocket URL 未配置或格式不合法:"${liveController.options.url}"`);
1541
- this.emit('ws.error', { type: WebSocketErrorType.IllegalURL, error });
1542
- return error;
1543
- }
1544
- if (!liveController.options.getTicket) {
1545
- const error = new Error(`getTicket() 未配置!`);
1546
- this.emit('ws.error', { type: WebSocketErrorType.IllegalArgs, error });
1547
- return error;
1548
- }
1549
- // 连接锁
1550
- liveController.connecting = true;
1551
- // 连接前销毁之前绑定的事件
1552
- liveController.disposeWebSocket();
1553
- this.emit('ws.beforeConnect');
1554
- const url = force || options.url || !this.url
1555
- ? appendUri(liveController.options.url, {
1556
- ticket: await liveController.options.getTicket(),
1557
- force: Number(!!force),
1558
- })
1559
- : this.url;
1560
- liveController.webSocket = new WebSocket(url);
1561
- liveController.onEvtOpnListener = () => {
1562
- liveController.checkReadyState(this);
1563
- this.emit('ws.afterConnect');
1564
- };
1565
- liveController.onEvtMsgListener = (evt) => {
1566
- liveController.checkReadyState(this);
1567
- try {
1568
- const liveMsg = parseLiveMsg(evt.data);
1569
- if (liveMsg === false)
1570
- return;
1571
- liveController.handleMessage(liveMsg, this);
1965
+ // 都不满足时取内置
1966
+ if (opts.useBuiltInRTC) {
1967
+ if (!opts.getVoiceSign) {
1968
+ logger$1.error('GetVoiceSign method must be passed when using built-in RTC instances');
1572
1969
  }
1573
- catch (error) {
1574
- // 未知错误
1575
- this.emit('ws.error', {
1576
- type: WebSocketErrorType.Unknown,
1577
- error,
1578
- target: evt,
1579
- });
1970
+ if (this._options.jsBridge) {
1971
+ if ((isRealseeVRWebview && (isAndroid || isIOS)) || isWxMiniProgram) {
1972
+ return new VRWebViewRTC({
1973
+ jsBridge: this._options.jsBridge,
1974
+ getVoiceSign: this._options.getVoiceSign,
1975
+ });
1976
+ }
1977
+ else {
1978
+ // 其它终端使用
1979
+ return opts.builtInRTCType === BuiltInRTCType.RealseeXChimeRTC
1980
+ ? new BrowserRTC4Chime({
1981
+ getVoiceSign: this._options.getVoiceSign,
1982
+ })
1983
+ : new BrowserRTC({ getVoiceSign: this._options.getVoiceSign });
1984
+ }
1580
1985
  }
1581
- };
1582
- liveController.onEvtErrListener = (evt) => {
1583
- live.emit('ws.error', { type: WebSocketErrorType.Error, target: evt });
1584
- liveController.checkReadyState(this);
1585
- };
1586
- liveController.onEvtCLEListener = (evt) => {
1587
- liveController.checkReadyState(this);
1588
- const code = Number(evt.code);
1589
- if (code === 1000)
1590
- return;
1591
- // 异常退出不一定会触发'error'事件,根据 evt.code 一些类型的退出也算是 error 行为
1592
- const errMsg = parseWSClsErr(code);
1593
- live.emit('ws.error', {
1594
- target: evt,
1595
- type: WebSocketErrorType.Close,
1596
- closeError: errMsg,
1597
- });
1598
- };
1599
- liveController.webSocket.addEventListener('open', liveController.onEvtOpnListener);
1600
- liveController.webSocket.addEventListener('message', liveController.onEvtMsgListener);
1601
- liveController.webSocket.addEventListener('error', liveController.onEvtErrListener);
1602
- liveController.webSocket.addEventListener('close', liveController.onEvtCLEListener);
1603
- return await new Promise((resolve, reject) => {
1604
- const success = () => {
1605
- resolve(true);
1606
- liveController.connecting = false;
1607
- this.off('ws.error', fail);
1608
- };
1609
- const fail = (error) => {
1610
- reject(error.error
1611
- ? error.error
1612
- : new Error('WebSocket connection failed!'));
1613
- liveController.connecting = false;
1614
- this.off('ws.afterConnect', success);
1615
- };
1616
- this.once('ws.afterConnect', success);
1617
- this.once('ws.error', fail);
1618
- });
1986
+ else {
1987
+ logger$1.error('jsBridge instance must be passed when using built-in RTC instances');
1988
+ return undefined;
1989
+ }
1990
+ }
1991
+ return undefined;
1992
+ })();
1993
+ if (!this._options.rtc) {
1994
+ logger$1.warn('unused rtc');
1619
1995
  }
1620
- async revoke() {
1621
- return true;
1996
+ // 第三步进行自动连接
1997
+ if (this._options.url && this._options.getTicket) {
1998
+ this.connect();
1622
1999
  }
2000
+ if (this._options.__debug__) {
2001
+ Object.assign(window, { $liveController: this._controller, $live: this });
2002
+ }
2003
+ }
2004
+ get options() {
2005
+ return Object.freeze(this._options || {});
2006
+ }
2007
+ /**
2008
+ * 带看状态
2009
+ */
2010
+ get state() {
2011
+ return this._controller.state;
2012
+ }
2013
+ /**
2014
+ * 兼容老逻辑
2015
+ * @deprecated 请直接读取 state 属性字段,未来将移除该属性
2016
+ */
2017
+ get readyState() {
2018
+ return this._controller.state;
2019
+ }
2020
+ /**
2021
+ * 获取当前WebSocket连接的URL。(注意:这个是WebSocket连接的完整连接,附带一些query参数)。
2022
+ * @deprecated 带看不需要关注底层ws的相关信息,未来将移除
2023
+ */
2024
+ get url() {
2025
+ return this.options.url;
2026
+ }
2027
+ /**
2028
+ * 获取当前live使用的RTC实例
2029
+ */
2030
+ get $RTC() {
2031
+ return this._options.rtc;
2032
+ }
2033
+ /**
2034
+ * 获取当前live使用的jsBridge实例
2035
+ */
2036
+ get jsBridge() {
2037
+ return this._options.jsBridge;
2038
+ }
2039
+ /**
2040
+ * 当前帧数据快照
2041
+ */
2042
+ get snapshot() {
2043
+ return this._buildInData.keyframes;
2044
+ }
2045
+ /**
2046
+ * 当前用户信息
2047
+ */
2048
+ get selfInfo() {
2049
+ return this._buildInData.selfInfo;
2050
+ }
2051
+ /**
2052
+ * 当前用户列表
2053
+ */
2054
+ get userList() {
2055
+ return this._buildInData.userList || [];
2056
+ }
2057
+ /**
2058
+ * 当前带看房间信息
2059
+ */
2060
+ get roomInfo() {
2061
+ return this._buildInData.roomInfo;
2062
+ }
2063
+ /**
2064
+ * 修改状态
2065
+ * @param evtType
2066
+ * @param atnType
2067
+ * @param status
2068
+ * @param toUserIds
2069
+ * @returns
2070
+ */
2071
+ updateStatus(evtType, atnType, status, toUserIds) {
2072
+ return __awaiter(this, void 0, void 0, function* () {
2073
+ if (this.state !== LiveState.OPEN)
2074
+ return false;
2075
+ const data = Object.assign({ event_type: evtType, action: atnType }, { data: status });
2076
+ const liveMsg = createLiveMsg(Command.BuiltinMsg, data, toUserIds);
2077
+ try {
2078
+ this._controller.sendMessage(liveMsg);
2079
+ return true;
2080
+ }
2081
+ catch (e) {
2082
+ logger$1.error(e);
2083
+ return false;
2084
+ }
2085
+ });
1623
2086
  }
1624
- const live = new LiveTpl();
1625
- // 如果是调试环境则将内部状态暴露出来
1626
- if (options.__debug__) {
1627
- Object.assign(live, { __controller__: liveController });
1628
- Object.assign(window, { $live: live });
2087
+ /**
2088
+ * 自定义广播
2089
+ * @param request 广播请求的数据
2090
+ * @param toUserIds
2091
+ * @param timeout
2092
+ * @returns
2093
+ */
2094
+ broadcast(request, toUserIds, timeout) {
2095
+ if (this.state !== LiveState.OPEN)
2096
+ return false;
2097
+ return new Promise((resolve, reject) => {
2098
+ const customEvent = createLiveMsg(Command.CustomEvent, request, toUserIds);
2099
+ const front_request_id = customEvent.front_request_id;
2100
+ const timeoutId = timeout
2101
+ ? setTimeout(() => {
2102
+ reject(new Error('RESPONSE TIMEOUT'));
2103
+ this.off('broadcast', broadcastRes);
2104
+ }, timeout)
2105
+ : undefined;
2106
+ const broadcastRes = (data, frontRequestId) => {
2107
+ if (frontRequestId !== front_request_id)
2108
+ return;
2109
+ if (timeoutId)
2110
+ clearTimeout(timeoutId);
2111
+ this.off('broadcast', broadcastRes);
2112
+ resolve(data);
2113
+ };
2114
+ this.on('broadcast', broadcastRes);
2115
+ try {
2116
+ this._controller.sendMessage(customEvent);
2117
+ }
2118
+ catch (e) {
2119
+ reject(e);
2120
+ }
2121
+ });
1629
2122
  }
1630
- return live;
1631
2123
  }
1632
2124
 
2125
+ /**
2126
+ * 创建`Live`实例
2127
+ * @param opts
2128
+ * @returns
2129
+ */
2130
+ const createLive = (opts) => {
2131
+ _clearLiveInstanceIfNeed();
2132
+ return new Live(opts);
2133
+ };
2134
+
1633
2135
  /**
1634
2136
  * 创建 {@link LiveReact} 实例,并提供 `React` 技术栈相关工具链。
1635
2137
  */
1636
2138
  function createLiveReact(options) {
1637
- const LiveContext = React.createContext(null);
2139
+ const LiveContext = createContext(null);
1638
2140
  const live = createLive(options);
1639
2141
  const jsBridge = live.jsBridge;
1640
- function LiveProvider(props) {
1641
- return (React.createElement(LiveContext.Provider, { value: props.live || live }, props.children));
1642
- }
1643
- function useLiveInstance() {
2142
+ const LiveProvider = (props) => (React.createElement(LiveContext.Provider, { value: live }, props.children));
2143
+ /**
2144
+ * 使用live实例
2145
+ * @returns
2146
+ */
2147
+ const useLiveInstance = () => {
1644
2148
  const context = React.useContext(LiveContext);
1645
2149
  if (!context)
1646
2150
  throw new Error('LiveProvider never found.');
1647
2151
  return context;
1648
- }
2152
+ };
1649
2153
  /**
2154
+ * 不建议这样使用
1650
2155
  * @deprecated
1651
2156
  * @returns
1652
2157
  */
1653
- function unsafe__useLiveInstance() {
1654
- return useLiveInstance();
1655
- }
1656
- function useRTCInstance() {
1657
- const live = useLiveInstance();
1658
- return live.$RTC;
1659
- }
2158
+ const unsafe__useLiveInstance = useCallback(() => useLiveInstance(), [useLiveInstance]);
2159
+ /**
2160
+ * 使用rtc实例
2161
+ */
2162
+ const useRTCInstance = useCallback(() => useLiveInstance().$RTC, [useLiveInstance]);
1660
2163
  /**
2164
+ * 不建议这样使用
1661
2165
  * @deprecated
1662
2166
  * @returns
1663
2167
  */
1664
- function unsafe__useRTCInstance() {
1665
- return useRTCInstance();
1666
- }
1667
- function useConnect() {
1668
- const live = useLiveInstance();
1669
- return async (options) => await live.connect(options);
1670
- }
1671
- function useCurrentWebSocketUrl() {
1672
- const live = useLiveInstance();
1673
- const [state, setState] = React.useState(undefined);
1674
- React.useEffect(() => {
1675
- const onWSBeforeConnect = () => setState(live.url);
1676
- live.on('ws.beforeConnect', onWSBeforeConnect);
1677
- return () => live.off('ws.beforeConnect', onWSBeforeConnect);
1678
- }, [live]);
1679
- return state;
1680
- }
1681
- function useKeyframeUpdateCallback(name, callback, deps = []) {
2168
+ const unsafe__useRTCInstance = useCallback(() => useRTCInstance(), [useRTCInstance]);
2169
+ /**
2170
+ * 带看连接操作
2171
+ */
2172
+ const useConnect = useCallback((options) => __awaiter(this, void 0, void 0, function* () { return yield useLiveInstance().connect(options); }), []);
2173
+ /**
2174
+ *
2175
+ * @param name
2176
+ * @param callback
2177
+ * @param deps
2178
+ * @returns
2179
+ */
2180
+ function useKeyframeUpdateCallback(key, callback, deps = []) {
1682
2181
  const live = useLiveInstance();
1683
2182
  const dependencyList = [live, name, ...deps];
1684
- const dispose = () => live.keyframes.off(name, callback);
2183
+ const dispose = () => live.keyframes.off(key, callback);
1685
2184
  React.useEffect(() => {
1686
- live.keyframes.on(name, callback);
2185
+ live.keyframes.on(key, callback);
1687
2186
  return dispose;
1688
2187
  }, dependencyList);
1689
2188
  return dispose;
1690
2189
  }
2190
+ /**
2191
+ * 带看的一些操作
2192
+ * @returns
2193
+ */
1691
2194
  function useLiveAction() {
1692
2195
  const live = useLiveInstance();
2196
+ const connect = React.useCallback((options) => __awaiter(this, void 0, void 0, function* () { return yield live.connect(options); }), [live]);
1693
2197
  const toggleMicro = React.useCallback((microStatus) => live.toggleMicro(microStatus), [live]);
1694
- const broadcast = React.useCallback((data, toUserIds, timeout = 0) => live.broadcast(data, toUserIds, timeout), [live]);
1695
- const exit = React.useCallback(() => live.exit(), [live]);
1696
- const kick = React.useCallback((toUserIds) => live.kick(toUserIds), [live]);
1697
- const forbidMicro = React.useCallback((micro, toUserIds) => live.forbidMicro(micro, toUserIds), [live]);
1698
- // const forbidSync = React.useCallback(
1699
- // (sync: boolean, toUserIds?: string | string[] | undefined) =>
1700
- // live.forbidSync(sync, toUserIds),
1701
- // [live],
1702
- // );
2198
+ const broadcast = React.useCallback((data, toUserIds, timeout = 0) => __awaiter(this, void 0, void 0, function* () { return yield live.broadcast(data, toUserIds, timeout); }), [live]);
2199
+ const exit = React.useCallback(() => __awaiter(this, void 0, void 0, function* () { return yield live.exit(); }), [live]);
2200
+ const kick = React.useCallback((toUserIds) => __awaiter(this, void 0, void 0, function* () { return yield live.kick(toUserIds); }), [live]);
2201
+ const forbidMicro = React.useCallback((micro, toUserIds = []) => __awaiter(this, void 0, void 0, function* () { return yield live.forbidMicro(micro, toUserIds); }), [live]);
2202
+ const forbidSync = React.useCallback((sync, toUserIds = []) => live.forbidSync(sync, toUserIds), [live]);
1703
2203
  const getFramesByKey = React.useCallback((key) => live.getFramesByKey(key), [live]);
1704
2204
  const sendKeyframe = React.useCallback((key, frame) => live.sendKeyframe(key, frame), [live]);
1705
2205
  const setSelfInfo = React.useCallback((userInfo) => live.setSelfInfo(userInfo), [live]);
1706
2206
  const updateStatus = React.useCallback((evtType, atnType, status, toUserIds) => live.updateStatus(evtType, atnType, status, toUserIds), [live]);
1707
2207
  return {
2208
+ connect,
1708
2209
  broadcast,
1709
2210
  exit,
1710
2211
  kick,
1711
2212
  toggleMicro,
1712
2213
  forbidMicro,
1713
- // forbidSync,
2214
+ forbidSync,
1714
2215
  sendKeyframe,
1715
2216
  getFramesByKey,
1716
2217
  setSelfInfo,
@@ -1741,16 +2242,16 @@ function createLiveReact(options) {
1741
2242
  return dispose;
1742
2243
  }
1743
2244
  /**
1744
- * @deprecated
2245
+ * 带看状态
1745
2246
  * @returns
1746
2247
  */
1747
- function useReadyState() {
2248
+ function useLiveState() {
1748
2249
  const live = useLiveInstance();
1749
- const [state, updateState] = React.useState(live.readyState);
2250
+ const [state, updateState] = React.useState(live.state);
1750
2251
  React.useEffect(() => {
1751
- const readyStateUpdate = (readyState) => updateState(readyState);
1752
- live.on('ws.readyStateUpdate', readyStateUpdate);
1753
- return () => live.off('ws.readyStateUpdate', readyStateUpdate);
2252
+ const stateChange = (state) => updateState(state);
2253
+ live.on('stateChange', stateChange);
2254
+ return () => live.off('stateChange', stateChange);
1754
2255
  }, [live]);
1755
2256
  return state;
1756
2257
  }
@@ -1787,12 +2288,12 @@ function createLiveReact(options) {
1787
2288
  live.on('selfInfoUpdate', selfInfoUpdate);
1788
2289
  return () => live.off('selfInfoUpdate', selfInfoUpdate);
1789
2290
  }, [live]);
1790
- const setState = React.useCallback(async (userInfo) => {
1791
- return await live.setSelfInfo(userInfo);
1792
- }, [live]);
2291
+ const setState = React.useCallback((userInfo) => __awaiter(this, void 0, void 0, function* () {
2292
+ return yield live.setSelfInfo(userInfo);
2293
+ }), [live]);
1793
2294
  return [state, setState];
1794
2295
  }
1795
- function useSnapshot() {
2296
+ function useKeyframesSnapshot() {
1796
2297
  const live = useLiveInstance();
1797
2298
  const [state, setState] = React.useState(live.snapshot);
1798
2299
  React.useEffect(() => {
@@ -1812,43 +2313,23 @@ function createLiveReact(options) {
1812
2313
  }, [live]);
1813
2314
  return state;
1814
2315
  }
1815
- /**
1816
- *
1817
- * @param name
1818
- * @param callback
1819
- * @param deps
1820
- * @returns
1821
- * @deprecated
1822
- */
1823
- function useWebSocketEventCallback(name, callback, deps = []) {
1824
- const live = useLiveInstance();
1825
- const dispose = () => live.off(name, callback);
1826
- const dependencyList = [live, name, ...deps];
1827
- React.useEffect(() => {
1828
- live.on(name, callback);
1829
- return dispose;
1830
- }, dependencyList);
1831
- return dispose;
1832
- }
1833
2316
  return {
1834
2317
  live,
1835
2318
  jsBridge,
1836
2319
  LiveProvider,
1837
2320
  unsafe__useLiveInstance,
1838
2321
  unsafe__useRTCInstance,
1839
- useCurrentWebSocketUrl,
1840
2322
  useConnect,
1841
2323
  useKeyframe,
1842
2324
  useKeyframeUpdateCallback,
1843
2325
  useLiveAction,
1844
2326
  useLiveEventCallback,
1845
- useReadyState,
2327
+ useLiveState,
1846
2328
  useRTCAction,
1847
2329
  useRTCEventCallback,
1848
2330
  useSelfInfo,
1849
- useSnapshot,
2331
+ useKeyframesSnapshot,
1850
2332
  useUserList,
1851
- useWebSocketEventCallback,
1852
2333
  };
1853
2334
  }
1854
2335