@spatius/avatarkit 1.3.1-beta.2 → 1.3.1-beta.4

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.
@@ -0,0 +1,129 @@
1
+ import { t as logger } from "./logger-C3fw-NWP.js";
2
+ //#region audio/OpusDecoderProxy.ts
3
+ var OpusDecoderProxy = class OpusDecoderProxy {
4
+ worker = null;
5
+ fallbackDecoder = null;
6
+ pending = /* @__PURE__ */ new Map();
7
+ seq = 0;
8
+ backend = "main-thread";
9
+ constructor() {}
10
+ /**
11
+ * Create the decoder, selecting the best backend. Never rejects: it degrades
12
+ * through worker → main-thread so a connection always gets a working decoder.
13
+ * Resolves once the chosen backend is ready.
14
+ */
15
+ static async create() {
16
+ const proxy = new OpusDecoderProxy();
17
+ try {
18
+ await proxy.startWorker();
19
+ proxy.backend = "worker";
20
+ return proxy;
21
+ } catch (err) {
22
+ logger.warn("[Opus][DecoderProxy] Worker unavailable, falling back to main-thread decode:", err instanceof Error ? err.message : String(err));
23
+ }
24
+ const { OggOpusDecoder } = await import("./OpusCodec-Bv4kzdt8.js").then((n) => n.n);
25
+ proxy.fallbackDecoder = new OggOpusDecoder();
26
+ proxy.backend = "main-thread";
27
+ return proxy;
28
+ }
29
+ startWorker() {
30
+ return new Promise((resolve, reject) => {
31
+ let worker;
32
+ try {
33
+ worker = new Worker(new URL(
34
+ /* @vite-ignore */
35
+ "/assets/OpusDecoderWorker.worker-Bd4svkEs.js",
36
+ "" + import.meta.url
37
+ ), { type: "module" });
38
+ } catch (err) {
39
+ reject(err instanceof Error ? err : new Error(String(err)));
40
+ return;
41
+ }
42
+ let ready = false;
43
+ const initTimeout = setTimeout(() => {
44
+ if (!ready) {
45
+ worker.terminate();
46
+ reject(/* @__PURE__ */ new Error("worker init timeout"));
47
+ }
48
+ }, 3e3);
49
+ worker.onmessage = (e) => {
50
+ const d = e.data;
51
+ if (d.type === "ready") {
52
+ ready = true;
53
+ clearTimeout(initTimeout);
54
+ this.worker = worker;
55
+ resolve();
56
+ return;
57
+ }
58
+ if (d.type === "pcm") {
59
+ this.pending.get(d.seq)?.resolve(new Uint8Array(d.pcm));
60
+ this.pending.delete(d.seq);
61
+ return;
62
+ }
63
+ if (d.type === "error") {
64
+ this.pending.get(d.seq)?.reject(new Error(d.message));
65
+ this.pending.delete(d.seq);
66
+ }
67
+ };
68
+ worker.onerror = (e) => {
69
+ clearTimeout(initTimeout);
70
+ const err = new Error(e.message || "worker error");
71
+ if (!ready) {
72
+ reject(err);
73
+ return;
74
+ }
75
+ for (const p of this.pending.values()) p.reject(err);
76
+ this.pending.clear();
77
+ };
78
+ worker.postMessage({ type: "init" });
79
+ });
80
+ }
81
+ /**
82
+ * Decode one slice of an Ogg Opus stream, resolving with the PCM16 (mono LE)
83
+ * decoded so far (possibly empty for header-only slices). On the worker path the
84
+ * main thread stays free while decoding runs; on the fallback path this blocks
85
+ * the main thread (same as the legacy synchronous behavior).
86
+ *
87
+ * The caller (AvatarController) must serialize these in feed order — the decoder
88
+ * is stateful. See its inputDecodeChain.
89
+ */
90
+ decode(ogg) {
91
+ if (this.worker) {
92
+ const seq = this.seq++;
93
+ return new Promise((resolve, reject) => {
94
+ this.pending.set(seq, {
95
+ resolve,
96
+ reject
97
+ });
98
+ this.worker.postMessage({
99
+ type: "decode",
100
+ ogg,
101
+ seq
102
+ });
103
+ });
104
+ }
105
+ if (this.fallbackDecoder) try {
106
+ const pcm = this.fallbackDecoder.decode(ogg);
107
+ return Promise.resolve(pcm);
108
+ } catch (err) {
109
+ return Promise.reject(err instanceof Error ? err : new Error(String(err)));
110
+ }
111
+ return Promise.reject(/* @__PURE__ */ new Error("OpusDecoderProxy not initialized"));
112
+ }
113
+ /** Tear down whichever backend is active. Call once on disconnect. */
114
+ destroy() {
115
+ for (const p of this.pending.values()) p.reject(/* @__PURE__ */ new Error("decoder destroyed"));
116
+ this.pending.clear();
117
+ if (this.worker) {
118
+ this.worker.postMessage({ type: "destroy" });
119
+ this.worker.terminate();
120
+ this.worker = null;
121
+ }
122
+ if (this.fallbackDecoder) {
123
+ this.fallbackDecoder.destroy();
124
+ this.fallbackDecoder = null;
125
+ }
126
+ }
127
+ };
128
+ //#endregion
129
+ export { OpusDecoderProxy };
@@ -0,0 +1,135 @@
1
+ import { t as logger } from "./logger-C3fw-NWP.js";
2
+ //#region audio/OpusEncoderProxy.ts
3
+ var OpusEncoderProxy = class OpusEncoderProxy {
4
+ worker = null;
5
+ fallbackEncoder = null;
6
+ pending = /* @__PURE__ */ new Map();
7
+ seq = 0;
8
+ sampleRate;
9
+ bitrate;
10
+ backend = "main-thread";
11
+ constructor(sampleRate, bitrate) {
12
+ this.sampleRate = sampleRate;
13
+ this.bitrate = bitrate;
14
+ }
15
+ /**
16
+ * Create the encoder, selecting the best backend. Never rejects: it degrades
17
+ * through worker → main-thread so a connection always gets a working encoder.
18
+ * Resolves once the chosen backend is ready.
19
+ */
20
+ static async create(sampleRate, bitrate) {
21
+ const proxy = new OpusEncoderProxy(sampleRate, bitrate);
22
+ try {
23
+ await proxy.startWorker();
24
+ proxy.backend = "worker";
25
+ return proxy;
26
+ } catch (err) {
27
+ logger.warn("[Opus][Proxy] Worker unavailable, falling back to main-thread encode:", err instanceof Error ? err.message : String(err));
28
+ }
29
+ const { OggOpusEncoder } = await import("./OpusCodec-Bv4kzdt8.js").then((n) => n.n);
30
+ proxy.fallbackEncoder = new OggOpusEncoder(sampleRate, bitrate);
31
+ proxy.backend = "main-thread";
32
+ return proxy;
33
+ }
34
+ startWorker() {
35
+ return new Promise((resolve, reject) => {
36
+ let worker;
37
+ try {
38
+ worker = new Worker(new URL(
39
+ /* @vite-ignore */
40
+ "/assets/OpusEncoderWorker.worker-BdxYhZZ9.js",
41
+ "" + import.meta.url
42
+ ), { type: "module" });
43
+ } catch (err) {
44
+ reject(err instanceof Error ? err : new Error(String(err)));
45
+ return;
46
+ }
47
+ let ready = false;
48
+ const initTimeout = setTimeout(() => {
49
+ if (!ready) {
50
+ worker.terminate();
51
+ reject(/* @__PURE__ */ new Error("worker init timeout"));
52
+ }
53
+ }, 3e3);
54
+ worker.onmessage = (e) => {
55
+ const d = e.data;
56
+ if (d.type === "ready") {
57
+ ready = true;
58
+ clearTimeout(initTimeout);
59
+ this.worker = worker;
60
+ resolve();
61
+ return;
62
+ }
63
+ if (d.type === "pages") {
64
+ this.pending.get(d.seq)?.resolve(d.pages);
65
+ this.pending.delete(d.seq);
66
+ return;
67
+ }
68
+ if (d.type === "error") {
69
+ this.pending.get(d.seq)?.reject(new Error(d.message));
70
+ this.pending.delete(d.seq);
71
+ }
72
+ };
73
+ worker.onerror = (e) => {
74
+ clearTimeout(initTimeout);
75
+ const err = new Error(e.message || "worker error");
76
+ if (!ready) {
77
+ reject(err);
78
+ return;
79
+ }
80
+ for (const p of this.pending.values()) p.reject(err);
81
+ this.pending.clear();
82
+ };
83
+ worker.postMessage({
84
+ type: "init",
85
+ sampleRate: this.sampleRate,
86
+ bitrate: this.bitrate
87
+ });
88
+ });
89
+ }
90
+ /**
91
+ * Encode one PCM chunk, resolving with the Ogg pages to send (in order). On the
92
+ * worker path the main thread stays free while encoding runs; on the fallback
93
+ * path this blocks the main thread (same as the legacy behavior).
94
+ */
95
+ encode(reqId, pcm, end) {
96
+ if (this.worker) {
97
+ const seq = this.seq++;
98
+ return new Promise((resolve, reject) => {
99
+ this.pending.set(seq, {
100
+ resolve,
101
+ reject
102
+ });
103
+ this.worker.postMessage({
104
+ type: "encode",
105
+ reqId,
106
+ pcm,
107
+ end,
108
+ seq
109
+ });
110
+ });
111
+ }
112
+ if (this.fallbackEncoder) try {
113
+ return Promise.resolve(this.fallbackEncoder.encode(reqId, pcm, end));
114
+ } catch (err) {
115
+ return Promise.reject(err instanceof Error ? err : new Error(String(err)));
116
+ }
117
+ return Promise.reject(/* @__PURE__ */ new Error("OpusEncoderProxy not initialized"));
118
+ }
119
+ /** Tear down whichever backend is active. Call once on disconnect. */
120
+ destroy() {
121
+ for (const p of this.pending.values()) p.reject(/* @__PURE__ */ new Error("encoder destroyed"));
122
+ this.pending.clear();
123
+ if (this.worker) {
124
+ this.worker.postMessage({ type: "destroy" });
125
+ this.worker.terminate();
126
+ this.worker = null;
127
+ }
128
+ if (this.fallbackEncoder) {
129
+ this.fallbackEncoder.destroy();
130
+ this.fallbackEncoder = null;
131
+ }
132
+ }
133
+ };
134
+ //#endregion
135
+ export { OpusEncoderProxy };