@microblink/camera-manager 7.2.0 → 7.2.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.
Files changed (60) hide show
  1. package/dist/camera-manager.js +202 -72
  2. package/dist/camera-manager.js.map +1 -1
  3. package/package.json +1 -1
  4. package/types/core/Camera.d.ts +73 -0
  5. package/types/core/Camera.d.ts.map +1 -1
  6. package/types/core/CameraManager.d.ts +87 -7
  7. package/types/core/CameraManager.d.ts.map +1 -1
  8. package/types/core/VideoFrameProcessor.d.ts +28 -6
  9. package/types/core/VideoFrameProcessor.d.ts.map +1 -1
  10. package/types/core/cameraManagerStore.d.ts +9 -2
  11. package/types/core/cameraManagerStore.d.ts.map +1 -1
  12. package/types/core/cameraNames.d.ts +21 -5
  13. package/types/core/cameraNames.d.ts.map +1 -1
  14. package/types/core/cameraUtils.d.ts +57 -9
  15. package/types/core/cameraUtils.d.ts.map +1 -1
  16. package/types/core/cameraUtils.test.d.ts +5 -0
  17. package/types/core/cameraUtils.test.d.ts.map +1 -0
  18. package/types/core/iosCameraNames.d.ts +3 -0
  19. package/types/core/iosCameraNames.d.ts.map +1 -1
  20. package/types/core/utils.d.ts +18 -0
  21. package/types/core/utils.d.ts.map +1 -1
  22. package/types/index.d.ts +9 -0
  23. package/types/index.d.ts.map +1 -1
  24. package/types/index.rollup.d.ts +252 -18
  25. package/types/media-mock/MediaMocker.d.ts +67 -0
  26. package/types/media-mock/MediaMocker.d.ts.map +1 -1
  27. package/types/media-mock/createInputDeviceInfo.d.ts +9 -0
  28. package/types/media-mock/createInputDeviceInfo.d.ts.map +1 -1
  29. package/types/media-mock/defineProperty.d.ts +6 -3
  30. package/types/media-mock/defineProperty.d.ts.map +1 -1
  31. package/types/media-mock/fake-devices.d.ts +6 -0
  32. package/types/media-mock/fake-devices.d.ts.map +1 -1
  33. package/types/media-mock/fakeDevices/DesktopSingleFrontFacing.d.ts +6 -0
  34. package/types/media-mock/fakeDevices/DesktopSingleFrontFacing.d.ts.map +1 -0
  35. package/types/ui/CameraErrorModal.d.ts +3 -0
  36. package/types/ui/CameraErrorModal.d.ts.map +1 -1
  37. package/types/ui/CameraSelector.d.ts +3 -0
  38. package/types/ui/CameraSelector.d.ts.map +1 -1
  39. package/types/ui/CameraUiStoreContext.d.ts +11 -0
  40. package/types/ui/CameraUiStoreContext.d.ts.map +1 -1
  41. package/types/ui/CaptureScreen.d.ts +12 -0
  42. package/types/ui/CaptureScreen.d.ts.map +1 -1
  43. package/types/ui/Header.d.ts +3 -0
  44. package/types/ui/Header.d.ts.map +1 -1
  45. package/types/ui/LocalizationContext.d.ts +12 -0
  46. package/types/ui/LocalizationContext.d.ts.map +1 -1
  47. package/types/ui/RootComponent.d.ts +3 -0
  48. package/types/ui/RootComponent.d.ts.map +1 -1
  49. package/types/ui/SolidShadowRoot.d.ts +16 -3
  50. package/types/ui/SolidShadowRoot.d.ts.map +1 -1
  51. package/types/ui/createCameraManagerUi.d.ts +26 -2
  52. package/types/ui/createCameraManagerUi.d.ts.map +1 -1
  53. package/types/ui/determineFitMode.d.ts +7 -6
  54. package/types/ui/determineFitMode.d.ts.map +1 -1
  55. package/types/ui/getVisibleVideoArea.d.ts +7 -1
  56. package/types/ui/getVisibleVideoArea.d.ts.map +1 -1
  57. package/types/ui/locales/en.d.ts +3 -0
  58. package/types/ui/locales/en.d.ts.map +1 -1
  59. package/types/ui/zustandRefStore.d.ts +12 -0
  60. package/types/ui/zustandRefStore.d.ts.map +1 -1
