@areumtecnologia/wasockets 2.0.0-alpha.1 → 2.2.3
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 +1929 -1649
- package/lib/Defaults/baileys-version.json +1 -1
- package/lib/Defaults/connection.js +14 -1
- package/lib/Socket/index.js +51 -48
- package/lib/Socket/messages-recv.js +74 -13
- package/lib/Socket/messages-send.js +50 -25
- package/lib/Socket/socket.js +13 -0
- package/lib/Socket/voip.js +123 -0
- package/lib/Store/make-cache-manager-store.js +14 -5
- package/lib/Types/index.d.ts +4 -0
- package/lib/Utils/auth-utils.js +16 -1
- package/lib/Utils/browser-utils.js +6 -2
- package/lib/Utils/generics.js +47 -8
- package/lib/Utils/index.d.ts +1 -0
- package/lib/Utils/messages-media.js +44 -21
- package/lib/Utils/pre-key-manager.js +16 -1
- package/lib/Utils/validate-connection.js +10 -11
- package/lib/VoIP/VoIPCrypto.js +150 -0
- package/lib/VoIP/VoIPManager.js +469 -0
- package/lib/VoIP/VoIPMediaEngine.js +224 -0
- package/lib/VoIP/VoIPProtocol.js +354 -0
- package/lib/VoIP/VoIPRelayTransport.js +173 -0
- package/lib/VoIP/VoIPSession.js +314 -0
- package/lib/VoIP/assets/wasm/loader.js +5 -0
- package/lib/VoIP/assets/wasm/whatsapp.wasm +0 -0
- package/lib/VoIP/assets/wasm/worker-modules.js +305 -0
- package/lib/VoIP/engine/audio-feeder.d.mts +15 -0
- package/lib/VoIP/engine/audio-feeder.mjs +243 -0
- package/lib/VoIP/engine/index.d.mts +91 -0
- package/lib/VoIP/engine/index.mjs +1683 -0
- package/lib/VoIP/engine/relay-transport.d.mts +43 -0
- package/lib/VoIP/engine/relay-transport.mjs +607 -0
- package/lib/VoIP/engine/signaling.d.mts +44 -0
- package/lib/VoIP/engine/signaling.mjs +893 -0
- package/lib/VoIP/engine/types.d.mts +183 -0
- package/lib/VoIP/engine/types.mjs +17 -0
- package/lib/VoIP/engine/wasm-engine.d.mts +103 -0
- package/lib/VoIP/engine/wasm-engine.mjs +1397 -0
- package/lib/VoIP/engine/worker-bootstrap.mjs +1049 -0
- package/lib/VoIP/index.js +51 -0
- package/lib/VoIP/utils/audio.d.ts +28 -0
- package/lib/VoIP/utils/audio.js +148 -0
- package/lib/WABinary/generic-utils.js +22 -6
- package/lib/index.d.ts +382 -274
- package/lib/index.js +5 -0
- package/package.json +28 -32
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
|
|
5
|
+
const { VoIPCrypto, deriveVoIPKeys, computeSRTPIV, encryptRTPPayload, decryptRTPPayload, computeAuthTag } = require("./VoIPCrypto");
|
|
6
|
+
const { VoIPProtocol, buildOfferStanza, buildAcceptStanza, buildRejectStanza, buildTerminateStanza, buildRelayQueryIq, parseRelayEndpoints, parseCallNode } = require("./VoIPProtocol");
|
|
7
|
+
const { VoIPRelayTransport } = require("./VoIPRelayTransport");
|
|
8
|
+
const { VoIPMediaEngine } = require("./VoIPMediaEngine");
|
|
9
|
+
const { VoIPSession, CallState } = require("./VoIPSession");
|
|
10
|
+
const { VoIPManager, makeVoIPManager } = require("./VoIPManager");
|
|
11
|
+
const { makeVoipSocket } = require("../Socket/voip");
|
|
12
|
+
const audioUtils = require("./utils/audio");
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
// Socket Mixin
|
|
16
|
+
makeVoipSocket,
|
|
17
|
+
|
|
18
|
+
// Audio DSP & Format Helpers
|
|
19
|
+
audioUtils,
|
|
20
|
+
...audioUtils,
|
|
21
|
+
|
|
22
|
+
// High-Level Manager & Engine
|
|
23
|
+
VoIPManager,
|
|
24
|
+
makeVoIPManager,
|
|
25
|
+
|
|
26
|
+
// Session & States
|
|
27
|
+
VoIPSession,
|
|
28
|
+
CallState,
|
|
29
|
+
|
|
30
|
+
// Media & Transport
|
|
31
|
+
VoIPMediaEngine,
|
|
32
|
+
VoIPRelayTransport,
|
|
33
|
+
|
|
34
|
+
// Protocol Stanzas
|
|
35
|
+
VoIPProtocol,
|
|
36
|
+
buildOfferStanza,
|
|
37
|
+
buildAcceptStanza,
|
|
38
|
+
buildRejectStanza,
|
|
39
|
+
buildTerminateStanza,
|
|
40
|
+
buildRelayQueryIq,
|
|
41
|
+
parseRelayEndpoints,
|
|
42
|
+
parseCallNode,
|
|
43
|
+
|
|
44
|
+
// Crypto
|
|
45
|
+
VoIPCrypto,
|
|
46
|
+
deriveVoIPKeys,
|
|
47
|
+
computeSRTPIV,
|
|
48
|
+
encryptRTPPayload,
|
|
49
|
+
decryptRTPPayload,
|
|
50
|
+
computeAuthTag
|
|
51
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
|
|
3
|
+
export interface WavHeaderOptions {
|
|
4
|
+
sampleRate?: number;
|
|
5
|
+
numChannels?: number;
|
|
6
|
+
bitDepth?: number;
|
|
7
|
+
dataByteLength?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface AudioMetrics {
|
|
11
|
+
rms: number;
|
|
12
|
+
volumeDbfs: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export declare function float32ToInt16(float32: Float32Array, asBuffer?: false): Int16Array;
|
|
16
|
+
export declare function float32ToInt16(float32: Float32Array, asBuffer: true): Buffer;
|
|
17
|
+
export declare function float32ToInt16(float32: Float32Array, asBuffer?: boolean): Int16Array | Buffer;
|
|
18
|
+
|
|
19
|
+
export declare function int16ToFloat32(int16OrBuffer: Int16Array | Buffer | Uint8Array): Float32Array;
|
|
20
|
+
|
|
21
|
+
export declare function resampleFloat32(inputSamples: Float32Array, fromRate: number, toRate: number): Float32Array;
|
|
22
|
+
|
|
23
|
+
export declare function createWavHeader(options?: WavHeaderOptions): Buffer;
|
|
24
|
+
|
|
25
|
+
export declare function calculateRmsDbfs(float32: Float32Array): AudioMetrics;
|
|
26
|
+
|
|
27
|
+
export declare function createSilenceBuffer(durationMs: number, sampleRate?: number): Float32Array;
|
|
28
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure, zero-dependency audio DSP and format conversion utilities for WaSockets VoIP
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Converts a Float32Array (-1.0 to 1.0) to 16-bit signed PCM (Int16Array or Buffer)
|
|
9
|
+
* @param {Float32Array} float32 Samples normalized between -1.0 and 1.0
|
|
10
|
+
* @param {boolean} [asBuffer=false] Whether to return a Node.js Buffer instead of Int16Array
|
|
11
|
+
* @returns {Int16Array|Buffer} 16-bit PCM samples
|
|
12
|
+
*/
|
|
13
|
+
function float32ToInt16(float32, asBuffer = false) {
|
|
14
|
+
const len = float32.length;
|
|
15
|
+
const int16 = new Int16Array(len);
|
|
16
|
+
for (let i = 0; i < len; i++) {
|
|
17
|
+
const s = Math.max(-1, Math.min(1, float32[i]));
|
|
18
|
+
int16[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
|
|
19
|
+
}
|
|
20
|
+
if (asBuffer) {
|
|
21
|
+
return Buffer.from(int16.buffer, int16.byteOffset, int16.byteLength);
|
|
22
|
+
}
|
|
23
|
+
return int16;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Converts a 16-bit signed PCM (Int16Array or Buffer) to Float32Array (-1.0 to 1.0)
|
|
28
|
+
* @param {Int16Array|Buffer|Uint8Array} int16OrBuffer
|
|
29
|
+
* @returns {Float32Array}
|
|
30
|
+
*/
|
|
31
|
+
function int16ToFloat32(int16OrBuffer) {
|
|
32
|
+
let int16;
|
|
33
|
+
if (int16OrBuffer instanceof Int16Array) {
|
|
34
|
+
int16 = int16OrBuffer;
|
|
35
|
+
} else {
|
|
36
|
+
const buf = Buffer.isBuffer(int16OrBuffer) ? int16OrBuffer : Buffer.from(int16OrBuffer);
|
|
37
|
+
int16 = new Int16Array(buf.buffer, buf.byteOffset, Math.floor(buf.byteLength / 2));
|
|
38
|
+
}
|
|
39
|
+
const len = int16.length;
|
|
40
|
+
const float32 = new Float32Array(len);
|
|
41
|
+
for (let i = 0; i < len; i++) {
|
|
42
|
+
float32[i] = int16[i] / 32768.0;
|
|
43
|
+
}
|
|
44
|
+
return float32;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Fast linear interpolation resampler for PCM audio
|
|
49
|
+
* @param {Float32Array} inputSamples Mono Float32Array samples
|
|
50
|
+
* @param {number} fromRate Source sample rate (e.g. 16000)
|
|
51
|
+
* @param {number} toRate Destination sample rate (e.g. 8000, 24000, 48000)
|
|
52
|
+
* @returns {Float32Array} Resampled Float32Array
|
|
53
|
+
*/
|
|
54
|
+
function resampleFloat32(inputSamples, fromRate, toRate) {
|
|
55
|
+
if (fromRate === toRate || inputSamples.length === 0) {
|
|
56
|
+
return new Float32Array(inputSamples);
|
|
57
|
+
}
|
|
58
|
+
const ratio = fromRate / toRate;
|
|
59
|
+
const outputLength = Math.round(inputSamples.length / ratio);
|
|
60
|
+
const output = new Float32Array(outputLength);
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < outputLength; i++) {
|
|
63
|
+
const srcPos = i * ratio;
|
|
64
|
+
const index = Math.floor(srcPos);
|
|
65
|
+
const frac = srcPos - index;
|
|
66
|
+
|
|
67
|
+
const s0 = inputSamples[index] ?? 0;
|
|
68
|
+
const s1 = inputSamples[index + 1] ?? s0;
|
|
69
|
+
output[i] = s0 + frac * (s1 - s0);
|
|
70
|
+
}
|
|
71
|
+
return output;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates a standard 44-byte RIFF/WAVE header
|
|
76
|
+
* @param {Object} options
|
|
77
|
+
* @param {number} [options.sampleRate=16000]
|
|
78
|
+
* @param {number} [options.numChannels=1]
|
|
79
|
+
* @param {number} [options.bitDepth=16]
|
|
80
|
+
* @param {number} [options.dataByteLength=0]
|
|
81
|
+
* @returns {Buffer}
|
|
82
|
+
*/
|
|
83
|
+
function createWavHeader({ sampleRate = 16000, numChannels = 1, bitDepth = 16, dataByteLength = 0 } = {}) {
|
|
84
|
+
const header = Buffer.alloc(44);
|
|
85
|
+
const byteRate = (sampleRate * numChannels * bitDepth) / 8;
|
|
86
|
+
const blockAlign = (numChannels * bitDepth) / 8;
|
|
87
|
+
const chunkSize = 36 + dataByteLength;
|
|
88
|
+
|
|
89
|
+
// RIFF chunk descriptor
|
|
90
|
+
header.write("RIFF", 0);
|
|
91
|
+
header.writeUInt32LE(chunkSize, 4);
|
|
92
|
+
header.write("WAVE", 8);
|
|
93
|
+
|
|
94
|
+
// "fmt " sub-chunk
|
|
95
|
+
header.write("fmt ", 12);
|
|
96
|
+
header.writeUInt32LE(16, 16); // Subchunk1Size for PCM
|
|
97
|
+
header.writeUInt16LE(1, 20); // AudioFormat 1 = PCM
|
|
98
|
+
header.writeUInt16LE(numChannels, 22);
|
|
99
|
+
header.writeUInt32LE(sampleRate, 24);
|
|
100
|
+
header.writeUInt32LE(byteRate, 28);
|
|
101
|
+
header.writeUInt16LE(blockAlign, 32);
|
|
102
|
+
header.writeUInt16LE(bitDepth, 34);
|
|
103
|
+
|
|
104
|
+
// "data" sub-chunk
|
|
105
|
+
header.write("data", 36);
|
|
106
|
+
header.writeUInt32LE(dataByteLength, 40);
|
|
107
|
+
|
|
108
|
+
return header;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Calculates Root Mean Square (RMS) and volume level in dBFS
|
|
113
|
+
* @param {Float32Array} float32
|
|
114
|
+
* @returns {{ rms: number, volumeDbfs: number }}
|
|
115
|
+
*/
|
|
116
|
+
function calculateRmsDbfs(float32) {
|
|
117
|
+
let sum = 0;
|
|
118
|
+
const len = float32.length;
|
|
119
|
+
if (len === 0) return { rms: 0, volumeDbfs: -100 };
|
|
120
|
+
|
|
121
|
+
for (let i = 0; i < len; i++) {
|
|
122
|
+
sum += float32[i] * float32[i];
|
|
123
|
+
}
|
|
124
|
+
const rms = Math.sqrt(sum / len);
|
|
125
|
+
const volumeDbfs = rms > 0.00001 ? Math.round(20 * Math.log10(rms)) : -100;
|
|
126
|
+
return { rms, volumeDbfs };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a silent audio frame (Float32Array) of specified duration
|
|
131
|
+
* @param {number} durationMs Duration in milliseconds
|
|
132
|
+
* @param {number} [sampleRate=16000] Sample rate in Hz
|
|
133
|
+
* @returns {Float32Array}
|
|
134
|
+
*/
|
|
135
|
+
function createSilenceBuffer(durationMs, sampleRate = 16000) {
|
|
136
|
+
const totalSamples = Math.floor((durationMs / 1000) * sampleRate);
|
|
137
|
+
return new Float32Array(totalSamples);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
141
|
+
float32ToInt16,
|
|
142
|
+
int16ToFloat32,
|
|
143
|
+
resampleFloat32,
|
|
144
|
+
createWavHeader,
|
|
145
|
+
calculateRmsDbfs,
|
|
146
|
+
createSilenceBuffer
|
|
147
|
+
};
|
|
148
|
+
|
|
@@ -5,12 +5,29 @@ Object.defineProperty(exports, "__esModule", { value: true })
|
|
|
5
5
|
const { Boom } = require("@hapi/boom")
|
|
6
6
|
const { proto } = require("../../WAProto")
|
|
7
7
|
|
|
8
|
+
const binaryNodeChildrenCache = new WeakMap()
|
|
9
|
+
|
|
8
10
|
// some extra useful utilities
|
|
9
11
|
const getBinaryNodeChildren = (node, childTag) => {
|
|
10
|
-
if (Array.isArray(node?.content)) {
|
|
11
|
-
return
|
|
12
|
+
if (!Array.isArray(node?.content)) {
|
|
13
|
+
return []
|
|
12
14
|
}
|
|
13
|
-
|
|
15
|
+
let map = binaryNodeChildrenCache.get(node)
|
|
16
|
+
if (!map) {
|
|
17
|
+
map = new Map()
|
|
18
|
+
for (const item of node.content) {
|
|
19
|
+
if (item && typeof item === 'object' && item.tag) {
|
|
20
|
+
let list = map.get(item.tag)
|
|
21
|
+
if (!list) {
|
|
22
|
+
list = []
|
|
23
|
+
map.set(item.tag, list)
|
|
24
|
+
}
|
|
25
|
+
list.push(item)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
binaryNodeChildrenCache.set(node, map)
|
|
29
|
+
}
|
|
30
|
+
return map.get(childTag) || []
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
const getAllBinaryNodeChildren = ({ content }) => {
|
|
@@ -21,9 +38,8 @@ const getAllBinaryNodeChildren = ({ content }) => {
|
|
|
21
38
|
}
|
|
22
39
|
|
|
23
40
|
const getBinaryNodeChild = (node, childTag) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
41
|
+
const children = getBinaryNodeChildren(node, childTag)
|
|
42
|
+
return children[0]
|
|
27
43
|
}
|
|
28
44
|
|
|
29
45
|
const getBinaryNodeChildBuffer = (node, childTag) => {
|