@rongcloud/plugin-rtc 5.1.10-alpha.3 → 5.1.10-enterprise.2

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.esm.js CHANGED
@@ -1,11 +1,10 @@
1
1
  /*
2
- * RCRTC - v5.1.10-alpha.3
3
- * CommitId - 799cc871ab8fce4eb595d368ebaa84664d101f6f
4
- * Thu Oct 21 2021 10:04:21 GMT+0800 (China Standard Time)
2
+ * RCRTC - v5.1.10-enterprise.2
3
+ * CommitId - 5b9b0aef08a0933ff4adc82569d6903422b7a232
4
+ * Thu Jun 23 2022 21:44:53 GMT+0800 (China Standard Time)
5
5
  * ©2020 RongCloud, Inc. All rights reserved.
6
6
  */
7
- import { Logger, EventEmitter, isNumber, ErrorCode, ConnectionStatus, assert, ConversationType, RTCApiType, validate, isArray, RTCMode, isHttpUrl, HttpMethod, isString, notEmptyString, RTCJoinType, RTCIdentityChangeType } from '@rongcloud/engine';
8
- export { RTCJoinType } from '@rongcloud/engine';
7
+ import { Logger, EventEmitter, isNumber, ErrorCode, ConnectionStatus, assert, ConversationType, RTCApiType, validate, isArray, RTCMode, isHttpUrl, isBoolean, HttpMethod, isString, notEmptyString, RTCIdentityChangeType } from '@rongcloud/engine';
9
8
 
10
9
  /*! *****************************************************************************
11
10
  Copyright (c) Microsoft Corporation.
@@ -107,19 +106,9 @@ var RCRTCCode;
107
106
  RCRTCCode[RCRTCCode["PACKAGE_ENVIRONMENT_ERROR"] = 53025] = "PACKAGE_ENVIRONMENT_ERROR";
108
107
  /** 单个用户发布资源超过限制 ( MediaServer 限制最多 10 个 track ) */
109
108
  RCRTCCode[RCRTCCode["PUBLISH_TRACK_LIMIT_EXCEEDED"] = 53026] = "PUBLISH_TRACK_LIMIT_EXCEEDED";
110
- /** 加入 RTC 房间 joinTYype 为 1 时,当前有其他端在房间时的应答码 */
111
- RCRTCCode[RCRTCCode["SIGNAL_JOIN_RTC_ROOM_REFUSED"] = 53207] = "SIGNAL_JOIN_RTC_ROOM_REFUSED";
109
+ /** 房间内无主播推 CDN */
110
+ RCRTCCode[RCRTCCode["CDN_RESOURCE_IS_EMPTY"] = 53027] = "CDN_RESOURCE_IS_EMPTY";
112
111
  })(RCRTCCode || (RCRTCCode = {}));
113
- /**
114
- * RTC 信令 Server 返回需处理的错误 Code
115
- */
116
- var RTCSignalCode;
117
- (function (RTCSignalCode) {
118
- /**
119
- * 加入 RTC 房间 joinTYype 为 1 时,当前有其他端在房间时的应答码
120
- */
121
- RTCSignalCode[RTCSignalCode["JOIN_REFUSED"] = 40032] = "JOIN_REFUSED";
122
- })(RTCSignalCode || (RTCSignalCode = {}));
123
112
 
