You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何基于PeerJS在客户端间发送确认消息

解决方案:用PeerJS数据通道传递操作信号

这问题我做实时语音通话功能时也碰到过,PeerJS本身就提供了**数据通道(DataChannel)**的能力,刚好能用来传递接听/拒绝这类操作反馈,下面给你一步步拆解实现:

核心思路

PeerJS的通话连接(Peer.Call)不仅能传输媒体流,还允许创建数据通道来发送自定义JSON消息。我们就用这个通道给发起方传递两种状态:answer(已接听)和decline(已拒绝),发起方收到信号后再执行对应的UI操作(显示计时器/弹出提示)。

具体实现代码

1. 发起方:创建通话+监听反馈信号

发起通话时,主动创建数据通道,并监听通道传来的消息:

// 初始化发起方Peer实例
const initiatorPeer = new Peer();
let callTimerInterval = null;

// 发起通话的函数
function initiateCall(targetPeerId) {
  // 发起通话,传入本地媒体流
  const call = initiatorPeer.call(targetPeerId, localMediaStream);

  // 创建名为"call-signaling"的数据通道
  const signalingChannel = call.createDataChannel('call-signaling');

  // 监听数据通道的消息
  signalingChannel.onmessage = (event) => {
    const signal = JSON.parse(event.data);
    switch (signal.type) {
      case 'decline':
        // 对方拒绝,弹出提示并关闭通话
        alert('对方已拒绝你的通话请求');
        call.close();
        break;
      case 'answer':
        // 对方接听,启动计时器并显示
        startCallTimer();
        break;
    }
  };

  // 监听通话结束,停止计时器
  call.onclose = () => {
    stopCallTimer();
  };
}

// 计时器实现示例
function startCallTimer() {
  let startTime = Date.now();
  callTimerInterval = setInterval(() => {
    const elapsed = Math.floor((Date.now() - startTime) / 1000);
    // 更新UI显示,比如把elapsed放到页面的计时器元素里
    document.getElementById('call-timer').textContent = `通话时长:${elapsed}s`;
  }, 1000);
}

function stopCallTimer() {
  if (callTimerInterval) {
    clearInterval(callTimerInterval);
    callTimerInterval = null;
  }
}

2. 接方:处理来电+发送操作信号

接方收到来电后,在按钮点击事件里通过数据通道给发起方发送信号:

// 初始化接方Peer实例
const receiverPeer = new Peer();

// 监听来电请求
receiverPeer.on('call', (incomingCall) => {
  // 显示自定义的接听/拒绝对话框(这里假设你已经实现了这个UI组件)
  showCallDialog({
    // 接听按钮点击事件
    onAnswer: () => {
      // 先回复通话,传入本地媒体流
      incomingCall.answer(localMediaStream);

      // 监听发起方创建的数据通道,发送接听信号
      incomingCall.on('datachannel', (signalingChannel) => {
        signalingChannel.send(JSON.stringify({ type: 'answer' }));
      });

      // 处理对方的媒体流(播放语音)
      incomingCall.on('stream', (remoteStream) => {
        document.getElementById('remote-audio').srcObject = remoteStream;
      });

      // 隐藏对话框
      hideCallDialog();
    },
    // 拒绝按钮点击事件
    onDecline: () => {
      // 监听数据通道,发送拒绝信号
      incomingCall.on('datachannel', (signalingChannel) => {
        signalingChannel.send(JSON.stringify({ type: 'decline' }));
      });

      // 关闭通话连接
      incomingCall.close();
      // 隐藏对话框
      hideCallDialog();
    }
  });
});

注意事项

  • 确保数据通道在连接建立后再发送消息:可以监听signalingChannel.onopen事件,确认通道就绪后再发信号,避免消息丢失;
  • 异常处理:比如对方离线、网络中断时,要监听call.onerror事件,给用户友好提示;
  • UI逻辑:计时器的样式和位置可以根据你的页面需求调整,拒绝提示也可以用自定义模态框代替alert

内容的提问来源于stack exchange,提问作者sourceplaze

火山引擎 最新活动