pw-client
Version:
Node.js wrapper for developing PipeWire clients
192 lines (191 loc) • 8.62 kB
JavaScript
import { endianness } from "node:os";
function fpOutputBuffer(ctor) {
class WrappedTypeArray {
#buffer;
constructor(buffer) {
this.#buffer = buffer;
}
set(index, value) {
this.#buffer[index] = value;
}
get buffer() {
return this.#buffer.buffer;
}
subarray(offset, size) {
return new WrappedTypeArray(this.#buffer.subarray(offset, size));
}
}
return (samples) => new WrappedTypeArray(new ctor(samples));
}
function intOutputBuffer(ctor, encode) {
class WrappedTypeArray {
#buffer;
constructor(buffer) {
this.#buffer = buffer;
}
set(index, value) {
const encoded = encode(value);
this.#buffer[index] = encoded;
}
get buffer() {
return this.#buffer.buffer;
}
subarray(offset, size) {
return new WrappedTypeArray(this.#buffer.subarray(offset, size));
}
}
return (samples) => new WrappedTypeArray(new ctor(samples));
}
function signedInt(bits) {
const multiplier = 2 ** (bits - 1) - 0.5;
return (n) => Math.floor(n * multiplier);
}
function unsignedInt(bits) {
const multiplier = (2 ** bits - 1) / 2;
return (n) => Math.floor((n + 1) * multiplier);
}
const Int8Buffer = intOutputBuffer(Int8Array, signedInt(8));
const Int16Buffer = intOutputBuffer(Int16Array, signedInt(16));
const Int32Buffer = intOutputBuffer(Int32Array, signedInt(32));
const Uint8Buffer = intOutputBuffer(Uint8Array, unsignedInt(8));
const Uint16Buffer = intOutputBuffer(Uint16Array, unsignedInt(16));
const Uint32Buffer = intOutputBuffer(Uint32Array, unsignedInt(32));
const Float32Buffer = fpOutputBuffer(Float32Array);
const Float64Buffer = fpOutputBuffer(Float64Array);
/**
* Audio format class representing different sample formats supported by PipeWire.
* Handles conversion between JavaScript Numbers and various binary audio formats.
*
* Users typically don't need to work with AudioFormat directly - it's handled
* internally through quality presets and format negotiation.
*
* @class AudioFormat
*
* @example
* ```typescript
* // Access negotiated format info
* console.log(`Stream format: ${stream.format.description}`);
* console.log(`Sample rate: ${stream.rate}Hz`);
* console.log(`Channels: ${stream.channels}`);
* ```
*/
export class AudioFormat {
#enumValue;
#byteSize;
#bufferFactory;
#description;
constructor(value, byteSize, BufferClass, description) {
this.#enumValue = value;
this.#byteSize = byteSize;
this.#bufferFactory = BufferClass;
this.#description = description;
AudioFormat.#enumMap.set(value, this);
}
get enumValue() {
return this.#enumValue;
}
get byteSize() {
return this.#byteSize;
}
get BufferClass() {
return this.#bufferFactory;
}
get description() {
return this.#description;
}
static #enumMap = new Map();
static fromEnum(format) {
return AudioFormat.#enumMap.get(format);
}
static Int8 = new AudioFormat(0x101, 1, Int8Buffer, "8-bit signed integer (low quality)");
static Uint8 = new AudioFormat(0x102, 1, Uint8Buffer, "8-bit unsigned integer (basic quality)");
static get Int16() {
return endianness() === "BE" ? AudioFormat.Int16BE : AudioFormat.Int16LE;
}
static get Uint16() {
return endianness() === "BE" ? AudioFormat.Uint16BE : AudioFormat.Uint16LE;
}
static get Int24_32() {
return endianness() === "BE"
? AudioFormat.Int24_32BE
: AudioFormat.Int24_32LE;
}
static get Uint24_32() {
return endianness() === "BE"
? AudioFormat.Uint24_32BE
: AudioFormat.Uint24_32LE;
}
static get Int32() {
return endianness() === "BE" ? AudioFormat.Int32BE : AudioFormat.Int32LE;
}
static get Uint32() {
return endianness() === "BE" ? AudioFormat.Uint32BE : AudioFormat.Uint32LE;
}
// static get Int24() {
// return endianness() === "BE" ? AudioFormat.Int24BE : AudioFormat.Int24LE;
// }
// static get Uint24() {
// return endianness() === "BE" ? AudioFormat.Uint24BE : AudioFormat.Uint24LE;
// }
// static get Int20() {
// return endianness() === "BE" ? AudioFormat.Int20BE : AudioFormat.Int20LE;
// }
// static get Uint20() {
// return endianness() === "BE" ? AudioFormat.Uint20BE : AudioFormat.Uint20LE;
// }
// static get Int18() {
// return endianness() === "BE" ? AudioFormat.Int18BE : AudioFormat.Int18LE;
// }
// static get Uint18() {
// return endianness() === "BE" ? AudioFormat.Uint18BE : AudioFormat.Uint18LE;
// }
static get Float32() {
return endianness() === "BE"
? AudioFormat.Float32BE
: AudioFormat.Float32LE;
}
static get Float64() {
return endianness() === "BE"
? AudioFormat.Float64BE
: AudioFormat.Float64LE;
}
static ULaw = new AudioFormat(0x11f, 1, Int8Buffer, "μ-law compressed audio");
static ALaw = new AudioFormat(0x120, 1, Int8Buffer, "A-law compressed audio");
static Uint8Planar = new AudioFormat(0x201, 1, Uint8Buffer, "8-bit unsigned planar");
static Int16Planar = new AudioFormat(0x202, 2, Int16Buffer, "16-bit signed planar");
static Int24_32Planar = new AudioFormat(0x203, 4, Int32Buffer, "24-bit in 32-bit planar");
static Int32Planar = new AudioFormat(0x204, 4, Int32Buffer, "32-bit signed planar");
// static Int24Planar = new AudioFormat(0x205, 3);
static Float32Planar = new AudioFormat(0x206, 4, Float32Buffer, "32-bit floating point planar");
static Float64Planar = new AudioFormat(0x207, 8, Float64Buffer, "64-bit floating point planar");
static Int8Planar = new AudioFormat(0x208, 1, Int8Buffer, "8-bit signed planar");
// Endian-specific
static Int16LE = new AudioFormat(0x103, 2, Int16Buffer, "16-bit signed integer (standard quality)");
static Int16BE = new AudioFormat(0x104, 2, Int16Buffer, "16-bit signed integer (standard quality)");
static Uint16LE = new AudioFormat(0x105, 2, Uint16Buffer, "16-bit unsigned integer (standard quality)");
static Uint16BE = new AudioFormat(0x106, 2, Uint16Buffer, "16-bit unsigned integer (standard quality)");
static Int24_32LE = new AudioFormat(0x107, 4, Int32Buffer, "24-bit in 32-bit container (professional quality)");
static Int24_32BE = new AudioFormat(0x108, 4, Int32Buffer, "24-bit in 32-bit container (professional quality)");
static Uint24_32LE = new AudioFormat(0x109, 4, Uint32Buffer, "24-bit unsigned in 32-bit container (professional quality)");
static Uint24_32BE = new AudioFormat(0x10a, 4, Uint32Buffer, "24-bit unsigned in 32-bit container (professional quality)");
static Int32LE = new AudioFormat(0x10b, 4, Int32Buffer, "32-bit signed integer (high precision)");
static Int32BE = new AudioFormat(0x10c, 4, Int32Buffer, "32-bit signed integer (high precision)");
static Uint32LE = new AudioFormat(0x10d, 4, Uint32Buffer, "32-bit unsigned integer (high precision)");
static Uint32BE = new AudioFormat(0x10e, 4, Uint32Buffer, "32-bit unsigned integer (high precision)");
// private static Int24LE = new AudioFormat(0x10f, 3);
// private static Int24BE = new AudioFormat(0x110, 3);
// private static Uint24LE = new AudioFormat(0x111, 3);
// private static Uint24BE = new AudioFormat(0x112, 3);
// private static Int20LE = new AudioFormat(0x113, 4); // No idea how to encode...
// private static Int20BE = new AudioFormat(0x114, 4); // No idea...
// private static Uint20LE = new AudioFormat(0x115, 4); // No idea...
// private static Uint20BE = new AudioFormat(0x116, 4); // No idea...
// private static Int18LE = new AudioFormat(0x117, 3); // No idea...
// private static Int18BE = new AudioFormat(0x118, 3); // No idea...
// private static Uint18LE = new AudioFormat(0x119, 3); // No idea...
// private static Uint18BE = new AudioFormat(0x11a, 3); // No idea...
static Float32LE = new AudioFormat(0x11b, 4, Float32Buffer, "32-bit floating point (excellent quality)");
static Float32BE = new AudioFormat(0x11c, 4, Float32Buffer, "32-bit floating point (excellent quality)");
static Float64LE = new AudioFormat(0x11d, 8, Float64Buffer, "64-bit floating point (highest precision)");
static Float64BE = new AudioFormat(0x11e, 8, Float64Buffer, "64-bit floating point (highest precision)");
}