用 Firebase 和 WebRTC 快速搭建一款浏览器视频聊天应用
在现代 Web 应用中,实时音视频通信变得越来越普遍。本文将通过一个简洁实用的示例,带你一步步搭建一个基于 Firebase + WebRTC 的浏览器视频聊天应用,帮助你理解 WebRTC 的核心通信机制以及如何借助 Firebase 进行信令传输。
🔧 技术栈与先决条件
本项目使用如下技术:
- WebRTC:浏览器原生支持的实时通信协议
- Firebase Firestore:用于传递信令信息(SDP 和 ICE)
- Firebase Hosting:用于本地和线上部署前端应用
环境准备
- Node.js(推荐 LTS 版本)
- npm(随 Node.js 一起安装)
- Firebase CLI 工具(用于部署和本地调试)
1️⃣ 创建 Firebase 项目
- 进入 Firebase 控制台,点击“添加项目”。
- 命名为
FirebaseRTC
。 - 创建完成后,前往“项目设置”中记下项目 ID。
2️⃣ 启用 Firebase 服务
✅ 启用 Firestore 数据库
- 进入控制台左侧导航的“开发 > 数据库”。
- 点击“创建数据库”,选择“测试模式”(开发阶段使用)。
- 等待创建完成。
✅ 启用 Firebase Hosting(后续用 CLI 配置)
3️⃣ 克隆并打开示例代码
git clone https://github.com/webrtc/FirebaseRTC
cd FirebaseRTC
这是 Google 官方的 WebRTC 示例项目,项目目录结构简洁,主要修改的是 public/app.js
。
4️⃣ 安装 Firebase CLI 工具
npm install -g firebase-tools
firebase login
firebase --version # 确保版本 >= 6.7.1
firebase use --add # 选择你刚刚创建的 Firebase 项目
5️⃣ 本地启动项目
firebase serve --only hosting
访问本地地址:http://localhost:5000
你将看到一个基础视频聊天界面。
6️⃣ 创建新房间(Caller)
我们通过 WebRTC 创建一个房间,生成 SDP offer,然后写入 Firestore:
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);const roomWithOffer = {offer: {type: offer.type,sdp: offer.sdp}
}
const roomRef = await db.collection('rooms').add(roomWithOffer);
document.querySelector('#currentRoom').innerText =`Current room is ${roomRef.id} - You are the caller!`;
监听被叫方的 answer,并设置为远程描述:
roomRef.onSnapshot(async snapshot => {const data = snapshot.data();if (!peerConnection.currentRemoteDescription && data.answer) {const answer = new RTCSessionDescription(data.answer);await peerConnection.setRemoteDescription(answer);}
});
7️⃣ 加入房间(Callee)
被叫方输入房间 ID 加入房间后,读取 caller 的 offer 并写入 answer:
const offer = roomSnapshot.data().offer;
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);const roomWithAnswer = {answer: {type: answer.type,sdp: answer.sdp}
}
await roomRef.update(roomWithAnswer);
这一步完成了双方 SDP 的交换。
8️⃣ 收集 ICE 候选(双向)
我们使用 Cloud Firestore 收集并同步 ICE 候选:
async function collectIceCandidates(roomRef, peerConnection,localName, remoteName) {const candidatesCollection = roomRef.collection(localName);peerConnection.addEventListener('icecandidate', event => {if (event.candidate) {const json = event.candidate.toJSON();candidatesCollection.add(json);}});roomRef.collection(remoteName).onSnapshot(snapshot => {snapshot.docChanges().forEach(change => {if (change.type === "added") {const candidate = new RTCIceCandidate(change.doc.data());peerConnection.addIceCandidate(candidate);}});});
}
- 来电者写入
callerCandidates
,读取calleeCandidates
- 被叫者写入
calleeCandidates
,读取callerCandidates
✅ 项目小结
通过本 Codelab 示例,你掌握了以下核心能力:
- 如何使用 WebRTC 创建视频通信通道
- 如何利用 Firebase Firestore 进行实时的信令交换
- 如何用 Firebase Hosting 快速部署 Web 应用
🔗 推荐资源
- FirebaseRTC 示例项目 (GitHub)
- WebRTC 官方文档
- Firebase Hosting 快速入门
欢迎你在此基础上继续优化,实现更多功能,如:
- 屏幕共享
- 聊天消息同步
- 多人房间
- 服务端中继(TURN)服务器配置
如有需要,我也可以帮你进一步完善 UI 或增加 STUN/TURN 服务接入策略,欢迎交流!