Camera API
The Camera API provides fine-grained control over camera behavior during scanning sessions.
Overview
The camera property on the AnylineJS instance exposes methods for controlling the camera stream, including mirroring, switching cameras, handling device sleep issues, manual focus control, and flash control.
const anyline = init({ /* ... */ });
// Access camera API
anyline.camera.mirrorStream(true);
anyline.camera.setCamera(deviceId);
await anyline.camera.refocus();
await anyline.camera.activateFlash(true);
anyline.camera.reappend();
Methods
mirrorStream(state: boolean): void
Mirrors the camera stream horizontally.
Parameters:
-
state-trueto enable mirroring,falseto disable
Use Case:
Front-facing cameras typically display a mirrored view to match user expectations (selfie mode). This method allows you to control mirroring behavior manually.
Platform Support: All platforms
Example:
// Enable mirroring for front-facing camera
anyline.camera.mirrorStream(true);
// Disable mirroring for back-facing camera
anyline.camera.mirrorStream(false);
| The SDK automatically handles mirroring based on camera facing mode. Use this method only when you need to override the default behavior. |
setCamera(deviceId: string): void
Switches to a specific camera device.
Parameters:
-
deviceId- The device ID from the MediaDevices API
Use Case:
Allows users to manually select a camera when multiple cameras are available (e.g., front and back cameras on mobile devices, or multiple webcams on desktop).
Platform Support: All platforms
Example:
// Get available cameras
const devices = await navigator.mediaDevices.enumerateDevices();
const cameras = devices.filter(d => d.kind === 'videoinput');
console.log('Available cameras:', cameras);
// Switch to back camera
const backCamera = cameras.find(c =>
c.label.toLowerCase().includes('back') ||
c.label.toLowerCase().includes('rear')
);
if (backCamera) {
anyline.camera.setCamera(backCamera.deviceId);
}
Complete Camera Selector Example:
async function createCameraSelector(anyline: AnylineJS) {
const devices = await navigator.mediaDevices.enumerateDevices();
const cameras = devices.filter(d => d.kind === 'videoinput');
const select = document.createElement('select');
cameras.forEach(camera => {
const option = document.createElement('option');
option.value = camera.deviceId;
option.text = camera.label || `Camera ${cameras.indexOf(camera) + 1}`;
select.appendChild(option);
});
select.addEventListener('change', (e) => {
const deviceId = (e.target as HTMLSelectElement).value;
anyline.camera.setCamera(deviceId);
});
return select;
}
| This method executes asynchronously and returns void immediately. |
Browser device lists are only populated after camera permission is granted. Ensure startScanning() has run before calling enumerateDevices().
|
Switching cameras requires an active video stream. Call this method after startScanning() has resolved.
|
Stream switching failures are handled inside the SDK; on error, the previous stream stays active and a message is logged to the console (or debug overlay when debugAnyline is enabled).
|
reappend(): void
Reappends the camera stream to the video element.
Use Case:
Fixes camera stream issues that can occur when a device wakes from sleep or when the app/tab regains focus after prolonged suspension. This is particularly common on mobile devices.
Platform Support: All platforms
Common Scenarios:
-
Device screen turns off and back on
-
Browser tab is backgrounded for extended periods
-
Mobile device locks and unlocks
-
System puts browser into low-power mode
Example:
// Reappend camera when window regains focus
window.addEventListener('focus', () => {
anyline.camera.reappend();
});
// Handle visibility change
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
// Page became visible, reappend camera
anyline.camera.reappend();
}
});
Best Practice Example:
// Comprehensive camera stream recovery
let wasHidden = false;
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
wasHidden = true;
} else if (wasHidden) {
// Only reappend if page was actually hidden
console.log('Recovering camera stream...');
anyline.camera.reappend();
wasHidden = false;
}
});
// Handle page show events (e.g., returning from background on mobile browsers)
window.addEventListener('pageshow', () => {
if (anyline.getState() === 'scanning') {
console.log('App resumed, recovering camera...');
anyline.camera.reappend();
}
});
| This method executes asynchronously and returns void immediately. |
Calling reappend() while no scan is active has no effect. Trigger it only after startScanning() has completed at least once.
|
refocus(): Promise<void>
Manually triggers camera refocus.
Returns: Promise<void> - Resolves when refocus completes
Throws: OnlyAndroidChromeError - If the browser doesn’t support this feature
Use Case:
Useful when scanning objects at varying distances or when the camera loses focus. Particularly helpful for barcode or text scanning where focus is critical.
Platform Support: Chrome for Android only
Browser Compatibility:
This method relies on camera focus controls exposed via the MediaStream Image Capture API. While Safari 18.4 added basic Image Capture API support, the focus capabilities needed for manual refocus are not available on iOS Safari, so this method remains supported only on Chrome for Android. Other browsers will throw OnlyAndroidChromeError.
If scanning is not currently running (no active camera stream), the promise resolves without making any changes.
Call this method only after startScanning() has completed.
|
Example:
import { OnlyAndroidChromeError } from '@anyline/anyline-js';
// Refocus button handler
async function handleRefocusClick() {
try {
await anyline.camera.refocus();
console.log('Camera refocused successfully');
} catch (error) {
if (error instanceof OnlyAndroidChromeError) {
console.warn('Manual refocus not supported on this browser');
} else {
console.error('Refocus failed:', error);
}
}
}
Conditional UI Example:
// Only show refocus button on supported platforms
async function setupRefocusButton() {
const refocusBtn = document.createElement('button');
refocusBtn.textContent = 'Refocus';
refocusBtn.onclick = async () => {
try {
await anyline.camera.refocus();
showToast('Camera refocused');
} catch (error) {
if (error instanceof OnlyAndroidChromeError) {
console.warn('Manual refocus not supported on this browser');
} else {
console.error('Refocus failed:', error);
}
}
};
document.body.appendChild(refocusBtn);
}
activateFlash(state: boolean): Promise<void>
Controls the camera flash (torch mode).
Parameters:
-
state-trueto enable flash,falseto disable
Returns: Promise<void> - Resolves when flash state changes
Throws: OnlyAndroidChromeError - If the browser doesn’t support torch control via MediaStream constraints
Use Case:
Provides additional lighting for scanning in low-light conditions. Particularly useful for barcode, meter, or document scanning.
Platform Support: Chrome for Android, Safari 18.4+ (iOS)
Browser Compatibility:
This method uses the camera torch constraint via MediaStreamTrack.applyConstraints(). Support depends on both the browser and the device hardware.
Supported browsers:
-
✅ Chrome for Android
-
✅ iOS Safari 17.5.1+ (iOS 17.5.1+) — torch constraint is supported; feature-detect with
track.getCapabilities().torch -
❌ Desktop browsers (usually no torch hardware)
-
❌ iOS Safari versions where
getCapabilities().torchis not present or returns false
| Call this method only after scanning has started so an active camera stream is available. |
Example:
import { OnlyAndroidChromeError } from '@anyline/anyline-js';
// Toggle flash
async function toggleFlash(enabled: boolean) {
try {
await anyline.camera.activateFlash(enabled);
console.log(`Flash ${enabled ? 'enabled' : 'disabled'}`);
} catch (error) {
if (error instanceof OnlyAndroidChromeError) {
console.warn('Flash control not supported on this browser');
} else {
console.error('Flash toggle failed:', error);
}
}
}
Complete Flash Toggle Button:
// Flash toggle with state management
let flashEnabled = false;
async function createFlashToggle() {
const flashBtn = document.createElement('button');
flashBtn.className = 'flash-toggle';
flashBtn.textContent = 'Flash Off';
flashBtn.onclick = async () => {
flashEnabled = !flashEnabled;
try {
await anyline.camera.activateFlash(flashEnabled);
flashBtn.textContent = flashEnabled ? 'Flash On' : 'Flash Off';
flashBtn.classList.toggle('active', flashEnabled);
} catch (error) {
if (error instanceof OnlyAndroidChromeError) {
console.warn('Flash control not supported on this browser');
} else {
console.error('Failed to toggle flash:', error);
}
flashEnabled = !flashEnabled; // Revert state
}
};
return flashBtn;
}
Flash availability depends on the device’s hardware capabilities. Always feature-detect first (for example, track.getCapabilities().torch) and handle failures. On iOS Safari 18.4, a WebKit bug fix addressed getSettings() returning stale torch values after applying constraints—avoid using getSettings().torch as your only source of truth for UI state.
|
Browser Support Summary
| Method | Desktop Browsers | Mobile Safari (iOS) | Chrome Android |
|---|---|---|---|
|
✅ Yes |
✅ Yes |
✅ Yes |
|
✅ Yes |
✅ Yes |
✅ Yes |
|
✅ Yes |
✅ Yes |
✅ Yes |
|
❌ No |
❌ No |
✅ Yes |
|
❌ No |
✅ Yes (18.4+) |
✅ Yes |
|
❌ No |
❌ No |
✅ Yes |
Safari 18.4 added Image Capture API support, but activateFlash() relies on the MediaStream torch constraint. Torch control became practically available on iOS Safari in the iOS 17.5.1 timeframe; always use runtime feature detection.
|
Troubleshooting
Camera Stream Black After Sleep
Problem: Camera stream shows black screen after device sleep.
Solution: Use reappend() when page becomes visible:
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
anyline.camera.reappend();
}
});
Flash/Refocus Not Working
Problem: Flash or refocus methods throw errors.
Solution: Refocus only works on Chrome for Android; flash (torch) works on Chrome for Android and on supported iOS Safari versions.
import { OnlyAndroidChromeError } from '@anyline/anyline-js';
try {
await anyline.camera.refocus();
} catch (error) {
if (error instanceof OnlyAndroidChromeError) {
console.log('Feature not supported on this browser');
}
}
See Also
-
API Reference - Complete API reference
-
Plugin Configuration - Configuration options
-
Error Handling - Error handling guide
-
Getting Started - Getting started guide