Get actual facingMode of a mediaStreamTrack in Firefox - javascript

I want to know the actual facingMode of a media stream track in order to invert (mirror) the image or not depending on whether the active camera is at the back or at the front of a device. If the actual facingMode is "user", the CSS property of the video will be: transform: scaleX(-1); if the facingMode is "environment", I do not invert the image.
This is my piece of code:
navigator.mediaDevices.getUserMedia({ facingMode: "environment", width: { ideal: 4096 } })
.then (function(mediaStream){
video.srcObject = mediaStream;
console.log('facingmode: ' + video.srcObject.getTracks()[0].getSettings().facingMode);
});
In Chrome, everything works as expected: The console shows "environment" or "user", depending on the actually active camera.
In Firefox, the console always shows "undefined" (what is not expected) (same behaviour on computer and on smartphone).
Could someone help me to retrieve the actual facingMode in Firefox too?
Thank you

In Firefox for Android and other clients that still don't provide
MediaTrackSettings.facingMode, a workaround is to inspect the
MediaStreamTrack.label, e.g.:
const isEnvironment =
"environment" == video.srcObject.getVideoTracks()[0].getSettings().facingMode
|| video.srcObject.getVideoTracks()[0].label.indexOf("acing back") !== -1;
Unfortunately, the labels may vary across user agents.
The above snippet works in Firefox Mobile 68. Even in German, the label for the back camera is "Camera 0, Facing back, Orientation 90".

Firefox can return the correct facing mode without problem. I've test it using the following code:
navigator.mediaDevices.getUserMedia({ video: true})
.then(function(stream) {
console.log(stream.getTracks()[0].getSettings().facingMode);
})
.catch(function(err) {
console.log(err)
});
The problem you have is maybe that you haven't authorized the page to use the camera. Go to Preferences -> Permissions -> Camera -> Settings ... and uncheck Block new requests asking to access your camera.

Related

Firefox navigator.mediaDevices.getUserMedia stream is correct on the first run, on the second run stream is broken and I cannot display video

I'm having trouble accessing the microphone and camera while using Firefox on windows after running this script on the second time. Chrome/edge is fine
let stream;
try {
document.getElementById('record').onclick = async () => {
stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true});
document.getElementById('video').srcObject = stream;
};
document.getElementById('stop').onclick = () => {
stream.getTracks().forEach(track => track.stop());
document.getElementById('video').srcObject = undefined;
stream = null;
};
} catch (e) {
console.error(e);
}
On the second go stream seams to be legit, it contains video and audio track, but it won't display video correctly whereas chrome and safari deals with it without any issues. Should I treat firefox in a specific way? What could be wrong? I'll add that my camera & microphone is fine + I've granted the permissions
fiddle link to the example code
Closing and reopening browser seam to make the issue go away, until I run that script again. Thanks in advance
Your code is correct. It's just that webcams tend to take a little extra time between when they're closed, and when they're re-opened. It's a big issue for webcams that don't support multiple clients simultaneously.
I've experienced this problem occasionally on Chrome, as well as Firefox.
The best thing to do is handle errors and try again.

iPhone continuity camera not displaying in Web API on Safari

iPhone continuity camera not displaying in MediaDevices enumerateDevices()
I'm using the simple code to enumerate media devices on Safari
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(stream => {
if (!navigator.mediaDevices?.enumerateDevices) {
console.log("enumerateDevices() not supported.");
} else {
// List cameras and microphones.
navigator.mediaDevices.enumerateDevices()
.then((devices) => {
devices.forEach((device) => {
console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
});
})
.catch((err) => {
console.error(`${err.name}: ${err.message}`);
});
}
})
.catch(err => console.error("queryMediaDevices:Error", err));
But I'm just getting the iPhone mic and not the camera. But when I enter another web app, or go to google meets, I can select the phone's camera and use it.
Currently on macOS 13.0, and iOS 16.2.
Is there anything I'm missing?
There's a "magic pose" your camera needs to be in for browsers to detect your continuity camera:
Due to privacy concern with unintended camera selection, browser based video apps only see the phone when it is in "magic pose" of landscape, screen off, locked, motionless (not handheld), and unobstructed camera. This pose is also used to trigger Automatic Camera Selection in supporting applications such as FaceTime and Photo Booth.
The issue was caused solved by updating macOS to 13.1 and safari to 16.2.
Now it's working just fine.

Switching facingMode with applyConstraints not CURRENTLY supported (Media Stream Api)

