WebRtc_QingGan/server.js
2025-07-23 15:55:48 +08:00

224 lines
5.8 KiB
JavaScript

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const cors = require('cors');
const path = require('path');
const fs = require('fs');
const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
// 中间件
app.use(cors());
app.use(express.json());
app.use(express.static('src'));
app.use('/videos', express.static('videos'));
// 存储连接的客户端和他们的视频流状态
const connectedClients = new Map();
// 视频映射配置
const videoMapping = {
'你好': 'asd.mp4',
'hello': 'asd.mp4',
'再见': 'zxc.mp4',
'goodbye': 'zxc.mp4',
'谢谢': 'jkl.mp4',
'thank you': 'jkl.mp4',
'默认': 'asd.mp4'
};
// 默认视频流配置
const DEFAULT_VIDEO = 'asd.mp4';
const INTERACTION_TIMEOUT = 10000; // 10秒后回到默认视频
// 获取视频列表
app.get('/api/videos', (req, res) => {
const videosDir = path.join(__dirname, 'videos');
fs.readdir(videosDir, (err, files) => {
if (err) {
return res.status(500).json({ error: '无法读取视频目录' });
}
const videoFiles = files.filter(file =>
file.endsWith('.mp4') || file.endsWith('.webm') || file.endsWith('.avi')
);
res.json({ videos: videoFiles });
});
});
// 获取视频映射
app.get('/api/video-mapping', (req, res) => {
res.json({ mapping: videoMapping });
});
// 获取默认视频
app.get('/api/default-video', (req, res) => {
res.json({
defaultVideo: DEFAULT_VIDEO,
autoLoop: true
});
});
// Socket.IO 连接处理
io.on('connection', (socket) => {
console.log('用户连接:', socket.id);
connectedClients.set(socket.id, {
socket: socket,
currentVideo: DEFAULT_VIDEO,
isInInteraction: false
});
// 处理WebRTC信令 - 用于传输视频流
socket.on('offer', (data) => {
console.log('收到offer:', socket.id);
socket.broadcast.emit('offer', {
...data,
from: socket.id
});
});
socket.on('answer', (data) => {
console.log('收到answer:', socket.id);
socket.broadcast.emit('answer', {
...data,
from: socket.id
});
});
socket.on('ice-candidate', (data) => {
console.log('收到ice-candidate:', socket.id);
socket.broadcast.emit('ice-candidate', {
...data,
from: socket.id
});
});
// 处理视频流切换请求
socket.on('switch-video-stream', (data) => {
const { videoFile, type, text } = data;
console.log(`用户 ${socket.id} 请求切换视频流: ${videoFile} (${type})`);
// 更新客户端状态
const client = connectedClients.get(socket.id);
if (client) {
client.currentVideo = videoFile;
client.isInInteraction = true;
}
// 广播视频流切换指令给所有用户
io.emit('video-stream-switched', {
videoFile,
type,
text,
from: socket.id
});
// 如果是交互类型,设置定时器回到默认视频
if (type === 'text' || type === 'voice') {
setTimeout(() => {
console.log(`交互超时,用户 ${socket.id} 回到默认视频`);
if (client) {
client.currentVideo = DEFAULT_VIDEO;
client.isInInteraction = false;
}
// 广播回到默认视频的指令
io.emit('video-stream-switched', {
videoFile: DEFAULT_VIDEO,
type: 'default',
from: socket.id
});
}, INTERACTION_TIMEOUT);
}
});
// 处理通话开始
socket.on('call-started', () => {
console.log('通话开始,用户:', socket.id);
const client = connectedClients.get(socket.id);
if (client) {
client.currentVideo = DEFAULT_VIDEO;
client.isInInteraction = false;
}
io.emit('call-started', { from: socket.id });
});
// 处理文本输入
socket.on('text-input', (data) => {
const { text } = data;
console.log('收到文本输入:', text, '来自用户:', socket.id);
// 根据文本查找对应视频
let videoFile = videoMapping['默认'];
for (const [key, value] of Object.entries(videoMapping)) {
if (text.toLowerCase().includes(key.toLowerCase())) {
videoFile = value;
break;
}
}
console.log(`用户 ${socket.id} 文本输入 "${text}" 对应视频: ${videoFile}`);
// 发送视频流切换请求
socket.emit('switch-video-stream', {
videoFile,
type: 'text',
text
});
});
// 处理语音输入
socket.on('voice-input', (data) => {
const { audioData, text } = data;
console.log('收到语音输入:', text, '来自用户:', socket.id);
// 根据语音识别的文本查找对应视频
let videoFile = videoMapping['默认'];
for (const [key, value] of Object.entries(videoMapping)) {
if (text.toLowerCase().includes(key.toLowerCase())) {
videoFile = value;
break;
}
}
console.log(`用户 ${socket.id} 语音输入 "${text}" 对应视频: ${videoFile}`);
// 发送视频流切换请求
socket.emit('switch-video-stream', {
videoFile,
type: 'voice',
text
});
});
// 处理回到默认视频请求
socket.on('return-to-default', () => {
console.log('用户请求回到默认视频:', socket.id);
const client = connectedClients.get(socket.id);
if (client) {
client.currentVideo = DEFAULT_VIDEO;
client.isInInteraction = false;
}
socket.emit('switch-video-stream', {
videoFile: DEFAULT_VIDEO,
type: 'default'
});
});
// 断开连接
socket.on('disconnect', () => {
console.log('用户断开连接:', socket.id);
connectedClients.delete(socket.id);
});
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
console.log(`访问 http://localhost:${PORT} 开始使用`);
});