Bắt đầu với thiết bị truyền thông

Khi phát triển cho web, tiêu chuẩn WebRTC cung cấp các API để truy cập camera và micrô kết nối với máy tính hoặc điện thoại thông minh. Các thiết bị này thường được gọi là Thiết bị truyền thông và có thể truy cập được bằng JavaScript thông qua đối tượng navigator.mediaDevices. Đối tượng này sẽ triển khai MediaDevices . Từ đối tượng này, chúng ta có thể liệt kê tất cả các thiết bị đã kết nối, theo dõi thiết bị thay đổi (khi một thiết bị được kết nối hoặc ngắt kết nối) và mở một thiết bị để truy xuất Luồng phương tiện (xem bên dưới).

Cách phổ biến nhất để thực hiện việc này là thông qua hàm getUserMedia(). Hàm này trả về lời hứa sẽ phân giải thành MediaStream cho nội dung nghe nhìn phù hợp thiết bị. Hàm này nhận một đối tượng MediaStreamConstraints duy nhất nêu rõ các yêu cầu mà chúng tôi có. Ví dụ: để mở micrô và camera mặc định, chúng ta sẽ thực hiện như sau.

Sử dụng lời hứa

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

Sử dụng chế độ không đồng bộ/chờ

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

Lệnh gọi đến getUserMedia() sẽ kích hoạt một yêu cầu quyền. Nếu người dùng chấp nhận quyền, lời hứa sẽ được giải quyết bằng một MediaStream chứa một video và một bản âm thanh. Nếu quyền bị từ chối, Hệ thống sẽ gửi PermissionDeniedError. Trong trường hợp không có thiết bị nào phù hợp được kết nối thì NotFoundError sẽ được gửi.

Bạn có thể xem tài liệu tham khảo API đầy đủ cho giao diện MediaDevices tại MDN web tài liệu.

Truy vấn thiết bị truyền thông

Trong một ứng dụng phức tạp hơn, nhiều khả năng chúng ta sẽ muốn kiểm tra tất cả các camera và micrô được kết nối cũng như đưa ra phản hồi thích hợp cho người dùng. Bạn có thể thực hiện việc này bằng cách gọi hàm enumerateDevices(). Thao tác này sẽ trả về một lời hứa phân giải thành một mảng MediaDevicesInfo mô tả từng thiết bị truyền thông đã biết. Chúng ta có thể sử dụng thông tin này để trình bày giao diện người dùng họ chọn cách họ thích. Mỗi MediaDevicesInfo chứa một thuộc tính có tên kind với giá trị audioinput, audiooutput hoặc videoinput, cho biết đó là loại thiết bị truyền thông nào.

Sử dụng lời hứa

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

Sử dụng chế độ không đồng bộ/chờ

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

Lắng nghe những thay đổi về thiết bị

Hầu hết máy tính đều hỗ trợ việc cắm nhiều thiết bị trong thời gian chạy. Đó có thể là webcam được kết nối bằng USB, tai nghe Bluetooth hoặc một bộ loa ngoài. Trong để hỗ trợ chính xác điều này, ứng dụng web phải theo dõi các thay đổi thiết bị truyền thông. Bạn có thể thực hiện việc này bằng cách thêm trình nghe vào navigator.mediaDevices cho sự kiện 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);
});

Hạn chế về nội dung nghe nhìn

Đối tượng ràng buộc phải triển khai MediaStreamConstraints mà chúng ta truyền dưới dạng tham số đến getUserMedia(), cho phép chúng ta mở một thiết bị đa phương tiện nào phù hợp với một yêu cầu nhất định. Yêu cầu này có thể rất xác định quá mức (âm thanh và/hoặc video) hoặc rất cụ thể (tối thiểu bằng camera hoặc mã thiết bị chính xác). Các ứng dụng sử dụng trước tiên, API getUserMedia() sẽ kiểm tra các thiết bị hiện có, sau đó chỉ định một quy tắc ràng buộc khớp với thiết bị chính xác bằng cách sử dụng quy tắc ràng buộc deviceId. Nếu có thể, các thiết bị cũng sẽ được định cấu hình theo các điều kiện ràng buộc. T4 có thể bật tính năng loại bỏ tiếng vọng trên micrô hoặc đặt chiều rộng cụ thể hoặc tối thiểu và chiều cao của video từ máy ảnh.

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

Bạn có thể xem tài liệu đầy đủ về giao diện MediaStreamConstraints trên trang web của MDN tài liệu.

Phát trên thiết bị

Sau khi một thiết bị đa phương tiện được mở và có sẵn một MediaStream, chúng ta có thể gán luồng cho một phần tử video hoặc âm thanh để phát luồng trên thiết bị.

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 cần cho phần tử video thông thường được sử dụng với getUserMedia() sẽ thường có các thuộc tính autoplayplaysinline. autoplay sẽ khiến luồng mới được gán cho phần tử phát tự động. Thuộc tính playsinline cho phép video phát tại chỗ thay vì chỉ phát toàn bộ trên một số trình duyệt di động nhất định. Bạn cũng nên sử dụng controls="false" đối với sự kiện phát trực tiếp, trừ phi người dùng có thể tạm dừng chúng.

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