diff --git a/src/components/autozoomControl.ts b/src/components/autozoomControl.ts index 15d69828..6eca1c36 100644 --- a/src/components/autozoomControl.ts +++ b/src/components/autozoomControl.ts @@ -112,7 +112,10 @@ export default class AutozoomControl implements IAutozoomControl { throw Error(`Option 'shouldAutoFrame' cannot not be set to ${options.shouldAutoFrame}`); } - if (!options.shouldAutoFrame && options.mode !== AutozoomModes.NORMAL) { + if ( + !options.shouldAutoFrame && + ![AutozoomModes.NORMAL, AutozoomModes.PLAZA].includes(options.mode) + ) { const modeName = options.mode; throw Error( `AutozoomMode '${modeName}' does not support option 'shouldAutoFrame' set to ${options.shouldAutoFrame}!` diff --git a/src/components/detector.ts b/src/components/detector.ts index 288161a0..68705ee7 100644 --- a/src/components/detector.ts +++ b/src/components/detector.ts @@ -13,6 +13,9 @@ import CameraEvents from './../utilitis/events'; import semver from 'semver'; import TypeHelper from './../utilitis/typehelper'; import DetectionsConverter from './../utilitis/detectionsConverter'; +import FramingModes from '@huddly/sdk-interfaces/lib/enums/FramingModes'; +import MsgBusSubscriber from './msgBusSubscriber'; +import { MsgBusSubscriberOptions } from '@huddly/sdk-interfaces/lib/interfaces/IMsgBusSubscriber'; const PREVIEW_IMAGE_SIZE = { width: 640, height: 480 }; const LATEST_WITHOUT_PEOPLE_COUNT = '1.3.14'; @@ -46,6 +49,15 @@ export default class Detector extends EventEmitter implements IDetector { _previewStreamStarted: boolean = false; /** @ignore */ _usePeopleCount: boolean = false; + /** @ignore */ + _detectionSubscriber: MsgBusSubscriber; + /** @ignore */ + _framingSubscriber: MsgBusSubscriber; + /** @ignore */ + _supportedFramingSubscriptions: Array = [ + FramingModes.NORMAL, + FramingModes.GALLERY_VIEW, + ]; constructor(manager: IDeviceManager, options?: DetectorOpts) { super(); @@ -53,6 +65,14 @@ export default class Detector extends EventEmitter implements IDetector { this._options = {}; this._validateOptions(options); this.setMaxListeners(50); + this._detectionSubscriber = new MsgBusSubscriber( + manager.transport as IUsbTransport, + this._detectionHandler + ); + this._framingSubscriber = new MsgBusSubscriber( + manager.transport as IUsbTransport, + this._framingHandler + ); } /** @@ -87,6 +107,13 @@ export default class Detector extends EventEmitter implements IDetector { throw new Error('Unable to talk to device. Tarnsport must be UsbTransport compatible'); } + framingSubscriptionCommandMap(framing: FramingModes): string { + return { + [FramingModes.NORMAL]: 'autozoom/framing', + [FramingModes.GALLERY_VIEW]: 'autozoom/plaza/framing', + }[framing]; + } + /** * Convenience function for setting detection and/or framing data event listeners. * @@ -240,24 +267,24 @@ export default class Detector extends EventEmitter implements IDetector { listenerConfigOpts: any = { detectionListener: true, framingListener: true, + framingMode: FramingModes.NORMAL, } ) { try { + const { detectionListener, framingListener } = listenerConfigOpts; + const framingMode = listenerConfigOpts.framingMode + ? listenerConfigOpts.framingMode + : FramingModes.NORMAL; // Detection listener setup - if (!this._subscriptionsSetup && listenerConfigOpts.detectionListener) { - await this.transport.subscribe('autozoom/predictions'); - this.transport.on('autozoom/predictions', this._detectionHandler); + if (!this._subscriptionsSetup && detectionListener) { + await this._detectionSubscriber.subscribe({ msgBusCmd: 'autozoom/predictions' }); } // Framing listener setup - if (!this._subscriptionsSetup && listenerConfigOpts.framingListener) { - await this.transport.subscribe('autozoom/framing'); - this.transport.on('autozoom/framing', this._framingHandler); + if (!this._subscriptionsSetup && framingListener) { + await this.updateFramingSubscriber(framingMode, this._framingHandler); } this._subscriptionsSetup = true; } catch (e) { - await this.transport.unsubscribe('autozoom/predictions'); - await this.transport.unsubscribe('autozoom/framing'); - Logger.error('Something went wrong getting predictions!', e, 'IQ Detector'); this._subscriptionsSetup = false; } } @@ -282,14 +309,12 @@ export default class Detector extends EventEmitter implements IDetector { ) { // Detection listener teardown if (this._subscriptionsSetup && listenerConfigOpts.detectionListener) { - await this.transport.unsubscribe('autozoom/predictions'); - this.transport.removeListener('autozoom/predictions', this._detectionHandler); + await this._detectionSubscriber.unsubscribe(); } // Framing listener teardown if (this._subscriptionsSetup && listenerConfigOpts.framingListener) { - await this.transport.unsubscribe('autozoom/framing'); - this.transport.removeListener('autozoom/framing', this._framingHandler); + this._framingSubscriber.unsubscribe(); } this._subscriptionsSetup = false; } @@ -310,4 +335,28 @@ export default class Detector extends EventEmitter implements IDetector { }; return new DetectionsConverter(detections, converterOpts).convert(); } + + /** + * Update framing subscriber with new framing mode and/or subscription handler + * + * @param framingMode New framing mode to listen to + * @param subscriptionHandler New function for handling the incoming frame buffer + */ + async updateFramingSubscriber(framingMode: FramingModes, subscriptionHandler?: Function) { + if (!this._supportedFramingSubscriptions.includes(framingMode)) { + throw new Error( + `Framing mode ${framingMode} does not have support for framing subscriptions` + ); + } + + const framingSubscriberOptions: MsgBusSubscriberOptions = { + msgBusCmd: + framingMode !== undefined + ? this.framingSubscriptionCommandMap(framingMode) + : this._framingSubscriber.currentSubscription, + subscriptionHandler, + }; + + await this._framingSubscriber.subscribe(framingSubscriberOptions); + } } diff --git a/src/components/msgBusSubscriber.ts b/src/components/msgBusSubscriber.ts new file mode 100644 index 00000000..9cca11e6 --- /dev/null +++ b/src/components/msgBusSubscriber.ts @@ -0,0 +1,58 @@ +import IUsbTransport from '@huddly/sdk-interfaces/lib/interfaces/IUsbTransport'; +import IMsgBusSubscriber, { + MsgBusSubscriberOptions, +} from '@huddly/sdk-interfaces/lib/interfaces/IMsgBusSubscriber'; +import Logger from '@huddly/sdk-interfaces/lib/statics/Logger'; + +/** + * Class for handling framing subscriptions + */ +export default class MsgBusSubscriber implements IMsgBusSubscriber { + _transport: IUsbTransport; + _currentSubscription: string; + _subscriptionHandler: Function; + + constructor(transport: IUsbTransport, subscriptionHandler: Function) { + this._transport = transport; + this._subscriptionHandler = subscriptionHandler; + this._currentSubscription = undefined; + } + + get currentSubscription() { + return this._currentSubscription; + } + + /** + * Initialize the framing subscriber to use a given + * subscription handler and autozoom mode. + * @param {FramingSubscriberOptions} options + */ + async subscribe({ msgBusCmd, subscriptionHandler }: MsgBusSubscriberOptions): Promise { + if (this._currentSubscription) { + this.unsubscribe(); + } + + if (subscriptionHandler) { + this._subscriptionHandler = subscriptionHandler; + } + + try { + await this._transport.subscribe(msgBusCmd); + this._transport.on(msgBusCmd, this._subscriptionHandler); + this._currentSubscription = msgBusCmd; + } catch (err) { + await this.unsubscribe(); + Logger.error(`Unable to subscribe to ${msgBusCmd}`, err, MsgBusSubscriber.name); + throw err; + } + } + + /** + * Removes the subscription from the transport. + */ + async unsubscribe(): Promise { + await this._transport.unsubscribe(this._currentSubscription); + this._transport.removeListener(this._currentSubscription, this._subscriptionHandler); + this._currentSubscription = undefined; + } +} diff --git a/tests/components/autozoomControl.spec.ts b/tests/components/autozoomControl.spec.ts index 8061a3f4..acb67816 100644 --- a/tests/components/autozoomControl.spec.ts +++ b/tests/components/autozoomControl.spec.ts @@ -72,12 +72,12 @@ describe('AutozoomControl', () => { it('should throw exception for bad combination of opts', () => { const opts: AutozoomControlOpts = { - mode: AutozoomModes.PLAZA, + mode: AutozoomModes.SPEAKER_FRAMING, shouldAutoFrame: false, }; const badFn = () => new AutozoomControl(deviceManager, opts); expect(badFn).to.throw( - "AutozoomMode 'plaza' does not support option 'shouldAutoFrame' set to false!" + "AutozoomMode 'speaker_framing' does not support option 'shouldAutoFrame' set to false!" ); }); }); @@ -246,12 +246,12 @@ describe('AutozoomControl', () => { }); it('should throw exception for bad combination of opts', () => { const opts: AutozoomControlOpts = { - mode: AutozoomModes.PLAZA, + mode: AutozoomModes.SPEAKER_FRAMING, shouldAutoFrame: false, }; return expect(autozoomControl.updateOpts(opts)).to.be.rejectedWith( Error, - "AutozoomMode 'plaza' does not support option 'shouldAutoFrame' set to false!" + "AutozoomMode 'speaker_framing' does not support option 'shouldAutoFrame' set to false!" ); }); it('should throw exception for undefined|null shouldAutoFrame option', () => { diff --git a/tests/components/detector.spec.ts b/tests/components/detector.spec.ts index 7ef6cff8..8e7a5e52 100644 --- a/tests/components/detector.spec.ts +++ b/tests/components/detector.spec.ts @@ -1,11 +1,14 @@ import sinon from 'sinon'; import { expect } from 'chai'; import IDeviceManager from '@huddly/sdk-interfaces/lib/interfaces/IDeviceManager'; -import DetectorOpts, { DetectionConvertion } from '@huddly/sdk-interfaces/lib/interfaces/IDetectorOpts'; +import DetectorOpts, { + DetectionConvertion, +} from '@huddly/sdk-interfaces/lib/interfaces/IDetectorOpts'; import Detector from './../../src/components/detector'; import DeviceManagerMock from './../mocks/devicemanager.mock'; import * as msgpack from 'msgpack-lite'; +import FramingModes from '@huddly/sdk-interfaces/lib/enums/FramingModes'; describe('Detector', () => { let detector: Detector; @@ -226,21 +229,21 @@ describe('Detector', () => { }); describe('detection/framing subscription listener setup/teardown', () => { - let transportOnStub; - let transportSubscribeStub; - let transportUnsubscribeStub; - let transportRemoveListenerStub; + let detectorSubscribeStub; + let detectorUnsubscribeStub; + let framingSubscribeStub; + let framingUnsubscribeStub; beforeEach(() => { - transportOnStub = sinon.stub(deviceManager.transport, 'on'); - transportSubscribeStub = sinon.stub(deviceManager.transport, 'subscribe'); - transportUnsubscribeStub = sinon.stub(deviceManager.transport, 'unsubscribe'); - transportRemoveListenerStub = sinon.stub(deviceManager.transport, 'removeListener'); + detectorSubscribeStub = sinon.stub(detector._detectionSubscriber, 'subscribe'); + detectorUnsubscribeStub = sinon.stub(detector._detectionSubscriber, 'unsubscribe'); + framingSubscribeStub = sinon.stub(detector._framingSubscriber, 'subscribe'); + framingUnsubscribeStub = sinon.stub(detector._framingSubscriber, 'unsubscribe'); }); afterEach(() => { - transportOnStub.restore(); - transportSubscribeStub.restore(); - transportUnsubscribeStub.restore(); - transportRemoveListenerStub.restore(); + detectorSubscribeStub.restore(); + detectorUnsubscribeStub.restore(); + framingSubscribeStub.restore(); + framingUnsubscribeStub.restore(); }); describe('on detection setup', () => { @@ -250,10 +253,7 @@ describe('Detector', () => { detectionListener: true, framingListener: false, }); - expect(transportSubscribeStub.getCall(0).args[0]).to.equals('autozoom/predictions'); - expect(transportOnStub.getCall(0).args[0]).to.equals('autozoom/predictions'); - expect(transportSubscribeStub.callCount).to.equals(1); - expect(transportOnStub.callCount).to.equals(1); + expect(detectorSubscribeStub.callCount).to.equals(1); expect(detector._subscriptionsSetup).to.equals(true); }); it('should setup framing event listeners only', async () => { @@ -261,22 +261,26 @@ describe('Detector', () => { detectionListener: false, framingListener: true, }); - expect(transportSubscribeStub.getCall(0).args[0]).to.equals('autozoom/framing'); - expect(transportOnStub.getCall(0).args[0]).to.equals('autozoom/framing'); - expect(transportSubscribeStub.callCount).to.equals(1); - expect(transportOnStub.callCount).to.equals(1); + expect(framingSubscribeStub.callCount).to.equals(1); expect(detector._subscriptionsSetup).to.equals(true); }); }); - describe('on subscription failure', () => { + describe('on detector subscription failure', () => { beforeEach(() => { - transportSubscribeStub.rejects('Something went wrong'); + detectorSubscribeStub.rejects('Something went wrong'); }); - it('should unsubscribe to detection and framing events', async () => { + it('should set _subscriptionsSetup to false', async () => { + await detector.setupDetectorSubscriptions(); + expect(detector._subscriptionsSetup).to.equals(false); + }); + }); + describe('on framing subscription failure', () => { + beforeEach(() => { + framingSubscribeStub.rejects('Something went wrong'); + }); + it('should set _subscriptionsSetup to false', async () => { await detector.setupDetectorSubscriptions(); - expect(transportUnsubscribeStub.getCall(0).args[0]).to.equals('autozoom/predictions'); - expect(transportUnsubscribeStub.getCall(1).args[0]).to.equals('autozoom/framing'); expect(detector._subscriptionsSetup).to.equals(false); }); }); @@ -289,10 +293,7 @@ describe('Detector', () => { detectionListener: true, framingListener: false, }); - expect(transportUnsubscribeStub.getCall(0).args[0]).to.equals('autozoom/predictions'); - expect(transportRemoveListenerStub.getCall(0).args[0]).to.equals('autozoom/predictions'); - expect(transportUnsubscribeStub.callCount).to.equals(1); - expect(transportRemoveListenerStub.callCount).to.equals(1); + expect(detectorUnsubscribeStub.callCount).to.equals(1); expect(detector._subscriptionsSetup).to.equals(false); }); it('should unsubscribe to framing events and remove detection listener', async () => { @@ -301,12 +302,43 @@ describe('Detector', () => { detectionListener: false, framingListener: true, }); - expect(transportUnsubscribeStub.getCall(0).args[0]).to.equals('autozoom/framing'); - expect(transportRemoveListenerStub.getCall(0).args[0]).to.equals('autozoom/framing'); - expect(transportUnsubscribeStub.callCount).to.equals(1); - expect(transportRemoveListenerStub.callCount).to.equals(1); + expect(framingUnsubscribeStub.callCount).to.equals(1); expect(detector._subscriptionsSetup).to.equals(false); }); }); }); + + describe('#updateFramingSubsciber', () => { + let framingSubscribeStub; + beforeEach(() => { + framingSubscribeStub = sinon.stub(detector._framingSubscriber, 'subscribe'); + }); + afterEach(() => { + framingSubscribeStub.restore(); + }); + describe('new framing mode is supported', () => { + it('should pass new msg bus command and undefined subscription handler when given just framing mode', async () => { + await detector.updateFramingSubscriber(FramingModes.GALLERY_VIEW); + expect(framingSubscribeStub.getCall(0).args[0].msgBusCmd).equals('autozoom/plaza/framing'); + expect(framingSubscribeStub.getCall(0).args[0].subscriptionHandler).equals(undefined); + }); + it('should pass new msg bus command and undefined subscription handler when given', async () => { + const handler = () => { + return 'pass'; + }; + await detector.updateFramingSubscriber(FramingModes.GALLERY_VIEW, handler); + expect(framingSubscribeStub.getCall(0).args[0].msgBusCmd).equals('autozoom/plaza/framing'); + expect(framingSubscribeStub.getCall(0).args[0].subscriptionHandler()).equals(handler()); + }); + }); + describe('new framing mode is not supported', () => { + it('should throw an error', async () => { + let error = undefined; + await detector + .updateFramingSubscriber(FramingModes.SPEAKER_FRAMING) + .catch((err) => (error = err)) + .finally(() => expect(error).not.to.equal(undefined)); + }); + }); + }); }); diff --git a/tests/components/msgBusSubscriber.spec.ts b/tests/components/msgBusSubscriber.spec.ts new file mode 100644 index 00000000..f5728a93 --- /dev/null +++ b/tests/components/msgBusSubscriber.spec.ts @@ -0,0 +1,138 @@ +import sinon from 'sinon'; +import { expect } from 'chai'; +import { transportMock } from '../mocks/devicemanager.mock'; +import MsgBusSubscriber from '../../src/components/msgBusSubscriber'; +import IUsbTransport from '@huddly/sdk-interfaces/lib/interfaces/IUsbTransport'; +import Logger from '@huddly/sdk-interfaces/lib/statics/Logger'; + +describe('MsgBusSubscriber', () => { + const subscribeMsg = 'autozoom/framing'; + let msgBusSubscriber: MsgBusSubscriber; + let transportSubscribeStub; + let transportOnStub; + let transportUnsubscribeStub; + let transportRemoveListenerStub; + let unsubscribeStub; + + const initHandler = () => { + return 'Test'; + }; + beforeEach(() => { + msgBusSubscriber = new MsgBusSubscriber(transportMock as IUsbTransport, initHandler); + transportSubscribeStub = sinon.stub(msgBusSubscriber._transport, 'subscribe'); + transportOnStub = sinon.stub(msgBusSubscriber._transport, 'on'); + transportUnsubscribeStub = sinon.stub(msgBusSubscriber._transport, 'unsubscribe'); + transportRemoveListenerStub = sinon.stub(msgBusSubscriber._transport, 'removeListener'); + }); + afterEach(() => { + transportSubscribeStub.restore(); + transportOnStub.restore(); + transportUnsubscribeStub.restore(); + transportRemoveListenerStub.restore(); + }); + it('should set _transport and _subscriptionHandler', () => { + expect(msgBusSubscriber._transport).to.deep.equal(transportMock); + expect(msgBusSubscriber._subscriptionHandler()).to.equal(initHandler()); + }); + + describe('#subscribe', () => { + describe('when successful', () => { + it('should set _currentSubscription to true', async () => { + await msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }); + expect(msgBusSubscriber._currentSubscription).equals(subscribeMsg); + }); + it('should subscribe to given message', async () => { + await msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }); + expect(transportSubscribeStub.getCall(0).args[0]).equals(subscribeMsg); + }); + it('should listen to given message with handler', async () => { + await msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }); + expect(transportOnStub.getCall(0).args[0]).equals(subscribeMsg); + expect(transportOnStub.getCall(0).args[1]()).equals(initHandler()); + }); + it('should update subscription handler if a new one is included in options', async () => { + const testSubHandler = () => 'Hi'; + await msgBusSubscriber.subscribe({ + msgBusCmd: subscribeMsg, + subscriptionHandler: testSubHandler, + }); + expect(transportOnStub.getCall(0).args[1]()).equals(testSubHandler()); + expect(msgBusSubscriber._subscriptionHandler()).equals(testSubHandler()); + }); + }); + describe('when unsuccesful', () => { + let errorLoggerStub; + beforeEach(() => { + transportSubscribeStub.rejects('error'); + unsubscribeStub = sinon.stub(msgBusSubscriber, 'unsubscribe'); + errorLoggerStub = sinon.stub(Logger, 'error'); + }); + afterEach(() => { + unsubscribeStub.restore(); + errorLoggerStub.restore(); + }); + it('should unsubscribe to msg', async () => { + await msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }).catch(() => {}); + expect(unsubscribeStub).to.have.callCount(1); + }); + it('should log error', async () => { + await msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }).catch(() => {}); + expect(errorLoggerStub).to.have.callCount(1); + // We want to make sure that stack trace gets logged + expect(errorLoggerStub.getCall(0).args.length > 1).equals(true); + }); + it('should throw error', () => { + msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }).catch((err) => { + expect(err).equals('error'); + }); + }); + }); + describe('when previously subscribed', () => { + beforeEach(async () => { + unsubscribeStub = sinon.stub(msgBusSubscriber, 'unsubscribe'); + await msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }); + }); + afterEach(() => { + unsubscribeStub.restore(); + }); + it('should unsubscribe to previous message', async () => { + const newSub = 'autozoom/plaza/framing'; + await msgBusSubscriber.subscribe({ msgBusCmd: newSub }); + expect(unsubscribeStub).to.have.callCount(1); + }); + it('should subscribe to new msg', async () => { + unsubscribeStub.reset(); + const newSub = 'autozoom/plaza/framing'; + await msgBusSubscriber.subscribe({ msgBusCmd: newSub }); + // Getting 2nd call because it's already run once in setup + expect(transportSubscribeStub.getCall(1).args[0]).equals(newSub); + expect(transportOnStub.getCall(1).args[0]).equals(newSub); + }); + it('should update set _currentSubscription to the new msg', async () => { + const newSub = 'autozoom/plaza/framing'; + await msgBusSubscriber.subscribe({ msgBusCmd: newSub }); + expect(msgBusSubscriber._currentSubscription).equals(newSub); + }); + }); + }); + describe('#unsubscribe', () => { + beforeEach(async () => { + await msgBusSubscriber.subscribe({ msgBusCmd: subscribeMsg }); + }); + it('should unsubscribe to current msg', async () => { + await msgBusSubscriber.unsubscribe(); + expect(transportUnsubscribeStub.getCall(0).args[0]).equals(subscribeMsg); + }); + it('should remove listener', async () => { + await msgBusSubscriber.unsubscribe(); + expect(transportRemoveListenerStub.getCall(0).args[0]).equals(subscribeMsg); + expect(transportRemoveListenerStub.getCall(0).args[1]()).equals( + msgBusSubscriber._subscriptionHandler() + ); + }); + it('should set _currentSubscription to undefined', async () => { + await msgBusSubscriber.unsubscribe(); + expect(msgBusSubscriber._currentSubscription).equals(undefined); + }); + }); +}); diff --git a/tests/mocks/devicemanager.mock.ts b/tests/mocks/devicemanager.mock.ts index a824cbbb..a078d7fb 100644 --- a/tests/mocks/devicemanager.mock.ts +++ b/tests/mocks/devicemanager.mock.ts @@ -7,6 +7,16 @@ import DetectorOpts from '@huddly/sdk-interfaces/lib/interfaces/IDetectorOpts'; import DiagnosticsMessage from '@huddly/sdk-interfaces/lib/abstract_classes/DiagnosticsMessage'; import ICnnControl from '@huddly/sdk-interfaces/lib/interfaces/ICnnControl'; +export const transportMock = { + read: (msg, timeout) => {}, + write: (msg) => {}, + receiveMessage: (msg, timeout) => {}, + on: (msg, listener) => {}, + removeListener: (msg, listener) => {}, + subscribe: (msg) => {}, + unsubscribe: (msg) => {}, +}; + /** * @ignore * @@ -15,38 +25,62 @@ import ICnnControl from '@huddly/sdk-interfaces/lib/interfaces/ICnnControl'; * @implements {IDeviceManager} */ export default class DeviceManagerMock implements IDeviceManager { - transport: any = { - read: (msg, timeout) => { }, - write: (msg) => { }, - receiveMessage: (msg, timeout) => { }, - on: (msg, listener) => { }, - removeListener: (msg, listener) => { }, - subscribe: (msg) => { }, - unsubscribe: (msg) => { } - }; + transport: any = transportMock; api: any = { - sendAndReceive: (buffer, commands, timeout) => { }, - sendAndReceiveMessagePack: (message, commands, timeout) => { }, - getAutozoomStatus: () => { }, - encode: (msg) => { }, - getProductInfo: () => { }, + sendAndReceive: (buffer, commands, timeout) => {}, + sendAndReceiveMessagePack: (message, commands, timeout) => {}, + getAutozoomStatus: () => {}, + encode: (msg) => {}, + getProductInfo: () => {}, transport: this.transport, }; uvcControlInterface: any; - initialize(): Promise { return Promise.resolve(); } - closeConnection(): Promise { return Promise.resolve(); } - getInfo(): Promise { return Promise.resolve({ version: '99.99.99' }); } - getErrorLog(): Promise { return Promise.resolve(); } - eraseErrorLog(): Promise { return Promise.resolve(); } - reboot(mode?: string): Promise { return Promise.resolve(); } - getUpgrader(): Promise { return Promise.resolve(undefined); } - upgrade(opts: UpgradeOpts): Promise { return Promise.resolve({}); } - getAutozoomControl(opts: AutozoomControlOpts): ICnnControl { return undefined; } - getFaceBasedExposureControl(): ICnnControl { return undefined; } - getDetector(opts: DetectorOpts): IDetector { return undefined; } - getDiagnostics(): Promise> { return Promise.resolve([]); } - getState(): Promise { return Promise.resolve(); } - getPowerUsage(): Promise { return Promise.resolve(); } - getTemperature(): Promise { return Promise.resolve(); } - getLatestFirmwareUrl(): Promise { return Promise.resolve(); } + initialize(): Promise { + return Promise.resolve(); + } + closeConnection(): Promise { + return Promise.resolve(); + } + getInfo(): Promise { + return Promise.resolve({ version: '99.99.99' }); + } + getErrorLog(): Promise { + return Promise.resolve(); + } + eraseErrorLog(): Promise { + return Promise.resolve(); + } + reboot(mode?: string): Promise { + return Promise.resolve(); + } + getUpgrader(): Promise { + return Promise.resolve(undefined); + } + upgrade(opts: UpgradeOpts): Promise { + return Promise.resolve({}); + } + getAutozoomControl(opts: AutozoomControlOpts): ICnnControl { + return undefined; + } + getFaceBasedExposureControl(): ICnnControl { + return undefined; + } + getDetector(opts: DetectorOpts): IDetector { + return undefined; + } + getDiagnostics(): Promise> { + return Promise.resolve([]); + } + getState(): Promise { + return Promise.resolve(); + } + getPowerUsage(): Promise { + return Promise.resolve(); + } + getTemperature(): Promise { + return Promise.resolve(); + } + getLatestFirmwareUrl(): Promise { + return Promise.resolve(); + } }