@tmigone/pulseaudio
Version:
A TypeScript based client library for PulseAudio.
190 lines • 7.94 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PA_PACKET_HEADER = void 0;
const fs = require("fs");
const iterator_1 = require("./utils/iterator");
const tag_1 = require("./tag");
const bigInt_1 = require("./utils/bigInt");
exports.PA_PACKET_HEADER = Buffer.from([
0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
]);
var SectionLength;
(function (SectionLength) {
SectionLength[SectionLength["SIZE"] = 4] = "SIZE";
SectionLength[SectionLength["HEADER"] = 16] = "HEADER";
SectionLength[SectionLength["COMMAND"] = 5] = "COMMAND";
SectionLength[SectionLength["REQUEST"] = 5] = "REQUEST";
})(SectionLength || (SectionLength = {}));
var SectionIndex;
(function (SectionIndex) {
SectionIndex[SectionIndex["SIZE"] = 0] = "SIZE";
SectionIndex[SectionIndex["HEADER"] = 4] = "HEADER";
SectionIndex[SectionIndex["HEADER_END"] = 20] = "HEADER_END";
SectionIndex[SectionIndex["COMMAND"] = 21] = "COMMAND";
SectionIndex[SectionIndex["REQUEST"] = 26] = "REQUEST";
SectionIndex[SectionIndex["TAGS"] = 30] = "TAGS";
})(SectionIndex || (SectionIndex = {}));
class PAPacket {
constructor(buffer) {
this.tagsSize = 0;
this.header = exports.PA_PACKET_HEADER;
this.tags = [];
this.debugPrint = process.env.DEBUG_PRINT !== undefined;
if (buffer != null) {
this.packet = Buffer.from(buffer.subarray(0, PAPacket.getPacketSize(buffer)));
this.read(this.packet);
}
}
write() {
const allTags = [this.command, this.requestId, ...this.tags];
this.tagsSize = allTags.reduce((sum, tag) => {
sum += tag.size;
return sum;
}, 0);
this.packet = Buffer.allocUnsafe(4 + 16 + this.tagsSize);
let offset = 0;
offset = this.packet.writeUInt32BE(this.tagsSize, offset);
offset += exports.PA_PACKET_HEADER.copy(this.packet, offset);
for (const tag of allTags) {
tag.tag.copy(this.packet, offset);
offset += tag.size;
}
if (this.debugPrint) {
fs.writeFileSync('PAPacket.write.buffer', this.packet.toString('hex'));
fs.writeFileSync('PAPacket.write.tags', (0, bigInt_1.JSONStringify)(allTags));
}
return this.packet;
}
read(buffer) {
if (!PAPacket.isValidPacket(buffer)) {
throw new Error('Packet is not valid.');
}
try {
this.tagsSize = buffer.readUInt32BE(0);
this.header = buffer.subarray(4, 20);
this.command = new tag_1.PAU32(buffer.readUInt32BE(21));
this.requestId = new tag_1.PAU32(buffer.readUInt32BE(26));
const tagsBuffer = buffer.subarray(30, 30 + this.tagsSize - 5 - 5);
let offset = 0;
let tag;
while (offset < tagsBuffer.length) {
const tagType = tagsBuffer.readUInt8(offset);
switch (tagType) {
case tag_1.PATagType.PA_TAG_U32.toString().charCodeAt(0):
tag = new tag_1.PAU32(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_ARBITRARY.toString().charCodeAt(0):
tag = new tag_1.PAArbitrary(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_STRING.toString().charCodeAt(0):
case tag_1.PATagType.PA_TAG_STRING_NULL.toString().charCodeAt(0):
tag = new tag_1.PAString(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_BOOLEAN.toString().charCodeAt(0):
case tag_1.PATagType.PA_TAG_BOOLEAN_FALSE.toString().charCodeAt(0):
case tag_1.PATagType.PA_TAG_BOOLEAN_TRUE.toString().charCodeAt(0):
tag = new tag_1.PABoolean(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_PROPLIST.toString().charCodeAt(0):
tag = new tag_1.PAPropList(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_SAMPLE_SPEC.toString().charCodeAt(0):
tag = new tag_1.PASampleSpec(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_CHANNEL_MAP.toString().charCodeAt(0):
tag = new tag_1.PAChannelMap(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_CVOLUME.toString().charCodeAt(0):
tag = new tag_1.PAChannelVolume(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_USEC.toString().charCodeAt(0):
tag = new tag_1.PAUsec(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_VOLUME.toString().charCodeAt(0):
tag = new tag_1.PAVolume(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_U8.toString().charCodeAt(0):
tag = new tag_1.PAU8(tagsBuffer.subarray(offset));
break;
case tag_1.PATagType.PA_TAG_FORMAT_INFO.toString().charCodeAt(0):
tag = new tag_1.PAFormat(tagsBuffer.subarray(offset));
break;
default:
throw new Error(`Tag type: ${tagType} not supported. Please report issue.`);
}
this.tags.push(tag);
offset += tag.size;
}
}
catch (error) {
console.log(error);
}
if (this.debugPrint) {
fs.writeFileSync('PAPacket.read.buffer', buffer.toString('hex'));
fs.writeFileSync('PAPacket.read.tags', (0, bigInt_1.JSONStringify)(this.tags));
}
}
static isChunkHeader(chunk) {
if (chunk.length < 4 + 16) {
return false;
}
const header = chunk.subarray(4, 20);
return Buffer.compare(header, exports.PA_PACKET_HEADER) === 0;
}
static getChunksSize(chunks) {
return chunks.reduce((sum, chunk) => {
sum += chunk.length;
return sum;
}, 0);
}
static getPacketSize(buffer) {
const tagsSize = buffer.readUInt32BE(0);
return 4 + 16 + tagsSize;
}
static isValidPacket(chunks) {
if (chunks instanceof Buffer) {
chunks = [chunks];
}
if (chunks.length === 0) {
return false;
}
const chunksSize = this.getChunksSize(chunks);
const dataLength = chunks[0].readUInt32BE(0);
return this.isChunkHeader(chunks[0]) && chunksSize >= (4 + 16 + dataLength);
}
setCommand(value) {
this.command = new tag_1.PAU32(value);
}
setRequestId(value) {
this.requestId = new tag_1.PAU32(value);
}
putU32(value) {
this.tags.push(new tag_1.PAU32(value));
}
putBoolean(value) {
this.tags.push(new tag_1.PABoolean(value));
}
putArbitrary(value) {
this.tags.push(new tag_1.PAArbitrary(value));
}
putString(value) {
this.tags.push(new tag_1.PAString(value));
}
putProp(value) {
this.tags.push(new tag_1.PAProp(value));
}
putPropList(value) {
this.tags.push(new tag_1.PAPropList(value));
}
putChannelVolume(value) {
this.tags.push(new tag_1.PAChannelVolume(value));
}
getTagsIterable() {
return (0, iterator_1.createIterator)(this.tags.map(t => t.value));
}
}
exports.default = PAPacket;
//# sourceMappingURL=packet.js.map