Skip to content

Commit

Permalink
Reimplement WebWorkers on top of the v4.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
peaBerberian committed Sep 1, 2023
1 parent 17fa838 commit 7779c1a
Show file tree
Hide file tree
Showing 74 changed files with 5,109 additions and 1,183 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

/dist/_esm5.processed
/dist/_esm5.raw
/dist/multithread
!/dist/multithread/index.html

/doc/generated

Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
"sideEffects": false,
"scripts": {
"build": "webpack --progress --config webpack.config.js --env production",
"build:multi": "npm run build:multi:main && npm run build:multi:worker",
"build:multi:main": "esbuild ./src/main/index.ts --bundle --outfile=dist/multithread/main.js --define:__ENVIRONMENT__=\"{ \\\"PRODUCTION\\\": 0, \\\"DEV\\\": 1, \\\"CURRENT_ENV\\\": 1 }\"",
"build:multi:worker": "esbuild ./src/worker/index.ts --bundle --outfile=dist/multithread/worker.js --define:__ENVIRONMENT__=\"{ \\\"PRODUCTION\\\": 0, \\\"DEV\\\": 1, \\\"CURRENT_ENV\\\": 1 }\"",
"build:all": "npm run build && npm run build:min && npm run build:wasm:release && npm run build:modular",
"build:min": "webpack --progress --config webpack.config.js --env minify --env production",
"build:min:report": "webpack --progress --config webpack.config.js --env minify --env production --env reportSize",
Expand Down
7 changes: 4 additions & 3 deletions src/compat/eme/custom_media_keys/old_webkit_media_keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ export interface IOldWebkitHTMLMediaElement extends HTMLVideoElement {
* @returns {Boolean}
*/
export function isOldWebkitMediaElement(
element : HTMLMediaElement|IOldWebkitHTMLMediaElement
element : unknown
) : element is IOldWebkitHTMLMediaElement {
return typeof (element as IOldWebkitHTMLMediaElement)
.webkitGenerateKeyRequest === "function";
return typeof (
element as IOldWebkitHTMLMediaElement
)?.webkitGenerateKeyRequest === "function";
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/compat/eme/eme-api-implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ function getEmeApiImplementation(
implementation = "webkit";
} else {
// This is for Chrome with unprefixed EME api
if (isOldWebkitMediaElement(HTMLVideoElement.prototype)) {
if (isOldWebkitMediaElement(globalScope.HTMLVideoElement?.prototype)) {
onEncrypted = createCompatibleEventListener(["needkey"]);
const callbacks = getOldKitWebKitMediaKeyCallbacks();
isTypeSupported = callbacks.isTypeSupported;
Expand Down
5 changes: 5 additions & 0 deletions src/compat/is_codec_supported.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import isWorker from "../compat/is_worker";
import { MediaSource_ } from "./browser_compatibility_types";

/**
Expand All @@ -26,6 +27,10 @@ import { MediaSource_ } from "./browser_compatibility_types";
* @returns {Boolean}
*/
export default function isCodecSupported(mimeType : string) : boolean {
if (isWorker) {
// XXX TODO
return mimeType.indexOf("ec-3") < 0;
}
if (MediaSource_ == null) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/compat/is_worker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
declare const WorkerGlobalScope : any | undefined;
declare const WorkerGlobalScope : any;

/**
* `true` if the current code is running in a WebWorker.
Expand Down
21 changes: 5 additions & 16 deletions src/core/adaptive/adaptive_representation_selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import config from "../../config";
import log from "../../log";
import Manifest, {
Adaptation,
Expand Down Expand Up @@ -253,7 +252,7 @@ function getEstimateReference(
}, { includeLastObservation: false, clearSignal: innerCancellationSignal });

onAddedSegment = function (val : IAddedSegmentCallbackPayload) {
if (lastPlaybackObservation === null) {
if (lastPlaybackObservation === null || val.buffered === null) {
return;
}
const { position, speed } = lastPlaybackObservation;
Expand Down Expand Up @@ -283,7 +282,7 @@ function getEstimateReference(

/** Returns the actual estimate based on all methods and algorithm available. */
function getCurrentEstimate(): IABREstimate {
const { bufferGap, position, maximumPosition } = lastPlaybackObservation;
const { position, maximumPosition } = lastPlaybackObservation;
const resolutionLimit = filters.limitResolution.getValue();
const bitrateThrottle = filters.throttleBitrate.getValue();
const currentRepresentationVal = currentRepresentation.getValue();
Expand All @@ -306,17 +305,7 @@ function getEstimateReference(
lastPlaybackObservation.speed :
1);

const { ABR_ENTER_BUFFER_BASED_ALGO,
ABR_EXIT_BUFFER_BASED_ALGO } = config.getCurrent();

if (allowBufferBasedEstimates && bufferGap <= ABR_EXIT_BUFFER_BASED_ALGO) {
allowBufferBasedEstimates = false;
} else if (!allowBufferBasedEstimates &&
isFinite(bufferGap) &&
bufferGap >= ABR_ENTER_BUFFER_BASED_ALGO)
{
allowBufferBasedEstimates = true;
}
allowBufferBasedEstimates = false;

/**
* Representation chosen when considering only [pessimist] bandwidth
Expand Down Expand Up @@ -576,7 +565,7 @@ export interface IRepresentationEstimatorPlaybackObservation {
* For the concerned media buffer, difference in seconds between the next
* position where no segment data is available and the current position.
*/
bufferGap : number;
// bufferGap : number;
/**
* Information on the current media position in seconds at the time of a
* Playback Observation.
Expand Down Expand Up @@ -686,7 +675,7 @@ export interface IAddedSegmentCallbackPayload {
* The buffered ranges of the related media buffer after that segment has
* been pushed.
*/
buffered : TimeRanges;
buffered : TimeRanges | null;
/** The context for the segment that has been pushed. */
content : { representation : Representation };
}
Expand Down
13 changes: 4 additions & 9 deletions src/core/adaptive/guess_based_chooser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,6 @@ export default class GuessBasedChooser {
public getGuess(
representations : Representation[],
observation : {
/**
* For the concerned media buffer, difference in seconds between the next
* position where no segment data is available and the current position.
*/
bufferGap: number;
/**
* Last "playback rate" set by the user. This is the ideal "playback rate" at
* which the media should play.
Expand All @@ -99,7 +94,7 @@ export default class GuessBasedChooser {
incomingBestBitrate : number,
requests : IRequestInfo[]
) : Representation | null {
const { bufferGap, speed } = observation;
const { speed } = observation;
const lastChosenRep = this._lastAbrEstimate.representation;
if (lastChosenRep === null) {
return null; // There's nothing to base our guess on
Expand All @@ -122,7 +117,7 @@ export default class GuessBasedChooser {
if (scoreData === undefined) {
return null; // not enough information to start guessing
}
if (this._canGuessHigher(bufferGap, speed, scoreData)) {
if (this._canGuessHigher(5, speed, scoreData)) {
const nextRepresentation = getNextRepresentation(representations,
currentRepresentation);
if (nextRepresentation !== null) {
Expand All @@ -146,7 +141,7 @@ export default class GuessBasedChooser {

const shouldStopGuess = this._shouldStopGuess(currentRepresentation,
scoreData,
bufferGap,
5,
requests);
if (shouldStopGuess) {
// Block guesses for a time
Expand All @@ -158,7 +153,7 @@ export default class GuessBasedChooser {
return currentRepresentation;
}

if (this._canGuessHigher(bufferGap, speed, scoreData)) {
if (this._canGuessHigher(5, speed, scoreData)) {
const nextRepresentation = getNextRepresentation(representations,
currentRepresentation);
if (nextRepresentation !== null) {
Expand Down
15 changes: 6 additions & 9 deletions src/core/adaptive/network_analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
/** Object describing the current playback conditions. */
type IPlaybackConditionsInfo = Pick<
IRepresentationEstimatorPlaybackObservation,
"bufferGap" | "position" | "speed" | "duration">;
"position" | "speed" | "duration">;

/**
* Get pending segment request(s) starting with the asked segment position.
Expand Down Expand Up @@ -149,9 +149,8 @@ function estimateStarvationModeBitrate(
// TODO Skip only for newer segments?
return undefined;
}
const { bufferGap, speed, position } = playbackInfo;
const realBufferGap = isFinite(bufferGap) ? bufferGap :
0;
const { speed, position } = playbackInfo;
const realBufferGap = 5;
const nextNeededPosition = position.last + realBufferGap;
const concernedRequests = getConcernedRequests(pendingRequests, nextNeededPosition);

Expand Down Expand Up @@ -234,8 +233,7 @@ function shouldDirectlySwitchToLowBitrate(
// TODO only when playing close to the live edge?
return true;
}
const realBufferGap = isFinite(playbackInfo.bufferGap) ? playbackInfo.bufferGap :
0;
const realBufferGap = 5;
const nextNeededPosition = playbackInfo.position.last + realBufferGap;
const nextRequest = arrayFind(requests, ({ content }) =>
content.segment.duration > 0 &&
Expand Down Expand Up @@ -326,9 +324,8 @@ export default class NetworkAnalyzer {
let newBitrateCeil : number | undefined; // bitrate ceil for the chosen Representation
let bandwidthEstimate;
const localConf = this._config;
const { bufferGap, position, duration } = playbackInfo;
const realBufferGap = isFinite(bufferGap) ? bufferGap :
0;
const { position, duration } = playbackInfo;
const realBufferGap = 5;
const { ABR_STARVATION_DURATION_DELTA } = config.getCurrent();
// check if should get in/out of starvation mode
if (isNaN(duration) ||
Expand Down
15 changes: 8 additions & 7 deletions src/core/api/debug/modules/segment_buffer_content.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
Adaptation,
Period,
Representation,
getPeriodForTime,
IAdaptationMetadata,
IPeriodMetadata,
IRepresentationMetadata,
} from "../../../../manifest";
import isNullOrUndefined from "../../../../utils/is_null_or_undefined";
import { CancellationSignal } from "../../../../utils/task_canceller";
Expand Down Expand Up @@ -94,7 +95,7 @@ export default function createSegmentBufferGraph(
const adap = instance.__priv_getCurrentAdaptation()?.[bufferType];
const manifest = instance.__priv_getManifest();
if (manifest !== null && !isNullOrUndefined(rep) && !isNullOrUndefined(adap)) {
const period = manifest.getPeriodForTime(currentTime);
const period = getPeriodForTime(manifest, currentTime);
if (period !== undefined) {
loadingRangeRepInfoElt.appendChild(createMetricTitle("load"));
loadingRangeRepInfoElt.appendChild(createElement("span", {
Expand All @@ -112,9 +113,9 @@ export default function createSegmentBufferGraph(

function constructRepresentationInfo(
content : {
period : Period;
adaptation : Adaptation;
representation : Representation;
period : IPeriodMetadata;
adaptation : IAdaptationMetadata;
representation : IRepresentationMetadata;
}
) : string {
const period = content.period;
Expand Down
5 changes: 5 additions & 0 deletions src/core/api/option_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export interface IParsedConstructorOptions {

videoElement : HTMLMediaElement;
baseBandwidth : number;
workerOptions : {
workerUrl: string;
dashWasmUrl: string;
} | undefined;
}

/**
Expand Down Expand Up @@ -215,6 +219,7 @@ function parseConstructorOptions(
videoElement,
wantedBufferAhead,
maxVideoBufferSize,
workerOptions: options.workerOptions,
throttleVideoBitrateWhenHidden,
baseBandwidth };
}
Expand Down
35 changes: 25 additions & 10 deletions src/core/api/playback_observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,23 +511,38 @@ export interface IPlaybackObservation extends IMediaInfos {
* `IReadOnlyPlaybackObserver` to "remove" its right to update playback.
*/
export interface IReadOnlyPlaybackObserver<TObservationType> {
/** Get the current playing position, in seconds. */
getCurrentTime() : number;
/**
* Get the current playing position, in seconds.
* Returns `undefined` when this cannot be known, such as when the playback
* observer is running in a WebWorker.
* @returns {number|undefined}
*/
getCurrentTime() : number | undefined;
/**
* Returns the current playback rate advertised by the `HTMLMediaElement`.
* @returns {number}
* Returns `undefined` when this cannot be known, such as when the playback
* observer is running in a WebWorker.
* @returns {number|undefined}
*/
getPlaybackRate() : number;
/** Get the HTMLMediaElement's current `readyState`. */
getReadyState() : number;
getPlaybackRate() : number | undefined;
/**
* Get the HTMLMediaElement's current `readyState`.
* Returns `undefined` when this cannot be known, such as when the playback
* observer is running in a WebWorker.
* @returns {number|undefined}
*/
getReadyState() : number | undefined;
/**
* Returns the current `paused` status advertised by the `HTMLMediaElement`.
*
* Use this instead of the same status emitted on an observation when you want
* to be sure you're using the current value.
* @returns {boolean}
*
* Returns `undefined` when this cannot be known, such as when the playback
* observer is running in a WebWorker.
* @returns {boolean|undefined}
*/
getIsPaused() : boolean;
getIsPaused() : boolean | undefined;
/**
* Returns an `IReadOnlySharedReference` storing the last playback observation
* produced by the `IReadOnlyPlaybackObserver` and updated each time a new one
Expand Down Expand Up @@ -939,7 +954,7 @@ function prettyPrintBuffered(
* @param {Function} transform
* @returns {Object}
*/
function generateReadOnlyObserver<TSource, TDest>(
export function generateReadOnlyObserver<TSource, TDest>(
src : IReadOnlyPlaybackObserver<TSource>,
transform : (
observationRef : IReadOnlySharedReference<TSource>,
Expand All @@ -955,7 +970,7 @@ function generateReadOnlyObserver<TSource, TDest>(
getReadyState() {
return src.getReadyState();
},
getPlaybackRate() : number {
getPlaybackRate() {
return src.getPlaybackRate();
},
getIsPaused() {
Expand Down
Loading

0 comments on commit 7779c1a

Please sign in to comment.