fcr-core 3.10.2 → 3.11.0-rc.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/lib/imports.d.ts +7 -1
- package/lib/imports.js +27 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +14 -2
- package/lib/room-control/helpers/constants.d.ts +8 -0
- package/lib/room-control/helpers/constants.js +8 -0
- package/lib/room-control/index.js +145 -1
- package/lib/room-control/infinity-room-control/index.js +3 -4
- package/lib/room-control/mainroom-control/index.js +3 -4
- package/lib/room-control/privilege-control/index.js +22 -3
- package/lib/room-control/privilege-control/type.d.ts +20 -0
- package/lib/room-control/privilege-control/type.js +11 -1
- package/lib/room-control/type.d.ts +44 -0
- package/lib/room-control/user-control/index.js +32 -0
- package/lib/room-control/user-control/type.d.ts +24 -0
- package/lib/room-control/whiteboard-control-v2/base/index.js +9 -12
- package/lib/room-control/whiteboard-control-v2/base/main-window.d.ts +6 -0
- package/lib/room-control/whiteboard-control-v2/base/main-window.js +13 -3
- package/lib/room-control/whiteboard-control-v2/type.d.ts +5 -0
- package/lib/service/api.d.ts +15 -1
- package/lib/service/api.js +48 -0
- package/lib/utilities/parameters.js +17 -4
- package/lib-es/imports.js +6 -0
- package/lib-es/index.js +4 -0
- package/lib-es/media-control/desktop.js +1 -0
- package/lib-es/room-control/helpers/constants.js +8 -0
- package/lib-es/room-control/index.js +146 -2
- package/lib-es/room-control/infinity-room-control/index.js +3 -4
- package/lib-es/room-control/mainroom-control/index.js +3 -4
- package/lib-es/room-control/privilege-control/index.js +23 -4
- package/lib-es/room-control/privilege-control/type.js +10 -0
- package/lib-es/room-control/user-control/index.js +32 -0
- package/lib-es/room-control/whiteboard-control-v2/base/index.js +9 -12
- package/lib-es/room-control/whiteboard-control-v2/base/main-window.js +13 -3
- package/lib-es/service/api.js +48 -0
- package/lib-es/utilities/parameters.js +17 -4
- package/package.json +10 -8
|
@@ -35,6 +35,7 @@ var _logger = require("../../utilities/logger");
|
|
|
35
35
|
var _error = require("../../utilities/error");
|
|
36
36
|
var _validateParams = _interopRequireDefault(require("../../utilities/validate-params"));
|
|
37
37
|
var _schema = require("../../schema");
|
|
38
|
+
var _constants = require("../helpers/constants");
|
|
38
39
|
let _initProto, _getUserDecs, _fetchUserListDecs, _updateUserNameDecs, _updateUserPropertiesDecs, _updateIncrementUserPropertiesDecs, _deleteUserPropertiesDecs, _getUserPropertiesByUserIdDecs, _getUserPropertiesByKeyPathDecs, _updateRemoteUserRoleDecs, _claimHostDecs, _kickOutDecs, _kickOutByUserIdsDecs, _kickOutByUserRolesDecs, _mergeAudioStreamDecs;
|
|
39
40
|
function _applyDecs(e, t, r, n, o, a) { function i(e, t, r) { return function (n, o) { return r && r(n), e[t].call(n, o); }; } function c(e, t) { for (var r = 0; r < e.length; r++) e[r].call(t); return t; } function s(e, t, r, n) { if ("function" != typeof e && (n || void 0 !== e)) throw new TypeError(t + " must " + (r || "be") + " a function" + (n ? "" : " or undefined")); return e; } function applyDec(e, t, r, n, o, a, c, u, l, f, p, d, h) { function m(e) { if (!h(e)) throw new TypeError("Attempted to access private element on non-instance"); } var y, v = t[0], g = t[3], b = !u; if (!b) { r || Array.isArray(v) || (v = [v]); var w = {}, S = [], A = 3 === o ? "get" : 4 === o || d ? "set" : "value"; f ? (p || d ? w = { get: _setFunctionName(function () { return g(this); }, n, "get"), set: function (e) { t[4](this, e); } } : w[A] = g, p || _setFunctionName(w[A], n, 2 === o ? "" : A)) : p || (w = Object.getOwnPropertyDescriptor(e, n)); } for (var P = e, j = v.length - 1; j >= 0; j -= r ? 2 : 1) { var D = v[j], E = r ? v[j - 1] : void 0, I = {}, O = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: n, metadata: a, addInitializer: function (e, t) { if (e.v) throw Error("attempted to call addInitializer after decoration was finished"); s(t, "An initializer", "be", !0), c.push(t); }.bind(null, I) }; try { if (b) (y = s(D.call(E, P, O), "class decorators", "return")) && (P = y);else { var k, F; O.static = l, O.private = f, f ? 2 === o ? k = function (e) { return m(e), w.value; } : (o < 4 && (k = i(w, "get", m)), 3 !== o && (F = i(w, "set", m))) : (k = function (e) { return e[n]; }, (o < 2 || 4 === o) && (F = function (e, t) { e[n] = t; })); var N = O.access = { has: f ? h.bind() : function (e) { return n in e; } }; if (k && (N.get = k), F && (N.set = F), P = D.call(E, d ? { get: w.get, set: w.set } : w[A], O), d) { if ("object" == typeof P && P) (y = s(P.get, "accessor.get")) && (w.get = y), (y = s(P.set, "accessor.set")) && (w.set = y), (y = s(P.init, "accessor.init")) && S.push(y);else if (void 0 !== P) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); } else s(P, (p ? "field" : "method") + " decorators", "return") && (p ? S.push(P) : w[A] = P); } } finally { I.v = !0; } } return (p || d) && u.push(function (e, t) { for (var r = S.length - 1; r >= 0; r--) t = S[r].call(e, t); return t; }), p || b || (f ? d ? u.push(i(w, "get"), i(w, "set")) : u.push(2 === o ? w[A] : i.call.bind(w[A])) : Object.defineProperty(e, n, w)), P; } function u(e, t) { return Object.defineProperty(e, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: !0, enumerable: !0, value: t }); } if (arguments.length >= 6) var l = a[Symbol.metadata || Symbol.for("Symbol.metadata")]; var f = Object.create(null == l ? null : l), p = function (e, t, r, n) { var o, a, i = [], s = function (t) { return _checkInRHS(t) === e; }, u = new Map(); function l(e) { e && i.push(c.bind(null, e)); } for (var f = 0; f < t.length; f++) { var p = t[f]; if (Array.isArray(p)) { var d = p[1], h = p[2], m = p.length > 3, y = 16 & d, v = !!(8 & d), g = 0 == (d &= 7), b = h + "/" + v; if (!g && !m) { var w = u.get(b); if (!0 === w || 3 === w && 4 !== d || 4 === w && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h); u.set(b, !(d > 2) || d); } applyDec(v ? e : e.prototype, p, y, m ? "#" + h : _toPropertyKey(h), d, n, v ? a = a || [] : o = o || [], i, v, m, g, 1 === d, v && m ? s : r); } } return l(o), l(a), i; }(e, t, o, f); return r.length || u(e, f), { e: p, get c() { var t = []; return r.length && [u(applyDec(e, [r], n, e.name, 5, f, t), f), c.bind(null, t, e)]; } }; }
|
|
40
41
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
@@ -172,6 +173,29 @@ class FcrUserControlImpl {
|
|
|
172
173
|
});
|
|
173
174
|
}
|
|
174
175
|
}
|
|
176
|
+
if (event.cause?.cmd === _constants.ROOM_MESSAGE_COMMANDS.CLIENT_RECORDING_PERMISSION) {
|
|
177
|
+
const {
|
|
178
|
+
changedProperties,
|
|
179
|
+
modifiedUser
|
|
180
|
+
} = event;
|
|
181
|
+
const enable = (0, _imports.get)(changedProperties, 'security.clientRecording');
|
|
182
|
+
if (Object.keys(changedProperties).length > 0) {
|
|
183
|
+
this._observable.notifyObservers('onUserClientRecordingPermissionUpdated', modifiedUser.userId, !!enable);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (event.cause?.cmd === _constants.ROOM_MESSAGE_COMMANDS.USER_WIDGET_PROPERTIES_UPDATE) {
|
|
187
|
+
const widgetCauseCmd = event.cause?.data?.widgetCause?.cmd;
|
|
188
|
+
if (widgetCauseCmd === _constants.ROOM_MESSAGE_COMMANDS.CLIENT_RECORDING_STATE) {
|
|
189
|
+
const {
|
|
190
|
+
changedProperties,
|
|
191
|
+
modifiedUser
|
|
192
|
+
} = event;
|
|
193
|
+
const enable = (0, _imports.get)(changedProperties, 'widgets.clientRecording.state');
|
|
194
|
+
if (Object.keys(changedProperties).length > 0) {
|
|
195
|
+
this._observable.notifyObservers('onUserClientRecordingStateUpdated', modifiedUser.userId, !!enable);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
175
199
|
},
|
|
176
200
|
onUserPropertiesDeleted: (roomId, event) => {
|
|
177
201
|
if (event.cause?.cmd === 8) {
|
|
@@ -262,6 +286,14 @@ class FcrUserControlImpl {
|
|
|
262
286
|
} = this.getLocalUser();
|
|
263
287
|
return (0, _imports.get)(this._scene.getUserPropertiesByUserId(userId), 'security.watermark.content');
|
|
264
288
|
}
|
|
289
|
+
getUserClientRecordingState(userId) {
|
|
290
|
+
const state = (0, _imports.get)(this._scene.getUserPropertiesByUserId(userId), 'widgets.clientRecording.state');
|
|
291
|
+
return Boolean(state);
|
|
292
|
+
}
|
|
293
|
+
getUserClientRecordingPermission(userId) {
|
|
294
|
+
const permission = (0, _imports.get)(this._scene.getUserPropertiesByUserId(userId), 'security.clientRecording');
|
|
295
|
+
return Boolean(permission);
|
|
296
|
+
}
|
|
265
297
|
async fetchUserList(params) {
|
|
266
298
|
return await this._scene.fetchUserList(params);
|
|
267
299
|
}
|
|
@@ -116,6 +116,18 @@ export interface FcrUserControl {
|
|
|
116
116
|
* Retrieve the watermark content of the current user
|
|
117
117
|
*/
|
|
118
118
|
getWaterMarkContent(): string | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Gets the client recording state of a specific user.
|
|
121
|
+
* @param userId The user ID to query
|
|
122
|
+
* @returns true if the user is currently doing client recording, false otherwise
|
|
123
|
+
*/
|
|
124
|
+
getUserClientRecordingState(userId: string): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Gets the client recording permission of a specific user.
|
|
127
|
+
* @param userId The user ID to query
|
|
128
|
+
* @returns true if the user has client recording permission, false otherwise
|
|
129
|
+
*/
|
|
130
|
+
getUserClientRecordingPermission(userId: string): boolean;
|
|
119
131
|
/**
|
|
120
132
|
* Releases the user control.
|
|
121
133
|
*/
|
|
@@ -188,6 +200,18 @@ export type FcrUserObserver = {
|
|
|
188
200
|
* @param event
|
|
189
201
|
*/
|
|
190
202
|
onLocalUserKickedOut?(roomId: string, event: FcrUserKickedOutEvent): void;
|
|
203
|
+
/**
|
|
204
|
+
* Callback to receive the user client recording permission updated event.
|
|
205
|
+
* @param userId
|
|
206
|
+
* @param enable
|
|
207
|
+
*/
|
|
208
|
+
onUserClientRecordingPermissionUpdated?(userId: string, enable: boolean): void;
|
|
209
|
+
/**
|
|
210
|
+
* Callback to receive the user client recording state updated event.
|
|
211
|
+
* @param userId
|
|
212
|
+
* @param enable - whether the user is client recording
|
|
213
|
+
*/
|
|
214
|
+
onUserClientRecordingStateUpdated?(userId: string, enable: boolean): void;
|
|
191
215
|
/**
|
|
192
216
|
* Callback to receive the user count updated by role event.
|
|
193
217
|
* @param roomId
|
|
@@ -177,8 +177,8 @@ class FcrBaseWhiteboardControlImpl {
|
|
|
177
177
|
boardAppId,
|
|
178
178
|
boardId,
|
|
179
179
|
boardRegion,
|
|
180
|
-
boardToken
|
|
181
|
-
|
|
180
|
+
boardToken,
|
|
181
|
+
boardPerformance = false
|
|
182
182
|
} = this.boardRoomConfig || {};
|
|
183
183
|
if (!boardAppId) {
|
|
184
184
|
throw (0, _error.generateFcrCoreClientError)(_imports.ErrorModuleCode.FCR_ROOM_WHITEBOARD, _imports.DetailErrorCode.UNDEFINED_ERROR, 'boardAppId is required');
|
|
@@ -250,8 +250,8 @@ class FcrBaseWhiteboardControlImpl {
|
|
|
250
250
|
region: endpoint ? 'private' : boardRegion,
|
|
251
251
|
appIdentifier: boardAppId
|
|
252
252
|
},
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
writable: isNeedLaunch,
|
|
254
|
+
endpoint
|
|
255
255
|
// verboseLog: true,
|
|
256
256
|
};
|
|
257
257
|
this.logger.info(`Room.joinRoom calling, params: ${(0, _imports.jsonstring)(joinRoomParams)}, timeout: ${WHITEBOARD_ROOM_JOIN_TIMEOUT}`);
|
|
@@ -297,14 +297,11 @@ class FcrBaseWhiteboardControlImpl {
|
|
|
297
297
|
this.whiteboard = whiteboard;
|
|
298
298
|
this.boardView = boardView;
|
|
299
299
|
this.boardRoom = boardRoom;
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
// boardView.setPerformanceMode(boardPerformance);
|
|
307
|
-
|
|
300
|
+
if (isNeedLaunch) {
|
|
301
|
+
// 所有人开启白板时都默认没有开启写权限, 需要写权限的地方需要自己手动开启
|
|
302
|
+
boardView.internalSetWritable(false);
|
|
303
|
+
}
|
|
304
|
+
boardView.setPerformanceMode(boardPerformance);
|
|
308
305
|
this.updateConnectionState(_type.FcrConnectionState.CONNECTED);
|
|
309
306
|
resolve(boardView);
|
|
310
307
|
if (this._waitPromiseResolve) {
|
|
@@ -28,6 +28,12 @@ export declare class FcrBoardMainWindowImpl implements FcrBoardMainWindow {
|
|
|
28
28
|
redo(): Promise<FcrReturnCode>;
|
|
29
29
|
clean(): Promise<FcrReturnCode>;
|
|
30
30
|
getSnapshotImage(): Promise<ImageData>;
|
|
31
|
+
/**
|
|
32
|
+
* 设置性能模式状态, enabled 为 true 时开启性能模式, 否则关闭性能模式
|
|
33
|
+
* 性能模式下, 白板会降低渲染质量及同步频率以提升性能, 适用于低性能设备或需要大量绘制元素的场景
|
|
34
|
+
* @param enable 是否开启性能模式
|
|
35
|
+
*/
|
|
36
|
+
setPerformanceMode(enable: boolean): FcrReturnCode;
|
|
31
37
|
setBackgroundColor(color: string): Promise<FcrReturnCode>;
|
|
32
38
|
getPageInfo(): FcrBoardPageInfo;
|
|
33
39
|
prevPage(): Promise<FcrReturnCode>;
|
|
@@ -33,7 +33,7 @@ var _decorator = require("agora-foundation/lib/decorator");
|
|
|
33
33
|
var _type = require("../../../type");
|
|
34
34
|
var _error = require("../../../utilities/error");
|
|
35
35
|
var _imports = require("../../../imports");
|
|
36
|
-
let _initProto, _setBackgroundColorDecs, _setToolTypeDecs, _setStrokeWidthDecs, _setStrokeColorDecs, _setTextColorDecs, _setTextSizeDecs, _insertImageDecs, _setContainerSizeRatioDecs, _setBoardTransparentDecs, _updateWindowSizeDecs, _setAutoCancelDrawDecs, _handleApplicationLaunchDecs, _handleApplicationTerminalDecs, _enableAutoCancelDecs;
|
|
36
|
+
let _initProto, _setPerformanceModeDecs, _setBackgroundColorDecs, _setToolTypeDecs, _setStrokeWidthDecs, _setStrokeColorDecs, _setTextColorDecs, _setTextSizeDecs, _insertImageDecs, _setContainerSizeRatioDecs, _setBoardTransparentDecs, _updateWindowSizeDecs, _setAutoCancelDrawDecs, _handleApplicationLaunchDecs, _handleApplicationTerminalDecs, _enableAutoCancelDecs;
|
|
37
37
|
function _applyDecs(e, t, r, n, o, a) { function i(e, t, r) { return function (n, o) { return r && r(n), e[t].call(n, o); }; } function c(e, t) { for (var r = 0; r < e.length; r++) e[r].call(t); return t; } function s(e, t, r, n) { if ("function" != typeof e && (n || void 0 !== e)) throw new TypeError(t + " must " + (r || "be") + " a function" + (n ? "" : " or undefined")); return e; } function applyDec(e, t, r, n, o, a, c, u, l, f, p, d, h) { function m(e) { if (!h(e)) throw new TypeError("Attempted to access private element on non-instance"); } var y, v = t[0], g = t[3], b = !u; if (!b) { r || Array.isArray(v) || (v = [v]); var w = {}, S = [], A = 3 === o ? "get" : 4 === o || d ? "set" : "value"; f ? (p || d ? w = { get: _setFunctionName(function () { return g(this); }, n, "get"), set: function (e) { t[4](this, e); } } : w[A] = g, p || _setFunctionName(w[A], n, 2 === o ? "" : A)) : p || (w = Object.getOwnPropertyDescriptor(e, n)); } for (var P = e, j = v.length - 1; j >= 0; j -= r ? 2 : 1) { var D = v[j], E = r ? v[j - 1] : void 0, I = {}, O = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: n, metadata: a, addInitializer: function (e, t) { if (e.v) throw Error("attempted to call addInitializer after decoration was finished"); s(t, "An initializer", "be", !0), c.push(t); }.bind(null, I) }; try { if (b) (y = s(D.call(E, P, O), "class decorators", "return")) && (P = y);else { var k, F; O.static = l, O.private = f, f ? 2 === o ? k = function (e) { return m(e), w.value; } : (o < 4 && (k = i(w, "get", m)), 3 !== o && (F = i(w, "set", m))) : (k = function (e) { return e[n]; }, (o < 2 || 4 === o) && (F = function (e, t) { e[n] = t; })); var N = O.access = { has: f ? h.bind() : function (e) { return n in e; } }; if (k && (N.get = k), F && (N.set = F), P = D.call(E, d ? { get: w.get, set: w.set } : w[A], O), d) { if ("object" == typeof P && P) (y = s(P.get, "accessor.get")) && (w.get = y), (y = s(P.set, "accessor.set")) && (w.set = y), (y = s(P.init, "accessor.init")) && S.push(y);else if (void 0 !== P) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); } else s(P, (p ? "field" : "method") + " decorators", "return") && (p ? S.push(P) : w[A] = P); } } finally { I.v = !0; } } return (p || d) && u.push(function (e, t) { for (var r = S.length - 1; r >= 0; r--) t = S[r].call(e, t); return t; }), p || b || (f ? d ? u.push(i(w, "get"), i(w, "set")) : u.push(2 === o ? w[A] : i.call.bind(w[A])) : Object.defineProperty(e, n, w)), P; } function u(e, t) { return Object.defineProperty(e, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: !0, enumerable: !0, value: t }); } if (arguments.length >= 6) var l = a[Symbol.metadata || Symbol.for("Symbol.metadata")]; var f = Object.create(null == l ? null : l), p = function (e, t, r, n) { var o, a, i = [], s = function (t) { return _checkInRHS(t) === e; }, u = new Map(); function l(e) { e && i.push(c.bind(null, e)); } for (var f = 0; f < t.length; f++) { var p = t[f]; if (Array.isArray(p)) { var d = p[1], h = p[2], m = p.length > 3, y = 16 & d, v = !!(8 & d), g = 0 == (d &= 7), b = h + "/" + v; if (!g && !m) { var w = u.get(b); if (!0 === w || 3 === w && 4 !== d || 4 === w && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h); u.set(b, !(d > 2) || d); } applyDec(v ? e : e.prototype, p, y, m ? "#" + h : _toPropertyKey(h), d, n, v ? a = a || [] : o = o || [], i, v, m, g, 1 === d, v && m ? s : r); } } return l(o), l(a), i; }(e, t, o, f); return r.length || u(e, f), { e: p, get c() { var t = []; return r.length && [u(applyDec(e, [r], n, e.name, 5, f, t), f), c.bind(null, t, e)]; } }; }
|
|
38
38
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
39
39
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
@@ -41,9 +41,9 @@ function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.descrip
|
|
|
41
41
|
function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
|
|
42
42
|
class FcrBoardMainWindowImpl {
|
|
43
43
|
static {
|
|
44
|
-
[_initProto] = _applyDecs(this, [[_log.trace, 2, "addPage"], [_log.trace, 2, "removePage"], [_log.trace, 2, "undo"], [_log.trace, 2, "redo"], [_log.trace, 2, "clean"], [_log.trace, 2, "getSnapshotImage"], [_setBackgroundColorDecs, 2, "setBackgroundColor"], [_log.trace, 2, "getPageInfo"], [_log.trace, 2, "prevPage"], [_log.trace, 2, "nextPage"], [_setToolTypeDecs, 2, "setToolType"], [_setStrokeWidthDecs, 2, "setStrokeWidth"], [_setStrokeColorDecs, 2, "setStrokeColor"], [_setTextColorDecs, 2, "setTextColor"], [_setTextSizeDecs, 2, "setTextSize"], [_insertImageDecs, 2, "insertImage"], [_log.trace, 2, "getContentView"], [_setContainerSizeRatioDecs, 2, "setContainerSizeRatio"], [_setBoardTransparentDecs, 2, "setBoardTransparent"], [_updateWindowSizeDecs, 2, "updateWindowSize"], [_setAutoCancelDrawDecs, 2, "setAutoCancelDraw"], [_log.trace, 2, "getWritable"], [_handleApplicationLaunchDecs, 2, "_handleApplicationLaunch"], [_handleApplicationTerminalDecs, 2, "_handleApplicationTerminal"], [_enableAutoCancelDecs, 2, "_enableAutoCancel"]], []).e;
|
|
44
|
+
[_initProto] = _applyDecs(this, [[_log.trace, 2, "addPage"], [_log.trace, 2, "removePage"], [_log.trace, 2, "undo"], [_log.trace, 2, "redo"], [_log.trace, 2, "clean"], [_log.trace, 2, "getSnapshotImage"], [_setPerformanceModeDecs, 2, "setPerformanceMode"], [_setBackgroundColorDecs, 2, "setBackgroundColor"], [_log.trace, 2, "getPageInfo"], [_log.trace, 2, "prevPage"], [_log.trace, 2, "nextPage"], [_setToolTypeDecs, 2, "setToolType"], [_setStrokeWidthDecs, 2, "setStrokeWidth"], [_setStrokeColorDecs, 2, "setStrokeColor"], [_setTextColorDecs, 2, "setTextColor"], [_setTextSizeDecs, 2, "setTextSize"], [_insertImageDecs, 2, "insertImage"], [_log.trace, 2, "getContentView"], [_setContainerSizeRatioDecs, 2, "setContainerSizeRatio"], [_setBoardTransparentDecs, 2, "setBoardTransparent"], [_updateWindowSizeDecs, 2, "updateWindowSize"], [_setAutoCancelDrawDecs, 2, "setAutoCancelDraw"], [_log.trace, 2, "getWritable"], [_handleApplicationLaunchDecs, 2, "_handleApplicationLaunch"], [_handleApplicationTerminalDecs, 2, "_handleApplicationTerminal"], [_enableAutoCancelDecs, 2, "_enableAutoCancel"]], []).e;
|
|
45
45
|
}
|
|
46
|
-
[(_setBackgroundColorDecs = [(0, _log.trace)(['color']), (0, _validateParams.default)(_schema.stringSchema)], _setToolTypeDecs = [(0, _log.trace)(['type']), (0, _validateParams.default)(_schema2.fcrBoardToolTypeSchema)], _setStrokeWidthDecs = [(0, _log.trace)(['strokeWidth']), (0, _validateParams.default)(_schema2.numberSchema)], _setStrokeColorDecs = [(0, _log.trace)(['color']), (0, _validateParams.default)(_schema2.z.union([_schema2.colorSchema, _schema.stringSchema]))], _setTextColorDecs = [(0, _log.trace)(['color']), (0, _validateParams.default)(_schema2.colorSchema)], _setTextSizeDecs = [(0, _log.trace)(['textSize']), (0, _validateParams.default)(_schema2.numberSchema)], _insertImageDecs = [(0, _log.trace)(['resourceUrl', 'x', 'y', 'width', 'height']), (0, _validateParams.default)(_schema.stringSchema, _schema2.numberSchema, _schema2.numberSchema, _schema2.numberSchema, _schema2.numberSchema)], _setContainerSizeRatioDecs = [(0, _log.trace)(['ratio']), (0, _validateParams.default)(_schema2.numberSchema)], _setBoardTransparentDecs = [(0, _log.trace)(['isTransparent']), (0, _validateParams.default)(_schema2.booleanSchema)], _updateWindowSizeDecs = [(0, _log.trace)(['size']), (0, _validateParams.default)(_schema2.fcrSizeSchema)], _setAutoCancelDrawDecs = [(0, _log.trace)(['enable']), (0, _validateParams.default)(_schema2.booleanSchema)], _handleApplicationLaunchDecs = [_decorator.bound, (0, _log.trace)(['appId', 'app'])], _handleApplicationTerminalDecs = [_decorator.bound, (0, _log.trace)(['appId', 'app'])], _enableAutoCancelDecs = (0, _log.trace)(['enable']), "logger")] = (_initProto(this), (0, _logger.createLogger)({
|
|
46
|
+
[(_setPerformanceModeDecs = (0, _log.trace)(['enable']), _setBackgroundColorDecs = [(0, _log.trace)(['color']), (0, _validateParams.default)(_schema.stringSchema)], _setToolTypeDecs = [(0, _log.trace)(['type']), (0, _validateParams.default)(_schema2.fcrBoardToolTypeSchema)], _setStrokeWidthDecs = [(0, _log.trace)(['strokeWidth']), (0, _validateParams.default)(_schema2.numberSchema)], _setStrokeColorDecs = [(0, _log.trace)(['color']), (0, _validateParams.default)(_schema2.z.union([_schema2.colorSchema, _schema.stringSchema]))], _setTextColorDecs = [(0, _log.trace)(['color']), (0, _validateParams.default)(_schema2.colorSchema)], _setTextSizeDecs = [(0, _log.trace)(['textSize']), (0, _validateParams.default)(_schema2.numberSchema)], _insertImageDecs = [(0, _log.trace)(['resourceUrl', 'x', 'y', 'width', 'height']), (0, _validateParams.default)(_schema.stringSchema, _schema2.numberSchema, _schema2.numberSchema, _schema2.numberSchema, _schema2.numberSchema)], _setContainerSizeRatioDecs = [(0, _log.trace)(['ratio']), (0, _validateParams.default)(_schema2.numberSchema)], _setBoardTransparentDecs = [(0, _log.trace)(['isTransparent']), (0, _validateParams.default)(_schema2.booleanSchema)], _updateWindowSizeDecs = [(0, _log.trace)(['size']), (0, _validateParams.default)(_schema2.fcrSizeSchema)], _setAutoCancelDrawDecs = [(0, _log.trace)(['enable']), (0, _validateParams.default)(_schema2.booleanSchema)], _handleApplicationLaunchDecs = [_decorator.bound, (0, _log.trace)(['appId', 'app'])], _handleApplicationTerminalDecs = [_decorator.bound, (0, _log.trace)(['appId', 'app'])], _enableAutoCancelDecs = (0, _log.trace)(['enable']), "logger")] = (_initProto(this), (0, _logger.createLogger)({
|
|
47
47
|
prefix: 'FcrBoardMainWindowImpl'
|
|
48
48
|
}));
|
|
49
49
|
_observable = new _observable.AgoraObservable();
|
|
@@ -143,6 +143,16 @@ class FcrBoardMainWindowImpl {
|
|
|
143
143
|
throw new Error('Whiteboard is not initialized');
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 设置性能模式状态, enabled 为 true 时开启性能模式, 否则关闭性能模式
|
|
149
|
+
* 性能模式下, 白板会降低渲染质量及同步频率以提升性能, 适用于低性能设备或需要大量绘制元素的场景
|
|
150
|
+
* @param enable 是否开启性能模式
|
|
151
|
+
*/
|
|
152
|
+
setPerformanceMode(enable) {
|
|
153
|
+
this._whiteboard.setPerformanceMode(enable);
|
|
154
|
+
return _type.FcrReturnCode.SUCCESS;
|
|
155
|
+
}
|
|
146
156
|
async setBackgroundColor(color) {
|
|
147
157
|
this._background = color;
|
|
148
158
|
this.logger.info(`set canvas background color: ${this._background}`);
|
|
@@ -110,6 +110,11 @@ export interface FcrBoardMainWindow {
|
|
|
110
110
|
* @param textSize
|
|
111
111
|
*/
|
|
112
112
|
setTextSize(textSize: number): Promise<number>;
|
|
113
|
+
/**
|
|
114
|
+
* Sets the performance mode of the whiteboard.
|
|
115
|
+
* @param enable Whether to enable performance mode.
|
|
116
|
+
*/
|
|
117
|
+
setPerformanceMode(enable: boolean): number;
|
|
113
118
|
/**
|
|
114
119
|
* Sets the background color of the whiteboard.
|
|
115
120
|
* @param color
|
package/lib/service/api.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { AgoraRestfulClient, AgoraRteEntryRoomResponse } from '../imports';
|
|
|
2
2
|
import { FcrCloudRecordingConfig, FcrGroupCreateConfig, FcrGroupUpdateOptions, FcrLiveStreamingLayoutType, FcrLiveStreamingConfig, FcrSharePermissionProps, FcrAllowWatermarkPayloadBody, FcrAnnotationProps, FcrLanguageConfig, FcrLanguage } from '../type';
|
|
3
3
|
import { AgoraRteRegion } from '../imports';
|
|
4
4
|
import { FcrCheckInParams, FcrChatRoomTokenResData } from './type';
|
|
5
|
-
import { FcrChatPrivilegeConfig, FcrPrivilegeUserRole, FcrPrivilegeUserRoleToStringMap, FcrSecuritySendChatPayload } from '../room-control/privilege-control/type';
|
|
5
|
+
import { FcrChatPrivilegeConfig, FcrPrivilegeUserRole, FcrPrivilegeUserRoleToStringMap, FcrSecuritySendChatPayload, FcrClientRecordingPermissionType } from '../room-control/privilege-control/type';
|
|
6
6
|
import { FcrUserKickedOutType } from '../room-control/user-control/type';
|
|
7
7
|
import { AgoraRteAudioSourceType, AgoraRteMediaPublishState, AgoraRteVideoSourceType } from '../imports';
|
|
8
8
|
import { FcrBoardRoomConfig } from '../room-control/whiteboard-control-v2/type';
|
|
@@ -65,6 +65,9 @@ export declare class FcrCoreServiceApi {
|
|
|
65
65
|
pauseCloudRecording(roomId: string): Promise<any>;
|
|
66
66
|
resumeCloudRecording(roomId: string): Promise<any>;
|
|
67
67
|
stopCloudRecording(roomId: string): Promise<any>;
|
|
68
|
+
startClientRecording(roomId: string, userId: string): Promise<any>;
|
|
69
|
+
resumeClientRecording(roomId: string, userId: string): Promise<any>;
|
|
70
|
+
stopClientRecording(roomId: string, userId: string): Promise<any>;
|
|
68
71
|
setCloudRecordingReady(roomId: string): Promise<any>;
|
|
69
72
|
/** room session */
|
|
70
73
|
updateRoomSession(params: {
|
|
@@ -201,6 +204,17 @@ export declare class FcrCoreServiceApi {
|
|
|
201
204
|
enable: boolean;
|
|
202
205
|
targetRoles: string[];
|
|
203
206
|
}): Promise<any>;
|
|
207
|
+
allowClientRecording({ roomId, enable, permissionType, targetRoles, }: {
|
|
208
|
+
roomId: string;
|
|
209
|
+
enable: number;
|
|
210
|
+
permissionType: FcrClientRecordingPermissionType;
|
|
211
|
+
targetRoles?: string[];
|
|
212
|
+
}): Promise<any>;
|
|
213
|
+
allowClientRecordingByUserId({ roomId, toUserUuids, enable, }: {
|
|
214
|
+
roomId: string;
|
|
215
|
+
toUserUuids: string[];
|
|
216
|
+
enable: boolean;
|
|
217
|
+
}): Promise<any>;
|
|
204
218
|
allowJoinWithPromptSound({ roomId, enable, targetRoles, }: {
|
|
205
219
|
roomId: string;
|
|
206
220
|
enable: boolean;
|
package/lib/service/api.js
CHANGED
|
@@ -256,6 +256,24 @@ class FcrCoreServiceApi {
|
|
|
256
256
|
method: 'PUT'
|
|
257
257
|
});
|
|
258
258
|
}
|
|
259
|
+
async startClientRecording(roomId, userId) {
|
|
260
|
+
return this._client.fetch({
|
|
261
|
+
path: `/v1/rooms/${roomId}/users/${userId}/widgets/clientRecording/1`,
|
|
262
|
+
method: 'PUT'
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
async resumeClientRecording(roomId, userId) {
|
|
266
|
+
return this._client.fetch({
|
|
267
|
+
path: `/v1/rooms/${roomId}/users/${userId}/widgets/clientRecording/resume`,
|
|
268
|
+
method: 'PUT'
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
async stopClientRecording(roomId, userId) {
|
|
272
|
+
return this._client.fetch({
|
|
273
|
+
path: `/v1/rooms/${roomId}/users/${userId}/widgets/clientRecording/0`,
|
|
274
|
+
method: 'PUT'
|
|
275
|
+
});
|
|
276
|
+
}
|
|
259
277
|
async setCloudRecordingReady(roomId) {
|
|
260
278
|
return this._client.fetch({
|
|
261
279
|
path: `/v1/rooms/${roomId}/records/ready`,
|
|
@@ -650,6 +668,36 @@ class FcrCoreServiceApi {
|
|
|
650
668
|
});
|
|
651
669
|
return res.data;
|
|
652
670
|
}
|
|
671
|
+
async allowClientRecording({
|
|
672
|
+
roomId,
|
|
673
|
+
enable,
|
|
674
|
+
permissionType,
|
|
675
|
+
targetRoles
|
|
676
|
+
}) {
|
|
677
|
+
const res = await this._client.fetch({
|
|
678
|
+
path: `/v1/rooms/${roomId}/security/clientRecording/${enable}`,
|
|
679
|
+
method: 'PUT',
|
|
680
|
+
data: {
|
|
681
|
+
targetRoles,
|
|
682
|
+
selectType: permissionType
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
return res.data;
|
|
686
|
+
}
|
|
687
|
+
async allowClientRecordingByUserId({
|
|
688
|
+
roomId,
|
|
689
|
+
toUserUuids,
|
|
690
|
+
enable
|
|
691
|
+
}) {
|
|
692
|
+
const res = await this._client.fetch({
|
|
693
|
+
path: `/v1/rooms/${roomId}/security/clientRecording/users/${enable ? 1 : 0}`,
|
|
694
|
+
method: 'PUT',
|
|
695
|
+
data: {
|
|
696
|
+
toUserUuids
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
return res.data;
|
|
700
|
+
}
|
|
653
701
|
async allowJoinWithPromptSound({
|
|
654
702
|
roomId,
|
|
655
703
|
enable,
|
|
@@ -33,16 +33,26 @@ const DEFAULT_LOG_FILE_SIZE = 512;
|
|
|
33
33
|
/** RTC preset parameters configuration mapping table */
|
|
34
34
|
const RTC_PRESET_PARAMS_MAP = {
|
|
35
35
|
[_imports.FcrApplicationPlatform.WINDOWS]: [{
|
|
36
|
-
'
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
'engine.video.hw_decoder_fallback_config': {
|
|
37
|
+
max_instances_thres: -1,
|
|
38
|
+
width_thres: 540,
|
|
39
|
+
height_thres: 540,
|
|
40
|
+
decode_time_delay_thres_broadcaster: -1,
|
|
41
|
+
decode_time_delay_thres_audience: -1
|
|
42
|
+
}
|
|
39
43
|
}],
|
|
40
44
|
[_imports.FcrApplicationPlatform.MACOS]: [{
|
|
41
45
|
'che.video.screenCaptureMode': 1
|
|
42
46
|
}, {
|
|
43
47
|
'che.video.screen_disable_frame_transparent_check': true
|
|
44
48
|
}, {
|
|
45
|
-
'
|
|
49
|
+
'engine.video.hw_decoder_fallback_config': {
|
|
50
|
+
max_instances_thres: -1,
|
|
51
|
+
width_thres: 540,
|
|
52
|
+
height_thres: 540,
|
|
53
|
+
decode_time_delay_thres_broadcaster: -1,
|
|
54
|
+
decode_time_delay_thres_audience: -1
|
|
55
|
+
}
|
|
46
56
|
}],
|
|
47
57
|
[_imports.FcrApplicationPlatform.WEB_DESKTOP]: [{
|
|
48
58
|
RESTRICTION_SET_PLAYBACK_DEVICE: false
|
|
@@ -101,6 +111,9 @@ const ELECTRON_COMMON_PARAMS = [
|
|
|
101
111
|
'rtc.video.videoFullrange': 1
|
|
102
112
|
}, {
|
|
103
113
|
'rtc.video.matrixCoefficients': 5
|
|
114
|
+
}, {
|
|
115
|
+
'rtc.stream_sub_remote_stats': false,
|
|
116
|
+
'rtc.stream_pub_local_stats': false
|
|
104
117
|
}];
|
|
105
118
|
|
|
106
119
|
/** ELECTRON platforms set */
|
package/lib-es/imports.js
CHANGED
|
@@ -35,6 +35,12 @@ export { Mutex } from 'agora-foundation/lib/worker/mutex';
|
|
|
35
35
|
|
|
36
36
|
// Agora RTE exports
|
|
37
37
|
|
|
38
|
+
export { AgoraRteRecorderState, AgoraRteRecorderReasonCode } from 'agora-rte-sdk';
|
|
39
|
+
|
|
40
|
+
// Fcr-prefixed re-exports for edu-core layer
|
|
41
|
+
|
|
42
|
+
export { AgoraRteRecorderState as FcrRecorderState } from 'agora-rte-sdk';
|
|
43
|
+
export { AgoraRteRecorderReasonCode as FcrRecorderReasonCode } from 'agora-rte-sdk';
|
|
38
44
|
export { AgoraRteError } from 'agora-rte-sdk/lib/core/utilities/error';
|
|
39
45
|
export { AgoraError as FcrError } from 'agora-foundation/lib/utilities/error/agora-error';
|
|
40
46
|
export { AgoraRteConnectionState, AgoraRteEngine, convertStreamTypeToPublishState, AgoraRteLatencyLevel, AgoraRteVideoOutputOrientationMode } from 'agora-rte-sdk';
|
package/lib-es/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
// types
|
|
2
2
|
|
|
3
|
+
// Re-export recording types with Fcr prefix
|
|
4
|
+
|
|
5
|
+
export { FcrRecorderState, FcrRecorderReasonCode } from './imports';
|
|
6
|
+
|
|
3
7
|
//enums
|
|
4
8
|
export { FcrStreamLatencyLevel, FcrPermissionAction, FcrPrivilegeUserRole, FcrUserRole, FcrStreamState, FcrRegion, FcrStreamType, FcrUserUpdatedReason, FcrRoomConnectorType, FcrVideoSourceType, FcrAudioSourceType, FcrMediaSourceState, FcrVideoRenderMode, FcrVideoStreamType, FcrCapability, FcrAiDenoiseLevel, FcrStreamPrivilegeOperation, FcrStreamPrivilegeVideoSourceType, FcrStreamPrivilegeAudioSourceType, FcrConnectionState, registerPlugin, FcrBoardToolType, FcrBoardShape, FcrVideoEncoderConfig, FcrDualVideoStreamConfig } from './type';
|
|
5
9
|
export { FcrCoreEngineImpl as FcrCoreEngine } from './engine';
|
|
@@ -28,6 +28,7 @@ import { FcrReturnCode } from '../type';
|
|
|
28
28
|
import { fcrCapabilitySchema, numberSchema, stringSchema } from '../schema';
|
|
29
29
|
import validateParams from '../utilities/validate-params';
|
|
30
30
|
import { createLogger, generateLogObserver } from '../utilities/logger';
|
|
31
|
+
|
|
31
32
|
/**
|
|
32
33
|
* @internal
|
|
33
34
|
*/
|
|
@@ -47,6 +47,14 @@ export const ROOM_MESSAGE_COMMANDS = {
|
|
|
47
47
|
LIVE_STREAMING_UPDATE: 700,
|
|
48
48
|
/** 用户被踢出命令 */
|
|
49
49
|
USER_KICK_OUT: 5,
|
|
50
|
+
/** 用户widget属性更新命令(widget属性变更的通用cause.cmd) */
|
|
51
|
+
USER_WIDGET_PROPERTIES_UPDATE: 10,
|
|
52
|
+
/** 客户端录制权限变更(角色级, cause.cmd=3260) */
|
|
53
|
+
CLIENT_RECORDING_PERMISSION: 3260,
|
|
54
|
+
/** 客户端录制状态变更 cause.data.widgetCause.cmd=3261 (通过widget属性下发) */
|
|
55
|
+
CLIENT_RECORDING_STATE: 3261,
|
|
56
|
+
/** 用户权限变更(用户级,含客户端录制) */
|
|
57
|
+
USER_PERMISSION_UPDATE: 3121,
|
|
50
58
|
/** 房间会话请求命令 */
|
|
51
59
|
ROOM_SESSION_REQUEST: 1001,
|
|
52
60
|
/** 房间会话接受命令 */
|
|
@@ -19,14 +19,16 @@ import "core-js/modules/es.array.includes.js";
|
|
|
19
19
|
import "core-js/modules/es.array.push.js";
|
|
20
20
|
import "core-js/modules/es.json.stringify.js";
|
|
21
21
|
import "core-js/modules/esnext.iterator.constructor.js";
|
|
22
|
+
import "core-js/modules/esnext.iterator.find.js";
|
|
22
23
|
import "core-js/modules/esnext.iterator.for-each.js";
|
|
24
|
+
import "core-js/modules/esnext.iterator.some.js";
|
|
23
25
|
function _applyDecs(e, t, r, n, o, a) { function i(e, t, r) { return function (n, o) { return r && r(n), e[t].call(n, o); }; } function c(e, t) { for (var r = 0; r < e.length; r++) e[r].call(t); return t; } function s(e, t, r, n) { if ("function" != typeof e && (n || void 0 !== e)) throw new TypeError(t + " must " + (r || "be") + " a function" + (n ? "" : " or undefined")); return e; } function applyDec(e, t, r, n, o, a, c, u, l, f, p, d, h) { function m(e) { if (!h(e)) throw new TypeError("Attempted to access private element on non-instance"); } var y, v = t[0], g = t[3], b = !u; if (!b) { r || Array.isArray(v) || (v = [v]); var w = {}, S = [], A = 3 === o ? "get" : 4 === o || d ? "set" : "value"; f ? (p || d ? w = { get: _setFunctionName(function () { return g(this); }, n, "get"), set: function (e) { t[4](this, e); } } : w[A] = g, p || _setFunctionName(w[A], n, 2 === o ? "" : A)) : p || (w = Object.getOwnPropertyDescriptor(e, n)); } for (var P = e, j = v.length - 1; j >= 0; j -= r ? 2 : 1) { var D = v[j], E = r ? v[j - 1] : void 0, I = {}, O = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: n, metadata: a, addInitializer: function (e, t) { if (e.v) throw Error("attempted to call addInitializer after decoration was finished"); s(t, "An initializer", "be", !0), c.push(t); }.bind(null, I) }; try { if (b) (y = s(D.call(E, P, O), "class decorators", "return")) && (P = y);else { var k, F; O.static = l, O.private = f, f ? 2 === o ? k = function (e) { return m(e), w.value; } : (o < 4 && (k = i(w, "get", m)), 3 !== o && (F = i(w, "set", m))) : (k = function (e) { return e[n]; }, (o < 2 || 4 === o) && (F = function (e, t) { e[n] = t; })); var N = O.access = { has: f ? h.bind() : function (e) { return n in e; } }; if (k && (N.get = k), F && (N.set = F), P = D.call(E, d ? { get: w.get, set: w.set } : w[A], O), d) { if ("object" == typeof P && P) (y = s(P.get, "accessor.get")) && (w.get = y), (y = s(P.set, "accessor.set")) && (w.set = y), (y = s(P.init, "accessor.init")) && S.push(y);else if (void 0 !== P) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); } else s(P, (p ? "field" : "method") + " decorators", "return") && (p ? S.push(P) : w[A] = P); } } finally { I.v = !0; } } return (p || d) && u.push(function (e, t) { for (var r = S.length - 1; r >= 0; r--) t = S[r].call(e, t); return t; }), p || b || (f ? d ? u.push(i(w, "get"), i(w, "set")) : u.push(2 === o ? w[A] : i.call.bind(w[A])) : Object.defineProperty(e, n, w)), P; } function u(e, t) { return Object.defineProperty(e, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: !0, enumerable: !0, value: t }); } if (arguments.length >= 6) var l = a[Symbol.metadata || Symbol.for("Symbol.metadata")]; var f = Object.create(null == l ? null : l), p = function (e, t, r, n) { var o, a, i = [], s = function (t) { return _checkInRHS(t) === e; }, u = new Map(); function l(e) { e && i.push(c.bind(null, e)); } for (var f = 0; f < t.length; f++) { var p = t[f]; if (Array.isArray(p)) { var d = p[1], h = p[2], m = p.length > 3, y = 16 & d, v = !!(8 & d), g = 0 == (d &= 7), b = h + "/" + v; if (!g && !m) { var w = u.get(b); if (!0 === w || 3 === w && 4 !== d || 4 === w && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h); u.set(b, !(d > 2) || d); } applyDec(v ? e : e.prototype, p, y, m ? "#" + h : _toPropertyKey(h), d, n, v ? a = a || [] : o = o || [], i, v, m, g, 1 === d, v && m ? s : r); } } return l(o), l(a), i; }(e, t, o, f); return r.length || u(e, f), { e: p, get c() { var t = []; return r.length && [u(applyDec(e, [r], n, e.name, 5, f, t), f), c.bind(null, t, e)]; } }; }
|
|
24
26
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
25
27
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
26
28
|
function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
|
|
27
29
|
function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
|
|
28
30
|
// Core SDK imports
|
|
29
|
-
import { AgoraObservable, AgoraRteExDataSyncType, jsonstring, to, trace } from '../imports';
|
|
31
|
+
import { AgoraObservable, AgoraRteExDataSyncType, AgoraRteVideoSourceType, jsonstring, to, trace } from '../imports';
|
|
30
32
|
|
|
31
33
|
// Service and API imports
|
|
32
34
|
|
|
@@ -71,7 +73,7 @@ import { FcrApplicationControlImpl } from './application-control';
|
|
|
71
73
|
*/
|
|
72
74
|
export class FcrBaseRoomControlImpl {
|
|
73
75
|
static {
|
|
74
|
-
[_initProto] = _applyDecs(this, [[trace, 2, "getSyncTimestamp"], [trace, 2, "getRoomInfo"], [trace, 2, "getRoomSchedule"], [trace, 2, "getLocalExDataSyncTypeList"], [_joinDecs, 2, "join"], [trace, 2, "leave"], [trace, 2, "release"], [trace, 2, "start"], [trace, 2, "end"], [trace, 2, "close"], [trace, 2, "getRoomState"], [trace, 2, "getRoomProperties"], [trace, 2, "getRoomPropertiesByKeyPath"], [_updateRoomPropertiesDecs, 2, "updateRoomProperties"], [_updateIncrementRoomPropertiesDecs, 2, "updateIncrementRoomProperties"], [_deleteRoomPropertiesDecs, 2, "deleteRoomProperties"], [_startCloudRecordingDecs, 2, "startCloudRecording"], [trace, 2, "pauseCloudRecording"], [trace, 2, "resumeCloudRecording"], [trace, 2, "stopCloudRecording"], [trace, 2, "getLiveStreamingState"], [trace, 2, "getLiveStreamingConfig"], [_startLiveStreamingDecs, 2, "startLiveStreaming"], [_updateLiveStreamingLayoutDecs, 2, "updateLiveStreamingLayout"], [trace, 2, "stopLiveStreaming"], [trace, 2, "getCloudRecordingState"], [_sendRoomMessageDecs, 2, "sendRoomMessage"]], []).e;
|
|
76
|
+
[_initProto] = _applyDecs(this, [[trace, 2, "getSyncTimestamp"], [trace, 2, "getRoomInfo"], [trace, 2, "getRoomSchedule"], [trace, 2, "getLocalExDataSyncTypeList"], [_joinDecs, 2, "join"], [trace, 2, "leave"], [trace, 2, "release"], [trace, 2, "start"], [trace, 2, "end"], [trace, 2, "close"], [trace, 2, "getRoomState"], [trace, 2, "getRoomProperties"], [trace, 2, "getRoomPropertiesByKeyPath"], [_updateRoomPropertiesDecs, 2, "updateRoomProperties"], [_updateIncrementRoomPropertiesDecs, 2, "updateIncrementRoomProperties"], [_deleteRoomPropertiesDecs, 2, "deleteRoomProperties"], [_startCloudRecordingDecs, 2, "startCloudRecording"], [trace, 2, "pauseCloudRecording"], [trace, 2, "resumeCloudRecording"], [trace, 2, "stopCloudRecording"], [trace, 2, "startClientRecording"], [trace, 2, "resumeClientRecording"], [trace, 2, "stopClientRecording"], [trace, 2, "getLiveStreamingState"], [trace, 2, "getLiveStreamingConfig"], [_startLiveStreamingDecs, 2, "startLiveStreaming"], [_updateLiveStreamingLayoutDecs, 2, "updateLiveStreamingLayout"], [trace, 2, "stopLiveStreaming"], [trace, 2, "hasActiveClientRecording"], [trace, 2, "getCloudRecordingState"], [_sendRoomMessageDecs, 2, "sendRoomMessage"]], []).e;
|
|
75
77
|
}
|
|
76
78
|
//@internal
|
|
77
79
|
[(_joinDecs = trace(['options']), _updateRoomPropertiesDecs = trace(['properties', 'cause']), _updateIncrementRoomPropertiesDecs = trace(['increments', 'cause']), _deleteRoomPropertiesDecs = trace(['properties', 'cause']), _startCloudRecordingDecs = trace(['config']), _startLiveStreamingDecs = trace(['data']), _updateLiveStreamingLayoutDecs = trace(['layoutType']), _sendRoomMessageDecs = trace(['payload', 'guaranteedDelivery']), "logger")] = (_initProto(this), createLogger({
|
|
@@ -81,6 +83,8 @@ export class FcrBaseRoomControlImpl {
|
|
|
81
83
|
_joinRoomSuccess = false;
|
|
82
84
|
_joining = false;
|
|
83
85
|
_joinState = ROOM_CONTROL_CONSTANTS.JOIN_STATE.CANCELED;
|
|
86
|
+
_isClientRecordingOwner = false;
|
|
87
|
+
_isStartingClientRecording = false;
|
|
84
88
|
constructor(_engine, _scene, _api, _config, _roomType, _chatConnection, _sharedCache, _chatRoomControl) {
|
|
85
89
|
this._engine = _engine;
|
|
86
90
|
this._scene = _scene;
|
|
@@ -229,8 +233,45 @@ export class FcrBaseRoomControlImpl {
|
|
|
229
233
|
this._joinState = ROOM_CONTROL_CONSTANTS.JOIN_STATE.CANCELED;
|
|
230
234
|
this._cleanup();
|
|
231
235
|
}
|
|
236
|
+
// Handle user-level local recording permission change (cmd=3121)
|
|
237
|
+
if (event.cause?.cmd === ROOM_MESSAGE_COMMANDS.USER_PERMISSION_UPDATE && event.modifiedUser.userId === this._scene.localUser.getLocalUserId()) {
|
|
238
|
+
const causeData = event.cause?.data;
|
|
239
|
+
if (causeData?.removePermissions?.includes('record:startClientRecording')) {
|
|
240
|
+
if (this.isLocalClientRecordingActive()) {
|
|
241
|
+
this.stopClientRecording().catch(e => {
|
|
242
|
+
this.logger.error(`auto-stop client recording failed: ${e.message}`);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// 初始化客户端录制观察者
|
|
251
|
+
this._clientRecordingObserver = {
|
|
252
|
+
onRecorderStateChanged: (_channelId, _uid, state, reason) => {
|
|
253
|
+
this.logger.info(`onRecorderStateChanged: state=${state}, reason=${reason}, sceneId=${this._scene.sceneId}`);
|
|
254
|
+
this._observable.notifyObservers('onClientRecordingStateChanged', this._scene.sceneId, state, reason);
|
|
232
255
|
}
|
|
233
256
|
};
|
|
257
|
+
|
|
258
|
+
// 客户端录制观察者由子类(FcrMainRoomControlImpl)注册,基类不注册
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 注册客户端录制观察者。由主房间子类在构造时调用。
|
|
263
|
+
*/
|
|
264
|
+
_registerClientRecordingObserver() {
|
|
265
|
+
this._engine.getMediaControl().addClientRecordingObserver(this._clientRecordingObserver);
|
|
266
|
+
this._isClientRecordingOwner = true;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* 移除客户端录制观察者。由 _cleanup 调用时需要判断是否已注册。
|
|
271
|
+
*/
|
|
272
|
+
_unregisterClientRecordingObserver() {
|
|
273
|
+
this._engine.getMediaControl().removeClientRecordingObserver(this._clientRecordingObserver);
|
|
274
|
+
this._isClientRecordingOwner = false;
|
|
234
275
|
}
|
|
235
276
|
|
|
236
277
|
/**
|
|
@@ -577,6 +618,89 @@ export class FcrBaseRoomControlImpl {
|
|
|
577
618
|
await handleRequestError(() => this._api.stopCloudRecording(this._scene.sceneId), ErrorModuleCode.FCR_ROOM, 'stop cloud recording failed');
|
|
578
619
|
return FcrReturnCode.SUCCESS;
|
|
579
620
|
}
|
|
621
|
+
async startClientRecording(config) {
|
|
622
|
+
// 防止并发调用
|
|
623
|
+
if (this._isStartingClientRecording) {
|
|
624
|
+
this.logger.warn('startClientRecording: already starting, ignoring duplicate call');
|
|
625
|
+
return FcrReturnCode.SUCCESS;
|
|
626
|
+
}
|
|
627
|
+
const localUserId = this._scene.localUser.getLocalUserId();
|
|
628
|
+
|
|
629
|
+
// 标记正在启动本地录制,避免在 API 调用后、SDK 录制开始前的时间窗口内触发错误的提示
|
|
630
|
+
this._isStartingClientRecording = true;
|
|
631
|
+
let serverRecordingStarted = false;
|
|
632
|
+
try {
|
|
633
|
+
await handleRequestError(() => this._api.startClientRecording(this._scene.sceneId, localUserId), ErrorModuleCode.FCR_ROOM, 'start client recording failed');
|
|
634
|
+
serverRecordingStarted = true;
|
|
635
|
+
|
|
636
|
+
// 使用 mediaControl 来启动本地录制
|
|
637
|
+
const mediaControl = this._engine.getMediaControl();
|
|
638
|
+
const isScreenShareActive = mediaControl.isScreenShareActive();
|
|
639
|
+
const currentScreenShareSourceId = mediaControl.getCurrentScreenShareSourceId();
|
|
640
|
+
|
|
641
|
+
// 获取本地用户的主流 streamId 作为录制 uid(streamId 是数字,userUuid 可能是十六进制字符串)
|
|
642
|
+
const localStreams = this._scene.getStreamsByUserId(localUserId);
|
|
643
|
+
const mainStream = localStreams.find(s => s.videoSourceType === AgoraRteVideoSourceType.CAMERA) || localStreams[0];
|
|
644
|
+
if (!mainStream) {
|
|
645
|
+
throw new Error(`No stream found for local user: ${localUserId}`);
|
|
646
|
+
}
|
|
647
|
+
const uid = Number(mainStream.streamId);
|
|
648
|
+
await mediaControl.startClientRecording(this._scene.sceneId, uid, config, isScreenShareActive, currentScreenShareSourceId);
|
|
649
|
+
return FcrReturnCode.SUCCESS;
|
|
650
|
+
} catch (e) {
|
|
651
|
+
// API 调用成功但 SDK 启动失败时,回滚服务端状态
|
|
652
|
+
if (serverRecordingStarted) {
|
|
653
|
+
this.logger.error(`startClientRecording SDK failed, rolling back server state: ${e.message}`);
|
|
654
|
+
this._api.stopClientRecording(this._scene.sceneId, localUserId).catch(rollbackErr => {
|
|
655
|
+
this.logger.error(`startClientRecording rollback failed: ${rollbackErr.message}`);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
throw e;
|
|
659
|
+
} finally {
|
|
660
|
+
this._isStartingClientRecording = false;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
async resumeClientRecording() {
|
|
664
|
+
const localUserId = this._scene.localUser.getLocalUserId();
|
|
665
|
+
await handleRequestError(() => this._api.resumeClientRecording(this._scene.sceneId, localUserId), ErrorModuleCode.FCR_ROOM, 'resume client recording failed');
|
|
666
|
+
return FcrReturnCode.SUCCESS;
|
|
667
|
+
}
|
|
668
|
+
async stopClientRecording() {
|
|
669
|
+
const localUserId = this._scene.localUser.getLocalUserId();
|
|
670
|
+
|
|
671
|
+
// Step 1: 使用 mediaControl 的 stopClientRecording(即使失败也继续通知服务端)
|
|
672
|
+
const mediaControl = this._engine.getMediaControl();
|
|
673
|
+
try {
|
|
674
|
+
await mediaControl.stopClientRecording();
|
|
675
|
+
} catch (e) {
|
|
676
|
+
this.logger.error(`mediaControl.stopClientRecording failed: ${e.message}`);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Step 2: 无论 SDK 停止是否成功,都通知服务器停止录制
|
|
680
|
+
await handleRequestError(() => this._api.stopClientRecording(this._scene.sceneId, localUserId), ErrorModuleCode.FCR_ROOM, 'stop client recording failed');
|
|
681
|
+
return FcrReturnCode.SUCCESS;
|
|
682
|
+
}
|
|
683
|
+
isLocalClientRecordingActive() {
|
|
684
|
+
// 如果正在启动本地录制,也返回 true,避免在启动过程中触发错误的"其他人开启录制"提示
|
|
685
|
+
const mediaControl = this._engine.getMediaControl();
|
|
686
|
+
return this._isStartingClientRecording || mediaControl.isClientRecordingActive();
|
|
687
|
+
}
|
|
688
|
+
isClientRecordingOwnsCapture() {
|
|
689
|
+
const mediaControl = this._engine.getMediaControl();
|
|
690
|
+
return mediaControl.isClientRecordingOwnsCapture();
|
|
691
|
+
}
|
|
692
|
+
async resumeClientRecordingOwnCapture() {
|
|
693
|
+
const mediaControl = this._engine.getMediaControl();
|
|
694
|
+
await mediaControl.resumeClientRecordingOwnCapture();
|
|
695
|
+
}
|
|
696
|
+
async waitForScreenCaptureStopped() {
|
|
697
|
+
const mediaControl = this._engine.getMediaControl();
|
|
698
|
+
await mediaControl.waitForScreenCaptureStopped();
|
|
699
|
+
}
|
|
700
|
+
releaseClientRecordingOwnCapture() {
|
|
701
|
+
const mediaControl = this._engine.getMediaControl();
|
|
702
|
+
mediaControl.releaseClientRecordingOwnCapture();
|
|
703
|
+
}
|
|
580
704
|
getLiveStreamingState() {
|
|
581
705
|
let liveStreamingState = this._scene.getScenePropertiesByKeyPath('live.state');
|
|
582
706
|
if (liveStreamingState === LIVE_STREAMING_STATE_VALUES.STARTED) {
|
|
@@ -616,6 +740,11 @@ export class FcrBaseRoomControlImpl {
|
|
|
616
740
|
await this._liveStreamingAction(() => this._api.stopLiveStreaming(this._scene.sceneId), 'stop live streaming failed');
|
|
617
741
|
return FcrReturnCode.SUCCESS;
|
|
618
742
|
}
|
|
743
|
+
hasActiveClientRecording() {
|
|
744
|
+
const userControl = this.getUserControl();
|
|
745
|
+
const users = userControl.getUserList();
|
|
746
|
+
return users.some(user => userControl.getUserClientRecordingState(user.userId));
|
|
747
|
+
}
|
|
619
748
|
getCloudRecordingState() {
|
|
620
749
|
const {
|
|
621
750
|
state,
|
|
@@ -644,6 +773,21 @@ export class FcrBaseRoomControlImpl {
|
|
|
644
773
|
async _cleanup() {
|
|
645
774
|
this._scene.removeObserver(this._sceneObserver);
|
|
646
775
|
this._engine.removeObserver(this._engineObserver);
|
|
776
|
+
|
|
777
|
+
// 只有注册过录制观察者的 room control 才拥有录制生命周期,
|
|
778
|
+
// 其他房间(如等候室)的 cleanup 不应停止共享 mediaControl 上的录制。
|
|
779
|
+
if (this._isClientRecordingOwner) {
|
|
780
|
+
this._unregisterClientRecordingObserver();
|
|
781
|
+
try {
|
|
782
|
+
const mediaControl = this._engine.getMediaControl();
|
|
783
|
+
if (mediaControl.isClientRecordingActive()) {
|
|
784
|
+
await mediaControl.stopClientRecording();
|
|
785
|
+
this.logger.info('_cleanup: stopped client recording');
|
|
786
|
+
}
|
|
787
|
+
} catch (e) {
|
|
788
|
+
this.logger.error(`_cleanup: failed to stop client recording: ${e.message}`);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
647
791
|
this._sharedCache.getRoomCache(this._scene.sceneId).clear();
|
|
648
792
|
try {
|
|
649
793
|
return await Promise.all([this._chatRoomControl?.leave(), this.sharingControl?.getBoardControl().close(), this.sharingControl?.getAnnotationControl().close(), this._scene.leave()]);
|