@moq/watch 0.2.13 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +10 -9
  2. package/audio/source.d.ts.map +1 -1
  3. package/broadcast-jtLUfuyL.js +4291 -0
  4. package/broadcast-jtLUfuyL.js.map +1 -0
  5. package/broadcast.d.ts.map +1 -1
  6. package/dom-Yz3UT5ap.js +29 -0
  7. package/dom-Yz3UT5ap.js.map +1 -0
  8. package/element.js +162 -178
  9. package/element.js.map +1 -1
  10. package/index.d.ts +1 -3
  11. package/index.d.ts.map +1 -1
  12. package/index.js +5 -254
  13. package/libav-opus-af-CzuaKpJb.js +252 -0
  14. package/libav-opus-af-CzuaKpJb.js.map +1 -0
  15. package/main-bFFHfuX4.js +1999 -0
  16. package/main-bFFHfuX4.js.map +1 -0
  17. package/package.json +5 -4
  18. package/support/element.js +122 -172
  19. package/support/element.js.map +1 -1
  20. package/support/index.js +52 -53
  21. package/support/index.js.map +1 -1
  22. package/ui/element.js +335 -359
  23. package/ui/element.js.map +1 -1
  24. package/video/source.d.ts.map +1 -1
  25. package/broadcast-CLjMphZS.js +0 -5000
  26. package/broadcast-CLjMphZS.js.map +0 -1
  27. package/chat/index.d.ts +0 -17
  28. package/chat/index.d.ts.map +0 -1
  29. package/chat/message.d.ts +0 -16
  30. package/chat/message.d.ts.map +0 -1
  31. package/chat/typing.d.ts +0 -16
  32. package/chat/typing.d.ts.map +0 -1
  33. package/dom-BsFrLb_F.js +0 -35
  34. package/dom-BsFrLb_F.js.map +0 -1
  35. package/index.js.map +0 -1
  36. package/libav-opus-af-BlMWboA7.js +0 -368
  37. package/libav-opus-af-BlMWboA7.js.map +0 -1
  38. package/location/index.d.ts +0 -17
  39. package/location/index.d.ts.map +0 -1
  40. package/location/peers.d.ts +0 -16
  41. package/location/peers.d.ts.map +0 -1
  42. package/location/window.d.ts +0 -17
  43. package/location/window.d.ts.map +0 -1
  44. package/main-DGBFe0O7.js +0 -2301
  45. package/main-DGBFe0O7.js.map +0 -1
  46. package/preview.d.ts +0 -23
  47. package/preview.d.ts.map +0 -1
  48. package/user.d.ts +0 -17
  49. package/user.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@moq/watch",
3
3
  "type": "module",
4
- "version": "0.2.13",
4
+ "version": "0.2.15",
5
5
  "description": "Watch Media over QUIC broadcasts",
6
6
  "license": "(MIT OR Apache-2.0)",
7
7
  "repository": "github:moq-dev/moq",
@@ -33,9 +33,10 @@
33
33
  "./support/element.js"
34
34
  ],
35
35
  "dependencies": {
36
- "@moq/hang": "^0.2.7",
37
- "@moq/net": "^0.1.2",
36
+ "@moq/hang": "^0.2.8",
37
+ "@moq/json": "^0.0.2",
38
+ "@moq/net": "^0.1.3",
38
39
  "@moq/msf": "^0.1.1",
39
- "@moq/signals": "^0.1.7"
40
+ "@moq/signals": "^0.1.8"
40
41
  }
41
42
  }
