@rongcloud/plugin-rtc 5.2.2-alpha.1 → 5.2.4-beem.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.
- package/dist/index.d.ts +76 -8
- package/dist/index.esm.js +327 -115
- package/dist/index.js +327 -115
- package/dist/index.umd.js +327 -115
- package/package.json +3 -3
package/dist/index.umd.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* RCRTC - v5.2.
|
|
3
|
-
* CommitId -
|
|
4
|
-
*
|
|
2
|
+
* RCRTC - v5.2.4-beem.1
|
|
3
|
+
* CommitId - d026964c6715be7805a3e5c8addd64d4008d17bd
|
|
4
|
+
* Thu May 12 2022 18:57:27 GMT+0800 (China Standard Time)
|
|
5
5
|
* ©2020 RongCloud, Inc. All rights reserved.
|
|
6
6
|
*/
|
|
7
7
|
(function (global, factory) {
|
|
@@ -5603,6 +5603,25 @@
|
|
|
5603
5603
|
RCResolution["W1920_H1080"] = "W1920_H1080";
|
|
5604
5604
|
})(exports.RCResolution || (exports.RCResolution = {}));
|
|
5605
5605
|
|
|
5606
|
+
/**
|
|
5607
|
+
* 媒体资源类型
|
|
5608
|
+
*/
|
|
5609
|
+
exports.RCMediaType = void 0;
|
|
5610
|
+
(function (RCMediaType) {
|
|
5611
|
+
/**
|
|
5612
|
+
* 音频流
|
|
5613
|
+
*/
|
|
5614
|
+
RCMediaType[RCMediaType["AUDIO_ONLY"] = 0] = "AUDIO_ONLY";
|
|
5615
|
+
/**
|
|
5616
|
+
* 视频流
|
|
5617
|
+
*/
|
|
5618
|
+
RCMediaType[RCMediaType["VIDEO_ONLY"] = 1] = "VIDEO_ONLY";
|
|
5619
|
+
/**
|
|
5620
|
+
* 音视频混合流,只在 web 端存在混合流的情况
|
|
5621
|
+
*/
|
|
5622
|
+
RCMediaType[RCMediaType["AUDIO_VIDEO"] = 2] = "AUDIO_VIDEO";
|
|
5623
|
+
})(exports.RCMediaType || (exports.RCMediaType = {}));
|
|
5624
|
+
|
|
5606
5625
|
const RongRTCVideoBitrate = {
|
|
5607
5626
|
[exports.RCResolution.W176_H132]: { width: 176, height: 132, maxBitrate: 150, minBitrate: 80 },
|
|
5608
5627
|
[exports.RCResolution.W176_H144]: { width: 176, height: 144, maxBitrate: 160, minBitrate: 80 },
|
|
@@ -6121,6 +6140,40 @@
|
|
|
6121
6140
|
class RCScreenVideoTrack extends RCLocalVideoTrack {
|
|
6122
6141
|
}
|
|
6123
6142
|
|
|
6143
|
+
class RCRemoteTrack extends RCTrack {
|
|
6144
|
+
constructor(tag, userId, kind, roomId) {
|
|
6145
|
+
super(tag, userId, kind, false, roomId);
|
|
6146
|
+
this._isSubscribed = false;
|
|
6147
|
+
}
|
|
6148
|
+
/**
|
|
6149
|
+
* 根据房间数据更新状态
|
|
6150
|
+
* @param value
|
|
6151
|
+
*/
|
|
6152
|
+
__innerSetRemoteMuted(bool) {
|
|
6153
|
+
this._remoteMuted = bool;
|
|
6154
|
+
}
|
|
6155
|
+
__innerSetSubscribed(bool) {
|
|
6156
|
+
this._isSubscribed = bool;
|
|
6157
|
+
}
|
|
6158
|
+
/**
|
|
6159
|
+
* 查看是否已订阅了该远端资源
|
|
6160
|
+
* @returns
|
|
6161
|
+
*/
|
|
6162
|
+
isSubscribed() {
|
|
6163
|
+
return this._isSubscribed;
|
|
6164
|
+
}
|
|
6165
|
+
}
|
|
6166
|
+
class RCRemoteAudioTrack extends RCRemoteTrack {
|
|
6167
|
+
constructor(tag, userId, roomId) {
|
|
6168
|
+
super(tag, userId, 'audio', roomId);
|
|
6169
|
+
}
|
|
6170
|
+
}
|
|
6171
|
+
class RCRemoteVideoTrack extends RCRemoteTrack {
|
|
6172
|
+
constructor(tag, userId, roomId) {
|
|
6173
|
+
super(tag, userId, 'video', roomId);
|
|
6174
|
+
}
|
|
6175
|
+
}
|
|
6176
|
+
|
|
6124
6177
|
/**
|
|
6125
6178
|
* 构建增量消息内容
|
|
6126
6179
|
* @param objectname 消息名
|
|
@@ -6395,6 +6448,79 @@
|
|
|
6395
6448
|
});
|
|
6396
6449
|
return result;
|
|
6397
6450
|
};
|
|
6451
|
+
/**
|
|
6452
|
+
* 解析观众加房间 kv 数据
|
|
6453
|
+
* 远端无人员时,kvEntries 的 key 不包含 RC_ANCHOR_LIST
|
|
6454
|
+
* 远端无资源时,key 不包含 RC_RES_、RC_CDN
|
|
6455
|
+
* 远端有资源、无 CDN 资源时,key 不包含 RC_CDN
|
|
6456
|
+
*/
|
|
6457
|
+
const parseAudienceRoomData = (roomId, kvEntries) => {
|
|
6458
|
+
const sessionId = kvEntries.filter((kvItem) => {
|
|
6459
|
+
return kvItem.key === 'RC_RTC_SESSIONID';
|
|
6460
|
+
})[0].value;
|
|
6461
|
+
/**
|
|
6462
|
+
* 房间内远端人员
|
|
6463
|
+
*/
|
|
6464
|
+
const remoteUserIds = kvEntries.filter((kvItem) => {
|
|
6465
|
+
return kvItem.key === 'RC_ANCHOR_LIST';
|
|
6466
|
+
}).map((kvItem) => JSON.parse(kvItem.value || '[]'))[0];
|
|
6467
|
+
/**
|
|
6468
|
+
* 远端 RTC、MUC 资源
|
|
6469
|
+
*/
|
|
6470
|
+
const remoteRes = kvEntries.filter((kvItem) => {
|
|
6471
|
+
return kvItem.key.includes('RC_RES_');
|
|
6472
|
+
}).map((kvItem) => JSON.parse(kvItem.value || '{}'));
|
|
6473
|
+
/**
|
|
6474
|
+
* 远端 MUC 资源
|
|
6475
|
+
*/
|
|
6476
|
+
const remoteMUCUris = remoteRes.length ? JSON.parse(remoteRes[0].mcu_uris || '[]') : [];
|
|
6477
|
+
/**
|
|
6478
|
+
* 远端 MUC tracks
|
|
6479
|
+
*/
|
|
6480
|
+
const remoteMCUTracks = [];
|
|
6481
|
+
remoteMUCUris.forEach((uri) => {
|
|
6482
|
+
const { mediaType, tag } = uri;
|
|
6483
|
+
const track = mediaType === exports.RCMediaType.AUDIO_ONLY ? new RCRemoteAudioTrack(tag, '', roomId) : new RCRemoteVideoTrack(tag, '', roomId);
|
|
6484
|
+
remoteMCUTracks.push(track);
|
|
6485
|
+
});
|
|
6486
|
+
/**
|
|
6487
|
+
* 远端 RTC 资源
|
|
6488
|
+
*/
|
|
6489
|
+
const remoteRTCUris = [];
|
|
6490
|
+
/**
|
|
6491
|
+
* 远端 RTC tracks
|
|
6492
|
+
*/
|
|
6493
|
+
const remoteRTCTracks = [];
|
|
6494
|
+
remoteRes.forEach((res) => {
|
|
6495
|
+
const RTCUris = JSON.parse(res.uris || '[]');
|
|
6496
|
+
remoteRTCUris.push(...RTCUris);
|
|
6497
|
+
RTCUris.forEach((uri) => {
|
|
6498
|
+
const { mediaType, tag, msid } = uri;
|
|
6499
|
+
const userId = msid.split('_')[0];
|
|
6500
|
+
const track = mediaType === exports.RCMediaType.AUDIO_ONLY ? new RCRemoteAudioTrack(tag, userId) : new RCRemoteVideoTrack(tag, userId);
|
|
6501
|
+
remoteRTCTracks.push(track);
|
|
6502
|
+
});
|
|
6503
|
+
});
|
|
6504
|
+
/**
|
|
6505
|
+
* 房间内 CDN 信息
|
|
6506
|
+
*/
|
|
6507
|
+
const CDNUris = kvEntries.filter((kvItem) => {
|
|
6508
|
+
return kvItem.key === 'RC_CDN';
|
|
6509
|
+
}).map((kvItem) => {
|
|
6510
|
+
const CDNUriStr = JSON.parse(kvItem.value || '[]');
|
|
6511
|
+
return JSON.parse(CDNUriStr.cdn_uris)[0];
|
|
6512
|
+
})[0];
|
|
6513
|
+
return {
|
|
6514
|
+
sessionId,
|
|
6515
|
+
remoteUserIds: remoteUserIds || [],
|
|
6516
|
+
remoteRTCUris,
|
|
6517
|
+
remoteMUCUris,
|
|
6518
|
+
remoteRTCTracks,
|
|
6519
|
+
remoteMCUTracks,
|
|
6520
|
+
remoteTracks: [...remoteRTCTracks, ...remoteMCUTracks],
|
|
6521
|
+
CDNUris: CDNUris || {}
|
|
6522
|
+
};
|
|
6523
|
+
};
|
|
6398
6524
|
|
|
6399
6525
|
/**
|
|
6400
6526
|
* RTC 消息类型常量
|
|
@@ -6560,7 +6686,7 @@
|
|
|
6560
6686
|
audioLevel = audioLevel / 32767;
|
|
6561
6687
|
}
|
|
6562
6688
|
const rate = 10 ** factor;
|
|
6563
|
-
return Math.
|
|
6689
|
+
return Math.ceil(audioLevel * rate);
|
|
6564
6690
|
};
|
|
6565
6691
|
/**
|
|
6566
6692
|
* 计算丢包率
|
|
@@ -6602,25 +6728,6 @@
|
|
|
6602
6728
|
return true;
|
|
6603
6729
|
};
|
|
6604
6730
|
|
|
6605
|
-
/**
|
|
6606
|
-
* 媒体资源类型
|
|
6607
|
-
*/
|
|
6608
|
-
exports.RCMediaType = void 0;
|
|
6609
|
-
(function (RCMediaType) {
|
|
6610
|
-
/**
|
|
6611
|
-
* 音频流
|
|
6612
|
-
*/
|
|
6613
|
-
RCMediaType[RCMediaType["AUDIO_ONLY"] = 0] = "AUDIO_ONLY";
|
|
6614
|
-
/**
|
|
6615
|
-
* 视频流
|
|
6616
|
-
*/
|
|
6617
|
-
RCMediaType[RCMediaType["VIDEO_ONLY"] = 1] = "VIDEO_ONLY";
|
|
6618
|
-
/**
|
|
6619
|
-
* 音视频混合流,只在 web 端存在混合流的情况
|
|
6620
|
-
*/
|
|
6621
|
-
RCMediaType[RCMediaType["AUDIO_VIDEO"] = 2] = "AUDIO_VIDEO";
|
|
6622
|
-
})(exports.RCMediaType || (exports.RCMediaType = {}));
|
|
6623
|
-
|
|
6624
6731
|
class AbstractStatParser {
|
|
6625
6732
|
constructor(_rtcPeerConn, _sdpSemantics) {
|
|
6626
6733
|
this._rtcPeerConn = _rtcPeerConn;
|
|
@@ -7078,7 +7185,7 @@
|
|
|
7078
7185
|
}
|
|
7079
7186
|
const { trackId } = inboundInfo;
|
|
7080
7187
|
// inboundInfo 中取不到 audioLevel 时,需从 type 为 track 中取
|
|
7081
|
-
const
|
|
7188
|
+
const audioLevel = inboundInfo.audioLevel || stats[trackId].audioLevel;
|
|
7082
7189
|
const resourceId = this.getResourceIdByParseSdp(inboundInfo);
|
|
7083
7190
|
audioLevelList.push({
|
|
7084
7191
|
trackId: resourceId,
|
|
@@ -7491,6 +7598,7 @@
|
|
|
7491
7598
|
*/
|
|
7492
7599
|
static setSdpSemantics(sdpSemantics) {
|
|
7493
7600
|
const { browser, version, supportsUnifiedPlan } = browserInfo;
|
|
7601
|
+
logger.debug(`sdpSemantics, browser: ${browser}, version: ${version}, supportsUnifiedPlan: ${supportsUnifiedPlan}`);
|
|
7494
7602
|
// 在明确不支持 unified-plan 的版本中使用 plan-b
|
|
7495
7603
|
if (!supportsUnifiedPlan) {
|
|
7496
7604
|
this._sdpSemantics = 'plan-b';
|
|
@@ -7767,8 +7875,12 @@
|
|
|
7767
7875
|
removeTracks.length && removeTracks.forEach(item => {
|
|
7768
7876
|
const trackId = item.getTrackId();
|
|
7769
7877
|
item.__innerSetMediaStreamTrack(undefined);
|
|
7878
|
+
/**
|
|
7879
|
+
* peerConnection ontrack 回调参数 RTCTrackEvent 对象中 streams 为 [] 时,服务端无资源,不会添加 transceiver
|
|
7880
|
+
* 需兼容无 transceiver 的情况
|
|
7881
|
+
*/
|
|
7770
7882
|
const transceiver = this._recvTransceiver[trackId];
|
|
7771
|
-
transceiver.direction = 'inactive';
|
|
7883
|
+
transceiver && (transceiver.direction = 'inactive');
|
|
7772
7884
|
});
|
|
7773
7885
|
const addCount = { audio: 0, video: 0 };
|
|
7774
7886
|
addTracks.length && addTracks.forEach(item => {
|
|
@@ -7920,6 +8032,14 @@
|
|
|
7920
8032
|
}
|
|
7921
8033
|
}
|
|
7922
8034
|
_onTrackReady(evt) {
|
|
8035
|
+
/**
|
|
8036
|
+
* signal 和 mediaServer 不同步时,signal 有资源,mediaServer 没资源,
|
|
8037
|
+
* 订阅 mediaServer 不存在的资源时,对应 answer sdp 中的通道没有 ssrc,
|
|
8038
|
+
* ontrack 会被触发,但 RTCTrackEvent 对象中的 streams 为 [],需兼容
|
|
8039
|
+
*/
|
|
8040
|
+
if (!evt.streams.length) {
|
|
8041
|
+
return;
|
|
8042
|
+
}
|
|
7923
8043
|
// 更新 transceiver 与 trackId 的订阅关系
|
|
7924
8044
|
const msid = evt.streams[0].id;
|
|
7925
8045
|
const track = evt.receiver.track;
|
|
@@ -7936,13 +8056,13 @@
|
|
|
7936
8056
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7937
8057
|
const offer = yield this._sdpStrategy.createOffer(iceRestart);
|
|
7938
8058
|
// logger.debug(`sdpDemantics -> ${offer.semantics}`)
|
|
7939
|
-
|
|
8059
|
+
logger.debug(`offer -> ${JSON.stringify(offer.sdp)}`);
|
|
7940
8060
|
return offer;
|
|
7941
8061
|
});
|
|
7942
8062
|
}
|
|
7943
8063
|
setRemoteAnswer(answer) {
|
|
7944
8064
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7945
|
-
|
|
8065
|
+
logger.debug(`answer -> ${JSON.stringify(answer)}`);
|
|
7946
8066
|
return this._sdpStrategy.setRemoteAnswer(answer);
|
|
7947
8067
|
});
|
|
7948
8068
|
}
|
|
@@ -8317,7 +8437,7 @@
|
|
|
8317
8437
|
* 加入房间
|
|
8318
8438
|
*/
|
|
8319
8439
|
sendR1() {
|
|
8320
|
-
const rtcVersion = "5.2.
|
|
8440
|
+
const rtcVersion = "5.2.4-beem.1";
|
|
8321
8441
|
const imVersion = this._context.getCoreVersion();
|
|
8322
8442
|
const platform = 'web';
|
|
8323
8443
|
const pcName = navigator.platform;
|
|
@@ -8339,40 +8459,6 @@
|
|
|
8339
8459
|
}
|
|
8340
8460
|
}
|
|
8341
8461
|
|
|
8342
|
-
class RCRemoteTrack extends RCTrack {
|
|
8343
|
-
constructor(tag, userId, kind, roomId) {
|
|
8344
|
-
super(tag, userId, kind, false, roomId);
|
|
8345
|
-
this._isSubscribed = false;
|
|
8346
|
-
}
|
|
8347
|
-
/**
|
|
8348
|
-
* 根据房间数据更新状态
|
|
8349
|
-
* @param value
|
|
8350
|
-
*/
|
|
8351
|
-
__innerSetRemoteMuted(bool) {
|
|
8352
|
-
this._remoteMuted = bool;
|
|
8353
|
-
}
|
|
8354
|
-
__innerSetSubscribed(bool) {
|
|
8355
|
-
this._isSubscribed = bool;
|
|
8356
|
-
}
|
|
8357
|
-
/**
|
|
8358
|
-
* 查看是否已订阅了该远端资源
|
|
8359
|
-
* @returns
|
|
8360
|
-
*/
|
|
8361
|
-
isSubscribed() {
|
|
8362
|
-
return this._isSubscribed;
|
|
8363
|
-
}
|
|
8364
|
-
}
|
|
8365
|
-
class RCRemoteAudioTrack extends RCRemoteTrack {
|
|
8366
|
-
constructor(tag, userId, roomId) {
|
|
8367
|
-
super(tag, userId, 'audio', roomId);
|
|
8368
|
-
}
|
|
8369
|
-
}
|
|
8370
|
-
class RCRemoteVideoTrack extends RCRemoteTrack {
|
|
8371
|
-
constructor(tag, userId, roomId) {
|
|
8372
|
-
super(tag, userId, 'video', roomId);
|
|
8373
|
-
}
|
|
8374
|
-
}
|
|
8375
|
-
|
|
8376
8462
|
/**
|
|
8377
8463
|
* 北极星上报 R2 参数
|
|
8378
8464
|
*/
|
|
@@ -8681,15 +8767,18 @@
|
|
|
8681
8767
|
logger.warn(`onKickOff -> byServer: ${byServer}`);
|
|
8682
8768
|
this._ntfClearRoomItem();
|
|
8683
8769
|
this._leaveHandle(!byServer);
|
|
8770
|
+
// 扩展字段,备注用户为什么被踢出房间
|
|
8771
|
+
let kickExtra;
|
|
8684
8772
|
let kickType;
|
|
8685
8773
|
if (byServer) {
|
|
8686
8774
|
((content === null || content === void 0 ? void 0 : content.users) || []).forEach(item => {
|
|
8687
8775
|
if (item.userId === this._context.getCurrentId()) {
|
|
8688
8776
|
kickType = item.type;
|
|
8777
|
+
kickExtra = item.kickExtra;
|
|
8689
8778
|
}
|
|
8690
8779
|
});
|
|
8691
8780
|
}
|
|
8692
|
-
this._callAppListener('onKickOff', byServer, kickType);
|
|
8781
|
+
this._callAppListener('onKickOff', byServer, kickType, kickExtra);
|
|
8693
8782
|
}
|
|
8694
8783
|
_rtcpeerClosed() {
|
|
8695
8784
|
this._ntfClearRoomItem();
|
|
@@ -8710,7 +8799,8 @@
|
|
|
8710
8799
|
return;
|
|
8711
8800
|
}
|
|
8712
8801
|
const { uris, ignore } = content;
|
|
8713
|
-
|
|
8802
|
+
// 内置 CDN 为自动时,先收到 cdn_uris,无 uris 时,不用再对比资源
|
|
8803
|
+
if (ignore || !uris) {
|
|
8714
8804
|
return;
|
|
8715
8805
|
}
|
|
8716
8806
|
const publishedList = [];
|
|
@@ -9303,14 +9393,13 @@
|
|
|
9303
9393
|
extend: JSON.stringify({
|
|
9304
9394
|
resolutionInfo: this._pc.getOutboundVideoInfo()
|
|
9305
9395
|
}),
|
|
9306
|
-
/**
|
|
9307
|
-
* 需过滤房间内不存在的资源
|
|
9308
|
-
*/
|
|
9309
9396
|
subscribeList: subscribeList.filter((item) => {
|
|
9310
|
-
var _a;
|
|
9311
9397
|
const trackId = item.track.getTrackId();
|
|
9312
9398
|
const { userId } = parseTrackId(trackId);
|
|
9313
|
-
|
|
9399
|
+
if (!this._roomResources[userId]) {
|
|
9400
|
+
return false;
|
|
9401
|
+
}
|
|
9402
|
+
const isInclude = this._roomResources[userId].filter(item => trackId === `${item.msid}_${item.mediaType}`).length;
|
|
9314
9403
|
return isInclude;
|
|
9315
9404
|
}).map(item => ({
|
|
9316
9405
|
simulcast: item.subTiny ? RCStreamType.TINY : RCStreamType.NORMAL,
|
|
@@ -9611,7 +9700,7 @@
|
|
|
9611
9700
|
if (result.code !== exports.RCRTCCode.SUCCESS) {
|
|
9612
9701
|
return { code: result.code };
|
|
9613
9702
|
}
|
|
9614
|
-
const { sdp: answer, resultCode, message } = result.data;
|
|
9703
|
+
const { sdp: answer, resultCode, message, subscribedList } = result.data;
|
|
9615
9704
|
if (resultCode !== exports.RCRTCCode.SUCCESS) {
|
|
9616
9705
|
logger.error(`change subscribe list failed: ${resultCode}`);
|
|
9617
9706
|
return { code: resultCode };
|
|
@@ -9621,14 +9710,18 @@
|
|
|
9621
9710
|
if (resCode !== exports.RCRTCCode.SUCCESS) {
|
|
9622
9711
|
return { code: resCode };
|
|
9623
9712
|
}
|
|
9713
|
+
// 获取真正订阅成功的资源
|
|
9714
|
+
const subSuccessTrackIds = subscribedList === null || subscribedList === void 0 ? void 0 : subscribedList.map(item => `${item.msid}_${item.mediaType}`);
|
|
9715
|
+
const subSuccessList = attrs.filter(item => subSuccessTrackIds === null || subSuccessTrackIds === void 0 ? void 0 : subSuccessTrackIds.includes(item.track.getTrackId()));
|
|
9716
|
+
const failedList = attrs.filter(item => !(subSuccessTrackIds === null || subSuccessTrackIds === void 0 ? void 0 : subSuccessTrackIds.includes(item.track.getTrackId())));
|
|
9624
9717
|
// 更新 remoteTrack.isSubscribed
|
|
9625
9718
|
for (const trackId in this._remoteTracks) {
|
|
9626
|
-
const subed =
|
|
9719
|
+
const subed = subSuccessList.some(item => item.track.getTrackId() === trackId);
|
|
9627
9720
|
this._remoteTracks[trackId].__innerSetSubscribed(subed);
|
|
9628
9721
|
}
|
|
9629
9722
|
// 更新本地订阅关系
|
|
9630
|
-
this._subscribedList.splice(0, this._subscribedList.length, ...
|
|
9631
|
-
return { code: exports.RCRTCCode.SUCCESS };
|
|
9723
|
+
this._subscribedList.splice(0, this._subscribedList.length, ...subSuccessList);
|
|
9724
|
+
return failedList.length ? { code: exports.RCRTCCode.SUCCESS, failedList } : { code: exports.RCRTCCode.SUCCESS };
|
|
9632
9725
|
});
|
|
9633
9726
|
}
|
|
9634
9727
|
/**
|
|
@@ -10586,7 +10679,7 @@
|
|
|
10586
10679
|
'Content-Type': 'application/json;charset=UTF-8',
|
|
10587
10680
|
'Cache-Control': 'no-cache',
|
|
10588
10681
|
ClientType: `web|${browserInfo.browser}|${browserInfo.version}`,
|
|
10589
|
-
ClientVersion: "5.2.
|
|
10682
|
+
ClientVersion: "5.2.4-beem.1",
|
|
10590
10683
|
'Client-Session-Id': getUUID(),
|
|
10591
10684
|
'Request-Id': Date.now().toString()
|
|
10592
10685
|
});
|
|
@@ -11053,14 +11146,28 @@
|
|
|
11053
11146
|
this._roomId = _roomId;
|
|
11054
11147
|
this._joinResData = _joinResData;
|
|
11055
11148
|
this._livingType = _livingType;
|
|
11149
|
+
/**
|
|
11150
|
+
* 主播列表
|
|
11151
|
+
*/
|
|
11056
11152
|
this._roomAnchorList = [];
|
|
11153
|
+
/**
|
|
11154
|
+
* 合流、分流资源
|
|
11155
|
+
*/
|
|
11057
11156
|
this._roomRes = {};
|
|
11157
|
+
/**
|
|
11158
|
+
* 主播分流资源
|
|
11159
|
+
*/
|
|
11058
11160
|
this._roomAnchorRes = {};
|
|
11161
|
+
/**
|
|
11162
|
+
* 合流、分流 remoteTracks
|
|
11163
|
+
*/
|
|
11059
11164
|
this._remoteTracks = {};
|
|
11060
11165
|
this._appListener = null;
|
|
11061
11166
|
this._subscribedList = [];
|
|
11062
11167
|
this._sessionId = '';
|
|
11063
11168
|
this._destroyed = false;
|
|
11169
|
+
// 解析服务返回的 KV 数据,并赋值房间内数据
|
|
11170
|
+
this._setInitData();
|
|
11064
11171
|
this._service = new RCMediaService(this._runtime, this._context, this._initOptions.mediaServer, this._initOptions.timeout);
|
|
11065
11172
|
// 北极星数据
|
|
11066
11173
|
this._polarisReport = new PolarisReporter(this._context, this._runtime, this._roomId, this, PolarisRole.Audience);
|
|
@@ -11082,6 +11189,54 @@
|
|
|
11082
11189
|
// 房间主播加入|离开房间、发布|取消发布资源变更监听
|
|
11083
11190
|
this._context.onrtcdatachange = this.singalDataChange.bind(this);
|
|
11084
11191
|
}
|
|
11192
|
+
/**
|
|
11193
|
+
* 解析服务端返回的 KV 数据,赋值 room 内数据
|
|
11194
|
+
*/
|
|
11195
|
+
_setInitData() {
|
|
11196
|
+
const { sessionId, remoteUserIds, remoteRTCUris, remoteMUCUris, remoteTracks, CDNUris } = parseAudienceRoomData(this._roomId, this._joinResData.kvEntries);
|
|
11197
|
+
/**
|
|
11198
|
+
* session 赋值
|
|
11199
|
+
*/
|
|
11200
|
+
this._sessionId = sessionId;
|
|
11201
|
+
/**
|
|
11202
|
+
* 主播列表赋值
|
|
11203
|
+
*/
|
|
11204
|
+
this._roomAnchorList = remoteUserIds;
|
|
11205
|
+
/**
|
|
11206
|
+
* RTC、MCU tracks 赋值
|
|
11207
|
+
*/
|
|
11208
|
+
remoteTracks.forEach((track) => {
|
|
11209
|
+
this._remoteTracks[track.getTrackId()] = track;
|
|
11210
|
+
});
|
|
11211
|
+
/**
|
|
11212
|
+
* _CDNUris 赋值
|
|
11213
|
+
*/
|
|
11214
|
+
this._CDNUris = CDNUris;
|
|
11215
|
+
/**
|
|
11216
|
+
* 房间内 RTC 资源赋值
|
|
11217
|
+
*/
|
|
11218
|
+
remoteRTCUris.forEach((uri) => {
|
|
11219
|
+
const userId = uri.msid.split('_')[0];
|
|
11220
|
+
if (this._roomAnchorRes[userId]) {
|
|
11221
|
+
this._roomAnchorRes[userId].push(uri);
|
|
11222
|
+
}
|
|
11223
|
+
else {
|
|
11224
|
+
this._roomAnchorRes[userId] = [uri];
|
|
11225
|
+
}
|
|
11226
|
+
});
|
|
11227
|
+
/**
|
|
11228
|
+
* 房间内 RTC、MCU 资源赋值
|
|
11229
|
+
*/
|
|
11230
|
+
remoteMUCUris.forEach((uri) => {
|
|
11231
|
+
const { mediaType, tag } = uri;
|
|
11232
|
+
const trackId = [this._roomId, tag, mediaType].join('_');
|
|
11233
|
+
this._roomRes[trackId] = uri;
|
|
11234
|
+
});
|
|
11235
|
+
remoteRTCUris.forEach((uri) => {
|
|
11236
|
+
const trackId = getTrackId(uri);
|
|
11237
|
+
this._roomRes[trackId] = uri;
|
|
11238
|
+
});
|
|
11239
|
+
}
|
|
11085
11240
|
_assertRoomDestroyed() {
|
|
11086
11241
|
if (this._destroyed) {
|
|
11087
11242
|
const msg = 'This room has been destroyed. Please use `RCRTCClient.joinLivingRoomAsAudience` to catch another instance.';
|
|
@@ -11131,9 +11286,6 @@
|
|
|
11131
11286
|
this._handleLeftedAnchor(leftUserIds);
|
|
11132
11287
|
}
|
|
11133
11288
|
}
|
|
11134
|
-
if (key === 'RC_RTC_SESSIONID') {
|
|
11135
|
-
this._sessionId = value;
|
|
11136
|
-
}
|
|
11137
11289
|
});
|
|
11138
11290
|
// 处理直播间 MCU 合流资源资源
|
|
11139
11291
|
this._diffRoomResource(allMcuUris);
|
|
@@ -11539,7 +11691,7 @@
|
|
|
11539
11691
|
if (result.code !== exports.RCRTCCode.SUCCESS) {
|
|
11540
11692
|
return { code: result.code };
|
|
11541
11693
|
}
|
|
11542
|
-
const { sdp: answer, resultCode, message } = result.data;
|
|
11694
|
+
const { sdp: answer, resultCode, message, subscribedList } = result.data;
|
|
11543
11695
|
if (resultCode !== exports.RCRTCCode.SUCCESS) {
|
|
11544
11696
|
logger.error('change subscribe list failed:', message, resultCode);
|
|
11545
11697
|
return { code: resultCode };
|
|
@@ -11558,16 +11710,28 @@
|
|
|
11558
11710
|
if (resCode !== exports.RCRTCCode.SUCCESS) {
|
|
11559
11711
|
return { code: resCode };
|
|
11560
11712
|
}
|
|
11713
|
+
// 获取真正订阅成功的资源
|
|
11714
|
+
const subSuccessTrackIds = subscribedList === null || subscribedList === void 0 ? void 0 : subscribedList.map(item => `${item.msid}_${item.mediaType}`);
|
|
11715
|
+
const subSuccessList = attrs.filter(item => {
|
|
11716
|
+
if (item.track.isMCUTrack()) {
|
|
11717
|
+
const serverTrackInfo = this._roomRes[item.track.getTrackId()];
|
|
11718
|
+
const sdpResourceId = `${serverTrackInfo.msid}_${serverTrackInfo.mediaType}`;
|
|
11719
|
+
return subSuccessTrackIds.includes(sdpResourceId);
|
|
11720
|
+
}
|
|
11721
|
+
return subSuccessTrackIds === null || subSuccessTrackIds === void 0 ? void 0 : subSuccessTrackIds.includes(item.track.getTrackId());
|
|
11722
|
+
});
|
|
11723
|
+
const afterReplaceTrackIds = subSuccessList === null || subSuccessList === void 0 ? void 0 : subSuccessList.map(item => `${item.track.getTrackId()}`);
|
|
11724
|
+
const failedList = attrs.filter(item => !(afterReplaceTrackIds === null || afterReplaceTrackIds === void 0 ? void 0 : afterReplaceTrackIds.includes(item.track.getTrackId())));
|
|
11561
11725
|
// 更新 remoteTrack.isSubscribed
|
|
11562
11726
|
for (const trackId in this._remoteTracks) {
|
|
11563
|
-
const subed =
|
|
11727
|
+
const subed = subSuccessList.some(item => {
|
|
11564
11728
|
return item.track.getTrackId() === trackId;
|
|
11565
11729
|
});
|
|
11566
11730
|
this._remoteTracks[trackId].__innerSetSubscribed(subed);
|
|
11567
11731
|
}
|
|
11568
11732
|
// 更新本地订阅关系
|
|
11569
|
-
this._subscribedList.splice(0, this._subscribedList.length, ...
|
|
11570
|
-
return { code: exports.RCRTCCode.SUCCESS };
|
|
11733
|
+
this._subscribedList.splice(0, this._subscribedList.length, ...subSuccessList);
|
|
11734
|
+
return failedList.length ? { code: exports.RCRTCCode.SUCCESS, failedList } : { code: exports.RCRTCCode.SUCCESS };
|
|
11571
11735
|
});
|
|
11572
11736
|
}
|
|
11573
11737
|
/**
|
|
@@ -11575,12 +11739,11 @@
|
|
|
11575
11739
|
* @param newCDNUris 新的 cdn_uris 数据
|
|
11576
11740
|
*/
|
|
11577
11741
|
_diffCDNUris(newCDNUris) {
|
|
11578
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
11579
11742
|
return __awaiter(this, void 0, void 0, function* () {
|
|
11580
11743
|
/**
|
|
11581
11744
|
* CDN 资源减少: 上次 CDNUris 中有 url,变更后无 url
|
|
11582
11745
|
*/
|
|
11583
|
-
if (
|
|
11746
|
+
if (this._CDNUris.url && !newCDNUris.url) {
|
|
11584
11747
|
this._callAppListener('onCDNInfoDisable');
|
|
11585
11748
|
/**
|
|
11586
11749
|
* 更新内存中存储的 cdn_uris 数据
|
|
@@ -11593,22 +11756,22 @@
|
|
|
11593
11756
|
* 内存中无 CDNUris 或
|
|
11594
11757
|
* 上次 CDNUris 无 url,变更后有 url
|
|
11595
11758
|
*/
|
|
11596
|
-
if (!this._CDNUris || (!
|
|
11759
|
+
if (!this._CDNUris || (!this._CDNUris.url && newCDNUris.url)) {
|
|
11597
11760
|
this._callAppListener('onCDNInfoEnable', {
|
|
11598
11761
|
resolution: `W${newCDNUris.w}_H${newCDNUris.h}`,
|
|
11599
|
-
fps: newCDNUris.fps
|
|
11762
|
+
fps: `FPS_${newCDNUris.fps}`
|
|
11600
11763
|
});
|
|
11601
11764
|
}
|
|
11602
11765
|
/**
|
|
11603
11766
|
* CDN 资源变更: w、h、fps 其中一项变化
|
|
11604
11767
|
*/
|
|
11605
|
-
const isWChange = (
|
|
11606
|
-
const isHChange = (
|
|
11607
|
-
const isFpsChange = (
|
|
11768
|
+
const isWChange = (this._CDNUris.w && newCDNUris.w && (this._CDNUris.w !== newCDNUris.w));
|
|
11769
|
+
const isHChange = (this._CDNUris.h && newCDNUris.h && (this._CDNUris.h !== newCDNUris.h));
|
|
11770
|
+
const isFpsChange = (this._CDNUris.fps && newCDNUris.fps && (this._CDNUris.fps !== newCDNUris.fps));
|
|
11608
11771
|
if (isWChange || isHChange || isFpsChange) {
|
|
11609
11772
|
this._callAppListener('onCDNInfoChange', {
|
|
11610
11773
|
resolution: `W${newCDNUris.w}_H${newCDNUris.h}`,
|
|
11611
|
-
fps: newCDNUris.fps
|
|
11774
|
+
fps: `FPS_${newCDNUris.fps}`
|
|
11612
11775
|
});
|
|
11613
11776
|
}
|
|
11614
11777
|
/**
|
|
@@ -11619,21 +11782,16 @@
|
|
|
11619
11782
|
}
|
|
11620
11783
|
/**
|
|
11621
11784
|
* 获取 CDN 资源对应的拉流地址
|
|
11622
|
-
*
|
|
11623
|
-
* 业务层调用时使用内存中 _CDNUris 的 url,无 _CDNUris 时说明观众端未赋值过 _CDNUris
|
|
11785
|
+
* _CDNUris 无 url 时,说明未开启 CDN 推送
|
|
11624
11786
|
* @returns CDNPlayUrl
|
|
11625
11787
|
*/
|
|
11626
|
-
_getCDNPlayUrl(params
|
|
11627
|
-
var _a, _b;
|
|
11788
|
+
_getCDNPlayUrl(params) {
|
|
11628
11789
|
return __awaiter(this, void 0, void 0, function* () {
|
|
11629
11790
|
const { w, h, fps } = params;
|
|
11630
11791
|
const kind = this._initOptions.pullInnerCDNProtocol || exports.RCInnerCDNPullKind.FLV;
|
|
11631
11792
|
const useHttps = (this._initOptions.pullInnerCDNUseHttps === exports.RCInnerCDNPullIsHttps.NOT_HTTPS) ? exports.RCInnerCDNPullIsHttps.NOT_HTTPS : exports.RCInnerCDNPullIsHttps.HTTPS;
|
|
11632
|
-
|
|
11633
|
-
|
|
11634
|
-
*/
|
|
11635
|
-
if (!((_a = this._CDNUris) === null || _a === void 0 ? void 0 : _a.url) && !url) {
|
|
11636
|
-
logger.error(`cdn_uris url is empty, the anchor need to start CDN, code: ${exports.RCRTCCode.CDN_RESOURCE_IS_EMPTY}`);
|
|
11793
|
+
if (!this._CDNUris.url) {
|
|
11794
|
+
logger.error(`cdn_uris url is empty, the anchor need to open or push CDN, code: ${exports.RCRTCCode.CDN_RESOURCE_IS_EMPTY}`);
|
|
11637
11795
|
return { code: exports.RCRTCCode.CDN_RESOURCE_IS_EMPTY };
|
|
11638
11796
|
}
|
|
11639
11797
|
const headers = {
|
|
@@ -11650,7 +11808,7 @@
|
|
|
11650
11808
|
paramsArr.push(`kind=${kind}`);
|
|
11651
11809
|
paramsArr.push(`is_https=${useHttps}`);
|
|
11652
11810
|
const paramsStr = paramsArr.join('&');
|
|
11653
|
-
let requestUrl = `${
|
|
11811
|
+
let requestUrl = `${this._CDNUris.url}?`;
|
|
11654
11812
|
paramsStr && (requestUrl += paramsStr);
|
|
11655
11813
|
const { code, res } = yield this._service.getCDNResourceInfo(headers, requestUrl);
|
|
11656
11814
|
if (code !== exports.RCRTCCode.SUCCESS) {
|
|
@@ -11787,12 +11945,7 @@
|
|
|
11787
11945
|
* @param tag 参数描述
|
|
11788
11946
|
*/
|
|
11789
11947
|
registerRoomEventListener(listener) {
|
|
11790
|
-
var _a;
|
|
11791
11948
|
this._appListener = listener;
|
|
11792
|
-
if (!listener) {
|
|
11793
|
-
return;
|
|
11794
|
-
}
|
|
11795
|
-
((_a = this._joinResData.kvEntries) === null || _a === void 0 ? void 0 : _a.length) && this.singalDataChange(this._joinResData.kvEntries, this._roomId);
|
|
11796
11949
|
}
|
|
11797
11950
|
/**
|
|
11798
11951
|
* 音量上报
|
|
@@ -11873,6 +12026,44 @@
|
|
|
11873
12026
|
});
|
|
11874
12027
|
return [...mcuTracks, ...tracks];
|
|
11875
12028
|
}
|
|
12029
|
+
/**
|
|
12030
|
+
* 获取远端 RTC tracks
|
|
12031
|
+
*/
|
|
12032
|
+
getRemoteRTCTracks() {
|
|
12033
|
+
const tracks = [];
|
|
12034
|
+
for (const trackId in this._remoteTracks) {
|
|
12035
|
+
const track = this._remoteTracks[trackId];
|
|
12036
|
+
if (!track.isMCUTrack()) {
|
|
12037
|
+
tracks.push(track);
|
|
12038
|
+
}
|
|
12039
|
+
}
|
|
12040
|
+
return tracks;
|
|
12041
|
+
}
|
|
12042
|
+
/**
|
|
12043
|
+
* 获取远端 MCU tracks
|
|
12044
|
+
*/
|
|
12045
|
+
getRemoteMCUTracks() {
|
|
12046
|
+
const tracks = [];
|
|
12047
|
+
for (const trackId in this._remoteTracks) {
|
|
12048
|
+
const track = this._remoteTracks[trackId];
|
|
12049
|
+
if (track.isMCUTrack()) {
|
|
12050
|
+
tracks.push(track);
|
|
12051
|
+
}
|
|
12052
|
+
}
|
|
12053
|
+
return tracks;
|
|
12054
|
+
}
|
|
12055
|
+
/**
|
|
12056
|
+
* 获取房间内 CDN 信息
|
|
12057
|
+
*/
|
|
12058
|
+
getCDNInfo() {
|
|
12059
|
+
return this._CDNUris.w ? {
|
|
12060
|
+
resolution: `W${this._CDNUris.w}_H${this._CDNUris.h}`,
|
|
12061
|
+
fps: `FPS_${this._CDNUris.fps}`,
|
|
12062
|
+
CDNEnable: this._CDNUris.enableInnerCDN
|
|
12063
|
+
} : {
|
|
12064
|
+
CDNEnable: false
|
|
12065
|
+
};
|
|
12066
|
+
}
|
|
11876
12067
|
}
|
|
11877
12068
|
|
|
11878
12069
|
const getTracksWithOptions = (stream, options) => {
|
|
@@ -11924,11 +12115,15 @@
|
|
|
11924
12115
|
/**
|
|
11925
12116
|
* 加入普通音视频房间
|
|
11926
12117
|
* @param roomId
|
|
12118
|
+
* @param joinType 多端处理方式
|
|
12119
|
+
* @param outerUserDatas 业务层设置人员属性
|
|
12120
|
+
* @param useMutilPeerC
|
|
12121
|
+
* @param roomType 加入房间的类型 默认参数 RTCMode.RTC
|
|
11927
12122
|
*/
|
|
11928
|
-
joinRTCRoom(roomId, joinType) {
|
|
11929
|
-
return push(() => this._joinRTCRoom(roomId, joinType));
|
|
12123
|
+
joinRTCRoom(roomId, joinType, outerUserDatas, useMutilPeerC, roomType = engine.RTCMode.RTC) {
|
|
12124
|
+
return push(() => this._joinRTCRoom(roomId, joinType, outerUserDatas, useMutilPeerC, roomType));
|
|
11930
12125
|
}
|
|
11931
|
-
_joinRTCRoom(roomId, joinType) {
|
|
12126
|
+
_joinRTCRoom(roomId, joinType, outerUserDatas, useMutilPeerC, roomType = engine.RTCMode.RTC) {
|
|
11932
12127
|
return __awaiter(this, void 0, void 0, function* () {
|
|
11933
12128
|
if (isIllegalConnection(this._context.getNaviInfo())) {
|
|
11934
12129
|
return { code: exports.RCRTCCode.PACKAGE_ENVIRONMENT_ERROR };
|
|
@@ -11936,6 +12131,9 @@
|
|
|
11936
12131
|
if (!engine.validate('roomId', roomId, engine.notEmptyString, true)) {
|
|
11937
12132
|
return { code: exports.RCRTCCode.PARAMS_ERROR };
|
|
11938
12133
|
}
|
|
12134
|
+
if (!engine.validate('roomType', roomType, (value) => engine.RTCMode[value] !== undefined)) {
|
|
12135
|
+
return { code: exports.RCRTCCode.PARAMS_ERROR };
|
|
12136
|
+
}
|
|
11939
12137
|
if (this._crtRoom) {
|
|
11940
12138
|
return { code: exports.RCRTCCode.REPERT_JOIN_ROOM };
|
|
11941
12139
|
}
|
|
@@ -11946,8 +12144,8 @@
|
|
|
11946
12144
|
if (!urls.length) {
|
|
11947
12145
|
return { code: exports.RCRTCCode.NOT_OPEN_VIDEO_AUDIO_SERVER };
|
|
11948
12146
|
}
|
|
11949
|
-
logger.debug(`joinRoom -> roomId: ${roomId}; joinType: ${joinType || engine.RTCJoinType.KICK}`);
|
|
11950
|
-
const { code, data } = yield this._context.joinRTCRoom(roomId,
|
|
12147
|
+
logger.debug(`joinRoom -> roomId: ${roomId}; joinType: ${joinType || engine.RTCJoinType.KICK} roomType: ${roomType}`);
|
|
12148
|
+
const { code, data } = yield this._context.joinRTCRoom(roomId, roomType, undefined, joinType);
|
|
11951
12149
|
if (code !== engine.ErrorCode.SUCCESS) {
|
|
11952
12150
|
logger.error(`joinRoom failed -> code: ${code}`);
|
|
11953
12151
|
const errorCode = code === RTCSignalCode.JOIN_REFUSED ? exports.RCRTCCode.SIGNAL_JOIN_RTC_ROOM_REFUSED : code;
|
|
@@ -12378,7 +12576,14 @@
|
|
|
12378
12576
|
logger.info(`joinLivingRoomAsAudience success, room data: ${JSON.stringify(data)}`);
|
|
12379
12577
|
const room = new RCAudienceLivingRoom(this._context, this._runtime, this._options, roomId, data, livingType);
|
|
12380
12578
|
this._crtAudienceLivingRoom = room;
|
|
12381
|
-
return {
|
|
12579
|
+
return {
|
|
12580
|
+
room,
|
|
12581
|
+
code: exports.RCRTCCode.SUCCESS,
|
|
12582
|
+
userIds: room.getRemoteUserIds(),
|
|
12583
|
+
RTCTracks: room.getRemoteRTCTracks(),
|
|
12584
|
+
MCUTracks: room.getRemoteMCUTracks(),
|
|
12585
|
+
CDNUris: room.getCDNInfo()
|
|
12586
|
+
};
|
|
12382
12587
|
});
|
|
12383
12588
|
}
|
|
12384
12589
|
/**
|
|
@@ -12449,7 +12654,14 @@
|
|
|
12449
12654
|
this._crtRoom.__destroy(false);
|
|
12450
12655
|
// 重置主播房间
|
|
12451
12656
|
this._crtRoom = null;
|
|
12452
|
-
return {
|
|
12657
|
+
return {
|
|
12658
|
+
room: crtRoom,
|
|
12659
|
+
code: exports.RCRTCCode.SUCCESS,
|
|
12660
|
+
userIds: crtRoom.getRemoteUserIds(),
|
|
12661
|
+
RTCTracks: crtRoom.getRemoteRTCTracks(),
|
|
12662
|
+
MCUTracks: crtRoom.getRemoteMCUTracks(),
|
|
12663
|
+
CDNUris: crtRoom.getCDNInfo()
|
|
12664
|
+
};
|
|
12453
12665
|
});
|
|
12454
12666
|
}
|
|
12455
12667
|
/**
|
|
@@ -12495,9 +12707,9 @@
|
|
|
12495
12707
|
logger.error('Please use the https protocol or use `http://localhost` to open the page!');
|
|
12496
12708
|
return false;
|
|
12497
12709
|
}
|
|
12498
|
-
engine.VersionManage.add('plugin-rtc', "5.2.
|
|
12499
|
-
if (!engine.VersionManage.validEngine("
|
|
12500
|
-
logger.error(`The current engine version '${engine.VersionManage.getInfo().engine}' error, plugin-rtc required engine version at least '${"
|
|
12710
|
+
engine.VersionManage.add('plugin-rtc', "5.2.4-beem.1");
|
|
12711
|
+
if (!engine.VersionManage.validEngine("4.6.0-beem.5")) {
|
|
12712
|
+
logger.error(`The current engine version '${engine.VersionManage.getInfo().engine}' error, plugin-rtc required engine version at least '${"4.6.0-beem.5"}'.`);
|
|
12501
12713
|
return false;
|
|
12502
12714
|
}
|
|
12503
12715
|
return true;
|
|
@@ -12505,7 +12717,7 @@
|
|
|
12505
12717
|
setup(context, runtime, options = {}) {
|
|
12506
12718
|
logger.setLogLevel(options.logLevel);
|
|
12507
12719
|
logger.setLogStdout(options.logStdout);
|
|
12508
|
-
logger.warn(`RCRTC Version: ${"5.2.
|
|
12720
|
+
logger.warn(`RCRTC Version: ${"5.2.4-beem.1"}, Commit: ${"d026964c6715be7805a3e5c8addd64d4008d17bd"}`);
|
|
12509
12721
|
logger.warn(`browserInfo.browser -> ${browserInfo.browser}`);
|
|
12510
12722
|
logger.warn(`browserInfo.supportsUnifiedPlan -> ${browserInfo.supportsUnifiedPlan}`);
|
|
12511
12723
|
logger.warn(`browserInfo.version -> ${browserInfo.version}`);
|