@@ -538,6 +538,13 @@ const asError = (thrown) => {
538
538
  };
539
539
  class CameraError extends Error {
540
540
  code;
541
+ /**
542
+ * Creates a new camera error.
543
+ *
544
+ * @param message - The error message.
545
+ * @param code - The error code.
546
+ * @param cause - The cause of the error.
547
+ */
541
548
  constructor(message, code, cause) {
542
549
  super(message);
543
550
  this.code = code;
@@ -600,12 +607,40 @@ const createConstraints = (resolution, facing, id) => {
600
607
  };
601
608
  return constraints;
602
609
  };
610
+ function scoreCameraCapabilities(camera) {
611
+ let score = 0;
612
+ if (camera.torchSupported) score += 1;
613
+ if (camera.singleShotSupported) score += 1;
614
+ return score;
615
+ }
616
+ function filterCamerasByFacing(cameras, requestedFacing) {
617
+ return cameras.filter((camera) => {
618
+ if (requestedFacing === "back" || requestedFacing === void 0) {
619
+ return isBackCameraName(camera.name);
620
+ } else {
621
+ return isFrontCameraName(camera.name);
622
+ }
623
+ });
624
+ }
603
625
  const findIdealCamera = async (cameras, resolution = "4k", requestedFacing = "back") => {
604
626
  if (cameras.length === 0) {
605
627
  throw new Error("No cameras found");
606
628
  }
629
+ if (cameras.length === 1) {
630
+ await cameras[0].startStream(resolution);
631
+ return cameras[0];
632
+ }
633
+ let cameraPool = filterCamerasByFacing(cameras, requestedFacing);
634
+ if (cameraPool.length === 1) {
635
+ await cameraPool[0].startStream(resolution);
636
+ return cameraPool[0];
637
+ }
638
+ if (cameraPool.length === 0) {
639
+ console.debug("No camera found with requested facing, using all cameras");
640
+ cameraPool = cameras;
641
+ }
607
642
  if (requestedFacing === "back") {
608
- const dualWideCamera = cameras.find(
643
+ const dualWideCamera = cameraPool.find(
609
644
  (camera) => backDualWideCameraLocalizations.includes(camera.name)
610
645
  );
611
646
  if (dualWideCamera) {
@@ -613,65 +648,44 @@ const findIdealCamera = async (cameras, resolution = "4k", requestedFacing = "ba
613
648
  return dualWideCamera;
614
649
  }
615
650
  }
616
- const cameraPool = cameras.filter((camera) => {
617
- if (requestedFacing === "back" || requestedFacing === void 0) {
618
- return isBackCameraName(camera.name);
619
- } else {
620
- return isFrontCameraName(camera.name);
621
- }
622
- });
623
- if (cameraPool.length === 1 && cameraPool[0].facingMode === requestedFacing) {
624
- await cameraPool[0].startStream(resolution);
625
- return cameraPool[0];
626
- }
627
- if (cameraPool.length > 0 && requestedFacing === "front") {
651
+ if (requestedFacing === "front") {
628
652
  const lastCamera = cameraPool[cameraPool.length - 1];
629
653
  await lastCamera.startStream(resolution);
630
654
  return lastCamera;
631
655
  }
632
- if (cameraPool.length === 0) {
633
- console.debug("No camera found with requested facing, using all cameras");
634
- cameraPool.push(...cameras);
635
- }
636
656
  const cameraScores = /* @__PURE__ */ new Map();
637
- cameras.forEach((camera) => cameraScores.set(camera, 0));
657
+ let bestCamera;
658
+ let maxScore = -Infinity;
638
659
  for (let i = cameraPool.length - 1; i >= 0; i--) {
639
660
  const camera = cameraPool[i];
640
- await camera.startStream(resolution);
641
- if (!camera.facingMode) {
642
- console.debug("No facing mode, returning last camera");
643
- return camera;
644
- }
645
- if (camera.facingMode && camera.facingMode !== requestedFacing) {
646
- console.debug("Mismatched facing mode, moving on to the next camera");
647
- camera.stopStream();
648
- continue;
649
- }
650
- if (camera.torchSupported && camera.singleShotSupported) {
651
- console.debug("Camera supports torch and single shot, returning");
652
- return camera;
653
- }
654
- if (camera.torchSupported) {
655
- cameraScores.set(camera, cameraScores.get(camera) + 1);
656
- }
657
- if (camera.singleShotSupported) {
658
- cameraScores.set(camera, cameraScores.get(camera) + 1);
659
- }
660
- if (i === 0) {
661
- console.debug("Last camera in the pool, picking the best one");
662
- let maxKey;
663
- let maxValue = -Infinity;
664
- cameraScores.forEach((score, camera2) => {
665
- if (score > maxValue) {
666
- maxValue = score;
667
- maxKey = camera2;
661
+ try {
662
+ await camera.startStream(resolution);
663
+ const score = scoreCameraCapabilities(camera);
664
+ cameraScores.set(camera, score);
665
+ if (score > maxScore) {
666
+ if (bestCamera && bestCamera !== camera) {
667
+ bestCamera.stopStream();
668
668
  }
669
- });
670
- return maxKey;
669
+ maxScore = score;
670
+ bestCamera = camera;
671
+ } else {
672
+ camera.stopStream();
673
+ }
674
+ if (score === 2) {
675
+ console.debug("Found camera with all capabilities, returning early");
676
+ return camera;
677
+ }
678
+ } catch (error) {
679
+ console.warn(`Failed to test camera ${camera.name}:`, error);
680
+ camera.stopStream();
671
681
  }
672
- camera.stopStream();
673
682
  }
674
- throw new Error("No camera found, should not happen");
683
+ if (bestCamera) {
684
+ return bestCamera;
685
+ }
686
+ const firstCamera = cameraPool[0];
687
+ await firstCamera.startStream(resolution);
688
+ return firstCamera;
675
689
  };
676
690
  function createCameras(cameras) {
677
691
  const camerasWithStream = [];
@@ -734,6 +748,9 @@ function findResolutionKey(videoTrackResolution) {
734
748
  return resolutionKey;
735
749
  }
736
750
  class Camera {
751
+ /**
752
+ * The device info.
753
+ */
737
754
  deviceInfo;
738
755
  /**
739
756
  * Stream capabilities as reported by the stream.
@@ -767,6 +784,11 @@ class Camera {
767
784
  * @deprecated Not used. Reconsider using once Firefox and Chrome align on this.
768
785
  */
769
786
  #deviceCapabilities;
787
+ /**
788
+ * Creates a new Camera instance.
789
+ *
790
+ * @param deviceInfo - The device info.
791
+ */
770
792
  constructor(deviceInfo) {
771
793
  if (deviceInfo.kind !== "videoinput") {
772
794
  throw new Error("Device is not a video input device");
@@ -797,6 +819,12 @@ class Camera {
797
819
  };
798
820
  return proxy;
799
821
  }
822
+ /**
823
+ * Starts a stream with the specified resolution.
824
+ *
825
+ * @param resolution - The resolution to start the stream with.
826
+ * @returns The stream.
827
+ */
800
828
  async startStream(resolution) {
801
829
  if (this.activeStream) {
802
830
  return this.activeStream;
@@ -820,6 +848,9 @@ class Camera {
820
848
  /**
821
849
  * Acquires a camera stream with the specified resolution.
822
850
  * If acquisition fails, it tries a lower resolution as fallback.
851
+ *
852
+ * @param resolution - The resolution to acquire the stream with.
853
+ * @returns The stream.
823
854
  */
824
855
  async acquireStreamWithFallback(resolution) {
825
856
  try {
@@ -844,6 +875,8 @@ class Camera {
844
875
  }
845
876
  /**
846
877
  * Populates the camera instance with capabilities from the stream.
878
+ *
879
+ * @param stream - The stream to populate the capabilities from.
847
880
  */
848
881
  populateCapabilities(stream) {
849
882
  this.streamCapabilities = stream.getVideoTracks()[0].getCapabilities();
@@ -885,6 +918,11 @@ class Camera {
885
918
  }
886
919
  }
887
920
  }
921
+ /**
922
+ * Toggles the torch on the camera.
923
+ *
924
+ * @returns The torch status.
925
+ */
888
926
  async toggleTorch() {
889
927
  const videoTrack = this.getVideoTrack();
890
928
  if (!videoTrack) {
@@ -910,6 +948,9 @@ class Camera {
910
948
  }
911
949
  return this.torchEnabled;
912
950
  }
951
+ /**
952
+ * Stops the stream on the camera.
953
+ */
913
954
  stopStream() {
914
955
  if (this.activeStream) {
915
956
  console.debug(`Stopping active stream on ${this.name}`);
@@ -919,6 +960,11 @@ class Camera {
919
960
  this.torchEnabled = false;
920
961
  }
921
962
  }
963
+ /**
964
+ * Gets the video track on the camera.
965
+ *
966
+ * @returns The video track.
967
+ */
922
968
  getVideoTrack() {
923
969
  if (!this.activeStream) {
924
970
  console.warn(`No active stream on Camera instance: ${this.name}.`);
@@ -1241,6 +1287,11 @@ class VideoFrameProcessor {
1241
1287
  #cachedHeight = 0;
1242
1288
  #canvasRenderingMode;
1243
1289
  #requiredPackAlignment = 4;
1290
+ /**
1291
+ * Creates a new VideoFrameProcessor.
1292
+ *
1293
+ * @param options - The options for the VideoFrameProcessor.
1294
+ */
1244
1295
  constructor(options = {}) {
1245
1296
  const { canvasRenderingMode = "webgl2", fallbackWebGlTo2d = true } = options;
1246
1297
  this.#canvasRenderingMode = canvasRenderingMode;
@@ -1268,7 +1319,7 @@ class VideoFrameProcessor {
1268
1319
  }
1269
1320
  }
1270
1321
  /**
1271
- * Initializes the 2D canvas context
1322
+ * Initializes the 2D canvas context.
1272
1323
  */
1273
1324
  #initialize2dContext() {
1274
1325
  const ctx = this.#canvas.getContext("2d", {
@@ -1279,7 +1330,7 @@ class VideoFrameProcessor {
1279
1330
  this.#context2d = ctx;
1280
1331
  }
1281
1332
  /**
1282
- * Initializes the WebGL2 context and resources
1333
+ * Initializes the WebGL2 context and resources.
1283
1334
  */
1284
1335
  #initializeWebGl2Context() {
1285
1336
  const ctx = this.#canvas.getContext("webgl2", {
@@ -1315,9 +1366,12 @@ class VideoFrameProcessor {
1315
1366
  );
1316
1367
  }
1317
1368
  /**
1318
- * Returns ownership of an ArrayBuffer to the processor for reuse
1319
- * This should only be called with ArrayBuffers that were originally from this processor
1320
- * Typically used after transferring the buffer to/from a worker
1369
+ * Returns ownership of an ArrayBuffer to the processor for reuse.
1370
+ *
1371
+ * This should only be called with ArrayBuffers that were originally from this processor.
1372
+ * Typically used after transferring the buffer to/from a worker.
1373
+ *
1374
+ * @param arrayBuffer - The array buffer to reattach.
1321
1375
  */
1322
1376
  reattachArrayBuffer(arrayBuffer) {
1323
1377
  const actualBuffer = getBuffer(arrayBuffer);
@@ -1334,7 +1388,9 @@ class VideoFrameProcessor {
1334
1388
  }
1335
1389
  }
1336
1390
  /**
1337
- * Used to check if the processor owns the buffer
1391
+ * Used to check if the processor owns the buffer.
1392
+ *
1393
+ * @returns true if the processor owns the buffer, false otherwise.
1338
1394
  */
1339
1395
  isBufferDetached() {
1340
1396
  if (!this.#buffer) {
@@ -1343,7 +1399,11 @@ class VideoFrameProcessor {
1343
1399
  return isBufferDetached(this.#buffer.buffer);
1344
1400
  }
1345
1401
  /**
1346
- * Extracts image data from a source element
1402
+ * Extracts image data from a source element.
1403
+ *
1404
+ * @param source - The source element to extract image data from.
1405
+ * @param area - The extraction area.
1406
+ * @returns The image data.
1347
1407
  */
1348
1408
  getImageData(source, area) {
1349
1409
  return this.#canvasRenderingMode === "2d" ? this.#getImageData2d(source, area) : this.#getImageDataWebGl2(source, area);
@@ -1352,6 +1412,7 @@ class VideoFrameProcessor {
1352
1412
  * Used to get the current ImageData object with the current buffer. Useful
1353
1413
  * when you need to get the same `ImageData` object multiple times after the
1354
1414
  * original `ImageData` buffer has been detached
1415
+ *
1355
1416
  * @returns ImageData object with the current buffer
1356
1417
  */
1357
1418
  getCurrentImageData() {
@@ -1361,7 +1422,11 @@ class VideoFrameProcessor {
1361
1422
  return new ImageData(this.#buffer, this.#cachedWidth, this.#cachedHeight);
1362
1423
  }
1363
1424
  /**
1364
- * Extract image data using 2D canvas
1425
+ * Extract image data using 2D canvas.
1426
+ *
1427
+ * @param source - The source element to extract image data from.
1428
+ * @param area - The extraction area.
1429
+ * @returns The image data.
1365
1430
  */
1366
1431
  #getImageData2d(source, area) {
1367
1432
  if (!this.#context2d)
@@ -1377,7 +1442,11 @@ class VideoFrameProcessor {
1377
1442
  return this.#context2d.getImageData(0, 0, w, h);
1378
1443
  }
1379
1444
  /**
1380
- * Extract image data using WebGL2
1445
+ * Extract image data using WebGL2.
1446
+ *
1447
+ * @param source - The source element to extract image data from.
1448
+ * @param area - The extraction area.
1449
+ * @returns The image data.
1381
1450
  */
1382
1451
  #getImageDataWebGl2(source, area) {
1383
1452
  if (!this.#contextWebGl2 || !this.#webGl2Texture || !this.#webGl2Framebuffer) {
@@ -1418,9 +1487,12 @@ class VideoFrameProcessor {
1418
1487
  return new ImageData(this.#buffer, w, h);
1419
1488
  }
1420
1489
  /**
1421
- * Update canvas dimensions if needed
1490
+ * Update canvas dimensions if needed.
1491
+ *
1492
+ * This canvas is the orientation-aware.
1422
1493
  *
1423
- * This canvas is the orientation-aware
1494
+ * @param width - The width of the canvas.
1495
+ * @param height - The height of the canvas.
1424
1496
  */
1425
1497
  #updateCanvasSize(width, height) {
1426
1498
  if (this.#cachedWidth !== width || this.#cachedHeight !== height) {
@@ -1433,7 +1505,7 @@ class VideoFrameProcessor {
1433
1505
  }
1434
1506
  }
1435
1507
  /**
1436
- * Clean up resources
1508
+ * Clean up resources.
1437
1509
  */
1438
1510
  dispose() {
1439
1511
  if (this.#contextWebGl2) {
@@ -1474,6 +1546,10 @@ class CameraManager {
1474
1546
  * CameraManager from throwing errors when the user interrupts the process.
1475
1547
  */
1476
1548
  #userInitiatedAbort = false;
1549
+ /**
1550
+ * If true, the user has initiated an abort. This will prevent the
1551
+ * CameraManager from throwing errors when the user interrupts the process.
1552
+ */
1477
1553
  get userInitiatedAbort() {
1478
1554
  return this.#userInitiatedAbort;
1479
1555
  }
@@ -1482,6 +1558,7 @@ class CameraManager {
1482
1558
  }
1483
1559
  /**
1484
1560
  * Sets the area of the video frame that will be extracted.
1561
+ *
1485
1562
  * @param extractionArea The area of the video frame that will be extracted.
1486
1563
  */
1487
1564
  setExtractionArea(extractionArea) {
@@ -1492,6 +1569,12 @@ class CameraManager {
1492
1569
  * "capturing".
1493
1570
  */
1494
1571
  #frameCaptureCallbacks = /* @__PURE__ */ new Set();
1572
+ /**
1573
+ * Creates a new CameraManager instance.
1574
+ *
1575
+ * @param options - The options for the CameraManager.
1576
+ * @param videoFrameProcessorOptions - The options for the VideoFrameProcessor.
1577
+ */
1495
1578
  constructor(options = {}, videoFrameProcessorOptions) {
1496
1579
  const { mirrorFrontCameras } = {
1497
1580
  ...defaultCameraManagerOptions,
@@ -1503,7 +1586,9 @@ class CameraManager {
1503
1586
  this.#mirrorFrontCameras = mirrorFrontCameras;
1504
1587
  }
1505
1588
  /**
1506
- * Sets the resolution of the camera stream
1589
+ * Sets the resolution of the camera stream.
1590
+ *
1591
+ * @param resolution - The resolution to set.
1507
1592
  */
1508
1593
  setResolution = async (resolution) => {
1509
1594
  this.#resolution = resolution;
@@ -1514,16 +1599,25 @@ class CameraManager {
1514
1599
  await this.startCameraStream();
1515
1600
  }
1516
1601
  };
1602
+ /**
1603
+ * The resolution of the camera stream.
1604
+ */
1517
1605
  get resolution() {
1518
1606
  return this.#resolution;
1519
1607
  }
1520
1608
  /**
1521
1609
  * True if there is a video playing or capturing
1522
- * TODO: see if we can simplify this, by observing the video playback state
1610
+ *
1611
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaSession/playbackState for more details.
1523
1612
  */
1524
1613
  get isActive() {
1525
1614
  return cameraManagerStore.getState().playbackState !== "idle";
1526
1615
  }
1616
+ /**
1617
+ * Sets the facing filter.
1618
+ *
1619
+ * @param facingFilter - The facing filter.
1620
+ */
1527
1621
  setFacingFilter(facingFilter) {
1528
1622
  cameraManagerStore.setState({
1529
1623
  facingFilter
@@ -1532,6 +1626,8 @@ class CameraManager {
1532
1626
  /**
1533
1627
  * Returns the cameras that are available to the user, filtered by the facing mode.
1534
1628
  * If no facing mode is set, all cameras are returned.
1629
+ *
1630
+ * @returns The cameras that are available to the user, filtered by the facing mode.
1535
1631
  */
1536
1632
  async getCameraDevices() {
1537
1633
  let allCameras = cameraManagerStore.getState().cameras;
@@ -1549,7 +1645,9 @@ class CameraManager {
1549
1645
  return filteredCameras;
1550
1646
  }
1551
1647
  /**
1552
- * Single-time setup for a video element
1648
+ * Single-time setup for a video element.
1649
+ *
1650
+ * @param videoElement - The video element to initialize.
1553
1651
  */
1554
1652
  #initVideoElement(videoElement) {
1555
1653
  if (!(videoElement instanceof HTMLVideoElement)) {
@@ -1629,6 +1727,8 @@ class CameraManager {
1629
1727
  }
1630
1728
  /**
1631
1729
  * Initializes the CameraManager with a video element.
1730
+ *
1731
+ * @param videoElement - The video element to initialize.
1632
1732
  */
1633
1733
  initVideoElement(videoElement) {
1634
1734
  try {
@@ -1645,13 +1745,16 @@ class CameraManager {
1645
1745
  * Adds a callback that will be triggered on each frame when the playback state
1646
1746
  * is "capturing".
1647
1747
  *
1648
- * @param frameCaptureCallback
1748
+ * @param frameCaptureCallback - The callback to add.
1649
1749
  * @returns a cleanup function to remove the callback
1650
1750
  */
1651
1751
  addFrameCaptureCallback(frameCaptureCallback) {
1652
1752
  this.#frameCaptureCallbacks.add(frameCaptureCallback);
1653
1753
  return () => this.#frameCaptureCallbacks.delete(frameCaptureCallback);
1654
1754
  }
1755
+ /**
1756
+ * Cleans up the video element, and stops the stream.
1757
+ */
1655
1758
  releaseVideoElement() {
1656
1759
  this.#eventListenerCleanup?.();
1657
1760
  cameraManagerStore.setState({
@@ -1659,10 +1762,11 @@ class CameraManager {
1659
1762
  });
1660
1763
  this.stopStream();
1661
1764
  }
1765
+ // TODO: might become a private method in the future as an implementation detail of `startStream`
1662
1766
  /**
1663
1767
  * Select a camera device from available ones.
1664
1768
  *
1665
- * TODO: might become a private method in the future as an implementation detail of `startStream`
1769
+ * @param camera - The camera to select.
1666
1770
  */
1667
1771
  async selectCamera(camera) {
1668
1772
  const playbackState = cameraManagerStore.getState().playbackState;
@@ -1704,6 +1808,8 @@ class CameraManager {
1704
1808
  }
1705
1809
  /**
1706
1810
  * Refreshes available devices on the system and updates the state.
1811
+ *
1812
+ * @returns resolves when the camera devices are refreshed
1707
1813
  */
1708
1814
  async refreshCameraDevices() {
1709
1815
  if (cameraManagerStore.getState().isQueryingCameras || cameraManagerStore.getState().isSwappingCamera) {
@@ -1790,6 +1896,8 @@ class CameraManager {
1790
1896
  }
1791
1897
  /**
1792
1898
  * Starts playback and frame capturing.
1899
+ *
1900
+ * @returns resolves when frame capture starts
1793
1901
  */
1794
1902
  async #startFrameCapture() {
1795
1903
  const state = cameraManagerStore.getState();
@@ -1820,6 +1928,8 @@ class CameraManager {
1820
1928
  }
1821
1929
  /**
1822
1930
  * Starts capturing frames from the video element.
1931
+ *
1932
+ * @returns resolves when frame capture starts
1823
1933
  */
1824
1934
  startFrameCapture = async () => {
1825
1935
  try {
@@ -1832,6 +1942,12 @@ class CameraManager {
1832
1942
  }
1833
1943
  }
1834
1944
  };
1945
+ /**
1946
+ * Starts a camera stream.
1947
+ *
1948
+ * @param params - The parameters for the camera stream.
1949
+ * @returns resolves when the camera stream starts
1950
+ */
1835
1951
  async #startCameraStream({
1836
1952
  autoplay = true,
1837
1953
  preferredCamera,
@@ -1912,6 +2028,9 @@ class CameraManager {
1912
2028
  /**
1913
2029
  * Starts a best-effort camera stream. Will pick a camera automatically if
1914
2030
  * none is selected.
2031
+ *
2032
+ * @param params - The parameters for the camera stream.
2033
+ * @returns resolves when the camera stream starts
1915
2034
  */
1916
2035
  async startCameraStream(params = {}) {
1917
2036
  try {
@@ -1924,12 +2043,17 @@ class CameraManager {
1924
2043
  }
1925
2044
  }
1926
2045
  }
2046
+ /**
2047
+ * Checks if the error state is a permission error.
2048
+ *
2049
+ * @returns true if the error state is a permission error
2050
+ */
1927
2051
  #hasPermissionError = () => {
1928
2052
  const errorState = cameraManagerStore.getState().errorState;
1929
2053
  return errorState instanceof CameraError && errorState.code === "PERMISSION_DENIED";
1930
2054
  };
1931
2055
  /**
1932
- * Pauses capturing frames without pausing playback.
2056
+ * Pauses capturing frames, without stopping playback.
1933
2057
  */
1934
2058
  stopFrameCapture() {
1935
2059
  cameraManagerStore.setState({
@@ -1966,7 +2090,7 @@ class CameraManager {
1966
2090
  video.pause();
1967
2091
  }
1968
2092
  /**
1969
- * The main recognition loop. Do not call this method directly, use #queueFrame instead.
2093
+ * The main recognition loop. Do not call this method directly, use `#queueFrame` instead.
1970
2094
  */
1971
2095
  async #loop() {
1972
2096
  const state = cameraManagerStore.getState();
@@ -2007,7 +2131,7 @@ class CameraManager {
2007
2131
  this.#queueFrame();
2008
2132
  }
2009
2133
  /**
2010
- * Queues the next frame to be processed
2134
+ * Queues the next frame to be processed.
2011
2135
  */
2012
2136
  #queueFrame() {
2013
2137
  const state = cameraManagerStore.getState();
@@ -2046,6 +2170,8 @@ class CameraManager {
2046
2170
  }
2047
2171
  /**
2048
2172
  * If true, the video and captured frames will be mirrored horizontally.
2173
+ *
2174
+ * @param mirrorX - If true, the video and captured frames will be mirrored horizontally.
2049
2175
  */
2050
2176
  setCameraMirrorX(mirrorX) {
2051
2177
  const currentState = cameraManagerStore.getState();
@@ -2068,15 +2194,19 @@ class CameraManager {
2068
2194
  /**
2069
2195
  * Allows the user to subscribe to state changes inside the Camera Manager.
2070
2196
  * Implemented using Zustand. For usage information, see
2071
- * {@link https://github.com/pmndrs/zustand#using-subscribe-with-selector}
2197
+ * @see https://github.com/pmndrs/zustand#using-subscribe-with-selector for more details.
2198
+ *
2199
+ * @returns a cleanup function to remove the subscription
2072
2200
  */
2073
2201
  subscribe = cameraManagerStore.subscribe;
2074
2202
  /**
2075
2203
  * Gets the current internal state of the CameraManager.
2204
+ *
2205
+ * @returns the current state of the CameraManager
2076
2206
  */
2077
2207
  getState = cameraManagerStore.getState;
2078
2208
  /**
2079
- * Resets the CameraManager and stop all streams
2209
+ * Resets the CameraManager and stops all streams.
2080
2210
  */
2081
2211
  reset() {
2082
2212
  console.debug("Resetting camera manager");