Skip to content

Commit 3a509a3

Browse files
committed
Handle ManagedMediaSource endStreaming events without aborting requests
Fixes #6918 (cherry picked from #6186 commit 6de6587)
1 parent 91bb1e7 commit 3a509a3

File tree

7 files changed

+54
-20
lines changed

7 files changed

+54
-20
lines changed

api-extractor/report/hls.js.api.md

+10
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ export class BaseStreamController extends TaskLoop implements NetworkComponentAP
327327
// (undocumented)
328328
protected bufferFragmentData(data: RemuxedTrack, frag: Fragment, part: Part | null, chunkMeta: ChunkMetadata, noBacktracking?: boolean): void;
329329
// (undocumented)
330+
protected buffering: boolean;
331+
// (undocumented)
330332
protected checkLiveUpdate(details: LevelDetails): void;
331333
// (undocumented)
332334
protected clearTrackerIfNeeded(frag: Fragment): void;
@@ -453,6 +455,8 @@ export class BaseStreamController extends TaskLoop implements NetworkComponentAP
453455
// (undocumented)
454456
protected onvseeking: EventListener | null;
455457
// (undocumented)
458+
pauseBuffering(): void;
459+
// (undocumented)
456460
protected playlistType: PlaylistLevelType;
457461
// (undocumented)
458462
protected recoverWorkerError(data: ErrorData): void;
@@ -475,6 +479,8 @@ export class BaseStreamController extends TaskLoop implements NetworkComponentAP
475479
// (undocumented)
476480
protected resetWhenMissingContext(chunkMeta: ChunkMetadata): void;
477481
// (undocumented)
482+
resumeBuffering(): void;
483+
// (undocumented)
478484
protected retryDate: number;
479485
// (undocumented)
480486
protected seekToStartPos(): void;
@@ -2917,6 +2923,10 @@ export type MP4RemuxerConfig = {
29172923
//
29182924
// @public (undocumented)
29192925
export interface NetworkComponentAPI extends ComponentAPI {
2926+
// (undocumented)
2927+
pauseBuffering?(): void;
2928+
// (undocumented)
2929+
resumeBuffering?(): void;
29202930
// (undocumented)
29212931
startLoad(startPosition: number): void;
29222932
// (undocumented)

src/controller/audio-stream-controller.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,14 @@ class AudioStreamController
281281
const { hls, levels, media, trackId } = this;
282282
const config = hls.config;
283283

284-
// 1. if video not attached AND
284+
// 1. if buffering is suspended
285+
// 2. if video not attached AND
285286
// start fragment already requested OR start frag prefetch not enabled
286-
// 2. if tracks or track not loaded and selected
287+
// 3. if tracks or track not loaded and selected
287288
// then exit loop
288289
// => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
289290
if (
291+
!this.buffering ||
290292
(!media && (this.startFragRequested || !config.startFragPrefetch)) ||
291293
!levels?.[trackId]
292294
) {

src/controller/base-stream-controller.ts

+9
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export default class BaseStreamController
9797
protected startFragRequested: boolean = false;
9898
protected decrypter: Decrypter;
9999
protected initPTS: RationalTimestamp[] = [];
100+
protected buffering: boolean = true;
100101
protected onvseeking: EventListener | null = null;
101102
protected onvended: EventListener | null = null;
102103

@@ -150,6 +151,14 @@ export default class BaseStreamController
150151
this.state = State.STOPPED;
151152
}
152153

154+
public pauseBuffering() {
155+
this.buffering = false;
156+
}
157+
158+
public resumeBuffering() {
159+
this.buffering = true;
160+
}
161+
153162
protected _streamEnded(
154163
bufferInfo: BufferInfo,
155164
levelDetails: LevelDetails,

src/controller/buffer-controller.ts

+1
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ export default class BufferController implements ComponentAPI {
309309
this.resetBuffer(type);
310310
});
311311
this._initSourceBuffer();
312+
this.hls.resumeBuffering();
312313
}
313314

314315
private resetBuffer(type: SourceBufferName) {

src/controller/stream-controller.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export default class StreamController
237237
return;
238238
}
239239

240-
const level = hls.nextLoadLevel;
240+
const level = this.buffering ? hls.nextLoadLevel : hls.loadLevel;
241241
if (!levels?.[level]) {
242242
return;
243243
}
@@ -262,6 +262,9 @@ export default class StreamController
262262
this.state = State.ENDED;
263263
return;
264264
}
265+
if (!this.buffering) {
266+
return;
267+
}
265268

266269
// set next load level : this will trigger a playlist load if needed
267270
if (hls.loadLevel !== level && hls.manualLevel === -1) {

src/hls.ts

+24-17
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,13 @@ export default class Hls implements HlsEventEmitter {
430430
startLoad(startPosition: number = -1) {
431431
logger.log(`startLoad(${startPosition})`);
432432
this.started = true;
433-
this.networkControllers.forEach((controller) => {
434-
controller.startLoad(startPosition);
435-
});
433+
this.resumeBuffering();
434+
for (let i = 0; i < this.networkControllers.length; i++) {
435+
this.networkControllers[i].startLoad(startPosition);
436+
if (!this.started || !this.networkControllers) {
437+
break;
438+
}
439+
}
436440
}
437441

438442
/**
@@ -441,32 +445,35 @@ export default class Hls implements HlsEventEmitter {
441445
stopLoad() {
442446
logger.log('stopLoad');
443447
this.started = false;
444-
this.networkControllers.forEach((controller) => {
445-
controller.stopLoad();
446-
});
448+
for (let i = 0; i < this.networkControllers.length; i++) {
449+
this.networkControllers[i].stopLoad();
450+
if (this.started || !this.networkControllers) {
451+
break;
452+
}
453+
}
447454
}
448455

449456
/**
450-
* Resumes stream controller segment loading if previously started.
457+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
451458
*/
452459
resumeBuffering() {
453-
if (this.started) {
454-
this.networkControllers.forEach((controller) => {
455-
if ('fragmentLoader' in controller) {
456-
controller.startLoad(-1);
457-
}
458-
});
459-
}
460+
logger.log(`resume buffering`);
461+
this.networkControllers.forEach((controller) => {
462+
if (controller.resumeBuffering) {
463+
controller.resumeBuffering();
464+
}
465+
});
460466
}
461467

462468
/**
463-
* Stops stream controller segment loading without changing 'started' state like stopLoad().
469+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
464470
* This allows for media buffering to be paused without interupting playlist loading.
465471
*/
466472
pauseBuffering() {
473+
logger.log(`pause buffering`);
467474
this.networkControllers.forEach((controller) => {
468-
if ('fragmentLoader' in controller) {
469-
controller.stopLoad();
475+
if (controller.pauseBuffering) {
476+
controller.pauseBuffering();
470477
}
471478
});
472479
}

src/types/component-api.ts

+2
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ export interface AbrComponentAPI extends ComponentAPI {
1515
export interface NetworkComponentAPI extends ComponentAPI {
1616
startLoad(startPosition: number): void;
1717
stopLoad(): void;
18+
pauseBuffering?(): void;
19+
resumeBuffering?(): void;
1820
}

0 commit comments

Comments
 (0)