import { ElementRef , Injectable , ViewChild } from '@angular/core' ; import { Observable } from 'rxjs' ; import workerJS from '../../../assets/workers/entropyCalculatorWorker' ; import { Entropy , IEntropyGenerator } from '../entropy/IEntropyGenerator' ; const blobURL = window . URL . createObjectURL ( new Blob ( [ workerJS ] ) ) ; const entropyCalculatorWorker = new Worker ( blobURL ) ; @ Injectable ( { providedIn : 'root' } ) export class CameraBrowserService implements IEntropyGenerator { @ ViewChild ( 'cameraCanvas' ) public cameraCanvas : ElementRef ; public canvasElement : HTMLCanvasElement ; private readonly VIDEO_FREQUENCY = 2000 ; private collectedEntropyPercentage : number = 0 ; private handler : Function ; private readonly entropyObservable : Observable < Entropy > ; private cameraInterval : number ; private videoElement : any ; private videoStream : any ; constructor ( ) { this . entropyObservable = Observable . create ( ( observer ) => { entropyCalculatorWorker . onmessage = ( event ) => { this . collectedEntropyPercentage += event . data . entropyMeasure ; observer . next ( { entropyHex : event . data . entropyHex } ) ; } ; this . handler = ( buffer1 ) => { const uintArray = this . arrayBufferFromUint8Array ( buffer1 ) ; entropyCalculatorWorker . postMessage ( { entropyBuffer : uintArray } , [ uintArray ] ) ; } ; } ) ; } public setTransparentElementsByTags ( ... _ ) { } public viewWillLeave ( ) { } public viewWillEnter ( ) { } public start ( ) { return new Promise ( ( resolve ) => { const constraints = { video : true , audio : false } ; this . collectedEntropyPercentage = 0 ; const video = this . videoElement . nativeElement ; navigator . mediaDevices . getUserMedia ( constraints ) . then ( ( stream ) => { this . videoStream = stream ; video . srcObject = stream ; video . play ( ) ; resolve ( ) ; } ) . catch ( ( err ) => { console . log ( 'error in camera.brower.service' , err ) ; resolve ( ) ; } ) ; this . cameraInterval = window . setInterval ( ( ) => { if ( video . videoWidth === 0 ) { return ; } const canvas = document . createElement ( 'canvas' ) ; const context = canvas . getContext ( '2d' ) ; if ( context ) { context . drawImage ( video , 0 , 0 ) ; const buffer = context . getImageData ( 0 , 0 , video . videoWidth , video . videoHeight ) . data ; this . handler ( buffer ) ; } else { console . error ( 'context is undefined' ) ; } } , this . VIDEO_FREQUENCY / 5 ) ; } ) ; } public stop ( ) { if ( this . cameraInterval ) { clearInterval ( this . cameraInterval ) ; } try { this . videoStream . getTracks ( ) . forEach ( function ( track ) { track . stop ( ) ; } ) ; } catch ( e ) { console . log ( e ) ; } return Promise . resolve ( ) ; } public getEntropyUpdateObservable ( ) { return this . entropyObservable ; } public getCollectedEntropyPercentage ( ) { return this . collectedEntropyPercentage ; } public setVideoElement ( element ) { this . videoElement = element ; } private arrayBufferFromUint8Array ( uintArray ) { const buffer = new ArrayBuffer ( uintArray . length ) ; const bufView = new Uint8Array ( buffer ) ; for ( let i = 0 ; i < uintArray . length ; i ++ ) { bufView [ i ] = uintArray [ i ] ; } return buffer ; } }