Skip to content

Commit

Permalink
Update DirectfileContentInitializer documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
peaBerberian committed Jun 16, 2023
1 parent 16f75e7 commit 67741f5
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/core/api/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,8 @@ class Player extends EventEmitter<IPublicAPIEvent> {
this.stop();
this._priv_currentError = null;
throw new Error("DirectFile feature not activated in your build.");
} else if (isNullOrUndefined(url)) {
throw new Error("No URL for a DirectFile content");
}
mediaElementTrackChoiceManager =
this._priv_initializeMediaElementTrackChoiceManager(
Expand Down
90 changes: 75 additions & 15 deletions src/core/init/directfile_content_initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
IKeySystemOption,
IPlayerError,
} from "../../public_types";
import assert from "../../utils/assert";
import createSharedReference, {
IReadOnlySharedReference,
} from "../../utils/reference";
Expand All @@ -39,35 +40,68 @@ import initializeContentDecryption from "./utils/initialize_content_decryption";
import RebufferingController from "./utils/rebuffering_controller";
import listenToMediaError from "./utils/throw_on_media_error";

/**
* `ContentIntializer` which will load contents by putting their URL in the
* `src` attribute of the given HTMLMediaElement.
*
* Because such contents are mainly loaded by the browser, those (called
* "directfile" contents in the RxPlayer) needs a simpler logic in-JS when
* compared to a content that relies on the MSE API.
*
* @class DirectFileContentInitializer
*/
export default class DirectFileContentInitializer extends ContentInitializer {
/**
* Initial options given to the `DirectFileContentInitializer`.
*/
private _settings : IDirectFileOptions;
/**
* Allows to abort and clean everything the `DirectFileContentInitializer` is
* doing.
*/
private _initCanceller : TaskCanceller;

/**
* Creates a new `DirectFileContentInitializer` linked to the given settings.
* @param {Object} settings
*/
constructor(settings : IDirectFileOptions) {
super();
this._settings = settings;
this._initCanceller = new TaskCanceller();
}

public prepare(): void {
/**
* "Prepare" content so it can later be played by calling `start`.
*/
public prepare() : void {
return; // Directfile contents do not have any preparation
}

/**
* Start playback of the content linked to this `DirectFileContentInitializer`
* on the given `HTMLMediaElement` and its associated `PlaybackObserver`.
* @param {HTMLMediaElement} mediaElement - HTMLMediaElement on which the
* content will be played.
* @param {Object} playbackObserver - Object regularly emitting playback
* information.
*/
public start(
mediaElement : HTMLMediaElement,
playbackObserver : PlaybackObserver
): void {
) : void {
const cancelSignal = this._initCanceller.signal;
const { keySystems, speed, url } = this._settings;

clearElementSrc(mediaElement);

if (url == null) {
throw new Error("No URL for a DirectFile content");
}

/**
* Create dummy encryption data emitter, as those are not sent from the
* RxPlayer for directfile contents.
*/
const decryptionRef = createSharedReference(null);
decryptionRef.finish();

const drmInitRef =
initializeContentDecryption(mediaElement, keySystems, decryptionRef, {
onError: (err) => this._onFatalError(err),
Expand Down Expand Up @@ -99,7 +133,7 @@ export default class DirectFileContentInitializer extends ContentInitializer {

drmInitRef.onUpdate((evt, stopListeningToDrmUpdates) => {
if (evt.initializationState.type === "uninitialized") {
return;
return; // nothing done yet
}
stopListeningToDrmUpdates();

Expand All @@ -109,39 +143,57 @@ export default class DirectFileContentInitializer extends ContentInitializer {
cancelSignal.register(() => {
clearElementSrc(mediaElement);
});

if (evt.initializationState.type === "awaiting-media-link") {
evt.initializationState.value.isMediaLinked.setValue(true);
drmInitRef.onUpdate((newDrmStatus, stopListeningToDrmUpdatesAgain) => {
if (newDrmStatus.initializationState.type === "initialized") {
stopListeningToDrmUpdatesAgain();
this._seekAndPlay(mediaElement, playbackObserver);
return;
}
}, { emitCurrentValue: true, clearSignal: cancelSignal });
} else {
assert(evt.initializationState.type === "initialized");
this._seekAndPlay(mediaElement, playbackObserver);
return;
}
}, { emitCurrentValue: true, clearSignal: cancelSignal });
}

/**
* Update URL this `ContentIntializer` depends on.
* @param {Array.<string>|undefined} _urls
* @param {boolean} _refreshNow
*/
public updateContentUrls(_urls : string[] | undefined, _refreshNow : boolean) : void {
throw new Error("Cannot update content URL of directfile contents");
}

public dispose(): void {
/**
* Stop content and free all resources linked to this `ContentIntializer`.
*/
public dispose() : void {
this._initCanceller.cancel();
}

private _onFatalError(err : unknown) {
/**
* Logic performed when a fatal error was triggered.
* @param {*} err - The fatal error in question.
*/
private _onFatalError(err : unknown) : void {
this._initCanceller.cancel();
this.trigger("error", err);
}

/**
* Perform the initial seek (to begin playback at an initially-calculated
* position based on settings) and auto-play if needed when loaded.
* @param {HTMLMediaElement} mediaElement
* @param {Object} playbackObserver
*/
private _seekAndPlay(
mediaElement : HTMLMediaElement,
playbackObserver : PlaybackObserver
) {
) : void {
const cancelSignal = this._initCanceller.signal;
const { autoPlay, startAt } = this._settings;
const initialTime = () => {
Expand Down Expand Up @@ -177,7 +229,7 @@ export default class DirectFileContentInitializer extends ContentInitializer {
/**
* calculate initial time as a position in seconds.
* @param {HTMLMediaElement} mediaElement
* @param {Object|undefined} startAt
* @param {Object|undefined} [startAt]
* @returns {number}
*/
function getDirectFileInitialTime(
Expand Down Expand Up @@ -219,11 +271,19 @@ function getDirectFileInitialTime(
return 0;
}

// Argument used by `initializeDirectfileContent`
/** Options used by the `DirectFileContentInitializer` */
export interface IDirectFileOptions {
/** If `true` we will play right after the content is considered "loaded". */
autoPlay : boolean;
/**
* Encryption-related settings. Can be left as an empty array if the content
* isn't encrypted.
*/
keySystems : IKeySystemOption[];
/** Communicate the playback rate wanted by the user. */
speed : IReadOnlySharedReference<number>;
/** Optional initial position to start at. */
startAt? : IInitialTimeOptions | undefined;
url? : string | undefined;
/** URL that should be played. */
url : string;
}

0 comments on commit 67741f5

Please sign in to comment.