Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ For the subdirectories and files in this directory not represented in that schem
- `manifest` (_./manifest_): Defines a `Manifest` structure and its properties, a central
structure of the player describing a content.

- `PlaybackObserver` (./playback_observer): Defines `PlaybackObserver` instances, used by
many modules to obtain playback-related properties (such as the playing position, the
current playback speed etc.).
- `MediaElementMonitor` (./media_element_monitor): Defines the `MediaElementMonitor` ,
used by many modules to poll the `HTMLMediaElement` for playback-related properties
(such as the playing position, the current playback speed etc.).

- `parsers` (_./parsers_): Various parsers for several formats

Expand Down
24 changes: 6 additions & 18 deletions src/compat/__tests__/is_codec_supported.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,8 @@ describe("Compat - isCodecSupported", () => {
});
const isCodecSupported = (await vi.importActual("../is_codec_supported"))
.default as typeof IIsCodecSupported;
expect(isCodecSupported(document.createElement("video"), "foo")).toEqual(false);
expect(isCodecSupported(document.createElement("video"), "")).toEqual(false);
});

it("should return true in any case if the MediaSource does not have the right function", async () => {
vi.doMock("../browser_compatibility_types", () => {
return {
MediaSource_: { isTypeSupported: undefined },
};
});
const isCodecSupported = (await vi.importActual("../is_codec_supported"))
.default as typeof IIsCodecSupported;
expect(isCodecSupported(document.createElement("video"), "foo")).toEqual(true);
expect(isCodecSupported(document.createElement("video"), "")).toEqual(true);
expect(isCodecSupported("foo")).toEqual(false);
expect(isCodecSupported("")).toEqual(false);
});

it("should return true if MediaSource.isTypeSupported returns true", async () => {
Expand All @@ -42,8 +30,8 @@ describe("Compat - isCodecSupported", () => {
});
const isCodecSupported = (await vi.importActual("../is_codec_supported"))
.default as typeof IIsCodecSupported;
expect(isCodecSupported(document.createElement("video"), "foo")).toEqual(true);
expect(isCodecSupported(document.createElement("video"), "")).toEqual(true);
expect(isCodecSupported("foo")).toEqual(true);
expect(isCodecSupported("")).toEqual(true);
});

it("should return false if MediaSource.isTypeSupported returns false", async () => {
Expand All @@ -58,7 +46,7 @@ describe("Compat - isCodecSupported", () => {
});
const isCodecSupported = (await vi.importActual("../is_codec_supported"))
.default as typeof IIsCodecSupported;
expect(isCodecSupported(document.createElement("video"), "foo")).toEqual(false);
expect(isCodecSupported(document.createElement("video"), "")).toEqual(false);
expect(isCodecSupported("foo")).toEqual(false);
expect(isCodecSupported("")).toEqual(false);
});
});
7 changes: 6 additions & 1 deletion src/compat/browser_compatibility_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ export interface IMediaSourceEventMap {
endstreaming: Event;
}

export interface IMediaSourceClass {
new (): IMediaSource;
isTypeSupported(mimetype: string): boolean;
}

/**
* Type-compatible with the `MediaSource` type (i.e. a `MediaSource` is a valid
* `IMediaSource`), the `IMediaSource` type allows to:
Expand Down Expand Up @@ -234,7 +239,7 @@ export interface IMediaElement extends IEventTarget<IMediaElementEventMap> {
* Optional property allowing to force a specific MSE Implementation when
* relying on a given `IMediaElement`.
*/
FORCED_MEDIA_SOURCE?: new () => IMediaSource;
FORCED_MEDIA_SOURCE?: IMediaSourceClass;

FORCED_EME_API?: IEmeApiImplementation;

Expand Down
49 changes: 23 additions & 26 deletions src/compat/is_codec_supported.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
* limitations under the License.
*/

import type DummyMediaElement from "../experimental/tools/DummyMediaElement";
import log from "../log";
import isNullOrUndefined from "../utils/is_null_or_undefined";
import isWorker from "../utils/is_worker";
import type { IMediaSourceClass } from "./browser_compatibility_types";
import { MediaSource_ } from "./browser_compatibility_types";
import type { IMediaElement } from "./browser_compatibility_types";

/**
* Setting this value limit the number of entries in the support map
Expand All @@ -32,47 +30,46 @@ const MAX_SUPPORT_MAP_ENTRIES = 200;
* and help for performance especially on low-end devices.
*/
const supportMap: Map<string, boolean> = new Map();

