ngx-scanner icon indicating copy to clipboard operation
ngx-scanner copied to clipboard

Unable to specify preferred camera

Open rtamsatyam opened this issue 2 years ago • 12 comments

Angular 14, Zxing 3.6.2

As a user with more cameras sets the preferred camera, which is then stored in sessionStorage or localStorage. However, when the user reloads the page, the zxing scanner seems to pick its own default camera.

Is there a way the preferred camera is taken as the default camera?

rtamsatyam avatar Feb 20 '23 10:02 rtamsatyam

Yes, you can do it, start by defining the input of the device like this, then define the function that will initialize the camera in the camerasFound output.

Normally you should not need to initialize selectedCamera

Just store the cameraDeviceId somewhere.

<zxing-scanner 
  [formats]="formats"
  [device]="selectedCamera"
  (scanSuccess)="scan($event)"
  (torchCompatible)="setTorchButton($event)"
  (camerasFound)="getCamerasAvailable($event)"
  (camerasNotFound)="showErrorMessage($event)" 
/>

selectedCamera!: MediaDeviceInfo; // Define the camera used by the scanner
availableCameras: MediaDeviceInfo[] = []; // Defines the cameras available for this device
getCamerasAvailable(availableCameras: MediaDeviceInfo[]): void {
  this.availableCameras = availableCameras;  //We define this.availableCameras according to availableCameras sent by the 
  ZXingScannerComponent
  
  const prefCamera = availableCameras.find(
            (c) => c.deviceId === 'ID_OF_PREFERRED_CAMERA'
  );
  if (prefCamera) this.selectedCamera = prefCamera;
}

0pahh avatar Feb 20 '23 10:02 0pahh

It seems to set the value here, but it somehow doesn't reflect in the camera being selected itself. For e.g. in my situation I have an integrated webcam and a microsoft webcam. The zxing scanner always shows integrated webcam as the default option. When I force it to select the Microsoft camera, then selected camera in the select list shows as Microsoft Webcam. But the camera actually being selected is still the integrated webcam.

rtamsatyam avatar Feb 20 '23 12:02 rtamsatyam

Just in case, try adding a timeout before switching cameras, maybe that can help.

0pahh avatar Feb 20 '23 12:02 0pahh

Sorry that also did not help.

rtamsatyam avatar Feb 20 '23 13:02 rtamsatyam

I may be the problem, try switching to this ?

<zxing-scanner 
  [formats]="formats"
  [(device)]="selectedCamera"
  (scanSuccess)="scan($event)"
  (torchCompatible)="setTorchButton($event)"
  (camerasFound)="getCamerasAvailable($event)"
  (camerasNotFound)="showErrorMessage($event)" 
/>

0pahh avatar Feb 20 '23 13:02 0pahh

That was the original code actually with a two way bind on device. It doesn't work either!!

rtamsatyam avatar Feb 20 '23 14:02 rtamsatyam

Hi, it doesn't work for me either :(

NachoCarpintero2937 avatar Mar 16 '23 16:03 NachoCarpintero2937

[device]="selectedCamera" instead of [(device)]="selectedCamera" works for me

martindebrunne avatar Apr 05 '23 15:04 martindebrunne

doesn't work, is this bug or what?

hsayed21 avatar May 22 '23 11:05 hsayed21

I see the same behavior. Setting the selectedCamera has no effect on the scanning camera.

iijat avatar Jun 30 '23 16:06 iijat

Error is still there... also setting via scanner.device has no effect. It only worked for me when I add a delay, but this could end in a bad UX:

  /**
   * Sets the camera
   * @param event
   */
  foundCameras(event: MediaDeviceInfo[]) {
    this.cameras = event;
    const selected = localStorage.getItem('camera');
    if (selected) {
      const found = this.cameras.find((c) => c.deviceId === selected);
      if (found) {
        setTimeout(() => {
          this.changeCamera(found);
        }, 2000);
      }
    }
  }

  changeCamera(camera: MediaDeviceInfo) {
    localStorage.setItem('camera', camera.deviceId);
    this.activeCamera = camera;
  }

cre8 avatar Oct 04 '23 10:10 cre8

|Setting the camera programatically during startup only works if autostart is disabled, otherwise there's a race condition and the activeCamera is reset during zxing-scanner startup to whichever camera zxing-scanner chooses automatically.

In the template:

<zxing-scanner #scannerComponent
    ...
    [(device)]="activeCamera "
    [autostart]="false"
></zxing-scanner>

In the component:

    @ViewChild('scannerComponent')
    private scannerComponent: ZXingScannerComponent;

   ...

  /**
   * Sets the camera
   * @param event
   */
  foundCameras(event: MediaDeviceInfo[]) {
    this.cameras = event;
    const selected = localStorage.getItem('camera');
    if (selected) {
      const found = this.cameras.find((c) => c.deviceId === selected);
      if (found) {
      
            if (this.scannerComponent.device !== device) {
            this.scannerComponent.askForPermission()
                .then(() => changeCamera(found);
        }
      }
    }
  }

  changeCamera(camera: MediaDeviceInfo) {
    localStorage.setItem('camera', camera.deviceId);
    this.activeCamera = camera;
  }


Ju-l1a avatar Oct 11 '23 13:10 Ju-l1a