152 lines
4.5 KiB
JavaScript
152 lines
4.5 KiB
JavaScript
/**
|
|
* RTSP to WebSocket Proxy Server
|
|
* Convert RTSP stream ke WebSocket untuk jsmpeg player
|
|
*
|
|
* Usage:
|
|
* node rtsp-websocket-proxy.js <rtsp_url> <ws_port>
|
|
*
|
|
* Example:
|
|
* node rtsp-websocket-proxy.js rtsp://10.60.0.10:8554/cam1 8082
|
|
*/
|
|
|
|
const WebSocket = require('ws');
|
|
const { spawn } = require('child_process');
|
|
|
|
// Parse arguments
|
|
const rtspUrl = process.argv[2] || 'rtsp://10.60.0.10:8554/cam1';
|
|
const wsPort = parseInt(process.argv[3]) || 8082;
|
|
|
|
console.log('🚀 Starting RTSP to WebSocket Proxy');
|
|
console.log('📹 RTSP URL:', rtspUrl);
|
|
console.log('🔌 WebSocket Port:', wsPort);
|
|
console.log('');
|
|
|
|
// Create WebSocket server
|
|
const wss = new WebSocket.Server({
|
|
port: wsPort,
|
|
perMessageDeflate: false
|
|
});
|
|
|
|
let ffmpegProcess = null;
|
|
let clients = new Set();
|
|
|
|
wss.on('connection', (ws) => {
|
|
console.log('✅ New WebSocket client connected');
|
|
clients.add(ws);
|
|
|
|
// Start FFmpeg process jika belum ada
|
|
if (!ffmpegProcess) {
|
|
startFFmpeg();
|
|
}
|
|
|
|
ws.on('close', () => {
|
|
console.log('❌ WebSocket client disconnected');
|
|
clients.delete(ws);
|
|
|
|
// Stop FFmpeg jika tidak ada client lagi
|
|
if (clients.size === 0 && ffmpegProcess) {
|
|
console.log('⏹️ No clients, stopping FFmpeg');
|
|
stopFFmpeg();
|
|
}
|
|
});
|
|
|
|
ws.on('error', (error) => {
|
|
console.error('❌ WebSocket error:', error.message);
|
|
});
|
|
});
|
|
|
|
function startFFmpeg() {
|
|
console.log('🎬 Starting FFmpeg process...');
|
|
|
|
// FFmpeg command untuk convert RTSP ke MPEG1 video stream
|
|
// Format: MPEG1 video (untuk jsmpeg) dengan resolusi 800x600, bitrate 1000k
|
|
const ffmpegArgs = [
|
|
'-i', rtspUrl, // Input RTSP URL
|
|
'-f', 'mpegts', // Output format: MPEG Transport Stream
|
|
'-codec:v', 'mpeg1video', // Video codec: MPEG1 (untuk jsmpeg)
|
|
'-s', '800x600', // Resolution
|
|
'-b:v', '1000k', // Video bitrate
|
|
'-bf', '0', // No B-frames
|
|
'-codec:a', 'mp2', // Audio codec: MP2
|
|
'-b:a', '128k', // Audio bitrate
|
|
'-r', '25', // Frame rate: 25 fps
|
|
'pipe:1' // Output to stdout
|
|
];
|
|
|
|
ffmpegProcess = spawn('ffmpeg', ffmpegArgs, {
|
|
stdio: ['ignore', 'pipe', 'pipe']
|
|
});
|
|
|
|
ffmpegProcess.stdout.on('data', (data) => {
|
|
// Broadcast ke semua connected clients
|
|
clients.forEach(client => {
|
|
if (client.readyState === WebSocket.OPEN) {
|
|
try {
|
|
client.send(data);
|
|
} catch (error) {
|
|
console.error('Error sending data to client:', error.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
ffmpegProcess.stderr.on('data', (data) => {
|
|
// FFmpeg logs ke stderr, bisa di-ignore atau di-log untuk debugging
|
|
const message = data.toString();
|
|
if (message.includes('error') || message.includes('Error')) {
|
|
console.error('FFmpeg error:', message);
|
|
}
|
|
});
|
|
|
|
ffmpegProcess.on('exit', (code, signal) => {
|
|
console.log(`⚠️ FFmpeg process exited with code ${code}, signal ${signal}`);
|
|
ffmpegProcess = null;
|
|
|
|
// Restart jika masih ada clients
|
|
if (clients.size > 0) {
|
|
console.log('🔄 Restarting FFmpeg...');
|
|
setTimeout(() => startFFmpeg(), 2000);
|
|
}
|
|
});
|
|
|
|
ffmpegProcess.on('error', (error) => {
|
|
console.error('❌ FFmpeg spawn error:', error.message);
|
|
console.error('💡 Make sure FFmpeg is installed and available in PATH');
|
|
ffmpegProcess = null;
|
|
});
|
|
|
|
console.log('✅ FFmpeg process started');
|
|
}
|
|
|
|
function stopFFmpeg() {
|
|
if (ffmpegProcess) {
|
|
console.log('⏹️ Stopping FFmpeg process...');
|
|
ffmpegProcess.kill('SIGTERM');
|
|
ffmpegProcess = null;
|
|
}
|
|
}
|
|
|
|
// Graceful shutdown
|
|
process.on('SIGINT', () => {
|
|
console.log('\n🛑 Shutting down...');
|
|
stopFFmpeg();
|
|
wss.close(() => {
|
|
console.log('✅ Server closed');
|
|
process.exit(0);
|
|
});
|
|
});
|
|
|
|
process.on('SIGTERM', () => {
|
|
console.log('\n🛑 Shutting down...');
|
|
stopFFmpeg();
|
|
wss.close(() => {
|
|
console.log('✅ Server closed');
|
|
process.exit(0);
|
|
});
|
|
});
|
|
|
|
console.log(`✅ WebSocket server listening on ws://0.0.0.0:${wsPort}`);
|
|
console.log('💡 Connect from browser: ws://localhost:' + wsPort);
|
|
console.log('💡 Press Ctrl+C to stop\n');
|
|
|