tci-client-node 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/audio/index.cjs +343 -0
- package/dist/audio/index.cjs.map +1 -0
- package/dist/audio/index.d.cts +60 -0
- package/dist/audio/index.d.ts +60 -0
- package/dist/audio/index.js +301 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/index-CK3XdXP3.d.cts +42 -0
- package/dist/index-Dfmrk2MR.d.ts +42 -0
- package/dist/index.cjs +1182 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +130 -0
- package/dist/index.d.ts +130 -0
- package/dist/index.js +1117 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/index.cjs +309 -0
- package/dist/protocol/index.cjs.map +1 -0
- package/dist/protocol/index.d.cts +2 -0
- package/dist/protocol/index.d.ts +2 -0
- package/dist/protocol/index.js +274 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/testing/index.cjs +572 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +78 -0
- package/dist/testing/index.d.ts +78 -0
- package/dist/testing/index.js +533 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/text-BwCWY1k1.d.cts +21 -0
- package/dist/text-BwCWY1k1.d.ts +21 -0
- package/package.json +93 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var TciError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
details;
|
|
5
|
+
constructor(code, message, details) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "TciError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.details = details;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/audio/streamFrame.ts
|
|
14
|
+
var TCI_STREAM_HEADER_BYTES = 16 * 4;
|
|
15
|
+
var TciStreamType = /* @__PURE__ */ ((TciStreamType2) => {
|
|
16
|
+
TciStreamType2[TciStreamType2["IQ_STREAM"] = 0] = "IQ_STREAM";
|
|
17
|
+
TciStreamType2[TciStreamType2["RX_AUDIO_STREAM"] = 1] = "RX_AUDIO_STREAM";
|
|
18
|
+
TciStreamType2[TciStreamType2["TX_AUDIO_STREAM"] = 2] = "TX_AUDIO_STREAM";
|
|
19
|
+
TciStreamType2[TciStreamType2["TX_CHRONO"] = 3] = "TX_CHRONO";
|
|
20
|
+
TciStreamType2[TciStreamType2["LINEOUT_STREAM"] = 4] = "LINEOUT_STREAM";
|
|
21
|
+
return TciStreamType2;
|
|
22
|
+
})(TciStreamType || {});
|
|
23
|
+
var TciSampleType = /* @__PURE__ */ ((TciSampleType2) => {
|
|
24
|
+
TciSampleType2[TciSampleType2["INT16"] = 0] = "INT16";
|
|
25
|
+
TciSampleType2[TciSampleType2["INT24"] = 1] = "INT24";
|
|
26
|
+
TciSampleType2[TciSampleType2["INT32"] = 2] = "INT32";
|
|
27
|
+
TciSampleType2[TciSampleType2["FLOAT32"] = 3] = "FLOAT32";
|
|
28
|
+
return TciSampleType2;
|
|
29
|
+
})(TciSampleType || {});
|
|
30
|
+
function parseStreamFrame(input) {
|
|
31
|
+
const buffer = toBuffer(input);
|
|
32
|
+
if (buffer.byteLength < TCI_STREAM_HEADER_BYTES) {
|
|
33
|
+
throw new TciError("invalid-frame", `TCI stream frame is shorter than ${TCI_STREAM_HEADER_BYTES} bytes`);
|
|
34
|
+
}
|
|
35
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
36
|
+
const header = Array.from({ length: 16 }, (_, index) => view.getUint32(index * 4, true));
|
|
37
|
+
const sampleType = normalizeSampleType(header[2]);
|
|
38
|
+
let channels = header[7];
|
|
39
|
+
const bytesPerSample = sampleTypeBytes(sampleType);
|
|
40
|
+
const sampleCount = header[5];
|
|
41
|
+
const actualPayloadLength = buffer.byteLength - TCI_STREAM_HEADER_BYTES;
|
|
42
|
+
if (channels <= 0) {
|
|
43
|
+
const inferredChannels = sampleCount > 0 ? actualPayloadLength / sampleCount / bytesPerSample : 1;
|
|
44
|
+
if (!Number.isInteger(inferredChannels) || inferredChannels <= 0) {
|
|
45
|
+
throw new TciError("invalid-frame", `Invalid TCI channel count: ${channels}`);
|
|
46
|
+
}
|
|
47
|
+
channels = inferredChannels;
|
|
48
|
+
}
|
|
49
|
+
const payloadLength = sampleCount * bytesPerSample * channels;
|
|
50
|
+
const expectedLength = TCI_STREAM_HEADER_BYTES + payloadLength;
|
|
51
|
+
if (buffer.byteLength !== expectedLength) {
|
|
52
|
+
throw new TciError(
|
|
53
|
+
"invalid-frame",
|
|
54
|
+
`TCI stream frame length mismatch: header says ${sampleCount} samples (${payloadLength} payload bytes), got ${buffer.byteLength - TCI_STREAM_HEADER_BYTES}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
if (payloadLength % (bytesPerSample * channels) !== 0) {
|
|
58
|
+
throw new TciError("invalid-frame", "TCI payload length is not aligned to sample type and channel count");
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
receiver: header[0],
|
|
62
|
+
sampleRate: header[1],
|
|
63
|
+
sampleType,
|
|
64
|
+
codec: header[3],
|
|
65
|
+
crc: header[4],
|
|
66
|
+
payloadLength,
|
|
67
|
+
streamType: normalizeStreamType(header[6]),
|
|
68
|
+
channels,
|
|
69
|
+
reserved: header.slice(8),
|
|
70
|
+
payload: buffer.subarray(TCI_STREAM_HEADER_BYTES),
|
|
71
|
+
sampleCount
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function buildStreamFrame(options) {
|
|
75
|
+
const sampleType = normalizeSampleType(options.sampleType);
|
|
76
|
+
const payload = options.payload ? toBuffer(options.payload) : samplesToPayload(options.samples ?? [], sampleType);
|
|
77
|
+
const channels = options.channels;
|
|
78
|
+
if (channels <= 0) {
|
|
79
|
+
throw new TciError("invalid-frame", `Invalid TCI channel count: ${channels}`);
|
|
80
|
+
}
|
|
81
|
+
const bytesPerSample = sampleTypeBytes(sampleType);
|
|
82
|
+
if (payload.byteLength % (bytesPerSample * channels) !== 0) {
|
|
83
|
+
throw new TciError("invalid-frame", "TCI payload length is not aligned to sample type and channel count");
|
|
84
|
+
}
|
|
85
|
+
const sampleCount = payload.byteLength / bytesPerSample / channels;
|
|
86
|
+
const frame = Buffer.alloc(TCI_STREAM_HEADER_BYTES + payload.byteLength);
|
|
87
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
88
|
+
const reserved = options.reserved ?? [];
|
|
89
|
+
const header = [
|
|
90
|
+
options.receiver ?? 0,
|
|
91
|
+
options.sampleRate,
|
|
92
|
+
sampleType,
|
|
93
|
+
options.codec ?? 0,
|
|
94
|
+
options.crc ?? 0,
|
|
95
|
+
sampleCount,
|
|
96
|
+
options.streamType,
|
|
97
|
+
channels,
|
|
98
|
+
...Array.from({ length: 8 }, (_, index) => reserved[index] ?? 0)
|
|
99
|
+
];
|
|
100
|
+
header.forEach((value, index) => view.setUint32(index * 4, value >>> 0, true));
|
|
101
|
+
payload.copy(frame, TCI_STREAM_HEADER_BYTES);
|
|
102
|
+
return frame;
|
|
103
|
+
}
|
|
104
|
+
function buildTxAudioFrame(options) {
|
|
105
|
+
return buildStreamFrame({ ...options, streamType: 2 /* TX_AUDIO_STREAM */ });
|
|
106
|
+
}
|
|
107
|
+
function sampleTypeBytes(sampleType) {
|
|
108
|
+
switch (normalizeSampleType(sampleType)) {
|
|
109
|
+
case 0 /* INT16 */:
|
|
110
|
+
return 2;
|
|
111
|
+
case 1 /* INT24 */:
|
|
112
|
+
return 3;
|
|
113
|
+
case 2 /* INT32 */:
|
|
114
|
+
case 3 /* FLOAT32 */:
|
|
115
|
+
return 4;
|
|
116
|
+
default:
|
|
117
|
+
throw new TciError("invalid-frame", `Unsupported TCI sample type: ${sampleType}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function sampleTypeName(sampleType) {
|
|
121
|
+
switch (sampleType) {
|
|
122
|
+
case 0 /* INT16 */:
|
|
123
|
+
return "int16";
|
|
124
|
+
case 1 /* INT24 */:
|
|
125
|
+
return "int24";
|
|
126
|
+
case 2 /* INT32 */:
|
|
127
|
+
return "int32";
|
|
128
|
+
case 3 /* FLOAT32 */:
|
|
129
|
+
return "float32";
|
|
130
|
+
default:
|
|
131
|
+
throw new TciError("invalid-frame", `Unsupported TCI sample type: ${sampleType}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function normalizeSampleType(sampleType) {
|
|
135
|
+
if (typeof sampleType === "string") {
|
|
136
|
+
switch (sampleType.toLowerCase()) {
|
|
137
|
+
case "int16":
|
|
138
|
+
return 0 /* INT16 */;
|
|
139
|
+
case "int24":
|
|
140
|
+
return 1 /* INT24 */;
|
|
141
|
+
case "int32":
|
|
142
|
+
return 2 /* INT32 */;
|
|
143
|
+
case "float32":
|
|
144
|
+
return 3 /* FLOAT32 */;
|
|
145
|
+
default:
|
|
146
|
+
throw new TciError("invalid-frame", `Unsupported TCI sample type: ${sampleType}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (sampleType >= 0 /* INT16 */ && sampleType <= 3 /* FLOAT32 */) {
|
|
150
|
+
return sampleType;
|
|
151
|
+
}
|
|
152
|
+
throw new TciError("invalid-frame", `Unsupported TCI sample type: ${sampleType}`);
|
|
153
|
+
}
|
|
154
|
+
function normalizeStreamType(streamType) {
|
|
155
|
+
if (streamType >= 0 /* IQ_STREAM */ && streamType <= 4 /* LINEOUT_STREAM */) {
|
|
156
|
+
return streamType;
|
|
157
|
+
}
|
|
158
|
+
throw new TciError("invalid-frame", `Unsupported TCI stream type: ${streamType}`);
|
|
159
|
+
}
|
|
160
|
+
function payloadToFloat32(frameOrPayload, sampleType) {
|
|
161
|
+
const payload = isFrame(frameOrPayload) ? frameOrPayload.payload : toBuffer(frameOrPayload);
|
|
162
|
+
const type = isFrame(frameOrPayload) ? frameOrPayload.sampleType : normalizeSampleType(sampleType ?? 3 /* FLOAT32 */);
|
|
163
|
+
const bytes = sampleTypeBytes(type);
|
|
164
|
+
if (payload.byteLength % bytes !== 0) {
|
|
165
|
+
throw new TciError("invalid-frame", "Payload length is not aligned to sample type");
|
|
166
|
+
}
|
|
167
|
+
const output = new Float32Array(payload.byteLength / bytes);
|
|
168
|
+
const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
|
|
169
|
+
for (let i = 0; i < output.length; i += 1) {
|
|
170
|
+
const offset = i * bytes;
|
|
171
|
+
switch (type) {
|
|
172
|
+
case 0 /* INT16 */:
|
|
173
|
+
output[i] = view.getInt16(offset, true) / 32768;
|
|
174
|
+
break;
|
|
175
|
+
case 1 /* INT24 */:
|
|
176
|
+
output[i] = readInt24(view, offset) / 8388608;
|
|
177
|
+
break;
|
|
178
|
+
case 2 /* INT32 */:
|
|
179
|
+
output[i] = view.getInt32(offset, true) / 2147483648;
|
|
180
|
+
break;
|
|
181
|
+
case 3 /* FLOAT32 */:
|
|
182
|
+
output[i] = view.getFloat32(offset, true);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return output;
|
|
187
|
+
}
|
|
188
|
+
function samplesToPayload(samples, sampleType) {
|
|
189
|
+
const type = normalizeSampleType(sampleType);
|
|
190
|
+
const bytes = sampleTypeBytes(type);
|
|
191
|
+
const payload = Buffer.alloc(samples.length * bytes);
|
|
192
|
+
const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
|
|
193
|
+
for (let i = 0; i < samples.length; i += 1) {
|
|
194
|
+
const value = clampSample(samples[i] ?? 0);
|
|
195
|
+
const offset = i * bytes;
|
|
196
|
+
switch (type) {
|
|
197
|
+
case 0 /* INT16 */:
|
|
198
|
+
view.setInt16(offset, Math.round(value * 32767), true);
|
|
199
|
+
break;
|
|
200
|
+
case 1 /* INT24 */:
|
|
201
|
+
writeInt24(view, offset, Math.round(value * 8388607));
|
|
202
|
+
break;
|
|
203
|
+
case 2 /* INT32 */:
|
|
204
|
+
view.setInt32(offset, Math.round(value * 2147483647), true);
|
|
205
|
+
break;
|
|
206
|
+
case 3 /* FLOAT32 */:
|
|
207
|
+
view.setFloat32(offset, value, true);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return payload;
|
|
212
|
+
}
|
|
213
|
+
function pcm16ToFloat32(input) {
|
|
214
|
+
if (input instanceof Int16Array) {
|
|
215
|
+
const output = new Float32Array(input.length);
|
|
216
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
217
|
+
output[i] = input[i] / 32768;
|
|
218
|
+
}
|
|
219
|
+
return output;
|
|
220
|
+
}
|
|
221
|
+
return payloadToFloat32(toBuffer(input), 0 /* INT16 */);
|
|
222
|
+
}
|
|
223
|
+
function float32ToPcm16(samples) {
|
|
224
|
+
return samplesToPayload(samples, 0 /* INT16 */);
|
|
225
|
+
}
|
|
226
|
+
function deinterleaveChannels(samples, channels) {
|
|
227
|
+
if (channels <= 0 || samples.length % channels !== 0) {
|
|
228
|
+
throw new TciError("invalid-frame", "Cannot deinterleave samples with invalid channel count");
|
|
229
|
+
}
|
|
230
|
+
const frames = samples.length / channels;
|
|
231
|
+
const outputs = Array.from({ length: channels }, () => new Float32Array(frames));
|
|
232
|
+
for (let frame = 0; frame < frames; frame += 1) {
|
|
233
|
+
for (let channel = 0; channel < channels; channel += 1) {
|
|
234
|
+
outputs[channel][frame] = samples[frame * channels + channel];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return outputs;
|
|
238
|
+
}
|
|
239
|
+
function mixToMono(samples, channels) {
|
|
240
|
+
if (channels === 1) {
|
|
241
|
+
return samples;
|
|
242
|
+
}
|
|
243
|
+
const separated = deinterleaveChannels(samples, channels);
|
|
244
|
+
const mono = new Float32Array(separated[0]?.length ?? 0);
|
|
245
|
+
for (const channel of separated) {
|
|
246
|
+
for (let i = 0; i < mono.length; i += 1) {
|
|
247
|
+
mono[i] += channel[i] / channels;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return mono;
|
|
251
|
+
}
|
|
252
|
+
function toBuffer(input) {
|
|
253
|
+
if (Buffer.isBuffer(input)) {
|
|
254
|
+
return input;
|
|
255
|
+
}
|
|
256
|
+
if (input instanceof ArrayBuffer) {
|
|
257
|
+
return Buffer.from(input);
|
|
258
|
+
}
|
|
259
|
+
if (ArrayBuffer.isView(input)) {
|
|
260
|
+
return Buffer.from(input.buffer, input.byteOffset, input.byteLength);
|
|
261
|
+
}
|
|
262
|
+
return Buffer.from(input);
|
|
263
|
+
}
|
|
264
|
+
function isFrame(value) {
|
|
265
|
+
return Boolean(value && typeof value === "object" && "payload" in value && "sampleType" in value);
|
|
266
|
+
}
|
|
267
|
+
function clampSample(value) {
|
|
268
|
+
if (!Number.isFinite(value)) {
|
|
269
|
+
return 0;
|
|
270
|
+
}
|
|
271
|
+
return Math.max(-1, Math.min(1, value));
|
|
272
|
+
}
|
|
273
|
+
function readInt24(view, offset) {
|
|
274
|
+
const value = view.getUint8(offset) | view.getUint8(offset + 1) << 8 | view.getUint8(offset + 2) << 16;
|
|
275
|
+
return value & 8388608 ? value | 4278190080 : value;
|
|
276
|
+
}
|
|
277
|
+
function writeInt24(view, offset, value) {
|
|
278
|
+
const clamped = Math.max(-8388608, Math.min(8388607, value));
|
|
279
|
+
view.setUint8(offset, clamped & 255);
|
|
280
|
+
view.setUint8(offset + 1, clamped >> 8 & 255);
|
|
281
|
+
view.setUint8(offset + 2, clamped >> 16 & 255);
|
|
282
|
+
}
|
|
283
|
+
export {
|
|
284
|
+
TCI_STREAM_HEADER_BYTES,
|
|
285
|
+
TciSampleType,
|
|
286
|
+
TciStreamType,
|
|
287
|
+
buildStreamFrame,
|
|
288
|
+
buildTxAudioFrame,
|
|
289
|
+
deinterleaveChannels,
|
|
290
|
+
float32ToPcm16,
|
|
291
|
+
mixToMono,
|
|
292
|
+
normalizeSampleType,
|
|
293
|
+
normalizeStreamType,
|
|
294
|
+
parseStreamFrame,
|
|
295
|
+
payloadToFloat32,
|
|
296
|
+
pcm16ToFloat32,
|
|
297
|
+
sampleTypeBytes,
|
|
298
|
+
sampleTypeName,
|
|
299
|
+
samplesToPayload
|
|
300
|
+
};
|
|
301
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/audio/streamFrame.ts"],"sourcesContent":["export type TciErrorCode =\n | 'connect-timeout'\n | 'command-timeout'\n | 'not-connected'\n | 'disconnected'\n | 'protocol-error'\n | 'invalid-frame'\n | 'cancelled';\n\nexport class TciError extends Error {\n readonly code: TciErrorCode;\n readonly details?: unknown;\n\n constructor(code: TciErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = 'TciError';\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toTciError(error: unknown, fallbackCode: TciErrorCode = 'protocol-error'): TciError {\n if (error instanceof TciError) {\n return error;\n }\n if (error instanceof Error) {\n return new TciError(fallbackCode, error.message, error);\n }\n return new TciError(fallbackCode, String(error), error);\n}\n","import { TciError } from '../errors.js';\n\nexport const TCI_STREAM_HEADER_BYTES = 16 * 4;\n\nexport enum TciStreamType {\n IQ_STREAM = 0,\n RX_AUDIO_STREAM = 1,\n TX_AUDIO_STREAM = 2,\n TX_CHRONO = 3,\n LINEOUT_STREAM = 4,\n}\n\nexport enum TciSampleType {\n INT16 = 0,\n INT24 = 1,\n INT32 = 2,\n FLOAT32 = 3,\n}\n\nexport type TciSampleTypeName = 'int16' | 'int24' | 'int32' | 'float32';\n\nexport interface TciStreamFrame {\n receiver: number;\n sampleRate: number;\n sampleType: TciSampleType;\n codec: number;\n crc: number;\n /** Byte length of the payload following the 64-byte TCI stream header. */\n payloadLength: number;\n streamType: TciStreamType;\n channels: number;\n reserved: number[];\n payload: Buffer;\n /** Official Stream.length value: number of samples per channel in the payload. */\n sampleCount: number;\n}\n\nexport interface BuildStreamFrameOptions {\n receiver?: number;\n sampleRate: number;\n sampleType: TciSampleType | TciSampleTypeName;\n streamType: TciStreamType;\n channels: number;\n payload?: Buffer | Uint8Array | ArrayBuffer | ArrayBufferView;\n samples?: Float32Array | readonly number[];\n codec?: number;\n crc?: number;\n reserved?: readonly number[];\n}\n\nexport interface BuildTxAudioFrameOptions extends Omit<BuildStreamFrameOptions, 'streamType'> {\n receiver?: number;\n}\n\nexport function parseStreamFrame(input: Buffer | ArrayBuffer | ArrayBufferView): TciStreamFrame {\n const buffer = toBuffer(input);\n if (buffer.byteLength < TCI_STREAM_HEADER_BYTES) {\n throw new TciError('invalid-frame', `TCI stream frame is shorter than ${TCI_STREAM_HEADER_BYTES} bytes`);\n }\n\n const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n const header = Array.from({ length: 16 }, (_, index) => view.getUint32(index * 4, true));\n const sampleType = normalizeSampleType(header[2]);\n let channels = header[7];\n const bytesPerSample = sampleTypeBytes(sampleType);\n const sampleCount = header[5];\n const actualPayloadLength = buffer.byteLength - TCI_STREAM_HEADER_BYTES;\n if (channels <= 0) {\n const inferredChannels = sampleCount > 0 ? actualPayloadLength / sampleCount / bytesPerSample : 1;\n if (!Number.isInteger(inferredChannels) || inferredChannels <= 0) {\n throw new TciError('invalid-frame', `Invalid TCI channel count: ${channels}`);\n }\n channels = inferredChannels;\n }\n const payloadLength = sampleCount * bytesPerSample * channels;\n const expectedLength = TCI_STREAM_HEADER_BYTES + payloadLength;\n if (buffer.byteLength !== expectedLength) {\n throw new TciError(\n 'invalid-frame',\n `TCI stream frame length mismatch: header says ${sampleCount} samples (${payloadLength} payload bytes), got ${buffer.byteLength - TCI_STREAM_HEADER_BYTES}`,\n );\n }\n if (payloadLength % (bytesPerSample * channels) !== 0) {\n throw new TciError('invalid-frame', 'TCI payload length is not aligned to sample type and channel count');\n }\n\n return {\n receiver: header[0],\n sampleRate: header[1],\n sampleType,\n codec: header[3],\n crc: header[4],\n payloadLength,\n streamType: normalizeStreamType(header[6]),\n channels,\n reserved: header.slice(8),\n payload: buffer.subarray(TCI_STREAM_HEADER_BYTES),\n sampleCount,\n };\n}\n\nexport function buildStreamFrame(options: BuildStreamFrameOptions): Buffer {\n const sampleType = normalizeSampleType(options.sampleType);\n const payload = options.payload ? toBuffer(options.payload) : samplesToPayload(options.samples ?? [], sampleType);\n const channels = options.channels;\n if (channels <= 0) {\n throw new TciError('invalid-frame', `Invalid TCI channel count: ${channels}`);\n }\n const bytesPerSample = sampleTypeBytes(sampleType);\n if (payload.byteLength % (bytesPerSample * channels) !== 0) {\n throw new TciError('invalid-frame', 'TCI payload length is not aligned to sample type and channel count');\n }\n const sampleCount = payload.byteLength / bytesPerSample / channels;\n\n const frame = Buffer.alloc(TCI_STREAM_HEADER_BYTES + payload.byteLength);\n const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);\n const reserved = options.reserved ?? [];\n const header = [\n options.receiver ?? 0,\n options.sampleRate,\n sampleType,\n options.codec ?? 0,\n options.crc ?? 0,\n sampleCount,\n options.streamType,\n channels,\n ...Array.from({ length: 8 }, (_, index) => reserved[index] ?? 0),\n ];\n header.forEach((value, index) => view.setUint32(index * 4, value >>> 0, true));\n payload.copy(frame, TCI_STREAM_HEADER_BYTES);\n return frame;\n}\n\nexport function buildTxAudioFrame(options: BuildTxAudioFrameOptions): Buffer {\n return buildStreamFrame({ ...options, streamType: TciStreamType.TX_AUDIO_STREAM });\n}\n\nexport function sampleTypeBytes(sampleType: TciSampleType | TciSampleTypeName): number {\n switch (normalizeSampleType(sampleType)) {\n case TciSampleType.INT16:\n return 2;\n case TciSampleType.INT24:\n return 3;\n case TciSampleType.INT32:\n case TciSampleType.FLOAT32:\n return 4;\n default:\n throw new TciError('invalid-frame', `Unsupported TCI sample type: ${sampleType}`);\n }\n}\n\nexport function sampleTypeName(sampleType: TciSampleType): TciSampleTypeName {\n switch (sampleType) {\n case TciSampleType.INT16:\n return 'int16';\n case TciSampleType.INT24:\n return 'int24';\n case TciSampleType.INT32:\n return 'int32';\n case TciSampleType.FLOAT32:\n return 'float32';\n default:\n throw new TciError('invalid-frame', `Unsupported TCI sample type: ${sampleType}`);\n }\n}\n\nexport function normalizeSampleType(sampleType: TciSampleType | TciSampleTypeName | number): TciSampleType {\n if (typeof sampleType === 'string') {\n switch (sampleType.toLowerCase()) {\n case 'int16':\n return TciSampleType.INT16;\n case 'int24':\n return TciSampleType.INT24;\n case 'int32':\n return TciSampleType.INT32;\n case 'float32':\n return TciSampleType.FLOAT32;\n default:\n throw new TciError('invalid-frame', `Unsupported TCI sample type: ${sampleType}`);\n }\n }\n if (sampleType >= TciSampleType.INT16 && sampleType <= TciSampleType.FLOAT32) {\n return sampleType as TciSampleType;\n }\n throw new TciError('invalid-frame', `Unsupported TCI sample type: ${sampleType}`);\n}\n\nexport function normalizeStreamType(streamType: TciStreamType | number): TciStreamType {\n if (streamType >= TciStreamType.IQ_STREAM && streamType <= TciStreamType.LINEOUT_STREAM) {\n return streamType as TciStreamType;\n }\n throw new TciError('invalid-frame', `Unsupported TCI stream type: ${streamType}`);\n}\n\nexport function payloadToFloat32(frameOrPayload: TciStreamFrame | Buffer | Uint8Array, sampleType?: TciSampleType | TciSampleTypeName): Float32Array {\n const payload = isFrame(frameOrPayload) ? frameOrPayload.payload : toBuffer(frameOrPayload);\n const type = isFrame(frameOrPayload) ? frameOrPayload.sampleType : normalizeSampleType(sampleType ?? TciSampleType.FLOAT32);\n const bytes = sampleTypeBytes(type);\n if (payload.byteLength % bytes !== 0) {\n throw new TciError('invalid-frame', 'Payload length is not aligned to sample type');\n }\n\n const output = new Float32Array(payload.byteLength / bytes);\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);\n for (let i = 0; i < output.length; i += 1) {\n const offset = i * bytes;\n switch (type) {\n case TciSampleType.INT16:\n output[i] = view.getInt16(offset, true) / 32768;\n break;\n case TciSampleType.INT24:\n output[i] = readInt24(view, offset) / 8388608;\n break;\n case TciSampleType.INT32:\n output[i] = view.getInt32(offset, true) / 2147483648;\n break;\n case TciSampleType.FLOAT32:\n output[i] = view.getFloat32(offset, true);\n break;\n }\n }\n return output;\n}\n\nexport function samplesToPayload(samples: Float32Array | readonly number[], sampleType: TciSampleType | TciSampleTypeName): Buffer {\n const type = normalizeSampleType(sampleType);\n const bytes = sampleTypeBytes(type);\n const payload = Buffer.alloc(samples.length * bytes);\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);\n for (let i = 0; i < samples.length; i += 1) {\n const value = clampSample(samples[i] ?? 0);\n const offset = i * bytes;\n switch (type) {\n case TciSampleType.INT16:\n view.setInt16(offset, Math.round(value * 32767), true);\n break;\n case TciSampleType.INT24:\n writeInt24(view, offset, Math.round(value * 8388607));\n break;\n case TciSampleType.INT32:\n view.setInt32(offset, Math.round(value * 2147483647), true);\n break;\n case TciSampleType.FLOAT32:\n view.setFloat32(offset, value, true);\n break;\n }\n }\n return payload;\n}\n\nexport function pcm16ToFloat32(input: Buffer | Uint8Array | Int16Array): Float32Array {\n if (input instanceof Int16Array) {\n const output = new Float32Array(input.length);\n for (let i = 0; i < input.length; i += 1) {\n output[i] = input[i] / 32768;\n }\n return output;\n }\n return payloadToFloat32(toBuffer(input), TciSampleType.INT16);\n}\n\nexport function float32ToPcm16(samples: Float32Array | readonly number[]): Buffer {\n return samplesToPayload(samples, TciSampleType.INT16);\n}\n\nexport function deinterleaveChannels(samples: Float32Array, channels: number): Float32Array[] {\n if (channels <= 0 || samples.length % channels !== 0) {\n throw new TciError('invalid-frame', 'Cannot deinterleave samples with invalid channel count');\n }\n const frames = samples.length / channels;\n const outputs = Array.from({ length: channels }, () => new Float32Array(frames));\n for (let frame = 0; frame < frames; frame += 1) {\n for (let channel = 0; channel < channels; channel += 1) {\n outputs[channel][frame] = samples[frame * channels + channel];\n }\n }\n return outputs;\n}\n\nexport function mixToMono(samples: Float32Array, channels: number): Float32Array {\n if (channels === 1) {\n return samples;\n }\n const separated = deinterleaveChannels(samples, channels);\n const mono = new Float32Array(separated[0]?.length ?? 0);\n for (const channel of separated) {\n for (let i = 0; i < mono.length; i += 1) {\n mono[i] += channel[i] / channels;\n }\n }\n return mono;\n}\n\nfunction toBuffer(input: Buffer | Uint8Array | ArrayBuffer | ArrayBufferView): Buffer {\n if (Buffer.isBuffer(input)) {\n return input;\n }\n if (input instanceof ArrayBuffer) {\n return Buffer.from(input);\n }\n if (ArrayBuffer.isView(input)) {\n return Buffer.from(input.buffer, input.byteOffset, input.byteLength);\n }\n return Buffer.from(input);\n}\n\nfunction isFrame(value: unknown): value is TciStreamFrame {\n return Boolean(value && typeof value === 'object' && 'payload' in value && 'sampleType' in value);\n}\n\nfunction clampSample(value: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n return Math.max(-1, Math.min(1, value));\n}\n\nfunction readInt24(view: DataView, offset: number): number {\n const value = view.getUint8(offset) | (view.getUint8(offset + 1) << 8) | (view.getUint8(offset + 2) << 16);\n return value & 0x800000 ? value | 0xff000000 : value;\n}\n\nfunction writeInt24(view: DataView, offset: number, value: number): void {\n const clamped = Math.max(-8388608, Math.min(8388607, value));\n view.setUint8(offset, clamped & 0xff);\n view.setUint8(offset + 1, (clamped >> 8) & 0xff);\n view.setUint8(offset + 2, (clamped >> 16) & 0xff);\n}\n"],"mappings":"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","names":["TciStreamType","TciSampleType"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { T as TciCommand, a as TciCommandInput } from './text-BwCWY1k1.cjs';
|
|
2
|
+
|
|
3
|
+
type TciErrorCode = 'connect-timeout' | 'command-timeout' | 'not-connected' | 'disconnected' | 'protocol-error' | 'invalid-frame' | 'cancelled';
|
|
4
|
+
declare class TciError extends Error {
|
|
5
|
+
readonly code: TciErrorCode;
|
|
6
|
+
readonly details?: unknown;
|
|
7
|
+
constructor(code: TciErrorCode, message: string, details?: unknown);
|
|
8
|
+
}
|
|
9
|
+
declare function toTciError(error: unknown, fallbackCode?: TciErrorCode): TciError;
|
|
10
|
+
|
|
11
|
+
type TciCommandMatcher = (reply: TciCommand, request: TciCommand) => boolean;
|
|
12
|
+
interface QueueCommandOptions {
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
matcher?: TciCommandMatcher;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
interface QueuedCommandResult {
|
|
18
|
+
request: TciCommand;
|
|
19
|
+
reply: TciCommand;
|
|
20
|
+
}
|
|
21
|
+
interface TciCommandQueueOptions {
|
|
22
|
+
send: (raw: string) => void | Promise<void>;
|
|
23
|
+
timeoutMs?: number;
|
|
24
|
+
}
|
|
25
|
+
declare class TciCommandQueue {
|
|
26
|
+
private readonly send;
|
|
27
|
+
private readonly defaultTimeoutMs;
|
|
28
|
+
private queue;
|
|
29
|
+
private active?;
|
|
30
|
+
private connected;
|
|
31
|
+
constructor(options: TciCommandQueueOptions);
|
|
32
|
+
setConnected(connected: boolean): void;
|
|
33
|
+
enqueue(command: TciCommandInput, options?: QueueCommandOptions): Promise<QueuedCommandResult>;
|
|
34
|
+
handleCommand(commandInput: TciCommandInput): boolean;
|
|
35
|
+
cancelAll(error?: TciError): void;
|
|
36
|
+
get size(): number;
|
|
37
|
+
private pump;
|
|
38
|
+
private finishActive;
|
|
39
|
+
private rejectPending;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type QueueCommandOptions as Q, TciError as T, type QueuedCommandResult as a, type TciCommandMatcher as b, TciCommandQueue as c, type TciCommandQueueOptions as d, type TciErrorCode as e, toTciError as t };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { T as TciCommand, a as TciCommandInput } from './text-BwCWY1k1.js';
|
|
2
|
+
|
|
3
|
+
type TciErrorCode = 'connect-timeout' | 'command-timeout' | 'not-connected' | 'disconnected' | 'protocol-error' | 'invalid-frame' | 'cancelled';
|
|
4
|
+
declare class TciError extends Error {
|
|
5
|
+
readonly code: TciErrorCode;
|
|
6
|
+
readonly details?: unknown;
|
|
7
|
+
constructor(code: TciErrorCode, message: string, details?: unknown);
|
|
8
|
+
}
|
|
9
|
+
declare function toTciError(error: unknown, fallbackCode?: TciErrorCode): TciError;
|
|
10
|
+
|
|
11
|
+
type TciCommandMatcher = (reply: TciCommand, request: TciCommand) => boolean;
|
|
12
|
+
interface QueueCommandOptions {
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
matcher?: TciCommandMatcher;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
interface QueuedCommandResult {
|
|
18
|
+
request: TciCommand;
|
|
19
|
+
reply: TciCommand;
|
|
20
|
+
}
|
|
21
|
+
interface TciCommandQueueOptions {
|
|
22
|
+
send: (raw: string) => void | Promise<void>;
|
|
23
|
+
timeoutMs?: number;
|
|
24
|
+
}
|
|
25
|
+
declare class TciCommandQueue {
|
|
26
|
+
private readonly send;
|
|
27
|
+
private readonly defaultTimeoutMs;
|
|
28
|
+
private queue;
|
|
29
|
+
private active?;
|
|
30
|
+
private connected;
|
|
31
|
+
constructor(options: TciCommandQueueOptions);
|
|
32
|
+
setConnected(connected: boolean): void;
|
|
33
|
+
enqueue(command: TciCommandInput, options?: QueueCommandOptions): Promise<QueuedCommandResult>;
|
|
34
|
+
handleCommand(commandInput: TciCommandInput): boolean;
|
|
35
|
+
cancelAll(error?: TciError): void;
|
|
36
|
+
get size(): number;
|
|
37
|
+
private pump;
|
|
38
|
+
private finishActive;
|
|
39
|
+
private rejectPending;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type QueueCommandOptions as Q, TciError as T, type QueuedCommandResult as a, type TciCommandMatcher as b, TciCommandQueue as c, type TciCommandQueueOptions as d, type TciErrorCode as e, toTciError as t };
|