Skip to content

Commit

Permalink
[Proposal] Forbid usage of the HTMLMediaElement and MSE TS types
Browse files Browse the repository at this point in the history
In a recent PoC (Proof Of Concept), I attempted to replicate a subset of
the HTMLMediaElement and MSE APIs without the decoding part to facilitate
the implementation of some advanced features and integration tests.

It has shown potential, and though it may be a little too soon to merge
and rely on that development, I propose here to merge a component of it
that can be useful in multiple ways.

The idea is to restrict some key browser API (`HTMLMediaElement`,
`MediaSource` and `SourceBuffer`) types by providing our own
browser-compatible (this compatibilty is checked at compile-time through
some TypeScript trick) type definitions but with either optional
supplementary methods and attributes or compatible updated definitons
(e.g. a method whose return type was only an enumeration of some values
could now return even more values).

For example, for `IMediaElement` (the redefinition of
`HTMLMediaElement`), I added the vendor-prefixed events and methods that
may be used by the RxPlayer (that were previously in the
`ICompatHTMLMediaElement` type) - such as the `webkitSetMediaKeys`
method.
Here this allows to make TypeScript nicer to us when we're exploiting
webkit/moz/ms-prefixed API for example.

I also added to it the optional `FORCED_MEDIA_SOURCE` attribute allowing
to define a custom MSE implementation when relying on a given media
element, though we could also remove that part for this PR.

Another key advantage is that the subset of MSE-related API that are
relied-on by the RxPlayer are now clearly listed in a single file, which
can be useful when debugging, making API-interaction changes and/or when
refactoring.
  • Loading branch information
peaBerberian committed Jul 24, 2024
1 parent ee99661 commit c0c5430
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
57 changes: 57 additions & 0 deletions src/transports/utils/__tests__/find_complete_box.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* 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 findCompleteBox from "../find_complete_box";

describe("transports utils - findCompleteBox", () => {

Check failure on line 19 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value
it("should return -1 if the box is not found", () => {

Check failure on line 20 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value
const byteArr = new Uint8Array([
0, 0, 0, 9, 0x64, 0x67, 0x32, 0x55, 4, 0, 0, 0, 10, 0x88, 0x68, 0x47, 0x53, 12, 88,
]);

expect(findCompleteBox(byteArr, 0x75757575)).toEqual(-1);

Check failure on line 25 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value

Check failure on line 25 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value

Check failure on line 25 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe member access .toEqual on an `any` value
expect(findCompleteBox(byteArr, 0x99999999)).toEqual(-1);

Check failure on line 26 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value

Check failure on line 26 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value

Check failure on line 26 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe member access .toEqual on an `any` value
expect(findCompleteBox(byteArr, 0x99999)).toEqual(-1);

Check failure on line 27 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value

Check failure on line 27 in src/transports/utils/__tests__/find_complete_box.test.ts

View workflow job for this annotation

GitHub Actions / typechecking_and_linting (20.x)

Unsafe call of an `any` typed value
});

it("should return its index if the box is found", () => {
const byteArr = new Uint8Array([
0, 0, 0, 9, 0x64, 0x67, 0x32, 0x55, 4, 0, 0, 0, 10, 0x88, 0x68, 0x47, 0x53, 12, 88,
]);

expect(findCompleteBox(byteArr, 0x64673255)).toEqual(0);
expect(findCompleteBox(byteArr, 0x88684753)).toEqual(9);
});

it("should not return a box if it is incomplete", () => {
const byteArr = new Uint8Array([
0, 0, 0, 9, 0x64, 0x67, 0x32, 0x55, 4, 0, 0, 0, 10, 0x88, 0x68, 0x47, 0x53, 12,
]);

expect(findCompleteBox(byteArr, 0x88684753)).toEqual(-1);
});

it("should return a box if a later one is incomplete", () => {
const byteArr = new Uint8Array([
0, 0, 0, 9, 0x64, 0x67, 0x32, 0x55, 4, 0, 0, 0, 12, 0x58, 0x58, 0x57, 0x53, 15, 99,
87, 77, 0, 0, 0, 10, 0x88, 0x68, 0x47, 0x53, 12,
]);

expect(findCompleteBox(byteArr, 0x64673255)).toEqual(0);
expect(findCompleteBox(byteArr, 0x58585753)).toEqual(9);
expect(findCompleteBox(byteArr, 0x88684753)).toEqual(-1);
});
});
58 changes: 58 additions & 0 deletions src/transports/utils/find_complete_box.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* 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 { be4toi, be8toi } from "../../utils/byte_parsing";

/**
* Find the offset for the first declaration of the given box in an isobmff.
* Returns -1 if not found or if incomplete.
*
* This function does not throw or log in case of partial segments.
* @param {Uint8Array} buf - the isobmff
* @param {Number} wantedName
* @returns {Number} - Offset where the box begins. -1 if not found.
*/
export default function findCompleteBox(buf: Uint8Array, wantedName: number): number {
const len = buf.length;
let i = 0;
while (i + 8 <= len) {
let size = be4toi(buf, i);

if (size === 0) {
size = len - i;
} else if (size === 1) {
if (i + 16 > len) {
return -1;
}
size = be8toi(buf, i + 8);
}

if (isNaN(size) || size <= 0) {
// should not happen
return -1;
}

const name = be4toi(buf, i + 4);
if (name === wantedName) {
if (i + size <= len) {
return i;
}
return -1;
}
i += size;
}
return -1;
}

0 comments on commit c0c5430

Please sign in to comment.