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 autoplay
và playsinline
. 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>