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>