iPhone continuity camera not displaying in Web API on Safari - javascript

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.

Related

Using iPhone/Mac Continuity Camera on the web

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,
}
})

How to use the external web cam on browsers

Hi i have been working on a webpage where webcam is in use. it works fine with the primary laptop camera but my client is using a secondary/external webcam. what should i do to the webpage to use the specific camera instead of using the main laptop camera? or can he set up from windows the secondary camera as the default camera from windows like printers? (i dont have a second webcam test or check this)
Try this function
function getConnectedDevices(type, callback) {
navigator.mediaDevices.enumerateDevices()
.then(devices => {
const filtered = devices.filter(device => device.kind === type);
callback(filtered);
});
}
getConnectedDevices('videoinput', cameras => console.log('Cameras found', cameras));
There are good examples on the webrtc.org webpage
webrtc.org, Getting started with media devices, Querying media devices

Get actual facingMode of a mediaStreamTrack in Firefox

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.

how to restore the negotiation after changing the camera and microphone?

About a month ago, a Stackoverflow partner helped me with a big question, like changing the camera and the microphone during a conference. That question was answered in the following link:
Using WebRTC how to choose mic and camera?
After changing the camera and microphone, the previous media flow remains active. So the other people in the conference can not receive the new flow I have in some way.
I would like to know how to renegotiate this new flow, if necessary.
The library that I use for webRTC implementation in the project is "simplewebRTC" currently in disuse.
The code I use to change devices is based entirely on what was achieved in my previous question ...
I don't know about simpleWebRTC, but in plain WebRTC renegotiation is not necessary.
Just use sender.replaceTrack(). It's async, so to switch both camera and mic at the same time:
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
video.srcObject = stream;
return Promise.all(stream.getTracks().map(track => {
const sender = pc.getSenders().find((s => s.track.kind == track.kind);
return sender.replaceTrack(track);
}));
})
.catch(err => console.log(err));
This should instantly cause the sender to switch to sending media from your new camera and microphone. The other side won't know the difference.

Video tag with input from Camera is Working in Safari on iOS but neither working in Chrome nor in any In-app Browser

The video streaming works perfectly well for Android, and Safari in iOS. The problem occurs when we try to use Chrome on iOS or an In-app Browser. I am using Vue as a Single File Component.
My HTML code is as follows:
<video
height="400px"
width="300px"
autoplay
playsinline
/>
My Vue JS code is as follows:
data: () => ({
video: null,
}),
mounted() {
navigator.mediaDevices.getUserMedia({
audio: false,
// Prioritize Rear Camera
video: {facingMode: 'environment'},
})
.then((stream) => {
this.video = document.querySelector('video');
this.video.srcObject = stream;
this.video.tracks = stream.getTracks();
});
}
Any help or alternative methods to solve this would be appreciated. My goal is to start a stream from the camera on the webpage and take a photo on click.
Despite the information here Chrome, Firefox, and Edge for iOS do not support the navigator.mediaDevices property due to the fact that under the hood they all use the built-in WebKit rendering engine which does not provide this capability to third parties. There is a bug filed here which includes some promising discussions about how iOS 13.4 may have partially resolved this.
Until Apple decides to provide this, the only option is to check navigator.mediaDevices for null and catch errors on the promise:
if (navigator.mediaDevices == null) { /* unsupported */ }
else {
navigator.mediaDevices.getUserMedia({})
.then((stream) => {})
.catch((err) => { /* unsupported */ })
}
...and provide users with the appropriate feedback.

Categories