-
准备工作
基于 webrtc 的前端 p2p 库 simple-peer
客户端 socket.io socket.io-client
服务端 socket.io socket.io
-
说明
借鉴参考:本 demo 是基于此 例子 的变种,只是本人会分享一些自己踩过的坑。
-
code
server
const express = require("express"); const http = require("http"); const app = express(); const _ = require("lodash"); const server = http.createServer(app); const socket = require("socket.io"); // 这里需要注意,socket.io 的版本需要和前端的 socket.io-client 大版本一致(比如是 2.x.x 则两端都必须是 2.x.x 版本),否则会导致无法通信。 const io = socket(server, { cors: { origin: ["ws://10.173.6.13:9080/"], // 这里填写本机ip的地址 allowedHeaders: ["my-custom-header"], credentials: true, }, }); /** * users: user: {socketId, userId, peerInfo} */ let users = {}; io.on("connection", function (socket) { const userId = socket.handshake.query.userId; const socketId = socket.id; users[userId] = { socketId: socketId, userId: userId, }; /** * data: { userId: string, peerInfo: any } */ socket.on("signal", (data) => { // 给被通知者发送消息 console.log(users, [data.userId]); const socketId1 = users[data.userId].socketId; const informSocket = io.sockets.sockets.get(socketId1); if (!informSocket) { return; } informSocket.emit("signal", data); }); }); server.listen(process.env.PORT || 8000, () => { console.log("server is running on port 8000", server.address()); });client
// import Peer from 'peerjs'; import Peer from 'simple-peer'; import SocketIO from 'socket.io-client'; import state from '@/state'; import Basics from '../config/basics'; const iceServers: { urls: string }[] = [ { urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun.ekiga.net' }, { urls: 'stun:stun.ideasip.com' }, ]; export default class extends Basics { /** * 本地流 */ localStream?: TRTC.LocalStream | any; // 后端server socket: any; // peer 实例 peer: any; constructor(props: any) { super(props); } socketInit() { // 后端socket.io this.socket = SocketIO('ws://10.173.6.13:8000/', { transports: ['websocket'], // 确认连接为 ws ,防止调用 http 请求 query: { userId: state.user.info?.id, }, }); this.socket.on('connect', function () { console.log('Connected to signalling server, Peer ID: %s'); }); } init = async () => { this.socketInit(); await this.createStream(); if (Peer.WEBRTC_SUPPORT) { console.log('支持webrtc'); // webrtc support! } else { console.log('此浏览器不支持webrtc'); // fallback } if (state.user.info?.isStudent) { this.peer = new Peer({ initiator: true, // 确认谁是发起者,当调用 peer.on('signal',() => {}) 方法时,发起者会发起第一个 sigal 连接信令 config: { iceServers: iceServers, }, }); this.peer.addStream(this.localStream); } else { this.peer = new Peer({ config: { iceServers: iceServers, }, }); } this.socket.on('signal', (data: { userId: string; signalData: any }) => { if (data.userId == state.user.info?.id) { console.log( 'Received signalling data', data, 'from Peer ID:', data.userId ); this.peer.signal(data.signalData); } }); if (state.user.info?.isStudent) { this.peer.on('signal', (data: any) => { this.socket.emit('signal', { signalData: data, userId: '3199361187342825', }); }); } else { this.peer.on('signal', (data: any) => { this.socket.emit('signal', { signalData: data, userId: '8889361187356611', }); }); } this.peer.on('stream', (stream: any) => { // got remote video stream, now let's show it in a video tag var video: any = document.getElementsByClassName('dailog-share-video')[0]; if ('srcObject' in video) { video.srcObject = stream; } else { video.src = window.URL.createObjectURL(stream); // for older browsers } video.play(); }); this.isInitComplete.resolve(true); return; }; /** * 创建共享屏幕本地流 */ async createStream() { if (!this.localStream) { this.localStream = await navigator.mediaDevices .getUserMedia({ video: true, audio: true }) .catch((err) => console.log(err)); } else { return this.localStream; } } }
再加上一些能够播放视频的html代码一般就能跑通了。在实际的应用场景中,可以创建多个实例