From b44e5d306a5879e79138a1a5a34901fbeab8a425 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Sun, 13 Oct 2024 16:41:49 -0500 Subject: [PATCH 1/2] fix osc bundles not parsing multiple content chunks correctly --- packages/osc/src/bundle.ts | 72 ++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/packages/osc/src/bundle.ts b/packages/osc/src/bundle.ts index 8ea34df..ec9829c 100644 --- a/packages/osc/src/bundle.ts +++ b/packages/osc/src/bundle.ts @@ -22,42 +22,52 @@ export function bundleFromBuffer(bytes: Uint8Array): [OSCBundle | undefined, Uin 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'); - } + // let [contentSize, remainingBytes] = oscTypeConverterMap.i.fromBuffer(bytesAfterTimeTag); + let remainingBytes = bytesAfterTimeTag; - const bundleContentBytes = remainingBytes.subarray(0, contentSize); + while (!endOfBundle) { + let [contentSize, bytesAfterContentSize] = oscTypeConverterMap.i.fromBuffer(remainingBytes); - if (bundleContentBytes[0] === 35) { - // # character indicating contents is a bundle - const [content, bytesAfterContent] = bundleFromBuffer(bundleContentBytes); - if (content) { - bundleContents.push(content); - } - } else if (bundleContentBytes[0] === 47) { - const [content, bytesAfterContent] = messageFromBuffer(bundleContentBytes); - if (content && content !== undefined) { - 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; - } + if (typeof contentSize !== 'number') { + throw new Error('problem decoding content size'); + } + + remainingBytes = bytesAfterContentSize; + + if (remainingBytes.length < contentSize) { + throw new Error('bundle does not contain enough data'); + } + + const bundleContentBytes = bytesAfterContentSize.subarray(0, contentSize); + + if (bundleContentBytes[0] === 35) { + // # character indicating contents is a bundle + const [content, bytesAfterContent] = bundleFromBuffer(bundleContentBytes); + if (content) { + bundleContents.push(content); + } + } else if (bundleContentBytes[0] === 47) { + const [content, bytesAfterContent] = messageFromBuffer(bundleContentBytes); + if (content && content !== undefined) { + bundleContents.push(content); + } + } else { + throw new Error('bundle contents does not look like a OSC message or bundle'); + } + + remainingBytes = bytesAfterContentSize.subarray(contentSize); + if (remainingBytes.length === 0) { + endOfBundle = true; } - return [{ - timeTag, - contents: bundleContents, - },remainingBytes]; } - return [undefined, undefined] + return [ + { + timeTag, + contents: bundleContents, + }, + remainingBytes, + ]; } export function bundleToBuffer(bundle: OSCBundle): Uint8Array { From 4b56f09a64dc5ec3a80752f3a483f46f5b8a4aab Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Sun, 13 Oct 2024 16:42:11 -0500 Subject: [PATCH 2/2] add test osc bundle from resolume --- packages/osc/tests/bundle-decode.test.js | 68 +++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/packages/osc/tests/bundle-decode.test.js b/packages/osc/tests/bundle-decode.test.js index a9bceda..12e7c74 100644 --- a/packages/osc/tests/bundle-decode.test.js +++ b/packages/osc/tests/bundle-decode.test.js @@ -20,13 +20,79 @@ const tests = [ contents: [{ address: '/oscillator/4/frequency', args: [{ type: 'f', value: 440 }] }], }, }, + { + decription: 'resolume bundle example', + bytes: new Uint8Array([ + 0x23, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x28, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x73, 0x2f, 0x31, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x2c, 0x66, 0x00, 0x00, 0x3d, + 0x6d, 0x9c, 0x9c, 0x00, 0x00, 0x00, 0x2c, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x2f, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x2c, 0x66, 0x00, 0x00, 0x3d, 0x6d, 0x9c, 0x9c, 0x00, 0x00, 0x00, 0x3c, 0x2f, 0x63, + 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x2f, 0x31, + 0x2f, 0x63, 0x6c, 0x69, 0x70, 0x73, 0x2f, 0x34, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x66, 0x00, 0x00, 0x3d, 0x6d, 0x9c, + 0x9c, 0x00, 0x00, 0x00, 0x38, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x63, 0x6c, 0x69, 0x70, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, + 0x72, 0x74, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x66, 0x00, 0x00, + 0x3d, 0x6d, 0x9c, 0x9c, 0x00, 0x00, 0x00, 0x28, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x2f, 0x31, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x00, 0x00, 0x2c, 0x66, 0x00, 0x00, 0x3d, 0x6d, 0x9c, 0x9c, 0x00, 0x00, 0x00, 0x2c, 0x2f, 0x63, 0x6f, 0x6d, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x2c, 0x66, 0x00, 0x00, 0x3d, 0x6d, 0x9c, + 0x9c, 0x00, 0x00, 0x00, 0x3c, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6c, + 0x61, 0x79, 0x65, 0x72, 0x73, 0x2f, 0x31, 0x2f, 0x63, 0x6c, 0x69, 0x70, 0x73, 0x2f, 0x34, 0x2f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x66, 0x00, 0x00, 0x3d, 0x6d, 0x9c, 0x9c, 0x00, 0x00, 0x00, 0x38, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x63, 0x6c, 0x69, 0x70, 0x2f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, + 0x00, 0x00, 0x00, 0x2c, 0x66, 0x00, 0x00, 0x3d, 0x6d, 0x9c, 0x9c, + ]), + expected: { + timeTag: [0, 1], + contents: [ + { + address: '/composition/layers/1/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + { + address: '/composition/selectedlayer/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + { + address: '/composition/layers/1/clips/4/transport/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + { + address: '/composition/selectedclip/transport/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + { + address: '/composition/layers/1/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + { + address: '/composition/selectedlayer/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + { + address: '/composition/layers/1/clips/4/transport/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + { + address: '/composition/selectedclip/transport/position', + args: [{ type: 'f', value: 0.05801068246364593505859375 }], + }, + ], + }, + }, ]; describe('OSC Bundle Decoding', () => { tests.forEach((bundleTest) => { it(bundleTest.description, () => { const [encoded, remainingBytes] = osc.bundleFromBuffer(bundleTest.bytes); - equal(remainingBytes.length, 0) + equal(remainingBytes.length, 0); deepEqual(encoded, bundleTest.expected); }); });