Skip to content

Commit

Permalink
SourceBuffer controller cleanup (#5911)
Browse files Browse the repository at this point in the history
* Cleanup MMS setup, source childen removal, handle muxed ("audiovideo") fmp4 main playlist setup

* Remove MMS `quality` capping and allow for some tolerance in `should buffer up to maxBufferLength` with MMS
  • Loading branch information
robwalch committed Oct 17, 2023
1 parent 5150429 commit ce6821a
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 35 deletions.
66 changes: 31 additions & 35 deletions src/controller/buffer-controller.ts
Expand Up @@ -203,10 +203,10 @@ export default class BufferController implements ComponentAPI {
try {
media.removeAttribute('src');
// ManagedMediaSource will not open without disableRemotePlayback set to false or source alternatives
const MMS = (self as any).ManagedMediaSource;
media.disableRemotePlayback =
media.disableRemotePlayback ||
ms instanceof (self as any).ManagedMediaSource;
removeChildren(media);
media.disableRemotePlayback || (MMS && ms instanceof MMS);
removeSourceChildren(media);
addSource(media, objectUrl);
media.load();
} catch (error) {
Expand All @@ -219,32 +219,16 @@ export default class BufferController implements ComponentAPI {
}
}
private _onEndStreaming = (event) => {
if (!this.hls) {
return;
}
this.hls.pauseBuffering();
};
private _onStartStreaming = (event) => {
const { hls, mediaSource } = this;
if (!hls || !mediaSource) {
if (!this.hls) {
return;
}
if ('quality' in mediaSource) {
if (mediaSource.quality === 'low') {
hls.autoLevelCapping = CapLevelController.getMaxLevelByMediaSize(
hls.levels,
1280,
720,
);
} else if (mediaSource.quality === 'medium') {
hls.autoLevelCapping = CapLevelController.getMaxLevelByMediaSize(
hls.levels,
1920,
1080,
);
} else {
// do not cap max quality
hls.autoLevelCapping = -1;
}
}
hls.resumeBuffering();
this.hls.resumeBuffering();
};

protected onMediaDetaching() {
Expand Down Expand Up @@ -285,7 +269,7 @@ export default class BufferController implements ComponentAPI {
if (this.mediaSrc === _objectUrl) {
media.removeAttribute('src');
if (this.appendSource) {
removeChildren(media);
removeSourceChildren(media);
}
media.load();
} else {
Expand Down Expand Up @@ -335,8 +319,8 @@ export default class BufferController implements ComponentAPI {
data: BufferCodecsData,
) {
const sourceBufferCount = this.getSourceBufferTypes().length;

Object.keys(data).forEach((trackName) => {
const trackNames = Object.keys(data);
trackNames.forEach((trackName) => {
if (sourceBufferCount) {
// check if SourceBuffer codec needs to change
const track = this.tracks[trackName];
Expand Down Expand Up @@ -387,10 +371,19 @@ export default class BufferController implements ComponentAPI {
return;
}

this.bufferCodecEventsExpected = Math.max(
const bufferCodecEventsExpected = Math.max(
this.bufferCodecEventsExpected - 1,
0,
);
if (this.bufferCodecEventsExpected !== bufferCodecEventsExpected) {
this.log(
`${bufferCodecEventsExpected} bufferCodec event(s) expected ${trackNames.join(
',',
)}`,
);
this.bufferCodecEventsExpected = this._bufferCodecEventsTotal =
bufferCodecEventsExpected;
}
if (this.mediaSource && this.mediaSource.readyState === 'open') {
this.checkPendingTracks();
}
Expand Down Expand Up @@ -561,7 +554,7 @@ export default class BufferController implements ComponentAPI {
// logger.debug(`[buffer-controller]: Finished flushing ${data.startOffset} -> ${data.endOffset} for ${type} Source Buffer`);
this.hls.trigger(Events.BUFFER_FLUSHED, { type });
},
onError: (error) => {
onError: (error: Error) => {
this.warn(`Failed to remove from ${type} SourceBuffer`, error);
},
});
Expand Down Expand Up @@ -880,8 +873,10 @@ export default class BufferController implements ComponentAPI {
// 2 tracks is the max (one for audio, one for video). If we've reach this max go ahead and create the buffers.
const pendingTracksCount = Object.keys(pendingTracks).length;
if (
(pendingTracksCount && !bufferCodecEventsExpected) ||
pendingTracksCount === 2
pendingTracksCount &&
(!bufferCodecEventsExpected ||
pendingTracksCount === 2 ||
'audiovideo' in pendingTracks)
) {
// ok, let's create them now !
this.createSourceBuffers(pendingTracks);
Expand Down Expand Up @@ -1170,10 +1165,11 @@ export default class BufferController implements ComponentAPI {
}
}

function removeChildren(node: HTMLElement) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
function removeSourceChildren(node: HTMLElement) {
const sourceChildren = node.querySelectorAll('source');
[].slice.call(sourceChildren).forEach((source) => {
node.removeChild(source);
});
}

function addSource(media: HTMLMediaElement, url: string) {
Expand Down
3 changes: 3 additions & 0 deletions tests/functional/auto/setup.js
Expand Up @@ -112,6 +112,9 @@ async function testIdleBufferLength(url, config) {
self.startStream(url, config, callback, autoplay);
const video = self.video;
const maxBufferLength = self.hls.config.maxBufferLength;
if (self.ManagedMediaSource) {
config.avBufferOffset = Math.max(config.avBufferOffset || 0, 3);
}
video.onprogress = function () {
const buffered = video.buffered;
if (buffered.length) {
Expand Down

0 comments on commit ce6821a

Please sign in to comment.