Simple-peer
Video, âm thanh và kênh dữ liệu sử dụng WebRTC đơn giản.
Chúng tôi đang tuyển dụng một chuyên gia ứng dụng di động WebRTC ngang hàng.
DFINITY đang xây dựng một ứng dụng di động WebRTC dựa trên ngang hàng thú vị để giúp cải thiện nền dân chủ trên mạng Internet Computer blockchain. Ứng dụng di động này kết nối nhóm lên đến bốn người trong cuộc gọi âm thanh và video sử dụng WebRTC ngang hàng để họ có thể chứng minh độc nhất về sự hiện diện của họ.
Chúng tôi đang tìm kiếm một kỹ sư phần mềm hoặc tư vấn có thể giúp chúng tôi giải quyết các vấn đề đáng tin cậy (phụ thuộc vào nền tảng) trong việc triển khai của chúng tôi. Chúng tôi quan tâm đến ứng viên có kinh nghiệm WebRTC đáng kể cho các ứng dụng di động Web, kinh nghiệm với các mẫu giao tiếp khác nhau (ví dụ: ngang hàng, chuyển tiếp máy chủ) và kỹ năng giải quyết vấn đề đáng kể. Có kinh nghiệm trong kiểm tra tự động của loại ứng dụng này là một điểm cộng. Lương cực kỳ cạnh tranh cho sự chuyên môn đúng đắn. Để biết thêm chi tiết, vui lòng xem full job description.
Tính năng
- Giao diện API ngắn gọn theo phong cách node.js cho WebRTC
- Hoạt động trên node và trình duyệt!
- Hỗ trợ luồng video/âm thanh
- Hỗ trợ kênh dữ liệu
- Dữ liệu văn bản và nhị phân
- Giao diện node.js duplex stream
- Hỗ trợ các tùy chọn nâng cao như:
- Bật/tắt trickle ICE candidates
- Cấu hình tùy chọn thủ công
- Bộ trình tạo và đàm phán lại
Gói này được sử dụng bởi WebTorrent và nhiều gói khác.
- Cài đặt
- Ví dụ
- Ví dụ đơn giản hơn
- Kênh dữ liệu
- Video/âm thanh
- Video/âm thanh động
- Trong node
- Giao diện API
- Sự kiện
- Mã lỗi
- Kết nối nhiều hơn 2 ngang hàng?
- Sử dụng bộ nhớ
- Kết nối không hoạt động trên một số mạng?
- Ai đang sử dụng
simple-peer
? - giấy phép
cài đặt
npm install simple-peer
Gói này hoạt động trong trình duyệt với browserify. Nếu bạn không sử dụng trình bundler, bạn có thể sử dụng tập lệnh đơn simplepeer.min.js
trực tiếp trong thẻ <script>
. Điều này xuất ra một hàm tạo SimplePeer
trên window
. Bất cứ nơi nào bạn thấy Peer
trong các ví dụ dưới đây, thay thế bằng SimplePeer
.
cách sử dụng
Hãy tạo một trang html cho phép bạn kết nối thủ công hai peer:
<html>
<body>
<style>
#outgoing {
width: 600px;
word-wrap: break-word;
white-space: normal;
}
</style>
<form>
<textarea id="incoming"></textarea>
<button type="submit">submit</button>
</form>
<pre id="outgoing"></pre>
<script src="simplepeer.min.js"></script>
<script>
const p = new SimplePeer({
initiator: location.hash === '#1',
trickle: false
})
p.on('error', err => console.log('error', err))
p.on('signal', data => {
console.log('SIGNAL', JSON.stringify(data))
document.querySelector('#outgoing').textContent = JSON.stringify(data)
})
document.querySelector('form').addEventListener('submit', ev => {
ev.preventDefault()
p.signal(JSON.parse(document.querySelector('#incoming').value))
})
p.on('connect', () => {
console.log('CONNECT')
p.send('whatever' + Math.random())
})
p.on('data', data => {
console.log('data: ' + data)
})
</script>
</body>
</html>
Truy cập index.html#1
từ trình duyệt một (người bắt đầu) và index.html
từ trình duyệt khác (người nhận).
Một “đề nghị” sẽ được tạo ra bởi người bắt đầu. Dán nó vào biểu mẫu của người nhận và nhấn nút gửi. Người nhận tạo ra một “trả lời”. Dán nó vào biểu mẫu của người bắt đầu và nhấn nút gửi.
Bây giờ bạn đã có một kết nối P2P trực tiếp giữa hai trình duyệt!
Một ví dụ đơn giản hơn
Ví dụ này tạo ra hai peer trong cùng một trang web.
Trong ứng dụng thực tế, bạn sẽ không bao giờ làm như vậy. Các phiên bản “Peer” của người gửi và người nhận sẽ tồn tại trong các trình duyệt riêng biệt. Một “máy chủ tín hiệu” (thường được thực hiện bằng websockets) sẽ được sử dụng để trao đổi dữ liệu tín hiệu giữa hai trình duyệt cho đến khi kết nối peer-to-peer được thiết lập.
các kênh dữ liệu
var Peer = require('simple-peer')
var peer1 = new Peer({ initiator: true })
var peer2 = new Peer()
peer1.on('signal', data => {
// when peer1 has signaling data, give it to peer2 somehow
peer2.signal(data)
})
peer2.on('signal', data => {
// when peer2 has signaling data, give it to peer1 somehow
peer1.signal(data)
})
peer1.on('connect', () => {
// wait for 'connect' event before using the data channel
peer1.send('hey peer2, how is it going?')
})
peer2.on('data', data => {
// got a data channel message
console.log('got a message from peer1: ' + data)
})
video/voice
Video/voice cũng rất đơn giản! Trong ví dụ này, peer1 gửi video cho peer2.
var Peer = require('simple-peer')
// get video/voice stream
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(gotMedia).catch(() => {})
function gotMedia (stream) {
var peer1 = new Peer({ initiator: true, stream: stream })
var peer2 = new Peer()
peer1.on('signal', data => {
peer2.signal(data)
})
peer2.on('signal', data => {
peer1.signal(data)
})
peer2.on('stream', stream => {
// got remote video stream, now let's show it in a video tag
var video = document.querySelector('video')
if ('srcObject' in video) {
video.srcObject = stream
} else {
video.src = window.URL.createObjectURL(stream) // for older browsers
}
video.play()
})
}
Đối với video hai chiều, chỉ cần truyền tùy chọn stream
vào cả hai hàm tạo Peer
. Dễ dàng!
Lưu ý rằng getUserMedia
chỉ hoạt động trong pages loaded via https.
video/voice linh hoạt
Cũng có thể thiết lập một kết nối chỉ dữ liệu ban đầu, và sau đó thêm một luồng video/voice nếu cần.
var Peer = require('simple-peer') // create peer without waiting for media
var peer1 = new Peer({ initiator: true }) // you don't need streams here
var peer2 = new Peer()
peer1.on('signal', data => {
peer2.signal(data)
})
peer2.on('signal', data => {
peer1.signal(data)
})
peer2.on('stream', stream => {
// got remote video stream, now let's show it in a video tag
var video = document.querySelector('video')
if ('srcObject' in video) {
video.srcObject = stream
} else {
video.src = window.URL.createObjectURL(stream) // for older browsers
}
video.play()
})
function addMedia (stream) {
peer1.addStream(stream) // <- add streams to peer dynamically
}
// then, anytime later...
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(addMedia).catch(() => {})
Cảm ơn bạn!
trong node
Để sử dụng thư viện này trong node, truyền vào opts.wrtc
như một tham số (xem các tùy chọn hàm tạo):
var Peer = require('simple-peer')
var wrtc = require('wrtc')
var peer1 = new Peer({ initiator: true, wrtc: wrtc })
var peer2 = new Peer({ wrtc: wrtc })
api
peer = new Peer([opts])
Tạo một kết nối WebRTC mới.
Luôn thiết lập một “kênh dữ liệu” cho truyền thông văn bản/nhị phân, vì nó rẻ và thường hữu ích. Đối với truyền thông video/voice, truyền tùy chọn stream
.
Nếu opts
được chỉ định, các tùy chọn mặc định (hiển thị dưới đây) sẽ bị ghi đè.
{
initiator: false,
channelConfig: {},
channelName: '<random string>',
config: { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:global.stun.twilio.com:3478?transport=udp' }] },
offerOptions: {},
answerOptions: {},
sdpTransform: function (sdp) { return sdp },
stream: false,
streams: [],
trickle: true,
allowHalfTrickle: false,
wrtc: {}, // RTCPeerConnection/RTCSessionDescription/RTCIceCandidate
objectMode: false
}
Các tùy chọn thực hiện các chức năng sau:
initiator
– đặt thành true
nếu đây là peer khởi tạo
channelConfig
– cấu hình kênh dữ liệu webrtc tùy chỉnh (được sử dụng bởi createDataChannel)
channelName
– tên kênh dữ liệu webrtc tùy chỉnh
config
– cấu hình webrtc tùy chỉnh (được sử dụng bởi hàm tạo RTCPeerConnection)
offerOptions
– tùy chọn đề nghị tùy chỉnh (được sử dụng bởi phương thức createOffer)
answerOptions
– tùy chọn trả lời tùy chỉnh (được sử dụng bởi phương thức createAnswer)
sdpTransform
– hàm để biến đổi dữ liệu tín hiệu SDP được tạo ra (dành cho người dùng nâng cao)
stream
– nếu muốn video/voice, truyền luồng được trả về từ getUserMedia
streams
– một mảng các MediaStreams được trả về từ getUserMedia
trickle
– đặt thành false
để tắt trickle ICE và nhận một sự kiện ‘signal’ duy nhất (chậm hơn)
wrtc
– triển khai webrtc tùy chỉnh, thường hữu ích chủ yếu trong node để chỉ định trong gói wrtc. Chứa một đối tượng với các thuộc tính:
objectMode
– đặt thành true
để tạo luồng trong Object Mode. Ở chế độ này, dữ liệu chuỗi đầu vào không tự động chuyển đổi thành đối tượng Buffer
.
peer.signal(data)
Gọi phương thức này mỗi khi peer từ xa phát ra sự kiện peer.on('signal')
.
Dữ liệu sẽ bao gồm một đề nghị webrtc, trả lời hoặc ứng viên ice. Những tin nhắn này giúp các peer cuối cùng thiết lập một kết nối trực tiếp với nhau. Nội dung của các chuỗi này là một chi tiết thực hiện có thể bị bỏ qua bởi người dùng của mô-đun này; chỉ đơn giản là truyền dữ liệu từ sự kiện ‘signal’ cho peer từ xa và gọi peer.signal(data)
để kết nối.
peer.send(data)
Gửi dữ liệu văn bản/nhị phân đến peer từ xa. data
có thể là một trong một số kiểu: String
, Buffer
(xem buffer), ArrayBufferView
(Uint8Array
, v.v.), ArrayBuffer
hoặc Blob
(trong các trình duyệt hỗ trợ).
Lưu ý: Nếu phương thức này được gọi trước khi sự kiện peer.on('connect')
được kích hoạt, thì sẽ ném ra một ngoại lệ. Sử dụng peer.write(data)
(được kế thừa từ giao diện duplex stream của node.js) nếu bạn muốn dữ liệu này được đưa vào bộ đệm thay vì.
peer.addStream(stream)
Thêm một MediaStream
vào kết nối.
peer.removeStream(stream)
Xóa một MediaStream
khỏi kết nối.
peer.addTrack(track, stream)
Thêm một MediaStreamTrack
vào kết nối. Cũng phải truyền vào MediaStream
bạn muốn gắn nó vào.
peer.removeTrack(track, stream)
Xóa một MediaStreamTrack
khỏi kết nối. Cũng phải truyền vào MediaStream
mà nó đã được gắn vào.
peer.replaceTrack(oldTrack, newTrack, stream)
Thay thế một MediaStreamTrack
bằng một track khác. Cũng phải truyền vào MediaStream
mà track cũ đã được gắn vào.
peer.addTransceiver(kind, init)
Thêm một RTCRtpTransceiver
vào kết nối. Có thể được sử dụng để thêm các bộ truyền trước khi thêm các track. Tự động được gọi khi cần bởi addTrack
.
peer.destroy([err])
Hủy bỏ và dọn dẹp kết nối peer này.
Nếu tham số err
tùy chọn được truyền vào, thì nó sẽ được phát ra như một sự kiện 'error'
trên luồng.
Peer.WEBRTC_SUPPORT
Phát hiện sự hỗ trợ WebRTC bản gốc trong môi trường javascript.
var Peer = require('simple-peer')
if (Peer.WEBRTC_SUPPORT) {
// webrtc support!
} else {
// fallback
}
luồng song phương (duplex stream)
Các đối tượng Peer
là các phiên bản của stream.Duplex
. Chúng hoạt động rất tương tự như một net.Socket
từ mô-đun lõi net
của node. Luồng song phương đọc/ghi vào kênh dữ liệu.
var peer = new Peer(opts)
// ... signaling ...
peer.write(new Buffer('hey'))
peer.on('data', function (chunk) {
console.log('got a chunk', chunk)
})
sự kiện
Các đối tượng Peer
là các phiên bản của EventEmitter
. Xem nodejs events documentation để biết thêm thông tin.
Ví dụ về việc xóa tất cả các trình nghe sự kiện close đã đăng ký:
peer.removeAllListeners('close')
peer.on('signal', data => {})
Khi peer muốn gửi dữ liệu tín hiệu cho peer từ xa.
Trách nhiệm của nhà phát triển ứng dụng (chính là bạn!) là đưa dữ liệu này đến peer khác. Điều này thường bao gồm việc sử dụng máy chủ tín hiệu websocket. Dữ liệu này là một Object
, vì vậy hãy nhớ gọi JSON.stringify(data)
để trình bày nó trước. Sau đó, đơn giản gọi peer.signal(data)
trên peer từ xa.
(Chắc chắn lắng nghe sự kiện này ngay lập tức để tránh bỏ lỡ. Đối với các peer initiator: true
, nó sẽ được kích hoạt ngay lập tức. Đối với các peer initiator: false
, nó sẽ được kích hoạt khi đề nghị từ xa được nhận.)
peer.on('connect', () => {})
Khi kết nối peer và kênh dữ liệu sẵn sàng sử dụng.
peer.on('data', data => {})
Nhận một tin nhắn từ peer từ xa (qua kênh dữ liệu).
data
sẽ là một String
hoặc một Buffer/Uint8Array
(xem buffer).
peer.on('stream', stream => {})
Nhận luồng video từ xa, có thể hiển thị trong thẻ video:
peer.on('stream', stream => {
var video = document.querySelector('video')
if ('srcObject' in video) {
video.srcObject = stream
} else {
video.src = window.URL.createObjectURL(stream)
}
video.play()
})
peer.on('track', (track, stream) => {})
Nhận một track âm thanh/video từ xa. Luồng có thể chứa nhiều track.
peer.on('close', () => {})
Được gọi khi kết nối peer đã đóng.
peer.on('error', (err) => {})
Khi xảy ra một lỗi nghiêm trọng. Thường, điều này có nghĩa là dữ liệu tín hiệu không tốt đã được nhận từ peer từ xa.
err
là một đối tượng Error
.
mã lỗi
Các lỗi được trả về bởi sự kiện error
sẽ có một thuộc tính err.code
để chỉ ra nguồn gốc của sự cố.
Các mã lỗi có thể:
ERR_WEBRTC_SUPPORT
ERR_CREATE_OFFER
ERR_CREATE_ANSWER
ERR_SET_LOCAL_DESCRIPTION
ERR_SET_REMOTE_DESCRIPTION
ERR_ADD_ICE_CANDIDATE
ERR_ICE_CONNECTION_FAILURE
ERR_SIGNALING
ERR_DATA_CHANNEL
ERR_CONNECTION_FAILURE
kết nối hơn 2 peer?
Cách đơn giản nhất để làm điều đó là tạo một cấu trúc mạng full-mesh. Điều này có nghĩa là mỗi peer mở một kết nối đến mỗi peer khác. Để minh họa:
Để phát sóng một tin nhắn, chỉ cần lặp qua tất cả các peer và gọi peer.send
.
Ví dụ, nếu bạn có 3 peer. Khi một peer muốn gửi một số dữ liệu, nó phải gửi 2 lần, một lần cho mỗi peer còn lại. Vì vậy, bạn cần phải cẩn thận một chút về kích thước dữ liệu bạn gửi.
Cấu trúc full mesh không mở rộng tốt khi số lượng peer rất lớn. Tổng số cạnh trong mạng sẽ là trong đó n
là số lượng peer.
Để rõ ràng, dưới đây là mã để kết nối 3 peer với nhau:
Peer 1
// These are peer1's connections to peer2 and peer3
var peer2 = new Peer({ initiator: true })
var peer3 = new Peer({ initiator: true })
peer2.on('signal', data => {
// send this signaling data to peer2 somehow
})
peer2.on('connect', () => {
peer2.send('hi peer2, this is peer1')
})
peer2.on('data', data => {
console.log('got a message from peer2: ' + data)
})
peer3.on('signal', data => {
// send this signaling data to peer3 somehow
})
peer3.on('connect', () => {
peer3.send('hi peer3, this is peer1')
})
peer3.on('data', data => {
console.log('got a message from peer3: ' + data)
})
Peer 2
// These are peer2's connections to peer1 and peer3
var peer1 = new Peer()
var peer3 = new Peer({ initiator: true })
peer1.on('signal', data => {
// send this signaling data to peer1 somehow
})
peer1.on('connect', () => {
peer1.send('hi peer1, this is peer2')
})
peer1.on('data', data => {
console.log('got a message from peer1: ' + data)
})
peer3.on('signal', data => {
// send this signaling data to peer3 somehow
})
peer3.on('connect', () => {
peer3.send('hi peer3, this is peer2')
})
peer3.on('data', data => {
console.log('got a message from peer3: ' + data)
})
Peer 3
// These are peer3's connections to peer1 and peer2
var peer1 = new Peer()
var peer2 = new Peer()
peer1.on('signal', data => {
// send this signaling data to peer1 somehow
})
peer1.on('connect', () => {
peer1.send('hi peer1, this is peer3')
})
peer1.on('data', data => {
console.log('got a message from peer1: ' + data)
})
peer2.on('signal', data => {
// send this signaling data to peer2 somehow
})
peer2.on('connect', () => {
peer2.send('hi peer2, this is peer3')
})
peer2.on('data', data => {
console.log('got a message from peer2: ' + data)
})
sử dụng bộ nhớ
Nếu bạn gọi peer.send(buf)
, simple-peer
sẽ không giữ một tham chiếu đến buf
và sẽ gửi bộ đệm vào một thời điểm sau đó. Chúng ta ngay lập tức gọi channel.send()
trên kênh dữ liệu. Vì vậy, việc biến đổi bộ đệm ngay sau đó không vấn đề gì.
Tuy nhiên, cẩn thận với việc peer.write(buf)
(một phương thức luồng có thể ghi) không có hợp đồng giống nhau. Nó có thể đặt dữ liệu vào bộ đệm và gọi channel.send()
tại một thời điểm trong tương lai, vì vậy chắc chắn đừng giả định rằng việc biến đổi bộ đệm là an toàn.
Kết nối không hoạt động trên một số mạng?
Nếu kết nối trực tiếp thất bại, đặc biệt là do qua NAT và/hoặc tường lửa, WebRTC ICE sẽ sử dụng một máy chủ trung gian (relay) TURN. Nói cách khác, ICE sẽ sử dụng STUN với UDP để trực tiếp kết nối các peer và, nếu thất bại, sẽ chuyển sang máy chủ trung gian TURN.
Để sử dụng máy chủ TURN, bạn phải chỉ định tùy chọn config
cho hàm tạo Peer
. Xem tài liệu API ở trên.
Ai đang sử dụng simple-peer
?
WebTorrent – Ứng dụng trình phát torrent trực tiếp trong trình duyệt
Virus Cafe – Kết bạn trong 2 phút
Instant.io – Truyền tệp an toàn, ẩn danh qua mạng
Zencastr – Thu âm cuộc phỏng vấn podcast từ xa chất lượng phòng thu một cách dễ dàng.
Friends – Trò chuyện ngang hàng dựa trên web
Socket.io-p2p – Thư viện giao tiếp P2P chính thức cho Socket.io
ScreenCat – Ứng dụng chia sẻ màn hình + cộng tác từ xa
WebCat – Ứng dụng truyền dẫn P2P trên web sử dụng khóa riêng/tổng công khai của Github để xác thực
RTCCat – Netcat WebRTC
PeerNet – Mạng đồn đại ngang hàng sử dụng thuật toán ngẫu nhiên
PusherTC – Trò chuyện video sử dụng Pusher. Xem guide.
lxjs-chat – Trang trò chuyện video giống Omegle
Cảm ơn bạn!
Whiteboard – Bảng trắng P2P được cung cấp bởi WebRTC và WebTorrent
Peer Calls – Cuộc gọi video nhóm WebRTC. Tạo phòng. Chia sẻ liên kết.
Netsix – Gửi video cho bạn bè bằng WebRTC để họ có thể xem ngay lập tức.
Stealthy – Stealthy là ứng dụng chat p2p phi tập trung, mã hóa end-to-end.
oorja.io – Trò chuyện video-âm thanh dễ dàng với tính năng cộng tác thời gian thực. Mở rộng bằng các thành phần react 🙌
TalktoMe – Tùy chọn thay thế Skype cho cuộc họp âm thanh/video dựa trên WebRTC, nhưng không mất gói tin.
CDNBye – CDNBye thực hiện WebRTC datachannel để mở rộng phát trực tiếp/vod video thông qua mạng ngang hàng sử dụng giao thức tương tự bittorrent
Detox – Mạng chồng cho giao tiếp ngang hàng vô danh phân tán hoàn toàn trong trình duyệt
Metastream – Xem phương tiện truyền thông phát trực tuyến cùng bạn bè.
firepeer – Tín hiệu và xác thực an toàn bằng cơ sở dữ liệu thời gian thực của firebase
Genet – Mạng lưới cây béo để mở rộng số lượng kết nối WebRTC đồng thời đến một nguồn duy nhất (paper).
WebRTC Connection Testing – Kiểm tra kết nối trực tiếp nhanh chóng giữa tất cả các cặp người tham gia (demo).
Firstdate.co – Hẹn hò video trực tuyến để gặp gỡ người khác thực sự và không chỉ nhắn tin cho họ
TensorChat – Đơn giản thôi – Tạo. Chia sẻ. Trò chuyện.
On/Office – Xem desktop của bạn trong môi trường được cung cấp bởi WebVR
Cyph – Dịch vụ gửi tin nhắn và mạng xã hội bảo mật mật mã, cung cấp mức độ riêng tư cực cao kết hợp với tính dễ sử dụng hàng đầu
Ciphora – Ứng dụng chat mã hóa end-to-end ngang hàng.
Whisthub – Trò chơi bài trực tuyến Color Whist với khả năng bắt đầu cuộc trò chuyện video trong lúc chơi.
Brie.fi/ng – Trò chuyện video ẩn danh và an toàn
Peer.School – Phòng học ảo đơn giản bắt đầu từ lớp 1 bao gồm trò chuyện video và bảng trắng thời gian thực
FileFire – Chuyển tập tin và thư mục lớn với tốc độ cao mà không có giới hạn kích thước.
safeShare – Chuyển tập tin dễ dàng kèm theo trò chuyện văn bản và âm thanh.
CubeChat – Tiệc trong không gian 3D 🎉
Homely School – Hệ thống học trực tuyến
AnyDrop – Tùy chọn thay thế AirDrop chạy trên nhiều nền tảng with an Android app available at Google Play
Share-Anywhere – Truyền tập tin qua các nền tảng khác nhau
QuaranTime.io – Trò chơi Board-game The Activity dưới dạng video!
Trango – Giải pháp gọi và chia sẻ tập tin chạy trên nhiều nền tảng.
P2PT – Sử dụng máy chủ theo dõi WebTorrent như máy chủ tín hiệu để thiết lập kết nối WebRTC
Dots – Trò chơi Dots & Boxes đa người trực tuyến. Play Here!
simple-peer-files – Thư viện đơn giản giúp việc truyền tải tập tin qua WebRTC trở nên dễ dàng. Có tính năng tiếp tục truyền tải tập tin sau khi người tải lên bị gián đoạn.
WebDrop.Space – Chia sẻ tập tin và tin nhắn qua các thiết bị. Tùy chọn chạy trên nhiều nền tảng, không cần cài đặt thay thế cho AirDrop, Xender. Source Code
Speakrandom – Mạng xã hội trò chuyện âm thanh sử dụng simple-peer để tạo các cuộc họp âm thanh!
Deskreen – Ứng dụng desktop giúp bạn biến bất kỳ thiết bị nào thành màn hình phụ cho máy tính của bạn. Sử dụng simple-peer để chia sẻ toàn bộ màn hình máy tính lên bất kỳ thiết bị nào có trình duyệt web.
Ứng dụng của bạn ở đây! – gửi một PR!
Chi tiết tải xuống:
Tác giả: Feross
Mã nguồn: https://github.com/feross/simple-peer
Giấy phép: MIT license