一、基础设置
1. 项目初始化
首先,使用 TypeScript 来创建或升级我们的 Next.js 项目(如果尚未使用 TypeScript,可参考 官方文档 进行配置)。完成后,安装所需依赖:
npm install socket.io-client
说明:socket.io-client 用于在客户端与信令服务器进行通信。
二、核心组件实现
1. 视频通话组件(VideoChat.tsx)
下面以一个名为 VideoChat 的 React 组件为例,展示如何获取本地视频/音频流并进行初始化。示例中包含了核心的 TypeScript 类型声明。
import React, { useEffect, useRef } from 'react';
import { io, Socket } from 'socket.io-client';
interface VideoChatProps {
roomId: string;
userId: string;
}
const VideoChat: React.FC<VideoChatProps> = ({ roomId, userId }) => {
const userVideoRef = useRef<HTMLVideoElement>(null);
const peerVideoRef = useRef<HTMLVideoElement>(null);
const rtcConnectionRef = useRef<RTCPeerConnection | null>(null);
const socketRef = useRef<Socket | null>(null);
useEffect(() => {
// 1. 建立 Socket 连接
socketRef.current = io();
// 2. 获取本地媒体流
navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
})
.then(stream => {
if (userVideoRef.current) {
userVideoRef.current.srcObject = stream;
}
// 这里可以初始化 WebRTC 逻辑,例如创建 RTCPeerConnection
// 并将 track 添加进连接等...
})
.catch(error => {
console.error('获取媒体流失败:', error);
});
// 3. 组件卸载时断开连接
return () => {
socketRef.current?.disconnect();
};
}, []);
return (
<div>
<video autoPlay ref={userVideoRef} />
<video autoPlay ref={peerVideoRef} />
</div>
);
};
export default VideoChat;
关键点
useRef<HTMLVideoElement>(null) 定义了 HTML <video> 元素的引用。
useRef<RTCPeerConnection | null>(null) 用于持有 WebRTC 的 RTCPeerConnection 对象。
useRef<Socket | null>(null) 用于持有 Socket.io 客户端实例。
三、信令服务器设置
1. 创建信令服务器 (pages/api/socket.ts)
在 Next.js 中,我们可以在 pages/api/socket.ts 文件中创建一个 Socket.io 服务器来处理信令。当客户端请求这个 API 路径时,就会触发服务器端的 Socket.io 监听。
// pages/api/socket.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { Server } from 'socket.io';
type NextApiResponseWithSocket = NextApiResponse & {
socket: any & {
server: any & {
io?: Server;
};
};
};
export default function SocketHandler(
req: NextApiRequest,
res: NextApiResponseWithSocket
): void {
if (!res.socket.server.io) {
const io = new Server(res.socket.server);
res.socket.server.io = io;
io.on('connection', socket => {
// 监听客户端发来的 "join-room" 事件
socket.on('join-room', (roomId: string, userId: string) => {
// 把当前 socket 加入指定房间
socket.join(roomId);
// 通知房间里其他用户,有新用户加入了
socket.broadcast.to(roomId).emit('user-connected', userId);
});
});
}
res.end();
}
关键点
我们创建了一个类型 NextApiResponseWithSocket 来扩展原有的 NextApiResponse,以便在 res.socket.server 上使用自定义的 io 对象。
socket.join(roomId) 将当前连接放入指定房间,以实现房间内的广播和交流。
注意
由于 Next.js 会在服务器端复用同一个 Socket.io 实例,如果之前没有创建则会新建,否则会使用已有的实例。
四、主要功能实现
1. 媒体流处理
在进行 WebRTC 连接时,需要先获取本地视频/音频流,并将这些流添加到 RTCPeerConnection 中。以下示例展示了如何在 TypeScript 中获取用户媒体流并创建 RTCPeerConnection:
// utils/webrtc.ts
export interface ConnectTRTCParams {
userId: string;
roomId: string;
}
export const connectTRTC = async ({
userId,
roomId,
}: ConnectTRTCParams): Promise<RTCPeerConnection> => {
// 1. 获取本地音视频流
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
});
// 2. 创建 RTCPeerConnection
const peerConnection = new RTCPeerConnection();
// 3. 将所有 track(音视频轨道)添加到 PeerConnection
stream.getTracks().forEach(track => {
peerConnection.addTrack(track, stream);
});
return peerConnection;
};
关键类型和说明
navigator.mediaDevices.getUserMedia(...) 返回一个 MediaStream,包含音视频轨道。
RTCPeerConnection 是 WebRTC 的核心,负责连接双方并处理 ICE 协商、SDP 等过程。
peerConnection.addTrack(track, stream) 将媒体轨道添加到 PeerConnection,这样远端也能接收到相同的音视频内容。
2. 数据通道(Data Channel)设置
WebRTC 除了音视频,还可以通过数据通道进行文本、文件等数据传输。在 TypeScript 中可以这样写:
export const setupDataChannel = (peerConnection: RTCPeerConnection) => {
const dataChannel = peerConnection.createDataChannel('chat');
// 监听消息事件
dataChannel.onmessage = (event: MessageEvent) => {
const message = event.data;
// 在这里处理接收的消息
console.log('Received message:', message);
};
return dataChannel;
};
使用场景
当你需要在视频通话过程中传输文本、文件或指令等,就可以通过 DataChannel 来实现一个实时的 P2P 数据传输功能。
五、高级功能
1. 屏幕共享实现
WebRTC 也支持屏幕共享,代码示例如下:
export const startScreenShare = async (): Promise<MediaStream> => {
// 使用 getDisplayMedia 获取屏幕流
const screenStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
});
return screenStream;
};
提示
该 API 需要在安全环境(HTTPS)下使用,并且需要用户授权。
在实际项目中,要注意在不再需要时停止屏幕共享流,否则可能造成资源浪费。
六、注意事项
关键事件处理
用户加入房间(room)
创建对等连接(RTCPeerConnection)
交换 ICE 候选者(ICE candidates)
处理媒体流的添加与移除
WebRTC 连接建立流程
连接信令服务器(Socket.io)
在客户端创建对等连接(RTCPeerConnection)
交换 SDP(offer、answer) 信息
建立音视频或数据传输
优化性能和可靠性
配置 STUN/TURN 服务器以解决 NAT 穿透问题
实现断线重连机制(监听 Socket、PeerConnection 的连接状态)
添加必要的错误处理逻辑,比如捕获 getUserMedia 异常等