How to use iOS and macOS's latest feature of Continuity Camera feature with JavaScript, or how to avoid it from popping up in the process of requesting media devices, i.e. navigator.mediaDevices.getUserMedia({ video: true })? - as it actually breaks this code on Chrome whenever my iPhone is close to the laptop with the error Uncaught (in promise) DOMException: Could not start video source, even after I tried to set chrome://settings/content/camera to the original FaceTime HD Camera - seems Chrome just keeps trying to request iPhone as the webcam.
Update - To avoid Continuity Camera, I use this quick patch to prefer the FaceTime Camera if possible (while it would still be better and cool to be able to use iPhone whenever needed)
let preferredDeviceId = undefined
const availableDevices = await navigator.mediaDevices.enumerateDevices()
if (availableDevices.length > 1)
for (let d of availableDevices)
if (d.label.includes('FaceTime'))
preferredDeviceId = d.deviceId
await navigator.mediaDevices.getUserMedia({
video: {
deviceId: preferredDeviceId,
}
})
Related
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.
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.
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.
So iOS 11 Safari was supposed to add support for the Web Audio API, but it still doesn't seem to work with this javascript code:
//called on page load
get_user_media = get_user_media || navigator.webkitGetUserMedia;
get_user_media = get_user_media || navigator.mozGetUserMedia;
get_user_media.call(navigator, { "audio": true }, use_stream, function () { });
function use_stream(stream){
var audio_context = new AudioContext();
var microphone = audio_context.createMediaStreamSource(stream);
window.source = microphone; // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=934512
var script_processor = audio_context.createScriptProcessor(1024, 1, 1);
script_processor.connect(audio_context.destination);
microphone.connect(script_processor);
//do more stuff which involves processing the data from user's microphone...
}
I copy pasted most of this code, so I only have a cursory understanding of it. I know that it's supposed to (and does, on other browsers) capture the user's microphone for further processing. I know that the code breaks on the var audio_context = new AudioContext(); line (as in, no code after that is run), but don't have any error messages cause I don't have a mac which is required to debug iOS Safari (apple die already >_<) Anyone know what's going on and/or how to fix it?
e: forgot to mention that I looked it up and apparently I need the keyword "webkit" before using Web Audio API in Safari, but making it var audio_context = new webkitAudioContext(); doesn't work either
#TomW was on the right track - basically the webkitAudioContext is suspended unless it's created in direct response to the user's tap (before you get the stream).
See my answer at https://stackoverflow.com/a/46534088/933879 for more details and a working example.
Nothing works on mobile save to home screen apps. I issued a bug report to Apple developer. Got a response that it was a duplicate ( which means they know..no clue if or when they will actually fix it).
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.