vban
Version:
Node VBAN implementation
4 lines • 89.3 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/packets/VBANAudioPacket/EBitsResolutions.ts", "../../src/packets/VBANAudioPacket/ECodecs.ts", "../../src/packets/VBANPacket.ts", "../../src/packets/ESubProtocol.ts", "../../src/commons.ts", "../../src/packets/VBANSpecs.ts", "../../src/packets/VBANAudioPacket/VBANAudioPacket.ts", "../../src/packets/VBANSerialPacket/ESerialStreamType.ts", "../../src/packets/VBANSerialPacket/VBANSerialPacket.ts", "../../src/packets/VBANTXTPacket/ETextEncoding.ts", "../../src/packets/VBANTXTPacket/VBANTEXTPacket.ts", "../../src/packets/VBANServicePacket/VBANServicePacket.ts", "../../src/packets/VBANServicePacket/EServiceType.ts", "../../src/packets/VBANServicePacket/subPackets/VBANChatPacket.ts", "../../src/packets/VBANServicePacket/subPackets/VBANPingPacket.ts", "../../src/packets/VBANServicePacket/EServicePINGApplicationType.ts", "../../src/packets/VBANServicePacket/EServicePINGFeatures.ts", "../../src/packets/VBANServicePacket/subPackets/VBANRealTimePacket.ts", "../../src/packets/VBANServicePacket/subPackets/VBANRealTimeRegisterAnswerPacket.ts", "../../src/packets/VBANServicePacket/subPackets/VBANRealTimeRegisterPacket.ts", "../../src/packets/VBANServicePacket/subPackets/VBANRequestReplyPacket.ts", "../../src/packets/VBANServicePacket/EServiceFunction.ts", "../../src/packets/VBANServicePacket/VBANServicePacketFactory.ts", "../../src/packets/VBANUnknownPacket/VBANUnknownPacket.ts", "../../src/VBANProtocolFactory.ts", "../../src/VBANServer.ts", "../../src/pkg.ts"],
"sourcesContent": ["//Bit Resolution\nexport enum EBitsResolutions {\n VBAN_DATATYPE_BYTE8 = 0x00,\n VBAN_DATATYPE_INT16 = 0x01,\n VBAN_DATATYPE_INT24 = 0x02,\n VBAN_DATATYPE_INT32 = 0x03,\n VBAN_DATATYPE_FLOAT32 = 0x04,\n VBAN_DATATYPE_FLOAT64 = 0x05,\n VBAN_DATATYPE_12BITS = 0x06,\n VBAN_DATATYPE_10BITS = 0x07\n}\n", "export enum ECodecs {\n VBAN_CODEC_PCM = 0x00,\n VBAN_CODEC_VBCA = 0x10, //VB-AUDIO AOIP CODEC\n VBAN_CODEC_VBCV = 0x20, //VB-AUDIO VOIP CODEC\n VBAN_CODEC_UNDEFINED_1 = 0x30,\n VBAN_CODEC_UNDEFINED_2 = 0x40,\n VBAN_CODEC_UNDEFINED_3 = 0x50,\n VBAN_CODEC_UNDEFINED_4 = 0x60,\n VBAN_CODEC_UNDEFINED_5 = 0x70,\n VBAN_CODEC_UNDEFINED_6 = 0x80,\n VBAN_CODEC_UNDEFINED_7 = 0x90,\n VBAN_CODEC_UNDEFINED_8 = 0xa0,\n VBAN_CODEC_UNDEFINED_9 = 0xb0,\n VBAN_CODEC_UNDEFINED_10 = 0xc0,\n VBAN_CODEC_UNDEFINED_11 = 0xd0,\n VBAN_CODEC_UNDEFINED_12 = 0xe0,\n VBAN_CODEC_USER = 0xf0\n}\n", "import { Buffer } from 'node:buffer';\nimport { ESubProtocol } from './ESubProtocol.js';\nimport { IVBANHeaderCommon } from './IVBANHeaderCommon.js';\nimport {\n cleanPacketString,\n PACKET_IDENTIFICATION,\n sampleRates,\n sampleRatesMapIndex,\n STREAM_NAME_LENGTH,\n SUB_PROTOCOL_MASK\n} from '../commons.js';\nimport { IVBANHeader } from './IVBANHeader.js';\nimport { VBAN_DATA_MAX_SIZE, VBAN_HEADER_LENGTH } from './VBANSpecs.js';\n\nexport class VBANPacket {\n /**\n * the subProtocol of this packet\n * {@link ESubProtocol}\n */\n public subProtocol: ESubProtocol = ESubProtocol.AUDIO;\n /**\n * the name of the current stream .\n * Voicemeeter rely on it to allow a packet or not\n */\n public streamName: string;\n /**\n * Sample Rate for this stream\n */\n public sr: number;\n /**\n * frameCounter allow checking if you receive frame in order, and without losing them\n */\n public frameCounter: number;\n\n public static readonly frameCounters: Map<string, number> = new Map<string, number>();\n\n public static getSampleRate(srIndex?: number): number {\n if (srIndex === undefined || srIndex === null || !sampleRates.hasOwnProperty(srIndex) || sampleRates[srIndex] === undefined) {\n throw new Error(`unknown sample rate ${srIndex}`);\n }\n return sampleRates[srIndex];\n }\n\n public static parsePacketHeader(headersBuffer: Buffer): IVBANHeaderCommon {\n const headers: Partial<IVBANHeaderCommon> = {};\n\n if (headersBuffer.toString('ascii', 0, PACKET_IDENTIFICATION.length) !== PACKET_IDENTIFICATION) {\n throw new Error('Invalid Header');\n }\n\n // read next 4 Bytes\n const chunk = headersBuffer.readUInt32BE(PACKET_IDENTIFICATION.length);\n\n // noinspection PointlessArithmeticExpressionJS\n const sr_sp = (chunk >> (3 * 8)) & 0b11111111;\n // noinspection PointlessArithmeticExpressionJS\n headers.part1 = (chunk >> (2 * 8)) & 0b11111111;\n // noinspection PointlessArithmeticExpressionJS\n headers.part2 = (chunk >> (1 * 8)) & 0b11111111;\n // noinspection PointlessArithmeticExpressionJS\n headers.part3 = (chunk >> (0 * 8)) & 0b11111111;\n\n // 3 first bits\n headers.sp = sr_sp & SUB_PROTOCOL_MASK;\n\n //take last 5 bits for sampleRate\n headers.srIndex = sr_sp & 0b00011111; // 5 last bits\n\n // Stream Name (16 bytes)\n headers.streamName = cleanPacketString(headersBuffer.toString('ascii', 8, 8 + STREAM_NAME_LENGTH));\n\n // Frame Counter (32 bits)\n headers.frameCounter = headersBuffer.readUInt32LE(24);\n\n return headers as IVBANHeaderCommon;\n }\n\n public static parsePacket(packet: Buffer): {\n headers: IVBANHeaderCommon;\n data: Buffer;\n } {\n const headerBuffer = packet.subarray(0, VBAN_HEADER_LENGTH);\n const dataBuffer = packet.subarray(VBAN_HEADER_LENGTH);\n\n const headers = this.parsePacketHeader(headerBuffer);\n\n return {\n headers,\n data: dataBuffer\n };\n }\n\n /**\n * Extract headers and data from UDPPacket, each Packet will continue the process\n * @deprecated\n */\n public static prepareFromUDPPacket(headersBuffer: Buffer, checkSR = true): IVBANHeaderCommon {\n const headers = this.parsePacketHeader(headersBuffer);\n if (checkSR) {\n headers.sr = this.getSampleRate(headers.srIndex);\n }\n\n return headers;\n }\n\n /**\n * common constructor\n */\n constructor(headers: IVBANHeader) {\n this.sr = headers.sr ?? 0;\n this.streamName = headers.streamName;\n // Frame Counter (32 bits)\n this.frameCounter = headers.frameCounter ?? 1;\n }\n\n /**\n * Convert a VBANPacket to a UDP packet\n */\n protected static convertToUDPPacket(headers: Omit<IVBANHeaderCommon, 'srIndex'>, data: Buffer, sampleRate?: number): Buffer {\n if (headers.sp === ESubProtocol.UNKNOWN) {\n throw new Error(`You can't convert an unknown packet to UDP packet`);\n }\n if (data.length > VBAN_DATA_MAX_SIZE) {\n throw new Error(\n `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`\n );\n }\n\n const finalBuffer = Buffer.alloc(VBAN_HEADER_LENGTH + data.length);\n\n let offset = 0;\n\n offset += finalBuffer.write(PACKET_IDENTIFICATION, offset, 'ascii');\n\n let rateIndex: number = 0;\n if (sampleRate === undefined && headers.sr) {\n // La recherche est maintenant instantan\u00E9e (O(1))\n const rateIndexFromMap = sampleRatesMapIndex.get(headers.sr);\n if (!rateIndexFromMap) {\n throw new Error(`fail to find index for sample rate ${headers.sr}`);\n }\n\n rateIndex = rateIndexFromMap;\n } else if (sampleRate !== undefined) {\n rateIndex = sampleRate;\n }\n\n // \u00C9criture des parties du header avec `writeUInt8` (plus rapide que `fill`)\n offset = finalBuffer.writeUInt8((rateIndex & 0b00011111) | (headers.sp & 0b11100000), offset);\n offset = finalBuffer.writeUInt8(headers.part1, offset);\n offset = finalBuffer.writeUInt8(headers.part2, offset);\n offset = finalBuffer.writeUInt8(headers.part3, offset);\n\n // \u00C9criture du nom du stream\n offset += finalBuffer.write(headers.streamName.padEnd(STREAM_NAME_LENGTH, '\\0'), offset, 'ascii');\n\n // \u00C9criture du compteur\n finalBuffer.writeUInt32LE(headers.frameCounter ?? 1, offset);\n\n data.copy(finalBuffer, VBAN_HEADER_LENGTH);\n\n return finalBuffer;\n }\n\n /**\n * EXPERIMENTAL - DO NOT USE\n *\n * @experimental\n */\n public static checkFrameCounter(headers: VBANPacket) {\n //check frameCounter\n const frameCounterKey = 'str';\n const frameCounter = this.frameCounters.get(frameCounterKey);\n\n if (!headers.frameCounter) {\n return;\n }\n\n if (frameCounter && frameCounter > headers.frameCounter && headers.frameCounter > 0) {\n console.log('frameCounter error');\n } else if (frameCounter && headers.frameCounter > 0) {\n console.log('frame counter', 'old', frameCounter, 'new', headers.frameCounter, 'diff', headers.frameCounter - frameCounter);\n } else if (headers.frameCounter === 0) {\n console.log('frame 0');\n }\n\n this.frameCounters.set(frameCounterKey, headers.frameCounter);\n }\n\n public toUDPPacket(): Buffer {\n throw new Error('Not implemented');\n }\n}\n", "//sub protocols\nexport enum ESubProtocol {\n // specific, not handled by VBAN\n UNKNOWN = -1,\n // 0x00\n AUDIO = 0,\n // 0x20\n SERIAL = 32,\n // 0x40\n TEXT = 64,\n // 0x60\n SERVICE = 96\n}\n", "import { Buffer } from 'node:buffer';\n\nexport const PACKET_IDENTIFICATION = 'VBAN';\n\nexport const SUB_PROTOCOL_MASK = 0b11100000;\n\n/**\n * the stream name is limited to 16 bytes\n */\nexport const STREAM_NAME_LENGTH = 16;\n\nexport const BITS_SPEEDS: Record<number, number> = {\n 0: 0,\n 1: 110,\n 2: 150,\n 3: 300,\n 4: 600,\n 5: 1200,\n 6: 2400,\n 7: 4800,\n 8: 9600,\n 9: 14400,\n 10: 19200,\n 11: 31250,\n 12: 38400,\n 13: 57600,\n 14: 115200,\n 15: 128000,\n 16: 230400,\n 17: 250000,\n 18: 256000,\n 19: 460800,\n 20: 921600,\n 21: 1000000,\n 22: 1500000,\n 23: 2000000,\n 24: 3000000,\n 25: 0,\n 26: 0,\n 27: 0,\n 28: 0,\n 29: 0,\n 30: 0,\n 31: 0\n};\n\nexport const MBPS_SPEEDS: Record<number, number> = {\n 0: 0,\n 1: 1,\n 2: 2,\n 3: 3,\n 4: 4,\n 5: 5,\n 6: 6,\n 7: 8,\n 8: 10,\n 9: 12,\n 10: 16,\n 11: 24,\n 12: 36,\n 13: 48,\n 14: 60,\n 15: 84,\n 16: 108,\n 17: 156,\n 18: 204,\n 19: 252,\n 20: 300,\n 21: 400,\n 22: 500,\n 23: 600,\n 24: 800,\n 25: 0, // Undefined\n 26: 0, // Undefined\n 27: 0, // Undefined\n 28: 0, // Undefined\n 29: 0, // Undefined\n 30: 0, // Undefined\n 31: 0 // Undefined\n};\n\nexport enum EFormatBit {\n /**\n * 0 to 255\n */\n VBAN_DATATYPE_BYTE8 = 0x00\n}\n\nexport const serialStopModes: Array<{ mode: number; stop: number | null }> = [\n {\n mode: 0,\n stop: 1\n },\n {\n mode: 1,\n stop: 1.5\n },\n {\n mode: 2,\n stop: 2\n },\n {\n mode: 3,\n stop: null\n }\n];\n\nexport function dec2bin(dec: number) {\n return ((dec >>> 0).toString(2) || '').padStart(8, '0');\n}\n\nexport function bufferToHex(buffer: Buffer) {\n if (!Buffer.isBuffer(buffer)) {\n throw new TypeError('need to be a buffer');\n }\n\n let hexString = '';\n for (let i = 0; i < buffer.length; i++) {\n const hex = buffer[i].toString(16).padStart(2, '0');\n hexString += hex;\n\n if (i < buffer.length - 1) {\n hexString += ' ';\n }\n }\n return hexString?.toUpperCase();\n}\n\nexport function prepareStringForPacket(str: string, maxLength: number): string {\n return str.slice(0, maxLength).padEnd(maxLength, '\\0');\n}\n\nexport function cleanPacketString(str: string): string {\n return str.replace(/\\0/g, '');\n}\n\n//sample rates\nexport const sampleRates: Record<number, number> = {\n 0: 6000,\n 1: 12000,\n 2: 24000,\n 3: 48000,\n 4: 96000,\n 5: 192000,\n 6: 384000,\n 7: 8000,\n 8: 16000,\n 9: 32000,\n 10: 64000,\n 11: 128000,\n 12: 256000,\n 13: 512000,\n 14: 11025,\n 15: 22050,\n 16: 44100,\n 17: 88200,\n 18: 176400,\n 19: 352800,\n 20: 705600,\n 21: 0,\n 22: 0,\n 23: 0,\n 24: 0,\n 25: 0,\n 26: 0,\n 27: 0,\n 28: 0,\n 29: 0,\n 30: 0,\n 31: 0\n};\n\nexport const sampleRatesMap = new Map<number, number>();\nexport const sampleRatesMapIndex = new Map<number, number>();\nfor (const [index, rate] of Object.entries(sampleRates)) {\n sampleRatesMapIndex.set(rate, Number(index));\n sampleRatesMap.set(Number(index), rate);\n}\n", "export const MAX_FRAME_COUNTER = 4294967295;\nexport const VBAN_DATA_MAX_SIZE = 1436;\nexport const VBAN_HEADER_LENGTH = 28;\nexport const VBAN_PACKET_MAX_SIZE = 1464;\n", "import { VBANPacket } from '../VBANPacket.js';\nimport { ESubProtocol } from '../ESubProtocol.js';\nimport { EBitsResolutions } from './EBitsResolutions.js';\nimport { ECodecs } from './ECodecs.js';\nimport { IVBANHeaderAudio } from './IVBANHeaderAudio.js';\nimport { IBitResolution } from './IBitResolution.js';\nimport { Buffer } from 'node:buffer';\nimport { IVBANHeaderCommon } from '../IVBANHeaderCommon.js';\n\nexport class VBANAudioPacket extends VBANPacket {\n /**\n * {@link VBANAudioPacket.subProtocol}\n */\n public static readonly subProtocol: ESubProtocol = ESubProtocol.AUDIO;\n public subProtocol: ESubProtocol = VBANAudioPacket.subProtocol;\n /**\n * Number of sample is given by an 8 bits unsigned integer (0 \u2013 255) where 0 means 1 sample and\n * 255 means 256 samples\n */\n public nbSample: number;\n /**\n * Number of channel is given by an 8 bits unsigned integer (0 \u2013 255) where 0 means 1 channel\n * and 255 means 256 channels.\n */\n public nbChannel: number;\n /**\n * Data type used to store audio sample in the packet\n * Use it to select the correct bitResolution {@link VBANAudioPacket.bitResolutions}, or directly use {@link VBANAudioPacket.bitResolutionObject}\n */\n public bitResolution: EBitsResolutions;\n /**\n * the bit resolution selected by the id in {@link VBANAudioPacket.bitResolution}\n */\n public readonly bitResolutionObject: IBitResolution;\n /**\n * Audio codec used\n */\n public codec: ECodecs;\n\n /**\n * current audio\n */\n public data: Buffer;\n\n constructor(headers: IVBANHeaderAudio, data: Buffer) {\n super({\n ...headers,\n sp: VBANAudioPacket.subProtocol\n });\n\n this.nbSample = headers.nbSample;\n this.nbChannel = headers.nbChannel;\n this.bitResolution = headers.bitResolution;\n if (!VBANAudioPacket.bitResolutions[headers.bitResolution]) {\n throw new Error(`fail to found bitResolution with ID ${headers.bitResolution}`);\n }\n this.bitResolutionObject = VBANAudioPacket.bitResolutions[headers.bitResolution];\n this.codec = headers.codec;\n\n this.data = data;\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANAudioPacket)['toUDPPacket']> {\n return VBANAudioPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANAudioPacket): Buffer {\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: packet.nbSample - 1,\n part2: packet.nbChannel - 1,\n part3: (packet.bitResolution & 0b0000111) | (packet.codec & 0b11110000)\n },\n packet.data\n );\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, dataBuffer: Buffer): VBANAudioPacket {\n const nbSample = headers.part1 + 1;\n const nbChannel = headers.part2 + 1;\n\n // Data Format / Codec (3 + 1 + 4 bits)\n const dataFormatAndCodec = headers.part3;\n\n const bitResolution = dataFormatAndCodec & 0b0000111;\n if (!EBitsResolutions[bitResolution]) {\n throw new Error(`unknown bit resolution ${bitResolution}`);\n }\n\n const codec = dataFormatAndCodec & 0b11110000;\n if (!ECodecs[codec]) {\n throw new Error(`unknown codec ${codec}`);\n }\n\n headers.sr = this.getSampleRate(headers.srIndex);\n\n return new VBANAudioPacket(\n {\n ...headers,\n nbSample,\n nbChannel,\n bitResolution,\n codec\n },\n dataBuffer\n );\n }\n\n public static readonly bitResolutions: Record<number, IBitResolution> = {\n 0: { bitDepth: 8, signed: false, float: false },\n 1: { bitDepth: 16, signed: true, float: false },\n 2: { bitDepth: 24, signed: true, float: false },\n 3: { bitDepth: 32, signed: true, float: false },\n 4: { bitDepth: 32, signed: true, float: true },\n 5: { bitDepth: 64, signed: true, float: true },\n 6: { bitDepth: 12, signed: true, float: false },\n 7: { bitDepth: 10, signed: true, float: false }\n };\n}\n", "export enum ESerialStreamType {\n VBAN_SERIAL_GENERIC = 0x00,\n VBAN_SERIAL_MIDI = 0x10,\n VBAN_SERIAL_UNDEFINED_2 = 0x20,\n VBAN_SERIAL_UNDEFINED_3 = 0x30,\n VBAN_SERIAL_UNDEFINED_4 = 0x40,\n VBAN_SERIAL_UNDEFINED_5 = 0x50,\n VBAN_SERIAL_UNDEFINED_6 = 0x60,\n VBAN_SERIAL_UNDEFINED_7 = 0x70,\n VBAN_SERIAL_UNDEFINED_8 = 0x80,\n VBAN_SERIAL_UNDEFINED_9 = 0x90,\n VBAN_SERIAL_UNDEFINED_10 = 0xa0,\n VBAN_SERIAL_UNDEFINED_11 = 0xb0,\n VBAN_SERIAL_UNDEFINED_12 = 0xc0,\n VBAN_SERIAL_UNDEFINED_13 = 0xd0,\n VBAN_SERIAL_UNDEFINED_14 = 0xe0,\n VBAN_SERIAL_USER = 0xf0\n}\n", "import { VBANPacket } from '../VBANPacket.js';\nimport { ESubProtocol } from '../ESubProtocol.js';\nimport { BITS_SPEEDS, EFormatBit, serialStopModes } from '../../commons.js';\nimport { ISerialBitMode } from './ISerialBitMode.js';\nimport { ESerialStreamType } from './ESerialStreamType.js';\nimport { IVBANHeaderSerial } from './IVBANHeaderSerial.js';\nimport { Buffer } from 'node:buffer';\nimport { IVBANHeaderCommon } from '../IVBANHeaderCommon.js';\n\nexport class VBANSerialPacket extends VBANPacket {\n /**\n * {@link VBANSerialPacket.subProtocol}\n */\n public static readonly subProtocol: ESubProtocol = ESubProtocol.SERIAL;\n public subProtocol: ESubProtocol = VBANSerialPacket.subProtocol;\n /**\n * This field is used to give possible information on COM port and serial transmission mode related\n * to a Hardware COM port. This is made to possibly emulate COM to COM port connections and\n * let the receiver configure the physical COM port in the right mode.\n */\n public bitMode: ISerialBitMode;\n /**\n * Can be used to define a sub channel (sub serial link) and then manage up to 256 different\n * serial virtual pipes (ZERO by default).\n */\n public channelsIdents: number;\n /**\n * SR / bps : Bit rate is given in bps for information only. But it can be useful if serial data come from or go to\n * a particular COM port. Set to ZERO if there is no particular bit rate.\n */\n public bps: number;\n /**\n * not used . Replaced by {@link VBANSerialPacket.bps}\n */\n public sr: number = 0;\n /**\n * Data type used to store data in the packet (ZERO per default). The index is stored on 3 first bits.\n * Bit 3 must be ZERO. Bits 4 to 7 gives additional mode\n */\n public formatBit: EFormatBit;\n /**\n * type of stream . MIDI or SERIAL ... But in practice, only serial is used (MIDI is serial)\n */\n public streamType: ESerialStreamType;\n\n public data: Buffer;\n\n constructor(headers: IVBANHeaderSerial, data: Buffer) {\n super({\n ...headers,\n sp: VBANSerialPacket.subProtocol,\n sr: 0\n });\n\n this.bitMode = headers.bitMode;\n this.channelsIdents = headers.channelsIdents;\n this.bps = headers.bps;\n this.formatBit = headers.formatBit;\n this.streamType = headers.streamType;\n\n this.data = data;\n\n //reset sr\n this.sr = 0;\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANSerialPacket)['toUDPPacket']> {\n return VBANSerialPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANSerialPacket): Buffer {\n let part1 = 0;\n\n const mode = serialStopModes.find((m) => m.stop === packet.bitMode.stop)?.mode;\n if (mode === undefined) {\n throw new Error(`fail to found mode for stop ${packet.bitMode.stop}`);\n }\n part1 |= mode & 0b00000011;\n\n if (packet.bitMode.start) {\n part1 |= 0b00000100;\n }\n\n if (packet.bitMode.parity) {\n part1 |= 0b00001000;\n }\n\n if (packet.bitMode.multipart) {\n part1 |= 0b10000000;\n }\n\n //search bpsId\n const bpsId =\n Number(\n Object.entries(BITS_SPEEDS)\n .find(([, bps]) => bps && bps === packet.bps)\n ?.shift()\n ) || 0;\n\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.bps,\n frameCounter: packet.frameCounter,\n part1,\n part2: packet.channelsIdents,\n part3: (packet.formatBit & 0b00000111) | (packet.streamType & 0b11110000)\n },\n packet.data,\n bpsId\n );\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, dataBuffer: Buffer): VBANSerialPacket {\n if (headers.srIndex === undefined || BITS_SPEEDS[headers.srIndex] === undefined) {\n throw new Error(`unknown bits speed ${headers.srIndex}`);\n }\n\n const bps = BITS_SPEEDS[headers.srIndex];\n\n const bitModeRaw = headers.part1;\n\n const stopMode = bitModeRaw & 0b00000011;\n\n const stop = serialStopModes.find((m) => m.mode === stopMode)?.stop ?? null;\n\n const start = (bitModeRaw & 0b00000100) === 4;\n const parity = (bitModeRaw & 0b00001000) === 8;\n const multipart = (bitModeRaw & 0b10000000) === 128;\n\n const bitMode = {\n stop,\n start,\n parity,\n multipart\n };\n\n const channelsIdents = headers.part2;\n\n const dataFormat = headers.part3;\n const formatBit = dataFormat & 0b00000111;\n if (!EFormatBit[formatBit]) {\n throw new Error(`unknown format bit ${formatBit}`);\n }\n\n const streamType = dataFormat & 0b11110000;\n if (!ESerialStreamType[streamType]) {\n throw new Error(`unknown stream type ${streamType}`);\n }\n\n return new VBANSerialPacket(\n {\n ...headers,\n bps,\n bitMode,\n channelsIdents,\n formatBit,\n streamType\n },\n dataBuffer\n );\n }\n}\n", "export enum ETextEncoding {\n VBAN_TXT_ASCII = 0x00,\n VBAN_TXT_UTF8 = 0x10,\n VBAN_TXT_WCHAR = 0x20,\n VBAN_SERIAL_UNDEFINED_3 = 0x30,\n VBAN_SERIAL_UNDEFINED_4 = 0x40,\n VBAN_SERIAL_UNDEFINED_5 = 0x50,\n VBAN_SERIAL_UNDEFINED_6 = 0x60,\n VBAN_SERIAL_UNDEFINED_7 = 0x70,\n VBAN_SERIAL_UNDEFINED_8 = 0x80,\n VBAN_SERIAL_UNDEFINED_9 = 0x90,\n VBAN_SERIAL_UNDEFINED_10 = 0xa0,\n VBAN_SERIAL_UNDEFINED_11 = 0xb0,\n VBAN_SERIAL_UNDEFINED_12 = 0xc0,\n VBAN_SERIAL_UNDEFINED_13 = 0xd0,\n VBAN_SERIAL_UNDEFINED_14 = 0xe0,\n VBAN_SERIAL_USER = 0xf0\n}\n", "import { VBANPacket } from '../VBANPacket.js';\nimport { Buffer } from 'node:buffer';\nimport { ESubProtocol } from '../ESubProtocol.js';\nimport { BITS_SPEEDS, EFormatBit } from '../../commons.js';\nimport { ETextEncoding } from './ETextEncoding.js';\nimport { IVBANHeaderTEXT } from './IVBANHeaderTEXT.js';\nimport { IVBANHeaderCommon } from '../IVBANHeaderCommon.js';\n\nexport class VBANTEXTPacket extends VBANPacket {\n /**\n * {@link VBANTEXTPacket.subProtocol}\n */\n public static readonly subProtocol: ESubProtocol = ESubProtocol.TEXT;\n public subProtocol: ESubProtocol = VBANTEXTPacket.subProtocol;\n /**\n * Bit rate is given in bps for information only. But it can be used internally to limit the bandwidth of\n * the stream and for example gives more priority to audio stream or RT MIDI stream. It can be set\n * to ZERO if there is no particular bit rate.\n */\n public bps: number;\n /**\n * Can be used to define a sub channel (sub text channel) and then manage up to 256 different\n * virtual pipes (ZERO by default).\n */\n public channelsIdents: number;\n /**\n * Data type used to store data in the packet (ZERO/VBAN_DATATYPE_BYTE8 per default).\n */\n public formatBit: EFormatBit;\n /**\n * Text format\n */\n public encoding: ETextEncoding;\n /**\n * not used . Replaced by {@link VBANTEXTPacket.bps}\n */\n sr: number;\n /**\n * if data can be decoded, it will be decoded in text\n */\n public text: string;\n /**\n * you can access the raw dataBuffer (if available) to try another decoding\n * but will not be sent\n */\n public dataBuffer?: Buffer;\n\n constructor(headers: IVBANHeaderTEXT, txt: string = '', dataBuffer?: Buffer) {\n super({\n ...headers,\n sp: VBANTEXTPacket.subProtocol,\n sr: 0\n });\n\n this.bps = headers.bps ?? BITS_SPEEDS[0];\n this.channelsIdents = headers.channelsIdents ?? 0;\n this.formatBit = headers.formatBit ?? EFormatBit.VBAN_DATATYPE_BYTE8;\n this.encoding = headers.encoding;\n\n this.text = txt;\n this.dataBuffer = dataBuffer;\n\n //force sr to 0\n this.sr = 0;\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANTEXTPacket)['toUDPPacket']> {\n return VBANTEXTPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANTEXTPacket): Buffer {\n const data = packet.text\n ? Buffer.from(packet.text, VBANTEXTPacket.getEncoding(packet.encoding))\n : (packet.dataBuffer ?? Buffer.from(''));\n\n const bpsId =\n Number(\n Object.entries(BITS_SPEEDS)\n .find(([, bps]) => bps && bps === packet.bps)\n ?.shift()\n ) || 0;\n\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.bps,\n frameCounter: packet.frameCounter,\n part1: 0,\n part2: packet.channelsIdents,\n part3: (packet.formatBit & 0b00000111) | (packet.encoding & 0b11110000)\n },\n data,\n bpsId\n );\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, dataBuffer: Buffer) {\n if (headers.srIndex === undefined || BITS_SPEEDS[headers.srIndex] === undefined) {\n throw new Error(`unknown bits speed ${headers.srIndex}`);\n }\n\n const bps = BITS_SPEEDS[headers.srIndex];\n\n const channelsIdents = headers.part2;\n\n const dataFormat = headers.part3;\n const formatBit = dataFormat & 0b00000111;\n if (!EFormatBit[formatBit]) {\n throw new Error(`unknown format bit ${formatBit}`);\n }\n\n const encoding = dataFormat & 0b11110000;\n if (!ETextEncoding[encoding]) {\n throw new Error(`unknown text stream type ${encoding}`);\n }\n\n const textEncoding = VBANTEXTPacket.getEncoding(encoding);\n\n let text;\n if (textEncoding) {\n text = dataBuffer.toString(textEncoding);\n }\n\n return new VBANTEXTPacket(\n {\n ...headers,\n bps,\n channelsIdents,\n formatBit,\n encoding\n },\n text,\n dataBuffer\n );\n }\n\n static getEncoding(streamType: ETextEncoding): BufferEncoding | undefined {\n let textEncoding: BufferEncoding | undefined;\n if (streamType === ETextEncoding.VBAN_TXT_UTF8) {\n textEncoding = 'utf8';\n } else if (streamType === ETextEncoding.VBAN_TXT_WCHAR) {\n //need to test this, voicemeeter seems to don't use it\n textEncoding = 'utf16le';\n } else if (streamType === ETextEncoding.VBAN_TXT_ASCII) {\n textEncoding = 'ascii';\n }\n\n return textEncoding;\n }\n}\n", "import { Buffer } from 'node:buffer';\nimport { VBANPacket } from '../VBANPacket.js';\nimport { ESubProtocol } from '../ESubProtocol.js';\nimport { EServiceType } from './EServiceType.js';\nimport { IVBANHeaderService } from './IVBANHeaderService.js';\nimport { EServiceFunction } from './EServiceFunction.js';\nimport { IVBANHeaderCommon } from '../IVBANHeaderCommon.js';\n\nexport class VBANServicePacket extends VBANPacket {\n /**\n * {@link VBANServicePacket.subProtocol}\n */\n public static readonly subProtocol: ESubProtocol = ESubProtocol.SERVICE;\n public subProtocol: ESubProtocol = VBANServicePacket.subProtocol;\n /**\n * Sub Type of the service packet\n * {@link EServiceType}\n */\n public service: EServiceType;\n /**\n * current function for this function\n */\n public serviceFunction: EServiceFunction;\n /**\n * answer is a reply to another request\n */\n public isReply: boolean = false;\n\n public data: unknown;\n\n /**\n * not used .\n */\n public sr: number = 0;\n\n constructor(headers: IVBANHeaderService) {\n super({\n ...headers,\n sp: VBANServicePacket.subProtocol,\n sr: 0\n });\n\n this.service = headers.service;\n this.serviceFunction = headers.serviceFunction;\n this.isReply = headers.isReply ?? false;\n\n //force sr to 0\n this.sr = 0;\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANServicePacket)['toUDPPacket']> {\n return VBANServicePacket.toUDPPacket(this);\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, dataBuffer: Buffer): undefined | VBANServicePacket {\n throw new Error('call VBANServicePacketFactory.fromUDPPacker');\n }\n\n public static toUDPPacket(packet: VBANServicePacket): Buffer {\n return VBANServicePacket.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: ((packet.isReply ? 0b10000000 : 0) & 0b10000000) | (packet.serviceFunction & 0b01111111),\n part2: packet.service,\n part3: 0\n },\n Buffer.from(''),\n packet.sr\n );\n }\n}\n", "export enum EServiceType {\n // 0x00\n IDENTIFICATION = 0,\n // 0x01\n CHATUTF8 = 1,\n // 0x02\n VBAN_SERVICE_REQUESTREPLY = 2,\n // 0x20\n RTPACKETREGISTER = 32,\n // 0x21\n RTPACKET = 33\n}\n", "import { VBANServicePacket } from '../VBANServicePacket.js';\nimport { IVBANHeaderService } from '../IVBANHeaderService.js';\nimport { EServiceType } from '../EServiceType.js';\nimport { prepareStringForPacket } from '../../../commons.js';\nimport { IVBANHeaderCommon } from '../../IVBANHeaderCommon.js';\nimport { Buffer } from 'node:buffer';\n\nexport class VBANChatPacket extends VBANServicePacket {\n public data: string;\n constructor(headers: IVBANHeaderService, data: string) {\n super(headers);\n\n this.data = data;\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, dataBuffer: Buffer): VBANChatPacket {\n const fn = headers.part1;\n const serviceFunction = fn & 0b01111111;\n const isReply = (fn & 0b10000000) >= 1;\n\n return new VBANChatPacket(\n {\n ...headers,\n service: EServiceType.CHATUTF8,\n serviceFunction,\n isReply\n },\n dataBuffer.toString()\n );\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANChatPacket)['toUDPPacket']> {\n return VBANChatPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANChatPacket): Buffer {\n // 704 is the size for a service packet\n const dataBuffer = Buffer.alloc(676);\n dataBuffer.write(prepareStringForPacket(packet.data, 676), 0, 'utf8');\n\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: ((packet.isReply ? 0b10000000 : 0) & 0b10000000) | (packet.serviceFunction & 0b01111111),\n part2: packet.service,\n part3: 0\n },\n dataBuffer,\n packet.sr\n );\n }\n}\n", "import { VBANServicePacket } from '../VBANServicePacket.js';\nimport { IVBANHeaderService } from '../IVBANHeaderService.js';\nimport { IPacketPingData } from '../IPacketPingData.js';\nimport { Buffer } from 'node:buffer';\nimport { EServiceType } from '../EServiceType.js';\nimport { EServicePINGApplicationType } from '../EServicePINGApplicationType.js';\nimport { EServicePINGFeatures } from '../EServicePINGFeatures.js';\nimport { cleanPacketString, prepareStringForPacket } from '../../../commons.js';\nimport { IVBANHeaderCommon } from '../../IVBANHeaderCommon.js';\n\nexport class VBANPingPacket extends VBANServicePacket {\n public data: IPacketPingData;\n constructor(headers: IVBANHeaderService, data: IPacketPingData) {\n super(headers);\n\n this.data = data;\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, dataBuffer: Buffer): VBANServicePacket {\n const fn = headers.part1;\n const serviceFunction = fn & 0b01111111;\n const isReply = (fn & 0b10000000) >= 1;\n\n let currentByte = 0;\n const getXNextBytes = (size: number): Buffer => {\n const b = dataBuffer.subarray(currentByte, currentByte + size);\n currentByte += size;\n return b;\n };\n\n const bitType = getXNextBytes(4).readUInt32LE();\n const applicationType = EServicePINGApplicationType[bitType] ? bitType : EServicePINGApplicationType.UNKNOWN;\n const bitFeature = getXNextBytes(4).readUInt32LE();\n const features = (\n Object.entries(EServicePINGFeatures).filter(([k]) => Number.isNaN(Number(k))) as Array<[string, EServicePINGFeatures]>\n )\n .filter(([, v]) => bitFeature & v)\n .map(([, v]) => v);\n const bitFeatureEx = getXNextBytes(4).readUInt32LE();\n const PreferredRate = getXNextBytes(4).readUInt32LE();\n const minRate = getXNextBytes(4).readUInt32LE();\n const maxRate = getXNextBytes(4).readUInt32LE();\n const colorRGB = getXNextBytes(4).readUInt32LE();\n const color = {\n blue: colorRGB & 255,\n green: (colorRGB >> 8) & 255,\n red: (colorRGB >> 16) & 255\n };\n const nVersion = getXNextBytes(4).readUInt32LE();\n const GPSPosition = cleanPacketString(getXNextBytes(8).toString('ascii'));\n const userPosition = cleanPacketString(getXNextBytes(8).toString('ascii'));\n const langCode = cleanPacketString(getXNextBytes(8).toString('ascii'));\n const reservedASCII = cleanPacketString(getXNextBytes(8).toString('ascii'));\n const reservedEx = cleanPacketString(getXNextBytes(64).toString('ascii'));\n const reservedEx2 = cleanPacketString(getXNextBytes(36).toString('ascii'));\n const deviceName = cleanPacketString(getXNextBytes(64).toString('ascii'));\n const manufacturerName = cleanPacketString(getXNextBytes(64).toString('ascii'));\n const applicationName = cleanPacketString(getXNextBytes(64).toString('ascii'));\n const hostnameASCII = cleanPacketString(getXNextBytes(64).toString('ascii'));\n const userName = cleanPacketString(getXNextBytes(128).toString('utf8'));\n const userComment = cleanPacketString(getXNextBytes(128).toString('utf8'));\n\n //extract information\n const data: IPacketPingData = {\n applicationType,\n features,\n bitFeatureEx,\n PreferredRate,\n minRate,\n maxRate,\n color,\n nVersion,\n GPSPosition,\n userPosition,\n langCode,\n reservedASCII,\n reservedEx,\n reservedEx2,\n deviceName,\n manufacturerName,\n applicationName,\n hostname: hostnameASCII,\n userName,\n userComment\n };\n\n return new VBANPingPacket(\n {\n ...headers,\n service: EServiceType.IDENTIFICATION,\n serviceFunction,\n isReply\n },\n data\n );\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANPingPacket)['toUDPPacket']> {\n return VBANPingPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANPingPacket): Buffer {\n // 704 is the size for a service packet\n const dataBuffer = Buffer.alloc(676);\n let offset = 0;\n\n offset = dataBuffer.writeUInt32LE(packet.data.applicationType, offset);\n let features = 0;\n for (const feature of packet.data.features) {\n if (EServicePINGFeatures[feature]) {\n features = features | feature;\n }\n }\n offset = dataBuffer.writeUInt32LE(features, offset);\n offset = dataBuffer.writeUInt32LE(packet.data.bitFeatureEx, offset);\n offset = dataBuffer.writeUInt32LE(packet.data.PreferredRate, offset);\n offset = dataBuffer.writeUInt32LE(packet.data.minRate, offset);\n offset = dataBuffer.writeUInt32LE(packet.data.maxRate, offset);\n\n const { red, green, blue } = packet.data.color;\n offset = dataBuffer.writeUInt32LE(((red & 255) << 16) | ((green & 255) << 8) | (blue & 255), offset);\n\n offset = dataBuffer.writeUInt32LE(packet.data.nVersion, offset);\n\n offset += dataBuffer.write(prepareStringForPacket(packet.data.GPSPosition, 8), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.userPosition, 8), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.langCode, 8), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.reservedASCII, 8), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.reservedEx, 64), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.reservedEx2, 36), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.deviceName, 64), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.manufacturerName, 64), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.applicationName, 64), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.hostname, 64), offset, 'ascii');\n offset += dataBuffer.write(prepareStringForPacket(packet.data.userName, 128), offset, 'utf8');\n dataBuffer.write(prepareStringForPacket(packet.data.userComment, 128), offset, 'utf8');\n\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: ((packet.isReply ? 0b10000000 : 0) & 0b10000000) | (packet.serviceFunction & 0b01111111),\n part2: packet.service,\n part3: 0\n },\n dataBuffer,\n packet.sr\n );\n }\n}\n", "export enum EServicePINGApplicationType {\n UNKNOWN = 0x00000000,\n RECEPTOR = 0x00000001,\n TRANSMITTER = 0x00000002,\n RECEPTORSPOT = 0x00000004,\n TRANSMITTERSPOT = 0x00000008,\n VIRTUALDEVICE = 0x00000010,\n VIRTUALMIXER = 0x00000020,\n MATRIX = 0x00000040,\n DAW = 0x00000080,\n SERVER = 0x01000000\n}\n", "export enum EServicePINGFeatures {\n AUDIO = 0x00000001,\n AOIP = 0x00000002,\n VOIP = 0x00000004,\n SERIAL = 0x00000100,\n MIDI = 0x00000300,\n FRAME = 0x00001000,\n TXT = 0x00010000\n}\n", "import { VBANServicePacket } from '../VBANServicePacket.js';\nimport { IVBANHeaderService } from '../IVBANHeaderService.js';\nimport { EServiceType } from '../EServiceType.js';\nimport { IVBANHeaderCommon } from '../../IVBANHeaderCommon.js';\nimport { Buffer } from 'node:buffer';\n\nexport class VBANRealTimePacket extends VBANServicePacket {\n /**\n * not clear about the content of this buffer\n */\n public data: Buffer;\n constructor(headers: IVBANHeaderService, data: Buffer) {\n super(headers);\n\n this.data = data;\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, dataBuffer: Buffer): VBANRealTimePacket {\n const fn = headers.part1;\n const serviceFunction = fn & 0b01111111;\n const isReply = (fn & 0b10000000) >= 1;\n\n return new VBANRealTimePacket(\n {\n ...headers,\n service: EServiceType.RTPACKET,\n serviceFunction,\n isReply\n },\n dataBuffer\n );\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANRealTimePacket)['toUDPPacket']> {\n return VBANRealTimePacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANRealTimePacket): Buffer {\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: ((packet.isReply ? 0b10000000 : 0) & 0b10000000) | (packet.serviceFunction & 0b01111111),\n part2: packet.service,\n part3: 0\n },\n Buffer.from(''),\n packet.sr\n );\n }\n}\n", "import { Buffer } from 'node:buffer';\nimport { VBANServicePacket } from '../VBANServicePacket.js';\nimport { IVBANHeaderService } from '../IVBANHeaderService.js';\nimport { EServiceType } from '../EServiceType.js';\nimport { IVBANHeaderCommon } from '../../IVBANHeaderCommon.js';\n\nexport enum ERegistrationAnswer {\n /**\n * no RT packet service (could mean the packet ID is not existing).\n */\n NO_RT_PACKET_SERVICE = 0,\n /**\n * RT packet service registered\n */\n RT_PACKET_SERVICE_REGISTERED = 1,\n /**\n * RT packet service busy (no more slot).\n */\n RT_PACKET_SERVICE_BUSY = 2\n}\n\nexport interface IRealTimeRegisterAnswerPacket {\n /**\n * Registration answer\n */\n answer: ERegistrationAnswer;\n}\n\nexport class VBANRealTimeRegisterAnswerPacket extends VBANServicePacket {\n public data: IRealTimeRegisterAnswerPacket;\n constructor(headers: IVBANHeaderService, data: IRealTimeRegisterAnswerPacket) {\n super(headers);\n\n this.data = data;\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon): VBANRealTimeRegisterAnswerPacket {\n const fn = headers.part1;\n const serviceFunction = fn & 0b01111111;\n const isReply = (fn & 0b10000000) >= 1;\n\n return new VBANRealTimeRegisterAnswerPacket(\n {\n ...headers,\n service: EServiceType.RTPACKETREGISTER,\n serviceFunction,\n isReply\n },\n {\n answer: headers.part3\n }\n );\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANRealTimeRegisterAnswerPacket)['toUDPPacket']> {\n return VBANRealTimeRegisterAnswerPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANRealTimeRegisterAnswerPacket): Buffer {\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: ((packet.isReply ? 0b10000000 : 0) & 0b10000000) | (packet.serviceFunction & 0b01111111),\n part2: packet.service,\n part3: packet.data.answer\n },\n Buffer.from(''),\n packet.sr\n );\n }\n}\n", "import { Buffer } from 'node:buffer';\nimport { VBANServicePacket } from '../VBANServicePacket.js';\nimport { IVBANHeaderService } from '../IVBANHeaderService.js';\nimport { EServiceType } from '../EServiceType.js';\nimport { IVBANHeaderCommon } from '../../IVBANHeaderCommon.js';\nimport { VBANRealTimeRegisterAnswerPacket } from './VBANRealTimeRegisterAnswerPacket.js';\n\nexport interface IRealTimeRegisterPacket {\n /**\n * Time out in second (to stop RT packet broadcast)\n */\n timeout: number;\n}\n\nexport class VBANRealTimeRegisterPacket extends VBANServicePacket {\n public data: IRealTimeRegisterPacket;\n constructor(headers: IVBANHeaderService, data: IRealTimeRegisterPacket) {\n super(headers);\n\n this.data = data;\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon): VBANRealTimeRegisterPacket | VBANRealTimeRegisterAnswerPacket {\n const fn = headers.part1;\n const serviceFunction = fn & 0b01111111;\n const isReply = (fn & 0b10000000) >= 1;\n\n if (isReply) {\n return VBANRealTimeRegisterAnswerPacket.fromUDPPacket(headers);\n }\n\n return new VBANRealTimeRegisterPacket(\n {\n ...headers,\n service: EServiceType.RTPACKETREGISTER,\n serviceFunction,\n isReply\n },\n {\n timeout: headers.part3\n }\n );\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANRealTimeRegisterPacket)['toUDPPacket']> {\n return VBANRealTimeRegisterPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANRealTimeRegisterPacket): Buffer {\n if (packet.data.timeout > 255 || packet.data.timeout < 0) {\n throw new Error('timeout need to be between 0 and 255');\n }\n\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: ((packet.isReply ? 0b10000000 : 0) & 0b10000000) | (packet.serviceFunction & 0b01111111),\n part2: packet.service,\n part3: packet.data.timeout\n },\n Buffer.from(''),\n packet.sr\n );\n }\n}\n", "import { Buffer } from 'node:buffer';\nimport { VBANServicePacket } from '../VBANServicePacket.js';\nimport type { IVBANHeaderService } from '../IVBANHeaderService.js';\nimport { EServiceType } from '../EServiceType.js';\nimport type { IVBANHeaderCommon } from '../../IVBANHeaderCommon.js';\n\nexport class VBANRequestReplyPacket extends VBANServicePacket {\n public answer: string;\n constructor(headers: IVBANHeaderService, data: Buffer) {\n super(headers);\n\n this.answer = data?.toString('utf8');\n }\n\n public static fromUDPPacket(headers: IVBANHeaderCommon, data: Buffer): VBANRequestReplyPacket {\n const fn = headers.part1;\n const serviceFunction = fn & 0b01111111;\n const isReply = (fn & 0b10000000) >= 1;\n\n return new VBANRequestReplyPacket(\n {\n ...headers,\n service: EServiceType.VBAN_SERVICE_REQUESTREPLY,\n serviceFunction,\n isReply\n },\n data\n );\n }\n\n public toUDPPacket(): ReturnType<(typeof VBANRequestReplyPacket)['toUDPPacket']> {\n return VBANRequestReplyPacket.toUDPPacket(this);\n }\n\n public static toUDPPacket(packet: VBANRequestReplyPacket): Buffer {\n return this.convertToUDPPacket(\n {\n streamName: packet.streamName,\n sp: packet.subProtocol,\n sr: packet.sr,\n frameCounter: packet.frameCounter,\n part1: ((packet.isReply ? 0b10000000 : 0) & 0b10000000) | (packet.serviceFunction & 0b01111111),\n part2: packet.service,\n part3: 0\n },\n Buffer.from(packet.answer, 'utf8')\n );\n }\n}\n", "expor