UNPKG

rx-player

Version:
207 lines (197 loc) 6.67 kB
/** * 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 EventEmitter from "../../../utils/event_emitter"; import isNullOrUndefined from "../../../utils/is_null_or_undefined"; import TaskCanceller from "../../../utils/task_canceller"; import wrapInPromise from "../../../utils/wrapInPromise"; import type { IMediaElement, IMediaKeySession, IMediaKeys, } from "../../browser_compatibility_types"; import * as events from "../../event_listeners"; import type { MSMediaKeys, MSMediaKeySession } from "./ms_media_keys_constructor"; import { MSMediaKeysConstructor } from "./ms_media_keys_constructor"; class IE11MediaKeySession extends EventEmitter<MediaKeySessionEventMap> implements IMediaKeySession { public readonly update: (license: BufferSource) => Promise<void>; public readonly closed: Promise<MediaKeySessionClosedReason>; public expiration: number; public keyStatuses: MediaKeyStatusMap; private readonly _mk: MSMediaKeys; private readonly _sessionClosingCanceller: TaskCanceller; private _ss: MSMediaKeySession | undefined; constructor(mk: MSMediaKeys) { super(); this.expiration = NaN; this.keyStatuses = new Map(); this._mk = mk; this._sessionClosingCanceller = new TaskCanceller("IE11 MediaKeySession Closing"); this.closed = new Promise((resolve) => { this._sessionClosingCanceller.signal.register(() => resolve("closed-by-application"), ); }); this.update = (license: BufferSource) => { return new Promise((resolve, reject) => { if (this._ss === undefined) { return reject("MediaKeySession not set."); } try { resolve( (this._ss.update as (license: BufferSource, sessionId: string) => void)( license, "", ), ); } catch (err) { reject(err); } }); }; } generateRequest(_initDataType: string, initData: BufferSource): Promise<void> { return new Promise((resolve) => { let initDataU8: Uint8Array; if (initData instanceof Uint8Array) { initDataU8 = initData; } else if (initData instanceof ArrayBuffer) { initDataU8 = new Uint8Array(initData); } else { initDataU8 = new Uint8Array(initData.buffer); } this._ss = this._mk.createSession("video/mp4", initDataU8); events.onKeyMessage( this._ss, (evt) => { this.trigger( ((evt as Event).type ?? "message") as keyof MediaKeySessionEventMap, evt as Event, ); }, this._sessionClosingCanceller.signal, ); events.onKeyAdded( this._ss, (evt) => { this.trigger( ((evt as Event).type ?? "keyadded") as keyof MediaKeySessionEventMap, evt as Event, ); }, this._sessionClosingCanceller.signal, ); events.onKeyError( this._ss, (evt) => { this.trigger( ((evt as Event).type ?? "keyerror") as keyof MediaKeySessionEventMap, evt as Event, ); }, this._sessionClosingCanceller.signal, ); resolve(); }); } close(): Promise<void> { return new Promise((resolve) => { if (!isNullOrUndefined(this._ss)) { this._ss.close(); this._ss = undefined; } this._sessionClosingCanceller.cancel("IE11 MediaKeySession close"); resolve(); }); } load(): Promise<boolean> { return Promise.resolve(false); } remove(): Promise<void> { return Promise.resolve(); } get sessionId(): string { return this._ss?.sessionId ?? ""; } } class IE11CustomMediaKeys implements IMediaKeys { private _videoElement?: IMediaElement; private _mediaKeys?: MSMediaKeys; constructor(keyType: string) { if (MSMediaKeysConstructor === undefined) { throw new Error("No MSMediaKeys API."); } this._mediaKeys = new MSMediaKeysConstructor(keyType); } _setVideo(videoElement: IMediaElement): Promise<unknown> { return wrapInPromise(() => { this._videoElement = videoElement; if (this._videoElement.msSetMediaKeys !== undefined) { this._videoElement.msSetMediaKeys(this._mediaKeys); } }); } createSession(/* sessionType */): IMediaKeySession { if (this._videoElement === undefined || this._mediaKeys === undefined) { throw new Error("Video not attached to the MediaKeys"); } return new IE11MediaKeySession(this._mediaKeys); } setServerCertificate(): Promise<boolean> { throw new Error("Server certificate is not implemented in your browser"); } } export default function getIE11MediaKeysCallbacks(): { isTypeSupported: (keyType: string) => boolean; createCustomMediaKeys: (keyType: string) => IE11CustomMediaKeys; setMediaKeys: (elt: IMediaElement, mediaKeys: IMediaKeys | null) => Promise<unknown>; } { const isTypeSupported = (keySystem: string, type?: string | null) => { if (MSMediaKeysConstructor === undefined) { throw new Error("No MSMediaKeys API."); } if (type !== undefined) { return MSMediaKeysConstructor.isTypeSupported(keySystem, type); } return MSMediaKeysConstructor.isTypeSupported(keySystem); }; const createCustomMediaKeys = (keyType: string) => new IE11CustomMediaKeys(keyType); const setMediaKeys = ( elt: IMediaElement, mediaKeys: IMediaKeys | null, ): Promise<unknown> => { if (mediaKeys === null) { // msSetMediaKeys only accepts native MSMediaKeys as argument. // Calling it with null or undefined will raise an exception. // There is no way to unset the mediakeys in that case, so return here. return Promise.resolve(undefined); } if (!(mediaKeys instanceof IE11CustomMediaKeys)) { throw new Error( "Custom setMediaKeys is supposed to be called " + "with IE11 custom MediaKeys.", ); } return mediaKeys._setVideo(elt); }; return { isTypeSupported, createCustomMediaKeys, setMediaKeys, }; } export { MSMediaKeysConstructor };