diff --git a/package.json b/package.json index 732e5604..54ff5ce8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ericblade/quagga2", - "version": "1.2.1", + "version": "1.2.3", "description": "An advanced barcode-scanner written in JavaScript", "main": "lib/quagga.js", "types": "type-definitions/quagga.d.ts", diff --git a/src/input/camera_access.ts b/src/input/camera_access.ts index 8f583229..da15b5da 100644 --- a/src/input/camera_access.ts +++ b/src/input/camera_access.ts @@ -1,6 +1,6 @@ import pick from 'lodash/pick'; import { getUserMedia, enumerateDevices } from '../common/mediaDevices'; -import { MediaTrackConstraintsWithDeprecated } from '../../type-definitions/quagga.d'; +import { MediaTrackConstraintsWithDeprecated, QuaggaJSCameraAccess as CameraAccessType } from '../../type-definitions/quagga.d'; let streamRef: MediaStream | null; @@ -92,18 +92,28 @@ function getActiveTrack(): MediaStreamTrack | null { /** * Used for accessing information about the active stream track and available video devices. */ -const QuaggaJSCameraAccess = { +const QuaggaJSCameraAccess: CameraAccessType = { + requestedVideoElement: null, async request(video: HTMLVideoElement, videoConstraints?: MediaTrackConstraintsWithDeprecated): Promise { + QuaggaJSCameraAccess.requestedVideoElement = video; const newConstraints = await pickConstraints(videoConstraints); return initCamera(video, newConstraints); }, - release(): void { - // TODO: i wonder if telling the Video element to pause() before calling MediaStreamTrack.stop() would alleviate some of the issues with the camera appearing to stay open on Android even after stopping. + release(): Promise { const tracks = streamRef && streamRef.getVideoTracks(); - if (tracks && tracks.length) { - tracks[0].stop(); + if (QuaggaJSCameraAccess.requestedVideoElement !== null) { + QuaggaJSCameraAccess.requestedVideoElement.pause(); } - streamRef = null; + return new Promise((resolve) => { + setTimeout(() => { + if (tracks && tracks.length) { + tracks[0].stop(); + } + streamRef = null; + QuaggaJSCameraAccess.requestedVideoElement = null; + resolve(); + }); + }); }, enumerateVideoDevices, getActiveStreamLabel(): string { diff --git a/src/input/test/browser/camera_access.spec.ts b/src/input/test/browser/camera_access.spec.ts index bfe8e900..bc5d824b 100644 --- a/src/input/test/browser/camera_access.spec.ts +++ b/src/input/test/browser/camera_access.spec.ts @@ -112,7 +112,7 @@ describe('CameraAccess (browser)', () => { it('works', async () => { const video = document.createElement('video'); await Quagga.CameraAccess.request(video, {}); - Quagga.CameraAccess.release(); + await Quagga.CameraAccess.release(); expect(((video?.srcObject) as any)?.active).to.equal(false); }); }); diff --git a/src/quagga.js b/src/quagga.js index 694fc740..9ab9a353 100644 --- a/src/quagga.js +++ b/src/quagga.js @@ -1,3 +1,4 @@ +import merge from 'lodash/merge'; import TypeDefs from './common/typedefs'; // eslint-disable-line no-unused-vars import ImageWrapper from './common/image_wrapper'; import BarcodeDecoder from './decoder/barcode_decoder'; @@ -7,7 +8,6 @@ import CameraAccess from './input/camera_access'; import ImageDebug from './common/image_debug'; import ResultCollector from './analytics/result_collector'; import Config from './config/config'; -import merge from 'lodash/merge'; import Quagga from './quagga/quagga'; @@ -39,10 +39,10 @@ const QuaggaJSStaticInterface = { return promise; }, start: function () { - instance.start(); + return instance.start(); }, stop: function () { - instance.stop(); + return instance.stop(); }, pause: function () { _context.stopped = true; diff --git a/src/quagga/quagga.ts b/src/quagga/quagga.ts index 885c983c..5429e48c 100644 --- a/src/quagga/quagga.ts +++ b/src/quagga/quagga.ts @@ -256,11 +256,11 @@ export default class Quagga { } } - stop(): void { + async stop(): Promise { this.context.stopped = true; QWorkers.adjustWorkerPool(0); if (this.context.config?.inputStream && this.context.config.inputStream.type === 'LiveStream') { - CameraAccess.release(); + await CameraAccess.release(); this.context.inputStream.clearEventHandlers(); } } diff --git a/test/test-import.js b/test/test-import.js index bf2c65a3..89e17a4b 100644 --- a/test/test-import.js +++ b/test/test-import.js @@ -15,7 +15,7 @@ describe('testing node import', () => { const { CameraAccess: CA } = Q; expect(CA).to.be.an('object').with.keys([ 'request', 'release', 'enumerateVideoDevices', - 'getActiveStreamLabel', 'getActiveTrack', + 'getActiveStreamLabel', 'getActiveTrack', 'requestedVideoElement', ]); }); }); diff --git a/type-definitions/quagga.d.ts b/type-definitions/quagga.d.ts index 9e901e5b..6c2b1dfd 100644 --- a/type-definitions/quagga.d.ts +++ b/type-definitions/quagga.d.ts @@ -118,13 +118,13 @@ export interface QuaggaJSStatic { init( config: QuaggaJSConfigObject, callback?: (err: any) => void - ): void; + ): Promise; init( config: QuaggaJSConfigObject, callback: (err: any) => void, imageWrapper: ImageWrapper, - ): void; + ): Promise; /** * When the library is initialized, the start() @@ -139,7 +139,7 @@ export interface QuaggaJSStatic { * Additionally, if a camera-stream was requested upon initialization, * this operation also disconnects the camera. */ - stop(): void; + stop(): Promise; /** * Pauses processing, but does not release any handlers @@ -220,9 +220,10 @@ export interface QuaggaJSStatic { * Used for accessing information about the active stream track and available video devices. */ export interface QuaggaJSCameraAccess { - request(video: HTMLVideoElement, videoConstraints: MediaTrackConstraintsWithDeprecated): Promise | never; + requestedVideoElement: HTMLVideoElement | null, + request(video: HTMLVideoElement, videoConstraints?: MediaTrackConstraintsWithDeprecated): Promise | never; - release(): void; + release(): Promise; enumerateVideoDevices(): Promise | never;