基于node.js使用webrtc + peerjs 实现一对一在线视频聊天

首先了解一下peerJS, 个人简单的理解为使用peerJS可以绕过nat拦截,实现两个客户端之间直接通信,可以先看一下Peerjs文档 ,下面就开始吧。

既然是音视频通话,首先需要检查有没有音视频设备,代码如下:

refreshMediaDevices () {
  window.mediaDevices = {
    'videoinput': [],
    'audioinput': [],
  };
  navigator.mediaDevices.enumerateDevices().then((devices) => {
    devices.forEach((device) => {
      switch (device.kind) {
        case 'videoinput':
          window.mediaDevices.videoinput.push(device);
          break;
        case 'audioinput':
          window.mediaDevices.audioinput.push(device);
          break;
      }
    });
    this.$Bus.$emit('on.refreshMediaDevices.finished');
  }).catch((e) => {
    console.info('获取音视频设备信息失败:', e);
  });
},

 提醒一下,这里检查设备时需要定时刷新,不然可能识别不到设备

(window.refreshMediaDevices = this.refreshMediaDevices)();
this.refreshMediaDevicesTimer = window.setInterval(window.refreshMediaDevices, 2000);

接下来就是注册Peer, 注册之前先断开之前的连接防止重复注册,刚开始我使用的peerID是固定的,后来改为自定义的随机数,

因为如果不断刷新页面的话难免会出现相同的id注册多次,每次都是随机数,客户端B在接收的之前也是先获取(通过socket)客户端A的peerID:

crtPeer () {
  this.desPeer();
  // peer
  // 随机生成peerId
  let peerId = 'YX_' + Date.now() + Math.floor(Math.random() * (100 - 1)) + 1;
  // 放入socket
  this.parent.setPeerId(peerId);
  let peer = this.peer = window.peer = new Peer(peerId, {
    config: {
      iceServers: pkg.iceServers.map((url) => {
        return { url };
      }),
    },
  });
  // peer.on.open
  peer.on('open', (id) => {
    console.info(`Peer注册成功!`, id);
  });
  peer.on('error', (error) => {
    this.$message.error({
      message: `Peer错误: [${error.type}],请刷新页面重试`,
    });
  });
  // ##
  // peer.on.connection
  peer.on('connection', (conn) => {
    console.info(`peer.on.connection`, conn);
    this.$message.info(`peer.on.connection:${conn.peer}`);
  });
  // ##
  // peer.on.disconnected
  peer.on('disconnected', () => {
    console.info('peer.on.disconnected');
    console.info('peer.reconnect():begin...');
    peer.reconnect();
    console.info('peer.reconnect():finish...');
  });
},

双方注册成功以后,就要开始处理呼叫和被呼叫,首先呼叫,呼叫前先检查peer是否注册,是否有音视频设备等等。

let localStream = this.localStream = window.localStream = await this.getUserMedia();
this.mediaConnection && this.mediaConnection.close && this.mediaConnection.close();
let call = this.mediaConnection = window.peer.call(this.peerIdRemote, localStream);
// remoteStream
call.on('stream', (remoteStream) => {
  this.remoteStream = window.remoteStream = remoteStream;
  this.showLocalVideo(localStream);
  this.showRemoteVideo(remoteStream);
  // 开始录制音频
  this.recordStart();
  this.$message.success('远程通话已接通!');
});
call.on('close', () => {
  this.clearStream();
});
call.on('error', () => {
  this.clearStream();
});
// 获取用户媒体流
async getUserMedia () {
  // ##
  // localStream
  this.localStream = window.localStream = await navigator.mediaDevices.getUserMedia({
    video: this.callType === 1 ? this.videoDeviceEnabledCaller : false,
    audio: this.audioDeviceEnabledCaller,
  });
  return this.localStream;
},

 

这里先拿到了本地视频流,用于连接显示本地视频,peerIdRemote就是获取的客户端B注册的peerId,到这里基本呼叫基本完成了,然后在监听一个被呼叫的方法,直接上代码:

setTimeout(() => {
  window.peer.on('call', async (call) => {
    console.info('on.call', call);
    this.mediaConnection && this.mediaConnection.close && this.mediaConnection.close();
    this.mediaConnection = call;
    try {
      // ##
      // localStream
      let localStream = await this.getUserMedia();
      this.showLocalVideo(localStream);
      // ##
      // remoteStream
      call.on('stream', (remoteStream) => {
        if (this.callType === 1) {
        this.remoteStream = window.remoteStream = remoteStream;
        this.showRemoteVideo(remoteStream);
        // 开始录制音频
        this.recordStart();
        this.$message.success('远程通话已接通!');
      });
      call.on('close', () => {
        this.clearStream();        
      });
      call.on('error', () => {
        this.clearStream();
      });
      let msg = this.callType === 2 ? '音频' : '视频';
      // 确认请求
      this.$confirm(`xxx请求与您进行` + msg + `通话!`, '通话请求', {
        confirmButtonText: '接通',
        cancelButtonText: '拒绝',
        type: 'warning',
      }).then(() => {
        this.parent.isCalling = true;
        this.peerIdRemote = call.peer;
        call.answer(localStream); // Answer the call with an A/V stream.
      }).catch(() => {
        this.clearStream();
      });
    } catch (e) {
      console.log('Failed to get local stream', e);
    }
  });
}, 1000);

这样基本的通话功能就可以实现了,除了视频通话,还可以实现语音,聊天等功能,再说一点就是呼叫时网络不好的话,对方会有延迟,或者挂断以后需要提示等等,可以结合socket使用,体验会更好一些,本人研究的不是太多,只是基本的使用,如果感兴趣的话可以多看看这方面的资料,如果有什么不对的欢迎指出,有问题也欢迎提问(*^▽^*)。

你可能感兴趣的:(基于node.js使用webrtc + peerjs 实现一对一在线视频聊天)