Google is committed to advancing racial equity for Black communities. See how.
此页面由 Cloud Translation API 翻译。
Switch to English

媒体设备入门

在开发Web时,WebRTC标准提供了API,用于访问连接到计算机或智能手机的相机和麦克风。这些设备通常称为媒体设备,可以通过实现MediaDevices接口的navigator.mediaDevices对象使用JavaScript进行访问。通过该对象,我们可以枚举所有已连接的设备,侦听设备更改(连接或断开设备时),并打开设备以检索媒体流(请参见下文)。

最常用的方法是通过getUserMedia()函数,该函数返回一个承诺,该承诺将解析为匹配媒体设备的MediaStream 。此函数采用一个MediaStreamConstraints对象,该对象指定我们具有的要求。例如,要简单地打开默认的麦克风和摄像头,我们将执行以下操作。

使用承诺

 const constraints = {
    'video': true,
    'audio': true
}
navigator.mediaDevices.getUserMedia(constraints)
    .then(stream => {
        console.log('Got MediaStream:', stream);
    })
    .catch(error => {
        console.error('Error accessing media devices.', error);
    });
 

使用异步/等待

 const openMediaDevices = async (constraints) => {
    return await navigator.mediaDevices.getUserMedia(constraints);
}

try {
    const stream = openMediaDevices({'video':true,'audio':true});
    console.log('Got MediaStream:', stream);
} catch(error) {
    console.error('Error accessing media devices.', error);
}
 

调用getUserMedia()将触发权限请求。如果用户接受许可,则通过包含一个视频和一个音轨的MediaStream来解决承诺。如果权限被拒绝,则抛出PermissionDeniedError 。如果没有连接匹配的设备,则会抛出NotFoundError

可在MDN Web文档中找到MediaDevices接口的完整API参考。

查询媒体设备

在更复杂的应用程序中,我们很可能希望检查所有连接的摄像机和麦克风,并向用户提供适当的反馈。这可以通过调用函数enumerateDevices()来完成。这将返回一个承诺,该承诺将解析为描述每个已知媒体设备的MediaDevicesInfo数组。我们可以使用它向用户展示一个UI,让他们选择自己喜欢的UI。每个MediaDevicesInfo包含一个名为kind的属性,其值audioinputaudiooutputvideoinput ,指示其是哪种媒体设备。

使用承诺

 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));
 

使用异步/等待

 async function getConnectedDevices(type) {
    const devices = await navigator.mediaDevices.enumerateDevices();
    return devices.filter(device => device.kind === type)
}

const videoCameras = getConnectedDevices('videoinput');
console.log('Cameras found:', videoCameras);
 

侦听设备更改

大多数计算机在运行时都支持插入各种设备。它可能是通过USB,蓝牙耳机或一组外部扬声器连接的网络摄像头。为了适当地支持此功能,Web应用程序应侦听媒体设备的更改。这可以通过在navigator.mediaDevicesdevicechange事件添加一个侦听器来完成。

 // Updates the select element with the provided set of cameras
function updateCameraList(cameras) {
    const listElement = document.querySelector('select#availableCameras');
    listElement.innerHTML = '';
    cameras.map(camera => {
        const cameraOption = document.createElement('option');
        cameraOption.label = camera.label;
        cameraOption.value = camera.deviceId;
    }).forEach(cameraOption => listElement.add(cameraOption));
}

// Fetch an array of devices of a certain type
async function getConnectedDevices(type) {
    const devices = await navigator.mediaDevices.enumerateDevices();
    return devices.filter(device => device.kind === type)
}

// Get the initial set of cameras connected
const videoCameras = getConnectedDevices('videoinput');
updateCameraList(videoCameras);

// Listen for changes to media devices and update the list accordingly
navigator.mediaDevices.addEventListener('devicechange', event => {
    const newCameraList = getConnectedDevices('video');
    updateCameraList(newCameraList);
});
 

媒体限制

作为参数传递给getUserMedia()的约束对象(必须实现MediaStreamConstraints接口getUserMedia()允许我们打开符合特定要求的媒体设备。可以非常宽松地定义此要求(音频和/或视频),也可以非常具体地定义此要求(最低摄像机分辨率或确切的设备ID)。建议使用getUserMedia() API的应用程序先检查现有设备,然后使用deviceId约束指定一个与确切设备匹配的约束。如果可能,还将根据约束条件配置设备。我们可以在麦克风上启用回声消除,或者设置来自摄像机的视频的特定或最小宽度和高度。

 async function getConnectedDevices(type) {
    const devices = await navigator.mediaDevices.enumerateDevices();
    return devices.filter(device => device.kind === type)
}

// Open camera with at least minWidth and minHeight capabilities
async function openCamera(cameraId, minWidth, minHeight) {
    const constraints = {
        'audio': {'echoCancellation': true},
        'video': {
            'deviceId': cameraId,
            'width': {'min': minWidth},
            'height': {'min': minHeight}
            }
        }

    return await navigator.mediaDevices.getUserMedia(constraints);
}

const cameras = getConnectedDevices('videoinput');
if (cameras && cameras.length > 0) {
    // Open first available video camera with a resolution of 1280x720 pixels
    const stream = openCamera(cameras[0].deviceId, 1280, 720);
}
 

有关MediaStreamConstraints接口的完整文档,请参见MDN Web文档

本地播放

打开媒体设备并提供MediaStream ,我们可以将其分配给视频或音频元素以在本地播放流。

 async function playVideoFromCamera() {
    try {
        const constraints = {'video': true, 'audio': true};
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        const videoElement = document.querySelector('video#localVideo');
        videoElement.srcObject = stream;
    } catch(error) {
        console.error('Error opening video camera.', error);
    }
}
 

getUserMedia()一起使用的典型视频元素所需的HTML通常具有属性autoplayplaysinlineautoplay属性将使分配给该元素的新流自动播放。 playsinline属性允许视频在某些移动浏览器上内联播放,而不仅仅是全屏播放。还建议对实时流使用controls="false" ,除非用户应该能够暂停它们。

 <html>
<head><title>Local video playback</video></head>
<body>
    <video id="localVideo" autoplay playsinline controls="false"/>
</body>
</html>