WebRTC 雙向視頻通話

WebRTC 雙向視頻通話

一、項目概述

WebRTC(Web Real - Time Communication)是一種支持瀏覽器之間進行實時通信的技術,它使得在網頁上實現音視頻通話、文件共享等功能變得更加容易。為了體驗這個技術,所以我實現了webrtc - local

二、項目結構

項目主要分為兩個主要部分:webrtc - server(服務端)和 webrtc - client(客戶端)。

1. 服務端(webrtc - server)

服務端使用 Node.js 搭建,借助 socket.io (也可以是其他)實現信令的一個交換,其實就是一個信息中轉的地方。

2. 客戶端(webrtc - client)

客戶端基于 Vue 3 和 TypeScript 構建,使用 socket.io - client 與服務端進行通信。

三、項目啟動步驟

詳看 README

四、代碼實現分析

1. 服務端(index.js)

服務端使用 https 協議創建服務器,并使用 socket.io 處理實時通信。以下是主要邏輯:

const socket = require('socket.io')
const https = require('https')
const fs = require('fs')
const path = require('path')const server = https.createServer({key: fs.readFileSync(path.join(__dirname, '../cert/key.pem')),cert: fs.readFileSync(path.join(__dirname, '../cert/cert.pem')),
})const io = socket(server, {cors: {origin: '*', // 配置跨域},
})io.on('connection', (sock) => {console.log('連接成功...')sock.emit('connectionSuccess')// 監聽客戶端進入房間的事件sock.on('joinRoom', (roomId) => {sock.join(roomId)})// 處理各種視頻通話相關事件sock.on('callRemote', (roomId) => {io.to(roomId).emit('receiveCall')})sock.on('acceptCall', (roomId) => {io.to(roomId).emit('acceptCall')})// 處理 offer、answer 和 candidate 信息sock.on('sendOffer', ({ roomId, offer }) => {io.to(roomId).emit('sendOffer', offer)})sock.on('sendAnswer', ({ roomId, answer }) => {io.to(roomId).emit('receiveAnswer', answer)})sock.on('sendCandidate', ({ roomId, candidate }) => {io.to(roomId).emit('receiveCandidate', candidate)})sock.on('hangUp', (roomId) => {io.to(roomId).emit('hangUp')})
})server.listen(3001, () => {console.log('服務器啟動成功')
})

服務端主要負責監聽客戶端的連接和各種事件,用來交換不同客戶端的信令等數據。

2. 客戶端(App.vue)

客戶端使用 Vue 3,結合 socket.io - clientRTCPeerConnection 實現視頻通話。以下是主要邏輯及相關知識解釋:

4.2.1 獲取本地音視頻流
// 獲取本地音視頻流
const getLocalStream = async () => {// 獲取音視頻流const stream = await navigator.mediaDevices.getUserMedia({video: true,audio: true,})// 將媒體流設置到 video 標簽上播放localVideo.value!.srcObject = stream// 播放音視頻流localVideo.value!.play()// 存儲本地流localStream.value = streamreturn stream
}

知識解釋
navigator.mediaDevices.getUserMedia 是 WebRTC 提供的一個 API,用于請求訪問用戶的攝像頭和麥克風。它接受一個約束對象作為參數,該對象指定了需要獲取的媒體類型(如視頻、音頻)以及其他可選的配置。當用戶允許訪問后,該方法會返回一個 Promise,該 Promise 會解析為一個 MediaStream 對象,該對象包含了用戶的音視頻流。

4.2.2 處理視頻請求
// 發起視頻請求(發起方)
const callRemote = async () => {if (calling.value || communicating.value) {return}calling.value = true// 獲取本地音視頻流await getLocalStream()// 向服務器發送發起視頻請求的事件caller.value = truesocket.value.emit('callRemote', roomId)
}// 接收視頻請求(接受方)
const acceptCall = () => {// 向服務器發送接受視頻請求的事件socket.value.emit('acceptCall', roomId)
}

知識解釋
在 WebRTC 視頻通話中,發起方首先需要獲取本地音視頻流,然后通過 socket.io 向服務端發送視頻請求。服務端接收到請求后,將其廣播給房間內的其他客戶端。接收方接收到請求后,可以選擇接受或拒絕。如果接受,接收方會向服務端發送接受請求的事件,服務端再將該事件廣播給發起方。

4.2.3 交換 offer/answer
// 發送方收到同意視頻事件
sock.on('acceptCall', async () => {if (caller.value) {// 發送方// 創建RTCPeerConnection對象peer.value = new RTCPeerConnection()// 添加本地音視頻流peer.value.addStream(localStream.value)// 生成offerconst offer = await peer.value.createOffer({offerToReceiveAudio: true,offerToReceiveVideo: true,})// 設置本地描述的offerawait peer.value.setLocalDescription(offer)// 發送offersock.emit('sendOffer', { roomId, offer })}
})// 接收方收到offer
sock.on('sendOffer', async (offer: any) => {if (called.value) {const stream = await getLocalStream()// 接收方創建自己的RTCPeerConnection對象peer.value = new RTCPeerConnection()// 添加本地音視頻流peer.value.addStream(stream)// 設置遠端描述信息await peer.value.setRemoteDescription(offer)// 生成answerconst answer = await peer.value.createAnswer()// 設置本地描述信息await peer.value.setLocalDescription(answer)// 發送answersock.emit('sendAnswer', { roomId, answer })}
})// 發送方收到接收方的answer
sock.on('receiveAnswer', (answer: any) => {if (caller.value) {// 設置遠端描述信息peer.value.setRemoteDescription(answer)}
})

知識解釋

  • offer:發起方通過 RTCPeerConnection.createOffer 方法創建一個 offer,該 offer 包含了發起方的會話描述信息,如支持的編解碼器、媒體類型等。然后使用 RTCPeerConnection.setLocalDescription 方法將該 offer 設置為本地描述,并通過 socket.io 發送給接收方。
  • answer:接收方收到 offer 后,使用 RTCPeerConnection.setRemoteDescription 方法設置遠端描述,然后通過 RTCPeerConnection.createAnswer 方法創建一個 answer,該 answer 包含了接收方的會話描述信息。同樣,使用 RTCPeerConnection.setLocalDescription 方法將該 answer 設置為本地描述,并通過 socket.io 發送給發起方。
  • 會話描述協議(SDP)offeranswer 都是基于會話描述協議(SDP)的,SDP 是一種用于描述多媒體會話的格式,它包含了會話的各種信息,如媒體類型、編解碼器、傳輸地址等。通過交換 offeranswer,雙方可以協商出一個共同支持的會話配置。
4.2.4 交換 candidate 信息
// 獲取candidate信息
peer.value.onicecandidate = (event: any) => {if (event.candidate) {// 向服務器發送candidate信息sock.emit('sendCandidate', { roomId, candidate: event.candidate })}
}// 接收candidate信息
sock.on('receiveCandidate', async (candidate: any) => {await peer.value.addIceCandidate(candidate)
})

知識解釋

  • ICE(交互式連接建立):由于雙方可能位于不同的網絡環境中,需要通過 ICE 機制來找到雙方之間的最佳通信路徑。ICE 會收集雙方的網絡地址信息,這些信息被稱為 candidate
  • candidatecandidate 包含了設備的網絡地址和端口信息,可能是本地地址、反射地址(通過 NAT 獲得)或中繼地址(通過 TURN 服務器獲得)。當 RTCPeerConnection 對象收集到一個 candidate 時,會觸發 onicecandidate 事件,此時可以將該 candidate 通過 socket.io 發送給對方。
  • addIceCandidate:對方接收到 candidate 后,使用 RTCPeerConnection.addIceCandidate 方法將其添加到自己的 RTCPeerConnection 對象中,這樣雙方就可以嘗試通過該 candidate 建立連接。

五、總結

webrtc - local 項目通過結合 WebRTC 技術和 socket.io 實現了簡單的局域雙向視頻通話功能,客戶端和服務端在同一網絡環境下運行。
在實際應用中,可以考慮使用 STUN/TURN 服務器來解決跨網絡通信的問題。

倉庫

https://github.com/PL-FE/webrtc-local/tree/main

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/87794.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/87794.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/87794.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Paimon lookup核心過程:分級查找、二分和緩存創建

LookupLevels LookupLevels 在 Paimon 中扮演著**“帶緩存的、基于 Key 的數據查找引擎”**的角色。它的核心使命是:當需要根據主鍵(Key)查找某條數據時,能夠高效地在 LSM-Tree 的多層(Levels)數據文件中定…

Ruby大會演講實錄:Baklib 如何用 AI 重構內容管理賽道

“2015 年成都 Ruby 大會時,我們還在做大數據項目;2025 年的今天,Baklib 已服務 800 多家企業。” 在 RubyConf China 2025 的演講臺上,Baklib 創始人Song以十年對比開篇,講述了從技術愛好者到企業服務創業者的蛻變&am…

408第三季part2 - 計算機網絡 - 傳輸層II

理解第一次和第二次握手是不能攜帶數據,只能消耗一個序號后面揮手也有第一次和第三次題目建立連接是1000,FIN揮手是5001,這兩個是不會帶數據的所以字節數范圍是1001-50005000-10011 4000c再次理解還可以叫快速重傳題目服務器想要100確認號客…

揭秘圖像LLM:從像素到語言的智能轉換

圖像LLM是怎么工作 圖像LLM(多模態大語言模型)的核心是將圖像轉化為語言模型能理解的“語言”,并與文本深度融合。以下結合CLIP、DALL-E、GPT-4V等主流模型,通過具體例子說明其工作機制: 一、圖像→特征向量:從像素到“密碼” 例子:識別“戴墨鏡的貓” 視覺編碼器提取…

十、K8s集群資源合理化分配

十、K8s集群資源合理化分配 文章目錄 十、K8s集群資源合理化分配1、K8s 資源限制 ResourceQuota1.1 什么是ResourceQuota?1.2 ResourceQuota通常用于如下場景:1.3 基于租戶和團隊的資源限制1.4 基于命名空間的資源限制 2、K8s 資源限制 LimitRange2.1 設…

Android 13 設置界面會判斷當前屏幕的大小,如果是大屏,則為左右屏顯示

1.前言 在13.0的系統rom定制化開發中,在某些時候,在大屏設備中,設置新增了左右分屏的功能,就是 左邊顯示主菜單,右邊顯示一級菜單的功能,某些情況下不需要,接下來關閉這個功能 2.設置界面會判斷當前屏幕的大小,如果是大屏,則為左右屏顯示的核心類 packages/apps/Sett…

算法學習day15----藍橋杯--進制轉換

python代碼:def jinzhizhuanhuan(x, n):ans 0while x > 0:ans x % nx // nreturn ans sum 0 for i in range(1, 2025):if jinzhizhuanhuan(i, 2) jinzhizhuanhuan(i, 4):sum 1 print(sum)雖然結束了期末周,但是又變懶了不少,水一個先…

OpenStack擴展

一、OpenStack (開源云計算管理平臺)的核心服務組件及功能計算服務(Compute - Nova)功能:是 OpenStack 計算資源管理的核心組件,負責虛擬機實例全生命周期管理,像實例的創建、啟動、暫停、遷移、…

【LeetCode 熱題 100】41. 缺失的第一個正數——(解法二)原地哈希

Problem: 41. 缺失的第一個正數 題目:給你一個未排序的整數數組 nums ,請你找出其中沒有出現的最小的正整數。 請你實現時間復雜度為 O(n) 并且只使用常數級別額外空間的解決方案。 【LeetCode 熱題 100】41. 缺失的第一個正數——(解法一&am…

C#上位機之Modbus通信協議!

文章目錄前言一、Modbus概念二、使用步驟1.使用Modbus準備2.使用步驟三、Modbus RTU 與 Modbus ASCII對比前言 Modbus通信協議! 一、Modbus概念 從站設備編碼(從站地址、單元ID),一主多從。 存儲區:0-線圈狀態、1-輸…

前后端分離架構下的跨域問題與解決方案

在現代Web開發中,特別是隨著前后端分離架構的普及,跨域問題成為了開發者必須面對的一個重要議題。本文將詳細介紹什么是跨域問題、其產生的原因以及如何從前端和后端兩個角度來解決這個問題,并提供一些實用的代碼示例。一、跨域問題概述1. 定…

搜索數據建設系列之數據架構重構

導讀 主要概述百度搜索業務數據建設的創新實踐,重點圍繞寬表模型設計、計算引擎優化和新一代業務服務交付模式(圖靈3.0開發模式)三大方向,解決了傳統數倉在搜索場景下面臨的諸多挑戰,實現了搜索數據建設的高效、穩定、…

2025年滲透測試面試題總結-2025年HW(護網面試) 29(題目+回答)

安全領域各種資源,學習文檔,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具,歡迎關注。、 目錄 2025年HW(護網面試) 29 1. 樣本分析思路 2. Linux GDB分析樣本示例 3. 應急案例:WebShell后…

動態編程入門第二節:委托與事件 - Unity 開發者的高級回調與通信藝術

動態編程入門第一節:C# 反射 - Unity 開發者的超級工具箱 動態編程入門第二節:委托與事件 - Unity 開發者的高級回調與通信藝術 上次我們聊了 C# 反射,它讓程序擁有了在運行時“看清自己”的能力。但光能看清還不夠,我們還需要讓…

降低網絡安全中的人為風險:以人為本的路徑

有效降低網絡安全中的人為風險,關鍵在于采取以人為本的方法。這種方法的核心在于通過高效的培訓和實踐,使員工掌握安全知識、踐行安全行為,并最終培育出安全且相互支持的文化氛圍。 誠然,技術和政策必須為良好的安全行為提供支持、…

opencv裁剪和編譯

opencv裁剪和編譯 0. 準備工作 0.1 下載和安裝Eigen 地址 https://eigen.tuxfamily.org/index.php?titleMain_Page對于opencv編譯,需要增加EIGEN_INCLUDE_PATH和開啟WITH_EIGEN -DWITH_EIGENON -DEIGEN_INCLUDE_PATH./3rd/eigen-3.4.01. 實際腳本 編譯腳本如下: ch…

小白成長之路-mysql數據基礎(三)

文章目錄一、主從復制二、案例總結一、主從復制 1、master開啟二進制日志記錄2、slave開啟IO進程,從master中讀取二進制日志并寫入slave的中繼日志3、slave開啟SQL進程,從中繼日志中讀取二進制日志并進行重放4、最終,達到slave與master中數據…

通過 Windows 共享文件夾 + 手機訪問(SMB協議)如何實現

通過 Windows 共享文件夾 手機訪問(SMB協議) 實現 PC 和安卓手機局域網文件共享,具體步驟如下: 📌 前置條件 電腦和手機連接同一局域網(同一個Wi-Fi或路由器)。關閉防火墻或放行SMB端口&#…

【Python3教程】Python3高級篇之正則表達式

博主介紹:?全網粉絲23W+,CSDN博客專家、Java領域優質創作者,掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域? 技術范圍:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大數據、物聯網、機器學習等設計與開發。 感興趣的可…

Redis--黑馬點評--達人探店功能實現詳解

達人探店發布探店筆記探店筆記類似于點評網站的評價,往往是圖文結合,對應的表有兩個:tb_blog:探店筆記表,包含筆記中的標題、文字、圖片等tb_blog_comments:其他用戶對探店筆記的評價tb_blog表結構如下&…