Skip to content

Commit

Permalink
feat: add pliOnConnect feature flag to force PLIs on new subscriber c…
Browse files Browse the repository at this point in the history
…onnections

Disabled by default
  • Loading branch information
prlanzarin committed Apr 4, 2023
1 parent 72cec88 commit 541d3be
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 25 deletions.
8 changes: 7 additions & 1 deletion config/default.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@ audioIceRestartEnabled: false
# WebRTC should be used for environments where the bridge is between external
# servers AND when mediasoup is being used
fsBridgeMode: 'RTP'

# pliOnConnect: whether to send a PLI when a new subscriber joins
# amount: max amount of PLIs to send. If 0, it won't send any PLIs (default)
# interval: interval between PLIs (in ms)
# (e.g.: amount: 3, interval: 2000 => send 3 PLIs every 2 seconds)
pliOnConnect:
amount: 0
interval: 2000
# Whether to record screen raw files
recordScreenSharing: true
# Whether to record camera raw files
Expand Down
39 changes: 27 additions & 12 deletions lib/screenshare/screenshare.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ const GENERATE_TS_ON_RECORDING_EVT = config.has('recordingGenerateTsOnRecEvt')
const RECORDING_PLI_ON_NOT_FLOWING = config.has('recordingPliOnNotFlowing')
? config.get('recordingPliOnNotFlowing')
: false;
const PLI_ON_CONNECT = config.has('pliOnConnect')
? config.get('pliOnConnect')
: null;

const LOG_PREFIX = "[screenshare]";
const PLI_SHOTS = 3;
const PLI_FREQ = 2000;
const REC_PLI_SHOTS = 3;
const REC_PLI_FREQ = 2000;
const REC_FLOW_TIMER = 500;

module.exports = class Screenshare extends BaseProvider {
Expand Down Expand Up @@ -124,7 +127,6 @@ module.exports = class Screenshare extends BaseProvider {
hgaPubMediaId: null, // ?: string (<T>)
};
this._pliInterval = null;
this._pliShots = 0;

this._trackMCSEvents();
}
Expand Down Expand Up @@ -452,7 +454,13 @@ module.exports = class Screenshare extends BaseProvider {

if (RECORDING_PLI_ON_NOT_FLOWING && this.hgaRecordingSet.flowTracker == null) {
this.hgaRecordingSet.flowTracker = setTimeout(() => {
this._pliSalvo(this.hgaRecordingSet.nativeSubMediaId);
this._pliSalvo(
this.hgaRecordingSet.nativeSubMediaId,
REC_PLI_SHOTS,
REC_PLI_FREQ, {
fastStart: true,
},
);
}, REC_FLOW_TIMER);
}
} else if (details === 'FLOWING') {
Expand Down Expand Up @@ -485,32 +493,35 @@ module.exports = class Screenshare extends BaseProvider {
});
}

_pliSalvo (endpoint) {
_pliSalvo (endpoint, shots, freq, { fastStart = false } = {}) {
if (this._pliInterval || endpoint == null) return;
let iterations = 0;

Logger.warn(
`Firing recording PLI salvo: ${endpoint}`,
this._getFullPresenterLogMetadata(this._connectionId)
);
this._requestKeyframe(endpoint);
this._pliShots++

if (fastStart) {
this._requestKeyframe(endpoint);
iterations++;
}

this._pliInterval = setInterval(() => {
if (this._pliShots >= PLI_SHOTS) {
if (iterations >= shots) {
this._clearPliSalvo();
} else {
this._pliShots++;
iterations++;
this._requestKeyframe(endpoint);
}
}, PLI_FREQ);
}, freq);
}

_clearPliSalvo () {
if (this._pliInterval) {
clearInterval(this._pliInterval);
this._pliInterval = null;
}

this._pliShots = 0;
}