/**
* Returns true if the given codec is supported by the browser's MediaSource
* implementation.
* @param {HTMLMediaElement} mediaElement
* @param {string} mimeType - The MIME media type that you want to test support
* for in the current browser.
* This may include the codecs parameter to provide added details about the
* codecs used within the file.
* @param {Object|undefined} [MediaSourceClass] - The `MediaSource` class relied
* on to play contents.
* `undefined` if unknown or if the `MediaSource` we rely on is in another
* environment (e.g. a WebWorker).
* @returns {Boolean}
*/
export default function isCodecSupported(
mediaElement: IMediaElement,
mimeType: string,
/* eslint-disable-next-line @typescript-eslint/naming-convention */
MediaSourceClass?: IMediaSourceClass | undefined,
): boolean {
// TODO: We only added that as a hotfix for now, to allow support of the right codecs
// on a dummy media element
if ((mediaElement as DummyMediaElement).isDummy) {
return (mediaElement as DummyMediaElement).FORCED_MEDIA_SOURCE.isTypeSupported(
mimeType,
);
}
if (isNullOrUndefined(MediaSource_)) {
/* eslint-disable @typescript-eslint/unbound-method */
const isTypeSupported =
MediaSourceClass !== undefined
? MediaSourceClass.isTypeSupported
: MediaSource_?.isTypeSupported;
if (typeof isTypeSupported !== "function") {
if (isWorker) {
log.error("mse", "Cannot request codec support in a worker without MSE.");
}
return false;
}

if (typeof MediaSource_.isTypeSupported === "function") {
const cachedSupport = supportMap.get(mimeType);
if (cachedSupport !== undefined) {
return cachedSupport;
} else {
const isSupported = MediaSource_.isTypeSupported(mimeType);
if (supportMap.size >= MAX_SUPPORT_MAP_ENTRIES) {
supportMap.clear();
}
supportMap.set(mimeType, isSupported);
return isSupported;
const cachedSupport = supportMap.get(mimeType);
if (cachedSupport !== undefined) {
return cachedSupport;
} else {
const isSupported = isTypeSupported(mimeType);
if (supportMap.size >= MAX_SUPPORT_MAP_ENTRIES) {
supportMap.clear();
}
supportMap.set(mimeType, isSupported);
return isSupported;
}

return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ function makePlaybackObservation(overrides: Partial<any> = {}) {
};
}

/** Build a minimal playback observer around a single observation value. */
function makePlaybackObserver(obs: any) {
/** Build a minimal MediaElementMonitor around a single observation value. */
function makeMediaElementMonitor(obs: any) {
const ref = new SharedReference(obs);
return {
getReference: () => ref,
Expand Down Expand Up @@ -87,7 +87,7 @@ describe("createAdaptiveRepresentationSelector", () => {
const currentRepRef = new SharedReference(null);
const repsRef = new SharedReference([rep]);
const obs = makePlaybackObservation({ bufferGap: 0 });
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);

selector(makeContext(), currentRepRef, repsRef, observer, canceller.signal);

Expand All @@ -104,15 +104,15 @@ describe("createAdaptiveRepresentationSelector", () => {
const currentRepRef = new SharedReference(null);
const repsRef = new SharedReference([rep]);
const obs = makePlaybackObservation();
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);
const ctx = makeContext();

selector(ctx, currentRepRef, repsRef, observer, canceller.signal);
selector(
ctx,
new SharedReference(null),
new SharedReference([rep]),
makePlaybackObserver(obs),
makeMediaElementMonitor(obs),
canceller.signal,
);

Expand Down Expand Up @@ -145,14 +145,14 @@ describe("createAdaptiveRepresentationSelector", () => {
videoCtx,
new SharedReference(null),
new SharedReference([rep]),
makePlaybackObserver(obs),
makeMediaElementMonitor(obs),
canceller.signal,
);
selector(
audioCtx,
new SharedReference(null),
new SharedReference([rep]),
makePlaybackObserver(obs),
makeMediaElementMonitor(obs),
canceller.signal,
);

Expand All @@ -170,7 +170,7 @@ describe("createAdaptiveRepresentationSelector", () => {
const currentRepRef = new SharedReference(null);
const repsRef = new SharedReference([rep]);
const obs = makePlaybackObservation();
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);

const { estimates } = selector(
makeContext(),
Expand Down Expand Up @@ -242,7 +242,7 @@ describe("createAdaptiveRepresentationSelector", () => {
const currentRepRef = new SharedReference(currentRep);
const repsRef = new SharedReference([repLow, repMid, repHigh]);
const obs = makePlaybackObservation(obsOverrides);
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);

const result = selector(
makeContext(isDynamic),
Expand Down Expand Up @@ -400,7 +400,7 @@ describe("createAdaptiveRepresentationSelector", () => {
maximumPosition: 50,
position: makeObservationPosition(20),
});
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);

const { estimates } = selector(
makeContext(true),
Expand All @@ -426,7 +426,7 @@ describe("createAdaptiveRepresentationSelector", () => {
const currentRepRef = new SharedReference(null);
const repsRef = new SharedReference([repLow, repHigh]);
const obs = makePlaybackObservation();
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);

const { callbacks } = selector(
makeContext(),
Expand Down Expand Up @@ -577,7 +577,7 @@ describe("createAdaptiveRepresentationSelector", () => {
makeContext(),
new SharedReference(null),
new SharedReference(reps),
makePlaybackObserver(makePlaybackObservation()),
makeMediaElementMonitor(makePlaybackObservation()),
canceller.signal,
);

Expand Down Expand Up @@ -608,7 +608,7 @@ describe("createAdaptiveRepresentationSelector", () => {
makeContext(),
new SharedReference(null),
new SharedReference(reps),
makePlaybackObserver(makePlaybackObservation({ speed: 2 })),
makeMediaElementMonitor(makePlaybackObservation({ speed: 2 })),
canceller.signal,
);

Expand Down Expand Up @@ -640,7 +640,7 @@ describe("createAdaptiveRepresentationSelector", () => {
makeContext(),
new SharedReference(null),
new SharedReference(reps),
makePlaybackObserver(makePlaybackObservation({ speed: 0 })),
makeMediaElementMonitor(makePlaybackObservation({ speed: 0 })),
canceller.signal,
);

Expand All @@ -667,7 +667,7 @@ describe("createAdaptiveRepresentationSelector", () => {
const currentRepRef = new SharedReference(null);
const repsRef = new SharedReference([repLow]);
const obs = makePlaybackObservation();
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);

const { estimates } = selector(
makeContext(),
Expand Down Expand Up @@ -712,7 +712,7 @@ describe("createAdaptiveRepresentationSelector", () => {
const currentRepRef = new SharedReference(null);
const repsRef = new SharedReference([rep]);
const obs = makePlaybackObservation();
const observer = makePlaybackObserver(obs);
const observer = makeMediaElementMonitor(obs);

const { estimates } = selector(
makeContext(),
Expand Down
Loading
Loading