Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: HA & Demux - Audio Increment Not Respecting Position Diff-Threshold #301

Merged
merged 4 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
chore: first version of seperate fn for audio increment + unit tests
  • Loading branch information
Nfrederiksen committed Oct 27, 2023
commit b022db8f10d61aeea02a43168b0d00378051b879
83 changes: 46 additions & 37 deletions engine/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -836,45 +836,19 @@ class Session {
sessionState.vodMediaSeqVideo = await this._sessionState.increment("vodMediaSeqVideo", 1);
let audioIncrement;
if (this.use_demuxed_audio) {
let positionV = 0;
let positionA = 0;
const position = (await this._getCurrentPlayheadPosition()) * 1000;
positionV = position ? position / 1000 : 0;
let currentVod = await this._sessionState.getCurrentVod();
const sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
let posDiff;
let incrementValue = 1;
let index = 0;
const playheadPosVideo = (await this._getCurrentPlayheadPosition()) * 1000;
const audioSeqLastIdx = currentVod.getLiveMediaSequencesCount("audio") - 1;
const thresh = 0.5;
const maxAcceptableDiff = 0.001;
debug(`[${this._sessionId}]: About to determine audio increment`);
do {
const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
positionA = audioPosition ? audioPosition / 1000 : 0;
posDiff = (positionV - positionA).toFixed(3);
debug(`[${this._sessionId}]: positionV=${positionV};positionA=${positionA};posDiff=${posDiff}`);
if (posDiff <= maxAcceptableDiff) {
break;
}
if (posDiff > thresh) {
index++;
incrementValue++;
} else if (posDiff > maxAcceptableDiff) {
index = incrementValue;
debug(`[${this._sessionId}]: Audio Stepping index set to = ${index}`);
break;
}
if (sessionState.vodMediaSeqAudio + index > audioSeqLastIdx) {
break;
}
} while (!(-thresh < posDiff && posDiff < thresh) && !isNaN(posDiff));
audioIncrement = index;
debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${posDiff})`);
const _sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
audioIncrement = await this._determineAudioIncrement(
playheadPosVideo,
audioSeqLastIdx,
sessionState.vodMediaSeqAudio,
this._getAudioPlayheadPosition.bind(this)
);
// Perform the Increment
debug(`[${this._sessionId}]: Will increment audio with ${audioIncrement}`);
sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", audioIncrement);
}
debug(`[${this._sessionId}]: Will increment audio with ${audioIncrement}`);
sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", audioIncrement);

if (this.use_vtt_subtitles) {
debug(`[${this._sessionId}]: Will increment subtitle with 1`);
sessionState.vodMediaSeqSubtitle = await this._sessionState.increment("vodMediaSeqSubtitle", 1);
Expand Down Expand Up @@ -2089,6 +2063,41 @@ class Session {
}
return false;
}

async _determineAudioIncrement(_currentPosVideo, _audioSeqFinalIndex, _vodMediaSeqAudio, _getAudioPlayheadPositionAsyncFn) {
debug(`[${this._sessionId}]: About to determine audio increment. Video increment has already been executed.`);
let audioIncrement = 0;
let positionV = _currentPosVideo ? _currentPosVideo / 1000 : 0;
let positionA;
let posDiff;
const threshold = 0.250;
let currentIndex = 0;

while (currentIndex < _audioSeqFinalIndex) {
const currentPosAudio = (await _getAudioPlayheadPositionAsyncFn(_vodMediaSeqAudio + currentIndex)) * 1000;
positionA = currentPosAudio ? currentPosAudio / 1000 : 0;
posDiff = (positionV - positionA).toFixed(3);
debug(`[${this._sessionId}]: positionV=${positionV};positionA=${positionA};posDiff=${posDiff}`);
if (isNaN(posDiff)) {
break;
}
if (positionA >= positionV) {
debug(`[${this._sessionId}]: positionA=${positionA} >= positionV=${positionV};IncrementValue=${currentIndex}`);
break;
}
const difference = Math.abs(posDiff);
if (difference > threshold && difference > Number.EPSILON) {
debug(`[${this._sessionId}]: Audio is too behind video. Incrementing...`);
currentIndex++;
} else {
debug(`[${this._sessionId}]: Difference(${difference}) is acceptable; IncrementValue=${currentIndex}`);
break;
}
}
audioIncrement = currentIndex;
debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${posDiff})`);
return audioIncrement;
}
}

