@openclaw/whatsapp 2026.5.28 → 2026.5.31-beta.1

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 (157) hide show
  1. package/dist/{access-control-Z0fYaWrx.js → access-control-C53zKYSN.js} +1 -1
  2. package/dist/{accounts-BMGM1RtF.js → accounts-DgViSyJx.js} +1 -0
  3. package/dist/{action-runtime-BdhkGtaP.js → action-runtime-Cyp5GNIT.js} +2 -2
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/action-runtime.runtime.js +1 -1
  6. package/dist/api.js +9 -9
  7. package/dist/{approval-handler.runtime-C25wPeBf.js → approval-handler.runtime-BVmOu6x1.js} +1 -2
  8. package/dist/{auth-store-BrKb0mwT.js → auth-store-CZ22aNcV.js} +4 -2
  9. package/dist/{channel-D3y4A5Dd.js → channel-DA2BAIo5.js} +17 -64
  10. package/dist/channel-config-api.js +1 -1
  11. package/dist/channel-plugin-api.js +1 -1
  12. package/dist/{channel-react-action-Cd2qkLqp.js → channel-react-action-zvbaCnGe.js} +3 -3
  13. package/dist/{channel.runtime-C228XUjs.js → channel.runtime-Q1LZDB5s.js} +4 -4
  14. package/dist/{channel.setup-BJQyTUUP.js → channel.setup-DHXOo4h5.js} +2 -3
  15. package/dist/{config-schema-CsNDlDpL.js → config-schema-CROZuhT-.js} +16 -0
  16. package/dist/{connection-controller-mpPGmqGq.js → connection-controller-Bnm4INld.js} +2 -2
  17. package/dist/contract-api.js +1 -1
  18. package/dist/light-runtime-api.js +1 -1
  19. package/dist/{login-CE4UYnyO.js → login-2fuBM7Je.js} +4 -4
  20. package/dist/{login-qr-LBvhEes5.js → login-qr-B1o7GFy8.js} +10 -6
  21. package/dist/login-qr-runtime.js +1 -1
  22. package/dist/{monitor-Ccph7Y8M.js → monitor-BVRq04Dt.js} +36 -18
  23. package/dist/runtime-api.js +7 -7
  24. package/dist/{send-C4LG-Cl6.js → send-DSlVXKL_.js} +53 -41
  25. package/dist/{send-api-C66vkRl9.js → send-api-Bjn-h80j.js} +3 -2
  26. package/dist/{session-D8UW2Vbn.js → session-DyGWNClj.js} +1 -1
  27. package/dist/{setup-core-DpfT4K-2.js → setup-core-OvPMaAsx.js} +4 -4
  28. package/dist/{setup-finalize-CFnxX7la.js → setup-finalize-Dk23pfKc.js} +3 -3
  29. package/dist/setup-plugin-api.js +1 -1
  30. package/dist/{setup-surface-DRsmp0ZS.js → setup-surface-F-jVrH8u.js} +3 -3
  31. package/node_modules/@audio/decode-aac/LICENSE +9 -0
  32. package/node_modules/@audio/decode-aac/README.md +60 -0
  33. package/node_modules/@audio/decode-aac/decode-aac.d.ts +16 -0
  34. package/node_modules/@audio/decode-aac/decode-aac.js +391 -0
  35. package/node_modules/@audio/decode-aac/package.json +47 -0
  36. package/node_modules/@audio/decode-aac/src/aac.wasm.cjs +0 -0
  37. package/node_modules/@audio/decode-aiff/LICENSE +21 -0
  38. package/node_modules/@audio/decode-aiff/README.md +53 -0
  39. package/node_modules/@audio/decode-aiff/decode-aiff.d.ts +16 -0
  40. package/node_modules/@audio/decode-aiff/decode-aiff.js +583 -0
  41. package/node_modules/@audio/decode-aiff/package.json +42 -0
  42. package/node_modules/@audio/decode-amr/LICENSE +191 -0
  43. package/node_modules/@audio/decode-amr/README.md +65 -0
  44. package/node_modules/@audio/decode-amr/decode-amr.d.ts +16 -0
  45. package/node_modules/@audio/decode-amr/decode-amr.js +159 -0
  46. package/node_modules/@audio/decode-amr/package.json +48 -0
  47. package/node_modules/@audio/decode-amr/src/amr.wasm.cjs +0 -0
  48. package/node_modules/@audio/decode-caf/LICENSE +21 -0
  49. package/node_modules/@audio/decode-caf/README.md +55 -0
  50. package/node_modules/@audio/decode-caf/decode-caf.d.ts +16 -0
  51. package/node_modules/@audio/decode-caf/decode-caf.js +190 -0
  52. package/node_modules/@audio/decode-caf/package.json +43 -0
  53. package/node_modules/{audio-buffer → @audio/decode-flac}/LICENSE +5 -2
  54. package/node_modules/@audio/decode-flac/README.md +23 -0
  55. package/node_modules/@audio/decode-flac/decode-flac.d.ts +16 -0
  56. package/node_modules/@audio/decode-flac/decode-flac.js +2994 -0
  57. package/node_modules/@audio/decode-flac/meta.js +115 -0
  58. package/node_modules/@audio/decode-flac/package.json +49 -0
  59. package/node_modules/@audio/decode-mp3/LICENSE +25 -0
  60. package/node_modules/@audio/decode-mp3/README.md +23 -0
  61. package/node_modules/@audio/decode-mp3/decode-mp3.d.ts +16 -0
  62. package/node_modules/@audio/decode-mp3/decode-mp3.js +868 -0
  63. package/node_modules/@audio/decode-mp3/meta.js +143 -0
  64. package/node_modules/@audio/decode-mp3/package.json +50 -0
  65. package/node_modules/@audio/decode-opus/LICENSE +25 -0
  66. package/node_modules/@audio/decode-opus/README.md +23 -0
  67. package/node_modules/@audio/decode-opus/decode-opus.d.ts +16 -0
  68. package/node_modules/@audio/decode-opus/decode-opus.js +3179 -0
  69. package/node_modules/@audio/decode-opus/package.json +47 -0
  70. package/node_modules/@audio/decode-qoa/LICENSE +25 -0
  71. package/node_modules/@audio/decode-qoa/README.md +21 -0
  72. package/node_modules/@audio/decode-qoa/decode-qoa.d.ts +16 -0
  73. package/node_modules/@audio/decode-qoa/decode-qoa.js +278 -0
  74. package/node_modules/@audio/decode-qoa/package.json +46 -0
  75. package/node_modules/@audio/decode-vorbis/LICENSE +25 -0
  76. package/node_modules/@audio/decode-vorbis/README.md +23 -0
  77. package/node_modules/@audio/decode-vorbis/decode-vorbis.d.ts +16 -0
  78. package/node_modules/@audio/decode-vorbis/decode-vorbis.js +2984 -0
  79. package/node_modules/@audio/decode-vorbis/package.json +47 -0
  80. package/node_modules/@audio/decode-wav/decode-wav.js +104 -0
  81. package/node_modules/@audio/decode-wav/meta.js +114 -0
  82. package/node_modules/@audio/decode-wav/package.json +27 -0
  83. package/node_modules/@audio/decode-webm/LICENSE +21 -0
  84. package/node_modules/@audio/decode-webm/README.md +57 -0
  85. package/node_modules/@audio/decode-webm/decode-webm.d.ts +16 -0
  86. package/node_modules/@audio/decode-webm/decode-webm.js +3964 -0
  87. package/node_modules/@audio/decode-webm/package.json +51 -0
  88. package/node_modules/@audio/decode-wma/LICENSE +12 -0
  89. package/node_modules/@audio/decode-wma/README.md +76 -0
  90. package/node_modules/@audio/decode-wma/decode-wma.d.ts +33 -0
  91. package/node_modules/@audio/decode-wma/decode-wma.js +525 -0
  92. package/node_modules/@audio/decode-wma/package.json +47 -0
  93. package/node_modules/@audio/decode-wma/src/wma.wasm.cjs +0 -0
  94. package/node_modules/audio-decode/.claude/settings.json +204 -0
  95. package/node_modules/audio-decode/.github/workflows/test.js.yml +11 -20
  96. package/node_modules/audio-decode/.gitmodules +9 -0
  97. package/node_modules/audio-decode/audio-decode.d.ts +48 -10
  98. package/node_modules/audio-decode/audio-decode.js +193 -77
  99. package/node_modules/audio-decode/meta.js +11 -0
  100. package/node_modules/audio-decode/package.json +49 -21
  101. package/node_modules/audio-decode/readme.md +129 -29
  102. package/node_modules/audio-decode/stream.d.ts +15 -0
  103. package/node_modules/audio-decode/stream.js +1 -0
  104. package/node_modules/audio-decode/test.html +29 -10
  105. package/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +2 -2
  106. package/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -1
  107. package/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -1
  108. package/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +1 -1
  109. package/node_modules/lru-cache/dist/commonjs/index.d.ts +2 -2
  110. package/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
  111. package/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
  112. package/node_modules/lru-cache/dist/commonjs/index.min.js.map +1 -1
  113. package/node_modules/lru-cache/dist/commonjs/node/index.d.ts +2 -2
  114. package/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -1
  115. package/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -1
  116. package/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +1 -1
  117. package/node_modules/lru-cache/dist/esm/browser/index.d.ts +2 -2
  118. package/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -1
  119. package/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -1
  120. package/node_modules/lru-cache/dist/esm/browser/index.min.js.map +1 -1
  121. package/node_modules/lru-cache/dist/esm/index.d.ts +2 -2
  122. package/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
  123. package/node_modules/lru-cache/dist/esm/index.js.map +1 -1
  124. package/node_modules/lru-cache/dist/esm/index.min.js.map +1 -1
  125. package/node_modules/lru-cache/dist/esm/node/index.d.ts +2 -2
  126. package/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -1
  127. package/node_modules/lru-cache/dist/esm/node/index.js.map +1 -1
  128. package/node_modules/lru-cache/dist/esm/node/index.min.js.map +1 -1
  129. package/node_modules/lru-cache/package.json +1 -1
  130. package/node_modules/typebox/build/type/script/mapping.d.mts +5 -2
  131. package/node_modules/typebox/build/type/script/mapping.mjs +15 -8
  132. package/node_modules/typebox/build/type/script/parser.d.mts +3 -1
  133. package/node_modules/typebox/build/type/script/parser.mjs +2 -1
  134. package/node_modules/typebox/package.json +29 -29
  135. package/npm-shrinkwrap.json +156 -39
  136. package/openclaw.plugin.json +76 -0
  137. package/package.json +6 -6
  138. package/node_modules/audio-buffer/.eslintrc.json +0 -44
  139. package/node_modules/audio-buffer/.github/workflows/node.js.yml +0 -31
  140. package/node_modules/audio-buffer/.travis.yml +0 -7
  141. package/node_modules/audio-buffer/index.js +0 -76
  142. package/node_modules/audio-buffer/package.json +0 -37
  143. package/node_modules/audio-buffer/readme.md +0 -56
  144. package/node_modules/audio-decode/.eslintrc.json +0 -43
  145. package/node_modules/audio-decode/.travis.yml +0 -13
  146. package/node_modules/audio-decode/tea.yaml +0 -6
  147. package/node_modules/audio-decode/test-case.js +0 -11
  148. package/node_modules/audio-decode/test.js +0 -107
  149. package/node_modules/node-wav/README.md +0 -35
  150. package/node_modules/node-wav/file.wav +0 -0
  151. package/node_modules/node-wav/index.js +0 -291
  152. package/node_modules/node-wav/package.json +0 -29
  153. package/node_modules/node-wav/tests/file1.wav +0 -0
  154. package/node_modules/node-wav/tests/test.js +0 -66
  155. package/node_modules/node-wav/x.js +0 -12
  156. package/node_modules/node-wav/x.json +0 -86702
  157. package/node_modules/node-wav/x.js~ +0 -13
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@audio/decode-webm",
3
+ "version": "1.2.1",
4
+ "description": "Decode WebM audio (Opus, Vorbis) to PCM samples",
5
+ "type": "module",
6
+ "main": "decode-webm.js",
7
+ "types": "decode-webm.d.ts",
8
+ "exports": {
9
+ ".": "./decode-webm.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "files": [
13
+ "decode-webm.js",
14
+ "decode-webm.d.ts",
15
+ "LICENSE"
16
+ ],
17
+ "dependencies": {
18
+ "@wasm-audio-decoders/ogg-vorbis": "^0.1.20",
19
+ "opus-decoder": "^0.7.6"
20
+ },
21
+ "keywords": [
22
+ "webm",
23
+ "matroska",
24
+ "ebml",
25
+ "opus",
26
+ "vorbis",
27
+ "audio",
28
+ "decode",
29
+ "decoder",
30
+ "pcm"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "license": "MIT",
36
+ "author": "audiojs",
37
+ "homepage": "https://github.com/audiojs/decode-webm#readme",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/audiojs/decode-webm.git"
41
+ },
42
+ "engines": {
43
+ "node": ">=16"
44
+ },
45
+ "bugs": "https://github.com/audiojs/decode-webm/issues",
46
+ "scripts": {
47
+ "build": "bash build.sh",
48
+ "prepack": "npm run build",
49
+ "test": "node test.js"
50
+ }
51
+ }
@@ -0,0 +1,12 @@
1
+ wma-decode - WMA audio decoder
2
+ Copyright (c) 2025 audiojs
3
+
4
+ This library is free software; you can redistribute it and/or modify it
5
+ under the terms of the GNU Lesser General Public License as published by
6
+ the Free Software Foundation; either version 2.1 of the License, or (at
7
+ your option) any later version.
8
+
9
+ This library is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12
+ License for more details.
@@ -0,0 +1,76 @@
1
+ # @audio/decode-wma
2
+
3
+ Decode WMA audio to PCM float samples. ASF demuxer in pure JS, WMA decoding via [RockBox](https://www.rockbox.org/) fixed-point decoder compiled to WASM (70 KB).
4
+
5
+ Part of [audio-decode](https://github.com/audiojs/audio-decode).
6
+
7
+ ## Install
8
+
9
+ ```
10
+ npm i @audio/decode-wma
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```js
16
+ import decode from '@audio/decode-wma'
17
+
18
+ let { channelData, sampleRate } = await decode(wmaBuffer)
19
+ ```
20
+
21
+ ### Streaming
22
+
23
+ ```js
24
+ import { decoder } from '@audio/decode-wma'
25
+
26
+ let dec = await decoder()
27
+ let result = dec.decode(chunk)
28
+ dec.free()
29
+ ```
30
+
31
+ ### ASF demuxer only
32
+
33
+ ```js
34
+ import { demuxASF } from '@audio/decode-wma'
35
+
36
+ let { channels, sampleRate, bitRate, packets } = demuxASF(buffer)
37
+ ```
38
+
39
+ ## API
40
+
41
+ ### `decode(src): Promise<AudioData>`
42
+
43
+ Whole-file decode. Accepts `Uint8Array` or `ArrayBuffer`.
44
+
45
+ ### `decoder(): Promise<WMADecoder>`
46
+
47
+ Creates a decoder instance.
48
+
49
+ - **`dec.decode(data)`** — decode chunk, returns `{ channelData, sampleRate }`
50
+ - **`dec.flush()`** — flush (returns empty)
51
+ - **`dec.free()`** — release WASM memory
52
+
53
+ ### `demuxASF(buf): ASFInfo`
54
+
55
+ Parse ASF container without decoding. Returns stream properties and raw packets.
56
+
57
+ ## Formats
58
+
59
+ - WMA v1 (0x0160)
60
+ - WMA v2 (0x0161)
61
+
62
+ WMA Pro and Lossless are not supported. An FFmpeg-based build is available via `build-ffmpeg.sh` for those formats.
63
+
64
+ ## Building WASM
65
+
66
+ ```
67
+ npm run build
68
+ ```
69
+
70
+ RockBox source is included in `lib/rockbox-wma/` (3 files, 152 KB).
71
+
72
+ ## License
73
+
74
+ GPL-2.0+ (RockBox)
75
+
76
+ <a href="https://github.com/krishnized/license/">ॐ</a>
@@ -0,0 +1,33 @@
1
+ interface AudioData {
2
+ channelData: Float32Array[];
3
+ sampleRate: number;
4
+ }
5
+
6
+ interface WmaDecoder {
7
+ decode(data: Uint8Array): AudioData;
8
+ flush(): AudioData;
9
+ free(): void;
10
+ }
11
+
12
+ /** Decode WMA audio buffer to PCM samples */
13
+ export default function decode(src: ArrayBuffer | Uint8Array): Promise<AudioData>;
14
+
15
+ /** Create streaming decoder instance */
16
+ export function decoder(): Promise<WmaDecoder>;
17
+
18
+ /** Parse ASF data packet, extract compressed audio payloads */
19
+ export function parsePacket(pkt: Uint8Array, packetSize: number): Uint8Array[];
20
+
21
+ /** Parse ASF container, extract audio properties and raw packets */
22
+ export function demuxASF(buf: Uint8Array): {
23
+ channels: number;
24
+ sampleRate: number;
25
+ bitRate: number;
26
+ blockAlign: number;
27
+ bitsPerSample: number;
28
+ formatTag: number;
29
+ codecData: Uint8Array | null;
30
+ duration: number;
31
+ packetSize: number;
32
+ packets: Uint8Array[];
33
+ };
@@ -0,0 +1,525 @@
1
+ /**
2
+ * WMA decoder — ASF demuxer (pure JS) + RockBox wmadec (WASM)
3
+ * Decodes WMA v1/v2 in ASF containers
4
+ *
5
+ * let { channelData, sampleRate } = await decode(wmabuf)
6
+ */
7
+
8
+ const EMPTY = Object.freeze({ channelData: [], sampleRate: 0 })
9
+
10
+ // ASF GUIDs (16 bytes each, little-endian)
11
+ const GUID = {
12
+ header: [0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c],
13
+ fileProps: [0xa1,0xdc,0xab,0x8c,0x47,0xa9,0xcf,0x11,0x8e,0xe4,0x00,0xc0,0x0c,0x20,0x53,0x65],
14
+ streamProps: [0x91,0x07,0xdc,0xb7,0xb7,0xa9,0xcf,0x11,0x8e,0xe6,0x00,0xc0,0x0c,0x20,0x53,0x65],
15
+ audioMedia: [0x40,0x9e,0x69,0xf8,0x4d,0x5b,0xcf,0x11,0xa8,0xfd,0x00,0x80,0x5f,0x5c,0x44,0x2b],
16
+ data: [0x36,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c],
17
+ headerExt: [0xb5,0x03,0xbf,0x5f,0x2e,0xa9,0xcf,0x11,0x8e,0xe3,0x00,0xc0,0x0c,0x20,0x53,0x65],
18
+ }
19
+
20
+ function guidEq(buf, off, guid) {
21
+ for (let i = 0; i < 16; i++) if (buf[off + i] !== guid[i]) return false
22
+ return true
23
+ }
24
+
25
+ // Little-endian readers
26
+ function u16(b, o) { return b[o] | (b[o + 1] << 8) }
27
+ function u32(b, o) { return (b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24)) >>> 0 }
28
+ function u64(b, o) {
29
+ // JS safe up to 2^53; read low 32 + high 32
30
+ let lo = u32(b, o), hi = u32(b, o + 4)
31
+ return hi * 0x100000000 + lo
32
+ }
33
+
34
+ /**
35
+ * Parse ASF container — extract audio stream properties + data packets
36
+ * @param {Uint8Array} buf
37
+ * @returns {{ channels, sampleRate, bitRate, blockAlign, bitsPerSample, formatTag, codecData, duration, packetSize, packets }}
38
+ */
39
+ export function demuxASF(buf) {
40
+ if (!(buf instanceof Uint8Array)) buf = new Uint8Array(buf)
41
+ if (buf.length < 30) throw Error('Not an ASF/WMA file')
42
+
43
+ // Verify ASF Header Object GUID
44
+ if (!guidEq(buf, 0, GUID.header)) throw Error('Not an ASF/WMA file')
45
+
46
+ let headerSize = u64(buf, 16)
47
+ let numObjects = u32(buf, 24)
48
+ // reserved1(1) + reserved2(1) at offset 28-29
49
+
50
+ let audio = null // WAVEFORMATEX fields
51
+ let packetSize = 0
52
+ let duration = 0 // in seconds
53
+ let datOff = 0 // data object offset
54
+ let datSize = 0 // data object total size
55
+ let totalPackets = 0
56
+
57
+ // Parse header sub-objects
58
+ let pos = 30
59
+ let headerEnd = Math.min(Number(headerSize), buf.length)
60
+ for (let i = 0; i < numObjects && pos < headerEnd - 24; i++) {
61
+ let objSize = u64(buf, pos + 16)
62
+ if (objSize < 24) break
63
+ let objEnd = pos + Math.min(Number(objSize), headerEnd - pos)
64
+
65
+ if (guidEq(buf, pos, GUID.streamProps)) {
66
+ audio = parseStreamProps(buf, pos + 24, objEnd) || audio
67
+ } else if (guidEq(buf, pos, GUID.fileProps)) {
68
+ let fp = parseFileProps(buf, pos + 24, objEnd)
69
+ if (fp) { packetSize = fp.packetSize; duration = fp.duration }
70
+ } else if (guidEq(buf, pos, GUID.headerExt)) {
71
+ // Header Extension Object — nested sub-objects skipped (no metadata needed for decode)
72
+ }
73
+
74
+ pos = objEnd
75
+ }
76
+
77
+ if (!audio) throw Error('No audio stream in ASF')
78
+
79
+ // Find Data Object after header
80
+ pos = Number(headerSize)
81
+ if (pos + 50 <= buf.length && guidEq(buf, pos, GUID.data)) {
82
+ datSize = u64(buf, pos + 16)
83
+ // fileId(16) + totalPackets(8) + reserved(2) = 26 bytes after object header
84
+ totalPackets = u64(buf, pos + 24 + 16)
85
+ datOff = pos + 24 + 26 // start of packet data
86
+ }
87
+
88
+ // Extract packets
89
+ let packets = []
90
+ if (datOff && packetSize > 0) {
91
+ let datEnd = Math.min(pos + Number(datSize), buf.length)
92
+ let ppos = datOff
93
+ while (ppos + packetSize <= datEnd) {
94
+ packets.push(buf.subarray(ppos, ppos + packetSize))
95
+ ppos += packetSize
96
+ }
97
+ } else if (datOff && totalPackets > 0) {
98
+ // Variable-size packets — fallback: treat remaining data as one blob
99
+ let datEnd = Math.min(pos + Number(datSize), buf.length)
100
+ if (datOff < datEnd) packets.push(buf.subarray(datOff, datEnd))
101
+ }
102
+
103
+ return {
104
+ channels: audio.channels,
105
+ sampleRate: audio.sampleRate,
106
+ bitRate: audio.avgBytesPerSec * 8,
107
+ blockAlign: audio.blockAlign,
108
+ bitsPerSample: audio.bitsPerSample,
109
+ formatTag: audio.formatTag,
110
+ codecData: audio.codecData,
111
+ duration,
112
+ packetSize,
113
+ packets
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Parse Stream Properties Object body
119
+ * Returns audio WAVEFORMATEX fields if this is an audio stream, null otherwise
120
+ */
121
+ function parseStreamProps(buf, start, end) {
122
+ // Stream Type GUID(16) + Error Correction Type GUID(16) + Time Offset(8)
123
+ // + Type-Specific Data Length(4) + Error Correction Data Length(4)
124
+ // + Flags(2) + Reserved(4)
125
+ if (start + 54 > end) return null
126
+
127
+ // Check that stream type is Audio Media
128
+ if (!guidEq(buf, start, GUID.audioMedia)) return null
129
+
130
+ // flags(2) + reserved(4) = 6 bytes after type/ec data lengths
131
+ let waveOff = start + 54
132
+
133
+ if (waveOff + 18 > end) return null
134
+
135
+ // WAVEFORMATEX
136
+ let formatTag = u16(buf, waveOff)
137
+ let channels = u16(buf, waveOff + 2)
138
+ let sampleRate = u32(buf, waveOff + 4)
139
+ let avgBytesPerSec = u32(buf, waveOff + 8)
140
+ let blockAlign = u16(buf, waveOff + 12)
141
+ let bitsPerSample = u16(buf, waveOff + 14)
142
+ let cbSize = u16(buf, waveOff + 16)
143
+
144
+ // Codec-specific data follows WAVEFORMATEX
145
+ let codecData = null
146
+ if (cbSize > 0 && waveOff + 18 + cbSize <= end) {
147
+ codecData = buf.subarray(waveOff + 18, waveOff + 18 + cbSize)
148
+ }
149
+
150
+ return { formatTag, channels, sampleRate, avgBytesPerSec, blockAlign, bitsPerSample, codecData }
151
+ }
152
+
153
+ /**
154
+ * Parse File Properties Object body
155
+ * Returns { packetSize, duration } or null
156
+ */
157
+ function parseFileProps(buf, start, end) {
158
+ // File ID(16) + File Size(8) + Creation Date(8) + Data Packets Count(8)
159
+ // + Play Duration(8) + Send Duration(8) + Preroll(8)
160
+ // + Flags(4) + Min Data Packet Size(4) + Max Data Packet Size(4)
161
+ // + Max Bitrate(4)
162
+ if (start + 80 > end) return null
163
+
164
+ // Play Duration is 100-ns units (offset 40)
165
+ let playDur = u64(buf, start + 40)
166
+ // Preroll in ms (offset 56)
167
+ let preroll = u64(buf, start + 56)
168
+ // Duration in seconds
169
+ let duration = Math.max(0, playDur / 10000000 - preroll / 1000)
170
+
171
+ // Max packet size at offset 72 (min at 68, always equal for WMA)
172
+ let packetSize = u32(buf, start + 72)
173
+
174
+ return { packetSize, duration }
175
+ }
176
+
177
+ /**
178
+ * Parse ASF data packet — extract compressed audio payload(s)
179
+ * Returns array of payload buffers
180
+ */
181
+ export function parsePacket(pkt, packetSize) {
182
+ if (!pkt || pkt.length < 3) return []
183
+
184
+ let pos = 0
185
+
186
+ // Error Correction — first byte flags
187
+ let ecFlags = pkt[pos++]
188
+ if (ecFlags & 0x80) {
189
+ // Error correction present
190
+ let ecLen = ecFlags & 0x0F
191
+ // Opaque data flag is bit 4
192
+ pos += ecLen
193
+ }
194
+
195
+ if (pos >= pkt.length) return []
196
+
197
+ // Payload Parsing Information
198
+ let ppFlags = pkt[pos++]
199
+ let lenFlags = pkt[pos++]
200
+
201
+ let multiplePayloads = !!(ppFlags & 0x01)
202
+ let seqType = (ppFlags >> 1) & 0x03
203
+ let padType = (ppFlags >> 3) & 0x03
204
+ let pktLenType = (ppFlags >> 5) & 0x03
205
+
206
+ let repType = lenFlags & 0x03
207
+ let offType = (lenFlags >> 2) & 0x03
208
+ let medNumType = (lenFlags >> 4) & 0x03
209
+
210
+ // Skip optional packet length field
211
+ if (pktLenType === 1) pos += 1
212
+ else if (pktLenType === 2) pos += 2
213
+ else if (pktLenType === 3) pos += 4
214
+
215
+ // Sequence (skip)
216
+ if (seqType === 1) pos += 1
217
+ else if (seqType === 2) pos += 2
218
+ else if (seqType === 3) pos += 4
219
+
220
+ // Padding length
221
+ let padLen = 0
222
+ if (padType === 1) { padLen = pkt[pos++] }
223
+ else if (padType === 2) { padLen = u16(pkt, pos); pos += 2 }
224
+ else if (padType === 3) { padLen = u32(pkt, pos); pos += 4 }
225
+
226
+ // Send time (4 bytes) + duration (2 bytes)
227
+ pos += 6
228
+
229
+ if (pos >= pkt.length) return []
230
+
231
+ let payloads = []
232
+
233
+ if (!multiplePayloads) {
234
+ // Single payload — rest of packet minus padding
235
+ pos += 1 // stream number (always 1 byte)
236
+
237
+ // Media object number
238
+ pos += fieldSize(medNumType)
239
+
240
+ // Offset into media object
241
+ pos += fieldSize(offType)
242
+
243
+ // Replicated data length
244
+ let repLen = readVarField(pkt, pos, repType)
245
+ pos += fieldSize(repType)
246
+
247
+ // Skip replicated data
248
+ if (repLen === 1) {
249
+ // Compressed payload: repLen==1 means compressed
250
+ pos += 1 // presentation time delta
251
+ } else {
252
+ pos += repLen
253
+ }
254
+
255
+ let payloadLen = pkt.length - pos - padLen
256
+ if (payloadLen > 0 && pos + payloadLen <= pkt.length) {
257
+ payloads.push(pkt.subarray(pos, pos + payloadLen))
258
+ }
259
+ } else {
260
+ // Multiple payloads
261
+ let payloadFlags = pkt[pos++]
262
+ let numPayloads = payloadFlags & 0x3F
263
+ let payLenType = (payloadFlags >> 6) & 0x03
264
+
265
+ for (let i = 0; i < numPayloads && pos < pkt.length; i++) {
266
+ // Stream number (1 byte, lower 7 = number, bit 7 = key frame)
267
+ pos += 1
268
+
269
+ // Media object number
270
+ pos += fieldSize(medNumType)
271
+
272
+ // Offset into media object
273
+ pos += fieldSize(offType)
274
+
275
+ // Replicated data
276
+ let repLen = readVarField(pkt, pos, repType)
277
+ pos += fieldSize(repType)
278
+
279
+ if (repLen === 1) {
280
+ pos += 1 // compressed: presentation time delta
281
+ } else {
282
+ pos += repLen
283
+ }
284
+
285
+ // Payload length
286
+ let payLen = 0
287
+ if (payLenType === 1) { payLen = pkt[pos++] }
288
+ else if (payLenType === 2) { payLen = u16(pkt, pos); pos += 2 }
289
+ else if (payLenType === 3) { payLen = u32(pkt, pos); pos += 4 }
290
+ else { payLen = pkt.length - pos }
291
+
292
+ if (payLen > 0 && pos + payLen <= pkt.length) {
293
+ payloads.push(pkt.subarray(pos, pos + payLen))
294
+ }
295
+ pos += payLen
296
+ }
297
+ }
298
+
299
+ return payloads
300
+ }
301
+
302
+ function fieldSize(type) {
303
+ return type === 0 ? 0 : type === 1 ? 1 : type === 2 ? 2 : 4
304
+ }
305
+
306
+ function readVarField(buf, off, type) {
307
+ if (type === 0) return 0
308
+ if (type === 1) return buf[off] || 0
309
+ if (type === 2) return (off + 2 <= buf.length) ? u16(buf, off) : 0
310
+ return (off + 4 <= buf.length) ? u32(buf, off) : 0
311
+ }
312
+
313
+ // ===== WMA format tag names =====
314
+
315
+ const WMA_FORMATS = {
316
+ 0x0160: 'WMAv1',
317
+ 0x0161: 'WMAv2',
318
+ 0x0162: 'WMAPro',
319
+ 0x0163: 'WMALossless',
320
+ }
321
+
322
+ // ===== WASM module loader =====
323
+
324
+ let _modP
325
+
326
+ async function getMod() {
327
+ if (_modP) return _modP
328
+ let p = (async () => {
329
+ let createWMA
330
+ if (typeof process !== 'undefined' && process.versions?.node) {
331
+ let m = 'module'
332
+ let { createRequire } = await import(m)
333
+ createWMA = createRequire(import.meta.url)('./src/wma.wasm.cjs')
334
+ } else {
335
+ let mod = await import('./src/wma.wasm.cjs')
336
+ createWMA = mod.default || mod
337
+ }
338
+ return createWMA()
339
+ })()
340
+ _modP = p
341
+ try { return await p }
342
+ catch (e) { _modP = null; throw e }
343
+ }
344
+
345
+ /**
346
+ * Whole-file decode
347
+ * @param {Uint8Array|ArrayBuffer} src
348
+ * @returns {Promise<{channelData: Float32Array[], sampleRate: number}>}
349
+ */
350
+ export default async function decode(src) {
351
+ let buf = src instanceof Uint8Array ? src : new Uint8Array(src)
352
+ let dec = await decoder()
353
+ try {
354
+ return dec.decode(buf)
355
+ } finally {
356
+ dec.free()
357
+ }
358
+ }
359
+
360
+ /**
361
+ * Create decoder instance
362
+ * @returns {Promise<{decode(chunk: Uint8Array): {channelData, sampleRate}, flush(), free()}>}
363
+ */
364
+ export async function decoder() {
365
+ return new WMADecoder(await getMod())
366
+ }
367
+
368
+ class WMADecoder {
369
+ constructor(mod) {
370
+ this.m = mod
371
+ this.h = null
372
+ this.sr = 0
373
+ this.ch = 0
374
+ this.done = false
375
+ this._ptr = 0
376
+ this._cap = 0
377
+ this._meta = null // parsed ASF metadata
378
+ this._left = null // leftover bytes (partial packet)
379
+ }
380
+
381
+ decode(data) {
382
+ if (this.done) throw Error('Decoder already freed')
383
+ if (!data?.length) return EMPTY
384
+
385
+ let buf = data instanceof Uint8Array ? data : new Uint8Array(data)
386
+ if (this._left) { buf = catW(this._left, buf); this._left = null }
387
+
388
+ // Phase 1: parse header, init WASM, decode initial packets
389
+ if (!this._meta) {
390
+ let asf
391
+ try { asf = demuxASF(buf) } catch {
392
+ this._left = buf.slice()
393
+ return EMPTY
394
+ }
395
+
396
+ if (!asf.packets.length && !asf.packetSize) return EMPTY
397
+
398
+ let fmt = WMA_FORMATS[asf.formatTag]
399
+ if (!fmt) throw Error('Unsupported WMA format tag: 0x' + asf.formatTag.toString(16))
400
+ this.sr = asf.sampleRate
401
+ this.ch = asf.channels
402
+ this._meta = asf
403
+
404
+ let m = this.m
405
+ let extraPtr = 0, extraLen = 0
406
+ if (asf.codecData?.length) {
407
+ extraPtr = this._alloc(asf.codecData.length)
408
+ m.HEAPU8.set(asf.codecData, extraPtr)
409
+ extraLen = asf.codecData.length
410
+ }
411
+ this.h = m._wma_create(
412
+ asf.channels, asf.sampleRate, asf.bitRate,
413
+ asf.blockAlign, asf.formatTag, asf.bitsPerSample,
414
+ extraPtr, extraLen
415
+ )
416
+ if (!this.h) throw Error('WMA decoder init failed')
417
+
418
+ // Compute data start + consumed offset to keep leftover
419
+ let headerSize = u64(buf, 16)
420
+ let datOff = Number(headerSize) + 50
421
+ let consumed = datOff + asf.packets.length * asf.packetSize
422
+ if (consumed < buf.length) this._left = buf.subarray(consumed).slice()
423
+
424
+ if (!asf.packets.length) return EMPTY
425
+ return this._decodePkts(asf.packets, asf)
426
+ }
427
+
428
+ // Phase 2: incremental — extract fixed-size packets from new data
429
+ let ps = this._meta.packetSize
430
+ if (!ps) { this._left = buf; return EMPTY } // variable-size: accumulate, decode on flush
431
+ let pkts = []
432
+ let pos = 0
433
+ while (pos + ps <= buf.length) {
434
+ pkts.push(buf.subarray(pos, pos + ps))
435
+ pos += ps
436
+ }
437
+ if (pos < buf.length) this._left = buf.subarray(pos).slice()
438
+ if (!pkts.length) return EMPTY
439
+ return this._decodePkts(pkts, this._meta)
440
+ }
441
+
442
+ _decodePkts(pkts, asf) {
443
+ let m = this.m
444
+ let chunks = [], totalPerCh = 0, channels = this.ch, errors = 0
445
+ let ba = asf.blockAlign
446
+
447
+ for (let pkt of pkts) {
448
+ let payloads = parsePacket(pkt, asf.packetSize)
449
+ for (let payload of payloads) {
450
+ for (let off = 0; off + ba <= payload.length; off += ba) {
451
+ let frame = payload.subarray(off, off + ba)
452
+ let ptr = this._alloc(ba)
453
+ m.HEAPU8.set(frame, ptr)
454
+ let out = m._wma_decode(this.h, ptr, ba)
455
+ if (!out) { errors++; continue }
456
+
457
+ let n = m._wma_samples()
458
+ let sr = m._wma_samplerate()
459
+ if (sr) this.sr = sr
460
+ let ch = m._wma_channels()
461
+ if (ch) channels = ch
462
+
463
+ let spc = n / channels
464
+ chunks.push({ data: new Float32Array(m.HEAPF32.buffer, out, n).slice(), ch: channels, spc })
465
+ totalPerCh += spc
466
+ }
467
+ }
468
+ }
469
+
470
+ if (!totalPerCh) {
471
+ if (errors) throw Error(errors + ' frame(s) failed to decode')
472
+ return EMPTY
473
+ }
474
+
475
+ let channelData = Array.from({ length: channels }, () => new Float32Array(totalPerCh))
476
+ let pos = 0
477
+ for (let { data, ch, spc } of chunks) {
478
+ for (let c = 0; c < ch; c++) {
479
+ let out = channelData[c]
480
+ for (let s = 0; s < spc; s++) out[pos + s] = data[s * ch + c]
481
+ }
482
+ pos += spc
483
+ }
484
+
485
+ return { channelData, sampleRate: this.sr }
486
+ }
487
+
488
+ flush() {
489
+ let r = EMPTY
490
+ if (this._left && this._meta && !this._meta.packetSize) r = this._decodePkts([this._left], this._meta)
491
+ this._left = null
492
+ return r
493
+ }
494
+
495
+ free() {
496
+ if (this.done) return
497
+ this.done = true
498
+ if (this.h) {
499
+ this.m._wma_close(this.h)
500
+ this.m._wma_free_buf()
501
+ this.h = null
502
+ }
503
+ if (this._ptr) {
504
+ this.m._free(this._ptr)
505
+ this._ptr = 0
506
+ this._cap = 0
507
+ }
508
+ this._left = null; this._meta = null
509
+ }
510
+
511
+ _alloc(len) {
512
+ if (len > this._cap) {
513
+ if (this._ptr) this.m._free(this._ptr)
514
+ this._cap = len
515
+ this._ptr = this.m._malloc(len)
516
+ }
517
+ return this._ptr
518
+ }
519
+ }
520
+
521
+ function catW(a, b) {
522
+ let r = new Uint8Array(a.length + b.length)
523
+ r.set(a); r.set(b, a.length)
524
+ return r
525
+ }