124
113
  class AsyncTaskQueue {
125
114
  constructor() {
@@ -6157,7 +6146,7 @@ const deepCopyResources = (resources) => {
6157
6146
  * @param prevResources 原资源数据
6158
6147
  * @param resources 变更的全量资源
6159
6148
  */
6160
- const diffPublishResources = (prevResources, resources, isReconnect = false) => {
6149
+ const diffPublishResources = (prevResources, resources) => {
6161
6150
  prevResources = prevResources.slice();
6162
6151
  const publishedList = [];
6163
6152
  const unpublishedList = [];
@@ -6166,15 +6155,7 @@ const diffPublishResources = (prevResources, resources, isReconnect = false) =>
6166
6155
  resources.forEach(item => {
6167
6156
  const resId = getTrackId(item);
6168
6157
  // 从当前房间数据中查找相同资源索引
6169
- let index = prevResources.findIndex(value => getTrackId(value) === resId);
6170
- /**
6171
- * 重连计算时,直接通过 uri 来算新增和删减的资源。因为 resources 即是最新资源,不能算资源已重新发布的情况
6172
- * 在断网重连情况下如果使用 trackId 计算 index 会导致己端在断网期间,远端取消发布资源 A(tag:C)又重新发布资源 B(tag:C)时, 无法
6173
- * 计算出取消发布的资源 A,只能算出新发布的资源 B, 导致页面视图无法更新、且订阅成功 B 资源后不抛 onTrackReady
6174
- */
6175
- if (isReconnect) {
6176
- index = prevResources.findIndex(value => value.uri === item.uri);
6177
- }
6158
+ const index = prevResources.findIndex(value => getTrackId(value) === resId);
6178
6159
  if (index === -1) {
6179
6160
  // 新增资源
6180
6161
  publishedList.push(item);
@@ -6294,7 +6275,7 @@ const isNull = (val) => {
6294
6275
  * 公有云连接私有云 SDK 为非法连接
6295
6276
  */
6296
6277
  const isIllegalConnection = (navi) => {
6297
- return navi.type === 1;
6278
+ return !true ;
6298
6279
  };
6299
6280
  /**
6300
6281
  * 获取将要发布的 track 数量
@@ -6317,6 +6298,27 @@ const calcTracksNum = (tracks) => {
6317
6298
  });
6318
6299
  return length;
6319
6300
  };
6301
+ /**
6302
+ * 解析房间数据
6303
+ */
6304
+ const parseRoomData = (data) => {
6305
+ const result = {};
6306
+ const userIds = Object.keys(data.users);
6307
+ userIds.length && userIds.forEach(userId => {
6308
+ const tmp = [];
6309
+ const userData = data.users[userId];
6310
+ if (userData.uris) {
6311
+ try {
6312
+ tmp.push(...JSON.parse(userData.uris));
6313
+ }
6314
+ catch (error) {
6315
+ logger.warn(`invalid user data -> userId: ${userId}, userData: ${userData}`);
6316
+ }
6317
+ }
6318
+ result[userId] = tmp;
6319
+ });
6320
+ return result;
6321
+ };
6320
6322
 
6321
6323
  /**
6322
6324
  * RTC 消息类型常量
@@ -6361,12 +6363,6 @@ var RCRTCMessageType;
6361
6363
  RCRTCMessageType["KICK"] = "RCRTC:kick";
6362
6364
  })(RCRTCMessageType || (RCRTCMessageType = {}));
6363
6365
 
6364
- var RCRTCPingResult;
6365
- (function (RCRTCPingResult) {
6366
- RCRTCPingResult["SUCCESS"] = "Success";
6367
- RCRTCPingResult["FAIL"] = "Fail";
6368
- })(RCRTCPingResult || (RCRTCPingResult = {}));
6369
-
6370
6366
  /**
6371
6367
  * rtcping 间隔
6372
6368
  */
@@ -6403,7 +6399,7 @@ class Pinger {
6403
6399
  });
6404
6400
  }
6405
6401
  _loop() {
6406
- var _a, _b, _c;
6402
+ var _a;
6407
6403
  return __awaiter(this, void 0, void 0, function* () {
6408
6404
  // logger.debug('rtcping send ->')
6409
6405
  const code = yield new Promise(resolve => {
@@ -6420,15 +6416,13 @@ class Pinger {
6420
6416
  if (code === ErrorCode.SUCCESS) {
6421
6417
  // logger.debug('rtcping success <-')
6422
6418
  this._latestTimestamp = now;
6423
- (_a = this.onPingResult) === null || _a === void 0 ? void 0 : _a.call(this, RCRTCPingResult.SUCCESS);
6424
6419
  return;
6425
6420
  }
6426
- (_b = this.onPingResult) === null || _b === void 0 ? void 0 : _b.call(this, RCRTCPingResult.FAIL);
6427
6421
  logger.warn(`rtcping failed -> code: ${code}`);
6428
6422
  // 超出 1 分钟未成功进行 rtcping 操作,或用户已不存在于房间内时,通知客户离线
6429
6423
  if (code === 40003 || now - this._latestTimestamp > 60 * 1000) {
6430
6424
  this.stop();
6431
- (_c = this.onFailed) === null || _c === void 0 ? void 0 : _c.call(this, code === 40003);
6425
+ (_a = this.onFailed) === null || _a === void 0 ? void 0 : _a.call(this, code === 40003);
6432
6426
  }
6433
6427
  });
6434
6428
  }
@@ -6482,7 +6476,7 @@ const handleAudioLevel = (audioLevel, factor = 2) => {
6482
6476
  audioLevel = audioLevel / 32767;
6483
6477
  }
6484
6478
  const rate = 10 ** factor;
6485
- return Math.floor(audioLevel * rate);
6479
+ return Math.ceil(audioLevel * rate);
6486
6480
  };
6487
6481
  /**
6488
6482
  * 计算丢包率
@@ -7000,7 +6994,7 @@ class RTCReportParser$2 extends AbstractStatParser {
7000
6994
  }
7001
6995
  const { trackId } = inboundInfo;
7002
6996
  // inboundInfo 中取不到 audioLevel 时,需从 type 为 track 中取
7003
- const { audioLevel } = inboundInfo || stats[trackId];
6997
+ const audioLevel = inboundInfo.audioLevel || stats[trackId].audioLevel;
7004
6998
  const resourceId = this.getResourceIdByParseSdp(inboundInfo);
7005
6999
  audioLevelList.push({
7006
7000
  trackId: resourceId,
@@ -7689,8 +7683,12 @@ class UnifiedPlanStrategy extends ASdpStrategy {
7689
7683
  removeTracks.length && removeTracks.forEach(item => {
7690
7684
  const trackId = item.getTrackId();
7691
7685
  item.__innerSetMediaStreamTrack(undefined);
7686
+ /**
7687
+ * peerConnection ontrack 回调参数 RTCTrackEvent 对象中 streams 为 [] 时,服务端无资源,不会添加 transceiver
7688
+ * 需兼容无 transceiver 的情况
7689
+ */
7692
7690
  const transceiver = this._recvTransceiver[trackId];
7693
- transceiver.direction = 'inactive';
7691
+ transceiver && (transceiver.direction = 'inactive');
7694
7692
  });
7695
7693
  const addCount = { audio: 0, video: 0 };
7696
7694
  addTracks.length && addTracks.forEach(item => {
@@ -7818,7 +7816,6 @@ class RCRTCPeerConnection extends EventEmitter {
7818
7816
  logger.info(`onconnectionstatechange -> ${this._rtcPeerConn.connectionState}`);
7819
7817
  }
7820
7818
  _onICEConnectionStateChange() {
7821
- var _a, _b;
7822
7819
  logger.info(`oniceconnectionstatechange -> ${this._rtcPeerConn.iceConnectionState}`);
7823
7820
  if (this._rtcPeerConn.iceConnectionState === 'connected') {
7824
7821
  // 开启 peerConnection stats 统计定时器
@@ -7828,20 +7825,21 @@ class RCRTCPeerConnection extends EventEmitter {
7828
7825
  this._reportStatsTimer = setInterval(this._reportHandle.bind(this), 1000);
7829
7826
  }
7830
7827
  // ICE 连接中断后,需要尝试重新走 exchange 流程以恢复
7831
- if (this._rtcPeerConn.iceConnectionState === 'failed' || this._rtcPeerConn.iceConnectionState === 'disconnected') {
7828
+ if (this._rtcPeerConn.iceConnectionState === 'failed') {
7832
7829
  logger.warn('iceconenction state is `failed`, exchange SDP to try again.');
7833
7830
  this._reTryExchange();
7834
7831
  this._reTryExchangeTimer = setInterval(this._reTryExchange, 15 * 1000);
7835
7832
  }
7836
- // ICE 变更通知
7837
- try {
7838
- (_b = (_a = this._reportListener) === null || _a === void 0 ? void 0 : _a.onICEConnectionStateChange) === null || _b === void 0 ? void 0 : _b.call(_a, this._rtcPeerConn.iceConnectionState);
7839
- }
7840
- catch (error) {
7841
- logger.error('onICEConnectionStateChange error', error);
7842
- }
7843
7833
  }
7844
7834
  _onTrackReady(evt) {
7835
+ /**
7836
+ * signal 和 mediaServer 不同步时,signal 有资源,mediaServer 没资源,
7837
+ * 订阅 mediaServer 不存在的资源时,对应 answer sdp 中的通道没有 ssrc,
7838
+ * ontrack 会被触发,但 RTCTrackEvent 对象中的 streams 为 [],需兼容
7839
+ */
7840
+ if (!evt.streams.length) {
7841
+ return;
7842
+ }
7845
7843
  // 更新 transceiver 与 trackId 的订阅关系
7846
7844
  const msid = evt.streams[0].id;
7847
7845
  const track = evt.receiver.track;
@@ -8239,7 +8237,7 @@ class PolarisReporter {
8239
8237
  * 加入房间
8240
8238
  */
8241
8239
  sendR1() {
8242
- const rtcVersion = "5.1.10-alpha.3";
8240
+ const rtcVersion = "5.1.10-enterprise.2";
8243
8241
  const imVersion = this._context.getCoreVersion();
8244
8242
  const platform = 'web';
8245
8243
  const pcName = navigator.platform;
@@ -8375,24 +8373,6 @@ class RCAudioLevelReport {
8375
8373
  }
8376
8374
  }
8377
8375
 
8378
- const parseRoomData = (data) => {
8379
- const result = {};
8380
- const userIds = Object.keys(data.users);
8381
- userIds.length && userIds.forEach(userId => {
8382
- const tmp = [];
8383
- const userData = data.users[userId];
8384
- if (userData.uris) {
8385
- try {
8386
- tmp.push(...JSON.parse(userData.uris));
8387
- }
8388
- catch (error) {
8389
- logger.warn(`invalid user data -> userId: ${userId}, userData: ${userData}`);
8390
- }
8391
- }
8392
- result[userId] = tmp;
8393
- });
8394
- return result;
8395
- };
8396
8376
  const getTrackIdFromAttr = (track) => {
8397
8377
  if (track instanceof RCTrack) {
8398
8378
  return track.getTrackId();
@@ -8450,11 +8430,10 @@ class RCAbstractRoom {
8450
8430
  /**
8451
8431
  * 观众升级为主播后不会收到全量 uri 消息,需直接触发人员、资源变更
8452
8432
  */
8453
- isUpgrade && this._afterChangedRole(parseRoomData(data));
8433
+ isUpgrade && this._afterChangedRole(data);
8454
8434
  // 开始心跳,心跳失败时主动退出房间
8455
8435
  this._pinger = new Pinger(_roomId, this._roomMode, _context, this._initOptions.pingGap);
8456
8436
  this._pinger.onFailed = this._kickoff.bind(this);
8457
- this._pinger.onPingResult = this._handlePingResult.bind(this);
8458
8437
  this._pinger.start();
8459
8438
  this._polarisReport = new PolarisReporter(this._context, this._runtime, this._roomId, this);
8460
8439
  this._polarisReport.sendR1();
@@ -8479,9 +8458,6 @@ class RCAbstractRoom {
8479
8458
  });
8480
8459
  }
8481
8460
  }
8482
- _handlePingResult(result) {
8483
- this._callAppListener('onPing', result);
8484
- }
8485
8461
  /**
8486
8462
  * 设置房间上行资源的总码率配置
8487
8463
  * @description
@@ -8573,7 +8549,7 @@ class RCAbstractRoom {
8573
8549
  const content = message.content;
8574
8550
  switch (message.messageType) {
8575
8551
  case RCRTCMessageType.KICK:
8576
- this._kickoff(true, content);
8552
+ this._kickoff(true);
8577
8553
  break;
8578
8554
  case RCRTCMessageType.STATE:
8579
8555
  this.msgTaskQueue.push(() => this._stateHandle(content));
@@ -8602,19 +8578,11 @@ class RCAbstractRoom {
8602
8578
  * * 当值为 false 时,说明本端 rtcPing 超时
8603
8579
  * * 当值为 true 时,说明本端收到被踢出房间通知
8604
8580
  */
8605
- _kickoff(byServer, content) {
8581
+ _kickoff(byServer) {
8606
8582
  logger.warn(`onKickOff -> byServer: ${byServer}`);
8607
8583
  this._ntfClearRoomItem();
8608
8584
  this._leaveHandle(!byServer);
8609
- let kickType;
8610
- if (byServer) {
8611
- ((content === null || content === void 0 ? void 0 : content.users) || []).forEach(item => {
8612
- if (item.userId === this._context.getCurrentId()) {
8613
- kickType = item.type;
8614
- }
8615
- });
8616
- }
8617
- this._callAppListener('onKickOff', byServer, kickType);
8585
+ this._callAppListener('onKickOff', byServer);
8618
8586
  }
8619
8587
  _rtcpeerClosed() {
8620
8588
  this._ntfClearRoomItem();
@@ -9195,14 +9163,13 @@ class RCAbstractRoom {
9195
9163
  extend: JSON.stringify({
9196
9164
  resolutionInfo: this._pc.getOutboundVideoInfo()
9197
9165
  }),
9198
- /**
9199
- * 需过滤房间内不存在的资源
9200
- */
9201
9166
  subscribeList: subscribeList.filter((item) => {
9202
- var _a;
9203
9167
  const trackId = item.track.getTrackId();
9204
- const { userId } = helper.parseTrackId(trackId);
9205
- const isInclude = (_a = this._roomResources[userId]) === null || _a === void 0 ? void 0 : _a.filter(item => trackId === `${item.msid}_${item.mediaType}`).length;
9168
+ const { userId } = parseTrackId(trackId);
9169
+ if (!this._roomResources[userId]) {
9170
+ return false;
9171
+ }
9172
+ const isInclude = this._roomResources[userId].filter(item => trackId === `${item.msid}_${item.mediaType}`).length;
9206
9173
  return isInclude;
9207
9174
  }).map(item => ({
9208
9175
  simulcast: item.subTiny ? RCStreamType.TINY : RCStreamType.NORMAL,
@@ -9503,7 +9470,7 @@ class RCAbstractRoom {
9503
9470
  if (result.code !== RCRTCCode.SUCCESS) {
9504
9471
  return { code: result.code };
9505
9472
  }
9506
- const { sdp: answer, resultCode, message } = result.data;
9473
+ const { sdp: answer, resultCode, message, subscribedList } = result.data;
9507
9474
  if (resultCode !== RCRTCCode.SUCCESS) {
9508
9475
  logger.error(`change subscribe list failed: ${resultCode}`);
9509
9476
  return { code: resultCode };
@@ -9513,14 +9480,18 @@ class RCAbstractRoom {
9513
9480
  if (resCode !== RCRTCCode.SUCCESS) {
9514
9481
  return { code: resCode };
9515
9482
  }
9483
+ // 获取真正订阅成功的资源
9484
+ const subSuccessTrackIds = subscribedList === null || subscribedList === void 0 ? void 0 : subscribedList.map(item => `${item.msid}_${item.mediaType}`);
9485
+ const subSuccessList = attrs.filter(item => subSuccessTrackIds === null || subSuccessTrackIds === void 0 ? void 0 : subSuccessTrackIds.includes(item.track.getTrackId()));
9486
+ const failedList = attrs.filter(item => !(subSuccessTrackIds === null || subSuccessTrackIds === void 0 ? void 0 : subSuccessTrackIds.includes(item.track.getTrackId())));
9516
9487
  // 更新 remoteTrack.isSubscribed
9517
9488
  for (const trackId in this._remoteTracks) {
9518
- const subed = attrs.some(item => item.track.getTrackId() === trackId);
9489
+ const subed = subSuccessList.some(item => item.track.getTrackId() === trackId);
9519
9490
  this._remoteTracks[trackId].__innerSetSubscribed(subed);
9520
9491
  }
9521
9492
  // 更新本地订阅关系
9522
- this._subscribedList.splice(0, this._subscribedList.length, ...attrs);
9523
- return { code: RCRTCCode.SUCCESS };
9493
+ this._subscribedList.splice(0, this._subscribedList.length, ...subSuccessList);
9494
+ return failedList.length ? { code: RCRTCCode.SUCCESS, failedList } : { code: RCRTCCode.SUCCESS };
9524
9495
  });
9525
9496
  }
9526
9497
  /**
@@ -9590,14 +9561,14 @@ class RCAbstractRoom {
9590
9561
  joinedUserIds.push(userId);
9591
9562
  // 新增人员发布的资源
9592
9563
  published[userId] = deepCopyResources(roomData[userId]);
9593
- continue;
9564
+ return;
9594
9565
  }
9595
9566
  // 房间缓存中的已发布资源
9596
9567
  const prevResources = this._roomResources[userId];
9597
9568
  // 当前资源
9598
9569
  const nowResources = roomData[userId];
9599
9570
  // 资源比对
9600
- const { publishedList, modifiedList, unpublishedList } = diffPublishResources(prevResources, nowResources, true);
9571
+ const { publishedList, modifiedList, unpublishedList } = diffPublishResources(prevResources, nowResources);
9601
9572
  published[userId] = deepCopyResources(publishedList);
9602
9573
  unpublished[userId] = deepCopyResources(unpublishedList);
9603
9574
  modified[userId] = deepCopyResources(modifiedList);
@@ -9649,6 +9620,7 @@ class RCAbstractRoom {
9649
9620
  rTrack.isAudioTrack() ? this._onAudioMuteChange(rTrack) : this._onVideoMuteChange(rTrack);
9650
9621
  });
9651
9622
  });
9623
+ return { data };
9652
9624
  });
9653
9625
  }
9654
9626
  _onAudioMuteChange(audioTrack) {
@@ -9660,27 +9632,7 @@ class RCAbstractRoom {
9660
9632
  /**
9661
9633
  * 观众切换为主播后直接处理人员变更及资源变更
9662
9634
  */
9663
- _afterChangedRole(data) {
9664
- const currentUserId = this._context.getCurrentId();
9665
- const joinedAnchorList = Object.keys(data);
9666
- // 观众升级主播成功后返回房间实例,才可注册房间事件,需异步抛出
9667
- setTimeout(() => {
9668
- // 通知业务层人员变更
9669
- const needNoticeUserIds = joinedAnchorList.filter(id => {
9670
- return id !== currentUserId;
9671
- });
9672
- needNoticeUserIds.length > 0 && this._callAppListener('onUserJoin', needNoticeUserIds);
9673
- // 通知业务层资源变更
9674
- for (const userId in data) {
9675
- if (userId === currentUserId) {
9676
- continue;
9677
- }
9678
- this.msgTaskQueue.push(() => this._resourceHandle({
9679
- uris: data[userId]
9680
- }, RCRTCMessageType.TOTAL_CONTENT_RESOURCE, userId));
9681
- }
9682
- });
9683
- }
9635
+ _afterChangedRole(data) { }
9684
9636
  /**
9685
9637
  * 主播身份降级,取消己端已发布的所有资源
9686
9638
  */
@@ -9766,9 +9718,14 @@ class RCMCUConfigBuilder {
9766
9718
  /**
9767
9719
  * trackId 有效性验证方法
9768
9720
  */
9769
- _isValidTrackId) {
9721
+ _isValidTrackId,
9722
+ /**
9723
+ * 扩散 cdn_uris
9724
+ */
9725
+ _sendCDNInfoSignal) {
9770
9726
  this._onFlush = _onFlush;
9771
9727
  this._isValidTrackId = _isValidTrackId;
9728
+ this._sendCDNInfoSignal = _sendCDNInfoSignal;
9772
9729
  /**
9773
9730
  * mcu 配置数据,每次向服务器提交全量数据
9774
9731
  */
@@ -10155,24 +10112,62 @@ class RCMCUConfigBuilder {
10155
10112
  * 使已修改的配置生效,在调用该方法前,所有数据只会对本地配置进行修改,不会产生实际效果
10156
10113
  */
10157
10114
  flush() {
10115
+ var _a, _b, _c, _d;
10158
10116
  return __awaiter(this, void 0, void 0, function* () {
10159
10117
  const config = JSON.parse(JSON.stringify(this._values));
10160
10118
  const { code } = yield this._onFlush(config);
10119
+ /**
10120
+ * 合流布局中包含分辨率设置时,需扩散 cdn_uris
10121
+ */
10122
+ if (code === RCRTCCode.SUCCESS && (((_b = (_a = this._values.output) === null || _a === void 0 ? void 0 : _a.video.normal) === null || _b === void 0 ? void 0 : _b.width) || ((_d = (_c = this._values.output) === null || _c === void 0 ? void 0 : _c.video.normal) === null || _d === void 0 ? void 0 : _d.fps))) {
10123
+ this._sendCDNInfoSignal();
10124
+ }
10161
10125
  this._values = createMCUConfig();
10162
10126
  return { code };
10163
10127
  });
10164
10128
  }
10165
10129
  }
10166
10130
 
10131
+ var RCInnerCDNModel;
10132
+ (function (RCInnerCDNModel) {
10133
+ // 开启
10134
+ RCInnerCDNModel[RCInnerCDNModel["OPEN"] = 1] = "OPEN";
10135
+ // 停用
10136
+ RCInnerCDNModel[RCInnerCDNModel["STOP"] = 2] = "STOP";
10137
+ })(RCInnerCDNModel || (RCInnerCDNModel = {}));
10138
+
10139
+ var RCInnerCDNBroadcast;
10140
+ (function (RCInnerCDNBroadcast) {
10141
+ // 扩散
10142
+ RCInnerCDNBroadcast[RCInnerCDNBroadcast["SPREAD"] = 0] = "SPREAD";
10143
+ RCInnerCDNBroadcast[RCInnerCDNBroadcast["NO_SPREAD"] = -1] = "NO_SPREAD";
10144
+ })(RCInnerCDNBroadcast || (RCInnerCDNBroadcast = {}));
10145
+
10146
+ var RCInnerCDNPushMode;
10147
+ (function (RCInnerCDNPushMode) {
10148
+ // 自动模式
10149
+ RCInnerCDNPushMode[RCInnerCDNPushMode["AUTOMATIC"] = 0] = "AUTOMATIC";
10150
+ // 手动模式
10151
+ RCInnerCDNPushMode[RCInnerCDNPushMode["MANUAL"] = 1] = "MANUAL";
10152
+ })(RCInnerCDNPushMode || (RCInnerCDNPushMode = {}));
10153
+
10167
10154
  /**
10168
10155
  * 直播房间
10169
10156
  */
10170
10157
  class RCLivingRoom extends RCAbstractRoom {
10171
10158
  constructor(context, runtime, roomId, data, service, initOptions, clientEvent, _livingType, isUpgrage = false) {
10159
+ var _a;
10172
10160
  super(context, runtime, roomId, data, RTCMode.LIVE, service, initOptions, clientEvent, isUpgrage);
10173
10161
  this._livingType = _livingType;
10162
+ /**
10163
+ * cdn_uris 信令扩散数据
10164
+ */
10165
+ this._CDNUris = null;
10166
+ this._CDNEnable = false;
10174
10167
  // 初始化 MCUBuilder
10175
- this._mcuConfigBuilder = new RCMCUConfigBuilder(this._onMCUConfigFlush.bind(this), this._isValidResourceId.bind(this));
10168
+ this._mcuConfigBuilder = new RCMCUConfigBuilder(this._onMCUConfigFlush.bind(this), this._isValidResourceId.bind(this), this._sendCDNInfoSignal.bind(this));
10169
+ const CDNUris = (_a = data.roomInfo.filter((item) => { return item.key === 'cdn_uris'; })[0]) === null || _a === void 0 ? void 0 : _a.value;
10170
+ CDNUris && (this._CDNUris = JSON.parse(CDNUris)[0]);
10176
10171
  }
10177
10172
  getLivingType() {
10178
10173
  return this._livingType;
@@ -10196,16 +10191,214 @@ class RCLivingRoom extends RCAbstractRoom {
10196
10191
  UserId: this._context.getCurrentId(),
10197
10192
  SessionId: this.getSessionId()
10198
10193
  };
10199
- const { code } = yield this._service.setMcuConfig(headers, data);
10194
+ const { code, res } = yield this._service.setMcuConfig(headers, data);
10200
10195
  if (code !== RCRTCCode.SUCCESS) {
10201
10196
  logger.error(`set MCU config failed: ${code}`);
10197
+ return { code };
10202
10198
  }
10203
- logger.debug('set MCU config success');
10204
- return { code };
10199
+ logger.info('set MCU config success');
10200
+ res.pull_url && (this._CDNUris = JSON.parse(res.pull_url));
10201
+ return { code, res };
10205
10202
  });
10206
10203
  }
10204
+ /**
10205
+ * 主播端断线重连后,需更新内存中的 CDN 数据
10206
+ * 判断房间内 CDN 状态是否和内存数据一致,不一致时需通知到客户端
10207
+ */
10207
10208
  __onReconnected() {
10208
- return super.__onReconnected(this._livingType);
10209
+ const _super = Object.create(null, {
10210
+ __onReconnected: { get: () => super.__onReconnected }
10211
+ });
10212
+ var _a, _b;
10213
+ return __awaiter(this, void 0, void 0, function* () {
10214
+ const res = yield _super.__onReconnected.call(this, this._livingType);
10215
+ if (!res || !res.data) {
10216
+ return;
10217
+ }
10218
+ const roomInfo = res.data.roomInfo;
10219
+ const CDNUris = (_a = roomInfo.filter((item) => { return item.key === 'cdn_uris'; })[0]) === null || _a === void 0 ? void 0 : _a.value;
10220
+ if (!CDNUris) {
10221
+ return;
10222
+ }
10223
+ const parseCDNUris = JSON.parse(CDNUris);
10224
+ if (((_b = this._CDNUris) === null || _b === void 0 ? void 0 : _b.enableInnerCDN) !== parseCDNUris.enableInnerCDN) {
10225
+ this._callAppListener('onCDNEnableChange', parseCDNUris.enableInnerCDN);
10226
+ }
10227
+ this._CDNUris = parseCDNUris;
10228
+ });
10229
+ }
10230
+ /**
10231
+ * 开启/停用推 CDN
10232
+ */
10233
+ enableInnerCDN(enable) {
10234
+ return __awaiter(this, void 0, void 0, function* () {
10235
+ if (!isBoolean(enable)) {
10236
+ logger.error('`enable` is invalid');
10237
+ return { code: RCRTCCode.PARAMS_ERROR };
10238
+ }
10239
+ this._CDNEnable = enable;
10240
+ const params = {
10241
+ version: 2,
10242
+ output: {
10243
+ inCDNModel: enable ? RCInnerCDNModel.OPEN : RCInnerCDNModel.STOP
10244
+ }
10245
+ };
10246
+ const { code } = yield this._onMCUConfigFlush(params);
10247
+ if (code !== RCRTCCode.SUCCESS) {
10248
+ logger.error(`enableInnerCDN failed -> code: ${code}`);
10249
+ return { code: RCRTCCode.SIGNAL_ERROR };
10250
+ }
10251
+ // 判断是否需要扩散 cdn_uris 时
10252
+ if (this._CDNUris && (this._CDNUris.broadcast !== RCInnerCDNBroadcast.SPREAD)) {
10253
+ logger.info('enableInnerCDN succeed');
10254
+ return { code: RCRTCCode.SUCCESS };
10255
+ }
10256
+ /**
10257
+ * 扩散 cdn_uris
10258
+ */
10259
+ const { code: sendSingalCode } = yield push(() => __awaiter(this, void 0, void 0, function* () { return this._sendCDNInfoSignal(); }));
10260
+ if (sendSingalCode === RCRTCCode.SUCCESS) {
10261
+ logger.info('enableInnerCDN succeed');
10262
+ return { code: RCRTCCode.SUCCESS };
10263
+ }
10264
+ logger.error(`enableInnerCDN failed -> code: ${sendSingalCode}`);
10265
+ return { code: sendSingalCode };
10266
+ });
10267
+ }
10268
+ /**
10269
+ * 开启、停用 CDN 推资源后发信令
10270
+ */
10271
+ _sendCDNInfoSignal() {
10272
+ return __awaiter(this, void 0, void 0, function* () {
10273
+ this._CDNUris = Object.assign({}, this._CDNUris, { enableInnerCDN: this._CDNEnable });
10274
+ const resCodeArr = yield Promise.all([this._spreadCDNInfo(this._CDNUris), this._setRoomCDNInfo(this._CDNUris)]);
10275
+ const isSuccess = resCodeArr.every((item) => {
10276
+ return item.code === RCRTCCode.SUCCESS;
10277
+ });
10278
+ return isSuccess ? { code: RCRTCCode.SUCCESS } : { code: RCRTCCode.SIGNAL_ERROR };
10279
+ });
10280
+ }
10281
+ /**
10282
+ * 扩散 cdn_uris 资源
10283
+ */
10284
+ _spreadCDNInfo(CDNUris) {
10285
+ return __awaiter(this, void 0, void 0, function* () {
10286
+ const code = yield this._context.setRTCCDNUris(this._roomId, RCRTCMessageType.TOTAL_CONTENT_RESOURCE, JSON.stringify([CDNUris]));
10287
+ if (code !== ErrorCode.SUCCESS) {
10288
+ logger.error(`spreadCDNInfo failed -> code: ${code}`);
10289
+ return { code: RCRTCCode.SIGNAL_ERROR };
10290
+ }
10291
+ logger.info('spreadCDNInfo succeed');
10292
+ return { code: RCRTCCode.SUCCESS };
10293
+ });
10294
+ }
10295
+ /**
10296
+ * 给房间设置 CDN 数据
10297
+ */
10298
+ _setRoomCDNInfo(CDNUris) {
10299
+ return __awaiter(this, void 0, void 0, function* () {
10300
+ const code = yield this._context.setRTCData(this._roomId, 'cdn_uris', JSON.stringify([CDNUris]), true, RTCApiType.ROOM);
10301
+ if (code !== ErrorCode.SUCCESS) {
10302
+ logger.error(`setRoomCDNInfo failed -> code: ${code}`);
10303
+ return { code: RCRTCCode.SIGNAL_ERROR };
10304
+ }
10305
+ logger.info('setRoomCDNInfo succeed');
10306
+ return { code: RCRTCCode.SUCCESS };
10307
+ });
10308
+ }
10309
+ /**
10310
+ * 资源变化时触发
10311
+ * 直播房间需单独处理 cdn_uris
10312
+ */
10313
+ _resourceHandle(content, messageType, userId) {
10314
+ const _super = Object.create(null, {
10315
+ _resourceHandle: { get: () => super._resourceHandle }
10316
+ });
10317
+ var _a;
10318
+ return __awaiter(this, void 0, void 0, function* () {
10319
+ _super._resourceHandle.call(this, content, messageType, userId);
10320
+ if (!content.cdn_uris) {
10321
+ return;
10322
+ }
10323
+ // 给业务层抛 CDN 状态
10324
+ if (((_a = this._CDNUris) === null || _a === void 0 ? void 0 : _a.enableInnerCDN) !== content.cdn_uris[0].enableInnerCDN) {
10325
+ this._callAppListener('onCDNEnableChange', !this.__getCDNEnable());
10326
+ }
10327
+ // 更新 _CDNUris
10328
+ this._CDNUris = content.cdn_uris[0];
10329
+ });
10330
+ }
10331
+ /**
10332
+ * 重写父类 _exchangeHandle 方法
10333
+ */
10334
+ _exchangeHandle(body) {
10335
+ var _a, _b, _c;
10336
+ return __awaiter(this, void 0, void 0, function* () {
10337
+ const res = yield this._service.exchange(this._getRTCReqestHeaders(), body);
10338
+ const pullUrl = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.urls) === null || _b === void 0 ? void 0 : _b.pull_url;
10339
+ if (res.code !== RCRTCCode.SUCCESS || !pullUrl) {
10340
+ return res;
10341
+ }
10342
+ /**
10343
+ * 自动模式下:
10344
+ * /exchange 完需根据 broadcast 字端判断是否扩散 cdn_uris 数据,设置房间 cdn_uris 数据
10345
+ */
10346
+ this._CDNUris = JSON.parse(pullUrl);
10347
+ if (((_c = this._CDNUris) === null || _c === void 0 ? void 0 : _c.broadcast) === RCInnerCDNBroadcast.SPREAD) {
10348
+ this._CDNEnable = true;
10349
+ this._sendCDNInfoSignal();
10350
+ }
10351
+ return res;
10352
+ });
10353
+ }
10354
+ /**
10355
+ * 观众切换为主播后直接处理人员变更及资源变更
10356
+ */
10357
+ _afterChangedRole(data) {
10358
+ const parseData = parseRoomData(data);
10359
+ const currentUserId = this._context.getCurrentId();
10360
+ const joinedAnchorList = Object.keys(parseData);
10361
+ // 观众升级主播成功后返回房间实例,才可注册房间事件,需异步抛出
10362
+ setTimeout(() => {
10363
+ var _a, _b, _c;
10364
+ // 通知业务层人员变更
10365
+ const needNoticeUserIds = joinedAnchorList.filter(id => {
10366
+ return id !== currentUserId;
10367
+ });
10368
+ needNoticeUserIds.length > 0 && this._callAppListener('onUserJoin', needNoticeUserIds);
10369
+ // 通知业务层资源变更
10370
+ for (const userId in parseData) {
10371
+ if (userId === currentUserId) {
10372
+ continue;
10373
+ }
10374
+ this._resourceHandle({
10375
+ uris: parseData[userId]
10376
+ }, RCRTCMessageType.TOTAL_CONTENT_RESOURCE, userId);
10377
+ }
10378
+ const CDNUris = (_a = data.roomInfo.filter((item) => { return item.key === 'cdn_uris'; })[0]) === null || _a === void 0 ? void 0 : _a.value;
10379
+ if (!CDNUris) {
10380
+ return;
10381
+ }
10382
+ if (((_b = this._CDNUris) === null || _b === void 0 ? void 0 : _b.push_mode) === RCInnerCDNPushMode.MANUAL) {
10383
+ this._callAppListener('onCDNEnableChange', (_c = this._CDNUris) === null || _c === void 0 ? void 0 : _c.enableInnerCDN);
10384
+ }
10385
+ });
10386
+ }
10387
+ /**
10388
+ * 返回 CDN 是否可用
10389
+ * @returns boolean
10390
+ */
10391
+ __getCDNEnable() {
10392
+ var _a;
10393
+ return (_a = this._CDNUris) === null || _a === void 0 ? void 0 : _a.enableInnerCDN;
10394
+ }
10395
+ /**
10396
+ * 返回 CDN 推送模式: 自动 or 手动
10397
+ * @returns boolean
10398
+ */
10399
+ __getCDNPushMode() {
10400
+ var _a;
10401
+ return (_a = this._CDNUris) === null || _a === void 0 ? void 0 : _a.push_mode;
10209
10402
  }
10210
10403
  }
10211
10404
 
@@ -10264,7 +10457,7 @@ const getCommonHeader = () => ({
10264
10457
  'Content-Type': 'application/json;charset=UTF-8',
10265
10458
  'Cache-Control': 'no-cache',
10266
10459
  ClientType: `web|${browserInfo.browser}|${browserInfo.version}`,
10267
- ClientVersion: "5.1.10-alpha.3",
10460
+ ClientVersion: "5.1.10-enterprise.2",
10268
10461
  'Client-Session-Id': getUUID(),
10269
10462
  'Request-Id': Date.now().toString()
10270
10463
  });
@@ -10432,7 +10625,25 @@ class RCMediaService {
10432
10625
  if (status === 200) {
10433
10626
  logger.debug(`request success -> Request-Id: ${commonHeader['Request-Id']}`);
10434
10627
  const data = JSON.parse(jsonStr);
10435
- return { code: data.resultCode };
10628
+ return { code: data.resultCode, res: data };
10629
+ }
10630
+ return { code: RCRTCCode.REQUEST_FAILED };
10631
+ });
10632
+ }
10633
+ /**
10634
+ * 房间内观众获取 CDN 资源信息、拉流地址
10635
+ */
10636
+ getCDNResourceInfo(headers, url) {
10637
+ return __awaiter(this, void 0, void 0, function* () {
10638
+ const commonHeader = getCommonHeader();
10639
+ const { status, data: resStr } = yield this._runtime.httpReq({
10640
+ url,
10641
+ headers: Object.assign(Object.assign({}, commonHeader), headers),
10642
+ method: HttpMethod.GET
10643
+ });
10644
+ if (status === 200) {
10645
+ const data = JSON.parse(resStr);
10646
+ return { code: data.resultCode, res: data };
10436
10647
  }
10437
10648
  logger.warn(`request failed -> Request-Id: ${commonHeader['Request-Id']}, status: ${status}, url: ${url}`);
10438
10649
  return { code: RCRTCCode.REQUEST_FAILED };
@@ -10543,9 +10754,7 @@ class RCAudienceClient {
10543
10754
  var _a;
10544
10755
  return __awaiter(this, void 0, void 0, function* () {
10545
10756
  const tracks = [];
10546
- if (isIllegalConnection(this._context.getNaviInfo())) {
10547
- return { code: RCRTCCode.PACKAGE_ENVIRONMENT_ERROR, tracks };
10548
- }
10757
+ if (isIllegalConnection(this._context.getNaviInfo())) ;
10549
10758
  // 客户端主动调用 api 发请求时,清除 ice 断线重连的定时器
10550
10759
  !this._fromRetry && ((_a = this._pc) === null || _a === void 0 ? void 0 : _a.clearReTryExchangeTimer());
10551
10760
  this._fromRetry = false;
@@ -10682,6 +10891,19 @@ class RCAudienceClient {
10682
10891
  }
10683
10892
  }
10684
10893
 
10894
+ var RCInnerCDNPullKind;
10895
+ (function (RCInnerCDNPullKind) {
10896
+ RCInnerCDNPullKind["RTMP"] = "rtmp";
10897
+ RCInnerCDNPullKind["FLV"] = "flv";
10898
+ RCInnerCDNPullKind["HLS"] = "hls";
10899
+ })(RCInnerCDNPullKind || (RCInnerCDNPullKind = {}));
10900
+
10901
+ var RCInnerCDNPullIsHttps;
10902
+ (function (RCInnerCDNPullIsHttps) {
10903
+ RCInnerCDNPullIsHttps[RCInnerCDNPullIsHttps["NOT_HTTPS"] = 0] = "NOT_HTTPS";
10904
+ RCInnerCDNPullIsHttps[RCInnerCDNPullIsHttps["HTTPS"] = 1] = "HTTPS";
10905
+ })(RCInnerCDNPullIsHttps || (RCInnerCDNPullIsHttps = {}));
10906
+
10685
10907
  const tinyConf = Object.assign(Object.assign({}, transResolution(RCResolution.W176_H144)), { frameRate: transFrameRate(RCFrameRate.FPS_15) });
10686
10908
  /**
10687
10909
  * 观众直播房间类
@@ -10690,12 +10912,12 @@ const tinyConf = Object.assign(Object.assign({}, transResolution(RCResolution.W1
10690
10912
  * 2、观众订阅、取消订阅资源
10691
10913
  */
10692
10914
  class RCAudienceLivingRoom {
10693
- constructor(_context, _runtime, _initOptions, _roomId, _token, _livingType) {
10915
+ constructor(_context, _runtime, _initOptions, _roomId, _joinResData, _livingType) {
10694
10916
  this._context = _context;
10695
10917
  this._runtime = _runtime;
10696
10918
  this._initOptions = _initOptions;
10697
10919
  this._roomId = _roomId;
10698
- this._token = _token;
10920
+ this._joinResData = _joinResData;
10699
10921
  this._livingType = _livingType;
10700
10922
  this._roomAnchorList = [];
10701
10923
  this._roomRes = {};
@@ -10740,14 +10962,18 @@ class RCAudienceLivingRoom {
10740
10962
  * * key RC_ANCHOR_LIST value: 为主播 ID 集合
10741
10963
  * * key RC_RES_`userId` value: 为主播发布的资源
10742
10964
  * * key RC_RTC_SESSIONID value: sessionId
10965
+ * * key RC_CDN value: CDN 资源数据
10743
10966
  */
10744
10967
  singalDataChange(singalData, roomId) {
10968
+ var _a;
10745
10969
  if (roomId !== this._roomId) {
10746
10970
  logger.warn(`singalDataChange -> not the current room data: data roomId: ${roomId}, current roomId: ${this._roomId}`);
10747
10971
  return;
10748
10972
  }
10749
10973
  logger.debug('singalDataChange -> singalData:', JSON.stringify(singalData || {}));
10750
10974
  const allMcuUris = [];
10975
+ const CDNUrisStr = (_a = singalData.filter((item) => { return item.key === 'RC_CDN'; })[0]) === null || _a === void 0 ? void 0 : _a.value;
10976
+ CDNUrisStr && this._diffCDNUris(JSON.parse(JSON.parse(CDNUrisStr).cdn_uris)[0]);
10751
10977
  singalData.forEach(data => {
10752
10978
  const { key, value, timestamp, uid } = data;
10753
10979
  const isResKey = key.indexOf('RC_RES_') !== -1;
@@ -11101,7 +11327,7 @@ class RCAudienceLivingRoom {
11101
11327
  return {
11102
11328
  'App-Key': this._context.getAppkey(),
11103
11329
  RoomId: userId,
11104
- Token: this._token,
11330
+ Token: this._joinResData.token,
11105
11331
  RoomType: RTCMode.LIVE,
11106
11332
  UserId: userId,
11107
11333
  'Session-Id': this._sessionId
@@ -11179,7 +11405,7 @@ class RCAudienceLivingRoom {
11179
11405
  if (result.code !== RCRTCCode.SUCCESS) {
11180
11406
  return { code: result.code };
11181
11407
  }
11182
- const { sdp: answer, resultCode, message } = result.data;
11408
+ const { sdp: answer, resultCode, message, subscribedList } = result.data;
11183
11409
  if (resultCode !== RCRTCCode.SUCCESS) {
11184
11410
  logger.error('change subscribe list failed:', message, resultCode);
11185
11411
  return { code: resultCode };
@@ -11198,16 +11424,145 @@ class RCAudienceLivingRoom {
11198
11424
  if (resCode !== RCRTCCode.SUCCESS) {
11199
11425
  return { code: resCode };
11200
11426
  }
11427
+ // 获取真正订阅成功的资源
11428
+ const subSuccessTrackIds = subscribedList === null || subscribedList === void 0 ? void 0 : subscribedList.map(item => `${item.msid}_${item.mediaType}`);
11429
+ const subSuccessList = attrs.filter(item => {
11430
+ if (item.track.isMCUTrack()) {
11431
+ const serverTrackInfo = this._roomRes[item.track.getTrackId()];
11432
+ const sdpResourceId = `${serverTrackInfo.msid}_${serverTrackInfo.mediaType}`;
11433
+ return subSuccessTrackIds.includes(sdpResourceId);
11434
+ }
11435
+ return subSuccessTrackIds === null || subSuccessTrackIds === void 0 ? void 0 : subSuccessTrackIds.includes(item.track.getTrackId());
11436
+ });
11437
+ const afterReplaceTrackIds = subSuccessList === null || subSuccessList === void 0 ? void 0 : subSuccessList.map(item => `${item.track.getTrackId()}`);
11438
+ const failedList = attrs.filter(item => !(afterReplaceTrackIds === null || afterReplaceTrackIds === void 0 ? void 0 : afterReplaceTrackIds.includes(item.track.getTrackId())));
11201
11439
  // 更新 remoteTrack.isSubscribed
11202
11440
  for (const trackId in this._remoteTracks) {
11203
- const subed = attrs.some(item => {
11441
+ const subed = subSuccessList.some(item => {
11204
11442
  return item.track.getTrackId() === trackId;
11205
11443
  });
11206
11444
  this._remoteTracks[trackId].__innerSetSubscribed(subed);
11207
11445
  }
11208
11446
  // 更新本地订阅关系
11209
- this._subscribedList.splice(0, this._subscribedList.length, ...attrs);
11210
- return { code: RCRTCCode.SUCCESS };
11447
+ this._subscribedList.splice(0, this._subscribedList.length, ...subSuccessList);
11448
+ return failedList.length ? { code: RCRTCCode.SUCCESS, failedList } : { code: RCRTCCode.SUCCESS };
11449
+ });
11450
+ }
11451
+ /**
11452
+ * 对比 cdn_uris 资源
11453
+ * @param newCDNUris 新的 cdn_uris 数据
11454
+ */
11455
+ _diffCDNUris(newCDNUris) {
11456
+ var _a, _b, _c, _d, _e, _f, _g, _h;
11457
+ return __awaiter(this, void 0, void 0, function* () {
11458
+ /**
11459
+ * CDN 资源减少: 上次 CDNUris 中有 url,变更后无 url
11460
+ */
11461
+ if (((_a = this._CDNUris) === null || _a === void 0 ? void 0 : _a.url) && !newCDNUris.url) {
11462
+ this._callAppListener('onCDNInfoDisable');
11463
+ /**
11464
+ * 更新内存中存储的 cdn_uris 数据
11465
+ */
11466
+ this._CDNUris = newCDNUris;
11467
+ return;
11468
+ }
11469
+ /**
11470
+ * CDN 资源新增条件:
11471
+ * 内存中无 CDNUris 或
11472
+ * 上次 CDNUris 无 url,变更后有 url
11473
+ */
11474
+ if (!this._CDNUris || (!((_b = this._CDNUris) === null || _b === void 0 ? void 0 : _b.url) && newCDNUris.url)) {
11475
+ this._callAppListener('onCDNInfoEnable', {
11476
+ resolution: `W${newCDNUris.w}_H${newCDNUris.h}`,
11477
+ fps: newCDNUris.fps
11478
+ });
11479
+ }
11480
+ /**
11481
+ * CDN 资源变更: w、h、fps 其中一项变化
11482
+ */
11483
+ const isWChange = (((_c = this._CDNUris) === null || _c === void 0 ? void 0 : _c.w) && newCDNUris.w && (((_d = this._CDNUris) === null || _d === void 0 ? void 0 : _d.w) !== newCDNUris.w));
11484
+ const isHChange = (((_e = this._CDNUris) === null || _e === void 0 ? void 0 : _e.h) && newCDNUris.h && (((_f = this._CDNUris) === null || _f === void 0 ? void 0 : _f.h) !== newCDNUris.h));
11485
+ const isFpsChange = (((_g = this._CDNUris) === null || _g === void 0 ? void 0 : _g.fps) && newCDNUris.fps && (((_h = this._CDNUris) === null || _h === void 0 ? void 0 : _h.fps) !== newCDNUris.fps));
11486
+ if (isWChange || isHChange || isFpsChange) {
11487
+ this._callAppListener('onCDNInfoChange', {
11488
+ resolution: `W${newCDNUris.w}_H${newCDNUris.h}`,
11489
+ fps: newCDNUris.fps
11490
+ });
11491
+ }
11492
+ /**
11493
+ * 更新内存中存储的 cdn_uris 数据
11494
+ */
11495
+ this._CDNUris = newCDNUris;
11496
+ });
11497
+ }
11498
+ /**
11499
+ * 获取 CDN 资源对应的拉流地址
11500
+ * 首次获取 CDNPlayUrl 时,需传入 url,
11501
+ * 业务层调用时使用内存中 _CDNUris 的 url,无 _CDNUris 时说明观众端未赋值过 _CDNUris
11502
+ * @returns CDNPlayUrl
11503
+ */
11504
+ _getCDNPlayUrl(params, url) {
11505
+ var _a, _b;
11506
+ return __awaiter(this, void 0, void 0, function* () {
11507
+ const { w, h, fps } = params;
11508
+ const kind = this._initOptions.pullInnerCDNProtocol || RCInnerCDNPullKind.FLV;
11509
+ const useHttps = (this._initOptions.pullInnerCDNUseHttps === RCInnerCDNPullIsHttps.NOT_HTTPS) ? RCInnerCDNPullIsHttps.NOT_HTTPS : RCInnerCDNPullIsHttps.HTTPS;
11510
+ /**
11511
+ * 加入房间后拉 KV 数据,数据还未返回时,同步拉 KV 获取 CDN 信息
11512
+ */
11513
+ if (!((_a = this._CDNUris) === null || _a === void 0 ? void 0 : _a.url) && !url) {
11514
+ logger.error(`cdn_uris url is empty, the anchor need to start CDN, code: ${RCRTCCode.CDN_RESOURCE_IS_EMPTY}`);
11515
+ return { code: RCRTCCode.CDN_RESOURCE_IS_EMPTY };
11516
+ }
11517
+ const headers = {
11518
+ 'App-Key': this._context.getAppkey(),
11519
+ Token: this._joinResData.token,
11520
+ RoomId: this.getRoomId(),
11521
+ UserId: this._context.getCurrentId(),
11522
+ SessionId: this.getSessionId()
11523
+ };
11524
+ const paramsArr = [];
11525
+ w && paramsArr.push(`w=${w}`);
11526
+ h && paramsArr.push(`h=${h}`);
11527
+ fps && paramsArr.push(`fps=${fps}`);
11528
+ paramsArr.push(`kind=${kind}`);
11529
+ paramsArr.push(`is_https=${useHttps}`);
11530
+ const paramsStr = paramsArr.join('&');
11531
+ let requestUrl = `${url || ((_b = this._CDNUris) === null || _b === void 0 ? void 0 : _b.url)}?`;
11532
+ paramsStr && (requestUrl += paramsStr);
11533
+ const { code, res } = yield this._service.getCDNResourceInfo(headers, requestUrl);
11534
+ if (code !== RCRTCCode.SUCCESS) {
11535
+ logger.error(`getCDNPlayUrl failed: ${code}`);
11536
+ return { code };
11537
+ }
11538
+ logger.info(`getCDNPlayUrl success: ${res === null || res === void 0 ? void 0 : res.data.pull_url}`);
11539
+ return {
11540
+ code,
11541
+ CDNPlayUrl: res === null || res === void 0 ? void 0 : res.data.pull_url
11542
+ };
11543
+ });
11544
+ }
11545
+ /**
11546
+ * 获取 CDN 资源对应的拉流地址
11547
+ * @returns CDNPlayUrl
11548
+ */
11549
+ getCDNPlayUrl(resolution, fps) {
11550
+ return __awaiter(this, void 0, void 0, function* () {
11551
+ if (resolution && !isValidResolution(resolution)) {
11552
+ logger.error('`resolution` is invalid');
11553
+ return { code: RCRTCCode.PARAMS_ERROR };
11554
+ }
11555
+ if (fps && !isValidFPS(fps)) {
11556
+ logger.error('`fps` is invalid');
11557
+ return { code: RCRTCCode.PARAMS_ERROR };
11558
+ }
11559
+ const { width, height } = resolution ? transResolution(resolution) : { width: null, height: null };
11560
+ const fpsNum = fps ? transFrameRate(fps) : null;
11561
+ const params = {};
11562
+ width && (params.w = width);
11563
+ height && (params.h = height);
11564
+ fpsNum && (params.fps = fpsNum);
11565
+ return this._getCDNPlayUrl(params);
11211
11566
  });
11212
11567
  }
11213
11568
  /**
@@ -11267,6 +11622,8 @@ class RCAudienceLivingRoom {
11267
11622
  this._pc.destroy();
11268
11623
  // 销毁 polarisReport 实例
11269
11624
  this._polarisReport = null;
11625
+ // 清空 onrtcdatachange 事件监听
11626
+ this._context.onrtcdatachange = () => { };
11270
11627
  });
11271
11628
  }
11272
11629
  /**
@@ -11308,7 +11665,12 @@ class RCAudienceLivingRoom {
11308
11665
  * @param tag 参数描述
11309
11666
  */
11310
11667
  registerRoomEventListener(listener) {
11668
+ var _a;
11311
11669
  this._appListener = listener;
11670
+ if (!listener) {
11671
+ return;
11672
+ }
11673
+ ((_a = this._joinResData.kvEntries) === null || _a === void 0 ? void 0 : _a.length) && this.singalDataChange(this._joinResData.kvEntries, this._roomId);
11312
11674
  }
11313
11675
  /**
11314
11676
  * 音量上报
@@ -11441,14 +11803,12 @@ class RCRTCClient {
11441
11803
  * 加入普通音视频房间
11442
11804
  * @param roomId
11443
11805
  */
11444
- joinRTCRoom(roomId, joinType) {
11445
- return push(() => this._joinRTCRoom(roomId, joinType));
11806
+ joinRTCRoom(roomId) {
11807
+ return push(() => this._joinRTCRoom(roomId));
11446
11808
  }
11447
- _joinRTCRoom(roomId, joinType) {
11809
+ _joinRTCRoom(roomId) {
11448
11810
  return __awaiter(this, void 0, void 0, function* () {
11449
- if (isIllegalConnection(this._context.getNaviInfo())) {
11450
- return { code: RCRTCCode.PACKAGE_ENVIRONMENT_ERROR };
11451
- }
11811
+ if (isIllegalConnection(this._context.getNaviInfo())) ;
11452
11812
  if (!validate('roomId', roomId, notEmptyString, true)) {
11453
11813
  return { code: RCRTCCode.PARAMS_ERROR };
11454
11814
  }
@@ -11462,12 +11822,11 @@ class RCRTCClient {
11462
11822
  if (!urls.length) {
11463
11823
  return { code: RCRTCCode.NOT_OPEN_VIDEO_AUDIO_SERVER };
11464
11824
  }
11465
- logger.debug(`joinRoom -> roomId: ${roomId}; joinType: ${joinType || RTCJoinType.KICK}`);
11466
- const { code, data } = yield this._context.joinRTCRoom(roomId, RTCMode.RTC, undefined, joinType);
11825
+ logger.debug(`joinRoom -> roomId: ${roomId}`);
11826
+ const { code, data } = yield this._context.joinRTCRoom(roomId, RTCMode.RTC);
11467
11827
  if (code !== ErrorCode.SUCCESS) {
11468
11828
  logger.error(`joinRoom failed -> code: ${code}`);
11469
- const errorCode = code === RTCSignalCode.JOIN_REFUSED ? RCRTCCode.SIGNAL_JOIN_RTC_ROOM_REFUSED : code;
11470
- return { code: errorCode };
11829
+ return { code: code };
11471
11830
  }
11472
11831
  logger.debug(`joinRoom success -> userId: ${this._context.getCurrentId()}, roomId: ${roomId}, data: ${JSON.stringify(data)}`);
11473
11832
  const room = new RCRTCRoom(this._context, this._runtime, roomId, data, this._service, this._options, this._releaseCrtRoomObj.bind(this));
@@ -11485,9 +11844,7 @@ class RCRTCClient {
11485
11844
  }
11486
11845
  _joinLivingRoom(roomId, livingType) {
11487
11846
  return __awaiter(this, void 0, void 0, function* () {
11488
- if (isIllegalConnection(this._context.getNaviInfo())) {
11489
- return { code: RCRTCCode.PACKAGE_ENVIRONMENT_ERROR };
11490
- }
11847
+ if (isIllegalConnection(this._context.getNaviInfo())) ;
11491
11848
  if (!(validate('roomId', roomId, notEmptyString, true) &&
11492
11849
  validate('livingType', livingType, (value) => value === RCLivingType.AUDIO || value === RCLivingType.VIDEO))) {
11493
11850
  return { code: RCRTCCode.PARAMS_ERROR };
@@ -11513,7 +11870,12 @@ class RCRTCClient {
11513
11870
  logger.debug(`JoinRoom success -> userId: ${this._context.getCurrentId()}, roomId: ${roomId}, data: ${JSON.stringify(data)}`);
11514
11871
  const room = new RCLivingRoom(this._context, this._runtime, roomId, data, this._service, this._options, this._releaseCrtRoomObj.bind(this), livingType, false);
11515
11872
  this._crtRoom = room;
11516
- return { room, code: RCRTCCode.SUCCESS, userIds: room.getRemoteUserIds(), tracks: room.getRemoteTracks() };
11873
+ const joinLivingResData = { room, code: RCRTCCode.SUCCESS, userIds: room.getRemoteUserIds(), tracks: room.getRemoteTracks() };
11874
+ // 手动模式时,用户加入房间,需返回 CDN 开关状态
11875
+ if (room.__getCDNPushMode() === RCInnerCDNPushMode.MANUAL) {
11876
+ Object.assign(joinLivingResData, { CDNEnable: room.__getCDNEnable() });
11877
+ }
11878
+ return joinLivingResData;
11517
11879
  });
11518
11880
  }
11519
11881
  /**
@@ -11864,9 +12226,7 @@ class RCRTCClient {
11864
12226
  */
11865
12227
  joinLivingRoomAsAudience(roomId, livingType) {
11866
12228
  return __awaiter(this, void 0, void 0, function* () {
11867
- if (isIllegalConnection(this._context.getNaviInfo())) {
11868
- return { code: RCRTCCode.PACKAGE_ENVIRONMENT_ERROR };
11869
- }
12229
+ if (isIllegalConnection(this._context.getNaviInfo())) ;
11870
12230
  if (!(validate('roomId', roomId, notEmptyString, true) &&
11871
12231
  validate('livingType', livingType, (value) => value === RCLivingType.AUDIO || value === RCLivingType.VIDEO))) {
11872
12232
  return { code: RCRTCCode.PARAMS_ERROR };
@@ -11884,7 +12244,8 @@ class RCRTCClient {
11884
12244
  logger.error('audienceJoinLivingRoomError:', code);
11885
12245
  return { code: RCRTCCode.SIGNAL_AUDIENCE_JOIN_ROOM_FAILED };
11886
12246
  }
11887
- const room = new RCAudienceLivingRoom(this._context, this._runtime, this._options, roomId, data.token, livingType);
12247
+ logger.info(`joinLivingRoomAsAudience success, room data: ${JSON.stringify(data)}`);
12248
+ const room = new RCAudienceLivingRoom(this._context, this._runtime, this._options, roomId, data, livingType);
11888
12249
  this._crtAudienceLivingRoom = room;
11889
12250
  return { room, code: RCRTCCode.SUCCESS };
11890
12251
  });
@@ -11955,8 +12316,8 @@ class RCRTCClient {
11955
12316
  logger.error('change room identity error', code);
11956
12317
  return { code: RCRTCCode.SIGNAL_ROOM_CHANGE_IDENTITY_FAILED };
11957
12318
  }
11958
- const { token } = data;
11959
- const crtRoom = new RCAudienceLivingRoom(this._context, this._runtime, this._options, room._roomId, token, room.getLivingType());
12319
+ logger.info(`downgradeToAudienceRoom success, room data: ${JSON.stringify(data)}`);
12320
+ const crtRoom = new RCAudienceLivingRoom(this._context, this._runtime, this._options, room._roomId, data, room.getLivingType());
11960
12321
  this._crtAudienceLivingRoom = crtRoom;
11961
12322
  // 主播房间内存数据清除及停止 Signal 房间心跳
11962
12323
  this._crtRoom.__destroy(false);
@@ -11965,38 +12326,8 @@ class RCRTCClient {
11965
12326
  return { room: crtRoom, code: RCRTCCode.SUCCESS };
11966
12327
  });
11967
12328
  }
11968
- /**
11969
- * 获取在房间内用户信息
11970
- * 当前仅能查自己
11971
- * @since version 5.1.5
11972
- */
11973
- getJoinedUserInfo(userId) {
11974
- return __awaiter(this, void 0, void 0, function* () {
11975
- if (!validate('userId', userId, notEmptyString, true)) {
11976
- return { code: RCRTCCode.PARAMS_ERROR };
11977
- }
11978
- const { code, data } = yield this._context.getRTCJoinedUserInfo(userId);
11979
- if (code !== ErrorCode.SUCCESS) {
11980
- logger.error('getJoinedUserInfo error', code);
11981
- return { code: RCRTCCode.SIGNAL_ROOM_CHANGE_IDENTITY_FAILED };
11982
- }
11983
- return { code: RCRTCCode.SUCCESS, data };
11984
- });
11985
- }
11986
12329
  }
11987
12330
 
11988
- var RCKickReason;
11989
- (function (RCKickReason) {
11990
- /**
11991
- * Server 主动踢(掉 Server API 踢出)
11992
- */
11993
- RCKickReason[RCKickReason["SERVER_KICK"] = 1] = "SERVER_KICK";
11994
- /**
11995
- * 其他设备登陆后,本端被踢
11996
- */
11997
- RCKickReason[RCKickReason["OTHER_KICK"] = 2] = "OTHER_KICK";
11998
- })(RCKickReason || (RCKickReason = {}));
11999
-
12000
12331
  /**
12001
12332
  * 获取 Microphone 列表
12002
12333
  */
@@ -12044,7 +12375,7 @@ const installer = {
12044
12375
  setup(context, runtime, options = {}) {
12045
12376
  logger.setLogLevel(options.logLevel);
12046
12377
  logger.setLogStdout(options.logStdout);
12047
- logger.warn(`RCRTC Version: ${"5.1.10-alpha.3"}, Commit: ${"799cc871ab8fce4eb595d368ebaa84664d101f6f"}`);
12378
+ logger.warn(`RCRTC Version: ${"5.1.10-enterprise.2"}, Commit: ${"5b9b0aef08a0933ff4adc82569d6903422b7a232"}`);
12048
12379
  logger.warn(`browserInfo.browser -> ${browserInfo.browser}`);
12049
12380
  logger.warn(`browserInfo.supportsUnifiedPlan -> ${browserInfo.supportsUnifiedPlan}`);
12050
12381
  logger.warn(`browserInfo.version -> ${browserInfo.version}`);
@@ -12080,4 +12411,4 @@ const helper = {
12080
12411
  ifSupportScreenShare
12081
12412
  };
12082
12413
 
12083
- export { BackgroundPictureFillMode, MixLayoutMode, MixVideoRenderMode, RCAbstractRoom, RCAudienceClient, RCAudienceLivingRoom, RCCameraVideoTrack, RCFrameRate, RCKickReason, RCLivingRoom, RCLivingType, RCLocalAudioTrack, RCLocalFileAudioTrack, RCLocalFileTrack, RCLocalFileVideoTrack, RCLocalTrack, RCLocalVideoTrack, RCMCUConfigBuilder, RCMediaType, RCMicphoneAudioTrack, RCRTCClient, RCRTCCode, RCRTCPingResult, RCRTCRoom, RCRemoteAudioTrack, RCRemoteTrack, RCRemoteVideoTrack, RCResolution, RCScreenVideoTrack, RCTag, RCTrack, device, helper, installer };
12414
+ export { BackgroundPictureFillMode, MixLayoutMode, MixVideoRenderMode, RCAbstractRoom, RCAudienceClient, RCAudienceLivingRoom, RCCameraVideoTrack, RCFrameRate, RCInnerCDNPullIsHttps, RCInnerCDNPullKind, RCLivingRoom, RCLivingType, RCLocalAudioTrack, RCLocalFileAudioTrack, RCLocalFileTrack, RCLocalFileVideoTrack, RCLocalTrack, RCLocalVideoTrack, RCMCUConfigBuilder, RCMediaType, RCMicphoneAudioTrack, RCRTCClient, RCRTCCode, RCRTCRoom, RCRemoteAudioTrack, RCRemoteTrack, RCRemoteVideoTrack, RCResolution, RCScreenVideoTrack, RCTag, RCTrack, device, helper, installer };