Reputation: 12512
I'm working on a functionality that will allow users taking pictures with their mobile device camera. Is there a reliable way to detect if a user has this access? Currently this is a constraint set by:
facingMode: { exact: "environment" }
I would like to hide this functionality from users that are not able to use device's back camera. Here's the code that works.
<script>
const player = document.getElementById('player');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const captureButton = document.getElementById('capture');
const constraints = {
video:
{
facingMode: { exact: "environment" }
}
};
captureButton.addEventListener('click', () => {
// Draw the video frame to the canvas.
context.drawImage(player, 0, 0, canvas.width, canvas.height);
});
// Attach the video stream to the video element and autoplay.
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
player.srcObject = stream;
});
</script>
Upvotes: 2
Views: 872
Reputation: 5853
How about something like this?
const isMobileDevice = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
navigator.getMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia
|| navigator.mozGetUserMedia || navigator.msGetUserMedia)
navigator.getMedia({video: true}, () => {
if (isMobileDevice) console.log("I'm mobile device with camera")
console.log("I have camera")
}, () => {
console.log("I do not have camera")
})
Upvotes: 1
Reputation: 133
You can chain a new 'catch' error handler like above answers and hide that button inside it.
If you still need to switch to the available camera device, you can consider to use navigator.mediaDevices.enumerateDevices method which returns a promise that receives an array of MediaDeviceInfo objects.
Upvotes: 0
Reputation: 6488
This answer adds an error handling part i.e: .catch(function(err){
to the getUserMedia(...)
method in the OP i.e: original post. In the error handling section, all possible errors are detected that would mean the back camera to be unusable and a brief explanation is held as a variable namely error_msg
in the if..else..
block.
<script>
const player = document.getElementById('player');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const captureButton = document.getElementById('capture');
var constraints = {
video:
{
facingMode: { exact: "environment" }
}
}
captureButton.addEventListener('click', () => {
// Draw the video frame to the canvas.
context.drawImage(player, 0, 0, canvas.width, canvas.height);
});
navigator.mediaDevices.getUserMedia(constraints)
.then(function success(stream) {
player.srcObject = stream;
}).catch(function(err) {
//log to console first
//console.log(err); /* handle the error */
var error_msg="";
if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") {
error_msg="Back camera not found error ";
//required track is missing
} else if (err.name == "NotReadableError" || err.name == "TrackStartError") {
//webcam or mic are already in use
error_msg="cam is already in use ";
} else if (err.name == "OverconstrainedError" || err.name == "ConstraintNotSatisfiedError") {
//constraints can not be satisfied by avb. devices
error_msg="constraints can not be satisfied by avb. devices ";
}
else if (err.name == "NotAllowedError" || err.name == "PermissionDeniedError") {
//permission denied in browser
error_msg="permission denied in browser ";
} else if (err.name == "TypeError" || err.name == "TypeError") {
//empty constraints object
error_msg="empty constraints object ";
} else {
//other errors
error_msg="Errors somehow";
}
captureButton.style.display = 'none';
alert(error_msg);
});
</script>
You can find a jsfiddle here.
In the fiddle the player
, canvas
and context
variables have been omitted as no HTML elements exist with the ID
s of the variables. I hope you have the HTML elements with the ID
s in your actual production code. Besides a button with the ID capture
has been added. These changes were necessary to run the code in the fiddle without producing any errors.
Upvotes: 0
Reputation: 316
When the exact constraint is not met, a OverconstrainedError
is thrown. You can catch the error and hide an element like so.
const video = document.getElementById('video');
const button = document.getElementById('button');
navigator.mediaDevices
.getUserMedia({
video: {
facingMode: {
exact: 'environment'
},
},
})
.then((stream) => video.srcObject = stream)
.catch((_) => button.style.display = 'none');
https://jsfiddle.net/68e5t4z1/13/
Upvotes: 3