Files
osc-js/src/bundle.ts
T
2024-10-09 12:33:38 -05:00

89 lines
2.9 KiB
TypeScript

import { messageFromBuffer, messageToBuffer } from "./message";
import { OSCBundle } from "./models";
import { oscTypeConverterMap } from "./osc-types";
export function bundleFromBuffer(bytes: Buffer): OSCBundle | undefined {
if (bytes.length < 8) {
throw new Error('bundle has to be at least 20 bytes');
}
if (bytes.subarray(0, 7).toString('ascii') !== '#bundle') {
throw new Error('bundle must start with #bundle');
}
const [bundleHeader, bytesAfterHeader] = oscTypeConverterMap.s.fromBuffer(bytes);
let [timeTag, bytesAfterTimeTag] = oscTypeConverterMap.t.fromBuffer(bytesAfterHeader);
if (!Array.isArray(timeTag)) {
throw new Error('problem getting bundle time tag');
}
const bundleContents = [];
let endOfBundle = false;
let [contentSize, remainingBytes] = oscTypeConverterMap.i.fromBuffer(bytesAfterTimeTag);
if (typeof contentSize === 'number') {
while (!endOfBundle) {
if (remainingBytes.length < contentSize) {
throw new Error('bundle does not contain enough data');
}
const bundleContentBytes = remainingBytes.subarray(0, contentSize);
if (bundleContentBytes[0] === 35) {
// # character indicating contents is a bundle
const content = bundleFromBuffer(bundleContentBytes);
if (content) {
bundleContents.push(content);
}
} else if (bundleContentBytes[0] === 47) {
const content = messageFromBuffer(bundleContentBytes);
if (content) {
bundleContents.push(content);
}
} else {
throw new Error('bundle contents does not look like a OSC message or bundle');
}
remainingBytes = remainingBytes.subarray(contentSize);
if (remainingBytes.length === 0) {
endOfBundle = true;
}
}
}
return {
timeTag,
contents: bundleContents,
};
}
export function bundleToBuffer(bundle: OSCBundle): Buffer {
const headerBuffer = oscTypeConverterMap.s.toBuffer('#bundle');
if (headerBuffer === undefined) {
throw new Error('problem encoding buffer header');
}
const timeTagBuffer = oscTypeConverterMap.t.toBuffer(bundle.timeTag);
if (timeTagBuffer === undefined) {
throw new Error('problem encoding buffer time tag');
}
const contentsBuffers: Buffer[] = [];
bundle.contents.forEach((bundleContent) => {
if ('address' in bundleContent) {
const contentBuffer = messageToBuffer(bundleContent);
const contentSizeBuffer = oscTypeConverterMap.i.toBuffer(contentBuffer.length);
if (contentBuffer && contentSizeBuffer) {
contentsBuffers.push(Buffer.concat([contentSizeBuffer, contentBuffer]));
}
}
});
return Buffer.concat([headerBuffer, timeTagBuffer, ...contentsBuffers]);
}