From 790bcc37e88d8b5c3e9dd31648c94061b9045c76 Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Thu, 22 Jun 2023 14:18:04 +0200 Subject: [PATCH 1/2] Compat: wait for a readyState of before considering the content loaded on the PS5 --- src/compat/index.ts | 2 ++ src/compat/should_wait_for_have_enough_data.ts | 17 +++++++++++++++++ src/core/init/utils/get_loaded_reference.ts | 5 ++++- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/compat/should_wait_for_have_enough_data.ts diff --git a/src/compat/index.ts b/src/compat/index.ts index 96f805402c..09e9f619af 100644 --- a/src/compat/index.ts +++ b/src/compat/index.ts @@ -61,6 +61,7 @@ import shouldRenewMediaKeySystemAccess from "./should_renew_media_key_system_acc import shouldUnsetMediaKeys from "./should_unset_media_keys"; import shouldValidateMetadata from "./should_validate_metadata"; import shouldWaitForDataBeforeLoaded from "./should_wait_for_data_before_loaded"; +import shouldWaitForHaveEnoughData from "./should_wait_for_have_enough_data"; // TODO To remove. This seems to be the only side-effect done on import, which // we would prefer to disallow (both for the understandability of the code and @@ -105,5 +106,6 @@ export { shouldUnsetMediaKeys, shouldValidateMetadata, shouldWaitForDataBeforeLoaded, + shouldWaitForHaveEnoughData, tryToChangeSourceBufferType, }; diff --git a/src/compat/should_wait_for_have_enough_data.ts b/src/compat/should_wait_for_have_enough_data.ts new file mode 100644 index 0000000000..e5919ba223 --- /dev/null +++ b/src/compat/should_wait_for_have_enough_data.ts @@ -0,0 +1,17 @@ +import { isPlayStation5 } from "./browser_detection"; + +/** + * An `HTMLMediaElement`'s readyState allows the browser to communicate whether + * it can play a content reliably. + * Usually, we may consider that a `HAVE_FUTURE_DATA` (readyState `3`) or even + * a `HAVE_CURRENT_DATA` (readyState `2`) is enough to begin playing the content + * and consider it as loaded. + * + * However some devices wrongly anounce those readyStates before being actually + * able to decode the content. For those devices we wait for the + * `HAVE_ENOUGH_DATA` readyState before considering the content as loaded. + * @returns {boolean} + */ +export default function shouldWaitForHaveEnoughData() : boolean { + return isPlayStation5; +} diff --git a/src/core/init/utils/get_loaded_reference.ts b/src/core/init/utils/get_loaded_reference.ts index f800e4da53..212747541c 100644 --- a/src/core/init/utils/get_loaded_reference.ts +++ b/src/core/init/utils/get_loaded_reference.ts @@ -18,6 +18,7 @@ import { shouldValidateMetadata, shouldWaitForDataBeforeLoaded, + shouldWaitForHaveEnoughData, } from "../../../compat"; import createSharedReference, { IReadOnlySharedReference, @@ -64,7 +65,9 @@ export default function getLoadedReference( } } - if (observation.readyState >= 3 && observation.currentRange !== null) { + const minReadyState = shouldWaitForHaveEnoughData() ? 4 : + 3; + if (observation.readyState >= minReadyState && observation.currentRange !== null) { if (!shouldValidateMetadata() || mediaElement.duration > 0) { isLoaded.setValue(true); listenCanceller.cancel(); From c2d53c62b3a4c40585a30d40555f3f5c58472d0d Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Wed, 28 Jun 2023 18:17:54 +0200 Subject: [PATCH 2/2] Add unit tests for shouldWaitForHaveEnoughData --- .../should_wait_for_have_enough_data.test.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/compat/__tests__/should_wait_for_have_enough_data.test.ts diff --git a/src/compat/__tests__/should_wait_for_have_enough_data.test.ts b/src/compat/__tests__/should_wait_for_have_enough_data.test.ts new file mode 100644 index 0000000000..32713ed962 --- /dev/null +++ b/src/compat/__tests__/should_wait_for_have_enough_data.test.ts @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ + +describe("compat - shouldWaitForHaveEnoughData", () => { + beforeEach(() => { + jest.resetModules(); + }); + + it("should return false if we are not on the Playstation 5", () => { + jest.mock("../browser_detection", () => { + return { + __esModule: true as const, + isPlayStation5: false, + }; + }); + const shouldWaitForHaveEnoughData = + jest.requireActual("../should_wait_for_have_enough_data"); + expect(shouldWaitForHaveEnoughData.default()).toBe(false); + }); + + it("should return true if we are on the Playstation 5", () => { + jest.mock("../browser_detection", () => { + return { + __esModule: true as const, + isPlayStation5: true, + }; + }); + const shouldWaitForHaveEnoughData = + jest.requireActual("../should_wait_for_have_enough_data"); + expect(shouldWaitForHaveEnoughData.default()).toBe(true); + }); +});