You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Android: barcode scanner has no camera selection - always opens the default rear lens, which can be a fixed-focus one #71
On a phone with several rear cameras the scanner opens a camera that cannot focus, and there is no way to switch to a different one. The barcode never becomes sharp, so scanning is impossible.
Environment
LibrisLog ghcr.io/codebude/librislog/librislog:latest, image built 2026-06-22 (API image same build date), self-hosted behind nginx with a trusted internal CA — HTTPS/secure context is fine, permission is granted and the camera starts
Huawei P30, Android
Vivaldi (Chromium) — also reproduced in Brave (Chromium)
Camera 4 (facing back) is the only one that cannot focus — evidently a fixed-focus auxiliary lens. So the browser exposes both camera selection and zoom on this device; the app just doesn't use them.
Root cause
The scanner requests the camera like this (/_app/immutable/chunks/BTxGinf0.js in the current image):
Only facingMode is used, so the browser picks whichever rear camera it considers default and the user cannot influence it. On multi-camera Android phones that default is frequently an ultra-wide or a macro/depth sensor — and several of those are fixed-focus.
The bundled ZXing library does support deviceId: { exact: … } (it is right there in the same chunk), but this code path doesn't use it. No zoom or focusMode constraints are applied either.
Suggested fix
enumerateDevices() → list the videoinput devices and let the user choose, persisting the choice (a phone's "best" lens is not guessable from the label alone).
Request with deviceId: { exact: … }, and stop the previous track before switching — otherwise Android tends to hand back the old stream.
Where track.getCapabilities() reports them, apply focusMode: "continuous" and expose zoom through applyConstraints().
A "switch camera" button that simply cycles through the available videoinput devices would already make the scanner usable on this class of phone.
I implemented a camera selector in #73 . The code is merged to develop branch now. To test it before the next release, either checkout the develop branch and run from code or use the docker image with the develop tag.
Tested the develop image on the same setup as the report — it works. Zoom (the 1x–10x buttons and the slider), camera switching and actual scanning all function on the Huawei P30 in Vivaldi. Thanks for the quick turnaround, and for implementing focus and zoom as well, not just the selector.
Two observations from using it, in case they're useful:
1. Cycling includes the front cameras
"Switch camera" steps through every videoinput, so on this phone that's 4 rear + 1 front. Finding the one usable rear lens means tapping through several, and two of the steps are front-facing views that are never useful for scanning a book.
A dropdown listing the cameras would remove the guesswork — label is populated once permission has been granted, so entries like camera2 0, facing back can be shown directly. Failing that, filtering the cycle to rear-facing devices (with a separate front toggle) would still be a clear improvement.
2. Remembering the last choice would fix most of the friction
deviceId is persisted per origin across sessions, so storing the selected id in localStorage and restoring it when the scanner opens would mean picking the right lens once rather than every time.
Worth guarding: the id is regenerated if the user clears site data, and differs in private windows — so fall back to the default when a stored id is no longer present in enumerateDevices(), instead of failing to open the camera.
On picking a better default
enumerateDevices()lists default capture devices first, so defaulting to the firstvideoinput is already a reasonable improvement over an unconstrained facingMode request — on this phone the first rear camera does autofocus, while the one the old code ended up on does not.
Note that the number in the label (camera2 0) is Android's own camera id, not the index in the list, so "always use id 0" isn't portable.
If you ever want a fully robust default, track.getCapabilities() distinguishes them directly: the fixed-focus auxiliary lenses report no usable focusMode/focusDistance, while the main camera does. Probing is slow enough that it'd only be worth doing once and caching — which is the same mechanism as remembering the user's choice.
A dropdown listing the cameras would remove the guesswork
I don't plan to implement a dropdown. The technical names returned by enumerateDevices() will confuse most of the users. Cycling once through the available cameras until you find your preferred one, shouldn't be a big hurdle.
Remembering the last choice would fix most of the friction
Isn't it working for you? (Otherwise I didn't get your point. In that case please try to explain it again to me.)
Worth guarding: the id is regenerated if the user clears site data, and differs in private windows — so fall back to the default when a stored id is no longer present in enumerateDevices(), instead of failing to open the camera.
My bad — I fired off an idea before properly reading your commit. Sorry about that.
It works for me: camera switching, zoom and scanning all fine, and it remembers my choice.
Two small notes, take them or leave them:
The switch also cycles through the front cameras. Not sure if that's intended.
I have three rear cameras that look identical in quality and resolution, so if I didn't already know there were several, I'd probably wonder whether the button did anything. Instead of a dropdown, just a small label showing the currently selected camera would be enough to guide.
But it works, so I'm happy. Thanks for the quick turnaround.
Activity
codebude commentedon Sep 1, 2026
That's a great issue description. Thanks! I'll put it on my to-do list for the next release and keep you updated.
codebude commentedon Sep 2, 2026
Hi @AFT-syd ,
I implemented a camera selector in #73 . The code is merged to develop branch now. To test it before the next release, either checkout the develop branch and run from code or use the docker image with the
developtag.AFT-syd commentedon Sep 2, 2026
Tested the
developimage on the same setup as the report — it works. Zoom (the 1x–10x buttons and the slider), camera switching and actual scanning all function on the Huawei P30 in Vivaldi. Thanks for the quick turnaround, and for implementing focus and zoom as well, not just the selector.Two observations from using it, in case they're useful:
1. Cycling includes the front cameras
"Switch camera" steps through every
videoinput, so on this phone that's 4 rear + 1 front. Finding the one usable rear lens means tapping through several, and two of the steps are front-facing views that are never useful for scanning a book.A dropdown listing the cameras would remove the guesswork —
labelis populated once permission has been granted, so entries likecamera2 0, facing backcan be shown directly. Failing that, filtering the cycle to rear-facing devices (with a separate front toggle) would still be a clear improvement.2. Remembering the last choice would fix most of the friction
deviceIdis persisted per origin across sessions, so storing the selected id inlocalStorageand restoring it when the scanner opens would mean picking the right lens once rather than every time.Worth guarding: the id is regenerated if the user clears site data, and differs in private windows — so fall back to the default when a stored id is no longer present in
enumerateDevices(), instead of failing to open the camera.On picking a better default
enumerateDevices()lists default capture devices first, so defaulting to the firstvideoinputis already a reasonable improvement over an unconstrainedfacingModerequest — on this phone the first rear camera does autofocus, while the one the old code ended up on does not.Note that the number in the label (
camera2 0) is Android's own camera id, not the index in the list, so "always use id 0" isn't portable.If you ever want a fully robust default,
track.getCapabilities()distinguishes them directly: the fixed-focus auxiliary lenses report no usablefocusMode/focusDistance, while the main camera does. Probing is slow enough that it'd only be worth doing once and caching — which is the same mechanism as remembering the user's choice.Happy to test any of this on the same device.
codebude commentedon Sep 2, 2026
I don't plan to implement a dropdown. The technical names returned by enumerateDevices() will confuse most of the users. Cycling once through the available cameras until you find your preferred one, shouldn't be a big hurdle.
That's what actually already is implemented. See write- and readCameraPref functions over here: b94ebeb#diff-a1239feb7a93870c9fd4f14992dcf1a474f074a4795d912fac36ad9f654a07e6R68
Isn't it working for you? (Otherwise I didn't get your point. In that case please try to explain it again to me.)
That's also already implemented:
(Source: b94ebeb#diff-a1239feb7a93870c9fd4f14992dcf1a474f074a4795d912fac36ad9f654a07e6R175 )
AFT-syd commentedon Sep 5, 2026
My bad — I fired off an idea before properly reading your commit. Sorry about that.
It works for me: camera switching, zoom and scanning all fine, and it remembers my choice.
Two small notes, take them or leave them:
But it works, so I'm happy. Thanks for the quick turnaround.
codebude commentedon Sep 8, 2026
@AFT-syd I added a small camera name badge besides the scanner in #98 (You can try out via develop image or wait for the next release.)
AFT-syd commentedon Sep 8, 2026
Great. Thanks for the fixes