Skip to content

Commit

Permalink
use audio in hls-v2l reload
Browse files Browse the repository at this point in the history
  • Loading branch information
Johan Lautakoksi committed Aug 14, 2023
1 parent 7bcfcdb commit b1bbe6c
Showing 1 changed file with 78 additions and 39 deletions.
117 changes: 78 additions & 39 deletions engine/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -429,15 +429,14 @@ class Session {
}
}

async setCurrentAudioSequenceSegments(segments, mSeqOffset, reloadBehind) {
async setCurrentAudioSequenceSegments(segments, aSeqOffset, reloadBehind) {
if (!this._sessionState) {
throw new Error("Session not ready");
}
this.isSwitchingBackToV2L = true;

this.switchDataForSession.reloadBehind = reloadBehind;
this.switchDataForSession.transitionSegments = segments;
this.switchDataForSession.mediaSeqOffset = mSeqOffset;
this.switchDataForSession.transitionAudioSegments = segments;
this.switchDataForSession.audioSeqOffset = aSeqOffset;
let waitTimeMs = 2000;
let groupId = Object.keys(segments)[0];
let lang = Object.keys(segments[groupId])[0]
Expand Down Expand Up @@ -567,7 +566,7 @@ class Session {
tries--;
state = await this.getSessionState();
}

const playheadState = {
vodMediaSeqAudio: null
}
Expand Down Expand Up @@ -631,10 +630,10 @@ class Session {
state = await this.getSessionState();
}

const playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo", "mediaSeqAudio","vodMediaSeqAudio"]);
const playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo", "mediaSeqAudio", "vodMediaSeqAudio"]);
const discSeqOffset = await this._sessionState.get("discSeq");
const discAudioSeqOffset = await this._sessionState.get("discSeqAudio");


// Clear Vod Cache here when Switching to Live just to be safe...
if (playheadState.vodMediaSeqVideo === 0) {
Expand Down Expand Up @@ -849,7 +848,7 @@ class Session {
throw new Error("Engine not ready");
}
}

async getCurrentSubtitleManifestAsync(subtitleGroupId, subtitleLanguage) {
if (!this._sessionState) {
throw new Error('Session not ready');
Expand Down Expand Up @@ -1005,7 +1004,7 @@ class Session {
}
} while (!(-thresh < posDiff && posDiff < thresh));
audioIncrement = index;
debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${(positionA-positionV).toFixed(3)})`);
debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${(positionA - positionV).toFixed(3)})`);
}
debug(`[${this._sessionId}]: Will increment audio with ${audioIncrement}`);
sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", audioIncrement);
Expand Down Expand Up @@ -1294,38 +1293,38 @@ class Session {
const profileChannels = profile.channels ? profile.channels : "2";
audioGroupIdToUse = currentVod.getAudioGroupIdForCodecs(audioCodec, profileChannels);
if (!audioGroupIds.includes(audioGroupIdToUse)) {
audioGroupIdToUse = defaultAudioGroupId;
audioGroupIdToUse = defaultAudioGroupId;
}
}

debug(`[${this._sessionId}]: audioGroupIdToUse=${audioGroupIdToUse}`);

