feat(VoiceReceiver): Proof of concept - Video recording

This commit is contained in:
Elysia
2024-10-27 12:13:57 +07:00
parent a3dfa8ab90
commit f4beb1e4ff
6 changed files with 76 additions and 10 deletions

View File

@@ -5,6 +5,8 @@ const { createSocket } = require('dgram');
const { EventEmitter } = require('events');
const { Buffer } = require('node:buffer');
const { Writable } = require('stream');
const find = require('find-process');
const kill = require('tree-kill');
const Util = require('../../../util/Util');
const { StreamOutput } = require('../util/Socket');
@@ -46,11 +48,7 @@ class FFmpegHandler extends EventEmitter {
*/
this.ready = false;
/**
* The FFmpeg process
* @type {ChildProcessWithoutNullStreams}
*/
this.stream = spawn('ffmpeg', [
const stream = spawn('ffmpeg', [
'-reorder_queue_size',
'50',
'-err_detect',
@@ -73,9 +71,15 @@ class FFmpegHandler extends EventEmitter {
'500000',
'-y',
'-f', // Specify the format
'matroska', // MKV format
'mpegts', // MKV format
isStream ? this.outputStream.url : output,
]);
/**
* The FFmpeg process
* @type {ChildProcessWithoutNullStreams}
*/
this.stream = stream;
this.stream.stdin.write(sdpData);
this.stream.stdin.end();
this.stream.stderr.once('data', data => {
@@ -101,6 +105,17 @@ class FFmpegHandler extends EventEmitter {
const message = Buffer.from(payload);
this.socket.send(message, 0, message.length, this.portUdp, '127.0.0.1', callback);
}
destroy() {
const ffmpegPid = this.stream.pid; // But it is ppid ;-;
const args = this.stream.spawnargs.slice(1).join(' '); // Skip ffmpeg
find('name', 'ffmpeg', true).then(list => {
let process = list.find(o => o.pid === ffmpegPid || o.ppid === ffmpegPid || o.cmd.includes(args));
if (process) {
kill(process.pid);
}
});
}
}
module.exports = FFmpegHandler;

View File

@@ -59,6 +59,7 @@ class VoiceReceiver extends EventEmitter {
* @typedef {Object} ReceiveVideoStreamOptions
* @property {number} [portUdp] The UDP port to use for the video stream (local stream).
* @property {string} [codec='H264'] The codec to use for encoding the video. Default is 'H264'.
* <info>H265 supported, but not implemented</info>
* @property {any} [output] Additional output options, as required.
*/
@@ -70,9 +71,10 @@ class VoiceReceiver extends EventEmitter {
* @param {ReceiveVideoStreamOptions} options Options.
* @returns {FFmpegHandler} The video stream for the specified user.
*/
createVideoStream(user, { portUdp, codec = 'H264', output } = {}) {
createVideoStream(user, { portUdp, codec, output } = {}) {
user = this.connection.client.users.resolve(user);
if (!user) throw new Error('VOICE_USER_MISSING');
codec = 'H264';
const stream = this.packets.makeVideoStream(user.id, portUdp, codec, output);
return stream;
}

View File

@@ -68,7 +68,7 @@ const payloadTypes = [
priority: 5000,
payload_type: 109,
rtx_payload_type: 110,
encode: true,
encode: false,
decode: false,
},
];
@@ -951,7 +951,6 @@ class Util extends null {
payloadType = payload.payload_type;
} else {
const payloadType = packet[1] > 120 ? packet[1] & 0x80 : packet[1];
console.log('payloadType', payloadType, packet, portUdp);
payload = payloadTypes.find(p => p.payload_type === payloadType);
}
let sdpData = `o=- 0 0 IN IP4 127.0.0.1