vban
Version:
Node VBAN implementation
1,389 lines (1,361 loc) • 48 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
BITS_SPEEDS: () => BITS_SPEEDS,
EBitsResolutions: () => EBitsResolutions,
ECodecs: () => ECodecs,
EFormatBit: () => EFormatBit,
ERegistrationAnswer: () => ERegistrationAnswer,
ESerialStreamType: () => ESerialStreamType,
EServiceFunction: () => EServiceFunction,
EServicePINGApplicationType: () => EServicePINGApplicationType,
EServicePINGFeatures: () => EServicePINGFeatures,
EServiceType: () => EServiceType,
ESubProtocol: () => ESubProtocol,
ETextEncoding: () => ETextEncoding,
MAX_FRAME_COUNTER: () => MAX_FRAME_COUNTER,
PACKET_IDENTIFICATION: () => PACKET_IDENTIFICATION,
STREAM_NAME_LENGTH: () => STREAM_NAME_LENGTH,
VBANAudioPacket: () => VBANAudioPacket,
VBANChatPacket: () => VBANChatPacket,
VBANPacket: () => VBANPacket,
VBANPingPacket: () => VBANPingPacket,
VBANProtocolFactory: () => VBANProtocolFactory,
VBANRealTimePacket: () => VBANRealTimePacket,
VBANRealTimeRegisterAnswerPacket: () => VBANRealTimeRegisterAnswerPacket,
VBANRealTimeRegisterPacket: () => VBANRealTimeRegisterPacket,
VBANSerialPacket: () => VBANSerialPacket,
VBANServer: () => VBANServer,
VBANServicePacket: () => VBANServicePacket,
VBANServicePacketFactory: () => VBANServicePacketFactory,
VBANTEXTPacket: () => VBANTEXTPacket,
VBAN_DATA_MAX_SIZE: () => VBAN_DATA_MAX_SIZE,
VBAN_PACKET_MAX_SIZE: () => VBAN_PACKET_MAX_SIZE,
bufferToHex: () => bufferToHex,
cleanPacketString: () => cleanPacketString,
dec2bin: () => dec2bin,
pkg: () => pkg,
prepareStringForPacket: () => prepareStringForPacket,
sampleRates: () => sampleRates,
serialStopModes: () => serialStopModes
});
module.exports = __toCommonJS(index_exports);
// src/packets/VBANAudioPacket/EBitsResolutions.ts
var EBitsResolutions = /* @__PURE__ */ ((EBitsResolutions2) => {
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_BYTE8"] = 0] = "VBAN_DATATYPE_BYTE8";
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_INT16"] = 1] = "VBAN_DATATYPE_INT16";
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_INT24"] = 2] = "VBAN_DATATYPE_INT24";
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_INT32"] = 3] = "VBAN_DATATYPE_INT32";
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_FLOAT32"] = 4] = "VBAN_DATATYPE_FLOAT32";
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_FLOAT64"] = 5] = "VBAN_DATATYPE_FLOAT64";
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_12BITS"] = 6] = "VBAN_DATATYPE_12BITS";
EBitsResolutions2[EBitsResolutions2["VBAN_DATATYPE_10BITS"] = 7] = "VBAN_DATATYPE_10BITS";
return EBitsResolutions2;
})(EBitsResolutions || {});
// src/packets/VBANAudioPacket/ECodecs.ts
var ECodecs = /* @__PURE__ */ ((ECodecs2) => {
ECodecs2[ECodecs2["VBAN_CODEC_PCM"] = 0] = "VBAN_CODEC_PCM";
ECodecs2[ECodecs2["VBAN_CODEC_VBCA"] = 16] = "VBAN_CODEC_VBCA";
ECodecs2[ECodecs2["VBAN_CODEC_VBCV"] = 32] = "VBAN_CODEC_VBCV";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_1"] = 48] = "VBAN_CODEC_UNDEFINED_1";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_2"] = 64] = "VBAN_CODEC_UNDEFINED_2";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_3"] = 80] = "VBAN_CODEC_UNDEFINED_3";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_4"] = 96] = "VBAN_CODEC_UNDEFINED_4";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_5"] = 112] = "VBAN_CODEC_UNDEFINED_5";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_6"] = 128] = "VBAN_CODEC_UNDEFINED_6";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_7"] = 144] = "VBAN_CODEC_UNDEFINED_7";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_8"] = 160] = "VBAN_CODEC_UNDEFINED_8";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_9"] = 176] = "VBAN_CODEC_UNDEFINED_9";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_10"] = 192] = "VBAN_CODEC_UNDEFINED_10";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_11"] = 208] = "VBAN_CODEC_UNDEFINED_11";
ECodecs2[ECodecs2["VBAN_CODEC_UNDEFINED_12"] = 224] = "VBAN_CODEC_UNDEFINED_12";
ECodecs2[ECodecs2["VBAN_CODEC_USER"] = 240] = "VBAN_CODEC_USER";
return ECodecs2;
})(ECodecs || {});
// src/packets/VBANPacket.ts
var import_buffer = require("buffer");
// src/packets/ESubProtocol.ts
var ESubProtocol = /* @__PURE__ */ ((ESubProtocol2) => {
ESubProtocol2[ESubProtocol2["AUDIO"] = 0] = "AUDIO";
ESubProtocol2[ESubProtocol2["SERIAL"] = 32] = "SERIAL";
ESubProtocol2[ESubProtocol2["TEXT"] = 64] = "TEXT";
ESubProtocol2[ESubProtocol2["SERVICE"] = 96] = "SERVICE";
return ESubProtocol2;
})(ESubProtocol || {});
// src/commons.ts
var PACKET_IDENTIFICATION = "VBAN";
var STREAM_NAME_LENGTH = 16;
var BITS_SPEEDS = {
0: 0,
1: 110,
2: 150,
3: 300,
4: 600,
5: 1200,
6: 2400,
7: 4800,
8: 9600,
9: 14400,
10: 19200,
11: 31250,
12: 38400,
13: 57600,
14: 115200,
15: 128e3,
16: 230400,
17: 25e4,
18: 256e3,
19: 460800,
20: 921600,
21: 1e6,
22: 15e5,
23: 2e6,
24: 3e6,
25: 0,
26: 0,
27: 0,
28: 0,
29: 0,
30: 0,
31: 0
};
var EFormatBit = /* @__PURE__ */ ((EFormatBit2) => {
EFormatBit2[EFormatBit2["VBAN_DATATYPE_BYTE8"] = 0] = "VBAN_DATATYPE_BYTE8";
return EFormatBit2;
})(EFormatBit || {});
var serialStopModes = [
{
mode: 0,
stop: 1
},
{
mode: 1,
stop: 1.5
},
{
mode: 2,
stop: 2
},
{
mode: 3,
stop: null
}
];
function dec2bin(dec) {
return ((dec >>> 0).toString(2) || "").padStart(8, "0");
}
function bufferToHex(buffer) {
if (!Buffer.isBuffer(buffer)) {
throw new Error("need to be a buffer");
}
let hexString = "";
for (let i = 0; i < buffer.length; i++) {
const hex = buffer[i].toString(16).padStart(2, "0");
hexString += hex;
if (i < buffer.length - 1) {
hexString += " ";
}
}
return hexString;
}
function prepareStringForPacket(str, maxLength) {
return str.slice(0, maxLength).padEnd(maxLength, "\0");
}
function cleanPacketString(str) {
return str.replace(/\0/g, "");
}
var sampleRates = {
0: 6e3,
1: 12e3,
2: 24e3,
3: 48e3,
4: 96e3,
5: 192e3,
6: 384e3,
7: 8e3,
8: 16e3,
9: 32e3,
10: 64e3,
11: 128e3,
12: 256e3,
13: 512e3,
14: 11025,
15: 22050,
16: 44100,
17: 88200,
18: 176400,
19: 352800,
20: 705600,
21: 0,
22: 0,
23: 0,
24: 0,
25: 0,
26: 0,
27: 0,
28: 0,
29: 0,
30: 0,
31: 0
};
// src/packets/VBANSpecs.ts
var MAX_FRAME_COUNTER = 4294967295;
var VBAN_DATA_MAX_SIZE = 1436;
var VBAN_PACKET_MAX_SIZE = 1464;
// src/packets/VBANPacket.ts
var VBANPacket = class {
/**
* the subProtocol of this packet
* {@link ESubProtocol}
*/
subProtocol = 0 /* AUDIO */;
/**
* the name of the current stream .
* Voicemeeter rely on it to allow a packet or not
*/
streamName;
/**
* Sample Rate for this stream
*/
sr;
/**
* frameCounter allow checking if you receive frame in order, and without losing them
*/
frameCounter;
static frameCounters = /* @__PURE__ */ new Map();
/**
* Extract headers and data from UDPPacket, each Packet will continue the process
*/
static prepareFromUDPPacket(headersBuffer, checkSR = true) {
const headers = {};
const srsp = headersBuffer.readUInt8(PACKET_IDENTIFICATION.length);
const srIndex = srsp & 31;
if (checkSR && !sampleRates.hasOwnProperty(srIndex) || sampleRates[srIndex] === void 0) {
throw new Error(`unknown sample rate ${srIndex}`);
}
headers.sr = sampleRates[srIndex];
headers.srIndex = srIndex;
headers.part1 = headersBuffer.readUInt8(5);
headers.part2 = headersBuffer.readUInt8(6);
headers.part3 = headersBuffer.readUInt8(7);
headers.streamName = cleanPacketString(headersBuffer.toString("ascii", 8, 8 + STREAM_NAME_LENGTH));
headers.frameCounter = headersBuffer.readUInt32LE(24);
return headers;
}
/**
* common constructor
*/
constructor(headers) {
this.sr = headers.sr;
this.streamName = headers.streamName;
this.frameCounter = headers.frameCounter ?? 1;
}
/**
* Convert a VBANPacket to a UDP packet
*/
static convertToUDPPacket(headers, data, sampleRate) {
var _a;
let bufferStart = 0;
const headersBuffer = import_buffer.Buffer.alloc(28);
bufferStart += PACKET_IDENTIFICATION.length;
headersBuffer.fill(PACKET_IDENTIFICATION, bufferStart - PACKET_IDENTIFICATION.length, bufferStart, "ascii");
let rate = sampleRate ?? 0;
if (sampleRate === void 0) {
rate = Number(
(_a = Object.entries(sampleRates).find(([, sr]) => sr && sr === headers.sr)) == null ? void 0 : _a.shift()
);
if (!rate) {
throw new Error(`fail to find index for sample rate ${headers.sr}`);
}
}
headersBuffer.fill(rate & 31 | headers.sp & 224, bufferStart++);
headersBuffer.fill(headers.part1, bufferStart++);
headersBuffer.fill(headers.part2, bufferStart++);
headersBuffer.fill(headers.part3, bufferStart++);
headersBuffer.fill(headers.streamName.padEnd(STREAM_NAME_LENGTH, "\0"), bufferStart, bufferStart + STREAM_NAME_LENGTH, "ascii");
bufferStart += STREAM_NAME_LENGTH;
headersBuffer.writeUInt32LE(headers.frameCounter ?? 1, bufferStart);
if (data.length > VBAN_DATA_MAX_SIZE) {
throw new Error(
`VBAN DATA MAX SIZE = ${VBAN_DATA_MAX_SIZE} ! You try to send a packet with ${data.length} bytes . You can use the exported var VBAN_DATA_MAX_SIZE to split your datas in packets`
);
}
return import_buffer.Buffer.concat([headersBuffer, data.subarray(0, VBAN_DATA_MAX_SIZE)]);
}
/**
* EXPERIMENTAL - DO NOT USE
*
* @experimental
*/
static checkFrameCounter(headers) {
const frameCounterKey = "str";
const frameCounter = this.frameCounters.get(frameCounterKey);
if (!headers.frameCounter) {
return;
}
if (frameCounter && frameCounter > headers.frameCounter && headers.frameCounter > 0) {
console.log("frameCounter error");
} else if (frameCounter && headers.frameCounter > 0) {
console.log("frame counter", "old", frameCounter, "new", headers.frameCounter, "diff", headers.frameCounter - frameCounter);
} else if (headers.frameCounter === 0) {
console.log("frame 0");
}
this.frameCounters.set(frameCounterKey, headers.frameCounter);
}
};
// src/packets/VBANAudioPacket/VBANAudioPacket.ts
var VBANAudioPacket = class _VBANAudioPacket extends VBANPacket {
/**
* {@link VBANAudioPacket.subProtocol}
*/
static subProtocol = 0 /* AUDIO */;
subProtocol = _VBANAudioPacket.subProtocol;
/**
* Number of sample is given by an 8 bits unsigned integer (0 – 255) where 0 means 1 sample and
* 255 means 256 samples
*/
nbSample;
/**
* Number of channel is given by an 8 bits unsigned integer (0 – 255) where 0 means 1 channel
* and 255 means 256 channels.
*/
nbChannel;
/**
* Data type used to store audio sample in the packet
* Use it to select the correct bitResolution {@link VBANAudioPacket.bitResolutions}, or directly use {@link VBANAudioPacket.bitResolutionObject}
*/
bitResolution;
/**
* the bit resolution selected by the id in {@link VBANAudioPacket.bitResolution}
*/
bitResolutionObject;
/**
* Audio codec used
*/
codec;
/**
* current audio
*/
data;
constructor(headers, data) {
super({
...headers,
sp: _VBANAudioPacket.subProtocol
});
this.nbSample = headers.nbSample;
this.nbChannel = headers.nbChannel;
this.bitResolution = headers.bitResolution;
if (!_VBANAudioPacket.bitResolutions[headers.bitResolution]) {
throw new Error(`fail to found bitResolution with ID ${headers.bitResolution}`);
}
this.bitResolutionObject = _VBANAudioPacket.bitResolutions[headers.bitResolution];
this.codec = headers.codec;
this.data = data;
}
static toUDPPacket(packet) {
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.sr,
frameCounter: packet.frameCounter,
part1: packet.nbSample - 1,
part2: packet.nbChannel - 1,
part3: packet.bitResolution & 7 | packet.codec & 240
},
packet.data
);
}
static fromUDPPacket(headersBuffer, dataBuffer) {
const headers = this.prepareFromUDPPacket(headersBuffer);
const nbSample = headers.part1 + 1;
const nbChannel = headers.part2 + 1;
const dataFormatAndCodec = headers.part3;
const bitResolution = dataFormatAndCodec & 7;
if (!EBitsResolutions[bitResolution]) {
throw new Error(`unknown bit resolution ${bitResolution}`);
}
const codec = dataFormatAndCodec & 240;
if (!ECodecs[codec]) {
throw new Error(`unknown codec ${codec}`);
}
return new _VBANAudioPacket(
{
...headers,
nbSample,
nbChannel,
bitResolution,
codec
},
dataBuffer
);
}
static bitResolutions = {
0: { bitDepth: 8, signed: false, float: false },
1: { bitDepth: 16, signed: true, float: false },
2: { bitDepth: 24, signed: true, float: false },
3: { bitDepth: 32, signed: true, float: false },
4: { bitDepth: 32, signed: true, float: true },
5: { bitDepth: 64, signed: true, float: true },
6: { bitDepth: 12, signed: true, float: false },
7: { bitDepth: 10, signed: true, float: false }
};
};
// src/packets/VBANSerialPacket/ESerialStreamType.ts
var ESerialStreamType = /* @__PURE__ */ ((ESerialStreamType2) => {
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_GENERIC"] = 0] = "VBAN_SERIAL_GENERIC";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_MIDI"] = 16] = "VBAN_SERIAL_MIDI";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_2"] = 32] = "VBAN_SERIAL_UNDEFINED_2";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_3"] = 48] = "VBAN_SERIAL_UNDEFINED_3";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_4"] = 64] = "VBAN_SERIAL_UNDEFINED_4";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_5"] = 80] = "VBAN_SERIAL_UNDEFINED_5";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_6"] = 96] = "VBAN_SERIAL_UNDEFINED_6";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_7"] = 112] = "VBAN_SERIAL_UNDEFINED_7";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_8"] = 128] = "VBAN_SERIAL_UNDEFINED_8";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_9"] = 144] = "VBAN_SERIAL_UNDEFINED_9";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_10"] = 160] = "VBAN_SERIAL_UNDEFINED_10";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_11"] = 176] = "VBAN_SERIAL_UNDEFINED_11";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_12"] = 192] = "VBAN_SERIAL_UNDEFINED_12";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_13"] = 208] = "VBAN_SERIAL_UNDEFINED_13";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_UNDEFINED_14"] = 224] = "VBAN_SERIAL_UNDEFINED_14";
ESerialStreamType2[ESerialStreamType2["VBAN_SERIAL_USER"] = 240] = "VBAN_SERIAL_USER";
return ESerialStreamType2;
})(ESerialStreamType || {});
// src/packets/VBANSerialPacket/VBANSerialPacket.ts
var VBANSerialPacket = class _VBANSerialPacket extends VBANPacket {
/**
* {@link VBANSerialPacket.subProtocol}
*/
static subProtocol = 32 /* SERIAL */;
subProtocol = _VBANSerialPacket.subProtocol;
/**
* This field is used to give possible information on COM port and serial transmission mode related
* to a Hardware COM port. This is made to possibly emulate COM to COM port connections and
* let the receiver configure the physical COM port in the right mode.
*/
bitMode;
/**
* Can be used to define a sub channel (sub serial link) and then manage up to 256 different
* serial virtual pipes (ZERO by default).
*/
channelsIdents;
/**
* SR / bps : Bit rate is given in bps for information only. But it can be useful if serial data come from or go to
* a particular COM port. Set to ZERO if there is no particular bit rate.
*/
bps;
/**
* not used . Replaced by {@link VBANSerialPacket.bps}
*/
sr = 0;
/**
* Data type used to store data in the packet (ZERO per default). The index is stored on 3 first bits.
* Bit 3 must be ZERO. Bits 4 to 7 gives additional mode
*/
formatBit;
/**
* type of stream . MIDI or SERIAL ... But in practice, only serial is used (MIDI is serial)
*/
streamType;
data;
constructor(headers, data) {
super({
...headers,
sp: _VBANSerialPacket.subProtocol,
sr: 0
});
this.bitMode = headers.bitMode;
this.channelsIdents = headers.channelsIdents;
this.bps = headers.bps;
this.formatBit = headers.formatBit;
this.streamType = headers.streamType;
this.data = data;
this.sr = 0;
}
static toUDPPacket(packet) {
var _a, _b;
let part1 = 0;
const mode = (_a = serialStopModes.find((m) => m.stop === packet.bitMode.stop)) == null ? void 0 : _a.mode;
if (mode === void 0) {
throw new Error(`fail to found mode for stop ${packet.bitMode.stop}`);
}
part1 |= mode & 3;
if (packet.bitMode.start) {
part1 |= 4;
}
if (packet.bitMode.parity) {
part1 |= 8;
}
if (packet.bitMode.multipart) {
part1 |= 128;
}
const bpsId = Number(
(_b = Object.entries(BITS_SPEEDS).find(([, bps]) => bps && bps === packet.bps)) == null ? void 0 : _b.shift()
) || 0;
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.bps,
frameCounter: packet.frameCounter,
part1,
part2: packet.channelsIdents,
part3: packet.formatBit & 7 | packet.streamType & 240
},
packet.data,
bpsId
);
}
static fromUDPPacket(headersBuffer, dataBuffer) {
var _a;
const headers = this.prepareFromUDPPacket(headersBuffer, false);
if (headers.srIndex === void 0 || BITS_SPEEDS[headers.srIndex] === void 0) {
throw new Error(`unknown bits speed ${headers.srIndex}`);
}
const bps = BITS_SPEEDS[headers.srIndex];
const bitModeRaw = headers.part1;
const stopMode = bitModeRaw & 3;
const stop = ((_a = serialStopModes.find((m) => m.mode === stopMode)) == null ? void 0 : _a.stop) ?? null;
const start = (bitModeRaw & 4) === 4;
const parity = (bitModeRaw & 8) === 8;
const multipart = (bitModeRaw & 128) === 128;
const bitMode = {
stop,
start,
parity,
multipart
};
const channelsIdents = headers.part2;
const dataFormat = headers.part3;
const formatBit = dataFormat & 7;
if (!EFormatBit[formatBit]) {
throw new Error(`unknown format bit ${formatBit}`);
}
const streamType = dataFormat & 240;
if (!ESerialStreamType[streamType]) {
throw new Error(`unknown stream type ${streamType}`);
}
return new _VBANSerialPacket(
{
...headers,
bps,
bitMode,
channelsIdents,
formatBit,
streamType
},
dataBuffer
);
}
};
// src/packets/VBANServicePacket/EServiceFunction.ts
var EServiceFunction = /* @__PURE__ */ ((EServiceFunction2) => {
EServiceFunction2[EServiceFunction2["PING0"] = 0] = "PING0";
EServiceFunction2[EServiceFunction2["REPLY"] = 128] = "REPLY";
return EServiceFunction2;
})(EServiceFunction || {});
// src/packets/VBANServicePacket/EServicePINGApplicationType.ts
var EServicePINGApplicationType = /* @__PURE__ */ ((EServicePINGApplicationType2) => {
EServicePINGApplicationType2[EServicePINGApplicationType2["UNKNOWN"] = 0] = "UNKNOWN";
EServicePINGApplicationType2[EServicePINGApplicationType2["RECEPTOR"] = 1] = "RECEPTOR";
EServicePINGApplicationType2[EServicePINGApplicationType2["TRANSMITTER"] = 2] = "TRANSMITTER";
EServicePINGApplicationType2[EServicePINGApplicationType2["RECEPTORSPOT"] = 4] = "RECEPTORSPOT";
EServicePINGApplicationType2[EServicePINGApplicationType2["TRANSMITTERSPOT"] = 8] = "TRANSMITTERSPOT";
EServicePINGApplicationType2[EServicePINGApplicationType2["VIRTUALDEVICE"] = 16] = "VIRTUALDEVICE";
EServicePINGApplicationType2[EServicePINGApplicationType2["VIRTUALMIXER"] = 32] = "VIRTUALMIXER";
EServicePINGApplicationType2[EServicePINGApplicationType2["MATRIX"] = 64] = "MATRIX";
EServicePINGApplicationType2[EServicePINGApplicationType2["DAW"] = 128] = "DAW";
EServicePINGApplicationType2[EServicePINGApplicationType2["SERVER"] = 16777216] = "SERVER";
return EServicePINGApplicationType2;
})(EServicePINGApplicationType || {});
// src/packets/VBANServicePacket/EServicePINGFeatures.ts
var EServicePINGFeatures = /* @__PURE__ */ ((EServicePINGFeatures2) => {
EServicePINGFeatures2[EServicePINGFeatures2["AUDIO"] = 1] = "AUDIO";
EServicePINGFeatures2[EServicePINGFeatures2["AOIP"] = 2] = "AOIP";
EServicePINGFeatures2[EServicePINGFeatures2["VOIP"] = 4] = "VOIP";
EServicePINGFeatures2[EServicePINGFeatures2["SERIAL"] = 256] = "SERIAL";
EServicePINGFeatures2[EServicePINGFeatures2["MIDI"] = 768] = "MIDI";
EServicePINGFeatures2[EServicePINGFeatures2["FRAME"] = 4096] = "FRAME";
EServicePINGFeatures2[EServicePINGFeatures2["TXT"] = 65536] = "TXT";
return EServicePINGFeatures2;
})(EServicePINGFeatures || {});
// src/packets/VBANServicePacket/EServiceType.ts
var EServiceType = /* @__PURE__ */ ((EServiceType2) => {
EServiceType2[EServiceType2["IDENTIFICATION"] = 0] = "IDENTIFICATION";
EServiceType2[EServiceType2["CHATUTF8"] = 1] = "CHATUTF8";
EServiceType2[EServiceType2["RTPACKETREGISTER"] = 32] = "RTPACKETREGISTER";
EServiceType2[EServiceType2["RTPACKET"] = 33] = "RTPACKET";
return EServiceType2;
})(EServiceType || {});
// src/packets/VBANServicePacket/VBANServicePacket.ts
var import_buffer2 = require("buffer");
var VBANServicePacket = class _VBANServicePacket extends VBANPacket {
/**
* {@link VBANServicePacket.subProtocol}
*/
static subProtocol = 96 /* SERVICE */;
subProtocol = _VBANServicePacket.subProtocol;
/**
* Sub Type of the service packet
* {@link EServiceType}
*/
service;
/**
* current function for this function
*/
serviceFunction;
/**
* answer is a reply to another request
*/
isReply = false;
data;
/**
* not used .
*/
sr = 0;
constructor(headers) {
super({
...headers,
sp: _VBANServicePacket.subProtocol,
sr: 0
});
this.service = headers.service;
this.serviceFunction = headers.serviceFunction;
this.isReply = headers.isReply ?? false;
this.sr = 0;
}
toUDPPacket() {
return _VBANServicePacket.toUDPPacket(this);
}
static toUDPPacket(packet) {
return _VBANServicePacket.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.sr,
frameCounter: packet.frameCounter,
part1: (packet.isReply ? 128 : 0) & 128 | packet.serviceFunction & 127,
part2: packet.service,
part3: 0
},
import_buffer2.Buffer.from(""),
packet.sr
);
}
};
// src/packets/VBANServicePacket/VBANChatPacket.ts
var import_buffer3 = require("buffer");
var VBANChatPacket = class _VBANChatPacket extends VBANServicePacket {
data;
constructor(headers, data) {
super(headers);
this.data = data;
}
static fromUDPPacket(headers, dataBuffer) {
const fn = headers.part1;
const serviceFunction = fn & 127;
const isReply = (fn & 128) >= 1;
return new _VBANChatPacket(
{
...headers,
service: 1 /* CHATUTF8 */,
serviceFunction,
isReply
},
dataBuffer.toString()
);
}
toUDPPacket() {
return _VBANChatPacket.toUDPPacket(this);
}
static toUDPPacket(packet) {
const dataBuffer = import_buffer3.Buffer.alloc(676);
dataBuffer.write(prepareStringForPacket(packet.data, 676), 0, "utf8");
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.sr,
frameCounter: packet.frameCounter,
part1: (packet.isReply ? 128 : 0) & 128 | packet.serviceFunction & 127,
part2: packet.service,
part3: 0
},
dataBuffer,
packet.sr
);
}
};
// src/packets/VBANServicePacket/VBANPingPacket.ts
var import_buffer4 = require("buffer");
var VBANPingPacket = class _VBANPingPacket extends VBANServicePacket {
data;
constructor(headers, data) {
super(headers);
this.data = data;
}
static fromUDPPacket(headers, dataBuffer) {
const fn = headers.part1;
const serviceFunction = fn & 127;
const isReply = (fn & 128) >= 1;
let currentByte = 0;
const getXNextBytes = (size) => {
const b = dataBuffer.subarray(currentByte, currentByte + size);
currentByte += size;
return b;
};
const bitType = getXNextBytes(4).readUInt32LE();
const applicationType = EServicePINGApplicationType[bitType] ? bitType : 0 /* UNKNOWN */;
const bitFeature = getXNextBytes(4).readUInt32LE();
const features = Object.entries(EServicePINGFeatures).filter(([k]) => Number.isNaN(Number(k))).filter(([, v]) => bitFeature & v).map(([, v]) => v);
const bitFeatureEx = getXNextBytes(4).readUInt32LE();
const PreferredRate = getXNextBytes(4).readUInt32LE();
const minRate = getXNextBytes(4).readUInt32LE();
const maxRate = getXNextBytes(4).readUInt32LE();
const colorRGB = getXNextBytes(4).readUInt32LE();
const color = {
blue: colorRGB & 255,
green: colorRGB >> 8 & 255,
red: colorRGB >> 16 & 255
};
const nVersion = getXNextBytes(4).readUInt32LE();
const GPSPosition = cleanPacketString(getXNextBytes(8).toString("ascii"));
const userPosition = cleanPacketString(getXNextBytes(8).toString("ascii"));
const langCode = cleanPacketString(getXNextBytes(8).toString("ascii"));
const reservedASCII = cleanPacketString(getXNextBytes(8).toString("ascii"));
const reservedEx = cleanPacketString(getXNextBytes(64).toString("ascii"));
const reservedEx2 = cleanPacketString(getXNextBytes(36).toString("ascii"));
const deviceName = cleanPacketString(getXNextBytes(64).toString("ascii"));
const manufacturerName = cleanPacketString(getXNextBytes(64).toString("ascii"));
const applicationName = cleanPacketString(getXNextBytes(64).toString("ascii"));
const hostnameASCII = cleanPacketString(getXNextBytes(64).toString("ascii"));
const userName = cleanPacketString(getXNextBytes(128).toString("utf8"));
const userComment = cleanPacketString(getXNextBytes(128).toString("utf8"));
const data = {
applicationType,
features,
bitFeatureEx,
PreferredRate,
minRate,
maxRate,
color,
nVersion,
GPSPosition,
userPosition,
langCode,
reservedASCII,
reservedEx,
reservedEx2,
deviceName,
manufacturerName,
applicationName,
hostname: hostnameASCII,
userName,
userComment
};
return new _VBANPingPacket(
{
...headers,
service: 0 /* IDENTIFICATION */,
serviceFunction,
isReply
},
data
);
}
toUDPPacket() {
return _VBANPingPacket.toUDPPacket(this);
}
static toUDPPacket(packet) {
const dataBuffer = import_buffer4.Buffer.alloc(676);
let offset = 0;
offset = dataBuffer.writeUInt32LE(packet.data.applicationType, offset);
let features = 0;
packet.data.features.forEach((feature) => {
if (EServicePINGFeatures[feature]) {
features = features | feature;
}
});
offset = dataBuffer.writeUInt32LE(features, offset);
offset = dataBuffer.writeUInt32LE(packet.data.bitFeatureEx, offset);
offset = dataBuffer.writeUInt32LE(packet.data.PreferredRate, offset);
offset = dataBuffer.writeUInt32LE(packet.data.minRate, offset);
offset = dataBuffer.writeUInt32LE(packet.data.maxRate, offset);
const { red, green, blue } = packet.data.color;
offset = dataBuffer.writeUInt32LE((red & 255) << 16 | (green & 255) << 8 | blue & 255, offset);
offset = dataBuffer.writeUInt32LE(packet.data.nVersion, offset);
offset += dataBuffer.write(prepareStringForPacket(packet.data.GPSPosition, 8), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.userPosition, 8), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.langCode, 8), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.reservedASCII, 8), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.reservedEx, 64), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.reservedEx2, 36), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.deviceName, 64), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.manufacturerName, 64), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.applicationName, 64), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.hostname, 64), offset, "ascii");
offset += dataBuffer.write(prepareStringForPacket(packet.data.userName, 128), offset, "utf8");
dataBuffer.write(prepareStringForPacket(packet.data.userComment, 128), offset, "utf8");
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.sr,
frameCounter: packet.frameCounter,
part1: (packet.isReply ? 128 : 0) & 128 | packet.serviceFunction & 127,
part2: packet.service,
part3: 0
},
dataBuffer,
packet.sr
);
}
};
// src/packets/VBANServicePacket/VBANRealTimePacket.ts
var import_buffer5 = require("buffer");
var VBANRealTimePacket = class _VBANRealTimePacket extends VBANServicePacket {
/**
* not clear about the content of this buffer
*/
data;
constructor(headers, data) {
super(headers);
this.data = data;
}
static fromUDPPacket(headers, dataBuffer) {
const fn = headers.part1;
const serviceFunction = fn & 127;
const isReply = (fn & 128) >= 1;
return new _VBANRealTimePacket(
{
...headers,
service: 33 /* RTPACKET */,
serviceFunction,
isReply
},
dataBuffer
);
}
toUDPPacket() {
return _VBANRealTimePacket.toUDPPacket(this);
}
static toUDPPacket(packet) {
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.sr,
frameCounter: packet.frameCounter,
part1: (packet.isReply ? 128 : 0) & 128 | packet.serviceFunction & 127,
part2: packet.service,
part3: 0
},
import_buffer5.Buffer.from(""),
packet.sr
);
}
};
// src/packets/VBANServicePacket/VBANRealTimeRegisterAnswerPacket.ts
var import_buffer6 = require("buffer");
var ERegistrationAnswer = /* @__PURE__ */ ((ERegistrationAnswer2) => {
ERegistrationAnswer2[ERegistrationAnswer2["NO_RT_PACKET_SERVICE"] = 0] = "NO_RT_PACKET_SERVICE";
ERegistrationAnswer2[ERegistrationAnswer2["RT_PACKET_SERVICE_REGISTERED"] = 1] = "RT_PACKET_SERVICE_REGISTERED";
ERegistrationAnswer2[ERegistrationAnswer2["RT_PACKET_SERVICE_BUSY"] = 2] = "RT_PACKET_SERVICE_BUSY";
return ERegistrationAnswer2;
})(ERegistrationAnswer || {});
var VBANRealTimeRegisterAnswerPacket = class _VBANRealTimeRegisterAnswerPacket extends VBANServicePacket {
data;
constructor(headers, data) {
super(headers);
this.data = data;
}
static fromUDPPacket(headers) {
const fn = headers.part1;
const serviceFunction = fn & 127;
const isReply = (fn & 128) >= 1;
return new _VBANRealTimeRegisterAnswerPacket(
{
...headers,
service: 32 /* RTPACKETREGISTER */,
serviceFunction,
isReply
},
{
answer: headers.part3
}
);
}
toUDPPacket() {
return _VBANRealTimeRegisterAnswerPacket.toUDPPacket(this);
}
static toUDPPacket(packet) {
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.sr,
frameCounter: packet.frameCounter,
part1: (packet.isReply ? 128 : 0) & 128 | packet.serviceFunction & 127,
part2: packet.service,
part3: packet.data.answer
},
import_buffer6.Buffer.from(""),
packet.sr
);
}
};
// src/packets/VBANServicePacket/VBANRealTimeRegisterPacket.ts
var import_buffer7 = require("buffer");
var VBANRealTimeRegisterPacket = class _VBANRealTimeRegisterPacket extends VBANServicePacket {
data;
constructor(headers, data) {
super(headers);
this.data = data;
}
static fromUDPPacket(headers) {
const fn = headers.part1;
const serviceFunction = fn & 127;
const isReply = (fn & 128) >= 1;
if (isReply) {
return VBANRealTimeRegisterAnswerPacket.fromUDPPacket(headers);
}
return new _VBANRealTimeRegisterPacket(
{
...headers,
service: 32 /* RTPACKETREGISTER */,
serviceFunction,
isReply
},
{
timeout: headers.part3
}
);
}
toUDPPacket() {
return _VBANRealTimeRegisterPacket.toUDPPacket(this);
}
static toUDPPacket(packet) {
if (packet.data.timeout > 255 || packet.data.timeout < 0) {
throw new Error("timeout need to be between 0 and 255");
}
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.sr,
frameCounter: packet.frameCounter,
part1: (packet.isReply ? 128 : 0) & 128 | packet.serviceFunction & 127,
part2: packet.service,
part3: packet.data.timeout
},
import_buffer7.Buffer.from(""),
packet.sr
);
}
};
// src/packets/VBANServicePacket/VBANServicePacketFactory.ts
var VBANServicePacketFactory = class {
static fromUDPPacket(headersBuffer, dataBuffer) {
const headers = VBANPacket.prepareFromUDPPacket(headersBuffer);
const service = headers.part2;
return this.getConstructor(service).fromUDPPacket(headers, dataBuffer);
}
static getConstructor(protocol) {
switch (protocol) {
case 0 /* IDENTIFICATION */:
return VBANPingPacket;
case 1 /* CHATUTF8 */:
return VBANChatPacket;
case 33 /* RTPACKET */:
return VBANRealTimePacket;
case 32 /* RTPACKETREGISTER */:
return VBANRealTimeRegisterPacket;
default:
throw new Error(`unknown protocol ${protocol}`);
}
}
static toUDPPacket(packet) {
return packet.toUDPPacket();
}
};
// src/packets/VBANTXTPacket/ETextEncoding.ts
var ETextEncoding = /* @__PURE__ */ ((ETextEncoding2) => {
ETextEncoding2[ETextEncoding2["VBAN_TXT_ASCII"] = 0] = "VBAN_TXT_ASCII";
ETextEncoding2[ETextEncoding2["VBAN_TXT_UTF8"] = 16] = "VBAN_TXT_UTF8";
ETextEncoding2[ETextEncoding2["VBAN_TXT_WCHAR"] = 32] = "VBAN_TXT_WCHAR";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_3"] = 48] = "VBAN_SERIAL_UNDEFINED_3";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_4"] = 64] = "VBAN_SERIAL_UNDEFINED_4";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_5"] = 80] = "VBAN_SERIAL_UNDEFINED_5";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_6"] = 96] = "VBAN_SERIAL_UNDEFINED_6";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_7"] = 112] = "VBAN_SERIAL_UNDEFINED_7";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_8"] = 128] = "VBAN_SERIAL_UNDEFINED_8";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_9"] = 144] = "VBAN_SERIAL_UNDEFINED_9";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_10"] = 160] = "VBAN_SERIAL_UNDEFINED_10";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_11"] = 176] = "VBAN_SERIAL_UNDEFINED_11";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_12"] = 192] = "VBAN_SERIAL_UNDEFINED_12";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_13"] = 208] = "VBAN_SERIAL_UNDEFINED_13";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_UNDEFINED_14"] = 224] = "VBAN_SERIAL_UNDEFINED_14";
ETextEncoding2[ETextEncoding2["VBAN_SERIAL_USER"] = 240] = "VBAN_SERIAL_USER";
return ETextEncoding2;
})(ETextEncoding || {});
// src/packets/VBANTXTPacket/VBANTEXTPacket.ts
var import_buffer8 = require("buffer");
var VBANTEXTPacket = class _VBANTEXTPacket extends VBANPacket {
/**
* {@link VBANTEXTPacket.subProtocol}
*/
static subProtocol = 64 /* TEXT */;
subProtocol = _VBANTEXTPacket.subProtocol;
/**
* Bit rate is given in bps for information only. But it can be used internally to limit the bandwidth of
* the stream and for example gives more priority to audio stream or RT MIDI stream. It can be set
* to ZERO if there is no particular bit rate.
*/
bps;
/**
* Can be used to define a sub channel (sub text channel) and then manage up to 256 different
* virtual pipes (ZERO by default).
*/
channelsIdents;
/**
* Data type used to store data in the packet (ZERO/VBAN_DATATYPE_BYTE8 per default).
*/
formatBit;
/**
* Text format
*/
encoding;
/**
* not used . Replaced by {@link VBANTEXTPacket.bps}
*/
sr;
/**
* if data can be decoded, it will be decoded in text
*/
text;
/**
* you can access the raw dataBuffer (if available) to try another decoding
*/
dataBuffer;
constructor(headers, txt = "", dataBuffer) {
super({
...headers,
sp: _VBANTEXTPacket.subProtocol,
sr: 0
});
this.bps = headers.bps ?? BITS_SPEEDS[0];
this.channelsIdents = headers.channelsIdents ?? 0;
this.formatBit = headers.formatBit ?? 0 /* VBAN_DATATYPE_BYTE8 */;
this.encoding = headers.encoding;
this.text = txt;
this.dataBuffer = dataBuffer;
this.sr = 0;
}
static toUDPPacket(packet) {
var _a;
const data = packet.text ? import_buffer8.Buffer.from(packet.text, _VBANTEXTPacket.getEncoding(packet.encoding)) : packet.dataBuffer ?? import_buffer8.Buffer.from("");
const bpsId = Number(
(_a = Object.entries(BITS_SPEEDS).find(([, bps]) => bps && bps === packet.bps)) == null ? void 0 : _a.shift()
) || 0;
return this.convertToUDPPacket(
{
streamName: packet.streamName,
sp: packet.subProtocol,
sr: packet.bps,
frameCounter: packet.frameCounter,
part1: 0,
part2: packet.channelsIdents,
part3: packet.formatBit & 7 | packet.encoding & 240
},
data,
bpsId
);
}
static fromUDPPacket(headersBuffer, dataBuffer) {
const headers = this.prepareFromUDPPacket(headersBuffer);
if (headers.srIndex === void 0 || BITS_SPEEDS[headers.srIndex] === void 0) {
throw new Error(`unknown bits speed ${headers.srIndex}`);
}
const bps = BITS_SPEEDS[headers.srIndex];
const channelsIdents = headers.part2;
const dataFormat = headers.part3;
const formatBit = dataFormat & 7;
if (!EFormatBit[formatBit]) {
throw new Error(`unknown format bit ${formatBit}`);
}
const encoding = dataFormat & 240;
if (!ETextEncoding[encoding]) {
throw new Error(`unknown text stream type ${encoding}`);
}
const textEncoding = _VBANTEXTPacket.getEncoding(encoding);
let text;
if (textEncoding) {
text = dataBuffer.toString(textEncoding);
}
return new _VBANTEXTPacket(
{
...headers,
bps,
channelsIdents,
formatBit,
encoding
},
text,
dataBuffer
);
}
static getEncoding(streamType) {
let textEncoding;
if (streamType === 16 /* VBAN_TXT_UTF8 */) {
textEncoding = "utf8";
} else if (streamType === 32 /* VBAN_TXT_WCHAR */) {
textEncoding = "utf16le";
} else if (streamType === 0 /* VBAN_TXT_ASCII */) {
textEncoding = "ascii";
}
return textEncoding;
}
};
// src/VBANProtocolFactory.ts
var VBANProtocolFactory = class _VBANProtocolFactory {
static processPacket(packet) {
const headerBuffer = packet.subarray(0, 28);
const dataBuffer = packet.subarray(28);
if (headerBuffer.toString("ascii", 0, PACKET_IDENTIFICATION.length) !== PACKET_IDENTIFICATION) {
throw new Error("Invalid Header");
}
const header1 = headerBuffer.readUInt8(PACKET_IDENTIFICATION.length);
const subProtocol = header1 & 224;
return _VBANProtocolFactory.getConstructor(subProtocol).fromUDPPacket(headerBuffer, dataBuffer);
}
static getConstructor(protocol) {
switch (protocol) {
case 0 /* AUDIO */:
return VBANAudioPacket;
case 32 /* SERIAL */:
return VBANSerialPacket;
case 64 /* TEXT */:
return VBANTEXTPacket;
case 96 /* SERVICE */:
return VBANServicePacketFactory;
default:
throw new Error(`unknown protocol ${protocol}`);
}
}
static toUDPBuffer(packet) {
switch (packet.subProtocol) {
case 0 /* AUDIO */:
return VBANAudioPacket.toUDPPacket(packet);
case 32 /* SERIAL */:
return VBANSerialPacket.toUDPPacket(packet);
case 64 /* TEXT */:
return VBANTEXTPacket.toUDPPacket(packet);
case 96 /* SERVICE */:
return VBANServicePacketFactory.toUDPPacket(packet);
default:
throw new Error("unknown packet instance");
}
}
};
// src/VBANServer.ts
var import_node_dgram = __toESM(require("node:dgram"), 1);
var import_events = require("events");
var import_node_util = require("node:util");
var import_node_os = __toESM(require("node:os"), 1);
var VBANServer = class extends import_events.EventEmitter {
UDPServer;
options;
frameCounter = /* @__PURE__ */ new Map();
isListening = false;
constructor(options) {
super();
this.UDPServer = import_node_dgram.default.createSocket("udp4");
this.options = options || {};
if (this.options.autoReplyToPing === void 0) {
this.options.autoReplyToPing = true;
}
this.UDPServer.on("listening", (...args) => {
this.emit("listening", ...args);
this.isListening = true;
});
this.UDPServer.on("close", () => {
this.isListening = false;
});
this.UDPServer.on("error", (...args) => {
this.emit("error", ...args);
});
this.UDPServer.on("message", this.messageHandler.bind(this));
}
address() {
return this.UDPServer.address();
}
bind(...args) {
return new Promise((resolve) => {
this.UDPServer.bind(...args, resolve);
});
}
getFrameCounter(protocol) {
let frameCounter = this.frameCounter.get(protocol) ?? 0;
if (frameCounter >= MAX_FRAME_COUNTER) {
frameCounter = 0;
}
this.frameCounter.set(protocol, ++frameCounter);
return frameCounter;
}
send(packet, port, address) {
return new Promise((resolve, reject) => {
packet.frameCounter = this.getFrameCounter(packet.subProtocol);
this.UDPServer.send(VBANProtocolFactory.toUDPBuffer(packet), port, address, (error) => {
if (error) {
reject(error);
return;
}
resolve();
});
});
}
sendPing(receiver, isReply = false) {
const frameCounter = this.getFrameCounter(96 /* SERVICE */);
const defaultApp = {
applicationName: "Test application",
manufacturerName: "Anonymous",
applicationType: 16777216 /* SERVER */,
features: [1 /* AUDIO */, 768 /* MIDI */, 65536 /* TXT */, 256 /* SERIAL */],
bitFeatureEx: 0,
PreferredRate: 0,
minRate: 6e3,
maxRate: 705600,
color: { blue: 0, green: 128, red: 128 },
nVersion: 12345,
GPSPosition: "",
userPosition: "",
langCode: "fr-fr",
reservedASCII: "",
reservedEx: "",
reservedEx2: "",
deviceName: "NodeJs Server",
userName: "",
userComment: ""
};
const application = Object.assign(defaultApp, this.options.application);
const answerPacket = new VBANPingPacket(
{
streamName: "VBAN Service",
service: 0 /* IDENTIFICATION */,
serviceFunction: 0 /* PING0 */,
frameCounter,
isReply
},
{
applicationName: application.applicationName,
manufacturerName: application.manufacturerName,
applicationType: application.applicationType,
features: application.features,
bitFeatureEx: application.bitFeatureEx,
PreferredRate: application.PreferredRate,
minRate: application.minRate,
maxRate: application.maxRate,
color: application.color,
nVersion: application.nVersion,
GPSPosition: application.GPSPosition,
userPosition: application.userPosition,
langCode: application.langCode,
reservedASCII: application.reservedASCII,
reservedEx: application.reservedEx,
reservedEx2: application.reservedEx2,
deviceName: application.deviceName,
hostname: application.hostname ?? import_node_os.default.hostname(),
userName: application.userName,
userComment: application.userComment
}
);
return this.send(answerPacket, receiver.port, receiver.address);
}
messageHandler = async (msg, sender) => {
if (this.options.beforeProcessPacket) {
if (!this.options.beforeProcessPacket(msg, sender)) {
return;
}
}
const packet = VBANProtocolFactory.processPacket(msg);
if (this.options.autoReplyToPing && packet instanceof VBANPingPacket && !packet.isReply) {
await this.sendPing(sender, true);
}
this.emit("message", packet, sender);
};
async close() {
await (0, import_node_util.promisify)(this.UDPServer.close)();
this.emit("close");
}
};
// src/pkg.ts
var pkg = { name: "vban", version: "1.4.1" };
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BITS_SPEEDS,
EBitsResolutions,
ECodecs,
EFormatBit,
ERegistrationAnswer,
ESerialStreamType,
EServiceFunction,
EServicePINGApplicationType,
EServicePINGFeatures,
EServiceType,
ESubProtocol,
ETextEncoding,
MAX_FRAME_COUNTER,
PACKET_IDENTIFICATION,
STREAM_NAME_LENGTH,
VBANAudioPacket,
VBANChatPacket,
VBANPacket,
VBANPingPacket,
VBANProtocolFactory,
VBANRealTimePacket,
VBANRealTimeRegisterAnswerPacket,
VBANRealTimeRegisterPacket,
VBANSerialPacket,
VBANServer,
VBANServicePacket,
VBANServicePacketFactory,
VBANTEXTPacket,
VBAN_DATA_MAX_SIZE,
VBAN_PACKET_MAX_SIZE,
bufferToHex,
cleanPacketString,
dec2bin,
pkg,
prepareStringForPacket,
sampleRates,
serialStopModes
});
//# sourceMappingURL=index.cjs.map