async _stopHGARecordingSet () {
Expand Down Expand Up @@ -893,6 +904,10 @@ module.exports = class Screenshare extends BaseProvider {
Logger.info(`Viewer WebRTC stream was successfully created`,
this._getFullViewerLogMetadata(connectionId));

if (PLI_ON_CONNECT && PLI_ON_CONNECT.amount > 0) {
this._pliSalvo(mediaId, PLI_ON_CONNECT.amount, PLI_ON_CONNECT.interval);
}

return answer;
} catch (error) {
Logger.error(`Viewer subscribe failed for ${userId} due to ${error.message}`,
Expand Down
39 changes: 27 additions & 12 deletions lib/video/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ const GENERATE_TS_ON_RECORDING_EVT = config.has('recordingGenerateTsOnRecEvt')
const RECORDING_PLI_ON_NOT_FLOWING = config.has('recordingPliOnNotFlowing')
? config.get('recordingPliOnNotFlowing')
: false;
const PLI_ON_CONNECT = config.has('pliOnConnect')
? config.get('pliOnConnect')
: null;

const LOG_PREFIX = "[video]";
const PLI_SHOTS = 3;
const PLI_FREQ = 2000;
const REC_PLI_SHOTS = 3;
const REC_PLI_FREQ = 2000;
const REC_FLOW_TIMER = 500;

let sources = {};
Expand Down Expand Up @@ -79,7 +82,6 @@ module.exports = class Video extends BaseProvider {
hgaPubMediaId: null, // ?: string (<T>)
};
this._pliInterval = null;
this._pliShots = 0;

this._bindEventHandlers();
this._trackBigBlueButtonEvents();
Expand Down Expand Up @@ -386,7 +388,13 @@ module.exports = class Video extends BaseProvider {

if (RECORDING_PLI_ON_NOT_FLOWING && this.hgaRecordingSet.flowTracker == null) {
this.hgaRecordingSet.flowTracker = setTimeout(() => {
this._pliSalvo(this.hgaRecordingSet.nativeSubMediaId);
this._pliSalvo(
this.hgaRecordingSet.nativeSubMediaId,
REC_PLI_SHOTS,
REC_PLI_FREQ, {
fastStart: true,
},
);
}, REC_FLOW_TIMER);
}
} else if (details === 'FLOWING') {
Expand Down Expand Up @@ -495,30 +503,32 @@ module.exports = class Video extends BaseProvider {
});
}

_pliSalvo (endpoint) {
_pliSalvo (endpoint, shots, freq, { fastStart = false } = {}) {
if (this._pliInterval || endpoint == null) return;
let iterations = 0;

Logger.warn(`Firing recording PLI salvo: ${endpoint}`, this._getLogMetadata());

this._requestKeyframe(endpoint);
this._pliShots++
if (fastStart) {
this._requestKeyframe(endpoint);
iterations++;
}

this._pliInterval = setInterval(() => {
if (this._pliShots >= PLI_SHOTS) {
if (iterations >= shots) {
this._clearPliSalvo();
} else {
this._pliShots++;
iterations++;
this._requestKeyframe(endpoint);
}
}, PLI_FREQ);
}, freq);
}

_clearPliSalvo () {
if (this._pliInterval) {
clearInterval(this._pliInterval);
this._pliInterval = null;
}

this._pliShots = 0;
}

shouldRecord () {
Expand Down Expand Up @@ -850,6 +860,11 @@ module.exports = class Video extends BaseProvider {
const stream = Video.getSource(this.id);
const { mediaId, answer } = await this.mcs.subscribe(this.userId, stream, C.WEBRTC, options);
this.mediaId = mediaId;

if (PLI_ON_CONNECT && PLI_ON_CONNECT.amount > 0) {
this._pliSalvo(this.mediaId, PLI_ON_CONNECT.amount, PLI_ON_CONNECT.interval);
}

return answer;
}

Expand Down

0 comments on commit 541d3be

Please sign in to comment.