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 }) 来获取屏幕共享流,并且可以动态切换。
  • 录制:可以指定录制的流类型(如 localscreen)。
  • 外部事件接口:事件回调 onIceCandidate, onSendSignal, onRemoteStream, onRecordingComplete 可由外部重写,以便处理信令和流事件。
  • 接听对话:通过 answerCall 方法接听对话。
  • 加入多人对话:通过 joinMultiCall 方法加入多人对话。
  • 创建多人对话:通过 createMultiCall 方法创建多人对话。

通过封装 WebRTCManager 类,我们可以轻松地实现一对一音视频通话、屏幕共享、录制、挂断、接听对话、加入多人对话和创建多人对话等功能。这个封装不仅简化了 WebRTC 的使用,还提供了灵活的配置和事件处理接口,方便开发者根据实际需求进行扩展和定制。

希望这篇教程能帮助你更好地理解和使用 WebRTC API!

标签: Javascript, WebRTC

相关文章

浏览器指纹识别的 JavaScript 库 - FingerprintJS

FingerprintJS 是一个用于浏览器指纹识别的 JavaScript 库。它通过收集浏览器和设备的各种特征来生成一个唯一的标识符,即“指纹”。这个指纹可以用于识别和跟踪用户,即使他们清除...

在JavaScript或Vue中屏蔽所有报错信息

在 JavaScript 或 Vue 中,如果你想屏蔽所有 JavaScript 报错,可以通过捕获全局的错误事件来实现。需要注意的是,尽量避免屏蔽所有错误,因为这可能会掩盖一些实际问题,影响调...

浏览器的开发工具中有个jsContext是什么

什么是 jsContext?在JavaScript中,jsContext 并不是一个官方的术语或概念。通常情况下,开发者可能会提到 context 这个词,它通常指的是执行上下文(Executi...

在HTML中为 h1-h6 标签添加序号及颜色背景色块

在HTML结构中,h1 到 h6 是常见的标题标签,通常我们会希望对这些标题进行标注或编号,使其更具层次感。在这篇文章中,我将向您展示如何通过纯JavaScript自动为 h1 到 h6 标签添...

VUE倒计时组件

常用于发送短信、邮件后1分钟倒计时,倒计时结束后又可以再次点击vue组件封装:<template> <div class="timer-btn">...

图片Base64编码

CSR生成

图片无损放大

图片占位符

Excel拆分文件