@openclaw/whatsapp 2026.5.30-beta.1 → 2026.5.31-beta.2
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.
- package/README.md +11 -0
- package/dist/{access-control-Z0fYaWrx.js → access-control-C53zKYSN.js} +1 -1
- package/dist/{accounts-BMGM1RtF.js → accounts-DgViSyJx.js} +1 -0
- package/dist/{action-runtime-BbUDQ78g.js → action-runtime-Cyp5GNIT.js} +2 -2
- package/dist/action-runtime-api.js +1 -1
- package/dist/action-runtime.runtime.js +1 -1
- package/dist/api.js +8 -8
- package/dist/{approval-handler.runtime-BIZgAkfR.js → approval-handler.runtime-BVmOu6x1.js} +1 -2
- package/dist/{channel-dHRyqWut.js → channel-DA2BAIo5.js} +5 -5
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-react-action-CYx128FS.js → channel-react-action-zvbaCnGe.js} +3 -3
- package/dist/{channel.runtime-3WElbRZG.js → channel.runtime-Q1LZDB5s.js} +3 -3
- package/dist/{channel.setup-BuSd1d1D.js → channel.setup-DHXOo4h5.js} +1 -2
- package/dist/{config-schema-CsNDlDpL.js → config-schema-CROZuhT-.js} +16 -0
- package/dist/contract-api.js +1 -1
- package/dist/{login-DygDn79y.js → login-2fuBM7Je.js} +1 -1
- package/dist/{login-qr-nPxKvdjP.js → login-qr-B1o7GFy8.js} +1 -1
- package/dist/login-qr-runtime.js +1 -1
- package/dist/{monitor-NKzAEWeJ.js → monitor-BVRq04Dt.js} +17 -9
- package/dist/runtime-api.js +5 -5
- package/dist/{send-DjMBLgiv.js → send-DSlVXKL_.js} +10 -2
- package/dist/{send-api-Cx2qeYqj.js → send-api-Bjn-h80j.js} +3 -2
- package/dist/{setup-core-B9CAuPOB.js → setup-core-OvPMaAsx.js} +4 -4
- package/dist/{setup-finalize-f95kxYvv.js → setup-finalize-Dk23pfKc.js} +3 -3
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-_Cid6xIf.js → setup-surface-F-jVrH8u.js} +2 -2
- package/node_modules/@audio/decode-aac/LICENSE +9 -0
- package/node_modules/@audio/decode-aac/README.md +60 -0
- package/node_modules/@audio/decode-aac/decode-aac.d.ts +16 -0
- package/node_modules/@audio/decode-aac/decode-aac.js +391 -0
- package/node_modules/@audio/decode-aac/package.json +47 -0
- package/node_modules/@audio/decode-aac/src/aac.wasm.cjs +0 -0
- package/node_modules/@audio/decode-aiff/LICENSE +21 -0
- package/node_modules/@audio/decode-aiff/README.md +53 -0
- package/node_modules/@audio/decode-aiff/decode-aiff.d.ts +16 -0
- package/node_modules/@audio/decode-aiff/decode-aiff.js +583 -0
- package/node_modules/@audio/decode-aiff/package.json +42 -0
- package/node_modules/@audio/decode-amr/LICENSE +191 -0
- package/node_modules/@audio/decode-amr/README.md +65 -0
- package/node_modules/@audio/decode-amr/decode-amr.d.ts +16 -0
- package/node_modules/@audio/decode-amr/decode-amr.js +159 -0
- package/node_modules/@audio/decode-amr/package.json +48 -0
- package/node_modules/@audio/decode-amr/src/amr.wasm.cjs +0 -0
- package/node_modules/@audio/decode-caf/LICENSE +21 -0
- package/node_modules/@audio/decode-caf/README.md +55 -0
- package/node_modules/@audio/decode-caf/decode-caf.d.ts +16 -0
- package/node_modules/@audio/decode-caf/decode-caf.js +190 -0
- package/node_modules/@audio/decode-caf/package.json +43 -0
- package/node_modules/{audio-buffer → @audio/decode-flac}/LICENSE +5 -2
- package/node_modules/@audio/decode-flac/README.md +23 -0
- package/node_modules/@audio/decode-flac/decode-flac.d.ts +16 -0
- package/node_modules/@audio/decode-flac/decode-flac.js +2994 -0
- package/node_modules/@audio/decode-flac/meta.js +115 -0
- package/node_modules/@audio/decode-flac/package.json +49 -0
- package/node_modules/@audio/decode-mp3/LICENSE +25 -0
- package/node_modules/@audio/decode-mp3/README.md +23 -0
- package/node_modules/@audio/decode-mp3/decode-mp3.d.ts +16 -0
- package/node_modules/@audio/decode-mp3/decode-mp3.js +868 -0
- package/node_modules/@audio/decode-mp3/meta.js +143 -0
- package/node_modules/@audio/decode-mp3/package.json +50 -0
- package/node_modules/@audio/decode-opus/LICENSE +25 -0
- package/node_modules/@audio/decode-opus/README.md +23 -0
- package/node_modules/@audio/decode-opus/decode-opus.d.ts +16 -0
- package/node_modules/@audio/decode-opus/decode-opus.js +3179 -0
- package/node_modules/@audio/decode-opus/package.json +47 -0
- package/node_modules/@audio/decode-qoa/LICENSE +25 -0
- package/node_modules/@audio/decode-qoa/README.md +21 -0
- package/node_modules/@audio/decode-qoa/decode-qoa.d.ts +16 -0
- package/node_modules/@audio/decode-qoa/decode-qoa.js +278 -0
- package/node_modules/@audio/decode-qoa/package.json +46 -0
- package/node_modules/@audio/decode-vorbis/LICENSE +25 -0
- package/node_modules/@audio/decode-vorbis/README.md +23 -0
- package/node_modules/@audio/decode-vorbis/decode-vorbis.d.ts +16 -0
- package/node_modules/@audio/decode-vorbis/decode-vorbis.js +2984 -0
- package/node_modules/@audio/decode-vorbis/package.json +47 -0
- package/node_modules/@audio/decode-wav/decode-wav.js +104 -0
- package/node_modules/@audio/decode-wav/meta.js +114 -0
- package/node_modules/@audio/decode-wav/package.json +27 -0
- package/node_modules/@audio/decode-webm/LICENSE +21 -0
- package/node_modules/@audio/decode-webm/README.md +57 -0
- package/node_modules/@audio/decode-webm/decode-webm.d.ts +16 -0
- package/node_modules/@audio/decode-webm/decode-webm.js +3964 -0
- package/node_modules/@audio/decode-webm/package.json +51 -0
- package/node_modules/@audio/decode-wma/LICENSE +12 -0
- package/node_modules/@audio/decode-wma/README.md +76 -0
- package/node_modules/@audio/decode-wma/decode-wma.d.ts +33 -0
- package/node_modules/@audio/decode-wma/decode-wma.js +525 -0
- package/node_modules/@audio/decode-wma/package.json +47 -0
- package/node_modules/@audio/decode-wma/src/wma.wasm.cjs +0 -0
- package/node_modules/audio-decode/.claude/settings.json +204 -0
- package/node_modules/audio-decode/.github/workflows/test.js.yml +11 -20
- package/node_modules/audio-decode/.gitmodules +9 -0
- package/node_modules/audio-decode/audio-decode.d.ts +48 -10
- package/node_modules/audio-decode/audio-decode.js +193 -77
- package/node_modules/audio-decode/meta.js +11 -0
- package/node_modules/audio-decode/package.json +49 -21
- package/node_modules/audio-decode/readme.md +129 -29
- package/node_modules/audio-decode/stream.d.ts +15 -0
- package/node_modules/audio-decode/stream.js +1 -0
- package/node_modules/audio-decode/test.html +29 -10
- package/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +2 -2
- package/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.d.ts +2 -2
- package/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.min.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.d.ts +2 -2
- package/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.d.ts +2 -2
- package/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.min.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/index.d.ts +2 -2
- package/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/index.min.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.d.ts +2 -2
- package/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.min.js.map +1 -1
- package/node_modules/lru-cache/package.json +1 -1
- package/node_modules/typebox/build/type/script/mapping.d.mts +5 -2
- package/node_modules/typebox/build/type/script/mapping.mjs +15 -8
- package/node_modules/typebox/build/type/script/parser.d.mts +3 -1
- package/node_modules/typebox/build/type/script/parser.mjs +2 -1
- package/node_modules/typebox/package.json +29 -29
- package/npm-shrinkwrap.json +156 -39
- package/openclaw.plugin.json +76 -0
- package/package.json +8 -7
- package/node_modules/audio-buffer/.eslintrc.json +0 -44
- package/node_modules/audio-buffer/.github/workflows/node.js.yml +0 -31
- package/node_modules/audio-buffer/.travis.yml +0 -7
- package/node_modules/audio-buffer/index.js +0 -76
- package/node_modules/audio-buffer/package.json +0 -37
- package/node_modules/audio-buffer/readme.md +0 -56
- package/node_modules/audio-decode/.eslintrc.json +0 -43
- package/node_modules/audio-decode/.travis.yml +0 -13
- package/node_modules/audio-decode/tea.yaml +0 -6
- package/node_modules/audio-decode/test-case.js +0 -11
- package/node_modules/audio-decode/test.js +0 -107
- package/node_modules/node-wav/README.md +0 -35
- package/node_modules/node-wav/file.wav +0 -0
- package/node_modules/node-wav/index.js +0 -291
- package/node_modules/node-wav/package.json +0 -29
- package/node_modules/node-wav/tests/file1.wav +0 -0
- package/node_modules/node-wav/tests/test.js +0 -66
- package/node_modules/node-wav/x.js +0 -12
- package/node_modules/node-wav/x.json +0 -86702
- package/node_modules/node-wav/x.js~ +0 -13
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AAC decoder — FAAD2 compiled to WASM
|
|
3
|
+
* Decodes M4A (MP4/AAC) and raw ADTS streams
|
|
4
|
+
*
|
|
5
|
+
* let { channelData, sampleRate } = await decode(m4abuf)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
let _modP
|
|
9
|
+
|
|
10
|
+
async function getMod() {
|
|
11
|
+
if (_modP) return _modP
|
|
12
|
+
let p = (async () => {
|
|
13
|
+
let createAAC
|
|
14
|
+
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
15
|
+
let m = 'module'
|
|
16
|
+
let { createRequire } = await import(m)
|
|
17
|
+
createAAC = createRequire(import.meta.url)('./src/aac.wasm.cjs')
|
|
18
|
+
} else {
|
|
19
|
+
let mod = await import('./src/aac.wasm.cjs')
|
|
20
|
+
createAAC = mod.default || mod
|
|
21
|
+
}
|
|
22
|
+
return createAAC()
|
|
23
|
+
})()
|
|
24
|
+
_modP = p
|
|
25
|
+
try { return await p }
|
|
26
|
+
catch (e) { _modP = null; throw e }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whole-file decode
|
|
31
|
+
* @param {Uint8Array|ArrayBuffer} src
|
|
32
|
+
* @returns {Promise<{channelData: Float32Array[], sampleRate: number}>}
|
|
33
|
+
*/
|
|
34
|
+
export default async function decode(src) {
|
|
35
|
+
let buf = src instanceof Uint8Array ? src : new Uint8Array(src)
|
|
36
|
+
let dec = await decoder()
|
|
37
|
+
try {
|
|
38
|
+
return dec.decode(buf)
|
|
39
|
+
} finally {
|
|
40
|
+
dec.free()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create decoder instance
|
|
46
|
+
* @returns {Promise<{decode(chunk: Uint8Array): {channelData, sampleRate}, flush(), free()}>}
|
|
47
|
+
*/
|
|
48
|
+
export async function decoder() {
|
|
49
|
+
return new AACDecoder(await getMod())
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const EMPTY = Object.freeze({ channelData: [], sampleRate: 0 })
|
|
53
|
+
|
|
54
|
+
class AACDecoder {
|
|
55
|
+
constructor(mod) {
|
|
56
|
+
this.m = mod
|
|
57
|
+
this.h = null
|
|
58
|
+
this.sr = 0
|
|
59
|
+
this.ch = 0
|
|
60
|
+
this.done = false
|
|
61
|
+
this._ptr = 0
|
|
62
|
+
this._cap = 0
|
|
63
|
+
this._left = null
|
|
64
|
+
this._fileOff = 0 // absolute file offset of _left[0] (M4A streaming)
|
|
65
|
+
this._skip = 0 // bytes to discard from incoming data (M4A streaming, when next frame is past _left)
|
|
66
|
+
this._m4a = null // M4A streaming iterator: { sizes, stco, stsc, idx, ci, sInC, spc, nextOff }
|
|
67
|
+
this._accum = null // Uint8Array[] — M4A header accumulator
|
|
68
|
+
this._accumLen = 0
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
decode(data) {
|
|
72
|
+
if (this.done) throw Error('Decoder already freed')
|
|
73
|
+
if (!data?.length) return EMPTY
|
|
74
|
+
|
|
75
|
+
let buf = data instanceof Uint8Array ? data : new Uint8Array(data)
|
|
76
|
+
|
|
77
|
+
if (this._m4a) return this._feedM4AData(buf)
|
|
78
|
+
if (this.h) return this._decodeADTS(buf)
|
|
79
|
+
// M4A: accumulating moov+mdat header, or first chunk starts with ftyp
|
|
80
|
+
if (this._accum || (buf.length > 8 && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70)) {
|
|
81
|
+
(this._accum ??= []).push(buf)
|
|
82
|
+
this._accumLen += buf.length
|
|
83
|
+
return this._tryM4AInit()
|
|
84
|
+
}
|
|
85
|
+
return this._decodeADTS(buf)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
flush() {
|
|
89
|
+
this._left = null
|
|
90
|
+
return EMPTY
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
free() {
|
|
94
|
+
if (this.done) return
|
|
95
|
+
this.done = true
|
|
96
|
+
if (this.h) {
|
|
97
|
+
this.m._aac_close(this.h)
|
|
98
|
+
this.m._aac_free_buf()
|
|
99
|
+
this.h = null
|
|
100
|
+
}
|
|
101
|
+
if (this._ptr) {
|
|
102
|
+
this.m._free(this._ptr)
|
|
103
|
+
this._ptr = 0
|
|
104
|
+
this._cap = 0
|
|
105
|
+
}
|
|
106
|
+
this._accum = null; this._accumLen = 0
|
|
107
|
+
this._m4a = null; this._left = null
|
|
108
|
+
this._fileOff = 0; this._skip = 0
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_catAccum() {
|
|
112
|
+
if (this._accum.length === 1) return this._accum[0]
|
|
113
|
+
let buf = new Uint8Array(this._accumLen), off = 0
|
|
114
|
+
for (let c of this._accum) { buf.set(c, off); off += c.length }
|
|
115
|
+
return buf
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_tryM4AInit() {
|
|
119
|
+
let buf = this._catAccum()
|
|
120
|
+
let asc = null, stsz = null, stco = null, stsc = null
|
|
121
|
+
|
|
122
|
+
parseBoxes(buf, 0, buf.length, (type, data) => {
|
|
123
|
+
if (type === 'esds') asc = parseEsds(data)
|
|
124
|
+
else if (type === 'stsz') stsz = parseStsz(data)
|
|
125
|
+
else if (type === 'stco') stco = parseStco(data)
|
|
126
|
+
else if (type === 'co64') stco = parseCo64(data)
|
|
127
|
+
else if (type === 'stsc') stsc = parseStsc(data)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
if (!asc || !stsz || !stco?.length) return EMPTY // moov/tables not ready
|
|
131
|
+
|
|
132
|
+
// Init WASM decoder with ASC
|
|
133
|
+
let m = this.m, h = m._aac_create()
|
|
134
|
+
let srP = m._aac_sr_ptr(), chP = m._aac_ch_ptr()
|
|
135
|
+
let ptr = this._alloc(asc.length)
|
|
136
|
+
m.HEAPU8.set(asc, ptr)
|
|
137
|
+
let err = m._aac_init2(h, ptr, asc.length, srP, chP)
|
|
138
|
+
if (err < 0) { m._aac_close(h); throw Error('M4A init failed (code ' + err + ')') }
|
|
139
|
+
this.sr = m.getValue(srP, 'i32')
|
|
140
|
+
this.ch = m.getValue(chP, 'i8')
|
|
141
|
+
if (!this.ch) { m._aac_close(h); throw Error('M4A init: no channels in ASC') }
|
|
142
|
+
this.h = h
|
|
143
|
+
|
|
144
|
+
// Streaming: walk sample tables by absolute file offset so chunk boundaries are irrelevant.
|
|
145
|
+
this._accum = null; this._accumLen = 0
|
|
146
|
+
this._m4a = { sizes: stsz, stco, stsc, idx: 0, ci: 0, sInC: 0, spc: spcAt(0, stsc), nextOff: stco[0] }
|
|
147
|
+
this._left = buf
|
|
148
|
+
this._fileOff = 0
|
|
149
|
+
this._skip = 0
|
|
150
|
+
return this._extractM4A()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
_feedM4AData(buf) {
|
|
154
|
+
if (this._skip > 0) {
|
|
155
|
+
let n = Math.min(this._skip, buf.length)
|
|
156
|
+
this._skip -= n
|
|
157
|
+
this._fileOff += n
|
|
158
|
+
buf = buf.subarray(n)
|
|
159
|
+
if (!buf.length) return EMPTY
|
|
160
|
+
}
|
|
161
|
+
this._left = append(this._left, buf)
|
|
162
|
+
return this._extractM4A()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
_extractM4A() {
|
|
166
|
+
let st = this._m4a, frames = []
|
|
167
|
+
while (st.idx < st.sizes.length) {
|
|
168
|
+
let off = st.nextOff, sz = st.sizes[st.idx]
|
|
169
|
+
let bufOff = off - this._fileOff
|
|
170
|
+
if (bufOff + sz > this._left.length) break
|
|
171
|
+
if (bufOff >= 0) frames.push(this._left.subarray(bufOff, bufOff + sz))
|
|
172
|
+
advanceM4A(st)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (st.idx < st.sizes.length) {
|
|
176
|
+
let nextOff = st.nextOff, end = this._fileOff + this._left.length
|
|
177
|
+
if (nextOff >= end) {
|
|
178
|
+
this._skip = nextOff - end
|
|
179
|
+
this._fileOff = end
|
|
180
|
+
this._left = null
|
|
181
|
+
} else if (nextOff > this._fileOff) {
|
|
182
|
+
this._left = this._left.subarray(nextOff - this._fileOff).slice()
|
|
183
|
+
this._fileOff = nextOff
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
this._left = null
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return frames.length ? this._feedFrames(frames) : EMPTY
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
_alloc(len) {
|
|
193
|
+
if (len > this._cap) {
|
|
194
|
+
if (this._ptr) this.m._free(this._ptr)
|
|
195
|
+
this._cap = len
|
|
196
|
+
this._ptr = this.m._malloc(len)
|
|
197
|
+
}
|
|
198
|
+
return this._ptr
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
_decodeADTS(buf) {
|
|
202
|
+
let m = this.m
|
|
203
|
+
|
|
204
|
+
if (this._left) { buf = append(this._left, buf); this._left = null }
|
|
205
|
+
|
|
206
|
+
if (!this.h) {
|
|
207
|
+
if (buf.length < 7) { this._left = buf.slice(); return EMPTY }
|
|
208
|
+
let h = m._aac_create()
|
|
209
|
+
let srP = m._aac_sr_ptr(), chP = m._aac_ch_ptr()
|
|
210
|
+
let ptr = this._alloc(buf.length)
|
|
211
|
+
m.HEAPU8.set(buf, ptr)
|
|
212
|
+
let consumed = m._aac_init(h, ptr, buf.length, srP, chP)
|
|
213
|
+
if (consumed < 0) { m._aac_close(h); throw Error('ADTS init failed (code ' + consumed + ')') }
|
|
214
|
+
this.sr = m.getValue(srP, 'i32')
|
|
215
|
+
this.ch = m.getValue(chP, 'i8')
|
|
216
|
+
if (!this.ch) {
|
|
217
|
+
// not enough data to detect channels — buffer for next call
|
|
218
|
+
m._aac_close(h)
|
|
219
|
+
this._left = buf.length < 8192 ? buf.slice() : null
|
|
220
|
+
return EMPTY
|
|
221
|
+
}
|
|
222
|
+
this.h = h
|
|
223
|
+
buf = buf.subarray(consumed)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// extract complete ADTS frames only — never feed partial data to FAAD2
|
|
227
|
+
let frames = [], pos = 0
|
|
228
|
+
while (pos + 6 < buf.length) {
|
|
229
|
+
if (buf[pos] !== 0xFF || (buf[pos + 1] & 0xF6) !== 0xF0) { pos++; continue }
|
|
230
|
+
let flen = ((buf[pos + 3] & 0x03) << 11) | (buf[pos + 4] << 3) | (buf[pos + 5] >> 5)
|
|
231
|
+
if (flen < 7 || pos + flen > buf.length) break
|
|
232
|
+
frames.push(buf.subarray(pos, pos + flen))
|
|
233
|
+
pos += flen
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (pos < buf.length) {
|
|
237
|
+
let left = buf.subarray(pos)
|
|
238
|
+
this._left = left.length < 8192 ? left.slice() : null
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!frames.length) return EMPTY
|
|
242
|
+
return this._feedFrames(frames)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
_feedFrames(frames) {
|
|
246
|
+
let m = this.m, h = this.h
|
|
247
|
+
let chunks = [], totalPerCh = 0, channels = this.ch, errors = 0
|
|
248
|
+
|
|
249
|
+
for (let frame of frames) {
|
|
250
|
+
let ptr = this._alloc(frame.length)
|
|
251
|
+
m.HEAPU8.set(frame, ptr)
|
|
252
|
+
let out = m._aac_decode(h, ptr, frame.length)
|
|
253
|
+
if (!out) { errors++; continue }
|
|
254
|
+
|
|
255
|
+
let n = m._aac_samples()
|
|
256
|
+
let sr = m._aac_samplerate()
|
|
257
|
+
if (sr) this.sr = sr
|
|
258
|
+
let ch = m._aac_channels()
|
|
259
|
+
if (ch) channels = ch
|
|
260
|
+
|
|
261
|
+
let spc = n / channels
|
|
262
|
+
chunks.push({ data: new Float32Array(m.HEAPF32.buffer, out, n).slice(), ch: channels, spc })
|
|
263
|
+
totalPerCh += spc
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!totalPerCh) return EMPTY
|
|
267
|
+
|
|
268
|
+
let channelData = Array.from({ length: channels }, () => new Float32Array(totalPerCh))
|
|
269
|
+
let pos = 0
|
|
270
|
+
for (let { data, ch, spc } of chunks) {
|
|
271
|
+
for (let c = 0; c < ch; c++) {
|
|
272
|
+
let out = channelData[c]
|
|
273
|
+
for (let s = 0; s < spc; s++) out[pos + s] = data[s * ch + c]
|
|
274
|
+
}
|
|
275
|
+
pos += spc
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return { channelData, sampleRate: this.sr, errors }
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
// ===== M4A demuxer =====
|
|
284
|
+
|
|
285
|
+
function append(left, buf) {
|
|
286
|
+
if (!left?.length) return buf.slice()
|
|
287
|
+
let merged = new Uint8Array(left.length + buf.length)
|
|
288
|
+
merged.set(left); merged.set(buf, left.length)
|
|
289
|
+
return merged
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const CONTAINERS = new Set(['moov', 'trak', 'mdia', 'minf', 'stbl', 'udta', 'meta', 'edts', 'sinf'])
|
|
293
|
+
|
|
294
|
+
function parseBoxes(buf, start, end, cb) {
|
|
295
|
+
let off = start
|
|
296
|
+
while (off < end - 8) {
|
|
297
|
+
let size = r32(buf, off)
|
|
298
|
+
let type = String.fromCharCode(buf[off + 4], buf[off + 5], buf[off + 6], buf[off + 7])
|
|
299
|
+
|
|
300
|
+
if (size === 0) size = end - off
|
|
301
|
+
else if (size === 1 && off + 16 <= end) {
|
|
302
|
+
size = r32(buf, off + 12)
|
|
303
|
+
if (size < 16) break
|
|
304
|
+
} else if (size < 8) break
|
|
305
|
+
|
|
306
|
+
// skip mdat fast — the raw frames don't interest us here
|
|
307
|
+
if (type === 'mdat') { off += size; continue }
|
|
308
|
+
// truncated non-mdat box: tables would be garbage — wait for more data
|
|
309
|
+
if (off + size > end) break
|
|
310
|
+
|
|
311
|
+
let bodyOff = off + 8
|
|
312
|
+
if (type === 'stsd') parseSampleDesc(buf, bodyOff, size - 8, cb)
|
|
313
|
+
else if (CONTAINERS.has(type)) parseBoxes(buf, bodyOff + (type === 'meta' ? 4 : 0), off + size, cb)
|
|
314
|
+
else cb(type, buf.subarray(bodyOff, off + size))
|
|
315
|
+
|
|
316
|
+
off += size
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function parseSampleDesc(buf, off, len, cb) {
|
|
321
|
+
let entries = r32(buf, off + 4), pos = off + 8
|
|
322
|
+
for (let i = 0; i < entries && pos < off + len; i++) {
|
|
323
|
+
let eSize = r32(buf, pos)
|
|
324
|
+
let eType = String.fromCharCode(buf[pos + 4], buf[pos + 5], buf[pos + 6], buf[pos + 7])
|
|
325
|
+
if (eType === 'mp4a' && eSize > 36) parseBoxes(buf, pos + 36, pos + eSize, cb)
|
|
326
|
+
pos += eSize
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function parseEsds(data) {
|
|
331
|
+
let off = 4
|
|
332
|
+
while (off < data.length - 2) {
|
|
333
|
+
let tag = data[off++], len = 0, b
|
|
334
|
+
do { b = data[off++]; len = (len << 7) | (b & 0x7f) } while (b & 0x80 && off < data.length)
|
|
335
|
+
if (tag === 0x03) off += 3
|
|
336
|
+
else if (tag === 0x04) off += 13
|
|
337
|
+
else if (tag === 0x05) return data.subarray(off, off + len)
|
|
338
|
+
else off += len
|
|
339
|
+
}
|
|
340
|
+
return null
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function parseStsz(data) {
|
|
344
|
+
let sz = r32(data, 4), n = r32(data, 8)
|
|
345
|
+
if (sz) return Array(n).fill(sz)
|
|
346
|
+
let sizes = new Array(n)
|
|
347
|
+
for (let i = 0; i < n; i++) sizes[i] = r32(data, 12 + i * 4)
|
|
348
|
+
return sizes
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function parseStco(data) {
|
|
352
|
+
let n = r32(data, 4), o = new Array(n)
|
|
353
|
+
for (let i = 0; i < n; i++) o[i] = r32(data, 8 + i * 4)
|
|
354
|
+
return o
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function parseCo64(data) {
|
|
358
|
+
let n = r32(data, 4), o = new Array(n)
|
|
359
|
+
for (let i = 0; i < n; i++) o[i] = r32(data, 8 + i * 8 + 4)
|
|
360
|
+
return o
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function parseStsc(data) {
|
|
364
|
+
let n = r32(data, 4), e = new Array(n)
|
|
365
|
+
for (let i = 0; i < n; i++) e[i] = { first: r32(data, 8 + i * 12), spc: r32(data, 12 + i * 12) }
|
|
366
|
+
return e
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function spcAt(ci, stsc) {
|
|
370
|
+
if (!stsc?.length) return 1
|
|
371
|
+
let spc = 1, cn = ci + 1
|
|
372
|
+
for (let j = stsc.length - 1; j >= 0; j--)
|
|
373
|
+
if (cn >= stsc[j].first) { spc = stsc[j].spc; break }
|
|
374
|
+
return spc
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function advanceM4A(st) {
|
|
378
|
+
st.nextOff += st.sizes[st.idx]
|
|
379
|
+
st.idx++
|
|
380
|
+
st.sInC++
|
|
381
|
+
if (st.sInC >= st.spc && st.ci + 1 < st.stco.length) {
|
|
382
|
+
st.ci++
|
|
383
|
+
st.sInC = 0
|
|
384
|
+
st.spc = spcAt(st.ci, st.stsc)
|
|
385
|
+
st.nextOff = st.stco[st.ci]
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function r32(buf, off) {
|
|
390
|
+
return (buf[off] << 24 | buf[off + 1] << 16 | buf[off + 2] << 8 | buf[off + 3]) >>> 0
|
|
391
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@audio/decode-aac",
|
|
3
|
+
"version": "1.1.3",
|
|
4
|
+
"description": "Decode AAC/M4A audio via FAAD2 WASM",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "decode-aac.js",
|
|
7
|
+
"types": "decode-aac.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./decode-aac.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "bash build.sh",
|
|
17
|
+
"prepack": "npm run build",
|
|
18
|
+
"test": "node test.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"decode-aac.js",
|
|
22
|
+
"decode-aac.d.ts",
|
|
23
|
+
"src/aac.wasm.cjs",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"aac",
|
|
28
|
+
"m4a",
|
|
29
|
+
"mp4",
|
|
30
|
+
"audio",
|
|
31
|
+
"decode",
|
|
32
|
+
"decoder",
|
|
33
|
+
"wasm",
|
|
34
|
+
"faad2"
|
|
35
|
+
],
|
|
36
|
+
"license": "GPL-2.0",
|
|
37
|
+
"author": "audiojs",
|
|
38
|
+
"homepage": "https://github.com/audiojs/decode-aac#readme",
|
|
39
|
+
"bugs": "https://github.com/audiojs/decode-aac/issues",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/audiojs/decode-aac.git"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=16"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 audiojs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @audio/decode-aiff
|
|
2
|
+
|
|
3
|
+
Decode AIFF and AIFF-C audio to PCM float samples.<br>
|
|
4
|
+
Part of [audio-decode](https://github.com/audiojs/audio-decode).
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
npm i @audio/decode-aiff
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import decode from '@audio/decode-aiff'
|
|
16
|
+
|
|
17
|
+
let { channelData, sampleRate } = await decode(aiffBuffer)
|
|
18
|
+
// channelData: Float32Array[] (one per channel)
|
|
19
|
+
// sampleRate: number
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Streaming
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
import { decoder } from '@audio/decode-aiff'
|
|
26
|
+
|
|
27
|
+
let dec = await decoder()
|
|
28
|
+
let result = dec.decode(chunk)
|
|
29
|
+
dec.free()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
### `decode(src): Promise<AudioData>`
|
|
35
|
+
|
|
36
|
+
Whole-file decode. Accepts `Uint8Array` or `ArrayBuffer`.
|
|
37
|
+
|
|
38
|
+
### `decoder(): Promise<AIFFDecoder>`
|
|
39
|
+
|
|
40
|
+
Creates a decoder instance.
|
|
41
|
+
|
|
42
|
+
- **`dec.decode(data)`** — decode chunk, returns `{ channelData, sampleRate }`
|
|
43
|
+
- **`dec.flush()`** — flush (returns empty — AIFF is stateless)
|
|
44
|
+
- **`dec.free()`** — release resources
|
|
45
|
+
|
|
46
|
+
## Formats
|
|
47
|
+
|
|
48
|
+
- AIFF — 8, 16, 24, 32-bit signed integer PCM (big-endian)
|
|
49
|
+
- AIFF-C — `NONE`/`twos` (BE PCM), `sowt` (LE PCM), `fl32`/`fl64` (float), `alaw`, `ulaw`
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
|
|
53
|
+
MIT — [krishnized](https://github.com/krishnized/license)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface AudioData {
|
|
2
|
+
channelData: Float32Array[];
|
|
3
|
+
sampleRate: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface AIFFDecoder {
|
|
7
|
+
decode(data: Uint8Array): AudioData;
|
|
8
|
+
flush(): AudioData;
|
|
9
|
+
free(): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Decode AIFF/AIFF-C audio buffer to PCM samples */
|
|
13
|
+
export default function decode(src: ArrayBuffer | Uint8Array): Promise<AudioData>;
|
|
14
|
+
|
|
15
|
+
/** Create decoder instance */
|
|
16
|
+
export function decoder(): Promise<AIFFDecoder>;
|