module.exports = Session;
88 changes: 80 additions & 8 deletions spec/engine/session_spec.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,92 @@
const Session = require('../../engine/session.js');
const Session = require("../../engine/session.js");

const { SessionStateStore } = require('../../engine/session_state.js');
const { PlayheadStateStore } = require('../../engine/playhead_state.js');
const { SessionStateStore } = require("../../engine/session_state.js");
const { PlayheadStateStore } = require("../../engine/playhead_state.js");

describe("Session", () => {
let sessionLiveStore = undefined;
beforeEach(() => {
sessionLiveStore = {
sessionStateStore: new SessionStateStore(),
playheadStateStore: new PlayheadStateStore()
};
playheadStateStore: new PlayheadStateStore(),
};
});

it("creates a unique session ID", () => {
const id1 = new Session('dummy', null, sessionLiveStore).sessionId;
const id2 = new Session('dummy', null, sessionLiveStore).sessionId;
const id1 = new Session("dummy", null, sessionLiveStore).sessionId;
const id2 = new Session("dummy", null, sessionLiveStore).sessionId;
expect(id1).not.toEqual(id2);
});
});

fit("for demuxed, returns the appropriate audio increment value", async () => {
const session = new Session("dummy", null, sessionLiveStore);
const mockFinalAudioIdx = 50; // current Vod has 50 media sequences to serve.
const mockCurrentVideoPosition = 200.0 * 1000; // Video is 200s deep into its content.
const mockMseqAudio = 25; // current mseq for audio on vod, 25 out of 50.
const mock_getAudioPlayheadPosition = async (pos_n_current) => {
const mockPositions = [196.0, 199.84, 203.68, 207.52];
return mockPositions[pos_n_current - mockMseqAudio];
};
const output = await session._determineAudioIncrement(
mockCurrentVideoPosition,
mockFinalAudioIdx,
mockMseqAudio,
mock_getAudioPlayheadPosition,
24
);
expect(output).toBe(1);
});

fit("for demuxed, returns the appropriate audio increment value", async () => {
const session = new Session("dummy", null, sessionLiveStore);
const mockFinalAudioIdx = 50; // current Vod has 50 media sequences to serve.
const mockCurrentVideoPosition = 441.7599999999981697 * 1000; // Video is 200s deep into its content.
const mockMseqAudio = 25; // current mseq for audio on vod, 25 out of 50.
const mock_getAudioPlayheadPosition = async (pos_n_current) => {
const mockPositions = [437.919999999999, 441.75999999999897];
return mockPositions[pos_n_current - mockMseqAudio];
};
const output = await session._determineAudioIncrement(
mockCurrentVideoPosition,
mockFinalAudioIdx,
mockMseqAudio,
mock_getAudioPlayheadPosition,
24
);
expect(output).toBe(1);
});
fit("for demuxed, returns the appropriate audio increment value", async () => {
const session = new Session("dummy", null, sessionLiveStore);
const mockFinalAudioIdx = 50; // current Vod has 50 media sequences to serve.
const mockCurrentVideoPosition = 3.840 * 8 * 1000; // Video is 200s deep into its content.
const mockMseqAudio = 5; // current mseq for audio on vod, 25 out of 50.
const mock_getAudioPlayheadPosition = async (pos_n_current) => {
const mockPositions = [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52];
return mockPositions[pos_n_current];
};
const output = await session._determineAudioIncrement(
mockCurrentVideoPosition,
mockFinalAudioIdx,
mockMseqAudio,
mock_getAudioPlayheadPosition
);
expect(output).toBe(3);
});
fit("for demuxed, returns the appropriate audio increment value", async () => {
const session = new Session("dummy", null, sessionLiveStore);
const mockFinalAudioIdx = 50; // current Vod has 50 media sequences to serve.
const mockCurrentVideoPosition = 14 * 1000; // Video is 200s deep into its content.
const mockMseqAudio = 0; // current mseq for audio on vod, 25 out of 50.
const mock_getAudioPlayheadPosition = async (pos_n_current) => {
const mockPositions = [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52];
return mockPositions[pos_n_current];
};
const output = await session._determineAudioIncrement(
mockCurrentVideoPosition,
mockFinalAudioIdx,
mockMseqAudio,
mock_getAudioPlayheadPosition
);
expect(output).toBe(4);
});
});