Skip to content

Commit

Permalink
Add requestMediaKeySytemAccess-specific tests
Browse files Browse the repository at this point in the history
  • Loading branch information
peaBerberian committed Aug 13, 2024
1 parent 76afb2c commit e19cc47
Show file tree
Hide file tree
Showing 11 changed files with 1,208 additions and 219 deletions.
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 @@ -42,7 +42,7 @@ export interface IEmeApiImplementation {
requestMediaKeySystemAccess: (
keyType: string,
config: MediaKeySystemConfiguration[],
) => Promise<IMediaKeySystemAccess | CustomMediaKeySystemAccess>;
) => Promise<IMediaKeySystemAccess>;

/**
* API allowing to listen for `"encrypted"` events, presumably sent by the
Expand Down
120 changes: 84 additions & 36 deletions src/experimental/tools/DummyMediaElement/eme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,46 +22,94 @@ import {
utf8ToStr,
} from "../../../utils/string_parsing";

const keySystemBlacklist: string[] = [];
const keySystemWhitelist: string[] = [];
export interface IRequestMediaKeySystemAccessConfig {
/**
* For the given arguments of the `navigator.requestMediaKeySystemAccess`
* API, returns the resulting `MediaKeySystemConfiguration`, or `null` if
* that configuration should be anounced as not supported.
*
* If not set, the first configuration will be anounced as supported for a
* supported key system.
*
* @param {string} keySystem
* @param {Array.<Object>} configs
* @returns {Object} config
*/
getMediaKeySystemConfiguration?:
| ((
keySystem: string,
configs: MediaKeySystemConfiguration[],
) => MediaKeySystemConfiguration | null)
| undefined;

/**
* For the given key system, returns `true` if it should be anounced as
* supported or `false` if it should be anounced as unsupported.
*
* If not set, all keySystems are supported.
* @param {string} keySystem
* @returns {boolean}
*/
isKeySystemSupported: ((keySystem: string) => boolean) | undefined;
}

/**
* Re-implementation of the EME `navigator.requestMediaKeySystemAccess` API.
* @param {string} keySystem
* @param {Array.<Object>} supportedConfigurations
* @returns {Promise.<Object>}
* Return a configured re-implementation of the EME
* `navigator.requestMediaKeySystemAccess` API.
* @param {Object|undefined} [config]
* @returns {Function}
*/
export function requestMediaKeySystemAccess(
keySystem: string,
supportedConfigurations: MediaKeySystemConfiguration[],
): Promise<DummyMediaKeySystemAccess> {
if (keySystem === "") {
return Promise.reject(
new TypeError("`requestMediaKeySystemAccess` error: empty string"),
);
}
if (supportedConfigurations.length === 0) {
return Promise.reject(
new TypeError("`requestMediaKeySystemAccess` error: no given configuration."),
export function createRequestMediaKeySystemAccess(
config?: IRequestMediaKeySystemAccessConfig | undefined,
) {
/**
* Re-implementation of the EME `navigator.requestMediaKeySystemAccess` API.
* @param {string} keySystem
* @param {Array.<Object>} supportedConfigurations
* @returns {Promise.<Object>}
*/
return function requestMediaKeySystemAccess(
keySystem: string,
supportedConfigurations: MediaKeySystemConfiguration[],
): Promise<DummyMediaKeySystemAccess> {
if (keySystem === "") {
return Promise.reject(
new TypeError("`requestMediaKeySystemAccess` error: empty string"),
);
}
if (supportedConfigurations.length === 0) {
return Promise.reject(
new TypeError("`requestMediaKeySystemAccess` error: no given configuration."),
);
}
if (
typeof config?.isKeySystemSupported === "function" &&
!config.isKeySystemSupported(keySystem)
) {
const error = new Error(`"${keySystem}" is not a supported keySystem`);
error.name = "NotSupportedError";
return Promise.reject(error);
}
let supportedConfiguration: MediaKeySystemConfiguration | null =
supportedConfigurations[0] ?? null;

if (typeof config?.getMediaKeySystemConfiguration === "function") {
supportedConfiguration = config.getMediaKeySystemConfiguration(
keySystem,
supportedConfigurations,
);
}
if (supportedConfiguration === null) {
const error = new Error(
"`requestMediaKeySystemAccess` error: No configuration supported.",
);
error.name = "NotSupportedError";
return Promise.reject(error);
}
return Promise.resolve(
new DummyMediaKeySystemAccess(keySystem, supportedConfiguration),
);
}
if (
(keySystemWhitelist.length > 0 && !arrayIncludes(keySystemWhitelist, keySystem)) ||
(keySystemBlacklist.length > 0 && arrayIncludes(keySystemBlacklist, keySystem))
) {
const error = new Error(`"${keySystem}" is not a supported keySystem`);
error.name = "NotSupportedError";
return Promise.reject(error);
}
for (const config of supportedConfigurations) {
// TODO configurable configuration validation. Callback?
return Promise.resolve(new DummyMediaKeySystemAccess(keySystem, config));
}
const error = new Error(
"`requestMediaKeySystemAccess` error: No configuration supported.",
);
error.name = "NotSupportedError";
return Promise.reject(error);
};
}

/**
Expand Down
14 changes: 12 additions & 2 deletions src/experimental/tools/DummyMediaElement/html5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ import {
keepRangeIntersection,
} from "../../../utils/ranges";
import TaskCanceller from "../../../utils/task_canceller";
import { DummyMediaKeys, requestMediaKeySystemAccess } from "./eme";
import { DummyMediaKeys, createRequestMediaKeySystemAccess } from "./eme";
import type { IRequestMediaKeySystemAccessConfig } from "./eme";
import { DummyMediaSource } from "./mse";
import TimeRangesWithMetadata, { EventScheduler } from "./utils";

export interface IDummyMediaElementOptions {
nodeName?: "AUDIO" | "VIDEO" | undefined | null;
drmOptions?:
| {
requestMediaKeySystemAccessConfig?:
| IRequestMediaKeySystemAccessConfig
| undefined;
}
| undefined;
}

export class DummyMediaElement
Expand Down Expand Up @@ -152,7 +160,9 @@ export class DummyMediaElement

this.FORCED_MEDIA_SOURCE = DummyMediaSource;
this.FORCED_EME_API = {
requestMediaKeySystemAccess,
requestMediaKeySystemAccess: createRequestMediaKeySystemAccess(
opts.drmOptions?.requestMediaKeySystemAccessConfig,
),
onEncrypted: createCompatibleEventListener(["encrypted"]),
setMediaKeys,
implementation: "standard",
Expand Down
6 changes: 5 additions & 1 deletion src/utils/are_codecs_compatible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ function areCodecsCompatible(a: string, b: string): boolean {
if (codecsA === "" || codecsB === "") {
return false;
}
if (codecsA.split(".")[0] !== codecsB.split(".")[0]) {
let initialPartA = codecsA.split(".")[0];
initialPartA = initialPartA === "hev1" ? "hvc1" : initialPartA;
let initialPartB = codecsB.split(".")[0];
initialPartB = initialPartB === "hev1" ? "hvc1" : initialPartB;
if (initialPartA !== initialPartB) {
return false;
}
return true;
Expand Down
Loading

0 comments on commit e19cc47

Please sign in to comment.