// skip stream if no corresponding audio group can be found
if (audioGroupIdToUse) {
m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw +
',RESOLUTION=' + profile.resolution[0] + 'x' + profile.resolution[1] +
',CODECS="' + profile.codecs + '"' +
`,AUDIO="${audioGroupIdToUse}"` +
(defaultSubtitleGroupId ? `,SUBTITLES="${defaultSubtitleGroupId}"` : '') +
m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw +
',RESOLUTION=' + profile.resolution[0] + 'x' + profile.resolution[1] +
',CODECS="' + profile.codecs + '"' +
`,AUDIO="${audioGroupIdToUse}"` +
(defaultSubtitleGroupId ? `,SUBTITLES="${defaultSubtitleGroupId}"` : '') +
(hasClosedCaptions ? ',CLOSED-CAPTIONS="cc"' : '') + '\n';
m3u8 += "master" + profile.bw + ".m3u8%3Bsession=" + this._sessionId + "\n";
}
} else {
m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw +
',RESOLUTION=' + profile.resolution[0] + 'x' + profile.resolution[1] +
',CODECS="' + profile.codecs + '"' +
(defaultAudioGroupId ? `,AUDIO="${defaultAudioGroupId}"` : '') +
(defaultSubtitleGroupId ? `,SUBTITLES="${defaultSubtitleGroupId}"` : '') +
m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw +
',RESOLUTION=' + profile.resolution[0] + 'x' + profile.resolution[1] +
',CODECS="' + profile.codecs + '"' +
(defaultAudioGroupId ? `,AUDIO="${defaultAudioGroupId}"` : '') +
(defaultSubtitleGroupId ? `,SUBTITLES="${defaultSubtitleGroupId}"` : '') +
(hasClosedCaptions ? ',CLOSED-CAPTIONS="cc"' : '') + '\n';
m3u8 += "master" + profile.bw + ".m3u8%3Bsession=" + this._sessionId + "\n";
}
});
} else {
currentVod.getUsageProfiles().forEach(profile => {
m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw +
',RESOLUTION=' + profile.resolution +
',CODECS="' + profile.codecs + '"' +
(defaultAudioGroupId ? `,AUDIO="${defaultAudioGroupId}"` : '') +
m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw +
',RESOLUTION=' + profile.resolution +
',CODECS="' + profile.codecs + '"' +
(defaultAudioGroupId ? `,AUDIO="${defaultAudioGroupId}"` : '') +
(defaultSubtitleGroupId ? `,SUBTITLES="${defaultSubtitleGroupId}"` : '') +
(hasClosedCaptions ? ',CLOSED-CAPTIONS="cc"' : '') + '\n';
m3u8 += "master" + profile.bw + ".m3u8%3Bsession=" + this._sessionId + "\n";
Expand Down Expand Up @@ -1466,8 +1465,9 @@ class Session {
let loadPromise;
if (!vodResponse.type) {
debug(`[${this._sessionId}]: got first VOD uri=${vodResponse.uri}:${vodResponse.offset || 0}`);
const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
const hlsOpts = {
sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
shouldContainSubtitles: this.use_vtt_subtitles,
Expand All @@ -1481,7 +1481,7 @@ class Session {
}
currentVod = newVod;
if (vodResponse.desiredDuration) {
const { mediaManifestLoader, audioManifestLoader} = await this._truncateVod(vodResponse);
const { mediaManifestLoader, audioManifestLoader } = await this._truncateVod(vodResponse);
loadPromise = currentVod.load(null, mediaManifestLoader, audioManifestLoader);
} else {
loadPromise = currentVod.load();
Expand Down Expand Up @@ -1642,8 +1642,9 @@ class Session {
let loadPromise;
if (!vodResponse.type) {
debug(`[${this._sessionId}]: got next VOD uri=${vodResponse.uri}:${vodResponse.offset}`);
const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
const hlsOpts = {
sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
shouldContainSubtitles: this.use_vtt_subtitles,
Expand All @@ -1664,7 +1665,7 @@ class Session {
}
});
if (vodResponse.desiredDuration) {
const { mediaManifestLoader, audioManifestLoader} = await this._truncateVod(vodResponse);
const { mediaManifestLoader, audioManifestLoader } = await this._truncateVod(vodResponse);
loadPromise = newVod.loadAfter(currentVod, null, mediaManifestLoader, audioManifestLoader);
} else {
loadPromise = newVod.loadAfter(currentVod);
Expand Down Expand Up @@ -1769,7 +1770,7 @@ class Session {
sessionState.state = await this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING);
// 2) Set new 'offset' sequences, to carry on the continuity from session-live
let mSeq = this.switchDataForSession.mediaSeq;
// TODO: support demux^
let aSeq = this.switchDataForSession.audioSeq;
let currentVod = await this._sessionState.getCurrentVod();
if (currentVod.sequenceAlwaysContainNewSegments) {
// (!) will need to compensate if using this setting on HLSVod Object.
Expand All @@ -1779,20 +1780,50 @@ class Session {
shiftedSeg = this.switchDataForSession.transitionSegments[bw].shift();
}
});
if (this.use_demuxed_audio) {
const groupIds = Object.keys(this.switchDataForSession.transitionAudioSegments)
for (let i = 0; i < groupIds.length; i++) {
const groupId = groupIds[i];
const langs = Object.keys(this.switchDataForSession.transitionAudioSegments[groupId])
for (let j = 0; j < langs.length; j++) {
const lang = langs[j];
let shiftedSeg = this.switchDataForSession.transitionAudioSegments[groupId][lang].shift();
if (shiftedSeg && shiftedSeg.discontinuity) {
shiftedSeg = this.switchDataForSession.transitionAudioSegments[groupId][lang].shift();
}

}
}
}
}
const dSeq = this.switchDataForSession.discSeq;
const mSeqOffset = this.switchDataForSession.mediaSeqOffset;
const reloadBehind = this.switchDataForSession.reloadBehind;
const segments = this.switchDataForSession.transitionSegments;

const audioDSeq = this.switchDataForSession.discAudioSeq;
const aSeqOffset = this.switchDataForSession.audioSeqOffset;
const audioSegments = this.switchDataForSession.transitionAudioSegments;


if ([mSeq, dSeq, mSeqOffset, reloadBehind, segments].includes(null)) {
debug(`[${this._sessionId}]: LEADER: Cannot Reload VOD, missing switch-back data`);
return;
}

if (this.use_demuxed_audio && [aSeq, audioDSeq, aSeqOffset, audioSegments].includes(null)) {
debug(`[${this._sessionId}]: LEADER: Cannot Reload VOD, missing switch-back data`);
return;
}
await this._sessionState.set("mediaSeq", mSeq);
await this._playheadState.set("mediaSeq", mSeq, isLeader);
await this._sessionState.set("discSeq", dSeq);
await this._sessionState.set("mediaSeqAudio", aSeq);
await this._playheadState.set("mediaSeqAudio", aSeq, isLeader);
await this._sessionState.set("discSeqAudio", audioDSeq);
// TODO: support demux^
debug(`[${this._sessionId}]: Setting current media and discontinuity count -> [${mSeq}]:[${dSeq}]`);
debug(`[${this._sessionId}]: Setting current audio media and discontinuity count -> [${aSeq}]:[${audioDSeq}]`);
// 3) Set new media segments/currentVod, to carry on the continuity from session-live
debug(`[${this._sessionId}]: LEADER: making changes to current VOD. I will also update currentVod in store.`);
const playheadState = await this._playheadState.getValues(["vodMediaSeqVideo"]);
Expand All @@ -1801,11 +1832,17 @@ class Session {
nextMseq = currentVod.getLiveMediaSequencesCount() - 1;
}

const playheadStateAudio = await this._playheadState.getValues(["vodMediaSeqAudio"]);
let nextAudioMseq = playheadStateAudio.vodMediaSeqAudio + 1;
if (nextAudioMseq > currentVod.getLiveMediaSequencesCount("audio") - 1) {
nextAudioMseq = currentVod.getLiveMediaSequencesCount("audio") - 1;
}

// ---------------------------------------------------.
// TODO: Support reloading with audioSegments and SubtitleSegments as well |
// TODO: Support reloading with SubtitleSegments as well |
// ---------------------------------------------------'

await currentVod.reload(nextMseq, segments, null, reloadBehind);
await currentVod.reload(nextMseq, segments, audioSegments, reloadBehind);
await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
await this._sessionState.set("vodReloaded", 1);
await this._sessionState.set("vodMediaSeqVideo", 0);
Expand All @@ -1820,6 +1857,7 @@ class Session {
debug(`[${this._sessionId}]: next VOD Reloaded (${currentVod.getDeltaTimes()})`);
debug(`[${this._sessionId}]: ${currentVod.getPlayheadPositions()}`);
debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}`);
debug(`[${this._sessionId}]: audio msequences=${currentVod.getLiveMediaSequencesCount("audio")}`);
cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
return;
} else {
Expand Down Expand Up @@ -1889,8 +1927,9 @@ class Session {

slateVod.load()
.then(() => {
const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
const hlsOpts = {
sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
shouldContainSubtitles: this.use_vtt_subtitles,
Expand Down Expand Up @@ -1987,10 +2026,10 @@ class Session {

slateVod.load()
.then(() => {
const hlsOpts = {
sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
const hlsOpts = {
sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
forcedDemuxMode: this.use_demuxed_audio,
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
shouldContainSubtitles: this.use_vtt_subtitles,
expectedSubtitleTracks: this._subtitleTracks
Expand Down

0 comments on commit b1bbe6c

Please sign in to comment.