@xmaxai/web-sdk 1.0.6 → 1.0.7
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/README.md +2 -290
- package/dist/{chunk-PLFWPS5A.js → chunk-4O5BSMUX.js} +251 -18
- package/dist/chunk-4O5BSMUX.js.map +1 -0
- package/dist/{chunk-NWNRFTLE.cjs → chunk-EKOYOFES.cjs} +484 -251
- package/dist/chunk-EKOYOFES.cjs.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +1 -1
- package/dist/react/index.cjs +3 -3
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-NWNRFTLE.cjs.map +0 -1
- package/dist/chunk-PLFWPS5A.js.map +0 -1
|
@@ -205,7 +205,7 @@ var XmaxError = class _XmaxError extends Error {
|
|
|
205
205
|
};
|
|
206
206
|
|
|
207
207
|
// src/Foundation/Runtime/RuntimeInfo.ts
|
|
208
|
-
var XMAX_SDK_VERSION = "1.0.
|
|
208
|
+
var XMAX_SDK_VERSION = "1.0.7";
|
|
209
209
|
var _RuntimeInfo = class _RuntimeInfo {
|
|
210
210
|
/**
|
|
211
211
|
* 序列化为接口传输使用的 snake_case 字段。
|
|
@@ -1365,6 +1365,178 @@ ${JSON.stringify({
|
|
|
1365
1365
|
}
|
|
1366
1366
|
};
|
|
1367
1367
|
|
|
1368
|
+
// src/Foundation/Media/Camera/CameraRotation.ts
|
|
1369
|
+
function validateCameraRotation(rotation) {
|
|
1370
|
+
if (![0, 90, 180, 270].includes(rotation)) {
|
|
1371
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera rotation must be 0, 90, 180 or 270");
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// src/Foundation/Media/Camera/CameraRotationProcessor.ts
|
|
1376
|
+
var CameraRotationProcessor = class {
|
|
1377
|
+
constructor(options) {
|
|
1378
|
+
__publicField(this, "options", options);
|
|
1379
|
+
__publicField(this, "video", document.createElement("video"));
|
|
1380
|
+
__publicField(this, "canvas", document.createElement("canvas"));
|
|
1381
|
+
__publicField(this, "context");
|
|
1382
|
+
__publicField(this, "stream");
|
|
1383
|
+
__publicField(this, "source");
|
|
1384
|
+
__publicField(this, "frameCallback");
|
|
1385
|
+
__publicField(this, "timer");
|
|
1386
|
+
__publicField(this, "cancelPending");
|
|
1387
|
+
__publicField(this, "stopped", false);
|
|
1388
|
+
__publicField(this, "version", 0);
|
|
1389
|
+
__publicField(this, "sourceEnded", () => {
|
|
1390
|
+
this.fail(new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera source ended during rotation"));
|
|
1391
|
+
});
|
|
1392
|
+
this.canvas.width = options.width;
|
|
1393
|
+
this.canvas.height = options.height;
|
|
1394
|
+
const context = this.canvas.getContext("2d", { alpha: false });
|
|
1395
|
+
if (!context || typeof this.canvas.captureStream !== "function") {
|
|
1396
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Canvas camera rotation is not supported by this browser");
|
|
1397
|
+
}
|
|
1398
|
+
this.context = context;
|
|
1399
|
+
this.video.muted = true;
|
|
1400
|
+
this.video.autoplay = true;
|
|
1401
|
+
this.video.playsInline = true;
|
|
1402
|
+
}
|
|
1403
|
+
/** 等待第一帧实际绘制成功;换摄像头时复用输出轨,不重建 sender。 */
|
|
1404
|
+
async setSource(source) {
|
|
1405
|
+
if (this.stopped) throw new XmaxError("CANCELLED" /* cancelled */, "Camera rotation has stopped");
|
|
1406
|
+
if (source.readyState === "ended") {
|
|
1407
|
+
this.stop();
|
|
1408
|
+
throw new XmaxError("MEDIA_ERROR" /* mediaError */, "Camera rotation requires a live source");
|
|
1409
|
+
}
|
|
1410
|
+
this.cancelPending?.();
|
|
1411
|
+
this.cancelFrame();
|
|
1412
|
+
this.source?.removeEventListener("ended", this.sourceEnded);
|
|
1413
|
+
const version = ++this.version;
|
|
1414
|
+
this.source = source;
|
|
1415
|
+
source.addEventListener("ended", this.sourceEnded);
|
|
1416
|
+
this.video.srcObject = new MediaStream([source]);
|
|
1417
|
+
try {
|
|
1418
|
+
await new Promise((resolve, reject) => {
|
|
1419
|
+
let settled = false;
|
|
1420
|
+
const finish = (error) => {
|
|
1421
|
+
if (settled) return;
|
|
1422
|
+
settled = true;
|
|
1423
|
+
clearTimeout(timeout);
|
|
1424
|
+
this.cancelPending = void 0;
|
|
1425
|
+
if (error) reject(error);
|
|
1426
|
+
else resolve();
|
|
1427
|
+
};
|
|
1428
|
+
const timeout = setTimeout(() => finish(new XmaxError("TIMEOUT" /* timeout */, "Timed out waiting for a camera rotation frame")), 1e4);
|
|
1429
|
+
this.cancelPending = () => finish(new XmaxError("CANCELLED" /* cancelled */, "Camera rotation source changed"));
|
|
1430
|
+
void this.video.play().then(() => {
|
|
1431
|
+
if (settled || this.stopped || version !== this.version) return;
|
|
1432
|
+
const firstFrame = () => {
|
|
1433
|
+
if (settled || this.stopped || version !== this.version) return;
|
|
1434
|
+
try {
|
|
1435
|
+
if (!this.draw()) {
|
|
1436
|
+
this.schedule(firstFrame);
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
this.stream ?? (this.stream = this.canvas.captureStream(this.options.frameRate));
|
|
1440
|
+
if (!this.stream.getVideoTracks()[0]) throw new Error("Canvas did not produce a video track");
|
|
1441
|
+
this.requestFrame();
|
|
1442
|
+
finish();
|
|
1443
|
+
this.schedule(() => this.render(version));
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
finish(error);
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
this.schedule(firstFrame);
|
|
1449
|
+
}, finish);
|
|
1450
|
+
});
|
|
1451
|
+
if (this.stopped || version !== this.version) {
|
|
1452
|
+
throw new XmaxError("CANCELLED" /* cancelled */, "Camera rotation source changed");
|
|
1453
|
+
}
|
|
1454
|
+
return this.stream.getVideoTracks()[0];
|
|
1455
|
+
} catch (error) {
|
|
1456
|
+
if (version === this.version) this.stop();
|
|
1457
|
+
throw XmaxError.from(error);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
/** 换设备前解除旧原始轨监听,保留 Canvas 最后一帧及输出轨。 */
|
|
1461
|
+
pauseSource() {
|
|
1462
|
+
++this.version;
|
|
1463
|
+
this.cancelPending?.();
|
|
1464
|
+
this.cancelFrame();
|
|
1465
|
+
this.source?.removeEventListener("ended", this.sourceEnded);
|
|
1466
|
+
this.source = void 0;
|
|
1467
|
+
this.video.pause();
|
|
1468
|
+
this.video.srcObject = null;
|
|
1469
|
+
}
|
|
1470
|
+
stop() {
|
|
1471
|
+
if (this.stopped) return;
|
|
1472
|
+
this.stopped = true;
|
|
1473
|
+
++this.version;
|
|
1474
|
+
this.cancelPending?.();
|
|
1475
|
+
this.cancelFrame();
|
|
1476
|
+
this.source?.removeEventListener("ended", this.sourceEnded);
|
|
1477
|
+
this.source = void 0;
|
|
1478
|
+
this.video.pause();
|
|
1479
|
+
this.video.srcObject = null;
|
|
1480
|
+
this.stream?.getTracks().forEach((track) => track.stop());
|
|
1481
|
+
this.stream = void 0;
|
|
1482
|
+
this.canvas.width = this.canvas.height = 0;
|
|
1483
|
+
}
|
|
1484
|
+
draw() {
|
|
1485
|
+
const { videoWidth: width, videoHeight: height } = this.video;
|
|
1486
|
+
if (this.video.readyState < 2 || !width || !height) return false;
|
|
1487
|
+
const { width: outWidth, height: outHeight, rotation } = this.options;
|
|
1488
|
+
const quarterTurn = rotation === 90 || rotation === 270;
|
|
1489
|
+
const targetWidth = quarterTurn ? outHeight : outWidth;
|
|
1490
|
+
const targetHeight = quarterTurn ? outWidth : outHeight;
|
|
1491
|
+
const scale = Math.max(targetWidth / width, targetHeight / height);
|
|
1492
|
+
const cropWidth = targetWidth / scale, cropHeight = targetHeight / scale;
|
|
1493
|
+
this.context.setTransform(1, 0, 0, 1, outWidth / 2, outHeight / 2);
|
|
1494
|
+
this.context.rotate(rotation * Math.PI / 180);
|
|
1495
|
+
this.context.drawImage(
|
|
1496
|
+
this.video,
|
|
1497
|
+
(width - cropWidth) / 2,
|
|
1498
|
+
(height - cropHeight) / 2,
|
|
1499
|
+
cropWidth,
|
|
1500
|
+
cropHeight,
|
|
1501
|
+
-targetWidth / 2,
|
|
1502
|
+
-targetHeight / 2,
|
|
1503
|
+
targetWidth,
|
|
1504
|
+
targetHeight
|
|
1505
|
+
);
|
|
1506
|
+
return true;
|
|
1507
|
+
}
|
|
1508
|
+
render(version) {
|
|
1509
|
+
if (this.stopped || version !== this.version) return;
|
|
1510
|
+
try {
|
|
1511
|
+
if (this.draw()) this.requestFrame();
|
|
1512
|
+
this.schedule(() => this.render(version));
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
this.fail(XmaxError.from(error));
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
requestFrame() {
|
|
1518
|
+
const track = this.stream?.getVideoTracks()[0];
|
|
1519
|
+
track?.requestFrame?.();
|
|
1520
|
+
}
|
|
1521
|
+
schedule(callback) {
|
|
1522
|
+
if (typeof this.video.requestVideoFrameCallback === "function") {
|
|
1523
|
+
this.frameCallback = this.video.requestVideoFrameCallback(callback);
|
|
1524
|
+
} else {
|
|
1525
|
+
this.timer = setTimeout(callback, 1e3 / this.options.frameRate);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
cancelFrame() {
|
|
1529
|
+
if (this.frameCallback !== void 0) this.video.cancelVideoFrameCallback(this.frameCallback);
|
|
1530
|
+
clearTimeout(this.timer);
|
|
1531
|
+
this.frameCallback = void 0;
|
|
1532
|
+
this.timer = void 0;
|
|
1533
|
+
}
|
|
1534
|
+
fail(error) {
|
|
1535
|
+
this.stop();
|
|
1536
|
+
this.options.onError(error);
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
|
|
1368
1540
|
// src/Foundation/RTC/Agora/AgoraRtcManager.ts
|
|
1369
1541
|
var _AgoraRtcManager = class _AgoraRtcManager {
|
|
1370
1542
|
/**
|
|
@@ -1381,6 +1553,9 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1381
1553
|
__publicField(this, "initialization");
|
|
1382
1554
|
__publicField(this, "lifecycle", 0);
|
|
1383
1555
|
__publicField(this, "camera");
|
|
1556
|
+
__publicField(this, "cameraSource");
|
|
1557
|
+
__publicField(this, "cameraRotation");
|
|
1558
|
+
__publicField(this, "captureVersion", 0);
|
|
1384
1559
|
__publicField(this, "microphone");
|
|
1385
1560
|
__publicField(this, "externalVideo");
|
|
1386
1561
|
__publicField(this, "externalAudio");
|
|
@@ -1474,8 +1649,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1474
1649
|
this.clearRoom();
|
|
1475
1650
|
this.client = void 0;
|
|
1476
1651
|
client?.removeAllListeners();
|
|
1477
|
-
this.
|
|
1478
|
-
this.camera?.close();
|
|
1652
|
+
this.releaseCameraCapture();
|
|
1479
1653
|
this.microphone?.close();
|
|
1480
1654
|
this.externalVideo?.close();
|
|
1481
1655
|
this.externalAudio?.close();
|
|
@@ -1499,19 +1673,41 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1499
1673
|
*/
|
|
1500
1674
|
async startCameraCapture(options) {
|
|
1501
1675
|
const client = this.requireClient();
|
|
1502
|
-
if (this.camera || this.externalVideo) {
|
|
1676
|
+
if (this.camera || this.cameraSource || this.externalVideo) {
|
|
1503
1677
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "A local video source is already active");
|
|
1504
1678
|
}
|
|
1679
|
+
const rotation = options.rotation ?? 0;
|
|
1680
|
+
validateCameraRotation(rotation);
|
|
1681
|
+
const version = ++this.captureVersion;
|
|
1682
|
+
let source;
|
|
1505
1683
|
try {
|
|
1506
|
-
const captureSize = rtcOrientedVideoSize(options);
|
|
1507
|
-
|
|
1684
|
+
const captureSize = rtcOrientedVideoSize(rotation === 90 || rotation === 270 ? { width: options.height, height: options.width } : options);
|
|
1685
|
+
source = await this.sdk.createCameraVideoTrack({
|
|
1508
1686
|
facingMode: options.position === "front" /* front */ ? "user" : "environment",
|
|
1509
1687
|
encoderConfig: { width: captureSize.width, height: captureSize.height, frameRate: options.frameRate }
|
|
1510
1688
|
});
|
|
1511
|
-
if (this.client !== client) {
|
|
1512
|
-
|
|
1689
|
+
if (this.client !== client || version !== this.captureVersion) {
|
|
1690
|
+
source.close();
|
|
1513
1691
|
throw this.cancelled();
|
|
1514
1692
|
}
|
|
1693
|
+
this.cameraSource = source;
|
|
1694
|
+
let camera = source;
|
|
1695
|
+
if (rotation !== 0) {
|
|
1696
|
+
const processor = new CameraRotationProcessor({
|
|
1697
|
+
...options,
|
|
1698
|
+
rotation,
|
|
1699
|
+
onError: (error) => this.listener?.onError?.(error)
|
|
1700
|
+
});
|
|
1701
|
+
this.cameraRotation = processor;
|
|
1702
|
+
const output = await processor.setSource(source.getMediaStreamTrack());
|
|
1703
|
+
if (this.client !== client || version !== this.captureVersion) throw this.cancelled();
|
|
1704
|
+
camera = this.sdk.createCustomVideoTrack({
|
|
1705
|
+
mediaStreamTrack: output,
|
|
1706
|
+
width: options.width,
|
|
1707
|
+
height: options.height,
|
|
1708
|
+
frameRate: options.frameRate
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1515
1711
|
this.camera = camera;
|
|
1516
1712
|
this.cameraTransceiverListener = () => {
|
|
1517
1713
|
if (this.client === client && client.localTracks.includes(camera) && this.videoPublishRequested && !this.rejoinTask) {
|
|
@@ -1525,6 +1721,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1525
1721
|
camera.on("transceiver-updated", this.cameraTransceiverListener);
|
|
1526
1722
|
return camera.getMediaStreamTrack();
|
|
1527
1723
|
} catch (error) {
|
|
1724
|
+
if (version === this.captureVersion) this.releaseCameraCapture();
|
|
1528
1725
|
throw this.mapError(error, "CAMERA_PERMISSION_DENIED" /* cameraPermissionDenied */);
|
|
1529
1726
|
}
|
|
1530
1727
|
}
|
|
@@ -1532,9 +1729,24 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1532
1729
|
* 切换声网相机设备并返回切换后的原生轨道。
|
|
1533
1730
|
*/
|
|
1534
1731
|
async switchCameraCapture(to) {
|
|
1535
|
-
const
|
|
1536
|
-
|
|
1537
|
-
|
|
1732
|
+
const source = this.requireCamera();
|
|
1733
|
+
const camera = this.camera;
|
|
1734
|
+
this.cameraRotation?.pauseSource();
|
|
1735
|
+
try {
|
|
1736
|
+
await this.run(() => source.setDevice({ facingMode: to === "front" /* front */ ? "user" : "environment" }));
|
|
1737
|
+
} catch (error) {
|
|
1738
|
+
if (this.camera === camera && this.cameraRotation) {
|
|
1739
|
+
await this.cameraRotation.setSource(source.getMediaStreamTrack()).catch((restoreError) => {
|
|
1740
|
+
this.listener?.onError?.(XmaxError.from(restoreError));
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
throw error;
|
|
1744
|
+
}
|
|
1745
|
+
if (this.camera !== camera || this.cameraSource !== source) throw this.cancelled();
|
|
1746
|
+
if (this.cameraRotation) {
|
|
1747
|
+
await this.cameraRotation.setSource(source.getMediaStreamTrack());
|
|
1748
|
+
if (this.camera !== camera) throw this.cancelled();
|
|
1749
|
+
}
|
|
1538
1750
|
if (this.videoPublishRequested) await this.restoreCameraSender(camera);
|
|
1539
1751
|
return camera.getMediaStreamTrack();
|
|
1540
1752
|
}
|
|
@@ -1542,17 +1754,25 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1542
1754
|
* 停止采集并释放摄像头。
|
|
1543
1755
|
*/
|
|
1544
1756
|
async stopCameraCapture() {
|
|
1757
|
+
this.releaseCameraCapture();
|
|
1758
|
+
}
|
|
1759
|
+
releaseCameraCapture() {
|
|
1760
|
+
++this.captureVersion;
|
|
1545
1761
|
const camera = this.camera;
|
|
1546
1762
|
this.releaseCameraSender();
|
|
1547
1763
|
this.camera = void 0;
|
|
1548
1764
|
camera?.close();
|
|
1765
|
+
this.cameraRotation?.stop();
|
|
1766
|
+
this.cameraRotation = void 0;
|
|
1767
|
+
if (this.cameraSource !== camera) this.cameraSource?.close();
|
|
1768
|
+
this.cameraSource = void 0;
|
|
1549
1769
|
}
|
|
1550
1770
|
/**
|
|
1551
1771
|
* 将外部原生轨包装为 Agora 本地轨,不申请设备权限;失败时释放本次克隆。
|
|
1552
1772
|
*/
|
|
1553
1773
|
async setExternalMediaTracks(tracks) {
|
|
1554
1774
|
this.requireClient();
|
|
1555
|
-
if (this.camera || this.microphone || this.externalVideo) {
|
|
1775
|
+
if (this.camera || this.cameraSource || this.microphone || this.externalVideo) {
|
|
1556
1776
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Release the current local media before attaching external tracks");
|
|
1557
1777
|
}
|
|
1558
1778
|
if (tracks.videoTrack.kind !== "video" || tracks.videoTrack.readyState !== "live" || tracks.audioTrack && (tracks.audioTrack.kind !== "audio" || tracks.audioTrack.readyState !== "live")) {
|
|
@@ -1592,7 +1812,7 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1592
1812
|
};
|
|
1593
1813
|
ensureActive2();
|
|
1594
1814
|
if (this.videoPublishRequested) {
|
|
1595
|
-
await AgoraVideoSender.apply(camera,
|
|
1815
|
+
await AgoraVideoSender.apply(camera, this.cameraEncodingConfiguration(config), ensureActive2);
|
|
1596
1816
|
}
|
|
1597
1817
|
this.cameraSenderConfiguration = { ...config };
|
|
1598
1818
|
}));
|
|
@@ -1630,9 +1850,12 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
1630
1850
|
};
|
|
1631
1851
|
ensureActive2();
|
|
1632
1852
|
const config = this.cameraSenderConfiguration;
|
|
1633
|
-
if (config) await AgoraVideoSender.apply(camera,
|
|
1853
|
+
if (config) await AgoraVideoSender.apply(camera, this.cameraEncodingConfiguration(config), ensureActive2);
|
|
1634
1854
|
});
|
|
1635
1855
|
}
|
|
1856
|
+
cameraEncodingConfiguration(config) {
|
|
1857
|
+
return this.cameraRotation ? config : { ...config, ...rtcOrientedVideoSize(config) };
|
|
1858
|
+
}
|
|
1636
1859
|
releaseCameraSender() {
|
|
1637
1860
|
if (this.cameraTransceiverListener) this.camera?.off("transceiver-updated", this.cameraTransceiverListener);
|
|
1638
1861
|
this.cameraTransceiverListener = void 0;
|
|
@@ -2069,8 +2292,8 @@ var _AgoraRtcManager = class _AgoraRtcManager {
|
|
|
2069
2292
|
* 获取已启动的相机采集。
|
|
2070
2293
|
*/
|
|
2071
2294
|
requireCamera() {
|
|
2072
|
-
if (!this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
|
|
2073
|
-
return this.
|
|
2295
|
+
if (!this.cameraSource || !this.camera) throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera capture is not running");
|
|
2296
|
+
return this.cameraSource;
|
|
2074
2297
|
}
|
|
2075
2298
|
/**
|
|
2076
2299
|
* 获取当前可编码、发布的视频轨,不要求来源为摄像头。
|
|
@@ -2509,6 +2732,9 @@ var TrtcRtcManager = class {
|
|
|
2509
2732
|
* @throws 引擎未初始化、已在采集、设备不可用或权限被拒绝时抛出错误。
|
|
2510
2733
|
*/
|
|
2511
2734
|
async startCameraCapture(options) {
|
|
2735
|
+
if (options.rotation !== void 0 && options.rotation !== 0) {
|
|
2736
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera rotation currently requires Agora");
|
|
2737
|
+
}
|
|
2512
2738
|
const engine = this.requireEngine();
|
|
2513
2739
|
if (this.isCapturing || this.externalVideo) {
|
|
2514
2740
|
throw new XmaxError(
|
|
@@ -3155,6 +3381,9 @@ var VeRtcManager = class {
|
|
|
3155
3381
|
}
|
|
3156
3382
|
}
|
|
3157
3383
|
async startCameraCapture(options) {
|
|
3384
|
+
if (options.rotation !== void 0 && options.rotation !== 0) {
|
|
3385
|
+
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Camera rotation currently requires Agora");
|
|
3386
|
+
}
|
|
3158
3387
|
const engine = this.requireEngine();
|
|
3159
3388
|
if (this.camera || this.externalVideo) {
|
|
3160
3389
|
throw new XmaxError("INVALID_CONFIGURATION" /* invalidConfiguration */, "Local video is already prepared");
|
|
@@ -3991,6 +4220,7 @@ var _CameraController = class _CameraController {
|
|
|
3991
4220
|
*
|
|
3992
4221
|
* @param options.videoFormat 期望的输出尺寸、帧率和编码配置;尺寸按模型规则调整。
|
|
3993
4222
|
* @param options.position 首次启动时使用的摄像头位置。
|
|
4223
|
+
* @param options.rotation 输入帧顺时针旋转角度,默认 0;videoFormat 为旋转后的规格,目前仅 Agora 支持非零角度。
|
|
3994
4224
|
* @param options.useMicrophone 是否申请麦克风权限并允许实时连接时启动音频采集。
|
|
3995
4225
|
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
3996
4226
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
@@ -4003,6 +4233,7 @@ var _CameraController = class _CameraController {
|
|
|
4003
4233
|
"Stop the current local camera stream before creating another one"
|
|
4004
4234
|
);
|
|
4005
4235
|
}
|
|
4236
|
+
validateCameraRotation(options.rotation ?? 0);
|
|
4006
4237
|
const resolvedFormat = this.resolveVideoFormat(options.videoFormat);
|
|
4007
4238
|
const track = new RealtimeVideoTrack({
|
|
4008
4239
|
id: _CameraController.localVideoTrackID,
|
|
@@ -4025,7 +4256,8 @@ var _CameraController = class _CameraController {
|
|
|
4025
4256
|
width: resolvedFormat.width,
|
|
4026
4257
|
height: resolvedFormat.height,
|
|
4027
4258
|
frameRate: resolvedFormat.fps,
|
|
4028
|
-
position: options.position
|
|
4259
|
+
position: options.position,
|
|
4260
|
+
...options.rotation !== void 0 ? { rotation: options.rotation } : {}
|
|
4029
4261
|
});
|
|
4030
4262
|
track.mediaStreamTrack = mediaTrack;
|
|
4031
4263
|
this.previewStream = new MediaStream([mediaTrack]);
|
|
@@ -8292,6 +8524,7 @@ var XmaxRealtimeManager = class _XmaxRealtimeManager {
|
|
|
8292
8524
|
* 将返回的轨道绑定到预览视图;收到有效帧且视图已绑定后进入 `ready`。
|
|
8293
8525
|
*
|
|
8294
8526
|
* @param options.enableFrameValidation 是否在发布前等待相机预热(固定 200ms),默认 true;false 跳过等待。
|
|
8527
|
+
* @param options.rotation 输入帧顺时针旋转角度,默认 0;videoFormat 为旋转后的规格,目前仅 Agora 支持非零角度。
|
|
8295
8528
|
* @returns 包含本地相机视频轨道的媒体流。
|
|
8296
8529
|
* @throws 模型不支持相机输入、配置无效、权限或采集启动失败时抛出错误。
|
|
8297
8530
|
*/
|
|
@@ -12467,4 +12700,4 @@ export {
|
|
|
12467
12700
|
XmaxVideoView,
|
|
12468
12701
|
XmaxRealtimeVideoView
|
|
12469
12702
|
};
|
|
12470
|
-
//# sourceMappingURL=chunk-
|
|
12703
|
+
//# sourceMappingURL=chunk-4O5BSMUX.js.map
|