WebRTC là công nghệ giúp chúng ta xây dựng ứng dụng stream audio, video, chia sẻ file, desktop, ... thông qua kết nối peer to peer [kết nối trực tiếp giữa các client mà không cần truyền dữ liệu qua server trung gian]. Loạt bài này sẽ giúp các bạn có thể tích hợp công nghệ WebRTC vào ứng dụng web của bạn.
Bạn chuẩn bị trước các tài khoản các trang sau: //heroku.com/ //peerjs.com/ //xirsys.com/ //github.com/
//heroku.com/
//peerjs.com/
//xirsys.com/
//github.com/
Project khởi đầu: //github.com/vanpho93/rtc-start-kit
//github.com/vanpho93/rtc-start-kit
Project kết thúc: //github.com/vanpho93/khoapham-rtc Các bạn có thể theo dõi project cuối mỗi video trong mục commit
//github.com/vanpho93/khoapham-rtc
Các bạn có thể theo dõi project cuối mỗi video trong mục commit
Xem thêm khoá học Lập trình Nodejs tại Khoa Phạm: //khoapham.vn/khoa-hoc-lap-trinh-nodejs.html
Overview
Chúng ta sẽ phát triển ứng dụng demo WebRTC bằng NodeJS.
Nội dung chính
- Lấy được video từ webcam
- Stream video với RTCPeerConnection
- Stream data với RTCDataChannel
- Cài đặt một signaling service để trao đổi messages
- Kết hợp peer connection và signaling
- Chụp ảnh và chia sẻ nó qua một kênh dữ liệu [data channel]
Các service cần cài đặt trước
- Chrome 47 trở lên
- NodeJS, npm
- Hiểu biết cơ bản về HTML, CSS và JavaScript
- Text editor
Stream video từ webcam
Thêm một thẻ
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
6 và một thẻ 'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
7 vào file 'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
8 trong thư mục chính như sau:
Realtime communication with WebRTC
Realtime communication with WebRTC
Thêm đoạn code sau vào file
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
9 trong thư mục navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
0:'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
Giải thích
Khi
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
1 được gọi, trình duyệt sẽ yêu cầu quyền truy cập camera của người dùng. Nếu thành công, một navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
2 sẽ được trả về và được sử dụng như một thẻ navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
3 thông qua thuộc tính navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
4:navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
Tham số
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
5 cho phép chỉ định cái mà media sẽ lấy [có thể là video hoặc audio]var constraints = {
video: true
};
Có thể sử dụng
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
6 cho các options khác như navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
7 chẳng hạn:const hdConstraints = {
video: {
width: {
min: 1280
},
height: {
min: 720
}
}
}
MediaTrackConstraints specification liêt kê tất cả
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
8. Nếu resolution yêu cầu không được hỗ trợ bởi camera hiện tại navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
9 sẽ từ chối với một lỗi var constraints = {
video: true
};
0 và người dùng sẽ không có quyền truy cập camera.Nếu
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
function handleSuccess[stream] {
video.srcObject = stream;
}
9 thành công, var constraints = {
video: true
};
2 từ webcam sẽ được cài đặt làm var constraints = {
video: true
};
3 của thẻ 'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
6.function handleSuccess[stream] {
video.srcObject = stream;
}
Như vậy chúng ta đã biết được cách:
- Lấy video từ webcam
- Cài đặt media constraints.
- Hiển thị video với thẻ
6. Một vài chú ý: Đừng quên thêm thuộc tính'use strict'; var constraints = { video: true }; var video = document.querySelector['video']; function handleSuccess[stream] { video.srcObject = stream; } function handleError[error] { console.error['getUserMedia error: ', error]; } navigator.mediaDevices.getUserMedia[constraints]. then[handleSuccess].catch[handleError];
6 cho thẻvar constraints = { video: true };
6. Thông tin thêm về'use strict'; var constraints = { video: true }; var video = document.querySelector['video']; function handleSuccess[stream] { video.srcObject = stream; } function handleError[error] { console.error['getUserMedia error: ', error]; } navigator.mediaDevices.getUserMedia[constraints]. then[handleSuccess].catch[handleError];
8 xem thêm ở đây Có thể thêm CSS cho thẻ video để hiện video ko bị tràn màn hình:var constraints = { video: true };
video {
max-width: 100%;
width: 320px;
}
Stream video với RTCPeerConnection
Stream data với RTCDataChannel
Cài đặt một signaling service để trao đổi messages
Kết hợp peer connection và signaling
Start
Call
Hang Up
Chụp ảnh và chia sẻ nó qua một kênh dữ liệu [data channel]
Các service cần cài đặt trước
Chrome 47 trở lên
Thêm thông tin về adapter.js
File
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
8 trông như sau:
Realtime communication with WebRTC
Realtime communication with WebRTC
Start
Call
Hang Up
File
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
9 như sau:'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
0 Tạo một cuộc gọi
Mở file
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
8, click button function handleSuccess[stream] {
video.srcObject = stream;
}
2 để get video từ webcam và click function handleSuccess[stream] {
video.srcObject = stream;
}
3 to tạo một function handleSuccess[stream] {
video.srcObject = stream;
}
4. Chúng ta sẽ thấy 2 video giống nhau. WebRTC sử dụng RTCPeerConnection API to cài đặt một connection to stream video giữa các WebRTC clients được biết như function handleSuccess[stream] {
video.srcObject = stream;
}
5. Trong ví dụ này, 2 RTCPeerConnection object ở cùng 1 trang: pc1 và pc2Cài đặt một cuộc gọi giữa 2 WebRTC peers bao gồm 3 bước sau:
- Tạo một RTCPeerConnection cho mỗi client và thêm
4 từ getUserMedia[]`.const hdConstraints = { video: { width: { min: 1280 }, height: { min: 720 } } }
- Lấy và chia sẻ thông tin
7 được biết như làfunction handleSuccess[stream] { video.srcObject = stream; }
8function handleSuccess[stream] { video.srcObject = stream; }
- Lấy và chia sẻ local và remote description, metadata về local media in SDP format
Tưởng tượng rằng Alice và Bob muốn sử dụng RTCPeerConnection để cài đặt một cuộc gọi video: Đầu tiên, Alice và Bob trao đổi các thông tin về network.
function handleSuccess[stream] {
video.srcObject = stream;
}
9 chính là quá trình tìm kiếm video {
max-width: 100%;
width: 320px;
}
0 và video {
max-width: 100%;
width: 320px;
}
1 sử dụng ICE framework.- Alice tạo một
2 với mộtvideo { max-width: 100%; width: 320px; }
3:video { max-width: 100%; width: 320px; }
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
1- Alice gọi getUserMedia[] và thêm
4 thông qua:video { max-width: 100%; width: 320px; }
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
2- Đối tượng
3 từ bước 1 được gọi khivideo { max-width: 100%; width: 320px; }
6 available.video { max-width: 100%; width: 320px; }
- Alice gửi dữ liệu candidate đã được mã hóa cho Bob. Trên thực tế , quá trình này [được biết như là signaling] xảy ra thông quá một tin nhắn dịch vụ [messaging service]. Ở đây 2 RTCPeerConnection object trên cùng một page nên nó có thể kết nối trực tiếp mà không cần một external messaging service.
- When Bob nhận được một
7 từ Alice, anh ấy sẽ gọivideo { max-width: 100%; width: 320px; }
8 để thêm candidate vào remote peer description:video { max-width: 100%; width: 320px; }
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
3WebRTC peers cũng cần tìm và trao đổi thông tin local và remote audio và video media như resolution, dung lượng codec. Signaling trao đổi thông tin media configuration bởi trao đổi metadata được gọi là một
video {
max-width: 100%;
width: 320px;
}
9 và một
Start
Call
Hang Up
0 sử dụng
Start
Call
Hang Up
1 format, gọi tắt là SDPAlice run phương thức
Start
Call
Hang Up
2 . Promise trả về một
Start
Call
Hang Up
3 [Alice's local session description]:'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
4- Nếu thành công, Alice sẽ set một
4 sử dụngStart Call Hang Up
5 và sau đó gửiStart Call Hang Up
6 này tới Bob thông quaStart Call Hang Up
7.Start Call Hang Up - Bob sẽ set
8 mà Alice đã gửi như mộtStart Call Hang Up
9 sử dụngStart Call Hang Up
0. - Bob run phương thức
1, truyền tham số là
9 mà nhận được từ Alice, Sau đó mộtStart Call Hang Up
3 thích hợp được sinh ra.
4 truyền một
3 : Bob sets nó nhưStart Call Hang Up
4 và gửi nó cho Alice.Start Call Hang Up - Khi Alice nhận session description của Bob, cô ấy set nó như một
9 với phương thứcStart Call Hang Up
0.
'use strict';
var constraints = {
video: true
};
var video = document.querySelector['video'];
function handleSuccess[stream] {
video.srcObject = stream;
}
function handleError[error] {
console.error['getUserMedia error: ', error];
}
navigator.mediaDevices.getUserMedia[constraints].
then[handleSuccess].catch[handleError];
5Như vậy chúng ta đã hiểu rõ các bước kết nối và thiết lập các kết nối peer trong WebRTC. Phần sau mình sẽ giới thiệu cách stream qua
9.