Skip to content

Commit 70f5b24

Browse files
Publish to gh-pages 9c774de
0 parents  commit 70f5b24

10 files changed

+1467
-0
lines changed

.nojekyll

Whitespace-only changes.

coi-serviceworker.js

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
2+
let coepCredentialless = false;
3+
if (typeof window === 'undefined') {
4+
self.addEventListener("install", () => self.skipWaiting());
5+
self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
6+
7+
self.addEventListener("message", (ev) => {
8+
if (!ev.data) {
9+
return;
10+
} else if (ev.data.type === "deregister") {
11+
self.registration
12+
.unregister()
13+
.then(() => {
14+
return self.clients.matchAll();
15+
})
16+
.then(clients => {
17+
clients.forEach((client) => client.navigate(client.url));
18+
});
19+
} else if (ev.data.type === "coepCredentialless") {
20+
coepCredentialless = ev.data.value;
21+
}
22+
});
23+
24+
self.addEventListener("fetch", function (event) {
25+
const r = event.request;
26+
if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
27+
return;
28+
}
29+
30+
const request = (coepCredentialless && r.mode === "no-cors")
31+
? new Request(r, {
32+
credentials: "omit",
33+
})
34+
: r;
35+
event.respondWith(
36+
fetch(request)
37+
.then((response) => {
38+
if (response.status === 0) {
39+
return response;
40+
}
41+
42+
const newHeaders = new Headers(response.headers);
43+
newHeaders.set("Cross-Origin-Embedder-Policy",
44+
coepCredentialless ? "credentialless" : "require-corp"
45+
);
46+
if (!coepCredentialless) {
47+
newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
48+
}
49+
newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
50+
51+
return new Response(response.body, {
52+
status: response.status,
53+
statusText: response.statusText,
54+
headers: newHeaders,
55+
});
56+
})
57+
.catch((e) => console.error(e))
58+
);
59+
});
60+
61+
} else {
62+
(() => {
63+
const reloadedBySelf = window.sessionStorage.getItem("coiReloadedBySelf");
64+
window.sessionStorage.removeItem("coiReloadedBySelf");
65+
const coepDegrading = (reloadedBySelf == "coepdegrade");
66+
67+
// You can customize the behavior of this script through a global `coi` variable.
68+
const coi = {
69+
shouldRegister: () => !reloadedBySelf,
70+
shouldDeregister: () => false,
71+
coepCredentialless: () => true,
72+
coepDegrade: () => true,
73+
doReload: () => window.location.reload(),
74+
quiet: false,
75+
...window.coi
76+
};
77+
78+
const n = navigator;
79+
const controlling = n.serviceWorker && n.serviceWorker.controller;
80+
81+
// Record the failure if the page is served by serviceWorker.
82+
if (controlling && !window.crossOriginIsolated) {
83+
window.sessionStorage.setItem("coiCoepHasFailed", "true");
84+
}
85+
const coepHasFailed = window.sessionStorage.getItem("coiCoepHasFailed");
86+
87+
if (controlling) {
88+
// Reload only on the first failure.
89+
const reloadToDegrade = coi.coepDegrade() && !(
90+
coepDegrading || window.crossOriginIsolated
91+
);
92+
n.serviceWorker.controller.postMessage({
93+
type: "coepCredentialless",
94+
value: (reloadToDegrade || coepHasFailed && coi.coepDegrade())
95+
? false
96+
: coi.coepCredentialless(),
97+
});
98+
if (reloadToDegrade) {
99+
!coi.quiet && console.log("Reloading page to degrade COEP.");
100+
window.sessionStorage.setItem("coiReloadedBySelf", "coepdegrade");
101+
coi.doReload("coepdegrade");
102+
}
103+
104+
if (coi.shouldDeregister()) {
105+
n.serviceWorker.controller.postMessage({ type: "deregister" });
106+
}
107+
}
108+
109+
// If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are
110+
// already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here.
111+
if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return;
112+
113+
if (!window.isSecureContext) {
114+
!coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required.");
115+
return;
116+
}
117+
118+
// In some environments (e.g. Firefox private mode) this won't be available
119+
if (!n.serviceWorker) {
120+
!coi.quiet && console.error("COOP/COEP Service Worker not registered, perhaps due to private mode.");
121+
return;
122+
}
123+
124+
n.serviceWorker.register(window.document.currentScript.src).then(
125+
(registration) => {
126+
!coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope);
127+
128+
registration.addEventListener("updatefound", () => {
129+
!coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker.");
130+
window.sessionStorage.setItem("coiReloadedBySelf", "updatefound");
131+
coi.doReload();
132+
});
133+
134+
// If the registration is active, but it's not controlling the page
135+
if (registration.active && !n.serviceWorker.controller) {
136+
!coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker.");
137+
window.sessionStorage.setItem("coiReloadedBySelf", "notcontrolling");
138+
coi.doReload();
139+
}
140+
},
141+
(err) => {
142+
!coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err);
143+
}
144+
);
145+
})();
146+
}

