UNPKG

scandit-sdk

Version:

Scandit Barcode Scanner SDK for the Web

912 lines 68.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CameraManager = exports.CameraResolutionConstraint = exports.MeteringMode = void 0; var tslib_1 = require("tslib"); var browserHelper_1 = require("../browserHelper"); var camera_1 = require("../camera"); var cameraAccess_1 = require("../cameraAccess"); var cameraSettings_1 = require("../cameraSettings"); var customError_1 = require("../customError"); var logger_1 = require("../logger"); var MeteringMode; (function (MeteringMode) { MeteringMode["CONTINUOUS"] = "continuous"; MeteringMode["MANUAL"] = "manual"; MeteringMode["NONE"] = "none"; MeteringMode["SINGLE_SHOT"] = "single-shot"; })(MeteringMode = exports.MeteringMode || (exports.MeteringMode = {})); var CameraResolutionConstraint; (function (CameraResolutionConstraint) { CameraResolutionConstraint[CameraResolutionConstraint["ULTRA_HD"] = 0] = "ULTRA_HD"; CameraResolutionConstraint[CameraResolutionConstraint["FULL_HD"] = 1] = "FULL_HD"; CameraResolutionConstraint[CameraResolutionConstraint["HD"] = 2] = "HD"; CameraResolutionConstraint[CameraResolutionConstraint["SD"] = 3] = "SD"; CameraResolutionConstraint[CameraResolutionConstraint["NONE"] = 4] = "NONE"; })(CameraResolutionConstraint = exports.CameraResolutionConstraint || (exports.CameraResolutionConstraint = {})); /** * A barcode picker utility class used to handle camera interaction. */ var CameraManager = /** @class */ (function () { function CameraManager(scanner, triggerCameraAccessError, gui) { this.postStreamInitializationListener = this.postStreamInitialization.bind(this); this.videoResizeListener = this.videoResizeHandle.bind(this); this.videoTrackEndedListener = this.videoTrackEndedRecovery.bind(this); this.videoTrackMuteListener = this.videoTrackMuteRecovery.bind(this); this.triggerManualFocusListener = this.triggerManualFocus.bind(this); this.triggerZoomStartListener = this.triggerZoomStart.bind(this); this.triggerZoomMoveListener = this.triggerZoomMove.bind(this); this.checkCameraVideoStreamAccessIfVisibleListener = this.checkCameraVideoStreamAccessIfVisible.bind(this); this.scanner = scanner; this.triggerCameraAccessError = triggerCameraAccessError; this.gui = gui; this.cameraType = camera_1.Camera.Type.BACK; } CameraManager.prototype.setInteractionOptions = function (cameraSwitcherEnabled, cameraFOVSwitcherEnabled, torchToggleEnabled, tapToFocusEnabled, pinchToZoomEnabled) { this.cameraSwitcherEnabled = cameraSwitcherEnabled; this.cameraFOVSwitcherEnabled = cameraFOVSwitcherEnabled; this.torchToggleEnabled = torchToggleEnabled; this.tapToFocusEnabled = tapToFocusEnabled; this.pinchToZoomEnabled = pinchToZoomEnabled; }; CameraManager.prototype.isCameraSwitcherEnabled = function () { return this.cameraSwitcherEnabled; }; CameraManager.prototype.setCameraSwitcherEnabled = function (enabled) { return tslib_1.__awaiter(this, void 0, void 0, function () { var cameras; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: this.cameraSwitcherEnabled = enabled; if (!this.cameraSwitcherEnabled) return [3 /*break*/, 2]; return [4 /*yield*/, cameraAccess_1.CameraAccess.getCameras()]; case 1: cameras = _a.sent(); if (cameras.length > 1) { this.gui.setCameraSwitcherVisible(true); } return [3 /*break*/, 3]; case 2: this.gui.setCameraSwitcherVisible(false); _a.label = 3; case 3: return [2 /*return*/]; } }); }); }; CameraManager.prototype.isCameraFOVSwitcherEnabled = function () { return this.cameraFOVSwitcherEnabled; }; CameraManager.prototype.setCameraFOVSwitcherEnabled = function (enabled) { return tslib_1.__awaiter(this, void 0, void 0, function () { var cameras, backWideCamera; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: this.cameraFOVSwitcherEnabled = enabled; if (!enabled) return [3 /*break*/, 3]; return [4 /*yield*/, cameraAccess_1.CameraAccess.getCameras()]; case 1: cameras = _a.sent(); backWideCamera = cameras.find(function (camera) { return cameraAccess_1.CameraAccess.isIOSWideBackCameraLabel(camera.label); }); if (!(backWideCamera != null)) return [3 /*break*/, 3]; return [4 /*yield*/, this.initializeCameraWithSettings(backWideCamera, this.activeCameraSettings)]; case 2: _a.sent(); _a.label = 3; case 3: if (this.isCameraFOVSwitcherAllowed() && this.activeCamera != null) { this.gui.setCameraFOVSwitcherState(cameraAccess_1.CameraAccess.isIOSUltraWideBackCameraLabel(this.activeCamera.label)); this.gui.setCameraFOVSwitcherVisible(true); } else { this.gui.setCameraFOVSwitcherVisible(false); } return [2 /*return*/]; } }); }); }; CameraManager.prototype.isTorchToggleEnabled = function () { return this.torchToggleEnabled; }; CameraManager.prototype.setTorchToggleEnabled = function (enabled) { var _a; this.torchToggleEnabled = enabled; if (this.torchToggleEnabled) { if (this.mediaStream != null && ((_a = this.mediaTrackCapabilities) === null || _a === void 0 ? void 0 : _a.torch) === true) { this.gui.setTorchTogglerVisible(true); } } else { this.gui.setTorchTogglerVisible(false); } }; CameraManager.prototype.isTapToFocusEnabled = function () { return this.tapToFocusEnabled; }; CameraManager.prototype.setTapToFocusEnabled = function (enabled) { this.tapToFocusEnabled = enabled; if (this.mediaStream != null) { if (this.tapToFocusEnabled) { this.enableTapToFocusListeners(); } else { this.disableTapToFocusListeners(); } } }; CameraManager.prototype.isPinchToZoomEnabled = function () { return this.pinchToZoomEnabled; }; CameraManager.prototype.setPinchToZoomEnabled = function (enabled) { this.pinchToZoomEnabled = enabled; if (this.mediaStream != null) { if (this.pinchToZoomEnabled) { this.enablePinchToZoomListeners(); } else { this.disablePinchToZoomListeners(); } } }; CameraManager.prototype.setInitialCameraType = function (cameraType) { this.cameraType = cameraType; }; CameraManager.prototype.setCameraType = function (cameraType) { return tslib_1.__awaiter(this, void 0, void 0, function () { var mainCameraForType, _a, _b; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: this.setInitialCameraType(cameraType); _b = (_a = cameraAccess_1.CameraAccess).getMainCameraForType; return [4 /*yield*/, cameraAccess_1.CameraAccess.getCameras()]; case 1: mainCameraForType = _b.apply(_a, [_c.sent(), cameraType]); if (mainCameraForType != null && mainCameraForType !== this.selectedCamera) { return [2 /*return*/, this.initializeCameraWithSettings(mainCameraForType, this.selectedCameraSettings)]; } return [2 /*return*/]; } }); }); }; CameraManager.prototype.setSelectedCamera = function (camera) { this.selectedCamera = camera; }; CameraManager.prototype.setSelectedCameraSettings = function (cameraSettings) { this.selectedCameraSettings = cameraSettings; }; CameraManager.prototype.setupCameras = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { if (this.cameraSetupPromise != null) { return [2 /*return*/, this.cameraSetupPromise]; } this.cameraSetupPromise = this.setupCamerasAndStream(); return [2 /*return*/, this.cameraSetupPromise]; }); }); }; CameraManager.prototype.stopStream = function (cameraInitializationFailure) { if (cameraInitializationFailure === void 0) { cameraInitializationFailure = false; } return tslib_1.__awaiter(this, void 0, void 0, function () { var _this = this; return tslib_1.__generator(this, function (_a) { if (this.activeCamera != null) { this.activeCamera.currentResolution = undefined; } this.activeCamera = undefined; this.torchEnabled = false; this.gui.setTorchTogglerVisible(false); this.gui.setCameraFOVSwitcherVisible(false); if (this.mediaStream != null) { logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Stop camera video stream access".concat(cameraInitializationFailure ? " (abort access detection)" : "", ":"), this.mediaStream); document.removeEventListener("visibilitychange", this.checkCameraVideoStreamAccessIfVisibleListener); window.clearTimeout(this.cameraAccessTimeout); window.clearInterval(this.videoMetadataCheckInterval); window.clearTimeout(this.getCapabilitiesTimeout); window.clearTimeout(this.manualFocusWaitTimeout); window.clearTimeout(this.manualToAutofocusResumeTimeout); window.clearInterval(this.autofocusInterval); // Pause video and asynchronously stop tracks to prevent bug on some Android devices freezing the camera on Chrome this.gui.videoElement.pause(); return [2 /*return*/, new Promise(function (resolve) { setTimeout(function () { var _a, _b; (_a = _this.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach(function (track) { track.removeEventListener("ended", _this.videoTrackEndedListener); track.stop(); }); _this.gui.videoElement.srcObject = null; _this.mediaStream = undefined; _this.mediaTrackCapabilities = undefined; if (!cameraInitializationFailure) { (_b = _this.abortedCameraInitializationResolveCallback) === null || _b === void 0 ? void 0 : _b.call(_this); } resolve(); }, 0); })]; } return [2 /*return*/]; }); }); }; CameraManager.prototype.applyCameraSettings = function (cameraSettings) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { this.selectedCameraSettings = cameraSettings; if (this.activeCamera == null) { throw new customError_1.CustomError(CameraManager.noCameraErrorParameters); } return [2 /*return*/, this.initializeCameraWithSettings(this.activeCamera, cameraSettings)]; }); }); }; CameraManager.prototype.reinitializeCamera = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var camera, error_1; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!(this.activeCamera == null)) return [3 /*break*/, 1]; // If the initial camera isn't active yet, do nothing: if and when the camera is later confirmed to be the correct // (main with wanted type or only) one this method will be called again after the camera is set to be active logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Camera reinitialization delayed"); return [3 /*break*/, 6]; case 1: logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Reinitialize camera:", this.activeCamera); _a.label = 2; case 2: _a.trys.push([2, 5, , 6]); camera = this.activeCamera; return [4 /*yield*/, this.stopStream()]; case 3: _a.sent(); return [4 /*yield*/, this.initializeCameraWithSettings(camera, this.activeCameraSettings)]; case 4: _a.sent(); return [3 /*break*/, 6]; case 5: error_1 = _a.sent(); logger_1.Logger.log(logger_1.Logger.Level.WARN, "Couldn't access camera:", this.activeCamera, error_1); this.triggerCameraAccessError(error_1); throw error_1; case 6: return [2 /*return*/]; } }); }); }; CameraManager.prototype.initializeCameraWithSettings = function (camera, cameraSettings) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!(this.cameraInitializationPromise != null)) return [3 /*break*/, 2]; return [4 /*yield*/, this.cameraInitializationPromise]; case 1: _a.sent(); _a.label = 2; case 2: if (camera == null) { throw new customError_1.CustomError(CameraManager.noCameraErrorParameters); } this.setSelectedCamera(camera); this.selectedCameraSettings = this.activeCameraSettings = cameraSettings; this.cameraInitializationPromise = this.initializeCameraAndCheckUpdatedSettings(camera); return [2 /*return*/, this.cameraInitializationPromise]; } }); }); }; CameraManager.prototype.setTorchEnabled = function (enabled) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function () { var videoTracks; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: if (!(this.mediaStream != null && ((_a = this.mediaTrackCapabilities) === null || _a === void 0 ? void 0 : _a.torch) === true)) return [3 /*break*/, 2]; this.torchEnabled = enabled; videoTracks = this.mediaStream.getVideoTracks(); if (!(videoTracks.length !== 0 && typeof videoTracks[0].applyConstraints === "function")) return [3 /*break*/, 2]; return [4 /*yield*/, videoTracks[0].applyConstraints({ advanced: [{ torch: enabled }] })]; case 1: _b.sent(); _b.label = 2; case 2: return [2 /*return*/]; } }); }); }; CameraManager.prototype.toggleTorch = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: this.torchEnabled = !this.torchEnabled; return [4 /*yield*/, this.setTorchEnabled(this.torchEnabled)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; CameraManager.prototype.setZoom = function (zoomPercentage, currentZoom) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function () { var videoTracks, zoomRange, targetZoom; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: if (!(this.mediaStream != null && ((_a = this.mediaTrackCapabilities) === null || _a === void 0 ? void 0 : _a.zoom) != null)) return [3 /*break*/, 2]; videoTracks = this.mediaStream.getVideoTracks(); if (!(videoTracks.length !== 0 && typeof videoTracks[0].applyConstraints === "function")) return [3 /*break*/, 2]; zoomRange = this.mediaTrackCapabilities.zoom.max - this.mediaTrackCapabilities.zoom.min; targetZoom = Math.max(this.mediaTrackCapabilities.zoom.min, Math.min((currentZoom !== null && currentZoom !== void 0 ? currentZoom : this.mediaTrackCapabilities.zoom.min) + zoomRange * zoomPercentage, this.mediaTrackCapabilities.zoom.max)); return [4 /*yield*/, videoTracks[0].applyConstraints({ advanced: [{ zoom: targetZoom }], })]; case 1: _b.sent(); _b.label = 2; case 2: return [2 /*return*/]; } }); }); }; CameraManager.prototype.isCameraFOVSwitcherAllowed = function () { return (this.cameraFOVSwitcherEnabled && browserHelper_1.BrowserHelper.isIOSDeviceWithExtendedCameraAccess() && this.activeCamera != null && (cameraAccess_1.CameraAccess.isIOSWideBackCameraLabel(this.activeCamera.label) || cameraAccess_1.CameraAccess.isIOSUltraWideBackCameraLabel(this.activeCamera.label))); }; CameraManager.prototype.recoverStreamIfNeeded = function () { var _a, _b; return tslib_1.__awaiter(this, void 0, void 0, function () { var videoTracks; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: videoTracks = (_a = this.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks(); if (!(((_b = videoTracks === null || videoTracks === void 0 ? void 0 : videoTracks[0]) === null || _b === void 0 ? void 0 : _b.readyState) === "ended")) return [3 /*break*/, 2]; return [4 /*yield*/, this.reinitializeCamera()]; case 1: _c.sent(); _c.label = 2; case 2: return [2 /*return*/]; } }); }); }; CameraManager.prototype.setupCamerasAndStream = function () { var _a, _b, _c; return tslib_1.__awaiter(this, void 0, void 0, function () { var initialCamera_1, cameras, initialCameraDeviceId_1, activeCamera; return tslib_1.__generator(this, function (_d) { switch (_d.label) { case 0: _d.trys.push([0, , 13, 14]); if (!(this.selectedCamera == null)) return [3 /*break*/, 2]; this.gui.setVideoVisible(false); return [4 /*yield*/, this.accessInitialCamera()]; case 1: initialCamera_1 = _d.sent(); _d.label = 2; case 2: return [4 /*yield*/, cameraAccess_1.CameraAccess.getCameras(false, true)]; case 3: cameras = _d.sent(); if (this.cameraSwitcherEnabled && cameras.length > 1) { this.gui.setCameraSwitcherVisible(true); } initialCameraDeviceId_1 = (_c = (_b = (_a = this.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks()[0]) === null || _b === void 0 ? void 0 : _b.getSettings) === null || _c === void 0 ? void 0 : _c.call(_b).deviceId; if (!(this.mediaStream != null && initialCamera_1 != null)) return [3 /*break*/, 8]; activeCamera = cameras.length === 1 ? cameras[0] : cameras.find(function (camera) { return (camera.deviceId === initialCameraDeviceId_1 || (camera.label !== "" && camera.label === (initialCamera_1 === null || initialCamera_1 === void 0 ? void 0 : initialCamera_1.label))); }); if (!(activeCamera != null)) return [3 /*break*/, 7]; cameraAccess_1.CameraAccess.adjustCameraFromMediaStream(this.mediaStream, activeCamera); if (browserHelper_1.BrowserHelper.isDesktopDevice()) { // When the device is a desktop/laptop, we store the initial camera as it should be considered the main one // for its camera type and the currently set camera type (which might be different) cameraAccess_1.CameraAccess.mainCameraForTypeOverridesOnDesktop.set(this.cameraType, activeCamera); cameraAccess_1.CameraAccess.mainCameraForTypeOverridesOnDesktop.set(activeCamera.cameraType, activeCamera); } if (!(cameras.length === 1 || cameraAccess_1.CameraAccess.getMainCameraForType(cameras, this.cameraType) === activeCamera)) return [3 /*break*/, 5]; logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Initial camera access was correct (main camera), keep camera:", activeCamera); this.setSelectedCamera(activeCamera); this.updateActiveCameraCurrentResolution(activeCamera); return [4 /*yield*/, this.recoverStreamIfNeeded()]; case 4: _d.sent(); return [2 /*return*/]; case 5: logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Initial camera access was incorrect (not main camera), change camera", tslib_1.__assign(tslib_1.__assign({}, initialCamera_1), { deviceId: initialCameraDeviceId_1 })); _d.label = 6; case 6: return [3 /*break*/, 8]; case 7: logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Initial camera access was incorrect (unknown camera), change camera", tslib_1.__assign(tslib_1.__assign({}, initialCamera_1), { deviceId: initialCameraDeviceId_1 })); _d.label = 8; case 8: if (!(this.selectedCamera == null)) return [3 /*break*/, 10]; return [4 /*yield*/, this.accessAutoselectedCamera(cameras)]; case 9: return [2 /*return*/, _d.sent()]; case 10: return [4 /*yield*/, this.initializeCameraWithSettings(this.selectedCamera, this.selectedCameraSettings)]; case 11: return [2 /*return*/, _d.sent()]; case 12: return [3 /*break*/, 14]; case 13: this.gui.setVideoVisible(true); this.cameraSetupPromise = undefined; return [7 /*endfinally*/]; case 14: return [2 /*return*/]; } }); }); }; CameraManager.prototype.getInitialCameraResolutionConstraint = function () { var _a; var cameraResolutionConstraint; switch ((_a = this.activeCameraSettings) === null || _a === void 0 ? void 0 : _a.resolutionPreference) { case cameraSettings_1.CameraSettings.ResolutionPreference.ULTRA_HD: cameraResolutionConstraint = CameraResolutionConstraint.ULTRA_HD; break; case cameraSettings_1.CameraSettings.ResolutionPreference.FULL_HD: cameraResolutionConstraint = CameraResolutionConstraint.FULL_HD; break; case cameraSettings_1.CameraSettings.ResolutionPreference.HD: default: cameraResolutionConstraint = CameraResolutionConstraint.HD; break; } return cameraResolutionConstraint; }; CameraManager.prototype.accessAutoselectedCamera = function (cameras) { return tslib_1.__awaiter(this, void 0, void 0, function () { var autoselectedCamera, error_2; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: cameras = cameraAccess_1.CameraAccess.sortCamerasForCameraType(cameras, this.cameraType); autoselectedCamera = cameras.shift(); _a.label = 1; case 1: if (!(autoselectedCamera != null)) return [3 /*break*/, 6]; _a.label = 2; case 2: _a.trys.push([2, 4, , 5]); return [4 /*yield*/, this.initializeCameraWithSettings(autoselectedCamera, this.selectedCameraSettings)]; case 3: return [2 /*return*/, _a.sent()]; case 4: error_2 = _a.sent(); this.setSelectedCamera(); if (cameras.length === 1) { this.gui.setCameraSwitcherVisible(false); } if (cameras.length >= 1) { logger_1.Logger.log(logger_1.Logger.Level.WARN, "Couldn't access camera:", autoselectedCamera, error_2); autoselectedCamera = cameras.shift(); return [3 /*break*/, 1]; } throw error_2; case 5: return [3 /*break*/, 1]; case 6: throw new customError_1.CustomError(CameraManager.noCameraErrorParameters); } }); }); }; CameraManager.prototype.accessInitialCamera = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var initialCamera, _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: initialCamera = { deviceId: "", label: "", cameraType: this.cameraType, }; _b.label = 1; case 1: _b.trys.push([1, 3, 4, 5]); return [4 /*yield*/, this.initializeCameraWithSettings(initialCamera, this.selectedCameraSettings)]; case 2: _b.sent(); return [3 /*break*/, 5]; case 3: _a = _b.sent(); return [3 /*break*/, 5]; case 4: this.setSelectedCamera(); return [7 /*endfinally*/]; case 5: return [2 /*return*/, initialCamera]; } }); }); }; CameraManager.prototype.updateActiveCameraCurrentResolution = function (camera) { if (this.gui.videoElement.videoWidth > 2 && this.gui.videoElement.videoHeight > 2) { camera.currentResolution = { width: this.gui.videoElement.videoWidth, height: this.gui.videoElement.videoHeight, }; } // If it's the initial camera, do nothing: if and when the camera is later confirmed to be the // correct (main with wanted type or only) one this method will be called again with the right camera object if (camera.deviceId !== "") { this.activeCamera = camera; this.gui.setMirrorImageEnabled(this.gui.isMirrorImageEnabled(), false); if (this.isCameraFOVSwitcherAllowed()) { this.gui.setCameraFOVSwitcherState(cameraAccess_1.CameraAccess.isIOSUltraWideBackCameraLabel(this.activeCamera.label)); this.gui.setCameraFOVSwitcherVisible(true); } } }; CameraManager.prototype.postStreamInitialization = function () { var _this = this; window.clearTimeout(this.getCapabilitiesTimeout); this.getCapabilitiesTimeout = window.setTimeout(function () { var _a; _this.storeStreamCapabilities(); _this.setupAutofocus(); if (_this.torchToggleEnabled && _this.mediaStream != null && ((_a = _this.mediaTrackCapabilities) === null || _a === void 0 ? void 0 : _a.torch) === true) { _this.gui.setTorchTogglerVisible(true); } }, CameraManager.getCapabilitiesTimeoutMs); }; CameraManager.prototype.videoResizeHandle = function () { if (this.activeCamera != null) { this.updateActiveCameraCurrentResolution(this.activeCamera); } }; CameraManager.prototype.checkCameraVideoStreamAccessIfVisible = function () { if (document.visibilityState === "visible") { logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Page is visible again, waiting for camera video stream start..."); document.removeEventListener("visibilitychange", this.checkCameraVideoStreamAccessIfVisibleListener); this.setCameraAccessTimeout(); } }; CameraManager.prototype.videoTrackEndedRecovery = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: logger_1.Logger.log(logger_1.Logger.Level.DEBUG, 'Detected video track "ended" event, try to reinitialize camera'); if (!(document.visibilityState !== "visible")) return [3 /*break*/, 1]; logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Page is currently not visible, delay camera reinitialization until visible"); document.addEventListener("visibilitychange", this.checkCameraVideoStreamAccessIfVisibleListener); return [3 /*break*/, 4]; case 1: _b.trys.push([1, 3, , 4]); return [4 /*yield*/, this.reinitializeCamera()]; case 2: _b.sent(); return [3 /*break*/, 4]; case 3: _a = _b.sent(); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; CameraManager.prototype.videoTrackMuteRecovery = function (event) { return tslib_1.__awaiter(this, void 0, void 0, function () { var isMuteEvent; return tslib_1.__generator(this, function (_a) { if (this.gui.videoElement.onloadeddata != null) { logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Detected video track \"".concat(event.type, "\" event, delay camera video stream access detection")); this.setCameraAccessTimeout(); return [2 /*return*/]; } isMuteEvent = event.type === "mute"; if (isMuteEvent !== this.gui.isCameraRecoveryVisible()) { logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Detected video track \"".concat(event.type, "\" event, ").concat(isMuteEvent ? "enable" : "disable", " camera recovery")); this.gui.setCameraRecoveryVisible(isMuteEvent); } return [2 /*return*/]; }); }); }; CameraManager.prototype.triggerManualFocusForContinuous = function () { var _a; return tslib_1.__awaiter(this, void 0, void 0, function () { var manualFocusResetNeeded, videoTracks; var _this = this; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: if (this.mediaStream == null) { return [2 /*return*/]; } this.manualToAutofocusResumeTimeout = window.setTimeout(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.triggerFocusMode(MeteringMode.CONTINUOUS)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }, CameraManager.manualToAutofocusResumeTimeoutMs); manualFocusResetNeeded = true; videoTracks = this.mediaStream.getVideoTracks(); // istanbul ignore else if (videoTracks.length !== 0 && typeof videoTracks[0].getConstraints === "function") { manualFocusResetNeeded = ((_a = videoTracks[0].getConstraints().advanced) === null || _a === void 0 ? void 0 : _a.some(function (constraint) { return constraint.focusMode === MeteringMode.MANUAL; })) === true; } if (!manualFocusResetNeeded) return [3 /*break*/, 2]; return [4 /*yield*/, this.triggerFocusMode(MeteringMode.CONTINUOUS)]; case 1: _b.sent(); this.manualFocusWaitTimeout = window.setTimeout(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.triggerFocusMode(MeteringMode.MANUAL)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }, CameraManager.manualFocusWaitTimeoutMs); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, this.triggerFocusMode(MeteringMode.MANUAL)]; case 3: _b.sent(); _b.label = 4; case 4: return [2 /*return*/]; } }); }); }; CameraManager.prototype.triggerManualFocusForSingleShot = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var _a; var _this = this; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: window.clearInterval(this.autofocusInterval); this.manualToAutofocusResumeTimeout = window.setTimeout(function () { _this.autofocusInterval = window.setInterval(_this.triggerAutoFocus.bind(_this), CameraManager.autofocusIntervalMs); }, CameraManager.manualToAutofocusResumeTimeoutMs); _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); return [4 /*yield*/, this.triggerFocusMode(MeteringMode.SINGLE_SHOT)]; case 2: _b.sent(); return [3 /*break*/, 4]; case 3: _a = _b.sent(); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; CameraManager.prototype.triggerManualFocus = function (event) { return tslib_1.__awaiter(this, void 0, void 0, function () { var focusModeCapability; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (event != null) { event.preventDefault(); if (event.type === "touchend" && event.touches.length !== 0) { return [2 /*return*/]; } // Check if we were using pinch-to-zoom if (this.pinchToZoomDistance != null) { this.pinchToZoomDistance = undefined; return [2 /*return*/]; } } window.clearTimeout(this.manualFocusWaitTimeout); window.clearTimeout(this.manualToAutofocusResumeTimeout); if (!(this.mediaStream != null && this.mediaTrackCapabilities != null)) return [3 /*break*/, 4]; focusModeCapability = this.mediaTrackCapabilities.focusMode; if (!(focusModeCapability instanceof Array)) return [3 /*break*/, 4]; if (!(focusModeCapability.includes(MeteringMode.CONTINUOUS) && focusModeCapability.includes(MeteringMode.MANUAL))) return [3 /*break*/, 2]; return [4 /*yield*/, this.triggerManualFocusForContinuous()]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: if (!focusModeCapability.includes(MeteringMode.SINGLE_SHOT)) return [3 /*break*/, 4]; return [4 /*yield*/, this.triggerManualFocusForSingleShot()]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/]; } }); }); }; CameraManager.prototype.triggerZoomStart = function (event) { var _a; if ((event === null || event === void 0 ? void 0 : event.touches.length) !== 2) { return; } event.preventDefault(); this.pinchToZoomDistance = Math.hypot((event.touches[1].screenX - event.touches[0].screenX) / screen.width, (event.touches[1].screenY - event.touches[0].screenY) / screen.height); if (this.mediaStream != null && ((_a = this.mediaTrackCapabilities) === null || _a === void 0 ? void 0 : _a.zoom) != null) { var videoTracks = this.mediaStream.getVideoTracks(); // istanbul ignore else if (videoTracks.length !== 0 && typeof videoTracks[0].getConstraints === "function") { this.pinchToZoomInitialZoom = this.mediaTrackCapabilities.zoom.min; var currentConstraints = videoTracks[0].getConstraints(); if (currentConstraints.advanced != null) { var currentZoomConstraint = currentConstraints.advanced.find(function (constraint) { return "zoom" in constraint; }); if ((currentZoomConstraint === null || currentZoomConstraint === void 0 ? void 0 : currentZoomConstraint.zoom) != null) { this.pinchToZoomInitialZoom = currentZoomConstraint.zoom; } } } } }; CameraManager.prototype.triggerZoomMove = function (event) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (this.pinchToZoomDistance == null || (event === null || event === void 0 ? void 0 : event.touches.length) !== 2) { return [2 /*return*/]; } event.preventDefault(); return [4 /*yield*/, this.setZoom((Math.hypot((event.touches[1].screenX - event.touches[0].screenX) / screen.width, (event.touches[1].screenY - event.touches[0].screenY) / screen.height) - this.pinchToZoomDistance) * 2, this.pinchToZoomInitialZoom)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; CameraManager.prototype.storeStreamCapabilities = function () { var _a; // istanbul ignore else if (this.mediaStream != null) { var videoTracks = this.mediaStream.getVideoTracks(); // istanbul ignore else if (videoTracks.length !== 0 && typeof videoTracks[0].getCapabilities === "function") { this.mediaTrackCapabilities = videoTracks[0].getCapabilities(); } } if (this.activeCamera != null) { this.scanner.reportCameraProperties(this.activeCamera.cameraType, ((_a = this.mediaTrackCapabilities) === null || _a === void 0 ? void 0 : _a.focusMode) == null || // assume the camera supports autofocus by default this.mediaTrackCapabilities.focusMode.includes(MeteringMode.CONTINUOUS)); } }; CameraManager.prototype.setupAutofocus = function () { window.clearTimeout(this.manualFocusWaitTimeout); window.clearTimeout(this.manualToAutofocusResumeTimeout); // istanbul ignore else if (this.mediaStream != null && this.mediaTrackCapabilities != null) { var focusModeCapability = this.mediaTrackCapabilities.focusMode; if (focusModeCapability instanceof Array && !focusModeCapability.includes(MeteringMode.CONTINUOUS) && focusModeCapability.includes(MeteringMode.SINGLE_SHOT)) { window.clearInterval(this.autofocusInterval); this.autofocusInterval = window.setInterval(this.triggerAutoFocus.bind(this), CameraManager.autofocusIntervalMs); } } }; CameraManager.prototype.triggerAutoFocus = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.triggerFocusMode(MeteringMode.SINGLE_SHOT)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; CameraManager.prototype.triggerFocusMode = function (focusMode) { return tslib_1.__awaiter(this, void 0, void 0, function () { var videoTracks, _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: if (!(this.mediaStream != null)) return [3 /*break*/, 4]; videoTracks = this.mediaStream.getVideoTracks(); if (!(videoTracks.length !== 0 && typeof videoTracks[0].applyConstraints === "function")) return [3 /*break*/, 4]; _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); return [4 /*yield*/, videoTracks[0].applyConstraints({ advanced: [{ focusMode: focusMode }] })]; case 2: _b.sent(); return [3 /*break*/, 4]; case 3: _a = _b.sent(); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; CameraManager.prototype.enableTapToFocusListeners = function () { var _this = this; ["touchend", "mousedown"].forEach(function (eventName) { _this.gui.videoElement.addEventListener(eventName, _this.triggerManualFocusListener); }); }; CameraManager.prototype.enablePinchToZoomListeners = function () { this.gui.videoElement.addEventListener("touchstart", this.triggerZoomStartListener); this.gui.videoElement.addEventListener("touchmove", this.triggerZoomMoveListener); }; CameraManager.prototype.disableTapToFocusListeners = function () { var _this = this; ["touchend", "mousedown"].forEach(function (eventName) { _this.gui.videoElement.removeEventListener(eventName, _this.triggerManualFocusListener); }); }; CameraManager.prototype.disablePinchToZoomListeners = function () { this.gui.videoElement.removeEventListener("touchstart", this.triggerZoomStartListener); this.gui.videoElement.removeEventListener("touchmove", this.triggerZoomMoveListener); }; CameraManager.prototype.initializeCameraAndCheckUpdatedSettings = function (camera) { return tslib_1.__awaiter(this, void 0, void 0, function () { var _this = this; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, , 4, 5]); return [4 /*yield*/, this.initializeCameraForResolution(camera)]; case 1: _a.sent(); if (!(this.selectedCameraSettings !== this.activeCameraSettings && (this.selectedCameraSettings == null || this.activeCameraSettings == null || Object.keys(this.selectedCameraSettings).some(function (cameraSettingsProperty) { return (_this.selectedCameraSettings[cameraSettingsProperty] !== _this.activeCameraSettings[cameraSettingsProperty]); })))) return [3 /*break*/, 3]; this.activeCameraSettings = this.selectedCameraSettings; return [4 /*yield*/, this.initializeCameraAndCheckUpdatedSettings(camera)]; case 2: return [2 /*return*/, _a.sent()]; case 3: return [3 /*break*/, 5]; case 4: this.cameraInitializationPromise = undefined; return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; CameraManager.prototype.handleCameraInitializationError = function (camera, cameraResolutionConstraint, error) { return tslib_1.__awaiter(this, void 0, void 0, function () { var currentCameraDeviceId; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!["OverconstrainedError", "NotReadableError"].includes(error.name) || (error.name === "NotReadableError" && cameraResolutionConstraint === CameraResolutionConstraint.NONE)) { // Camera is not accessible at all logger_1.Logger.log(logger_1.Logger.Level.DEBUG, "Camera video stream access failure (unrecoverable error)", camera, error); if (error.name !== "NotAllowedError") { cameraAccess_1.CameraAccess.markCameraAsInaccessible(camera); } throw error; } if (!(error.name === "OverconstrainedError" && cameraResolutionConstraint === CameraResolutionConstraint.NONE)) return [3 /*break*/, 2]; // Camera device has changed deviceId // We can't rely on