src/controller/buffer-operation-queue.ts
import { logger } from '../utils/logger';
import type { BufferOperation, BufferOperationQueues, SourceBuffers, SourceBufferName } from '../types/buffer';
export default class BufferOperationQueue {
private buffers: SourceBuffers;
private queues: BufferOperationQueues = {
video: [],
audio: [],
audiovideo: []
};
constructor (sourceBufferReference: SourceBuffers) {
this.buffers = sourceBufferReference;
}
public append (operation: BufferOperation, type: SourceBufferName) {
const queue = this.queues[type];
queue.push(operation);
if (queue.length === 1 && this.buffers[type]) {
this.executeNext(type);
}
}
public insertAbort (operation: BufferOperation, type: SourceBufferName) {
const queue = this.queues[type];
queue.unshift(operation);
this.executeNext(type, true);
}
public appendBlocker (type: SourceBufferName) : Promise<{}> {
let execute;
const promise: Promise<{}> = new Promise((resolve) => {
execute = resolve;
});
const operation: BufferOperation = {
execute,
onStart: () => {},
onComplete: () => {},
onError: () => {}
};
this.append(operation, type);
return promise;
}
public executeNext (type: SourceBufferName, ignoreUpdating?: boolean) {
const { buffers, queues } = this;
const sb = buffers[type];
console.assert(!sb || ignoreUpdating || !sb.updating, `${type} sourceBuffer must exist, and must not be updating`);
const queue = queues[type];
if (queue.length) {
const operation: BufferOperation = queue[0];
try {
// Operations are expected to result in an 'updateend' event being fired. If not, the queue will lock. Operations
// which do not end with this event must call _onSBUpdateEnd manually
operation.execute();
} catch (e) {
logger.warn('[buffer-operation-queue]: Unhandled exception executing the current operation');
operation.onError(e);
// Only shift the current operation off, otherwise the updateend handler will do this for us
if (!sb || !sb.updating) {
queue.shift();
}
}
}
}
public shiftAndExecuteNext (type: SourceBufferName) {
this.queues[type].shift();
this.executeNext(type);
}
public current (type: SourceBufferName) {
return this.queues[type][0];
}
}