From 15c7a8acd1eb27de553fa3a9e52a3f6e1b4ad243 Mon Sep 17 00:00:00 2001 From: Florent Date: Fri, 5 Apr 2024 14:39:58 +0200 Subject: [PATCH 1/4] fix: safari support audio lang "und" in audioTrack In HLS with Safari, if the lang "und" (undetermined) is provided in the HLS manifest, safari will set `audioTrack.language` to `""` because "und" does not seems to be recognised as a lang for safari. This commit patch this behavior by changing lang if the lang is "" and label is "und" --- .../media_element_track_choice_manager.ts | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/core/api/tracks_management/media_element_track_choice_manager.ts b/src/core/api/tracks_management/media_element_track_choice_manager.ts index 199c83e524..c09c79dc0c 100644 --- a/src/core/api/tracks_management/media_element_track_choice_manager.ts +++ b/src/core/api/tracks_management/media_element_track_choice_manager.ts @@ -91,24 +91,28 @@ function createAudioTracks( const languagesOccurences: Partial> = {}; for (let i = 0; i < audioTracks.length; i++) { const audioTrack = audioTracks[i]; - const language = audioTrack.language === "" ? "nolang" : - audioTrack.language; + /** + * "und" is a special value in ISO 639-3 that stands for "undetermined language". + * If a track is announced in the manifest with lang "und", Safari will + * incorrectly set `audioTrack.language` with an empty string instead of "und". + * To patch this, check if the label is "und". + */ + const language = audioTrack.language || (audioTrack.label === "und" ? "und" : ""); const occurences = languagesOccurences[language] ?? 1; - const id = "gen_audio_" + - language + - "_" + - occurences.toString(); + const id = "gen_audio_" + (language || "nolang") + "_" + occurences.toString(); languagesOccurences[language] = occurences + 1; - const track = { language: audioTrack.language, - id, - normalized: normalizeLanguage(audioTrack.language), - audioDescription: audioTrack.kind === "descriptions" || - // Safari seem to prefer the non-standard singular - // version, funnily enough - audioTrack.kind === "description", - representations: [] as Representation[] }; - newAudioTracks.push({ track, - nativeTrack: audioTrack }); + const track = { + language, + id, + normalized: normalizeLanguage(language), + audioDescription: + audioTrack.kind === "descriptions" || + // Safari seem to prefer the non-standard singular + // version, funnily enough + audioTrack.kind === "description", + representations: [] as Representation[], + }; + newAudioTracks.push({ track, nativeTrack: audioTrack }); } return newAudioTracks; } @@ -126,30 +130,31 @@ function createTextTracks( const languagesOccurences: Partial> = {}; for (let i = 0; i < textTracks.length; i++) { const textTrack = textTracks[i]; - const language = textTrack.language === "" ? "nolang" : - textTrack.language; + /** + * "und" is a special value in ISO 639-3 that stands for "undetermined language". + * If a track is announced in the manifest with lang "und", Safari will + * incorrectly set `textTrack.language` with an empty string instead of "und". + * To patch this, check if the label is "und". + */ + const language = textTrack.language || (textTrack.label === "und" ? "und" : ""); const occurences = languagesOccurences[language] ?? 1; - const id = "gen_text_" + - language + - "_" + - occurences.toString(); + const id = "gen_text_" + (language || "nolang") + "_" + occurences.toString(); languagesOccurences[language] = occurences + 1; // Safari seems to be indicating that the subtitles track is a forced // subtitles track by setting the `kind` attribute to `"forced"`. // As of now (2023-04-04), this is not standard. // @see https://github.com/whatwg/html/issues/4472 - const forced = (textTrack.kind as string) === "forced" ? - true : - undefined; - const track = { language: textTrack.language, - forced, - label: textTrack.label, - id, - normalized: normalizeLanguage(textTrack.language), - closedCaption: textTrack.kind === "captions" }; - newTextTracks.push({ track, - nativeTrack: textTrack }); + const forced = (textTrack.kind as string) === "forced" ? true : undefined; + const track = { + language, + forced, + label: textTrack.label, + id, + normalized: normalizeLanguage(language), + closedCaption: textTrack.kind === "captions", + }; + newTextTracks.push({ track, nativeTrack: textTrack }); } return newTextTracks; } @@ -168,13 +173,15 @@ function createVideoTracks( const languagesOccurences: Partial> = {}; for (let i = 0; i < videoTracks.length; i++) { const videoTrack = videoTracks[i]; - const language = videoTrack.language === "" ? "nolang" : - videoTrack.language; + /** + * "und" is a special value in ISO 639-3 that stands for "undetermined language". + * If a track is announced in the manifest with lang "und", Safari will + * incorrectly set `videoTrack.language` with an empty string instead of "und". + * To patch this, check if the label is "und". + */ + const language = videoTrack.language || (videoTrack.label === "und" ? "und" : ""); const occurences = languagesOccurences[language] ?? 1; - const id = "gen_video_" + - language + - "_" + - occurences.toString(); + const id = "gen_video_" + (language || "nolang") + "_" + occurences.toString(); languagesOccurences[language] = occurences + 1; newVideoTracks.push({ track: { id, representations: [] as Representation[] }, From 2da31b6da05ad004f5de7641148759452834ba90 Mon Sep 17 00:00:00 2001 From: Florent Date: Tue, 9 Apr 2024 11:31:51 +0200 Subject: [PATCH 2/4] fix Revert "fix: safari support audio lang "und" in audioTrack" This reverts commit 7bed259f009c22b7b2422debb6b20de84cdbfaa4. --- .../media_element_track_choice_manager.ts | 38 +++++-------------- src/utils/languages/normalize.ts | 5 ++- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/core/api/tracks_management/media_element_track_choice_manager.ts b/src/core/api/tracks_management/media_element_track_choice_manager.ts index c09c79dc0c..9dd9909e3f 100644 --- a/src/core/api/tracks_management/media_element_track_choice_manager.ts +++ b/src/core/api/tracks_management/media_element_track_choice_manager.ts @@ -91,20 +91,14 @@ function createAudioTracks( const languagesOccurences: Partial> = {}; for (let i = 0; i < audioTracks.length; i++) { const audioTrack = audioTracks[i]; - /** - * "und" is a special value in ISO 639-3 that stands for "undetermined language". - * If a track is announced in the manifest with lang "und", Safari will - * incorrectly set `audioTrack.language` with an empty string instead of "und". - * To patch this, check if the label is "und". - */ - const language = audioTrack.language || (audioTrack.label === "und" ? "und" : ""); + const language = audioTrack.language === "" ? "nolang" : audioTrack.language; const occurences = languagesOccurences[language] ?? 1; - const id = "gen_audio_" + (language || "nolang") + "_" + occurences.toString(); + const id = "gen_audio_" + language + "_" + occurences.toString(); languagesOccurences[language] = occurences + 1; const track = { - language, + language: audioTrack.language, id, - normalized: normalizeLanguage(language), + normalized: normalizeLanguage(audioTrack.language), audioDescription: audioTrack.kind === "descriptions" || // Safari seem to prefer the non-standard singular @@ -130,15 +124,9 @@ function createTextTracks( const languagesOccurences: Partial> = {}; for (let i = 0; i < textTracks.length; i++) { const textTrack = textTracks[i]; - /** - * "und" is a special value in ISO 639-3 that stands for "undetermined language". - * If a track is announced in the manifest with lang "und", Safari will - * incorrectly set `textTrack.language` with an empty string instead of "und". - * To patch this, check if the label is "und". - */ - const language = textTrack.language || (textTrack.label === "und" ? "und" : ""); + const language = textTrack.language === "" ? "nolang" : textTrack.language; const occurences = languagesOccurences[language] ?? 1; - const id = "gen_text_" + (language || "nolang") + "_" + occurences.toString(); + const id = "gen_text_" + language + "_" + occurences.toString(); languagesOccurences[language] = occurences + 1; // Safari seems to be indicating that the subtitles track is a forced @@ -147,11 +135,11 @@ function createTextTracks( // @see https://github.com/whatwg/html/issues/4472 const forced = (textTrack.kind as string) === "forced" ? true : undefined; const track = { - language, + language: textTrack.language, forced, label: textTrack.label, id, - normalized: normalizeLanguage(language), + normalized: normalizeLanguage(textTrack.language), closedCaption: textTrack.kind === "captions", }; newTextTracks.push({ track, nativeTrack: textTrack }); @@ -173,15 +161,9 @@ function createVideoTracks( const languagesOccurences: Partial> = {}; for (let i = 0; i < videoTracks.length; i++) { const videoTrack = videoTracks[i]; - /** - * "und" is a special value in ISO 639-3 that stands for "undetermined language". - * If a track is announced in the manifest with lang "und", Safari will - * incorrectly set `videoTrack.language` with an empty string instead of "und". - * To patch this, check if the label is "und". - */ - const language = videoTrack.language || (videoTrack.label === "und" ? "und" : ""); + const language = videoTrack.language === "" ? "nolang" : videoTrack.language; const occurences = languagesOccurences[language] ?? 1; - const id = "gen_video_" + (language || "nolang") + "_" + occurences.toString(); + const id = "gen_video_" + language + "_" + occurences.toString(); languagesOccurences[language] = occurences + 1; newVideoTracks.push({ track: { id, representations: [] as Representation[] }, diff --git a/src/utils/languages/normalize.ts b/src/utils/languages/normalize.ts index fb4f06259c..ff85c22ef7 100644 --- a/src/utils/languages/normalize.ts +++ b/src/utils/languages/normalize.ts @@ -47,7 +47,10 @@ interface INormalizedTextTrackObject extends IMinimalTextTrackObject { */ function normalizeLanguage(_language : string) : string { if (isNullOrUndefined(_language) || _language === "") { - return ""; + /** + * "und" is a special value in ISO 639-3 that stands for "undetermined language". + */ + return "und"; } const fields = ("" + _language).toLowerCase().split("-"); const base = fields[0]; From bd44659ec6f31b09807764877e5bfa477cfc5083 Mon Sep 17 00:00:00 2001 From: Florent Date: Tue, 9 Apr 2024 12:11:36 +0200 Subject: [PATCH 3/4] update Unit tests --- src/utils/languages/__tests__/normalize.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/utils/languages/__tests__/normalize.test.ts b/src/utils/languages/__tests__/normalize.test.ts index bd8a8ccc0b..521888b7bf 100644 --- a/src/utils/languages/__tests__/normalize.test.ts +++ b/src/utils/languages/__tests__/normalize.test.ts @@ -20,8 +20,8 @@ import normalizeLanguage, { } from "../normalize"; describe("utils - normalizeLanguage", () => { - it("should translate an empty string to an empty string", () => { - expect(normalizeLanguage("")).toBe(""); + it("should translate an empty string to an undertemined code", () => { + expect(normalizeLanguage("")).toBe("und"); }); it("should translate ISO639-1 to ISO639-3", () => { @@ -58,9 +58,11 @@ describe("utils - normalizeAudioTrack", () => { }); it("should format a normalized audio track for an empty string", () => { - expect(normalizeAudioTrack("")).toEqual({ language: "", - audioDescription: false, - normalized: "" }); + expect(normalizeAudioTrack("")).toEqual({ + language: "", + audioDescription: false, + normalized: "und", + }); }); it("should format a normalized audio track for a given language", () => { @@ -194,7 +196,7 @@ describe("utils - normalizeTextTrack", () => { expect(normalizeTextTrack("")).toEqual({ language: "", closedCaption: false, - normalized: "", + normalized: "und", }); }); From c5c5b52705d33996b5e97f7a2bd683c61c1d6890 Mon Sep 17 00:00:00 2001 From: Florent Date: Thu, 11 Apr 2024 10:54:22 +0200 Subject: [PATCH 4/4] typo --- src/utils/languages/__tests__/normalize.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/languages/__tests__/normalize.test.ts b/src/utils/languages/__tests__/normalize.test.ts index 521888b7bf..99be9d8114 100644 --- a/src/utils/languages/__tests__/normalize.test.ts +++ b/src/utils/languages/__tests__/normalize.test.ts @@ -20,7 +20,7 @@ import normalizeLanguage, { } from "../normalize"; describe("utils - normalizeLanguage", () => { - it("should translate an empty string to an undertemined code", () => { + it("should translate an empty string to an undetermined code", () => { expect(normalizeLanguage("")).toBe("und"); });