@@ -1,173 +1,123 @@
1
- import { Signal as c, Effect as v } from "@moq/signals";
2
- import { c as a } from "../dom-BsFrLb_F.js";
3
- import { isSupported as m } from "./index.js";
4
- const h = navigator.userAgent.toLowerCase().includes("firefox"), C = ["show", "details"];
5
- class b extends HTMLElement {
6
- #i = new c("warning");
7
- #e = new c(!1);
8
- #n = new c(void 0);
9
- #o = new c(!1);
10
- #t;
11
- static observedAttributes = C;
12
- constructor() {
13
- super(), m().then((e) => this.#n.set(e)).catch((e) => console.error("Failed to detect watch support:", e));
14
- }
15
- connectedCallback() {
16
- this.#t = new v(), this.#t.run(this.#d.bind(this));
17
- }
18
- disconnectedCallback() {
19
- this.#t?.close(), this.#t = void 0;
20
- }
21
- attributeChangedCallback(e, t, s) {
22
- if (e === "show") {
23
- const i = s ?? "warning";
24
- if (i === "always" || i === "warning" || i === "error" || i === "never")
25
- this.show = i;
26
- else
27
- throw new Error(`Invalid show: ${i}`);
28
- } else if (e === "details")
29
- this.details = s !== null;
30
- else {
31
- const i = e;
32
- throw new Error(`Invalid attribute: ${i}`);
33
- }
34
- }
35
- get show() {
36
- return this.#i.peek();
37
- }
38
- set show(e) {
39
- this.#i.set(e);
40
- }
41
- get details() {
42
- return this.#e.peek();
43
- }
44
- set details(e) {
45
- this.#e.set(e);
46
- }
47
- #r(e) {
48
- return e.webtransport === "none" || !e.audio.decoding || !e.video.decoding || !e.audio.render || !e.video.render || !Object.values(e.audio.decoding).some((t) => t === !0 || t === "full" || t === "partial") || !Object.values(e.video.decoding).some((t) => t.software || t.hardware) ? "none" : !Object.values(e.audio.decoding).every((t) => t === !0 || t === "full") || !Object.values(e.video.decoding).every((t) => t.software || t.hardware) ? "partial" : "full";
49
- }
50
- #d(e) {
51
- const t = e.get(this.#n);
52
- if (!t || e.get(this.#o)) return;
53
- const i = e.get(this.#i);
54
- if (i === "never") return;
55
- const r = this.#r(t);
56
- if (i === "warning" && r === "full" || i === "error" && r !== "none") return;
57
- const n = a("div", {
58
- style: {
59
- margin: "0 auto",
60
- maxWidth: "28rem",
61
- padding: "1rem"
62
- }
63
- });
64
- this.appendChild(n), e.cleanup(() => this.removeChild(n)), this.#a(n, r, e), e.get(this.#e) && this.#s(n, t, e);
65
- }
66
- #a(e, t, s) {
67
- const i = a("div", {
68
- style: {
69
- display: "flex",
70
- flexDirection: "row",
71
- gap: "1rem",
72
- flexWrap: "wrap",
73
- justifyContent: "space-between",
74
- alignItems: "center"
75
- }
76
- }), r = a("div", {
77
- style: { fontWeight: "bold" }
78
- });
79
- t === "full" ? r.textContent = "🟢 Full Browser Support" : t === "partial" ? r.textContent = "🟡 Partial Browser Support" : t === "none" && (r.textContent = "🔴 No Browser Support");
80
- const n = a("button", {
81
- type: "button",
82
- style: { fontSize: "14px" }
83
- });
84
- s.event(n, "click", () => {
85
- this.#e.update((o) => !o);
86
- }), s.run((o) => {
87
- n.textContent = o.get(this.#e) ? "Details ➖" : "Details ➕";
88
- });
89
- const l = a(
90
- "button",
91
- {
92
- type: "button",
93
- style: { fontSize: "14px" }
94
- },
95
- "Close "
96
- );
97
- s.event(l, "click", () => {
98
- this.#o.set(!0);
99
- }), i.appendChild(r), i.appendChild(n), i.appendChild(l), e.appendChild(i), s.cleanup(() => e.removeChild(i));
100
- }
101
- #s(e, t, s) {
102
- const i = a("div", {
103
- style: {
104
- display: "grid",
105
- gridTemplateColumns: "1fr 1fr 1fr",
106
- columnGap: "0.5rem",
107
- rowGap: "0.2rem",
108
- backgroundColor: "rgba(0, 0, 0, 0.6)",
109
- borderRadius: "0.5rem",
110
- padding: "1rem",
111
- fontSize: "0.875rem"
112
- }
113
- }), r = (d) => d ? "🟢 Yes" : "🔴 No", n = (d) => d?.hardware ? "🟢 Hardware" : d?.software ? `🟡 Software${h ? "*" : ""}` : "🔴 No", l = (d) => d === "full" ? "🟢 Full" : d === "partial" ? "🟡 Polyfill" : "🔴 None", o = (d, u, g) => {
114
- const w = a(
115
- "div",
116
- {
117
- style: {
118
- gridColumnStart: "1",
119
- fontWeight: "bold",
120
- textAlign: "right"
121
- }
122
- },
123
- d
124
- ), p = a(
125
- "div",
126
- {
127
- style: {
128
- gridColumnStart: "2",
129
- textAlign: "center"
130
- }
131
- },
132
- u
133
- ), f = a(
134
- "div",
135
- {
136
- style: { gridColumnStart: "3" }
137
- },
138
- g
139
- );
140
- i.appendChild(w), i.appendChild(p), i.appendChild(f);
141
- };
142
- if (o("WebTransport", "", l(t.webtransport)), o("Rendering", "Audio", r(t.audio.render)), o("", "Video", r(t.video.render)), o("Decoding", "Opus", l(t.audio.decoding.opus)), o("", "AAC", r(t.audio.decoding.aac)), o("", "AV1", n(t.video.decoding?.av1)), o("", "H.265", n(t.video.decoding?.h265)), o("", "H.264", n(t.video.decoding?.h264)), o("", "VP9", n(t.video.decoding?.vp9)), o("", "VP8", n(t.video.decoding?.vp8)), h) {
143
- const d = a(
144
- "div",
145
- {
146
- style: {
147
- gridColumnStart: "1",
148
- gridColumnEnd: "4",
149
- textAlign: "center",
150
- fontSize: "0.875rem",
151
- fontStyle: "italic"
152
- }
153
- },
154
- "Hardware acceleration is ",
155
- a(
156
- "a",
157
- {
158
- href: "https://github.com/w3c/webcodecs/issues/896"
159
- },
160
- "undetectable"
161
- ),
162
- " on Firefox."
163
- );
164
- i.appendChild(d);
165
- }
166
- e.appendChild(i), s.cleanup(() => e.removeChild(i));
167
- }
168
- }
169
- customElements.define("moq-watch-support", b);
170
- export {
171
- b as default
1
+ import { t as e } from "../dom-Yz3UT5ap.js";
2
+ import { isSupported as t } from "./index.js";
3
+ import { Effect as n, Signal as r } from "@moq/signals";
4
+ //#region src/support/element.ts
5
+ var i = navigator.userAgent.toLowerCase().includes("firefox"), a = ["show", "details"], o = class extends HTMLElement {
6
+ #e = new r("warning");
7
+ #t = new r(!1);
8
+ #n = new r(void 0);
9
+ #r = new r(!1);
10
+ #i;
11
+ static observedAttributes = a;
12
+ constructor() {
13
+ super(), t().then((e) => this.#n.set(e)).catch((e) => console.error("Failed to detect watch support:", e));
14
+ }
15
+ connectedCallback() {
16
+ this.#i = new n(), this.#i.run(this.#o.bind(this));
17
+ }
18
+ disconnectedCallback() {
19
+ this.#i?.close(), this.#i = void 0;
20
+ }
21
+ attributeChangedCallback(e, t, n) {
22
+ if (e === "show") {
23
+ let e = n ?? "warning";
24
+ if (e === "always" || e === "warning" || e === "error" || e === "never") this.show = e;
25
+ else throw Error(`Invalid show: ${e}`);
26
+ } else if (e === "details") this.details = n !== null;
27
+ else throw Error(`Invalid attribute: ${e}`);
28
+ }
29
+ get show() {
30
+ return this.#e.peek();
31
+ }
32
+ set show(e) {
33
+ this.#e.set(e);
34
+ }
35
+ get details() {
36
+ return this.#t.peek();
37
+ }
38
+ set details(e) {
39
+ this.#t.set(e);
40
+ }
41
+ #a(e) {
42
+ return e.webtransport === "none" || !e.audio.decoding || !e.video.decoding || !e.audio.render || !e.video.render || !Object.values(e.audio.decoding).some((e) => e === !0 || e === "full" || e === "partial") || !Object.values(e.video.decoding).some((e) => e.software || e.hardware) ? "none" : !Object.values(e.audio.decoding).every((e) => e === !0 || e === "full") || !Object.values(e.video.decoding).every((e) => e.software || e.hardware) ? "partial" : "full";
43
+ }
44
+ #o(t) {
45
+ let n = t.get(this.#n);
46
+ if (!n || t.get(this.#r)) return;
47
+ let r = t.get(this.#e);
48
+ if (r === "never") return;
49
+ let i = this.#a(n);
50
+ if (r === "warning" && i === "full" || r === "error" && i !== "none") return;
51
+ let a = e("div", { style: {
52
+ margin: "0 auto",
53
+ maxWidth: "28rem",
54
+ padding: "1rem"
55
+ } });
56
+ this.appendChild(a), t.cleanup(() => this.removeChild(a)), this.#s(a, i, t), t.get(this.#t) && this.#c(a, n, t);
57
+ }
58
+ #s(t, n, r) {
59
+ let i = e("div", { style: {
60
+ display: "flex",
61
+ flexDirection: "row",
62
+ gap: "1rem",
63
+ flexWrap: "wrap",
64
+ justifyContent: "space-between",
65
+ alignItems: "center"
66
+ } }), a = e("div", { style: { fontWeight: "bold" } });
67
+ n === "full" ? a.textContent = "🟢 Full Browser Support" : n === "partial" ? a.textContent = "🟡 Partial Browser Support" : n === "none" && (a.textContent = "🔴 No Browser Support");
68
+ let o = e("button", {
69
+ type: "button",
70
+ style: { fontSize: "14px" }
71
+ });
72
+ r.event(o, "click", () => {
73
+ this.#t.update((e) => !e);
74
+ }), r.run((e) => {
75
+ o.textContent = e.get(this.#t) ? "Details ➖" : "Details ➕";
76
+ });
77
+ let s = e("button", {
78
+ type: "button",
79
+ style: { fontSize: "14px" }
80
+ }, "Close ");
81
+ r.event(s, "click", () => {
82
+ this.#r.set(!0);
83
+ }), i.appendChild(a), i.appendChild(o), i.appendChild(s), t.appendChild(i), r.cleanup(() => t.removeChild(i));
84
+ }
85
+ #c(t, n, r) {
86
+ let a = e("div", { style: {
87
+ display: "grid",
88
+ gridTemplateColumns: "1fr 1fr 1fr",
89
+ columnGap: "0.5rem",
90
+ rowGap: "0.2rem",
91
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
92
+ borderRadius: "0.5rem",
93
+ padding: "1rem",
94
+ fontSize: "0.875rem"
95
+ } }), o = (e) => e ? "🟢 Yes" : "🔴 No", s = (e) => e?.hardware ? "🟢 Hardware" : e?.software ? `🟡 Software${i ? "*" : ""}` : "🔴 No", c = (e) => e === "full" ? "🟢 Full" : e === "partial" ? "🟡 Polyfill" : "🔴 None", l = (t, n, r) => {
96
+ let i = e("div", { style: {
97
+ gridColumnStart: "1",
98
+ fontWeight: "bold",
99
+ textAlign: "right"
100
+ } }, t), o = e("div", { style: {
101
+ gridColumnStart: "2",
102
+ textAlign: "center"
103
+ } }, n), s = e("div", { style: { gridColumnStart: "3" } }, r);
104
+ a.appendChild(i), a.appendChild(o), a.appendChild(s);
105
+ };
106
+ if (l("WebTransport", "", c(n.webtransport)), l("Rendering", "Audio", o(n.audio.render)), l("", "Video", o(n.video.render)), l("Decoding", "Opus", c(n.audio.decoding.opus)), l("", "AAC", o(n.audio.decoding.aac)), l("", "AV1", s(n.video.decoding?.av1)), l("", "H.265", s(n.video.decoding?.h265)), l("", "H.264", s(n.video.decoding?.h264)), l("", "VP9", s(n.video.decoding?.vp9)), l("", "VP8", s(n.video.decoding?.vp8)), i) {
107
+ let t = e("div", { style: {
108
+ gridColumnStart: "1",
109
+ gridColumnEnd: "4",
110
+ textAlign: "center",
111
+ fontSize: "0.875rem",
112
+ fontStyle: "italic"
113
+ } }, "Hardware acceleration is ", e("a", { href: "https://github.com/w3c/webcodecs/issues/896" }, "undetectable"), " on Firefox.");
114
+ a.appendChild(t);
115
+ }
116
+ t.appendChild(a), r.cleanup(() => t.removeChild(a));
117
+ }
172
118
  };
173
- //# sourceMappingURL=element.js.map
119
+ customElements.define("moq-watch-support", o);
120
+ //#endregion
121
+ export { o as default };
122
+
123
+ //# sourceMappingURL=element.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"element.js","sources":["../../src/support/element.ts"],"sourcesContent":["import { Effect, Signal } from \"@moq/signals\";\nimport * as DOM from \"@moq/signals/dom\";\nimport { type Codec, type Full, isSupported, type Partial } from \"./\";\n\n// https://bugzilla.mozilla.org/show_bug.cgi?id=1967793\nconst isFirefox = navigator.userAgent.toLowerCase().includes(\"firefox\");\n\nconst OBSERVED = [\"show\", \"details\"] as const;\ntype Observed = (typeof OBSERVED)[number];\n\n// Whether to display the support banner.\n// - \"always\": Always display the banner.\n// - \"warning\": Display the banner if a required feature needs a polyfill/fallback.\n// - \"error\": Display the banner if a required feature is unsupported.\n// - \"never\": Never display the banner.\nexport type Show = \"always\" | \"warning\" | \"error\" | \"never\";\n\nexport default class MoqWatchSupport extends HTMLElement {\n\t#show = new Signal<Show>(\"warning\");\n\t#details = new Signal<boolean>(false);\n\t#support = new Signal<Full | undefined>(undefined);\n\t#close = new Signal<boolean>(false);\n\n\t#signals?: Effect;\n\n\tstatic observedAttributes = OBSERVED;\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tisSupported()\n\t\t\t.then((s) => this.#support.set(s))\n\t\t\t.catch((err) => console.error(\"Failed to detect watch support:\", err));\n\t}\n\n\tconnectedCallback() {\n\t\tthis.#signals = new Effect();\n\t\tthis.#signals.run(this.#render.bind(this));\n\t}\n\n\tdisconnectedCallback() {\n\t\tthis.#signals?.close();\n\t\tthis.#signals = undefined;\n\t}\n\n\tattributeChangedCallback(name: Observed, _oldValue: string | null, newValue: string | null) {\n\t\tif (name === \"show\") {\n\t\t\tconst show = newValue ?? \"warning\";\n\t\t\tif (show === \"always\" || show === \"warning\" || show === \"error\" || show === \"never\") {\n\t\t\t\tthis.show = show;\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Invalid show: ${show}`);\n\t\t\t}\n\t\t} else if (name === \"details\") {\n\t\t\tthis.details = newValue !== null;\n\t\t} else {\n\t\t\tconst exhaustive: never = name;\n\t\t\tthrow new Error(`Invalid attribute: ${exhaustive}`);\n\t\t}\n\t}\n\n\tget show(): Show {\n\t\treturn this.#show.peek();\n\t}\n\n\tset show(show: Show) {\n\t\tthis.#show.set(show);\n\t}\n\n\tget details(): boolean {\n\t\treturn this.#details.peek();\n\t}\n\n\tset details(details: boolean) {\n\t\tthis.#details.set(details);\n\t}\n\n\t#getSummary(support: Full): Partial {\n\t\tif (support.webtransport === \"none\") return \"none\";\n\n\t\tif (!support.audio.decoding || !support.video.decoding) return \"none\";\n\t\tif (!support.audio.render || !support.video.render) return \"none\";\n\n\t\tif (!Object.values(support.audio.decoding).some((v) => v === true || v === \"full\" || v === \"partial\"))\n\t\t\treturn \"none\";\n\t\tif (!Object.values(support.video.decoding).some((v) => v.software || v.hardware)) return \"none\";\n\n\t\tif (!Object.values(support.audio.decoding).every((v) => v === true || v === \"full\")) return \"partial\";\n\t\tif (!Object.values(support.video.decoding).every((v) => v.software || v.hardware)) return \"partial\";\n\n\t\treturn \"full\";\n\t}\n\n\t#render(effect: Effect) {\n\t\tconst support = effect.get(this.#support);\n\t\tif (!support) return;\n\n\t\tconst close = effect.get(this.#close);\n\t\tif (close) return;\n\n\t\tconst show = effect.get(this.#show);\n\t\tif (show === \"never\") return;\n\n\t\tconst summary = this.#getSummary(support);\n\n\t\t// Don't render the banner if we have full support and they only asked for warnings.\n\t\tif (show === \"warning\" && summary === \"full\") return;\n\n\t\t// Don't render the banner if we have at least partial support and they only asked for errors.\n\t\tif (show === \"error\" && summary !== \"none\") return;\n\n\t\tconst container = DOM.create(\"div\", {\n\t\t\tstyle: {\n\t\t\t\tmargin: \"0 auto\",\n\t\t\t\tmaxWidth: \"28rem\",\n\t\t\t\tpadding: \"1rem\",\n\t\t\t},\n\t\t});\n\n\t\tthis.appendChild(container);\n\t\teffect.cleanup(() => this.removeChild(container));\n\n\t\tthis.#renderHeader(container, summary, effect);\n\n\t\tif (effect.get(this.#details)) {\n\t\t\tthis.#renderDetails(container, support, effect);\n\t\t}\n\t}\n\n\t#renderHeader(parent: HTMLDivElement, summary: Partial, effect: Effect) {\n\t\tconst headerDiv = DOM.create(\"div\", {\n\t\t\tstyle: {\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"row\",\n\t\t\t\tgap: \"1rem\",\n\t\t\t\tflexWrap: \"wrap\",\n\t\t\t\tjustifyContent: \"space-between\",\n\t\t\t\talignItems: \"center\",\n\t\t\t},\n\t\t});\n\n\t\tconst statusDiv = DOM.create(\"div\", {\n\t\t\tstyle: { fontWeight: \"bold\" },\n\t\t});\n\n\t\tif (summary === \"full\") {\n\t\t\tstatusDiv.textContent = \"🟢 Full Browser Support\";\n\t\t} else if (summary === \"partial\") {\n\t\t\tstatusDiv.textContent = \"🟡 Partial Browser Support\";\n\t\t} else if (summary === \"none\") {\n\t\t\tstatusDiv.textContent = \"🔴 No Browser Support\";\n\t\t}\n\n\t\tconst detailsButton = DOM.create(\"button\", {\n\t\t\ttype: \"button\",\n\t\t\tstyle: { fontSize: \"14px\" },\n\t\t});\n\n\t\teffect.event(detailsButton, \"click\", () => {\n\t\t\tthis.#details.update((prev) => !prev);\n\t\t});\n\n\t\teffect.run((effect) => {\n\t\t\tdetailsButton.textContent = effect.get(this.#details) ? \"Details ➖\" : \"Details ➕\";\n\t\t});\n\n\t\tconst closeButton = DOM.create(\n\t\t\t\"button\",\n\t\t\t{\n\t\t\t\ttype: \"button\",\n\t\t\t\tstyle: { fontSize: \"14px\" },\n\t\t\t},\n\t\t\t\"Close ❌\",\n\t\t);\n\n\t\teffect.event(closeButton, \"click\", () => {\n\t\t\tthis.#close.set(true);\n\t\t});\n\n\t\theaderDiv.appendChild(statusDiv);\n\t\theaderDiv.appendChild(detailsButton);\n\t\theaderDiv.appendChild(closeButton);\n\n\t\tparent.appendChild(headerDiv);\n\t\teffect.cleanup(() => parent.removeChild(headerDiv));\n\t}\n\n\t#renderDetails(parent: HTMLDivElement, support: Full, effect: Effect) {\n\t\tconst container = DOM.create(\"div\", {\n\t\t\tstyle: {\n\t\t\t\tdisplay: \"grid\",\n\t\t\t\tgridTemplateColumns: \"1fr 1fr 1fr\",\n\t\t\t\tcolumnGap: \"0.5rem\",\n\t\t\t\trowGap: \"0.2rem\",\n\t\t\t\tbackgroundColor: \"rgba(0, 0, 0, 0.6)\",\n\t\t\t\tborderRadius: \"0.5rem\",\n\t\t\t\tpadding: \"1rem\",\n\t\t\t\tfontSize: \"0.875rem\",\n\t\t\t},\n\t\t});\n\n\t\tconst binary = (value: boolean | undefined) => (value ? \"🟢 Yes\" : \"🔴 No\");\n\t\tconst hardware = (codec: Codec | undefined) =>\n\t\t\tcodec?.hardware ? \"🟢 Hardware\" : codec?.software ? `🟡 Software${isFirefox ? \"*\" : \"\"}` : \"🔴 No\";\n\t\tconst partial = (value: Partial | undefined) =>\n\t\t\tvalue === \"full\" ? \"🟢 Full\" : value === \"partial\" ? \"🟡 Polyfill\" : \"🔴 None\";\n\n\t\tconst addRow = (label: string, col2: string, col3: string) => {\n\t\t\tconst labelDiv = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\tgridColumnStart: \"1\",\n\t\t\t\t\t\tfontWeight: \"bold\",\n\t\t\t\t\t\ttextAlign: \"right\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tlabel,\n\t\t\t);\n\n\t\t\tconst col2Div = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\tgridColumnStart: \"2\",\n\t\t\t\t\t\ttextAlign: \"center\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcol2,\n\t\t\t);\n\n\t\t\tconst col3Div = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: { gridColumnStart: \"3\" },\n\t\t\t\t},\n\t\t\t\tcol3,\n\t\t\t);\n\n\t\t\tcontainer.appendChild(labelDiv);\n\t\t\tcontainer.appendChild(col2Div);\n\t\t\tcontainer.appendChild(col3Div);\n\t\t};\n\n\t\taddRow(\"WebTransport\", \"\", partial(support.webtransport));\n\t\taddRow(\"Rendering\", \"Audio\", binary(support.audio.render));\n\t\taddRow(\"\", \"Video\", binary(support.video.render));\n\t\taddRow(\"Decoding\", \"Opus\", partial(support.audio.decoding.opus));\n\t\taddRow(\"\", \"AAC\", binary(support.audio.decoding.aac));\n\t\taddRow(\"\", \"AV1\", hardware(support.video.decoding?.av1));\n\t\taddRow(\"\", \"H.265\", hardware(support.video.decoding?.h265));\n\t\taddRow(\"\", \"H.264\", hardware(support.video.decoding?.h264));\n\t\taddRow(\"\", \"VP9\", hardware(support.video.decoding?.vp9));\n\t\taddRow(\"\", \"VP8\", hardware(support.video.decoding?.vp8));\n\n\t\tif (isFirefox) {\n\t\t\tconst noteDiv = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\tgridColumnStart: \"1\",\n\t\t\t\t\t\tgridColumnEnd: \"4\",\n\t\t\t\t\t\ttextAlign: \"center\",\n\t\t\t\t\t\tfontSize: \"0.875rem\",\n\t\t\t\t\t\tfontStyle: \"italic\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"Hardware acceleration is \",\n\t\t\t\tDOM.create(\n\t\t\t\t\t\"a\",\n\t\t\t\t\t{\n\t\t\t\t\t\thref: \"https://github.com/w3c/webcodecs/issues/896\",\n\t\t\t\t\t},\n\t\t\t\t\t\"undetectable\",\n\t\t\t\t),\n\t\t\t\t\" on Firefox.\",\n\t\t\t);\n\t\t\tcontainer.appendChild(noteDiv);\n\t\t}\n\n\t\tparent.appendChild(container);\n\t\teffect.cleanup(() => parent.removeChild(container));\n\t}\n}\n\ncustomElements.define(\"moq-watch-support\", MoqWatchSupport);\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t\"moq-watch-support\": MoqWatchSupport;\n\t}\n}\n"],"names":["isFirefox","OBSERVED","MoqWatchSupport","#show","Signal","#details","#support","#close","#signals","isSupported","s","err","Effect","#render","name","_oldValue","newValue","show","exhaustive","details","#getSummary","support","v","effect","summary","container","DOM.create","#renderHeader","#renderDetails","parent","headerDiv","statusDiv","detailsButton","prev","closeButton","binary","value","hardware","codec","partial","addRow","label","col2","col3","labelDiv","col2Div","col3Div","noteDiv"],"mappings":"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"}
1
+ {"version":3,"file":"element.js","names":["#support","#signals","#render","#show","#details","#close","#getSummary","#renderHeader","#renderDetails"],"sources":["../../src/support/element.ts"],"sourcesContent":["import { Effect, Signal } from \"@moq/signals\";\nimport * as DOM from \"@moq/signals/dom\";\nimport { type Codec, type Full, isSupported, type Partial } from \"./\";\n\n// https://bugzilla.mozilla.org/show_bug.cgi?id=1967793\nconst isFirefox = navigator.userAgent.toLowerCase().includes(\"firefox\");\n\nconst OBSERVED = [\"show\", \"details\"] as const;\ntype Observed = (typeof OBSERVED)[number];\n\n// Whether to display the support banner.\n// - \"always\": Always display the banner.\n// - \"warning\": Display the banner if a required feature needs a polyfill/fallback.\n// - \"error\": Display the banner if a required feature is unsupported.\n// - \"never\": Never display the banner.\nexport type Show = \"always\" | \"warning\" | \"error\" | \"never\";\n\nexport default class MoqWatchSupport extends HTMLElement {\n\t#show = new Signal<Show>(\"warning\");\n\t#details = new Signal<boolean>(false);\n\t#support = new Signal<Full | undefined>(undefined);\n\t#close = new Signal<boolean>(false);\n\n\t#signals?: Effect;\n\n\tstatic observedAttributes = OBSERVED;\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tisSupported()\n\t\t\t.then((s) => this.#support.set(s))\n\t\t\t.catch((err) => console.error(\"Failed to detect watch support:\", err));\n\t}\n\n\tconnectedCallback() {\n\t\tthis.#signals = new Effect();\n\t\tthis.#signals.run(this.#render.bind(this));\n\t}\n\n\tdisconnectedCallback() {\n\t\tthis.#signals?.close();\n\t\tthis.#signals = undefined;\n\t}\n\n\tattributeChangedCallback(name: Observed, _oldValue: string | null, newValue: string | null) {\n\t\tif (name === \"show\") {\n\t\t\tconst show = newValue ?? \"warning\";\n\t\t\tif (show === \"always\" || show === \"warning\" || show === \"error\" || show === \"never\") {\n\t\t\t\tthis.show = show;\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Invalid show: ${show}`);\n\t\t\t}\n\t\t} else if (name === \"details\") {\n\t\t\tthis.details = newValue !== null;\n\t\t} else {\n\t\t\tconst exhaustive: never = name;\n\t\t\tthrow new Error(`Invalid attribute: ${exhaustive}`);\n\t\t}\n\t}\n\n\tget show(): Show {\n\t\treturn this.#show.peek();\n\t}\n\n\tset show(show: Show) {\n\t\tthis.#show.set(show);\n\t}\n\n\tget details(): boolean {\n\t\treturn this.#details.peek();\n\t}\n\n\tset details(details: boolean) {\n\t\tthis.#details.set(details);\n\t}\n\n\t#getSummary(support: Full): Partial {\n\t\tif (support.webtransport === \"none\") return \"none\";\n\n\t\tif (!support.audio.decoding || !support.video.decoding) return \"none\";\n\t\tif (!support.audio.render || !support.video.render) return \"none\";\n\n\t\tif (!Object.values(support.audio.decoding).some((v) => v === true || v === \"full\" || v === \"partial\"))\n\t\t\treturn \"none\";\n\t\tif (!Object.values(support.video.decoding).some((v) => v.software || v.hardware)) return \"none\";\n\n\t\tif (!Object.values(support.audio.decoding).every((v) => v === true || v === \"full\")) return \"partial\";\n\t\tif (!Object.values(support.video.decoding).every((v) => v.software || v.hardware)) return \"partial\";\n\n\t\treturn \"full\";\n\t}\n\n\t#render(effect: Effect) {\n\t\tconst support = effect.get(this.#support);\n\t\tif (!support) return;\n\n\t\tconst close = effect.get(this.#close);\n\t\tif (close) return;\n\n\t\tconst show = effect.get(this.#show);\n\t\tif (show === \"never\") return;\n\n\t\tconst summary = this.#getSummary(support);\n\n\t\t// Don't render the banner if we have full support and they only asked for warnings.\n\t\tif (show === \"warning\" && summary === \"full\") return;\n\n\t\t// Don't render the banner if we have at least partial support and they only asked for errors.\n\t\tif (show === \"error\" && summary !== \"none\") return;\n\n\t\tconst container = DOM.create(\"div\", {\n\t\t\tstyle: {\n\t\t\t\tmargin: \"0 auto\",\n\t\t\t\tmaxWidth: \"28rem\",\n\t\t\t\tpadding: \"1rem\",\n\t\t\t},\n\t\t});\n\n\t\tthis.appendChild(container);\n\t\teffect.cleanup(() => this.removeChild(container));\n\n\t\tthis.#renderHeader(container, summary, effect);\n\n\t\tif (effect.get(this.#details)) {\n\t\t\tthis.#renderDetails(container, support, effect);\n\t\t}\n\t}\n\n\t#renderHeader(parent: HTMLDivElement, summary: Partial, effect: Effect) {\n\t\tconst headerDiv = DOM.create(\"div\", {\n\t\t\tstyle: {\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"row\",\n\t\t\t\tgap: \"1rem\",\n\t\t\t\tflexWrap: \"wrap\",\n\t\t\t\tjustifyContent: \"space-between\",\n\t\t\t\talignItems: \"center\",\n\t\t\t},\n\t\t});\n\n\t\tconst statusDiv = DOM.create(\"div\", {\n\t\t\tstyle: { fontWeight: \"bold\" },\n\t\t});\n\n\t\tif (summary === \"full\") {\n\t\t\tstatusDiv.textContent = \"🟢 Full Browser Support\";\n\t\t} else if (summary === \"partial\") {\n\t\t\tstatusDiv.textContent = \"🟡 Partial Browser Support\";\n\t\t} else if (summary === \"none\") {\n\t\t\tstatusDiv.textContent = \"🔴 No Browser Support\";\n\t\t}\n\n\t\tconst detailsButton = DOM.create(\"button\", {\n\t\t\ttype: \"button\",\n\t\t\tstyle: { fontSize: \"14px\" },\n\t\t});\n\n\t\teffect.event(detailsButton, \"click\", () => {\n\t\t\tthis.#details.update((prev) => !prev);\n\t\t});\n\n\t\teffect.run((effect) => {\n\t\t\tdetailsButton.textContent = effect.get(this.#details) ? \"Details ➖\" : \"Details ➕\";\n\t\t});\n\n\t\tconst closeButton = DOM.create(\n\t\t\t\"button\",\n\t\t\t{\n\t\t\t\ttype: \"button\",\n\t\t\t\tstyle: { fontSize: \"14px\" },\n\t\t\t},\n\t\t\t\"Close ❌\",\n\t\t);\n\n\t\teffect.event(closeButton, \"click\", () => {\n\t\t\tthis.#close.set(true);\n\t\t});\n\n\t\theaderDiv.appendChild(statusDiv);\n\t\theaderDiv.appendChild(detailsButton);\n\t\theaderDiv.appendChild(closeButton);\n\n\t\tparent.appendChild(headerDiv);\n\t\teffect.cleanup(() => parent.removeChild(headerDiv));\n\t}\n\n\t#renderDetails(parent: HTMLDivElement, support: Full, effect: Effect) {\n\t\tconst container = DOM.create(\"div\", {\n\t\t\tstyle: {\n\t\t\t\tdisplay: \"grid\",\n\t\t\t\tgridTemplateColumns: \"1fr 1fr 1fr\",\n\t\t\t\tcolumnGap: \"0.5rem\",\n\t\t\t\trowGap: \"0.2rem\",\n\t\t\t\tbackgroundColor: \"rgba(0, 0, 0, 0.6)\",\n\t\t\t\tborderRadius: \"0.5rem\",\n\t\t\t\tpadding: \"1rem\",\n\t\t\t\tfontSize: \"0.875rem\",\n\t\t\t},\n\t\t});\n\n\t\tconst binary = (value: boolean | undefined) => (value ? \"🟢 Yes\" : \"🔴 No\");\n\t\tconst hardware = (codec: Codec | undefined) =>\n\t\t\tcodec?.hardware ? \"🟢 Hardware\" : codec?.software ? `🟡 Software${isFirefox ? \"*\" : \"\"}` : \"🔴 No\";\n\t\tconst partial = (value: Partial | undefined) =>\n\t\t\tvalue === \"full\" ? \"🟢 Full\" : value === \"partial\" ? \"🟡 Polyfill\" : \"🔴 None\";\n\n\t\tconst addRow = (label: string, col2: string, col3: string) => {\n\t\t\tconst labelDiv = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\tgridColumnStart: \"1\",\n\t\t\t\t\t\tfontWeight: \"bold\",\n\t\t\t\t\t\ttextAlign: \"right\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tlabel,\n\t\t\t);\n\n\t\t\tconst col2Div = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\tgridColumnStart: \"2\",\n\t\t\t\t\t\ttextAlign: \"center\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcol2,\n\t\t\t);\n\n\t\t\tconst col3Div = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: { gridColumnStart: \"3\" },\n\t\t\t\t},\n\t\t\t\tcol3,\n\t\t\t);\n\n\t\t\tcontainer.appendChild(labelDiv);\n\t\t\tcontainer.appendChild(col2Div);\n\t\t\tcontainer.appendChild(col3Div);\n\t\t};\n\n\t\taddRow(\"WebTransport\", \"\", partial(support.webtransport));\n\t\taddRow(\"Rendering\", \"Audio\", binary(support.audio.render));\n\t\taddRow(\"\", \"Video\", binary(support.video.render));\n\t\taddRow(\"Decoding\", \"Opus\", partial(support.audio.decoding.opus));\n\t\taddRow(\"\", \"AAC\", binary(support.audio.decoding.aac));\n\t\taddRow(\"\", \"AV1\", hardware(support.video.decoding?.av1));\n\t\taddRow(\"\", \"H.265\", hardware(support.video.decoding?.h265));\n\t\taddRow(\"\", \"H.264\", hardware(support.video.decoding?.h264));\n\t\taddRow(\"\", \"VP9\", hardware(support.video.decoding?.vp9));\n\t\taddRow(\"\", \"VP8\", hardware(support.video.decoding?.vp8));\n\n\t\tif (isFirefox) {\n\t\t\tconst noteDiv = DOM.create(\n\t\t\t\t\"div\",\n\t\t\t\t{\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\tgridColumnStart: \"1\",\n\t\t\t\t\t\tgridColumnEnd: \"4\",\n\t\t\t\t\t\ttextAlign: \"center\",\n\t\t\t\t\t\tfontSize: \"0.875rem\",\n\t\t\t\t\t\tfontStyle: \"italic\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"Hardware acceleration is \",\n\t\t\t\tDOM.create(\n\t\t\t\t\t\"a\",\n\t\t\t\t\t{\n\t\t\t\t\t\thref: \"https://github.com/w3c/webcodecs/issues/896\",\n\t\t\t\t\t},\n\t\t\t\t\t\"undetectable\",\n\t\t\t\t),\n\t\t\t\t\" on Firefox.\",\n\t\t\t);\n\t\t\tcontainer.appendChild(noteDiv);\n\t\t}\n\n\t\tparent.appendChild(container);\n\t\teffect.cleanup(() => parent.removeChild(container));\n\t}\n}\n\ncustomElements.define(\"moq-watch-support\", MoqWatchSupport);\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t\"moq-watch-support\": MoqWatchSupport;\n\t}\n}\n"],"mappings":"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"}
package/support/index.js CHANGED
@@ -1,57 +1,56 @@
1
- const d = navigator.userAgent.toLowerCase().includes("firefox"), o = {
2
- aac: "mp4a.40.2",
3
- opus: "opus",
4
- av1: "av01.0.08M.08",
5
- h264: "avc1.640028",
6
- h265: "hev1.1.6.L93.B0",
7
- vp9: "vp09.00.10.08",
8
- vp8: "vp8"
1
+ //#region src/support/index.ts
2
+ var e = navigator.userAgent.toLowerCase().includes("firefox"), t = {
3
+ aac: "mp4a.40.2",
4
+ opus: "opus",
5
+ av1: "av01.0.08M.08",
6
+ h264: "avc1.640028",
7
+ h265: "hev1.1.6.L93.B0",
8
+ vp9: "vp09.00.10.08",
9
+ vp8: "vp8"
9
10
  };
10
- async function t(a) {
11
- return globalThis.AudioDecoder ? (await AudioDecoder.isConfigSupported({
12
- codec: o[a],
13
- numberOfChannels: 2,
14
- sampleRate: 48e3
15
- })).supported === !0 : !1;
11
+ async function n(e) {
12
+ return globalThis.AudioDecoder ? (await AudioDecoder.isConfigSupported({
13
+ codec: t[e],
14
+ numberOfChannels: 2,
15
+ sampleRate: 48e3
16
+ })).supported === !0 : !1;
16
17
  }
17
- async function e(a) {
18
- const r = await VideoDecoder.isConfigSupported({
19
- codec: o[a],
20
- hardwareAcceleration: "prefer-software"
21
- }), n = await VideoDecoder.isConfigSupported({
22
- codec: o[a],
23
- hardwareAcceleration: "prefer-hardware"
24
- });
25
- return {
26
- hardware: d || n.config?.hardwareAcceleration !== "prefer-hardware" ? void 0 : n.supported === !0,
27
- software: r.supported === !0
28
- };
18
+ async function r(n) {
19
+ let r = await VideoDecoder.isConfigSupported({
20
+ codec: t[n],
21
+ hardwareAcceleration: "prefer-software"
22
+ }), i = await VideoDecoder.isConfigSupported({
23
+ codec: t[n],
24
+ hardwareAcceleration: "prefer-hardware"
25
+ });
26
+ return {
27
+ hardware: e || i.config?.hardwareAcceleration !== "prefer-hardware" ? void 0 : i.supported === !0,
28
+ software: r.supported === !0
29
+ };
29
30
  }
30
- async function p() {
31
- return {
32
- // Firefox's WebTransport drops server-initiated bidi streams, so we force the
33
- // WebSocket fallback. Report "partial" to surface the degraded path in UI.
34
- webtransport: typeof WebTransport < "u" ? d ? "partial" : "full" : "partial",
35
- audio: {
36
- decoding: {
37
- aac: await t("aac"),
38
- opus: await t("opus") ? "full" : "partial"
39
- },
40
- render: typeof AudioContext < "u" && typeof AudioBufferSourceNode < "u"
41
- },
42
- video: {
43
- decoding: typeof VideoDecoder < "u" ? {
44
- h264: await e("h264"),
45
- h265: await e("h265"),
46
- vp8: await e("vp8"),
47
- vp9: await e("vp9"),
48
- av1: await e("av1")
49
- } : void 0,
50
- render: typeof OffscreenCanvas < "u" && typeof CanvasRenderingContext2D < "u"
51
- }
52
- };
31
+ async function i() {
32
+ return {
33
+ webtransport: typeof WebTransport < "u" ? e ? "partial" : "full" : "partial",
34
+ audio: {
35
+ decoding: {
36
+ aac: await n("aac"),
37
+ opus: await n("opus") ? "full" : "partial"
38
+ },
39
+ render: typeof AudioContext < "u" && typeof AudioBufferSourceNode < "u"
40
+ },
41
+ video: {
42
+ decoding: typeof VideoDecoder < "u" ? {
43
+ h264: await r("h264"),
44
+ h265: await r("h265"),
45
+ vp8: await r("vp8"),
46
+ vp9: await r("vp9"),
47
+ av1: await r("av1")
48
+ } : void 0,
49
+ render: typeof OffscreenCanvas < "u" && typeof CanvasRenderingContext2D < "u"
50
+ }
51
+ };
53
52
  }
54
- export {
55
- p as isSupported
56
- };
57
- //# sourceMappingURL=index.js.map
53
+ //#endregion
54
+ export { i as isSupported };
55
+
56
+ //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/support/index.ts"],"sourcesContent":["// https://bugzilla.mozilla.org/show_bug.cgi?id=1967793\nconst isFirefox = navigator.userAgent.toLowerCase().includes(\"firefox\");\n\nexport type Partial = \"full\" | \"partial\" | \"none\";\n\nexport type Codec = {\n\thardware?: boolean; // undefined when we can't detect hardware acceleration\n\tsoftware: boolean;\n};\n\nexport type Audio = {\n\taac: boolean;\n\topus: Partial;\n};\n\nexport type Video = {\n\th264: Codec;\n\th265: Codec;\n\tvp8: Codec;\n\tvp9: Codec;\n\tav1: Codec;\n};\n\nexport type Full = {\n\twebtransport: Partial;\n\taudio: {\n\t\tdecoding: Audio;\n\t\trender: boolean;\n\t};\n\tvideo: {\n\t\tdecoding: Video | undefined;\n\t\trender: boolean;\n\t};\n};\n\n// Pick a codec string for each codec.\n// This is not strictly correct, as browsers may not support every profile or level.\nconst CODECS = {\n\taac: \"mp4a.40.2\",\n\topus: \"opus\",\n\tav1: \"av01.0.08M.08\",\n\th264: \"avc1.640028\",\n\th265: \"hev1.1.6.L93.B0\",\n\tvp9: \"vp09.00.10.08\",\n\tvp8: \"vp8\",\n};\n\nasync function audioDecoderSupported(codec: keyof typeof CODECS): Promise<boolean> {\n\tif (!globalThis.AudioDecoder) return false;\n\n\tconst res = await AudioDecoder.isConfigSupported({\n\t\tcodec: CODECS[codec],\n\t\tnumberOfChannels: 2,\n\t\tsampleRate: 48000,\n\t});\n\n\treturn res.supported === true;\n}\n\nasync function videoDecoderSupported(codec: keyof typeof CODECS): Promise<Codec> {\n\tconst software = await VideoDecoder.isConfigSupported({\n\t\tcodec: CODECS[codec],\n\t\thardwareAcceleration: \"prefer-software\",\n\t});\n\n\tconst hardware = await VideoDecoder.isConfigSupported({\n\t\tcodec: CODECS[codec],\n\t\thardwareAcceleration: \"prefer-hardware\",\n\t});\n\n\t// We can't reliably detect hardware encoding on Firefox: https://github.com/w3c/webcodecs/issues/896\n\tconst unknown = isFirefox || hardware.config?.hardwareAcceleration !== \"prefer-hardware\";\n\n\treturn {\n\t\thardware: unknown ? undefined : hardware.supported === true,\n\t\tsoftware: software.supported === true,\n\t};\n}\n\nexport async function isSupported(): Promise<Full> {\n\treturn {\n\t\t// Firefox's WebTransport drops server-initiated bidi streams, so we force the\n\t\t// WebSocket fallback. Report \"partial\" to surface the degraded path in UI.\n\t\twebtransport: typeof WebTransport !== \"undefined\" ? (isFirefox ? \"partial\" : \"full\") : \"partial\",\n\t\taudio: {\n\t\t\tdecoding: {\n\t\t\t\taac: await audioDecoderSupported(\"aac\"),\n\t\t\t\topus: (await audioDecoderSupported(\"opus\")) ? \"full\" : \"partial\",\n\t\t\t},\n\t\t\trender: typeof AudioContext !== \"undefined\" && typeof AudioBufferSourceNode !== \"undefined\",\n\t\t},\n\t\tvideo: {\n\t\t\tdecoding:\n\t\t\t\ttypeof VideoDecoder !== \"undefined\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\th264: await videoDecoderSupported(\"h264\"),\n\t\t\t\t\t\t\th265: await videoDecoderSupported(\"h265\"),\n\t\t\t\t\t\t\tvp8: await videoDecoderSupported(\"vp8\"),\n\t\t\t\t\t\t\tvp9: await videoDecoderSupported(\"vp9\"),\n\t\t\t\t\t\t\tav1: await videoDecoderSupported(\"av1\"),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\trender: typeof OffscreenCanvas !== \"undefined\" && typeof CanvasRenderingContext2D !== \"undefined\",\n\t\t},\n\t};\n}\n"],"names":["isFirefox","CODECS","audioDecoderSupported","codec","videoDecoderSupported","software","hardware","isSupported"],"mappings":"AACA,MAAMA,IAAY,UAAU,UAAU,YAAA,EAAc,SAAS,SAAS,GAoChEC,IAAS;AAAA,EACd,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACN;AAEA,eAAeC,EAAsBC,GAA8C;AAClF,SAAK,WAAW,gBAEJ,MAAM,aAAa,kBAAkB;AAAA,IAChD,OAAOF,EAAOE,CAAK;AAAA,IACnB,kBAAkB;AAAA,IAClB,YAAY;AAAA,EAAA,CACZ,GAEU,cAAc,KARY;AAStC;AAEA,eAAeC,EAAsBD,GAA4C;AAChF,QAAME,IAAW,MAAM,aAAa,kBAAkB;AAAA,IACrD,OAAOJ,EAAOE,CAAK;AAAA,IACnB,sBAAsB;AAAA,EAAA,CACtB,GAEKG,IAAW,MAAM,aAAa,kBAAkB;AAAA,IACrD,OAAOL,EAAOE,CAAK;AAAA,IACnB,sBAAsB;AAAA,EAAA,CACtB;AAKD,SAAO;AAAA,IACN,UAHeH,KAAaM,EAAS,QAAQ,yBAAyB,oBAGlD,SAAYA,EAAS,cAAc;AAAA,IACvD,UAAUD,EAAS,cAAc;AAAA,EAAA;AAEnC;AAEA,eAAsBE,IAA6B;AAClD,SAAO;AAAA;AAAA;AAAA,IAGN,cAAc,OAAO,eAAiB,MAAeP,IAAY,YAAY,SAAU;AAAA,IACvF,OAAO;AAAA,MACN,UAAU;AAAA,QACT,KAAK,MAAME,EAAsB,KAAK;AAAA,QACtC,MAAO,MAAMA,EAAsB,MAAM,IAAK,SAAS;AAAA,MAAA;AAAA,MAExD,QAAQ,OAAO,eAAiB,OAAe,OAAO,wBAA0B;AAAA,IAAA;AAAA,IAEjF,OAAO;AAAA,MACN,UACC,OAAO,eAAiB,MACrB;AAAA,QACA,MAAM,MAAME,EAAsB,MAAM;AAAA,QACxC,MAAM,MAAMA,EAAsB,MAAM;AAAA,QACxC,KAAK,MAAMA,EAAsB,KAAK;AAAA,QACtC,KAAK,MAAMA,EAAsB,KAAK;AAAA,QACtC,KAAK,MAAMA,EAAsB,KAAK;AAAA,MAAA,IAEtC;AAAA,MACJ,QAAQ,OAAO,kBAAoB,OAAe,OAAO,2BAA6B;AAAA,IAAA;AAAA,EACvF;AAEF;"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/support/index.ts"],"sourcesContent":["// https://bugzilla.mozilla.org/show_bug.cgi?id=1967793\nconst isFirefox = navigator.userAgent.toLowerCase().includes(\"firefox\");\n\nexport type Partial = \"full\" | \"partial\" | \"none\";\n\nexport type Codec = {\n\thardware?: boolean; // undefined when we can't detect hardware acceleration\n\tsoftware: boolean;\n};\n\nexport type Audio = {\n\taac: boolean;\n\topus: Partial;\n};\n\nexport type Video = {\n\th264: Codec;\n\th265: Codec;\n\tvp8: Codec;\n\tvp9: Codec;\n\tav1: Codec;\n};\n\nexport type Full = {\n\twebtransport: Partial;\n\taudio: {\n\t\tdecoding: Audio;\n\t\trender: boolean;\n\t};\n\tvideo: {\n\t\tdecoding: Video | undefined;\n\t\trender: boolean;\n\t};\n};\n\n// Pick a codec string for each codec.\n// This is not strictly correct, as browsers may not support every profile or level.\nconst CODECS = {\n\taac: \"mp4a.40.2\",\n\topus: \"opus\",\n\tav1: \"av01.0.08M.08\",\n\th264: \"avc1.640028\",\n\th265: \"hev1.1.6.L93.B0\",\n\tvp9: \"vp09.00.10.08\",\n\tvp8: \"vp8\",\n};\n\nasync function audioDecoderSupported(codec: keyof typeof CODECS): Promise<boolean> {\n\tif (!globalThis.AudioDecoder) return false;\n\n\tconst res = await AudioDecoder.isConfigSupported({\n\t\tcodec: CODECS[codec],\n\t\tnumberOfChannels: 2,\n\t\tsampleRate: 48000,\n\t});\n\n\treturn res.supported === true;\n}\n\nasync function videoDecoderSupported(codec: keyof typeof CODECS): Promise<Codec> {\n\tconst software = await VideoDecoder.isConfigSupported({\n\t\tcodec: CODECS[codec],\n\t\thardwareAcceleration: \"prefer-software\",\n\t});\n\n\tconst hardware = await VideoDecoder.isConfigSupported({\n\t\tcodec: CODECS[codec],\n\t\thardwareAcceleration: \"prefer-hardware\",\n\t});\n\n\t// We can't reliably detect hardware encoding on Firefox: https://github.com/w3c/webcodecs/issues/896\n\tconst unknown = isFirefox || hardware.config?.hardwareAcceleration !== \"prefer-hardware\";\n\n\treturn {\n\t\thardware: unknown ? undefined : hardware.supported === true,\n\t\tsoftware: software.supported === true,\n\t};\n}\n\nexport async function isSupported(): Promise<Full> {\n\treturn {\n\t\t// Firefox's WebTransport drops server-initiated bidi streams, so we force the\n\t\t// WebSocket fallback. Report \"partial\" to surface the degraded path in UI.\n\t\twebtransport: typeof WebTransport !== \"undefined\" ? (isFirefox ? \"partial\" : \"full\") : \"partial\",\n\t\taudio: {\n\t\t\tdecoding: {\n\t\t\t\taac: await audioDecoderSupported(\"aac\"),\n\t\t\t\topus: (await audioDecoderSupported(\"opus\")) ? \"full\" : \"partial\",\n\t\t\t},\n\t\t\trender: typeof AudioContext !== \"undefined\" && typeof AudioBufferSourceNode !== \"undefined\",\n\t\t},\n\t\tvideo: {\n\t\t\tdecoding:\n\t\t\t\ttypeof VideoDecoder !== \"undefined\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\th264: await videoDecoderSupported(\"h264\"),\n\t\t\t\t\t\t\th265: await videoDecoderSupported(\"h265\"),\n\t\t\t\t\t\t\tvp8: await videoDecoderSupported(\"vp8\"),\n\t\t\t\t\t\t\tvp9: await videoDecoderSupported(\"vp9\"),\n\t\t\t\t\t\t\tav1: await videoDecoderSupported(\"av1\"),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\trender: typeof OffscreenCanvas !== \"undefined\" && typeof CanvasRenderingContext2D !== \"undefined\",\n\t\t},\n\t};\n}\n"],"mappings":";AACA,IAAM,IAAY,UAAU,UAAU,YAAY,EAAE,SAAS,SAAS,GAoChE,IAAS;CACd,KAAK;CACL,MAAM;CACN,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;CACL,KAAK;AACN;AAEA,eAAe,EAAsB,GAA8C;CASlF,OARK,WAAW,gBAQT,MANW,aAAa,kBAAkB;EAChD,OAAO,EAAO;EACd,kBAAkB;EAClB,YAAY;CACb,CAAC,GAEU,cAAc,KARY;AAStC;AAEA,eAAe,EAAsB,GAA4C;CAChF,IAAM,IAAW,MAAM,aAAa,kBAAkB;EACrD,OAAO,EAAO;EACd,sBAAsB;CACvB,CAAC,GAEK,IAAW,MAAM,aAAa,kBAAkB;EACrD,OAAO,EAAO;EACd,sBAAsB;CACvB,CAAC;CAKD,OAAO;EACN,UAHe,KAAa,EAAS,QAAQ,yBAAyB,oBAGlD,KAAA,IAAY,EAAS,cAAc;EACvD,UAAU,EAAS,cAAc;CAClC;AACD;AAEA,eAAsB,IAA6B;CAClD,OAAO;EAGN,cAAc,OAAO,eAAiB,MAAe,IAAY,YAAY,SAAU;EACvF,OAAO;GACN,UAAU;IACT,KAAK,MAAM,EAAsB,KAAK;IACtC,MAAO,MAAM,EAAsB,MAAM,IAAK,SAAS;GACxD;GACA,QAAQ,OAAO,eAAiB,OAAe,OAAO,wBAA0B;EACjF;EACA,OAAO;GACN,UACC,OAAO,eAAiB,MACrB;IACA,MAAM,MAAM,EAAsB,MAAM;IACxC,MAAM,MAAM,EAAsB,MAAM;IACxC,KAAK,MAAM,EAAsB,KAAK;IACtC,KAAK,MAAM,EAAsB,KAAK;IACtC,KAAK,MAAM,EAAsB,KAAK;GACvC,IACC,KAAA;GACJ,QAAQ,OAAO,kBAAoB,OAAe,OAAO,2BAA6B;EACvF;CACD;AACD"}