Mulai menggunakan perangkat media

Saat mengembangkan untuk web, standar WebRTC menyediakan API untuk mengakses kamera dan mikrofon yang terhubung ke komputer atau smartphone. Perangkat ini umumnya disebut sebagai Perangkat Media dan dapat diakses dengan JavaScript melalui objek navigator.mediaDevices, yang menerapkan antarmuka MediaDevices. Dari objek ini, kita dapat menghitung semua perangkat yang terhubung, memproses perubahan perangkat (saat perangkat terhubung atau terputus), dan membuka perangkat untuk mengambil Aliran Media (lihat di bawah).

Cara yang paling umum digunakan adalah melalui fungsi getUserMedia(), yang menampilkan promise yang akan di-resolve ke MediaStream untuk perangkat media yang cocok. Fungsi ini menggunakan satu objek MediaStreamConstraints yang menentukan persyaratan yang kita miliki. Misalnya, untuk membuka mikrofon dan kamera default, kita akan melakukan hal berikut.

Menggunakan Promise

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

Menggunakan async/await

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

Panggilan ke getUserMedia() akan memicu permintaan izin. Jika pengguna menerima izin, promise akan diselesaikan dengan MediaStream yang berisi satu video dan satu trek audio. Jika izin ditolak, PermissionDeniedError akan ditampilkan. Jika tidak ada perangkat yang cocok yang terhubung, NotFoundError akan ditampilkan.

Referensi API lengkap untuk antarmuka MediaDevices tersedia di dokumen web MMD.

Membuat kueri perangkat media

Pada aplikasi yang lebih kompleks, kemungkinan besar kita ingin memeriksa semua kamera dan mikrofon yang terhubung dan memberikan masukan yang sesuai kepada pengguna. Tindakan ini dapat dilakukan dengan memanggil fungsi enumerateDevices(). Tindakan ini akan menampilkan promise yang di-resolve ke array MediaDevicesInfo yang mendeskripsikan setiap perangkat media yang diketahui. Kita dapat menggunakannya untuk menampilkan UI kepada pengguna sehingga mereka dapat memilih UI yang mereka sukai. Setiap MediaDevicesInfo berisi properti bernama kind dengan nilai audioinput, audiooutput, atau videoinput, yang menunjukkan jenis perangkat media tersebut.

Menggunakan Promise

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

Menggunakan async/await

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

Memproses perubahan perangkat

Sebagian besar komputer mendukung penyambungan berbagai perangkat selama runtime. Hal ini dapat berupa webcam yang terhubung melalui USB, headset Bluetooth, atau sekumpulan speaker eksternal. Untuk mendukung hal ini dengan benar, aplikasi web harus memproses perubahan pada perangkat media. Hal ini dapat dilakukan dengan menambahkan pemroses ke navigator.mediaDevices untuk peristiwa 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);
});

Batasan media

Objek batasan, yang harus mengimplementasikan antarmuka MediaStreamConstraints, yang kita teruskan sebagai parameter ke getUserMedia() memungkinkan kita membuka perangkat media yang cocok dengan persyaratan tertentu. Persyaratan ini dapat ditentukan secara longgar (audio dan/atau video), atau sangat spesifik (resolusi kamera minimum atau ID perangkat yang tepat). Sebaiknya aplikasi yang menggunakan getUserMedia() API terlebih dahulu memeriksa perangkat yang ada, lalu menentukan batasan yang cocok dengan perangkat yang tepat menggunakan batasan deviceId. Perangkat juga akan, jika memungkinkan, dikonfigurasi sesuai dengan batasan. Kita dapat mengaktifkan pengurangan gema pada mikrofon atau menetapkan lebar dan tinggi tertentu pada video dari kamera.

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

Dokumentasi lengkap untuk antarmuka MediaStreamConstraints dapat ditemukan di dokumen web MDN.

Pemutaran lokal

Setelah perangkat media dibuka dan MediaStream tersedia, kita dapat menetapkannya ke elemen video atau audio untuk memutar streaming secara lokal.

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

HTML yang diperlukan untuk elemen video standar yang digunakan dengan getUserMedia() biasanya akan memiliki atribut autoplay dan playsinline. Atribut autoplay akan menyebabkan streaming baru yang ditetapkan ke elemen diputar secara otomatis. Atribut playsinline memungkinkan video diputar inline, bukan hanya di layar penuh, di browser seluler tertentu. Sebaiknya gunakan juga controls="false" untuk live stream, kecuali jika pengguna dapat menjedanya.

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