Skip to content

Commit

Permalink
Begin implementing for non-MSE-in-Worker
Browse files Browse the repository at this point in the history
  • Loading branch information
peaBerberian committed Aug 30, 2023
1 parent 8a99af7 commit b8b290d
Show file tree
Hide file tree
Showing 39 changed files with 1,271 additions and 437 deletions.
20 changes: 12 additions & 8 deletions src/compat/browser_compatibility_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import isNullOrUndefined from "../utils/is_null_or_undefined";
import isWorker from "../utils/is_worker";
import isNode from "./is_node";

/** Regular MediaKeys type + optional functions present in IE11. */
Expand Down Expand Up @@ -164,23 +165,26 @@ export interface ICompatPictureInPictureWindow
extends EventTarget { width: number;
height: number; }

interface WindowsWithMediaSourceImplems extends Window {
type GlobalScope = typeof globalThis;
interface WindowsWithMediaSourceImplems extends GlobalScope {
MediaSource? : typeof MediaSource;
MozMediaSource? : typeof MediaSource;
WebKitMediaSource? : typeof MediaSource;
MSMediaSource? : typeof MediaSource;
}

const win : WindowsWithMediaSourceImplems | undefined = isNode ? undefined :
window;
const glob : WindowsWithMediaSourceImplems | undefined =
isWorker() ? self :
isNode ? undefined :
window;

/** MediaSource implementation, including vendored implementations. */
const MediaSource_ : typeof MediaSource | undefined =
win === undefined ? undefined :
!isNullOrUndefined(win.MediaSource) ? win.MediaSource :
!isNullOrUndefined(win.MozMediaSource) ? win.MozMediaSource :
!isNullOrUndefined(win.WebKitMediaSource) ? win.WebKitMediaSource :
win.MSMediaSource;
glob === undefined ? undefined :
!isNullOrUndefined(glob.MediaSource) ? glob.MediaSource :
!isNullOrUndefined(glob.MozMediaSource) ? glob.MozMediaSource :
!isNullOrUndefined(glob.WebKitMediaSource) ? glob.WebKitMediaSource :
glob.MSMediaSource;

/** List an HTMLMediaElement's possible values for its readyState property. */
const READY_STATES = { HAVE_NOTHING: 0,
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
7 changes: 5 additions & 2 deletions src/core/api/option_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ export interface IParsedConstructorOptions {

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

/**
Expand Down Expand Up @@ -216,7 +219,7 @@ function parseConstructorOptions(
videoElement,
wantedBufferAhead,
maxVideoBufferSize,
workerUrl: options.workerUrl,
workerOptions: options.workerOptions,
throttleVideoBitrateWhenHidden,
baseBandwidth };
}
Expand Down
13 changes: 10 additions & 3 deletions src/core/api/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
} from "../../errors";
import features from "../../features";
import log from "../../log";
import sendMessage from "../../main/send_message";
import {
getLivePosition,
getMaximumSafePosition,
Expand Down Expand Up @@ -335,7 +336,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
throttleVideoBitrateWhenHidden,
videoElement,
wantedBufferAhead,
workerUrl,
workerOptions,
maxVideoBufferSize } = parseConstructorOptions(options);
const { DEFAULT_UNMUTED_VOLUME } = config.getCurrent();
// Workaround to support Firefox autoplay on FF 42.
Expand Down Expand Up @@ -390,11 +391,17 @@ class Player extends EventEmitter<IPublicAPIEvent> {

this._priv_lastAutoPlay = false;

if (workerUrl !== undefined) {
this._priv_worker = new Worker(workerUrl);
if (workerOptions !== undefined) {
this._priv_worker = new Worker(workerOptions.workerUrl);
this._priv_worker.onerror = (evt: ErrorEvent) => {
log.error("UNEXPECTED WORKER ERROR:", evt.error as Error);
};
sendMessage(this._priv_worker, {
type: "init",
value: {
wasmUrl: workerOptions.dashWasmUrl,
},
});
} else {
this._priv_worker = null;
}
Expand Down
13 changes: 5 additions & 8 deletions src/core/init/create_content_time_boundaries_observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { IPlayerError } from "../../public_types";
import TaskCanceller, {
CancellationSignal,
} from "../../utils/task_canceller";
import MediaSourceInterface from "../../worker/media_source_interface";
import { IReadOnlyPlaybackObserver } from "../api";
import SegmentBuffersStore from "../segment_buffers";
import { IStreamOrchestratorPlaybackObservation } from "../stream";
import ContentTimeBoundariesObserver from "./utils/content_time_boundaries_observer";
import { maintainEndOfStream } from "./utils/end_of_stream";
import MediaSourceDurationUpdater from "./utils/media_source_duration_updater";

export interface IContentTimeBoundariesObserverCallbacks {
onWarning: (evt: IPlayerError) => void;
Expand All @@ -35,16 +35,14 @@ export interface IContentTimeBoundariesObserverCallbacks {
*/
export default function createContentTimeBoundariesObserver(
manifest : Manifest,
mediaSource : MediaSource,
mediaSource : MediaSourceInterface,
streamObserver : IReadOnlyPlaybackObserver<IStreamOrchestratorPlaybackObservation>,
segmentBuffersStore : SegmentBuffersStore,
callbacks: IContentTimeBoundariesObserverCallbacks,
cancelSignal : CancellationSignal
) : ContentTimeBoundariesObserver {
/** Maintains the MediaSource's duration up-to-date with the Manifest */
const mediaSourceDurationUpdater = new MediaSourceDurationUpdater(mediaSource);
cancelSignal.register(() => {
mediaSourceDurationUpdater.stopUpdating();
mediaSource.interruptDurationSetting();
});
/** Allows to cancel a pending `end-of-stream` operation. */
let endOfStreamCanceller : TaskCanceller | null = null;
Expand All @@ -61,7 +59,7 @@ export default function createContentTimeBoundariesObserver(
contentTimeBoundariesObserver.addEventListener("periodChange", (period) =>
callbacks.onPeriodChanged(period));
contentTimeBoundariesObserver.addEventListener("durationUpdate", (newDuration) => {
mediaSourceDurationUpdater.updateDuration(newDuration.duration, newDuration.isEnd);
mediaSource.setDuration(newDuration.duration, newDuration.isEnd);
});
contentTimeBoundariesObserver.addEventListener("endOfStream", () => {
if (endOfStreamCanceller === null) {
Expand All @@ -79,7 +77,6 @@ export default function createContentTimeBoundariesObserver(
}
});
const currentDuration = contentTimeBoundariesObserver.getCurrentDuration();
mediaSourceDurationUpdater.updateDuration(currentDuration.duration,
currentDuration.isEnd);
mediaSource.setDuration(currentDuration.duration, currentDuration.isEnd);
return contentTimeBoundariesObserver;
}
15 changes: 8 additions & 7 deletions src/core/init/media_source_content_initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import createSharedReference, {
import TaskCanceller, {
CancellationSignal,
} from "../../utils/task_canceller";
import MediaSourceInterface from "../../worker/media_source_interface";
import AdaptiveRepresentationSelector, {
IAdaptiveRepresentationSelectorArguments,
IRepresentationEstimator,
Expand All @@ -60,7 +61,7 @@ import StreamOrchestrator, {
/* eslint-disable-next-line max-len */
import createContentTimeBoundariesObserver from "./create_content_time_boundaries_observer";
import { ContentInitializer } from "./types";
import openMediaSource from "./utils/create_media_source";
import createMediaSource from "./utils/create_media_source";
import createStreamPlaybackObserver from "./utils/create_stream_playback_observer";
import getInitialTime, {
IInitialTimeOptions,
Expand Down Expand Up @@ -202,7 +203,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
private _initializeMediaSourceAndDecryption(
mediaElement : HTMLMediaElement,
protectionRef : IReadOnlySharedReference<IContentProtection | null>
) : Promise<{ mediaSource : MediaSource;
) : Promise<{ mediaSource : MediaSourceInterface;
drmSystemId : string | undefined;
unlinkMediaSource : TaskCanceller; }>
{
Expand All @@ -228,7 +229,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer {

const mediaSourceCanceller = new TaskCanceller();
mediaSourceCanceller.linkToSignal(initCanceller.signal);
openMediaSource(mediaElement, mediaSourceCanceller.signal)
createMediaSource(mediaElement, mediaSourceCanceller.signal)
.then((mediaSource) => {
const lastDrmStatus = drmInitRef.getValue();
if (lastDrmStatus.initializationState.type === "awaiting-media-link") {
Expand Down Expand Up @@ -261,7 +262,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer {

private async _onInitialMediaSourceReady(
mediaElement : HTMLMediaElement,
initialMediaSource : MediaSource,
initialMediaSource : MediaSourceInterface,
playbackObserver : PlaybackObserver,
drmSystemId : string | undefined,
protectionRef : ISharedReference<IContentProtection | null>,
Expand Down Expand Up @@ -333,7 +334,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
* @param {boolean} shouldPlay
*/
function recursivelyLoadOnMediaSource(
mediaSource : MediaSource,
mediaSource : MediaSourceInterface,
startingPos : number,
shouldPlay : boolean,
currentCanceller : TaskCanceller
Expand Down Expand Up @@ -366,7 +367,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer {

const newCanceller = new TaskCanceller();
newCanceller.linkToSignal(initCanceller.signal);
openMediaSource(mediaElement, newCanceller.signal)
createMediaSource(mediaElement, newCanceller.signal)
.then(newMediaSource => {
recursivelyLoadOnMediaSource(newMediaSource,
reloadOrder.position,
Expand Down Expand Up @@ -815,7 +816,7 @@ interface IBufferingMediaSettings {
*/
protectionRef : ISharedReference<IContentProtection | null>;
/** `MediaSource` element on which the media will be buffered. */
mediaSource : MediaSource;
mediaSource : MediaSourceInterface;
/** The initial position to seek to in media time, in seconds. */
initialTime : number;
/** If `true` it should automatically play once enough data is loaded. */
Expand Down
Loading

0 comments on commit b8b290d

Please sign in to comment.