Javascript封装WebRTC及使用教程
好的,我们将在现有基础上加入接听对话、加入多人对话、创建多人对话等功能,并重新生成完整的文章内容。
WebRTC 封装及使用教程
WebRTC 是一个强大的实时通信 API,允许在浏览器中进行音视频通话、屏幕共享和数据传输。本文将详细介绍如何封装 WebRTC API,并提供完整的示例代码,帮助你快速上手 WebRTC 的开发。
1. WebRTCManager 类封装
我们将创建一个 WebRTCManager
类,封装 WebRTC 的核心功能,包括:
- 初始化 WebRTC 连接
- 获取本地媒体流(音频、视频、屏幕共享)
- 创建和处理 RTCPeerConnection
- 录制音视频
- 挂断通话
- 接听对话
- 加入多人对话
- 创建多人对话
1.1 配置项外置
我们将 ICE 配置、录制格式等设置参数外置,以便用户可以根据需要进行配置。
1.2 屏幕共享功能
添加屏幕共享的支持,允许用户在音频、视频之外共享屏幕内容。
1.3 结构优化
将类封装成模块,支持不同的媒体类型(音频、视频、屏幕共享),并支持多个连接。
1.4 代码实现
class WebRTCManager {
constructor(config = {}) {
// 配置项:外部传入
this.iceServers = config.iceServers || [{ urls: "stun:stun.l.google.com:19302" }];
this.recordingOptions = config.recordingOptions || { mimeType: 'video/webm; codecs=vp9' };
// 媒体流与连接状态
this.localStream = null;
this.screenStream = null;
this.peerConnections = {}; // 保存多个 PeerConnection 对象
this.remoteStreams = {}; // 远程流集合
this.recording = false;
this.recorder = null;
}
// 获取媒体流:支持音频、视频或屏幕共享
async getMediaStream({ audio = true, video = true, screen = false } = {}) {
try {
if (screen) {
this.screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true });
return this.screenStream;
} else {
this.localStream = await navigator.mediaDevices.getUserMedia({ audio, video });
return this.localStream;
}
} catch (error) {
console.error("Error accessing media devices:", error);
}
}
// 初始化 RTCPeerConnection
createPeerConnection(remoteId) {
const pc = new RTCPeerConnection({ iceServers: this.iceServers });
pc.onicecandidate = event => {
if (event.candidate) {
this.onIceCandidate(remoteId, event.candidate);
}
};
pc.ontrack = event => {
if (!this.remoteStreams[remoteId]) {
this.remoteStreams[remoteId] = new MediaStream();
}
this.remoteStreams[remoteId].addTrack(event.track);
this.onRemoteStream(remoteId, this.remoteStreams[remoteId]);
};
this.peerConnections[remoteId] = pc;
return pc;
}
// 添加本地流到 PeerConnection
addStreamToConnection(pc, stream) {
stream.getTracks().forEach(track => pc.addTrack(track, stream));
}
// 开始一对一连接(创建 offer 并发送给远端)
async createOffer(remoteId) {
const pc = this.createPeerConnection(remoteId);
this.addStreamToConnection(pc, this.localStream);
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
this.onSendSignal(remoteId, offer);
}
// 响应连接请求(创建 answer 并发送给远端)
async createAnswer(remoteId, offer) {
const pc = this.createPeerConnection(remoteId);
this.addStreamToConnection(pc, this.localStream);
await pc.setRemoteDescription(new RTCSessionDescription(offer));
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
this.onSendSignal(remoteId, answer);
}
// 处理远端 answer
async handleAnswer(remoteId, answer) {
const pc = this.peerConnections[remoteId];
if (pc) {
await pc.setRemoteDescription(new RTCSessionDescription(answer));
}
}
// 处理 ICE 候选
async handleIceCandidate(remoteId, candidate) {
const pc = this.peerConnections[remoteId];
if (pc) {
await pc.addIceCandidate(new RTCIceCandidate(candidate));
}
}
// 挂断通话
hangUp(remoteId) {
if (this.peerConnections[remoteId]) {
this.peerConnections[remoteId].close();
delete this.peerConnections[remoteId];
delete this.remoteStreams[remoteId];
}
}
// 开始录制
startRecording(streamType = 'local') {
let stream;
if (streamType === 'local') {
stream = this.localStream;
} else if (streamType === 'screen') {
stream = this.screenStream;
} else {
console.error("Unsupported stream type for recording.");
return;
}
this.recorder = new MediaRecorder(stream, this.recordingOptions);
const chunks = [];
this.recorder.ondataavailable = event => {
if (event.data.size > 0) {
chunks.push(event.data);
}
};
this.recorder.onstop = () => {
const blob = new Blob(chunks, { type: this.recordingOptions.mimeType });
this.onRecordingComplete(blob);
};
this.recorder.start();
this.recording = true;
}
// 停止录制
stopRecording() {
if (this.recorder && this.recording) {
this.recorder.stop();
this.recording = false;
}
}
// 事件处理方法(用户可根据需要重写)
onIceCandidate(remoteId, candidate) {}
onSendSignal(remoteId, signal) {}
onRemoteStream(remoteId, stream) {}
onRecordingComplete(blob) {}
// 停止屏幕共享
stopScreenSharing() {
if (this.screenStream) {
this.screenStream.getTracks().forEach(track => track.stop());
this.screenStream = null;
}
}
// 接听对话
async answerCall(remoteId, offer) {
await this.createAnswer(remoteId, offer);
}
// 加入多人对话
async joinMultiCall(remoteIds) {
for (const remoteId of remoteIds) {
await this.createOffer(remoteId);
}
}
// 创建多人对话
async createMultiCall(remoteIds) {
for (const remoteId of remoteIds) {
await this.createOffer(remoteId);
}
}
}
2. 使用示例
2.1 初始化 WebRTCManager
首先,我们需要初始化 WebRTCManager
并配置相关参数。
const config = {
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
recordingOptions: { mimeType: 'video/webm; codecs=vp9' }
};
const webRTCManager = new WebRTCManager(config);
2.2 设置事件处理
我们可以通过重写事件处理方法来处理信令和流事件。
webRTCManager.onIceCandidate = (remoteId, candidate) => {
// 发送 ICE 候选到远端
console.log(`Sending ICE candidate to ${remoteId}:`, candidate);
};
webRTCManager.onSendSignal = (remoteId, signal) => {
// 发送 offer/answer 信令到远端
console.log(`Sending signal to ${remoteId}:`, signal);
};
webRTCManager.onRemoteStream = (remoteId, stream) => {
// 显示远端视频流
document.getElementById('remoteVideo').srcObject = stream;
};
webRTCManager.onRecordingComplete = (blob) => {
// 下载录制的音视频
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'recorded_video.webm';
document.body.appendChild(a);
a.click();
};
2.3 发起一对一通话
我们可以通过以下代码发起一对一通话。
async function startCall(remoteId) {
await webRTCManager.getMediaStream({ audio: true, video: true });
document.getElementById('localVideo').srcObject = webRTCManager.localStream;
webRTCManager.createOffer(remoteId);
}
2.4 接听对话
我们可以通过以下代码接听对话。
async function answerCall(remoteId, offer) {
await webRTCManager.answerCall(remoteId, offer);
}
2.5 处理信令数据
我们需要处理从远端接收到的信令数据。
function handleSignal(remoteId, signal) {
if (signal.type === 'offer') {
webRTCManager.createAnswer(remoteId, signal);
} else if (signal.type === 'answer') {
webRTCManager.handleAnswer(remoteId, signal);
} else if (signal.candidate) {
webRTCManager.handleIceCandidate(remoteId, signal.candidate);
}
}
2.6 屏幕共享
我们可以通过以下代码开始和停止屏幕共享。
async function startScreenSharing() {
await webRTCManager.getMediaStream({ screen: true });
document.getElementById('localVideo').srcObject = webRTCManager.screenStream;
for (let pc of Object.values(webRTCManager.peerConnections)) {
webRTCManager.addStreamToConnection(pc, webRTCManager.screenStream);
}
}
function stopScreenSharing() {
webRTCManager.stopScreenSharing();
}
2.7 挂断通话
我们可以通过以下代码挂断通话。
function endCall(remoteId) {
webRTCManager.hangUp(remoteId);
}
2.8 录制音视频
我们可以通过以下代码开始和停止录制音视频。
function startRecording() {
webRTCManager.startRecording('local');
}
function stopRecording() {
webRTCManager.stopRecording();
}
2.9 加入多人对话
我们可以通过以下代码加入多人对话。
async function joinMultiCall(remoteIds) {
await webRTCManager.joinMultiCall(remoteIds);
}
2.10 创建多人对话
我们可以通过以下代码创建多人对话。
async function createMultiCall(remoteIds) {
await webRTCManager.createMultiCall(remoteIds);
}
3. 说明
- 配置参数:使用
config
对象来配置 STUN/TURN 服务器、录制选项等。 - 屏幕共享:通过
getMediaStream({ screen: true })
来获取屏幕共享流,并且可以动态切换。 - 录制:可以指定录制的流类型(如
local
或screen
)。 - 外部事件接口:事件回调
onIceCandidate
,onSendSignal
,onRemoteStream
,onRecordingComplete
可由外部重写,以便处理信令和流事件。 - 接听对话:通过
answerCall
方法接听对话。 - 加入多人对话:通过
joinMultiCall
方法加入多人对话。 - 创建多人对话:通过
createMultiCall
方法创建多人对话。
通过封装 WebRTCManager
类,我们可以轻松地实现一对一音视频通话、屏幕共享、录制、挂断、接听对话、加入多人对话和创建多人对话等功能。这个封装不仅简化了 WebRTC 的使用,还提供了灵活的配置和事件处理接口,方便开发者根据实际需求进行扩展和定制。
希望这篇教程能帮助你更好地理解和使用 WebRTC API!
版权声明:本文为原创文章,版权归 全栈开发技术博客 所有。
本文链接:https://www.lvtao.net/dev/javascript-native-webrtc-class.html
转载时须注明出处及本声明