Skip to content

Commit

Permalink
Implement Dummy media API
Browse files Browse the repository at this point in the history
  • Loading branch information
peaBerberian committed Jul 9, 2024
1 parent 4c0c855 commit 340b67c
Show file tree
Hide file tree
Showing 15 changed files with 2,804 additions and 11 deletions.
5 changes: 3 additions & 2 deletions demo/full/scripts/components/Options/Playback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ function PlaybackConfig({
</Checkbox>
<span className="option-desc">
{useDummyMediaElement
? "Use mocked media API. The content will not really play but the " +
"RxPlayer will believe it does (useful for debugging inaccessible content)."
? "Use mocked media API: The content will not really play but the RxPlayer " +
"will believe it does. Useful for debugging the RxPlayer's logic even on " +
"undecipherable or undecodable content."
: "Actually play the chosen content."}
</span>
</li>
Expand Down
13 changes: 9 additions & 4 deletions demo/full/scripts/controllers/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import type {
ILoadVideoOptions,
IVideoRepresentationsSwitchingMode,
} from "../../../../src/public_types";
import { DummyMediaElement } from "../../../../src/compat/dummy_media_element";
import DummyMediaElement from "../../../../src/experimental/tools/DummyMediaElement";
import { toDummyDrmConfiguration } from "../lib/parseDRMConfigurations";

const { useCallback, useEffect, useRef, useState } = React;

Expand Down Expand Up @@ -158,13 +159,14 @@ function Player(): JSX.Element {
if (playerModule) {
playerModule.destroy();
}
const videoElement = useDummyMediaElement
? (new DummyMediaElement() as unknown as HTMLMediaElement)
: videoElementRef.current;
const playerMod = new PlayerModule(
Object.assign(
{},
{
videoElement: useDummyMediaElement ?
new DummyMediaElement() as unknown as HTMLMediaElement :
videoElementRef.current,
videoElement,
textTrackElement: textTrackElementRef.current,
debugElement: debugElementRef.current,
},
Expand Down Expand Up @@ -223,6 +225,9 @@ function Player(): JSX.Element {
created.actions.updateWorkerMode(relyOnWorker);
playerMod = created;
}
if (useDummyMediaElement && contentInfo.keySystems !== undefined) {
contentInfo.keySystems = toDummyDrmConfiguration(contentInfo.keySystems);
}
loadContent(playerMod, contentInfo, loadVideoOpts);
},
[
Expand Down
41 changes: 41 additions & 0 deletions demo/full/scripts/lib/parseDRMConfigurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,47 @@ export default async function parseDRMConfigurations(
return keySystems.filter((ks): ks is IKeySystemOption => ks !== undefined);
}

export function toDummyDrmConfiguration(
baseOptions: IKeySystemOption[],
): IKeySystemOption[] {
return baseOptions.map((ks) => {
return {
...ks,
getLicense(...args: Parameters<IKeySystemOption["getLicense"]>) {
try {
const challenge = args[0];
const challengeStr = utf8ToStr(challenge);
const challengeObj = JSON.parse(challengeStr) as {
certificate: string | null;
persistent: boolean;
keyIds: string[];
};
const keys: Record<
string,
{
policyLevel: number;
}
> = {};
challengeObj.keyIds.forEach((kid) => {
keys[kid] = {
policyLevel: 50,
};
});
const license = {
type: "license",
persistent: false,
keys,
};
const licenseU8 = strToUtf8(JSON.stringify(license));
return licenseU8.buffer;
} catch (e) {
return ks.getLicense(...args);
}
},
};
});
}

function getServerCertificate(url: string): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
Expand Down
10 changes: 10 additions & 0 deletions demo/full/scripts/modules/player/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@ const PlayerModule = declareModule(
if (!isStopped && !hasEnded) {
state.update("isPaused", false);
}
setTimeout(() => {
if (!isStopped && !hasEnded && player.isPaused() && !state.get("isPaused")) {
state.update("isPaused", true);
}
}, 100);
},

pause() {
Expand All @@ -317,6 +322,11 @@ const PlayerModule = declareModule(
if (!isStopped && !hasEnded) {
state.update("isPaused", true);
}
setTimeout(() => {
if (!isStopped && !hasEnded && !player.isPaused() && state.get("isPaused")) {
state.update("isPaused", false);
}
}, 100);
},

stop() {
Expand Down
6 changes: 4 additions & 2 deletions src/compat/browser_compatibility_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import type { IListener } from "../utils/event_emitter";
import globalScope from "../utils/global_scope";
import isNullOrUndefined from "../utils/is_null_or_undefined";
import type { IEmeApiImplementation } from "./eme";

/**
* Browser implementation of a VTTCue constructor.
Expand Down Expand Up @@ -227,6 +228,8 @@ export interface IMediaElement extends IEventTarget<IMediaElementEventMap> {
*/
FORCED_MEDIA_SOURCE?: new () => IMediaSource;

FORCED_EME_API?: IEmeApiImplementation;

/* From `HTMLMediaElement`: */
autoplay: boolean;
buffered: TimeRanges;
Expand All @@ -253,11 +256,10 @@ export interface IMediaElement extends IEventTarget<IMediaElementEventMap> {

addTextTrack: (kind: TextTrackKind) => TextTrack;
appendChild<T extends Node>(x: T): void;
hasAttribute(attr: string): boolean;
hasChildNodes(): boolean;
pause(): void;
play(): Promise<void>;
removeAttribute(attr: string): void;
removeAttribute(attr: "src"): void;
removeChild(x: unknown): void;
setMediaKeys(x: IMediaKeys | null): Promise<void>;

Expand Down
Loading

0 comments on commit 340b67c

Please sign in to comment.