如果你在 WebRTC 應用開發過程中遇到問題,歡迎在 RTC 開發者社群與更多有經驗的同行們交流。
WebRTC是一個協議,允許人們使用JavaScript在兩點之間建立實時通訊。
我們可以用這個結構使兩個或更多瀏覽器之間實現直接交流,而不需要中心伺服器。
伺服器只需要在連線的時候被使用,因此每個客戶端知道如何連線彼此。
我們可以使用這個特性建立什麼型別的App呢?例如,直接網路攝像頭連線。點對點通話,檔案共享,還有更多。
本教程我會介紹一個當你第一次使用的時候,會發出驚呼的App:一個網路攝像頭通訊App.
我們不會使用原始WebRTC API,然而,我們需要注意很多細節。這就是library的作用,它們做出了很好的抽象,人們可以集中精力建立App而不是將精力花費的底層API上。
其中一個library是PeerJS,它使得實時通訊變得非常簡單。簡單來說就是WebRTC,它的抽象使得結果獲取更快,之後你可以學習內部是如何運作的。
建議:當你建立一個App時候使用Bit分享到一個可重複利用的集合中,並且在你所有的專案中同步它們!不妨試一下,可以加快你的工作速度。
後端
首先我們需要建立後端。儘管我們會實現直接點對點通訊,起初的握手和合作需要中心伺服器。
一旦握手完成,點點之間會直接交流,而不再需要依靠後端。
PeerJS為我們提供了這樣一個伺服器,安裝過程很簡單,容易執行。
在一個資料夾下,初始化一個npm專案使用npm init命令,使用npm install peer指令安裝PeerJS,接著你可以使用npx執行它:
Npx peerjs –port 9000
複製程式碼
使用npx peerjs –help檢視更多選擇。
這就是你的後端。
現在我們可以建立一個最簡單的App,我們設定一個接收端和一個傳送端。
前端
首先建立一個接收端,連線PeerJS伺服器,等待接收資訊。第一個引數new Peer()為我們的端點名稱,我們叫做receiver,使得表意更清晰。: 匯入PeerJS客戶端:
<script src="https://cdnjs.cloudflare.com/ajax/libs/peerjs/0.3.16/peer.min.js"></script>
複製程式碼
接著初始化Peer物件。當另一個端點連線我們的時候,Connection事件被呼叫。當接收到一些資訊之後,data事件被呼叫:
const peer = new Peer('receiver', { host: 'localhost', port: 9000, path: '/' })
peer.on('connection', (conn) => {
conn.on('data', (data) => {
console.log(data);
})
})
複製程式碼
讓我們建立通訊的另一端。我們稱作sender,因為它會連線併傳送資訊到接收端。
初始化Peer物件,接著請求端點連線receiver端,接收端我們之前已經建立好。一旦連線建立,open事件啟動,接著呼叫send()方法來向接收端傳送資訊:
const peer = new Peer('sender', { host: 'localhost', port: 9000, path: '/' })
const conn = peer.connect('receiver')
conn.on('open', () => {
conn.send('hi!')
})
複製程式碼
這就是最簡單的例子。
首先開啟接收端,接著開啟傳送端。接受者從傳送者直接獲取資訊,不需要中心伺服器。伺服器只需要交換資訊,確保兩端連線。之後,就不會干預兩端之間的交流。
這是一個非常基礎的資訊連線。
下一步,我們不會傳送資訊,而是讓兩端彼此共享網路攝像頭流。
在客戶端,我們沒有使用peer.connect()
連線,而是使用了peer.call()
:
const call = peer.call('receiver', localStream)
})
複製程式碼
在接收端,當接收到一個通話事件反饋之後,必須對此作出應答:
peer.on('call', call => {
call.answer(localStream)
})
複製程式碼
就像電話交流一樣,我們不能自動回覆每個來電,必須明確的作出應答。
每個通話中的LocalStream
是什麼?它是網路攝像頭產生的流,我們必須通過呼叫navigator.mediaDevices.getUserMedia()
得到它,這是一個瀏覽器API。
這是一個非同步通訊,因此我們使用async/await來等待執行,我們需要將通話包裹在一個非同步函式中,首先:
const startChat = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true
})
}
startChat()
複製程式碼
一旦我們得到了localStream物件,可以將它分配給HTML網頁中的一個video元素。我們可以建立本地和遠端視訊元素:
<video id="local" autoplay></video>
<video id="remote" autoplay></video>
複製程式碼
將流分配給video#local
元素:
document.querySelector('video#local').srcObject = localStream
複製程式碼
呼叫receiver
端,傳遞localStream物件:
const call = peer.call('receiver', localStream)
複製程式碼
接收端的程式碼如下:
peer.on('call', call => {
call.answer(localStream)
})
複製程式碼
我們也需要得到媒體流。程式碼非常簡單,和傳送端類似,只是我們把所有程式碼包裹在call事件反饋中:
peer.on('call', call => {
const startChat = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true
})
document.querySelector('video#local').srcObject = localStream
call.answer(localStream)
}
startChat()
})
複製程式碼
展示遠端流
我們還需要新增最後一部分到傳送端和接收端中。
一旦從call物件的stream事件中得到遠端流,我們需要將它附加在video#remote元素上。
call.on('stream', remoteStream => {
document.querySelector('video#remote').srcObject = remoteStream
})
複製程式碼
接收端程式碼如下:
peer.on('call', call => {
const startChat = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true
})
document.querySelector('video#local').srcObject = localStream
call.answer(localStream)
call.on('stream', remoteStream => {
document.querySelector('video#remote').srcObject = remoteStream
})
}
startChat()
})
複製程式碼
傳送端程式碼如下:
const startChat = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true
})
document.querySelector('video#local').srcObject = localStream
const call = peer.call('receiver', localStream)
call.on('stream', remoteStream => {
document.querySelector('video#remote').srcObject = remoteStream
})
}
startChat()
複製程式碼
當其中一端通過導向新網頁或關閉瀏覽器標籤關閉了連線之後,另一端停止接收流,遠端視訊流停止。
總結
我們使用WebRTC建立了一個非常簡單的網路攝像頭通訊App。建立了兩個檔案來處理兩端通訊,但是沒必要這樣做。你可以建立一個使用者介面,允許使用者自己決定是否需要呼叫,更重要的是,他們想與誰通話。可以允許使用者輸入使用者名稱或者從列表中選擇來實現這個功能。