rx-player
Version:
Canal+ HTML5 Video Player
171 lines (160 loc) • 6.32 kB
text/typescript
/**
* Copyright 2015 CANAL+ Group
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type {
IMediaElement,
IMediaKeySystemAccess,
IMediaKeys,
} from "../../compat/browser_compatibility_types";
import canReuseMediaKeys from "../../compat/can_reuse_media_keys";
import type { IEmeApiImplementation } from "../../compat/eme";
import { EncryptedMediaError } from "../../errors";
import log from "../../log";
import type { IKeySystemOption } from "../../public_types";
import isNullOrUndefined from "../../utils/is_null_or_undefined";
import type { CancellationSignal } from "../../utils/task_canceller";
import getMediaKeySystemAccess from "./find_key_system";
import type { ICodecSupportList } from "./find_key_system";
import type { IMediaKeySessionStores } from "./types";
import LoadedSessionsStore from "./utils/loaded_sessions_store";
import MediaKeysAttacher from "./utils/media_keys_attacher";
import PersistentSessionsStore from "./utils/persistent_sessions_store";
import ServerCertificateStore from "./utils/server_certificate_store";
/**
* @throws {EncryptedMediaError}
* @param {Object} keySystemOptions
* @returns {Object|null}
*/
function createPersistentSessionsStorage(
keySystemOptions: IKeySystemOption,
): PersistentSessionsStore | null {
const { persistentLicenseConfig } = keySystemOptions;
if (isNullOrUndefined(persistentLicenseConfig)) {
return null;
}
log.debug("DRM", "Set the given license storage");
return new PersistentSessionsStore(persistentLicenseConfig);
}
/** Object returned by `getMediaKeysInfos`. */
export interface IMediaKeysInfos {
/** The MediaKeySystemAccess which allowed to create the MediaKeys instance. */
mediaKeySystemAccess: IMediaKeySystemAccess;
/**
* The MediaKeySystemConfiguration that has been provided to the
* `requestMediaKeySystemAccess` API.
*/
askedConfiguration: MediaKeySystemConfiguration;
/** The MediaKeys instance. */
mediaKeys: IMediaKeys;
/** Stores allowing to create and retrieve MediaKeySessions. */
stores: IMediaKeySessionStores;
/** IKeySystemOption compatible to the created MediaKeys instance. */
options: IKeySystemOption;
/** The codecs support */
codecSupport: ICodecSupportList;
}
/**
* Create a MediaKeys instance and associated structures (or just return the
* current ones if sufficient) based on a wanted configuration.
* @param {Object} eme - current EME implementation
* @param {HTMLMediaElement} mediaElement - The HTMLMediaElement on which you
* will attach the MediaKeys instance.
* This Element is here only used to check if the current MediaKeys and
* MediaKeySystemAccess instances are sufficient
* @param {Array.<Object>} keySystemsConfigs - The key system configuration.
* Needed to ask the right MediaKeySystemAccess.
* @param {Object} cancelSignal - CancellationSignal allowing to cancel the
* creation of the MediaKeys instance while the task is still pending.
* @returns {Promise.<Object>}
*/
export default async function getMediaKeysInfos(
eme: IEmeApiImplementation,
mediaElement: IMediaElement,
keySystemsConfigs: IKeySystemOption[],
cancelSignal: CancellationSignal,
): Promise<IMediaKeysInfos> {
const evt = await getMediaKeySystemAccess(
eme,
mediaElement,
keySystemsConfigs,
cancelSignal,
);
if (cancelSignal.cancellationError !== null) {
throw cancelSignal.cancellationError;
}
const { options, mediaKeySystemAccess, askedConfiguration, codecSupport } = evt.value;
const currentState = await MediaKeysAttacher.getAttachedMediaKeysState(mediaElement);
const persistentSessionsStore = createPersistentSessionsStorage(options);
if (
evt.value.options.reuseMediaKeys !== false &&
canReuseMediaKeys() &&
currentState !== null &&
evt.type === "reuse-media-key-system-access"
) {
log.debug("DRM", "Reusing already created MediaKeys");
const { mediaKeys, loadedSessionsStore } = currentState;
// We might just rely on the currently attached MediaKeys instance.
// First check if server certificate parameters are the same than in the
// current MediaKeys instance. If not, re-create MediaKeys from scratch.
if (
ServerCertificateStore.hasOne(mediaKeys) === false ||
(!isNullOrUndefined(options.serverCertificate) &&
ServerCertificateStore.has(mediaKeys, options.serverCertificate))
) {
return {
mediaKeys,
mediaKeySystemAccess,
askedConfiguration,
stores: { loadedSessionsStore, persistentSessionsStore },
options,
codecSupport,
};
}
}
const mediaKeys = await createMediaKeys(mediaKeySystemAccess);
log.info("DRM", "MediaKeys created with success");
const loadedSessionsStore = new LoadedSessionsStore(mediaKeys);
return {
mediaKeys,
mediaKeySystemAccess,
askedConfiguration,
stores: { loadedSessionsStore, persistentSessionsStore },
options,
codecSupport,
};
}
/**
* Create `MediaKeys` from the `MediaKeySystemAccess` given.
* Throws the right formatted error if it fails.
* @param {MediaKeySystemAccess} mediaKeySystemAccess
* @returns {Promise.<MediaKeys>}
*/
async function createMediaKeys(
mediaKeySystemAccess: IMediaKeySystemAccess,
): Promise<IMediaKeys> {
log.info("DRM", "Calling createMediaKeys on the MediaKeySystemAccess");
try {
const mediaKeys = await mediaKeySystemAccess.createMediaKeys();
return mediaKeys;
} catch (error) {
const message =
error instanceof Error ? error.message : "Unknown error when creating MediaKeys.";
throw new EncryptedMediaError("CREATE_MEDIA_KEYS_ERROR", message, {
keyStatuses: undefined,
keySystemConfiguration: mediaKeySystemAccess.getConfiguration(),
keySystem: mediaKeySystemAccess.keySystem,
});
}
}