new file: media-server.js
This commit is contained in:
parent
334dc8d34a
commit
29e8980983
3 changed files with 836 additions and 19 deletions
122
media-server.js
Normal file
122
media-server.js
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
/**
|
||||||
|
* AeThex LIVE - RTMP Media Server
|
||||||
|
*
|
||||||
|
* This receives RTMP streams from OBS and converts to HLS for playback.
|
||||||
|
*
|
||||||
|
* OBS Settings:
|
||||||
|
* Server: rtmp://localhost:1935/live
|
||||||
|
* Stream Key: anything (e.g., "stream" or a random key)
|
||||||
|
*
|
||||||
|
* HLS Playback URL:
|
||||||
|
* http://localhost:8000/live/{streamKey}/index.m3u8
|
||||||
|
*/
|
||||||
|
|
||||||
|
const NodeMediaServer = require('node-media-server');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// Create media directory if it doesn't exist
|
||||||
|
const mediaDir = path.join(__dirname, 'media');
|
||||||
|
if (!fs.existsSync(mediaDir)) {
|
||||||
|
fs.mkdirSync(mediaDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
rtmp: {
|
||||||
|
port: 1935,
|
||||||
|
chunk_size: 60000,
|
||||||
|
gop_cache: true,
|
||||||
|
ping: 30,
|
||||||
|
ping_timeout: 60
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
port: 8000,
|
||||||
|
mediaroot: mediaDir,
|
||||||
|
allow_origin: '*',
|
||||||
|
api: true
|
||||||
|
},
|
||||||
|
trans: {
|
||||||
|
ffmpeg: process.env.FFMPEG_PATH || 'ffmpeg',
|
||||||
|
tasks: [
|
||||||
|
{
|
||||||
|
app: 'live',
|
||||||
|
hls: true,
|
||||||
|
hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]',
|
||||||
|
hlsKeep: false, // Don't keep old segments
|
||||||
|
dash: false,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const nms = new NodeMediaServer(config);
|
||||||
|
|
||||||
|
nms.on('preConnect', (id, args) => {
|
||||||
|
console.log('[NodeEvent on preConnect]', `id=${id} args=${JSON.stringify(args)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('postConnect', (id, args) => {
|
||||||
|
console.log('[NodeEvent on postConnect]', `id=${id} args=${JSON.stringify(args)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('doneConnect', (id, args) => {
|
||||||
|
console.log('[NodeEvent on doneConnect]', `id=${id} args=${JSON.stringify(args)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('prePublish', (id, StreamPath, args) => {
|
||||||
|
console.log('[NodeEvent on prePublish]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
|
||||||
|
console.log('');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log('🎥 STREAM STARTED!');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log(`HLS URL: http://localhost:8000${StreamPath}/index.m3u8`);
|
||||||
|
console.log('');
|
||||||
|
console.log('Add this to your .env.local:');
|
||||||
|
console.log(`NEXT_PUBLIC_STREAM_URL=http://localhost:8000${StreamPath}/index.m3u8`);
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log('');
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('postPublish', (id, StreamPath, args) => {
|
||||||
|
console.log('[NodeEvent on postPublish]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('donePublish', (id, StreamPath, args) => {
|
||||||
|
console.log('[NodeEvent on donePublish]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
|
||||||
|
console.log('');
|
||||||
|
console.log('⏹️ Stream ended');
|
||||||
|
console.log('');
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('prePlay', (id, StreamPath, args) => {
|
||||||
|
console.log('[NodeEvent on prePlay]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('postPlay', (id, StreamPath, args) => {
|
||||||
|
console.log('[NodeEvent on postPlay]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
nms.on('donePlay', (id, StreamPath, args) => {
|
||||||
|
console.log('[NodeEvent on donePlay]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log('🚀 AeThex LIVE - Media Server Starting');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log('');
|
||||||
|
console.log('RTMP Server: rtmp://localhost:1935/live');
|
||||||
|
console.log('HTTP Server: http://localhost:8000');
|
||||||
|
console.log('');
|
||||||
|
console.log('OBS Settings:');
|
||||||
|
console.log(' Service: Custom');
|
||||||
|
console.log(' Server: rtmp://localhost:1935/live');
|
||||||
|
console.log(' Stream Key: stream (or any key you want)');
|
||||||
|
console.log('');
|
||||||
|
console.log('After you start streaming, your HLS URL will be:');
|
||||||
|
console.log(' http://localhost:8000/live/stream/index.m3u8');
|
||||||
|
console.log('');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
nms.run();
|
||||||
728
package-lock.json
generated
728
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -11,7 +11,9 @@
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "NODE_ENV=production node server.js",
|
"start": "NODE_ENV=production node server.js",
|
||||||
"start:next": "next start",
|
"start:next": "next start",
|
||||||
"lint": "eslint"
|
"lint": "eslint",
|
||||||
|
"media": "node media-server.js",
|
||||||
|
"stream": "node media-server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "6.5.0",
|
"@prisma/client": "6.5.0",
|
||||||
|
|
@ -20,6 +22,7 @@
|
||||||
"hls.js": "^1.6.15",
|
"hls.js": "^1.6.15",
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
"next-auth": "^4.24.13",
|
"next-auth": "^4.24.13",
|
||||||
|
"node-media-server": "^4.2.4",
|
||||||
"prisma": "6.5.0",
|
"prisma": "6.5.0",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.3",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue