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

MediaDevices 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>