index.apple-touch-icon.png

11.9 KB
Loading

index.audio.worklet.js

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/**************************************************************************/
2+
/* audio.worklet.js */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
class RingBuffer {
32+
constructor(p_buffer, p_state, p_threads) {
33+
this.buffer = p_buffer;
34+
this.avail = p_state;
35+
this.threads = p_threads;
36+
this.rpos = 0;
37+
this.wpos = 0;
38+
}
39+
40+
data_left() {
41+
return this.threads ? Atomics.load(this.avail, 0) : this.avail;
42+
}
43+
44+
space_left() {
45+
return this.buffer.length - this.data_left();
46+
}
47+
48+
read(output) {
49+
const size = this.buffer.length;
50+
let from = 0;
51+
let to_write = output.length;
52+
if (this.rpos + to_write > size) {
53+
const high = size - this.rpos;
54+
output.set(this.buffer.subarray(this.rpos, size));
55+
from = high;
56+
to_write -= high;
57+
this.rpos = 0;
58+
}
59+
if (to_write) {
60+
output.set(this.buffer.subarray(this.rpos, this.rpos + to_write), from);
61+
}
62+
this.rpos += to_write;
63+
if (this.threads) {
64+
Atomics.add(this.avail, 0, -output.length);
65+
Atomics.notify(this.avail, 0);
66+
} else {
67+
this.avail -= output.length;
68+
}
69+
}
70+
71+
write(p_buffer) {
72+
const to_write = p_buffer.length;
73+
const mw = this.buffer.length - this.wpos;
74+
if (mw >= to_write) {
75+
this.buffer.set(p_buffer, this.wpos);
76+
this.wpos += to_write;
77+
if (mw === to_write) {
78+
this.wpos = 0;
79+
}
80+
} else {
81+
const high = p_buffer.subarray(0, mw);
82+
const low = p_buffer.subarray(mw);
83+
this.buffer.set(high, this.wpos);
84+
this.buffer.set(low);
85+
this.wpos = low.length;
86+
}
87+
if (this.threads) {
88+
Atomics.add(this.avail, 0, to_write);
89+
Atomics.notify(this.avail, 0);
90+
} else {
91+
this.avail += to_write;
92+
}
93+
}
94+
}
95+
96+
class GodotProcessor extends AudioWorkletProcessor {
97+
constructor() {
98+
super();
99+
this.threads = false;
100+
this.running = true;
101+
this.lock = null;
102+
this.notifier = null;
103+
this.output = null;
104+
this.output_buffer = new Float32Array();
105+
this.input = null;
106+
this.input_buffer = new Float32Array();
107+
this.port.onmessage = (event) => {
108+
const cmd = event.data['cmd'];
109+
const data = event.data['data'];
110+
this.parse_message(cmd, data);
111+
};
112+
}
113+
114+
process_notify() {
115+
if (this.notifier) {
116+
Atomics.add(this.notifier, 0, 1);
117+
Atomics.notify(this.notifier, 0);
118+
}
119+
}
120+
121+
parse_message(p_cmd, p_data) {
122+
if (p_cmd === 'start' && p_data) {
123+
const state = p_data[0];
124+
let idx = 0;
125+
this.threads = true;
126+
this.lock = state.subarray(idx, ++idx);
127+
this.notifier = state.subarray(idx, ++idx);
128+
const avail_in = state.subarray(idx, ++idx);
129+
const avail_out = state.subarray(idx, ++idx);
130+
this.input = new RingBuffer(p_data[1], avail_in, true);
131+
this.output = new RingBuffer(p_data[2], avail_out, true);
132+
} else if (p_cmd === 'stop') {
133+
this.running = false;
134+
this.output = null;
135+
this.input = null;
136+
this.lock = null;
137+
this.notifier = null;
138+
} else if (p_cmd === 'start_nothreads') {
139+
this.output = new RingBuffer(p_data[0], p_data[0].length, false);
140+
} else if (p_cmd === 'chunk') {
141+
this.output.write(p_data);
142+
}
143+
}
144+
145+
static array_has_data(arr) {
146+
return arr.length && arr[0].length && arr[0][0].length;
147+
}
148+
149+
process(inputs, outputs, parameters) {
150+
if (!this.running) {
151+
return false; // Stop processing.
152+
}
153+
if (this.output === null) {
154+
return true; // Not ready yet, keep processing.
155+
}
156+
const process_input = GodotProcessor.array_has_data(inputs);
157+
if (process_input) {
158+
const input = inputs[0];
159+
const chunk = input[0].length * input.length;
160+
if (this.input_buffer.length !== chunk) {
161+
this.input_buffer = new Float32Array(chunk);
162+
}
163+
if (!this.threads) {
164+
GodotProcessor.write_input(this.input_buffer, input);
165+
this.port.postMessage({ 'cmd': 'input', 'data': this.input_buffer });
166+
} else if (this.input.space_left() >= chunk) {
167+
GodotProcessor.write_input(this.input_buffer, input);
168+
this.input.write(this.input_buffer);
169+
} else {
170+
// this.port.postMessage('Input buffer is full! Skipping input frame.'); // Uncomment this line to debug input buffer.
171+
}
172+
}
173+
const process_output = GodotProcessor.array_has_data(outputs);
174+
if (process_output) {
175+
const output = outputs[0];
176+
const chunk = output[0].length * output.length;
177+
if (this.output_buffer.length !== chunk) {
178+
this.output_buffer = new Float32Array(chunk);
179+
}
180+
if (this.output.data_left() >= chunk) {
181+
this.output.read(this.output_buffer);
182+
GodotProcessor.write_output(output, this.output_buffer);
183+
if (!this.threads) {
184+
this.port.postMessage({ 'cmd': 'read', 'data': chunk });
185+
}
186+
} else {
187+
// this.port.postMessage('Output buffer has not enough frames! Skipping output frame.'); // Uncomment this line to debug output buffer.
188+
}
189+
}
190+
this.process_notify();
191+
return true;
192+
}
193+
194+
static write_output(dest, source) {
195+
const channels = dest.length;
196+
for (let ch = 0; ch < channels; ch++) {
197+
for (let sample = 0; sample < dest[ch].length; sample++) {
198+
dest[ch][sample] = source[sample * channels + ch];
199+
}
200+
}
201+
}
202+
203+
static write_input(dest, source) {
204+
const channels = source.length;
205+
for (let ch = 0; ch < channels; ch++) {
206+
for (let sample = 0; sample < source[ch].length; sample++) {
207+
dest[sample * channels + ch] = source[ch][sample];
208+
}
209+
}
210+
}
211+
}
212+
213+
registerProcessor('godot-processor', GodotProcessor);

0 commit comments

Comments
 (0)