MediaDevices.getUserMedia() es parte de la API de captura de medios webRTC y se utiliza para obtener acceso a la cámara y al micrófono conectados al dispositivo del usuario (computadora del usuario, teléfono inteligente, etc.) desde el navegador. Cuando se invoca getUserMedia() , el navegador solicita permiso al usuario para utilizar las entradas multimedia (cámara, micrófono o ambos) conectadas al dispositivo del usuario.
Sintaxis:
navigator.mediaDevices.getUserMedia( MediaStreamConstraints ) .then( MediaStream => { // Code that uses the MediaStream }).catch( error => { // Code to handle the error });
Usando la API getUserMedia() : se puede acceder a getUserMedia() accediendo al objeto singleton navigator.mediaDevices que ofrece varios métodos para acceder a la cámara, el micrófono y compartir la pantalla. Cuando se invoca getUserMedia( ), el navegador solicita permiso al usuario para acceder a la cámara o al micrófono del dispositivo disponible (según el parámetro MediaStreamConstraints dado). Si el Usuario otorga el permiso, devuelve una Promesa que se resuelve en un MediaStream .
Nota: también se puede acceder a getUserMedia() a través de navigator.getUserMedia() , pero está en desuso y, por lo tanto, no se recomienda.
¿Qué es un MediaStream?
MediaStream es simplemente un flujo de datos de contenido de audio o video que no se guarda en la memoria del dispositivo, sino que simplemente se «pasa» a un elemento de audio o video específico como datos de origen. Tenga en cuenta que los datos del contenido multimedia no se guardan en la memoria en ejecución, lo que significa que si no tiene datos de audio o video «descargados previamente», aún puede usar la transmisión multimedia para reproducir el contenido de audio o video tal como lo hace. no necesita ser descargado.
¿Qué es MediaStreamConstraints?
MediaStreamConstraints es un objeto que contiene todas las restricciones, como qué tipo de datos se transmitirán (video o audio o ambos), cuál debería ser la resolución de la cámara, etc.
const mediaStreamConstraints = { audio: true, video: true }; // It basically tells the getUserMedia() to // open both the camera and the microphone const stream = await navigator.mediaDevices .getUserMedia(mediaStreamConstraints);
Usando el MediaStream recibido de getUserMedia(): si el usuario otorga permiso para acceder a la cámara y al micrófono, este método devuelve una promesa cuyo controlador de cumplimiento recibe un MediaStream que podemos usar en la función del controlador. Por lo general, pasamos el MediaStream recibido a un elemento de video o audio como fuente (usando el atributo srcObject del elemento de video o audio).
Javascript
navigator.mediaDevices.getUserMedia( MediaStreamConstraints ) .then( MediaStream => { /*assuming that there is a video tag having an id 'video' in the index.html*/ const videoElem = document.getElementById( 'video'); /*it is important to use the srcObject attribute and not the src attribute because, the src attribute does not support the mediaStream as a value*/ videoElem.srcObject = mediaStream; //Don't forget to set the autoplay attribute to true video.autoplay = true; }).catch( error => { //code to handle the error }); //Or using async/await — async function accessCamera() { const videoElem = document.getElementById( 'video'); let stream = null; try{ stream = await navigator.mediaDevices.getUserMedia( MediaStreamConstraints ); //adding the received stream to the source of the video element videoElem.srcObject = stream; videoElem.autoplay = true; }catch(err) { //code to handle the error } }
¿Qué pasa si el usuario no da permiso para acceder a la cámara y al micrófono?
Si el usuario niega dar permiso, getUserMedia() arroja un error NotAllowedError que podemos capturar usando el bloque catch. Si el usuario simplemente ignora el aviso, no sucede nada (la promesa nunca se resuelve ni se rechaza).
Ahora, hablemos de MediaStreamConstraints con más detalles:
Restricciones de flujo de medios:
Este es básicamente un objeto que contiene toda la información sobre qué tipo de medios usar, cuál debería ser la resolución de la cámara, qué dispositivo usar como entrada de medios, etc. El objeto MediaStreamConstraints más simple se ve así:
const constraints = { audio: false, // or true if you want to enable audio video: true // or false if you want to disable video }; // Includes only the video media if available
El objeto MediaStreamConstraints tiene solo dos propiedades (miembros): audio y video, ambos aceptan un valor booleano que le dice al navegador si debe incluir ese contenido multimedia específico en el flujo de medios resultante. «verdadero» hace que los medios sean «requeridos» en el flujo de medios resultante, si esos medios «requeridos» no están disponibles, entonces getUserMedia() arroja «NotFoundError». Por ejemplo, getUserMedia() arrojará «NotFoundError» para las restricciones anteriores si el dispositivo del usuario no tiene una cámara.
Además, puede agregar más restricciones para usar contenido multimedia con algunas capacidades preferidas:
Puede especificar la resolución de la cámara que el navegador debería preferir:
Javascript
/* This constraints object tells the browser to use the camera having 1200 X 800 resolution if available*/ const constraints = { //disables the audio media content in the resulting media stream audio: false, video: { width: 1200, height: 800 } // Inherently sets video content to true or "required" };
«preferir» porque el objeto de restricciones anterior no garantiza que el navegador use una cámara con esa resolución. El navegador primero verifica si hay algún tipo de entrada de medios que coincida con las restricciones dadas, y si hay alguna, solo el navegador usa esa entrada de medios coincidente. Pero si no hay ninguno que coincida con las restricciones dadas, entonces el navegador usa el dispositivo con la coincidencia más cercana.
Pero si desea hacer que algunas capacidades sean «requeridas» u obligatorias o aplicar algún límite a las capacidades, entonces puede usar varias palabras clave:
- Las palabras clave «min» y «max»:
Como sugieren los nombres de las palabras clave, la palabra clave » min » le dice al navegador que se requiere que los medios correspondientes tengan al menos las capacidades dadas, de manera similar, la palabra clave » max» le dice al navegador que es obligatorio para que los medios correspondientes tengan como máximo la restricción especificada. Si ningún dispositivo de entrada de medios cumple con las restricciones dadas, la promesa devuelta se rechaza con «NotFoundError».
Javascript
/* This constraints object tells the browser to use the camera having resolution between 1200 X 720 and 1600 X 1080 resolution if available otherwise the returned promise is rejected with "NotFoundError" */ const constraints = { //disables the audio media content in the resulting media stream audio: false, video: { width: { min: 1200, max: 1600 }, height: { min: 720, max: 1080 } } }; // Inherently sets video content to true or "required"
- La palabra clave «deviceId»:
La propiedad » deviceId » le pide al navegador que use el dispositivo de entrada de medios que tiene el deviceId dado, si está disponible; de lo contrario, use otros dispositivos de entrada disponibles. El deviceId se puede obtener del método navigator.mediaDevices.enumerateDevices() que devuelve una promesa que se resuelve en una lista de cámaras, micrófonos, auriculares, etc. conectados. Cada dispositivo conectado tiene una identificación única e indescifrable llamada «deviceId».
Javascript
//initializing the deviceId with null let deviceId = null; //returns a promise that resolves to a list of //connected devices navigator.mediaDevices.enumerateDevices() .then( devices => { devices.forEach(device => { //if the device is a video input //then get its deviceId if(device.kind === 'videoinput'){ deviceId = device.deviceId; } }); }) .catch(err => { //handle the error }); /* This constraints object tells the browser to use the camera having the given deviceId if available otherwise use other available devices*/ const constraints = { //disables the audio media content in the resulting media stream audio: false, video: { deviceId: deviceId } }; // Inherently sets video content to true or "required"
3. La palabra clave “exacta”:
La propiedad «exacta» le dice al navegador que es obligatorio usar un medio que tenga exactamente la restricción correspondiente
Javascript
// This constraints object tells the browser to use the camera having exactly the given deviceId if available otherwise the returned promise is rejected with "NotFoundError" */ const constraints = { audio: { /* browser prefers the device having the given deviceId if available otherwise use other devices*/ deviceId: audioDeviceId }, video: { deviceId: { exact: someId } } }; // Inherently sets video and audio content to true or "required"
4. La propiedad “ideal”:
La propiedad «ideal» le dice al navegador que el valor de restricción dado es el valor ideal y que se debe usar el dispositivo que tiene la restricción «ideal». Cualquier valor de propiedad normal es inherentemente ideal.
Javascript
/* This constraints object tells the browser to use the camera having 1200 X 800 resolution if available */ const constraints = { audio: true //enable the audio media track video: { width: 1200, // same as width: {ideal: 1200} height: 800 // same as height: {ideal: 800} } }; // Inherently sets video content to true or "required"
5. La propiedad “facingMode”:
Especifica si usar la cámara frontal o la trasera, si está disponible. Se utiliza principalmente para dispositivos móviles.
Javascript
const constraints = { //disables the audio media content in the resulting media stream audio: false, video: { facingMode: "user" //prefers front camera if available // or facingMode: "environment" --> perfers rear camera if available } }; // Inherently sets video content to true or "required"
Ejemplo de uso de getUserMedia() :
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { text-align: center; display: flex; flex-direction: column; justify-content: center; align-items: center; } video { background-color: black; margin-bottom: 1rem; } #error { color: red; padding: 0.6rem; background-color: rgb(236 157 157); margin-bottom: 0.6rem; display: none; } </style> <title>GetUserMedia demo</title> </head> <body> <h1> WebRTC getUserMedia() demo</h1> <!-- If you use the playsinline attribute then the video is played "inline". If you omit this attribute then it works normal in the desktop browsers, but for the mobile browsers, the video takes the fullscreen by default. And don't forget to use the autoplay attribute--> <video id='video' width="600" height="300" autoplay playsinline> Sorry, video element not supported in your browser </video> <div id="error"></div> <button onclick="openCamera()"> Open Camera</button> <script> const videoElem = document.getElementById('video'); const errorElem = document.getElementById('error'); //Declare the MediaStreamConstraints object const constraints = { audio: true, video: true } function openCamera() { //Ask the User for the access of the device camera and microphone navigator.mediaDevices.getUserMedia(constraints) .then(mediaStream => { /* The received mediaStream contains both the video and audio media data*/ /*Add the mediaStream directly to the source of the video element using the srcObject attribute*/ videoElem.srcObject = mediaStream; }).catch(err => { // handling the error if any errorElem.innerHTML = err; errorElem.style.display = "block"; }); } </script> </body> </html>
Producción:
Ahora, si hace clic en el botón «Abrir cámara», el navegador le pedirá permiso, si lo permite, se verá a sí mismo en la pantalla. Pero si lo niega, puede ver el error justo debajo del elemento de video en un cuadro rojo:
Cómo cerrar la cámara y el micrófono:
Hasta ahora, hemos discutido cómo abrir la cámara desde el navegador, no hemos hecho nada para dejar de usar la cámara y el micrófono. Sin embargo, si cierra la pestaña o la ventana, el navegador deja de usar la cámara y el micrófono automáticamente. Pero si desea cerrar la cámara y el micrófono usted mismo, puede seguir el siguiente código
Ejemplo 2: Primero, agregue un botón «Cerrar cámara» y el método «cerrar cámara().
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { text-align: center; display: flex; flex-direction: column; justify-content: center; align-items: center; } video { background-color: black; margin-bottom: 1rem; } #error { color: red; padding: 0.6rem; background-color: rgb(236 157 157); margin-bottom: 0.6rem; display: none; } </style> <title>GetUserMedia demo</title> </head> <body> <h1> WebRTC getUserMedia() demo</h1> <!-- If you use the playsinline attribute then the video is played "inline". If you omit this attribute then it works normal in the desktop browsers, but for the mobile browsers, the video takes the fullscreen by default. And don't forget to use the autoplay attribute--> <video id='video' width="600" height="300" autoplay playsinline> Sorry, video element not supported in your browsers </video> <div id="error"></div> <div id="button-container"> <button onclick="openCamera()"> Open Camera</button> <!-- Close Camera button --> <button onclick='closeCamera()'>Close Camera</button> </div> <script> const videoElem = document.getElementById('video'); const errorElem = document.getElementById('error'); let receivedMediaStream = null; //Declare the MediaStreamConstraints object const constraints = { audio: true, video: true } function openCamera() { //Ask the User for the access of the device camera and microphone navigator.mediaDevices.getUserMedia(constraints) .then(mediaStream => { // The received mediaStream contains both the // video and audio media data //Add the mediaStream directly to the source of the video element // using the srcObject attribute videoElem.srcObject = mediaStream; // make the received mediaStream available globally receivedMediaStream = mediaStream; }).catch(err => { // handling the error if any errorElem.innerHTML = err; errorElem.style.display = "block"; }); } const closeCamera = () => { if (!receivedMediaStream) { errorElem.innerHTML = "Camera is already closed!"; errorElem.style.display = "block"; } else { /* MediaStream.getTracks() returns an array of all the MediaStreamTracks being used in the received mediaStream we can iterate through all the mediaTracks and stop all the mediaTracks by calling its stop() method*/ receivedMediaStream.getTracks().forEach(mediaTrack => { mediaTrack.stop(); }); errorElem.innerHTML = "Camera closed successfully!" errorElem.style.display = "block"; } } </script> </body> </html>
Producción:
Antes:
Después de hacer clic en el botón «Cerrar cámara»:
El método closeCamera() verifica si la cámara y el micrófono están cerrados o no al verificar la variable receiveMediaStream. Si es nulo, significa que la cámara y el micrófono están cerrados; de lo contrario, llama al método getTracks() del MediaStream recibido, que devuelve una array de MediaStreamTracks. Puede detener esas pistas multimedia llamando a su método stop() .