{"version":3,"file":"useWebCameraStream.js","sourceRoot":"","sources":["../src/useWebCameraStream.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,mBAAmB,GAAG;IAC1B,WAAW;IACX,WAAW;IACX,sBAAsB;IACtB,kBAAkB;IAClB,KAAK;IACL,YAAY;IACZ,UAAU;IACV,YAAY;IACZ,WAAW;IACX,eAAe;IACf,cAAc;IACd,MAAM;CACP,CAAC;AAEF,SAAS,cAAc,CAAC,KAA8B,EAAE,QAAoB;IAC1E,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,KAAK,EAAE;YACT,KAAK,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,GAAG,EAAE;gBAC5C,kFAAkF;gBAClF,iFAAiF;gBACjF,2EAA2E;gBAC3E,qBAAqB,CAAC,GAAG,EAAE;oBACzB,QAAQ,EAAE,CAAC;gBACb,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;SACJ;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAsD,EACtD,aAAyB,EACzB,QAA6B,EAC7B,EACE,aAAa,EACb,YAAY,GAC+D;IAK7E,MAAM,gBAAgB,GAAG,KAAK,CAAC,MAAM,CAAiB,KAAK,CAAC,CAAC;IAC7D,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAgB,EAAE,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAoB;QACnD,SAAS,EAAE,YAAY;QACvB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,YAAY;QAC1B,IAAI,EAAE,CAAC;KACR,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAErE,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QAC5C,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,gFAAgF;IAChF,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QAC9B,IAAI,CAAC,kBAAkB,EAAE;YACvB,OAAO,IAAI,CAAC;SACb;QACD,gGAAgG;QAChG,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,GAAG,kBAAkB,CAAC;QACnD,OAAO,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAEzB,MAAM,oBAAoB,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,IAAiC,EAAE;QACrF,IAAI;YACF,OAAO,MAAM,KAAK,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC;SAC5D;QAAC,OAAO,WAAW,EAAE;YACpB,IAAI,OAAO,EAAE;gBACX,OAAO,CAAC,IAAI,CAAC,wCAAwC,aAAa,IAAI,EAAE,WAAW,CAAC,CAAC;aACtF;YACD,IAAI,YAAY,EAAE;gBAChB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;aAC/B;YACD,OAAO,IAAI,CAAC;SACb;IACH,CAAC,EAAE,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC;IAElC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,IAAsB,EAAE;QACjE,MAAM,UAAU,GAAG,MAAM,oBAAoB,EAAE,CAAC;QAChD,IAAI,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE;YAC5C,0CAA0C;YAC1C,yIAAyI;YACzI,uEAAuE;YACvE,OAAO,KAAK,CAAC;SACd;QAED,gFAAgF;QAChF,6DAA6D;QAC7D,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,UAAU,EAAE,EAAE,CAAC,EAAE;YACvE,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,UAAW,CAAC,CAAC;SACzC;QAED,4EAA4E;QAC5E,SAAS,CAAC,UAAU,CAAC,CAAC;QACtB,IAAI,aAAa,EAAE;YACjB,aAAa,EAAE,CAAC;SACjB;QACD,OAAO,KAAK,CAAC;IACf,CAAC,EAAE,CAAC,oBAAoB,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpF,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,mDAAmD;QACnD,IAAI,gBAAgB,CAAC,OAAO,EAAE;YAC5B,OAAO;SACR;QACD,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC;QAEhC,WAAW,EAAE;aACV,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;YACnB,gBAAgB,CAAC,OAAO,GAAG,UAAU,CAAC;QACxC,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,0CAA0C;YAC1C,gBAAgB,CAAC,OAAO,GAAG,KAAK,CAAC;QACnC,CAAC,CAAC,CAAC;IACP,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;IAEpB,yDAAyD;IACzD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,OAAO,GAAsB,EAAE,CAAC;QAEtC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;YACvC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;gBACtC,SAAS;aACV;YACD,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,SAAS,KAAK,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;gBAC3C,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;aAC1B;SACF;QAED,sDAAsD;QACtD,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QAEjD,MAAM,qBAAqB,GAAG,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;QACtE,IAAI,UAAU,EAAE;YACd,KAAK,CAAC,qBAAqB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;SAC7D;QAED,YAAY,CAAC,OAAO,GAAG,qBAAqB,CAAC;IAC/C,CAAC,EAAE;QACD,QAAQ,CAAC,SAAS;QAClB,QAAQ,CAAC,SAAS;QAClB,QAAQ,CAAC,oBAAoB;QAC7B,QAAQ,CAAC,gBAAgB;QACzB,QAAQ,CAAC,GAAG;QACZ,QAAQ,CAAC,UAAU;QACnB,QAAQ,CAAC,QAAQ;QACjB,QAAQ,CAAC,UAAU;QACnB,QAAQ,CAAC,SAAS;QAClB,QAAQ,CAAC,aAAa;QACtB,QAAQ,CAAC,YAAY;QACrB,QAAQ,CAAC,IAAI;KACd,CAAC,CAAC;IAEH,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,iCAAiC;QACjC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;YAClB,OAAO;SACR;QACD,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAE5B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,OAAO,GAAG,EAAE;YACV,mHAAmH;YACnH,KAAK,MAAM,MAAM,IAAI,aAAa,CAAC,OAAO,EAAE;gBAC1C,0BAA0B;gBAC1B,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;aAC/B;YACD,IAAI,KAAK,CAAC,OAAO,EAAE;gBACjB,+BAA+B;gBAC/B,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;aAC7C;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,qCAAqC;IACrC,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE;QACjC,KAAK,CAAC,qBAAqB,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI;QACJ,kBAAkB;KACnB,CAAC;AACJ,CAAC","sourcesContent":["/* eslint-env browser */\nimport * as React from 'react';\n\nimport {\n CameraReadyListener,\n CameraType,\n MountErrorListener,\n WebCameraSettings,\n} from './Camera.types';\nimport * as Utils from './WebCameraUtils';\nimport { FacingModeToCameraType } from './WebConstants';\n\nconst VALID_SETTINGS_KEYS = [\n 'autoFocus',\n 'flashMode',\n 'exposureCompensation',\n 'colorTemperature',\n 'iso',\n 'brightness',\n 'contrast',\n 'saturation',\n 'sharpness',\n 'focusDistance',\n 'whiteBalance',\n 'zoom',\n];\n\nfunction useLoadedVideo(video: HTMLVideoElement | null, onLoaded: () => void) {\n React.useEffect(() => {\n if (video) {\n video.addEventListener('loadedmetadata', () => {\n // without this async block the constraints aren't properly applied to the camera,\n // this means that if you were to turn on the torch and swap to the front camera,\n // then swap back to the rear camera the torch setting wouldn't be applied.\n requestAnimationFrame(() => {\n onLoaded();\n });\n });\n }\n }, [video]);\n}\n\nexport function useWebCameraStream(\n video: React.MutableRefObject,\n preferredType: CameraType,\n settings: Record,\n {\n onCameraReady,\n onMountError,\n }: { onCameraReady?: CameraReadyListener; onMountError?: MountErrorListener }\n): {\n type: CameraType | null;\n mediaTrackSettings: MediaTrackSettings | null;\n} {\n const isStartingCamera = React.useRef(false);\n const activeStreams = React.useRef([]);\n const capabilities = React.useRef({\n autoFocus: 'continuous',\n flashMode: 'off',\n whiteBalance: 'continuous',\n zoom: 1,\n });\n const [stream, setStream] = React.useState(null);\n\n const mediaTrackSettings = React.useMemo(() => {\n return stream ? stream.getTracks()[0].getSettings() : null;\n }, [stream]);\n\n // The actual camera type - this can be different from the incoming camera type.\n const type = React.useMemo(() => {\n if (!mediaTrackSettings) {\n return null;\n }\n // On desktop no value will be returned, in this case we should assume the cameraType is 'front'\n const { facingMode = 'user' } = mediaTrackSettings;\n return FacingModeToCameraType[facingMode];\n }, [mediaTrackSettings]);\n\n const getStreamDeviceAsync = React.useCallback(async (): Promise => {\n try {\n return await Utils.getPreferredStreamDevice(preferredType);\n } catch (nativeEvent) {\n if (__DEV__) {\n console.warn(`Error requesting UserMedia for type \"${preferredType}\":`, nativeEvent);\n }\n if (onMountError) {\n onMountError({ nativeEvent });\n }\n return null;\n }\n }, [preferredType, onMountError]);\n\n const resumeAsync = React.useCallback(async (): Promise => {\n const nextStream = await getStreamDeviceAsync();\n if (Utils.compareStreams(nextStream, stream)) {\n // Do nothing if the streams are the same.\n // This happens when the device only supports one camera (i.e. desktop) and the mode was toggled between front/back while already active.\n // Without this check there is a screen flash while the video switches.\n return false;\n }\n\n // Save a history of all active streams (usually 2+) so we can close them later.\n // Keeping them open makes swapping camera types much faster.\n if (!activeStreams.current.some((value) => value.id === nextStream?.id)) {\n activeStreams.current.push(nextStream!);\n }\n\n // Set the new stream -> update the video, settings, and actual camera type.\n setStream(nextStream);\n if (onCameraReady) {\n onCameraReady();\n }\n return false;\n }, [getStreamDeviceAsync, setStream, onCameraReady, stream, activeStreams.current]);\n\n React.useEffect(() => {\n // Restart the camera and guard concurrent actions.\n if (isStartingCamera.current) {\n return;\n }\n isStartingCamera.current = true;\n\n resumeAsync()\n .then((isStarting) => {\n isStartingCamera.current = isStarting;\n })\n .catch(() => {\n // ensure the camera can be started again.\n isStartingCamera.current = false;\n });\n }, [preferredType]);\n\n // Update the native camera with any custom capabilities.\n React.useEffect(() => {\n const changes: WebCameraSettings = {};\n\n for (const key of Object.keys(settings)) {\n if (!VALID_SETTINGS_KEYS.includes(key)) {\n continue;\n }\n const nextValue = settings[key];\n if (nextValue !== capabilities.current[key]) {\n changes[key] = nextValue;\n }\n }\n\n // Only update the native camera if changes were found\n const hasChanges = !!Object.keys(changes).length;\n\n const nextWebCameraSettings = { ...capabilities.current, ...changes };\n if (hasChanges) {\n Utils.syncTrackCapabilities(preferredType, stream, changes);\n }\n\n capabilities.current = nextWebCameraSettings;\n }, [\n settings.autoFocus,\n settings.flashMode,\n settings.exposureCompensation,\n settings.colorTemperature,\n settings.iso,\n settings.brightness,\n settings.contrast,\n settings.saturation,\n settings.sharpness,\n settings.focusDistance,\n settings.whiteBalance,\n settings.zoom,\n ]);\n\n React.useEffect(() => {\n // set or unset the video source.\n if (!video.current) {\n return;\n }\n Utils.setVideoSource(video.current, stream);\n }, [video.current, stream]);\n\n React.useEffect(() => {\n return () => {\n // Clean up on dismount, this is important for making sure the camera light goes off when the component is removed.\n for (const stream of activeStreams.current) {\n // Close all open streams.\n Utils.stopMediaStream(stream);\n }\n if (video.current) {\n // Invalidate the video source.\n Utils.setVideoSource(video.current, stream);\n }\n };\n }, []);\n\n // Update props when the video loads.\n useLoadedVideo(video.current, () => {\n Utils.syncTrackCapabilities(preferredType, stream, capabilities.current);\n });\n\n return {\n type,\n mediaTrackSettings,\n };\n}\n"]}