ngx-scanner
ngx-scanner copied to clipboard
Unable to specify preferred camera
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?
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;
}
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.
Just in case, try adding a timeout before switching cameras, maybe that can help.
Sorry that also did not help.
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)"
/>
That was the original code actually with a two way bind on device. It doesn't work either!!
Hi, it doesn't work for me either :(
[device]="selectedCamera"
instead of [(device)]="selectedCamera"
works for me
doesn't work, is this bug or what?
I see the same behavior. Setting the selectedCamera has no effect on the scanning camera.
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;
}
|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;
}