-
Notifications
You must be signed in to change notification settings - Fork 151
Expand file tree
/
Copy pathindex.ts
More file actions
169 lines (150 loc) · 4.46 KB
/
index.ts
File metadata and controls
169 lines (150 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import { isFirefox } from "../util/hacks";
export type SupportMode = "core" | "watch" | "publish" | "all";
export type Partial = "full" | "partial" | "none";
export type Audio = {
aac: boolean;
opus: boolean;
};
export type Codec = {
hardware?: boolean; // undefined when we can't detect hardware acceleration
software: boolean;
};
export type Video = {
h264: Codec;
h265: Codec;
vp8: Codec;
vp9: Codec;
av1: Codec;
};
export type Full = {
webtransport: Partial;
audio: {
capture: boolean;
encoding: Audio | undefined;
decoding: Audio | undefined;
render: boolean;
};
video: {
capture: Partial;
encoding: Video | undefined;
decoding: Video | undefined;
render: boolean;
};
};
// Pick a codec string for each codec.
// This is not strictly correct, as browsers may not support every profile or level.
const CODECS = {
aac: "mp4a.40.2",
opus: "opus",
av1: "av01.0.08M.08",
h264: "avc1.640028",
h265: "hev1.1.6.L93.B0",
vp9: "vp09.00.10.08",
vp8: "vp8",
};
async function audioDecoderSupported(codec: keyof typeof CODECS) {
const res = await AudioDecoder.isConfigSupported({
codec: CODECS[codec],
numberOfChannels: 2,
sampleRate: 48000,
});
return res.supported === true;
}
async function audioEncoderSupported(codec: keyof typeof CODECS) {
const res = await AudioEncoder.isConfigSupported({
codec: CODECS[codec],
numberOfChannels: 2,
sampleRate: 48000,
});
return res.supported === true;
}
async function videoDecoderSupported(codec: keyof typeof CODECS) {
const software = await VideoDecoder.isConfigSupported({
codec: CODECS[codec],
hardwareAcceleration: "prefer-software",
});
const hardware = await VideoDecoder.isConfigSupported({
codec: CODECS[codec],
hardwareAcceleration: "prefer-hardware",
});
// We can't reliably detect hardware encoding on Firefox: https://github.com/w3c/webcodecs/issues/896
const unknown = isFirefox || hardware.config?.hardwareAcceleration !== "prefer-hardware";
return {
hardware: unknown ? undefined : hardware.supported === true,
software: software.supported === true,
};
}
async function videoEncoderSupported(codec: keyof typeof CODECS) {
const software = await VideoEncoder.isConfigSupported({
codec: CODECS[codec],
width: 1280,
height: 720,
hardwareAcceleration: "prefer-software",
});
// We can't reliably detect hardware encoding on Firefox: https://github.com/w3c/webcodecs/issues/896
const hardware = await VideoEncoder.isConfigSupported({
codec: CODECS[codec],
width: 1280,
height: 720,
hardwareAcceleration: "prefer-hardware",
});
const unknown = isFirefox || hardware.config?.hardwareAcceleration !== "prefer-hardware";
return {
hardware: unknown ? undefined : hardware.supported === true,
software: software.supported === true,
};
}
export async function isSupported(): Promise<Full> {
return {
webtransport: typeof WebTransport !== "undefined" ? "full" : "partial",
audio: {
capture: typeof AudioWorkletNode !== "undefined",
encoding:
typeof AudioEncoder !== "undefined"
? {
aac: await audioEncoderSupported("aac"),
opus: await audioEncoderSupported("opus"),
}
: undefined,
decoding:
typeof AudioDecoder !== "undefined"
? {
aac: await audioDecoderSupported("aac"),
opus: await audioDecoderSupported("opus"),
}
: undefined,
render: typeof AudioContext !== "undefined" && typeof AudioBufferSourceNode !== "undefined",
},
video: {
capture:
// We have a fallback for MediaStreamTrackProcessor, but it's pretty gross so no full points.
// @ts-expect-error No typescript types yet.
typeof MediaStreamTrackProcessor !== "undefined"
? "full"
: typeof OffscreenCanvas !== "undefined"
? "partial"
: "none",
encoding:
typeof VideoEncoder !== "undefined"
? {
h264: await videoEncoderSupported("h264"),
h265: await videoEncoderSupported("h265"),
vp8: await videoEncoderSupported("vp8"),
vp9: await videoEncoderSupported("vp9"),
av1: await videoEncoderSupported("av1"),
}
: undefined,
decoding:
typeof VideoDecoder !== "undefined"
? {
h264: await videoDecoderSupported("h264"),
h265: await videoDecoderSupported("h265"),
vp8: await videoDecoderSupported("vp8"),
vp9: await videoDecoderSupported("vp9"),
av1: await videoDecoderSupported("av1"),
}
: undefined,
render: typeof OffscreenCanvas !== "undefined" && typeof CanvasRenderingContext2D !== "undefined",
},
};
}