Pierwsze kroki z urządzeniami multimedialnymi

Przy programowaniu do internetu standard WebRTC zapewnia interfejsy API umożliwiające dostęp kamer i mikrofonów podłączonych do komputera lub smartfona. Te urządzenia są potocznie nazywane „urządzeniami multimedialnymi” i można je otworzyć za pomocą języka JavaScript. za pomocą obiektu navigator.mediaDevices, który implementuje interfejs MediaDevices za pomocą prostego interfejsu online. Na podstawie tego obiektu możemy wyliczyć wszystkie połączone urządzenia, nasłuchiwać zmiana urządzenia (gdy urządzenie jest połączone lub odłączone) i otwarcie urządzenia; aby pobrać strumień multimediów (patrz poniżej).

Najpopularniejszym sposobem jest podanie tej funkcji za pomocą funkcji getUserMedia(), która zwraca obietnicę, która zostanie rozstrzygnięta na MediaStream w przypadku pasujących multimediów urządzenia. Ta funkcja przyjmuje pojedynczy obiekt MediaStreamConstraints, który określa nasze wymagania. Aby na przykład otworzyć domyślny mikrofon i kamerę, należy wykonać następujące czynności.

Korzystanie z obietnic

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

Używanie asynchronicznego/oczekiwania

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

Wywołanie getUserMedia() spowoduje wysłanie prośby o uprawnienia. Jeśli użytkownik akceptuje to uprawnienie, obietnica jest zakończona za pomocą elementu MediaStream zawierającego jeden film i jedną ścieżkę dźwiękową. W przypadku odmowy uprawnień PermissionDeniedError trafia na piłkę Na wypadek, gdyby nie znaleziono pasujących urządzeń połączono, zostanie zgłoszony NotFoundError.

Pełna dokumentacja interfejsu API usługi MediaDevices jest dostępna na stronie MDN dokumenty.

Wysyłanie zapytań dotyczących urządzeń multimedialnych

Przy bardziej złożonej aplikacji będziemy prawdopodobnie sprawdzać podłączone kamery i mikrofony oraz przekazywać odpowiednie informacje zwrotne użytkownika. Można to zrobić, wywołując funkcję enumerateDevices(). Dzięki temu zwraca obietnicę, która kończy się na tablicy MediaDevicesInfo, która opisuje każdego znanego urządzenia multimedialnego. Możemy to wykorzystać do zaprezentowania użytkownikowi interfejsu i wybiorą tę, która im odpowiada. Każdy element MediaDevicesInfo zawiera właściwość o nazwie kind o wartości audioinput, audiooutput lub videoinput, która wskazuje typu urządzenia multimedialnego.

Korzystanie z obietnic

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

Używanie asynchronicznego/oczekiwania

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

Nasłuchiwanie zmian dotyczących urządzeń

Większość komputerów pozwala podłączyć różne urządzenia podczas działania. Może to być kamera internetowa podłączona przez USB, zestaw słuchawkowy Bluetooth lub zestaw głośników zewnętrznych. W Aby to obsługiwać, aplikacja internetowa powinna nasłuchiwać zmian urządzeń multimedialnych. Można to zrobić, dodając detektor do navigator.mediaDevices dla wydarzenia devicechange.

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

Ograniczenia dotyczące multimediów

Obiekt ograniczeń, który musi implementować interfejs MediaStreamConstraints który przekazujemy jako parametr do getUserMedia(), pozwalamy na otwarcie urządzenia multimedialnego spełniające określone wymagania. Ten wymóg może być bardzo luźno zdefiniowane (dźwięk i/lub obraz) lub bardzo szczegółowe (minimalna jakość w przypadku kamery rozdzielczość lub dokładny identyfikator urządzenia). Zaleca się, aby aplikacje używające języka interfejs API getUserMedia() najpierw sprawdza istniejące urządzenia, a potem określa ograniczenie pasujące do konkretnego urządzenia z ograniczeniem deviceId. Urządzenia będą też w miarę możliwości skonfigurowane zgodnie z obowiązującymi ograniczeniami. Śr może włączyć redukcję echa w mikrofonach lub ustawić konkretną bądź minimalną szerokość oraz wysokość filmu od kamery.

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

Pełną dokumentację interfejsu MediaStreamConstraints znajdziesz w witrynie MDN dokumenty.

Odtwarzanie lokalne

Po otwarciu urządzenia multimedialnego i udostępnieniu urządzenia MediaStream możesz go przypisać do elementu wideo lub audio, aby odtwarzać strumień lokalnie.

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

Kod HTML potrzebny w typowym elemencie wideo używanym w kodzie getUserMedia() będzie zwykle mają atrybuty autoplay i playsinline. autoplay spowoduje automatyczne odtwarzanie nowych strumieni przypisanych do elementu. Atrybut playsinline umożliwia odtwarzanie filmu w tekście, a nie tylko w całości ekranu w niektórych przeglądarkach mobilnych. Zalecane jest też użycie controls="false" w przypadku transmisji na żywo, chyba że użytkownik powinien mieć możliwość wstrzymania .

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