I want to access the mobile camera or webcam through Javascript. I got it working fine for webcams and android devices. When testing on iPhone X iOS 15.6, I only get a black screen, no matter if i choose front or rear camera. The console says Unhandled Promise Rejection: NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
The popup for the permission comes up and I grant it. I also tried to change permissions for Safari generally to allow but it doesn’t change a thing.
Any clues anyone?
Here is the code for the Camera component. using react 18.1.0
export const MemeCam = ({
setShowCam,
handleUpload,
hasWeb3,
isConnected,
mobileCamera
}) => {
const videoRef = useRef(null);
const photoRef = useRef(null);
const [img, setImg] = useState();
const [imgFile, setImgFile] = useState();
const [topText, setTopText] = useState("");
const [bottomText, setBottomText] = useState("");
const [facingMode, setFacingMode] = useState();
const [effectiveCameraHeight, setEffectiveCameraHeight] = useState(0);
const [effectiveCameraWidth, setEffectiveCameraWidth] = useState(0);
useEffect(() => {
if (!mobileCamera) {
setFacingMode("user");
} else {
const facingMode = mobileCamera === "front" ? "user" : "environment";
setFacingMode(facingMode);
}
}, [mobileCamera]);
useEffect(() => {
if (!facingMode) {
return;
}
const getUserCamera = () => {
navigator.mediaDevices
.getUserMedia({
video: {
width: effectiveCameraWidth,
height: effectiveCameraHeight,
facingMode: facingMode
},
audio: false
})
.then((stream) => {
let video = videoRef.current;
let stream_settings = stream.getVideoTracks()[0].getSettings();
setEffectiveCameraHeight(stream_settings.height);
setEffectiveCameraWidth(stream_settings.width);
video.srcObject = stream;
video.play();
})
.catch((error) => {
console.error(error);
});
};
getUserCamera();
}, [videoRef, facingMode, effectiveCameraHeight, effectiveCameraWidth]);
if (
!("mediaDevices" in navigator && "getUserMedia" in navigator.mediaDevices)
) {
return null;
}
const handleImageSave = (canvasReference) => {
if (!photoRef) return null;
canvasToImage(canvasReference, {
name: "custom name",
type: "png",
quality: 0.5
});
};
const handleSnapshot = () => {
let width = effectiveCameraWidth;
let height = effectiveCameraHeight;
const photo = photoRef.current;
const video = videoRef.current;
photo.width = width;
photo.height = height;
let ctx = photo.getContext("2d");
ctx.drawImage(video, 0, 0, width, height);
const image = new Image();
image.src = photo.toDataURL("image/png");
image.onload = () => setImg(image);
};
const writeToCanvas = (event) => {
const text = event.target.value;
const field = event.target.name;
const canvas = photoRef.current;
const width = canvas.width;
const height = canvas.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
ctx.font = "20px Comic Sans MS";
ctx.fillStyle = "white";
ctx.textAlign = "center";
if (field === "topText") {
ctx.fillText(text, width / 2, 20);
ctx.fillText(bottomText, width / 2, height - 10);
}
if (field === "bottomText") {
ctx.fillText(topText, width / 2, 20);
ctx.fillText(text, width / 2, height - 10);
}
setImgFile(canvas.toDataURL("image/png"));
};
const dataURLtoFile = (dataurl, filename) => {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
};
const canMint = hasWeb3 && isConnected;
return (
<StyledMemeCam
cameraWidth={effectiveCameraWidth}
cameraHeight={effectiveCameraHeight}>
<div className="title">
{" "}
Use the Meme of the Day MemeCam and generate your own personal Meme!
</div>
<div className="cheeze-close-btn-wrapper">
<ButtonStandard
onClick={(e) => {
e.preventDefault();
handleSnapshot();
}}
label={!img ? "CHEEZE!" : "RETAKE!"}
/>
<ButtonStandard
onClick={(e) => {
e.preventDefault();
window.location.reload();
}}
label="CLOSE MEMECAM!"
/>
</div>
<video ref={videoRef} className={img ? "hide-me" : "video"}></video>
<canvas ref={photoRef} className={!img ? "hide-me" : "canvas"} />
{img && (
<div className="inputs">
<div className="inputs-fields">
<Input
name="topText"
type="text"
placeholder="Top Text"
value={topText}
onChange={(e) => {
setTopText(e.target.value);
writeToCanvas(e);
}}
/>
<Input
name="bottomText"
type="text"
placeholder="Bottom Text"
value={bottomText}
onChange={(e) => {
setBottomText(e.target.value);
writeToCanvas(e);
}}
/>
</div>
<div className="inputs-buttons">
<ButtonStandard
onClick={(e) => {
e.preventDefault();
handleImageSave(photoRef.current);
}}
label="Save Image"
/>
{canMint ? (
<ButtonStandard
onClick={(e) => {
e.preventDefault();
console.log({ imgFile });
const newFile = dataURLtoFile(imgFile, "newmeme.png");
console.log({ newFile });
handleUpload(newFile);
}}
label="MINT!"
/>
) : (
"Please connect with Web3 to mint!"
)}
</div>
</div>
)}
<div className="description">
<p>Simple take a snapshot and add your own text.</p>
<p>Then Mint it!</p>
<p>You can also download your Meme and save it for later.</p>
<p>We hope you enjoy the Meme of the Day MemeCam</p>
<p>
Please feel free to reach out and give us your feedback about this
feature!
</p>
</div>
</StyledMemeCam>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.produ