Skip to content

Commit

Permalink
[IMP] discuss: recording feature
Browse files Browse the repository at this point in the history
tests, forwarding, ffmpeg config,...
  • Loading branch information
ThanhDodeurOdoo committed Nov 22, 2024
1 parent 6ad0f49 commit 70bccf8
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 9 deletions.
8 changes: 7 additions & 1 deletion src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ const ACTIVE_STATES = new Set([
export class SfuClient extends EventTarget {
/** @type {Error[]} */
errors = [];
/**
* @type {{ recording: boolean, webRtc: boolean }}
*/
features = {};
/** @type {SFU_CLIENT_STATE[keyof SFU_CLIENT_STATE]} */
_state = SFU_CLIENT_STATE.DISCONNECTED;
/** @type {Bus | undefined} */
Expand Down Expand Up @@ -418,7 +422,9 @@ export class SfuClient extends EventTarget {
*/
webSocket.addEventListener(
"message",
() => {
(initDataMessage) => {
const { features } = JSON.parse(initDataMessage.data || initDataMessage);
this.features = features;
resolve(new Bus(webSocket));
},
{ once: true }
Expand Down
18 changes: 18 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,24 @@ export const LOG_TIMESTAMP = !FALSY_INPUT.has(process.env.LOG_TIMESTAMP);
export const LOG_COLOR = process.env.LOG_COLOR
? Boolean(process.env.LOG_COLOR)
: process.stdout.isTTY;
/**
* Whether recording is allowed
* If true, users can request their call to be recorded.
*
* e.g: RECORDING=1
*
* @type {boolean}
*/
export const RECORDING = Boolean(process.env.RECORDING ?? true);
/**
* The file type of the recording output, this must be a fragmentable type.
* If not set, defaults to mp4
*
* e.g: RECORDING_FILE_TYPE=mp4
*
* @type {string}
*/
export const RECORDING_FILE_TYPE = process.env.RECORDING_FILE_TYPE || "mp4";

// ------------------------------------------------------------
// -------------------- SETTINGS --------------------------
Expand Down
23 changes: 21 additions & 2 deletions src/models/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ const mediaCodecs = getAllowedCodecs();
* @property {number} screenCount
*/

/**
* @typedef {Object} Features
* @property {boolean} recording
* @property {boolean} webRtc
*/

/**
* @fires Channel#sessionJoin
* @fires Channel#sessionLeave
Expand All @@ -40,6 +46,7 @@ export class Channel extends EventEmitter {
name;
/** @type {WithImplicitCoercion<string>} base 64 buffer key */
key;
/** @type {Recorder | undefined} */
recorder;
/** @type {import("mediasoup").types.Router}*/
router;
Expand Down Expand Up @@ -132,10 +139,22 @@ export class Channel extends EventEmitter {
this.name = `${remoteAddress}*${this.uuid.slice(-5)}`;
this.router = router;
this._worker = worker;
this.recorder = new Recorder(this);
if (config.RECORDING) {
this.recorder = new Recorder(this);
}
this._onSessionClose = this._onSessionClose.bind(this);
}

/**
* @type {Features}
*/
get features() {
return {
recording: Boolean(this.recorder),
webRtc: Boolean(this.router),
};
}

/**
* @returns {Promise<{ uuid: string, remoteAddress: string, sessionsStats: SessionsStats, createDate: string }>}
*/
Expand Down Expand Up @@ -252,7 +271,7 @@ export class Channel extends EventEmitter {
}
clearTimeout(this._closeTimeout);
this.sessions.clear();
this.recorder.stop();
this.recorder?.stop();
Channel.records.delete(this.uuid);
/**
* @event Channel#close
Expand Down
11 changes: 6 additions & 5 deletions src/models/recorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import fs from "node:fs";
import { EventEmitter } from "node:events"; // TODO remove if unnecessary
import { Logger } from "#src/utils/utils.js";
import { STREAM_TYPE } from "#src/shared/enums.js";
import { RECORDING_FILE_TYPE } from "#src/config.js";

const logger = new Logger("RECORDER");
const temp = os.tmpdir();
const fileType = "mp4"; // TODO config
const VIDEO_LIMIT = 4; // TODO config (and other name?)
const VIDEO_LIMIT = 4;

/**
* @typedef {Object} RTPTransports
Expand Down Expand Up @@ -48,7 +48,7 @@ class FFMPEG extends EventEmitter {
"-c:a",
"aac", // audio codec
"-f",
fileType,
RECORDING_FILE_TYPE,
this._filePath,
];
}
Expand Down Expand Up @@ -116,7 +116,7 @@ export class Recorder extends EventEmitter {
constructor(channel) {
super();
this.channel = channel;
this.filePath = path.join(temp, `${this.uuid}.${fileType}`);
this.filePath = path.join(temp, `${this.uuid}.${RECORDING_FILE_TYPE}`);
Recorder.records.set(this.uuid, this);
}

Expand All @@ -138,6 +138,7 @@ export class Recorder extends EventEmitter {
session.producers[STREAM_TYPE.AUDIO],
STREAM_TYPE.AUDIO
);
// TODO maybe some logic for priority on session id or stream type
audioRtp && this._rtpTransports.audio.push(audioRtp);
for (const type in [STREAM_TYPE.CAMERA, STREAM_TYPE.SCREEN]) {
if (this.videoCount < VIDEO_LIMIT) {
Expand Down Expand Up @@ -170,7 +171,7 @@ export class Recorder extends EventEmitter {
// TODO check if this can be executed, otherwise end request, or throw error
const fileStream = fs.createReadStream(this._filePath); // may need to be explicitly closed?
res.writeHead(200, {
"Content-Type": `video/${fileType}`,
"Content-Type": `video/${RECORDING_FILE_TYPE}`,
"Content-Disposition": "inline",
});
fileStream.pipe(res); // Pipe the file stream to the response
Expand Down
5 changes: 4 additions & 1 deletion src/services/ws.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ async function connect(webSocket, { channelUUID, jwt }) {
if (!session_id) {
throw new AuthenticationError("Malformed JWT payload");
}
webSocket.send(); // client can start using ws after this message.
const initData = {
features: channel.features,
};
webSocket.send(JSON.stringify(initData)); // client can start using ws after this message.
const bus = new Bus(webSocket, { batchDelay: config.timeouts.busBatch });
const { session } = Channel.join(channel.uuid, session_id);
session.once("close", ({ code }) => {
Expand Down
8 changes: 8 additions & 0 deletions tests/network.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ describe("Full network", () => {
const [thirdStateChange] = await once(user3.session, "stateChange");
expect(thirdStateChange).toBe(SESSION_STATE.CONNECTED);
});
test("Get features information after connecting", async () => {
const channelUUID = await network.getChannelUUID();
const user1 = await network.connect(channelUUID, 1);
const [firstStateChange] = await once(user1.session, "stateChange");
expect(firstStateChange).toBe(SESSION_STATE.CONNECTED);
expect(user1.sfuClient.features.recording).toBe(true);
expect(user1.sfuClient.features.webRtc).toBe(true);
});
test("The session of the server closes when the client is disconnected", async () => {
const channelUUID = await network.getChannelUUID();
const user1 = await network.connect(channelUUID, 1);
Expand Down

0 comments on commit 70bccf8

Please sign in to comment.