Files
Phoenix/www/core/binary_protocol.js
T

69 lines
2.4 KiB
JavaScript

// Phoenix binary WebSocket packet decoders. Keep this module dependency-free so
// protocol compatibility can be tested without a browser.
export function decodePhoenixSpectroBuffer(buffer) {
if (!(buffer instanceof ArrayBuffer) || buffer.byteLength < 20) return null;
const view = new DataView(buffer);
if (view.getUint32(0, true) !== 0x50585350) return null;
const seq = view.getUint32(4, true);
const sampleRate = view.getUint32(8, true);
const fftSize = view.getUint32(12, true);
const count = view.getUint32(16, true);
if (count < 1 || buffer.byteLength !== 20 + count * 4) return null;
return {
seq,
sampleRate,
fftSize,
bins: new Float32Array(buffer, 20, count),
};
}
export function decodePhoenixVisualsBuffer(buffer) {
if (!(buffer instanceof ArrayBuffer) || buffer.byteLength < 32) return null;
const view = new DataView(buffer);
if (view.getUint32(0, true) !== 0x50585653 || view.getUint16(4, true) !== 1) return null;
const flags = view.getUint16(6, true);
const seq = view.getUint32(8, true);
const xyCount = view.getUint32(12, true);
const waveColumns = view.getUint32(16, true);
const waveChannels = view.getUint16(20, true);
const waveColumnSamples = view.getUint32(24, true);
const waveSampleRate = view.getUint32(28, true);
if (waveChannels > 2) return null;
const xyBytes = xyCount * 8;
const waveValues = waveColumns * waveChannels * 2;
const expectedBytes = 32 + xyBytes + waveValues * 4;
if (!Number.isSafeInteger(expectedBytes) || buffer.byteLength !== expectedBytes) return null;
let offset = 32;
let left = null;
let right = null;
if ((flags & 1) && xyCount > 0) {
left = new Float32Array(xyCount);
right = new Float32Array(xyCount);
for (let index = 0; index < xyCount; index++) {
left[index] = view.getFloat32(offset, true);
right[index] = view.getFloat32(offset + 4, true);
offset += 8;
}
} else {
offset += xyBytes;
}
let wave = null;
if ((flags & 2) && waveValues > 0 && (waveChannels === 1 || waveChannels === 2)) {
const data = new Float32Array(waveValues);
for (let index = 0; index < waveValues; index++) {
data[index] = view.getFloat32(offset + index * 4, true);
}
wave = {
data,
columns: waveColumns,
channels: waveChannels,
columnSamples: waveColumnSamples,
sampleRate: waveSampleRate,
};
}
return { seq, left, right, wave };
}