I am reading this article and almost halfway through it, you can read about the following
function switchCameras(track, camera) {
let constraints = track.getConstraints();
constraints.facingMode = camera;
track.applyConstraints(constraints);
}
This function accepts a MediaStreamTrack and a string indicating the
camera facing mode to use, fetches the current constraints, sets the
value of the MediaTrackConstraints.facingMode to the specified value,
then applies the updated constraint set.
But when giving it a try on the live demo at the end of the article, I am trying to change the facingMode videoConstraint on a MediaStreamTrack initiated with getUserMedia while streaming using track.applyConstraints(constraints);
For example, if started with getUserMedia() on these constraints:
{
video: {
"facingMode": "user"
},
audio: false
}
and using applyConstraints() with this configuration:
{
"facingMode": { "exact": "environment" }
}
the output is an error
in Android (Chrome): Error OverconstrainedError in contraint facingMode: Cannot satisfy constraints
in iOS (Safari): Error OverconstrainedError in constraint facingMode: Constraint not supported
and I tried also with a friend on a Windows surface and they received a similar error.
References to these issues are found within this article and this forum bug report.
So my question is, is this an expected behavior or are the help on those two and the first article outdated?
Additionally I would greatly appreciate any advice on how to correctly switch cameras using the applyConstraints()
Thanks in advance
I think the reason why the facingMode error is because it is a different device.
You can't switch a MediaStream from a front to a back camera, or vice versa. To do that you need to open a new stream with getUserMedia.

How to check which is the active user's microphone (audio input device) with JavaScript?

I've created a web app that allows users to do a voice recording and have noticed that there are problems with picking the correct audio input device. FireFox works great but Chrome and Safari don't always record if I use the default way for initializing the audio recording: navigator.mediaDevices.getUserMedia({audio: true}). Because of this, I have to specify which microphone to use like so:
let dD = [];
navigator.mediaDevices.enumerateDevices().then((devices) => {
dD = devices.filter((d) => d.kind === 'audioinput');
try {
// checking if there is a second audio input and select it
// it turns out that it works in most cases for Chrome :/
let audioD = dD[1] === undefined ? dD[0] : dD[1];
navigator.mediaDevices.getUserMedia({audio: { deviceId: audioD.deviceId }})
.then(function(stream){
startUserMedia(stream);
})
.catch(function(err) {
console.log(`${err.name}: ${err.message}`);
});
} catch (err) {
console.log(`${err.name}: ${err.message}`);
}
});
The problem with this code is that it only works sometimes. I still get reports from users complaining that the recording is not working for them or the recording is empty (which might mean that I'm using the wrong audio input).
I assume that my code is not the correct way to get the active (or let's say the working) audio input devices. How I can check which audio input is the correct one?

How to force a 16:9 ratio with getUserMedia on all devices?

I need to use getUserMedia while the video is set to record in 16:9 resolution.
My code works on most desktops and on Android 7 and above:
navigator.getUserMedia( {
audio: true,
video: {
mandatory: {
minWidth: 380,
minHeight: 214,
maxWidth: 380,
maxHeight: 214
}
}
})
But on Android 6 and below, and on some desktops too (can't figure out exactly which), getUserMedia breaks, and no image is available from the camera.
This works on all devices and desktop, but with a default resolution ratio of 4:3, while I need 16:9:
navigator.getUserMedia( {
audio: true,
video: true
})
I tried omitting the mandatory, no luck.
To add to my confusion, iOS devices (11 beta) and Android require passing the facingMode argument:
video: { facingMode: 'user' }
So, it seems that passing the width and height arguments breaks getUserMedia on some desktops and devices like Android 5 and 6.
Is there a way to force a 16:9 ratio on all devices? What is the correct and conventional method of capturing a video with specific dimensions?
You're assuming all cameras support 16:9, or that all browsers will crop the video for you. Not so. You're also using an outdated API. Try the latest API (fiddle, samples):
var constraints = {video: {width: 320, height: 180, facingMode: "user"}};
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => video.srcObject = stream)
.then(() => new Promise(resolve => video.onloadedmetadata = resolve))
.then(() => log(video.videoWidth +"x"+ video.videoHeight))
.catch(e => console.log(e));
getUserMedia at its heart is a camera/mic discovery API: All the min, max, exact, ideal keywords exist to describe your constraints, i.e. your tolerance for not getting what you want.
I would suggest the aspectRatio constraint, except nobody implements that yet, and it's just another constraint to decrease your tolerance.
At the moment I believe only Chrome will downscale and crop camera output to the exact size you want. Turns out this is what most people want, but discovers little about the user's camera. Other browsers may follow, since there hasn't been much demand for much else, but they don't currently downscale.
Note though that even Chrome won't upscale, so if you're using Chrome on Android, there's a chance you asked for a higher resolution than your Android 6 device can output. Check for OverconstrainedError in this case, and try again with lower values.
In short, you're not always going to get the exact size you want, as it ultimately depends on the user's camera and their browser.
But HTMLVideoElement downscales on playback anyway, and you can use CSS to crop.

Categories