alphatheta-connect 0.19.2 → 0.21.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/lib/index.js CHANGED
@@ -74,26 +74,30 @@ async function extractArtworkFromDevice(device, slot, filePath, logger = logger_
74
74
 
75
75
  Object.defineProperty(exports, "__esModule", ({ value: true }));
76
76
  exports.extractFromAiff = extractFromAiff;
77
- const id3_1 = __webpack_require__(/*! ./id3 */ "./src/artwork/parsers/id3.ts");
78
77
  const reader_1 = __webpack_require__(/*! ../reader */ "./src/artwork/reader.ts");
78
+ const id3_1 = __webpack_require__(/*! ./id3 */ "./src/artwork/parsers/id3.ts");
79
79
  async function extractFromAiff(reader) {
80
80
  const header = await reader.read(0, 12);
81
- if (header.length < 12 || header.toString('ascii', 0, 4) !== 'FORM')
81
+ if (header.length < 12 || header.toString('ascii', 0, 4) !== 'FORM') {
82
82
  return null;
83
+ }
83
84
  const formType = header.toString('ascii', 8, 12);
84
- if (formType !== 'AIFF' && formType !== 'AIFC')
85
+ if (formType !== 'AIFF' && formType !== 'AIFC') {
85
86
  return null;
87
+ }
86
88
  const formSize = header.readUInt32BE(4);
87
89
  const fileEnd = Math.min(8 + formSize, reader.size);
88
90
  let offset = 12;
89
91
  while (offset + 8 < fileEnd) {
90
92
  const chunkHeader = await reader.read(offset, 8);
91
- if (chunkHeader.length < 8)
93
+ if (chunkHeader.length < 8) {
92
94
  break;
95
+ }
93
96
  const chunkId = chunkHeader.toString('ascii', 0, 4);
94
97
  const chunkSize = chunkHeader.readUInt32BE(4);
95
- if (chunkSize <= 0 || offset + 8 + chunkSize > fileEnd)
98
+ if (chunkSize <= 0 || offset + 8 + chunkSize > fileEnd) {
96
99
  break;
100
+ }
97
101
  if (chunkId === 'ID3 ' || chunkId === 'id3 ') {
98
102
  const id3Data = await reader.read(offset + 8, chunkSize);
99
103
  const id3Reader = (0, reader_1.createBufferReader)(id3Data, 'mp3');
@@ -120,32 +124,37 @@ exports.extractFromFlac = extractFromFlac;
120
124
  const types_1 = __webpack_require__(/*! ../types */ "./src/artwork/types.ts");
121
125
  const utils_1 = __webpack_require__(/*! ./utils */ "./src/artwork/parsers/utils.ts");
122
126
  function parsePictureBlock(data) {
123
- if (data.length < 32)
127
+ if (data.length < 32) {
124
128
  return null;
129
+ }
125
130
  let offset = 0;
126
131
  const pictureType = data.readUInt32BE(offset);
127
132
  offset += 4;
128
133
  const mimeLength = data.readUInt32BE(offset);
129
134
  offset += 4;
130
- if (offset + mimeLength > data.length)
135
+ if (offset + mimeLength > data.length) {
131
136
  return null;
137
+ }
132
138
  const mimeType = data.toString('utf8', offset, offset + mimeLength);
133
139
  offset += mimeLength;
134
140
  const descLength = data.readUInt32BE(offset);
135
141
  offset += 4 + descLength;
136
- if (offset + 16 > data.length)
142
+ if (offset + 16 > data.length) {
137
143
  return null;
144
+ }
138
145
  const width = data.readUInt32BE(offset);
139
146
  offset += 4;
140
147
  const height = data.readUInt32BE(offset);
141
148
  offset += 4 + 8; // Skip depth and colors
142
149
  const imageLength = data.readUInt32BE(offset);
143
150
  offset += 4;
144
- if (offset + imageLength > data.length)
151
+ if (offset + imageLength > data.length) {
145
152
  return null;
153
+ }
146
154
  const imageData = data.subarray(offset, offset + imageLength);
147
- if (imageData.length === 0)
155
+ if (imageData.length === 0) {
148
156
  return null;
157
+ }
149
158
  return {
150
159
  data: imageData,
151
160
  mimeType: (0, utils_1.normalizeMimeType)(mimeType),
@@ -156,29 +165,34 @@ function parsePictureBlock(data) {
156
165
  }
157
166
  async function extractFromFlac(reader) {
158
167
  const signature = await reader.read(0, 4);
159
- if (signature.toString('ascii') !== 'fLaC')
168
+ if (signature.toString('ascii') !== 'fLaC') {
160
169
  return null;
170
+ }
161
171
  let offset = 4;
162
172
  let isLastBlock = false;
163
173
  let frontCover = null;
164
174
  let anyArtwork = null;
165
175
  while (!isLastBlock && offset < reader.size) {
166
176
  const blockHeader = await reader.read(offset, 4);
167
- if (blockHeader.length < 4)
177
+ if (blockHeader.length < 4) {
168
178
  break;
179
+ }
169
180
  isLastBlock = (blockHeader[0] & 0x80) !== 0;
170
181
  const blockType = blockHeader[0] & 0x7f;
171
182
  const blockLength = (blockHeader[1] << 16) | (blockHeader[2] << 8) | blockHeader[3];
172
- if (blockLength <= 0 || offset + 4 + blockLength > reader.size)
183
+ if (blockLength <= 0 || offset + 4 + blockLength > reader.size) {
173
184
  break;
185
+ }
174
186
  if (blockType === 6 /* MetadataBlockType.PICTURE */) {
175
187
  const pictureData = await reader.read(offset + 4, blockLength);
176
188
  const artwork = parsePictureBlock(pictureData);
177
189
  if (artwork) {
178
- if (artwork.pictureType === types_1.PictureType.FrontCover)
190
+ if (artwork.pictureType === types_1.PictureType.FrontCover) {
179
191
  frontCover = artwork;
180
- else if (!anyArtwork)
192
+ }
193
+ else if (!anyArtwork) {
181
194
  anyArtwork = artwork;
195
+ }
182
196
  }
183
197
  }
184
198
  offset += 4 + blockLength;
@@ -212,14 +226,16 @@ function readNullTerminatedString(buffer, offset, encoding) {
212
226
  let end = offset;
213
227
  if (isUtf16) {
214
228
  while (end < buffer.length - 1) {
215
- if (buffer[end] === 0 && buffer[end + 1] === 0)
229
+ if (buffer[end] === 0 && buffer[end + 1] === 0) {
216
230
  break;
231
+ }
217
232
  end += 2;
218
233
  }
219
234
  }
220
235
  else {
221
- while (end < buffer.length && buffer[end] !== 0)
236
+ while (end < buffer.length && buffer[end] !== 0) {
222
237
  end++;
238
+ }
223
239
  }
224
240
  let value;
225
241
  if (encoding === 'utf16be') {
@@ -237,56 +253,70 @@ function readNullTerminatedString(buffer, offset, encoding) {
237
253
  }
238
254
  function getTextEncoding(encodingByte) {
239
255
  switch (encodingByte) {
240
- case 0: return 'latin1';
241
- case 1: return 'utf16le';
242
- case 2: return 'utf16be';
243
- case 3: return 'utf8';
244
- default: return 'latin1';
256
+ case 0:
257
+ return 'latin1';
258
+ case 1:
259
+ return 'utf16le';
260
+ case 2:
261
+ return 'utf16be';
262
+ case 3:
263
+ return 'utf8';
264
+ default:
265
+ return 'latin1';
245
266
  }
246
267
  }
247
268
  function parseApicFrame(data) {
248
- if (data.length < 4)
269
+ if (data.length < 4) {
249
270
  return null;
271
+ }
250
272
  let offset = 0;
251
273
  const encodingByte = data[offset++];
252
274
  let encoding = getTextEncoding(encodingByte);
253
275
  if (encodingByte === 1 && data.length > offset + 2) {
254
276
  const bom = data.readUInt16BE(offset);
255
- if (bom === 0xfeff)
277
+ if (bom === 0xfeff) {
256
278
  encoding = 'utf16be';
257
- else if (bom === 0xfffe)
279
+ }
280
+ else if (bom === 0xfffe) {
258
281
  encoding = 'utf16le';
282
+ }
259
283
  }
260
284
  const mimeResult = readNullTerminatedString(data, offset, 'latin1');
261
285
  const mimeType = mimeResult.value;
262
286
  offset += mimeResult.bytesConsumed;
263
- if (offset >= data.length)
287
+ if (offset >= data.length) {
264
288
  return null;
289
+ }
265
290
  const pictureType = data[offset++];
266
- if (offset >= data.length)
291
+ if (offset >= data.length) {
267
292
  return null;
293
+ }
268
294
  const descResult = readNullTerminatedString(data, offset, encoding);
269
295
  offset += descResult.bytesConsumed;
270
- if (offset >= data.length)
296
+ if (offset >= data.length) {
271
297
  return null;
298
+ }
272
299
  const imageData = data.subarray(offset);
273
- if (imageData.length === 0)
300
+ if (imageData.length === 0) {
274
301
  return null;
302
+ }
275
303
  const detectedType = (0, utils_1.detectImageType)(imageData);
276
304
  const finalMimeType = detectedType !== null && detectedType !== void 0 ? detectedType : (mimeType.includes('png') ? 'image/png' : 'image/jpeg');
277
305
  return { data: imageData, mimeType: finalMimeType, pictureType };
278
306
  }
279
307
  async function extractFromMp3(reader) {
280
308
  const header = await reader.read(0, 10);
281
- if (header.length < 10 || header.toString('ascii', 0, 3) !== 'ID3')
309
+ if (header.length < 10 || header.toString('ascii', 0, 3) !== 'ID3') {
282
310
  return null;
311
+ }
283
312
  const majorVersion = header[3];
284
313
  const flags = header[5];
285
314
  const tagSize = readSyncsafe(header, 6);
286
315
  let extendedHeaderSize = 0;
287
316
  if (flags & 0x40) {
288
317
  const extHeader = await reader.read(10, 4);
289
- extendedHeaderSize = majorVersion === 4 ? readSyncsafe(extHeader, 0) : extHeader.readUInt32BE(0);
318
+ extendedHeaderSize =
319
+ majorVersion === 4 ? readSyncsafe(extHeader, 0) : extHeader.readUInt32BE(0);
290
320
  }
291
321
  const tagData = await reader.read(10 + extendedHeaderSize, tagSize - extendedHeaderSize);
292
322
  let offset = 0;
@@ -294,29 +324,37 @@ async function extractFromMp3(reader) {
294
324
  let frontCover = null;
295
325
  let anyArtwork = null;
296
326
  while (offset < tagData.length - frameHeaderSize) {
297
- if (tagData[offset] === 0)
327
+ if (tagData[offset] === 0) {
298
328
  break;
329
+ }
299
330
  let frameId;
300
331
  let frameSize;
301
332
  if (majorVersion >= 3) {
302
333
  frameId = tagData.toString('ascii', offset, offset + 4);
303
- frameSize = majorVersion === 4 ? readSyncsafe(tagData, offset + 4) : tagData.readUInt32BE(offset + 4);
334
+ frameSize =
335
+ majorVersion === 4
336
+ ? readSyncsafe(tagData, offset + 4)
337
+ : tagData.readUInt32BE(offset + 4);
304
338
  }
305
339
  else {
306
340
  frameId = tagData.toString('ascii', offset, offset + 3);
307
- frameSize = (tagData[offset + 3] << 16) | (tagData[offset + 4] << 8) | tagData[offset + 5];
341
+ frameSize =
342
+ (tagData[offset + 3] << 16) | (tagData[offset + 4] << 8) | tagData[offset + 5];
308
343
  }
309
- if (frameSize <= 0 || frameSize > tagData.length - offset)
344
+ if (frameSize <= 0 || frameSize > tagData.length - offset) {
310
345
  break;
346
+ }
311
347
  const frameIdNormalized = majorVersion >= 3 ? frameId : frameId === 'PIC' ? 'APIC' : frameId;
312
348
  if (frameIdNormalized === 'APIC') {
313
349
  const frameData = tagData.subarray(offset + frameHeaderSize, offset + frameHeaderSize + frameSize);
314
350
  const artwork = parseApicFrame(frameData);
315
351
  if (artwork) {
316
- if (artwork.pictureType === types_1.PictureType.FrontCover)
352
+ if (artwork.pictureType === types_1.PictureType.FrontCover) {
317
353
  frontCover = artwork;
318
- else if (!anyArtwork)
354
+ }
355
+ else if (!anyArtwork) {
319
356
  anyArtwork = artwork;
357
+ }
320
358
  }
321
359
  }
322
360
  offset += frameHeaderSize + frameSize;
@@ -336,15 +374,15 @@ async function extractFromMp3(reader) {
336
374
  "use strict";
337
375
 
338
376
  Object.defineProperty(exports, "__esModule", ({ value: true }));
339
- exports.normalizeMimeType = exports.detectImageType = exports.extractFromAiff = exports.extractFromFlac = exports.extractFromMp4 = exports.extractFromMp3 = void 0;
377
+ exports.normalizeMimeType = exports.detectImageType = exports.extractFromMp4 = exports.extractFromMp3 = exports.extractFromFlac = exports.extractFromAiff = void 0;
378
+ var aiff_1 = __webpack_require__(/*! ./aiff */ "./src/artwork/parsers/aiff.ts");
379
+ Object.defineProperty(exports, "extractFromAiff", ({ enumerable: true, get: function () { return aiff_1.extractFromAiff; } }));
380
+ var flac_1 = __webpack_require__(/*! ./flac */ "./src/artwork/parsers/flac.ts");
381
+ Object.defineProperty(exports, "extractFromFlac", ({ enumerable: true, get: function () { return flac_1.extractFromFlac; } }));
340
382
  var id3_1 = __webpack_require__(/*! ./id3 */ "./src/artwork/parsers/id3.ts");
341
383
  Object.defineProperty(exports, "extractFromMp3", ({ enumerable: true, get: function () { return id3_1.extractFromMp3; } }));
342
384
  var mp4_1 = __webpack_require__(/*! ./mp4 */ "./src/artwork/parsers/mp4.ts");
343
385
  Object.defineProperty(exports, "extractFromMp4", ({ enumerable: true, get: function () { return mp4_1.extractFromMp4; } }));
344
- var flac_1 = __webpack_require__(/*! ./flac */ "./src/artwork/parsers/flac.ts");
345
- Object.defineProperty(exports, "extractFromFlac", ({ enumerable: true, get: function () { return flac_1.extractFromFlac; } }));
346
- var aiff_1 = __webpack_require__(/*! ./aiff */ "./src/artwork/parsers/aiff.ts");
347
- Object.defineProperty(exports, "extractFromAiff", ({ enumerable: true, get: function () { return aiff_1.extractFromAiff; } }));
348
386
  var utils_1 = __webpack_require__(/*! ./utils */ "./src/artwork/parsers/utils.ts");
349
387
  Object.defineProperty(exports, "detectImageType", ({ enumerable: true, get: function () { return utils_1.detectImageType; } }));
350
388
  Object.defineProperty(exports, "normalizeMimeType", ({ enumerable: true, get: function () { return utils_1.normalizeMimeType; } }));
@@ -365,30 +403,37 @@ exports.extractFromMp4 = extractFromMp4;
365
403
  const types_1 = __webpack_require__(/*! ../types */ "./src/artwork/types.ts");
366
404
  const utils_1 = __webpack_require__(/*! ./utils */ "./src/artwork/parsers/utils.ts");
367
405
  async function readAtomHeader(reader, offset) {
368
- if (offset + 8 > reader.size)
406
+ if (offset + 8 > reader.size) {
369
407
  return null;
408
+ }
370
409
  const header = await reader.read(offset, 8);
371
410
  const size = header.readUInt32BE(0);
372
411
  const type = header.toString('ascii', 4, 8);
373
412
  if (size === 1) {
374
- if (offset + 16 > reader.size)
413
+ if (offset + 16 > reader.size) {
375
414
  return null;
415
+ }
376
416
  const extHeader = await reader.read(offset + 8, 8);
377
417
  const extSize = Number(extHeader.readBigUInt64BE(0));
378
418
  return { size: extSize, type, headerSize: 16 };
379
419
  }
380
- if (size === 0)
420
+ if (size === 0) {
381
421
  return { size: reader.size - offset, type, headerSize: 8 };
422
+ }
382
423
  return { size, type, headerSize: 8 };
383
424
  }
384
425
  async function findAtom(reader, startOffset, endOffset, targetType) {
385
426
  let offset = startOffset;
386
427
  while (offset < endOffset) {
387
428
  const header = await readAtomHeader(reader, offset);
388
- if (!header || header.size <= 0)
429
+ if (!header || header.size <= 0) {
389
430
  break;
431
+ }
390
432
  if (header.type === targetType) {
391
- return { dataOffset: offset + header.headerSize, dataSize: header.size - header.headerSize };
433
+ return {
434
+ dataOffset: offset + header.headerSize,
435
+ dataSize: header.size - header.headerSize,
436
+ };
392
437
  }
393
438
  offset += header.size;
394
439
  }
@@ -399,35 +444,43 @@ async function findMoovAtom(reader) {
399
444
  }
400
445
  async function findCoverArtData(reader, moovOffset, moovSize) {
401
446
  const udta = await findAtom(reader, moovOffset, moovOffset + moovSize, 'udta');
402
- if (!udta)
447
+ if (!udta) {
403
448
  return null;
449
+ }
404
450
  const meta = await findAtom(reader, udta.dataOffset, udta.dataOffset + udta.dataSize, 'meta');
405
- if (!meta)
451
+ if (!meta) {
406
452
  return null;
453
+ }
407
454
  const metaDataStart = meta.dataOffset + 4;
408
455
  const metaDataEnd = meta.dataOffset + meta.dataSize;
409
456
  const ilst = await findAtom(reader, metaDataStart, metaDataEnd, 'ilst');
410
- if (!ilst)
457
+ if (!ilst) {
411
458
  return null;
459
+ }
412
460
  const covr = await findAtom(reader, ilst.dataOffset, ilst.dataOffset + ilst.dataSize, 'covr');
413
- if (!covr)
461
+ if (!covr) {
414
462
  return null;
463
+ }
415
464
  const data = await findAtom(reader, covr.dataOffset, covr.dataOffset + covr.dataSize, 'data');
416
- if (!data || data.dataSize < 8)
465
+ if (!data || data.dataSize < 8) {
417
466
  return null;
467
+ }
418
468
  return reader.read(data.dataOffset + 8, data.dataSize - 8);
419
469
  }
420
470
  async function extractFromMp4(reader) {
421
471
  var _a;
422
472
  const ftypHeader = await reader.read(0, 8);
423
- if (ftypHeader.length < 8 || ftypHeader.toString('ascii', 4, 8) !== 'ftyp')
473
+ if (ftypHeader.length < 8 || ftypHeader.toString('ascii', 4, 8) !== 'ftyp') {
424
474
  return null;
475
+ }
425
476
  const moov = await findMoovAtom(reader);
426
- if (!moov)
477
+ if (!moov) {
427
478
  return null;
479
+ }
428
480
  const imageData = await findCoverArtData(reader, moov.dataOffset, moov.dataSize);
429
- if (!imageData || imageData.length === 0)
481
+ if (!imageData || imageData.length === 0) {
430
482
  return null;
483
+ }
431
484
  const mimeType = (_a = (0, utils_1.detectImageType)(imageData)) !== null && _a !== void 0 ? _a : 'image/jpeg';
432
485
  return { data: imageData, mimeType, pictureType: types_1.PictureType.FrontCover };
433
486
  }
@@ -447,22 +500,28 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
447
500
  exports.detectImageType = detectImageType;
448
501
  exports.normalizeMimeType = normalizeMimeType;
449
502
  function detectImageType(data) {
450
- if (data.length < 4)
503
+ if (data.length < 4) {
451
504
  return null;
452
- if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff)
505
+ }
506
+ if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff) {
453
507
  return 'image/jpeg';
454
- if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG')
508
+ }
509
+ if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') {
455
510
  return 'image/png';
456
- if (data.toString('ascii', 0, 3) === 'GIF')
511
+ }
512
+ if (data.toString('ascii', 0, 3) === 'GIF') {
457
513
  return 'image/gif';
514
+ }
458
515
  return null;
459
516
  }
460
517
  function normalizeMimeType(mimeType) {
461
518
  const lower = mimeType.toLowerCase();
462
- if (lower.includes('png'))
519
+ if (lower.includes('png')) {
463
520
  return 'image/png';
464
- if (lower.includes('gif'))
521
+ }
522
+ if (lower.includes('gif')) {
465
523
  return 'image/gif';
524
+ }
466
525
  return 'image/jpeg';
467
526
  }
468
527
 
@@ -639,19 +698,20 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
639
698
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
640
699
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
641
700
  };
642
- var _Control_hostDevice, _Control_beatSocket;
701
+ var _Control_hostDevice, _Control_beatSocket, _Control_correlationByte;
643
702
  Object.defineProperty(exports, "__esModule", ({ value: true }));
644
703
  exports.makePlaystatePacket = void 0;
645
704
  const constants_1 = __webpack_require__(/*! src/constants */ "./src/constants.ts");
646
705
  const types_1 = __webpack_require__(/*! src/types */ "./src/types.ts");
647
706
  const utils_1 = __webpack_require__(/*! src/utils */ "./src/utils/index.ts");
648
707
  const udp_1 = __webpack_require__(/*! src/utils/udp */ "./src/utils/udp.ts");
708
+ const stagehand_1 = __webpack_require__(/*! ./stagehand */ "./src/control/stagehand.ts");
649
709
  const STATE_MAP = {
650
710
  [types_1.CDJStatus.PlayState.Cued]: 0x01,
651
711
  [types_1.CDJStatus.PlayState.Playing]: 0x00,
652
712
  };
653
713
  /**
654
- * Generates the packet used to control the playstate of CDJs
714
+ * Generates the packet used to control the playstate of CDJs in active connection mode
655
715
  */
656
716
  const makePlaystatePacket = ({ hostDevice, device, playState }) => Uint8Array.from([
657
717
  ...constants_1.PROLINK_HEADER,
@@ -672,21 +732,174 @@ class Control {
672
732
  * The socket used to send control packets
673
733
  */
674
734
  _Control_beatSocket.set(this, void 0);
735
+ /**
736
+ * Randomized correlation byte per session for Stagehand commands
737
+ */
738
+ _Control_correlationByte.set(this, void 0);
675
739
  __classPrivateFieldSet(this, _Control_beatSocket, beatSocket, "f");
676
740
  __classPrivateFieldSet(this, _Control_hostDevice, hostDevice, "f");
741
+ __classPrivateFieldSet(this, _Control_correlationByte, Math.floor(Math.random() * 256), "f");
677
742
  }
678
743
  /**
679
- * Start or stop a CDJ on the network
744
+ * Start or stop a CDJ on the network.
745
+ * Delegates automatically to Stagehand-specific transport control if connected in Stagehand mode.
680
746
  */
681
747
  async setPlayState(device, playState) {
748
+ if (__classPrivateFieldGet(this, _Control_hostDevice, "f").type === types_1.DeviceType.Stagehand) {
749
+ if (playState === types_1.CDJStatus.PlayState.Playing) {
750
+ await this.play(device);
751
+ }
752
+ else {
753
+ await this.pause(device);
754
+ }
755
+ return;
756
+ }
682
757
  const packet = (0, exports.makePlaystatePacket)({ hostDevice: __classPrivateFieldGet(this, _Control_hostDevice, "f"), device, playState });
683
758
  await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), packet, constants_1.BEAT_PORT, device.ip.address);
684
759
  }
760
+ /**
761
+ * Send Stagehand PLAY command (paired 0x0f and 0x14 packets)
762
+ */
763
+ async play(device) {
764
+ const p1 = (0, stagehand_1.makeStagehandTransportPacket)(__classPrivateFieldGet(this, _Control_hostDevice, "f"), 0x0f, true, __classPrivateFieldGet(this, _Control_correlationByte, "f"));
765
+ const p2 = (0, stagehand_1.makeStagehandTransportPacket)(__classPrivateFieldGet(this, _Control_hostDevice, "f"), 0x14, true, __classPrivateFieldGet(this, _Control_correlationByte, "f"));
766
+ await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), p1, constants_1.BEAT_PORT, device.ip.address);
767
+ await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), p2, constants_1.BEAT_PORT, device.ip.address);
768
+ }
769
+ /**
770
+ * Send Stagehand PAUSE command (paired 0x14 packet)
771
+ */
772
+ async pause(device) {
773
+ const p = (0, stagehand_1.makeStagehandTransportPacket)(__classPrivateFieldGet(this, _Control_hostDevice, "f"), 0x14, false, __classPrivateFieldGet(this, _Control_correlationByte, "f"));
774
+ await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), p, constants_1.BEAT_PORT, device.ip.address);
775
+ }
776
+ /**
777
+ * Send Stagehand SEEK forward command
778
+ * @param press - true to start seek, false to release
779
+ */
780
+ async seekForward(device, press) {
781
+ const p = (0, stagehand_1.makeStagehandTransportPacket)(__classPrivateFieldGet(this, _Control_hostDevice, "f"), 0x1a, press, __classPrivateFieldGet(this, _Control_correlationByte, "f"));
782
+ await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), p, constants_1.BEAT_PORT, device.ip.address);
783
+ }
784
+ /**
785
+ * Send Stagehand SEEK backward command
786
+ * @param press - true to start seek, false to release
787
+ */
788
+ async seekBackward(device, press) {
789
+ const p = (0, stagehand_1.makeStagehandTransportPacket)(__classPrivateFieldGet(this, _Control_hostDevice, "f"), 0x1b, press, __classPrivateFieldGet(this, _Control_correlationByte, "f"));
790
+ await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), p, constants_1.BEAT_PORT, device.ip.address);
791
+ }
792
+ /**
793
+ * Send Stagehand SKIP track command
794
+ * @param press - true to start skip, false to release
795
+ */
796
+ async skip(device, press) {
797
+ const p = (0, stagehand_1.makeStagehandTransportPacket)(__classPrivateFieldGet(this, _Control_hostDevice, "f"), 0x18, press, __classPrivateFieldGet(this, _Control_correlationByte, "f"));
798
+ await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), p, constants_1.BEAT_PORT, device.ip.address);
799
+ }
800
+ /**
801
+ * Send Stagehand preference write command (0x6b packet) to port 50002
802
+ */
803
+ async setPreference(device, options) {
804
+ const p = (0, stagehand_1.makeStagehandPrefWritePacket)(__classPrivateFieldGet(this, _Control_hostDevice, "f"), options);
805
+ await (0, udp_1.udpSend)(__classPrivateFieldGet(this, _Control_beatSocket, "f"), p, constants_1.STATUS_PORT, device.ip.address);
806
+ }
685
807
  }
686
- _Control_hostDevice = new WeakMap(), _Control_beatSocket = new WeakMap();
808
+ _Control_hostDevice = new WeakMap(), _Control_beatSocket = new WeakMap(), _Control_correlationByte = new WeakMap();
687
809
  exports["default"] = Control;
688
810
 
689
811
 
812
+ /***/ },
813
+
814
+ /***/ "./src/control/stagehand.ts"
815
+ /*!**********************************!*\
816
+ !*** ./src/control/stagehand.ts ***!
817
+ \**********************************/
818
+ (__unused_webpack_module, exports, __webpack_require__) {
819
+
820
+ "use strict";
821
+
822
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
823
+ exports.makeStagehandTransportPacket = makeStagehandTransportPacket;
824
+ exports.makeStagehandPrefWritePacket = makeStagehandPrefWritePacket;
825
+ const constants_1 = __webpack_require__(/*! src/constants */ "./src/constants.ts");
826
+ const utils_1 = __webpack_require__(/*! src/utils */ "./src/utils/index.ts");
827
+ /**
828
+ * Generates a Stagehand transport control packet (0x07, 56 bytes)
829
+ *
830
+ * @param hostDevice - The Stagehand device posing as sender
831
+ * @param op - The command opcode (e.g. 0x0f, 0x14, 0x18, 0x1a, 0x1b)
832
+ * @param press - Whether the action is press (true) or release (false)
833
+ * @param correlationByte - The randomized per-session correlation byte
834
+ */
835
+ function makeStagehandTransportPacket(hostDevice, op, press, correlationByte) {
836
+ const packet = new Uint8Array(56);
837
+ // 0-9: magic header
838
+ packet.set(constants_1.PROLINK_HEADER, 0);
839
+ // 10: opcode 0x07
840
+ packet[10] = 0x07;
841
+ // 11-30: device name
842
+ packet.set((0, utils_1.buildName)(hostDevice), 11);
843
+ // 31: 0x01
844
+ packet[31] = 0x01;
845
+ // 32: 0x03
846
+ packet[32] = 0x03;
847
+ // 33: per-session correlation byte
848
+ packet[33] = correlationByte;
849
+ // 34-35: remaining length 0x0030 (48 bytes)
850
+ packet[34] = 0x00;
851
+ packet[35] = 0x30;
852
+ // 40: Stagehand sub-id 0x3a
853
+ packet[40] = 0x3a;
854
+ // 44: command opcode
855
+ packet[44] = op;
856
+ // 46: press/release flag
857
+ packet[46] = press ? 0x01 : 0x00;
858
+ return packet;
859
+ }
860
+ /**
861
+ * Generates a Stagehand preference write packet (0x6b, 124 bytes)
862
+ *
863
+ * @param hostDevice - The Stagehand device posing as sender
864
+ * @param options - The preferences to write (onAir, quantize)
865
+ */
866
+ function makeStagehandPrefWritePacket(hostDevice, options) {
867
+ const packet = new Uint8Array(124);
868
+ // 0-9: magic header
869
+ packet.set(constants_1.PROLINK_HEADER, 0);
870
+ // 10: opcode 0x6b
871
+ packet[10] = 0x6b;
872
+ // 11-30: device name
873
+ const name = (0, utils_1.buildName)(hostDevice);
874
+ // Trailing byte 30 (which is offset 30, meaning index 19 of name) is set to 0x03
875
+ name[19] = 0x03;
876
+ packet.set(name, 11);
877
+ // 31: 0x01 (subscription-id-a constant)
878
+ packet[31] = 0x01;
879
+ // 32: 0x03 (constant)
880
+ packet[32] = 0x03;
881
+ // 33: Stagehand sub-id constant 0x3a
882
+ packet[33] = 0x3a;
883
+ // 34-35: body length 0x0050 (80 bytes)
884
+ packet[34] = 0x00;
885
+ packet[35] = 0x50;
886
+ // 36: transaction flag (0x01 = write)
887
+ packet[36] = 0x01;
888
+ // 44: on_air slot (0x80 = OFF, 0x81 = ON, 0x00 = untouched)
889
+ if (options.onAir === 'on') {
890
+ packet[44] = 0x81;
891
+ }
892
+ else if (options.onAir === 'off') {
893
+ packet[44] = 0x80;
894
+ }
895
+ // 60: quantize slot (0x80 | enum_index, e.g. 0x81, 0x82 etc.)
896
+ if (options.quantize !== undefined) {
897
+ packet[60] = 0x80 | options.quantize;
898
+ }
899
+ return packet;
900
+ }
901
+
902
+
690
903
  /***/ },
691
904
 
692
905
  /***/ "./src/db/getArtworkFromFile.ts"
@@ -1840,10 +2053,6 @@ function deviceFromPacket(packet) {
1840
2053
 
1841
2054
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1842
2055
  exports.EntityFK = void 0;
1843
- /**
1844
- * Re-export entity types from onelibrary-connect.
1845
- * These types represent what is stored in the rekordbox database.
1846
- */
1847
2056
  var onelibrary_connect_1 = __webpack_require__(/*! onelibrary-connect */ "onelibrary-connect");
1848
2057
  Object.defineProperty(exports, "EntityFK", ({ enumerable: true, get: function () { return onelibrary_connect_1.EntityFK; } }));
1849
2058
 
@@ -1884,25 +2093,21 @@ var position_1 = __webpack_require__(/*! ./status/position */ "./src/status/posi
1884
2093
  Object.defineProperty(exports, "PositionEmitter", ({ enumerable: true, get: function () { return __importDefault(position_1).default; } }));
1885
2094
  // Passive mode (pcap-based monitoring without announcing a VCDJ)
1886
2095
  __exportStar(__webpack_require__(/*! ./passive */ "./src/passive/index.ts"), exports);
1887
- // Artwork extraction
1888
2096
  var artwork_1 = __webpack_require__(/*! ./artwork */ "./src/artwork/index.ts");
1889
2097
  Object.defineProperty(exports, "extractArtwork", ({ enumerable: true, get: function () { return artwork_1.extractArtwork; } }));
1890
2098
  Object.defineProperty(exports, "extractArtworkFromDevice", ({ enumerable: true, get: function () { return artwork_1.extractArtworkFromDevice; } }));
1891
2099
  Object.defineProperty(exports, "isArtworkExtractionSupported", ({ enumerable: true, get: function () { return artwork_1.isArtworkExtractionSupported; } }));
1892
2100
  Object.defineProperty(exports, "PictureType", ({ enumerable: true, get: function () { return artwork_1.PictureType; } }));
1893
- // Full metadata extraction (title, artist, album, BPM, key, genre, artwork)
1894
2101
  var metadata_1 = __webpack_require__(/*! ./metadata */ "./src/metadata.ts");
1895
2102
  Object.defineProperty(exports, "extractFullMetadata", ({ enumerable: true, get: function () { return metadata_1.extractFullMetadata; } }));
1896
2103
  Object.defineProperty(exports, "extractMetadataFromDevice", ({ enumerable: true, get: function () { return metadata_1.extractMetadataFromDevice; } }));
1897
2104
  Object.defineProperty(exports, "isMetadataExtractionSupported", ({ enumerable: true, get: function () { return metadata_1.isMetadataExtractionSupported; } }));
1898
- // ANLZ file loading (for analysis data: beat grid, cues, phrases, waveforms)
1899
2105
  var rekordbox_1 = __webpack_require__(/*! ./localdb/rekordbox */ "./src/localdb/rekordbox.ts");
1900
2106
  Object.defineProperty(exports, "loadAnlz", ({ enumerable: true, get: function () { return rekordbox_1.loadAnlz; } }));
1901
2107
  var nfs_1 = __webpack_require__(/*! ./nfs */ "./src/nfs/index.ts");
1902
2108
  Object.defineProperty(exports, "fetchFile", ({ enumerable: true, get: function () { return nfs_1.fetchFile; } }));
1903
2109
  var onelibrary_connect_1 = __webpack_require__(/*! onelibrary-connect */ "onelibrary-connect");
1904
2110
  Object.defineProperty(exports, "OneLibraryAdapter", ({ enumerable: true, get: function () { return onelibrary_connect_1.OneLibraryAdapter; } }));
1905
- // Logger interface for pluggable logging
1906
2111
  var logger_1 = __webpack_require__(/*! ./logger */ "./src/logger.ts");
1907
2112
  Object.defineProperty(exports, "noopLogger", ({ enumerable: true, get: function () { return logger_1.noopLogger; } }));
1908
2113
  // Types are exported last to avoid overwriting values with type-only exports
@@ -6161,8 +6366,8 @@ exports.extractFullMetadata = extractFullMetadata;
6161
6366
  exports.isMetadataExtractionSupported = isMetadataExtractionSupported;
6162
6367
  exports.extractMetadataFromDevice = extractMetadataFromDevice;
6163
6368
  const metadata_connect_1 = __webpack_require__(/*! metadata-connect */ "metadata-connect");
6164
- const nfs_1 = __webpack_require__(/*! ./nfs */ "./src/nfs/index.ts");
6165
6369
  const reader_1 = __webpack_require__(/*! ./artwork/reader */ "./src/artwork/reader.ts");
6370
+ const nfs_1 = __webpack_require__(/*! ./nfs */ "./src/nfs/index.ts");
6166
6371
  /**
6167
6372
  * Extract full metadata from an audio file using a FileReader.
6168
6373
  *
@@ -6653,14 +6858,15 @@ var _ProlinkNetwork_state, _ProlinkNetwork_announceSocket, _ProlinkNetwork_beatS
6653
6858
  Object.defineProperty(exports, "__esModule", ({ value: true }));
6654
6859
  exports.ProlinkNetwork = void 0;
6655
6860
  exports.bringOnline = bringOnline;
6861
+ exports.bringOnlineStagehand = bringOnlineStagehand;
6656
6862
  const crypto_1 = __webpack_require__(/*! crypto */ "crypto");
6657
6863
  const dgram_1 = __importDefault(__webpack_require__(/*! dgram */ "dgram"));
6658
6864
  const constants_1 = __webpack_require__(/*! src/constants */ "./src/constants.ts");
6659
6865
  const control_1 = __importDefault(__webpack_require__(/*! src/control */ "./src/control/index.ts"));
6660
6866
  const db_1 = __importDefault(__webpack_require__(/*! src/db */ "./src/db/index.ts"));
6661
6867
  const devices_1 = __importDefault(__webpack_require__(/*! src/devices */ "./src/devices/index.ts"));
6662
- const logger_1 = __webpack_require__(/*! src/logger */ "./src/logger.ts");
6663
6868
  const localdb_1 = __importDefault(__webpack_require__(/*! src/localdb */ "./src/localdb/index.ts"));
6869
+ const logger_1 = __webpack_require__(/*! src/logger */ "./src/logger.ts");
6664
6870
  const mixstatus_1 = __webpack_require__(/*! src/mixstatus */ "./src/mixstatus/index.ts");
6665
6871
  const remotedb_1 = __importDefault(__webpack_require__(/*! src/remotedb */ "./src/remotedb/index.ts"));
6666
6872
  const status_1 = __importDefault(__webpack_require__(/*! src/status */ "./src/status/index.ts"));
@@ -6715,6 +6921,17 @@ async function bringOnline(config) {
6715
6921
  });
6716
6922
  return network;
6717
6923
  }
6924
+ /**
6925
+ * Brings the Prolink network online using the Pioneer Stagehand connection method.
6926
+ *
6927
+ * This connects to the network as a non-player Stagehand device using its abbreviated handshake.
6928
+ */
6929
+ async function bringOnlineStagehand(config) {
6930
+ return bringOnline({
6931
+ ...config,
6932
+ connectMethod: 'stagehand',
6933
+ });
6934
+ }
6718
6935
  class ProlinkNetwork {
6719
6936
  /**
6720
6937
  * @internal
@@ -6764,6 +6981,7 @@ class ProlinkNetwork {
6764
6981
  * Defaults the Virtual CDJ ID to 7.
6765
6982
  */
6766
6983
  async autoconfigFromPeers() {
6984
+ var _a;
6767
6985
  const tx = Telemetry.startTransaction({ name: 'autoConfigure' });
6768
6986
  // wait for first device to appear on the network
6769
6987
  const firstDevice = await new Promise(resolve => __classPrivateFieldGet(this, _ProlinkNetwork_deviceManager, "f").once('connected', resolve));
@@ -6779,7 +6997,10 @@ class ProlinkNetwork {
6779
6997
  tx.finish();
6780
6998
  throw new Error('Unable to determine network interface');
6781
6999
  }
6782
- __classPrivateFieldSet(this, _ProlinkNetwork_config, { ...__classPrivateFieldGet(this, _ProlinkNetwork_config, "f"), vcdjId: constants_1.DEFAULT_VCDJ_ID, iface }, "f");
7000
+ const defaultId = ((_a = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f")) === null || _a === void 0 ? void 0 : _a.connectMethod) === 'stagehand'
7001
+ ? (0, virtualcdj_1.generateStagehandDeviceId)()
7002
+ : constants_1.DEFAULT_VCDJ_ID;
7003
+ __classPrivateFieldSet(this, _ProlinkNetwork_config, { ...__classPrivateFieldGet(this, _ProlinkNetwork_config, "f"), vcdjId: defaultId, iface }, "f");
6783
7004
  tx.finish();
6784
7005
  }
6785
7006
  /**
@@ -6789,23 +7010,34 @@ class ProlinkNetwork {
6789
7010
  * or manual configuration). This will then initialize all the network services.
6790
7011
  */
6791
7012
  connect() {
6792
- var _a, _b, _c;
7013
+ var _a, _b, _c, _d, _e, _f;
6793
7014
  if (__classPrivateFieldGet(this, _ProlinkNetwork_config, "f") === null) {
6794
7015
  throw new Error(connectErrorHelp);
6795
7016
  }
6796
7017
  const tx = Telemetry.startTransaction({ name: 'connect' });
6797
- // Create VCDJ for the interface's broadcast address
6798
- const vcdj = (0, virtualcdj_1.getVirtualCDJ)(__classPrivateFieldGet(this, _ProlinkNetwork_config, "f").iface, __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjId, __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjName);
6799
- // Update device manager to filter out our VCDJ name
6800
- if (__classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjName !== undefined) {
6801
- __classPrivateFieldGet(this, _ProlinkNetwork_deviceManager, "f").reconfigure({ vcdjName: __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjName });
7018
+ const connectMethod = (_a = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").connectMethod) !== null && _a !== void 0 ? _a : 'active';
7019
+ const vcdjId = (_b = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjId) !== null && _b !== void 0 ? _b : (connectMethod === 'stagehand' ? (0, virtualcdj_1.generateStagehandDeviceId)() : constants_1.DEFAULT_VCDJ_ID);
7020
+ const vcdjName = (_c = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjName) !== null && _c !== void 0 ? _c : (connectMethod === 'stagehand' ? 'Stagehand' : undefined);
7021
+ // Create VCDJ or Stagehand device
7022
+ const vcdj = connectMethod === 'stagehand'
7023
+ ? (0, virtualcdj_1.getVirtualStagehand)(__classPrivateFieldGet(this, _ProlinkNetwork_config, "f").iface, vcdjId, vcdjName)
7024
+ : (0, virtualcdj_1.getVirtualCDJ)(__classPrivateFieldGet(this, _ProlinkNetwork_config, "f").iface, vcdjId, vcdjName);
7025
+ // Update device manager to filter out our device name
7026
+ if (vcdjName !== undefined) {
7027
+ __classPrivateFieldGet(this, _ProlinkNetwork_deviceManager, "f").reconfigure({ vcdjName });
6802
7028
  }
6803
7029
  // Start announcing
6804
- const announcer = new virtualcdj_1.Announcer(vcdj, __classPrivateFieldGet(this, _ProlinkNetwork_announceSocket, "f"), this.deviceManager, __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").iface, (_a = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").fullStartup) !== null && _a !== void 0 ? _a : false, (_b = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").announceToStagehand) !== null && _b !== void 0 ? _b : false, __classPrivateFieldGet(this, _ProlinkNetwork_logger, "f"));
7030
+ let announcer;
7031
+ if (connectMethod === 'stagehand') {
7032
+ announcer = new virtualcdj_1.StagehandAnnouncer(vcdj, __classPrivateFieldGet(this, _ProlinkNetwork_announceSocket, "f"), this.deviceManager, __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").iface, __classPrivateFieldGet(this, _ProlinkNetwork_logger, "f"));
7033
+ }
7034
+ else {
7035
+ announcer = new virtualcdj_1.Announcer(vcdj, __classPrivateFieldGet(this, _ProlinkNetwork_announceSocket, "f"), this.deviceManager, __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").iface, (_d = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").fullStartup) !== null && _d !== void 0 ? _d : false, (_e = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").announceToStagehand) !== null && _e !== void 0 ? _e : false, __classPrivateFieldGet(this, _ProlinkNetwork_logger, "f"));
7036
+ }
6805
7037
  announcer.start();
6806
7038
  // Create remote and local databases
6807
7039
  const remotedb = new remotedb_1.default(__classPrivateFieldGet(this, _ProlinkNetwork_deviceManager, "f"), vcdj);
6808
- const localdb = new localdb_1.default(vcdj, __classPrivateFieldGet(this, _ProlinkNetwork_deviceManager, "f"), __classPrivateFieldGet(this, _ProlinkNetwork_statusEmitter, "f"), (_c = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").databasePreference) !== null && _c !== void 0 ? _c : 'auto');
7040
+ const localdb = new localdb_1.default(vcdj, __classPrivateFieldGet(this, _ProlinkNetwork_deviceManager, "f"), __classPrivateFieldGet(this, _ProlinkNetwork_statusEmitter, "f"), (_f = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").databasePreference) !== null && _f !== void 0 ? _f : 'auto');
6809
7041
  // Create unified database
6810
7042
  const database = new db_1.default(localdb, remotedb, __classPrivateFieldGet(this, _ProlinkNetwork_deviceManager, "f"));
6811
7043
  // Create controller service
@@ -10601,11 +10833,11 @@ exports["default"] = RemoteDatabase;
10601
10833
 
10602
10834
  Object.defineProperty(exports, "__esModule", ({ value: true }));
10603
10835
  exports.Message = void 0;
10604
- const telemetry_1 = __webpack_require__(/*! src/utils/telemetry */ "./src/utils/telemetry.ts");
10605
10836
  const constants_1 = __webpack_require__(/*! src/remotedb/constants */ "./src/remotedb/constants.ts");
10606
10837
  const fields_1 = __webpack_require__(/*! src/remotedb/fields */ "./src/remotedb/fields.ts");
10607
10838
  const response_1 = __webpack_require__(/*! src/remotedb/message/response */ "./src/remotedb/message/response.ts");
10608
10839
  const types_1 = __webpack_require__(/*! src/remotedb/message/types */ "./src/remotedb/message/types.ts");
10840
+ const telemetry_1 = __webpack_require__(/*! src/utils/telemetry */ "./src/utils/telemetry.ts");
10609
10841
  /**
10610
10842
  * Argument types are used in argument list fields. This is essentially
10611
10843
  * duplicating the field type, but has different values for whatever reason.
@@ -11685,6 +11917,13 @@ class StatusEmitter {
11685
11917
  this.off = __classPrivateFieldGet(this, _StatusEmitter_emitter, "f").removeListener.bind(__classPrivateFieldGet(this, _StatusEmitter_emitter, "f"));
11686
11918
  this.once = __classPrivateFieldGet(this, _StatusEmitter_emitter, "f").once.bind(__classPrivateFieldGet(this, _StatusEmitter_emitter, "f"));
11687
11919
  _StatusEmitter_handleStatus.set(this, (message) => {
11920
+ // Stagehand mixer state (type 0x39)
11921
+ if (message.length >= 11 && message[10] === 0x39) {
11922
+ const mixerState = (0, utils_1.mixerStateFromPacket)(message);
11923
+ if (mixerState !== undefined) {
11924
+ return __classPrivateFieldGet(this, _StatusEmitter_emitter, "f").emit('mixerState', mixerState);
11925
+ }
11926
+ }
11688
11927
  const status = (0, utils_1.statusFromPacket)(message);
11689
11928
  if (status !== undefined) {
11690
11929
  return __classPrivateFieldGet(this, _StatusEmitter_emitter, "f").emit('status', status);
@@ -11808,6 +12047,14 @@ class PositionEmitter {
11808
12047
  this.off = __classPrivateFieldGet(this, _PositionEmitter_emitter, "f").removeListener.bind(__classPrivateFieldGet(this, _PositionEmitter_emitter, "f"));
11809
12048
  this.once = __classPrivateFieldGet(this, _PositionEmitter_emitter, "f").once.bind(__classPrivateFieldGet(this, _PositionEmitter_emitter, "f"));
11810
12049
  _PositionEmitter_handlePosition.set(this, (message) => {
12050
+ // Stagehand VU meter (type 0x58)
12051
+ if (message.length >= 11 && message[10] === 0x58) {
12052
+ const vu = (0, utils_1.vuFromPacket)(message);
12053
+ if (vu !== undefined) {
12054
+ __classPrivateFieldGet(this, _PositionEmitter_emitter, "f").emit('vu', vu);
12055
+ return;
12056
+ }
12057
+ }
11811
12058
  const position = (0, utils_1.positionFromPacket)(message);
11812
12059
  if (position !== undefined) {
11813
12060
  __classPrivateFieldGet(this, _PositionEmitter_emitter, "f").emit('position', position);
@@ -11876,6 +12123,8 @@ exports.statusFromPacket = statusFromPacket;
11876
12123
  exports.mediaSlotFromPacket = mediaSlotFromPacket;
11877
12124
  exports.positionFromPacket = positionFromPacket;
11878
12125
  exports.onAirFromPacket = onAirFromPacket;
12126
+ exports.mixerStateFromPacket = mixerStateFromPacket;
12127
+ exports.vuFromPacket = vuFromPacket;
11879
12128
  const constants_1 = __webpack_require__(/*! src/constants */ "./src/constants.ts");
11880
12129
  const types_1 = __webpack_require__(/*! src/types */ "./src/types.ts");
11881
12130
  const MAX_INT32 = Math.pow(2, 32) - 1;
@@ -12058,6 +12307,83 @@ function onAirFromPacket(packet) {
12058
12307
  }
12059
12308
  return undefined;
12060
12309
  }
12310
+ /**
12311
+ * Parse unicast mixer state packet from DJM-A9 (packet type 0x39 on port 50002).
12312
+ */
12313
+ function mixerStateFromPacket(packet) {
12314
+ if (packet.indexOf(constants_1.PROLINK_HEADER) !== 0) {
12315
+ return undefined;
12316
+ }
12317
+ // Verify packet type 0x39
12318
+ if (packet[10] !== 0x39) {
12319
+ return undefined;
12320
+ }
12321
+ if (packet.length < 266) {
12322
+ return undefined;
12323
+ }
12324
+ const deviceName = packet.slice(11, 30).toString().replace(/\0/g, '').trim();
12325
+ const crossfader = packet[180];
12326
+ const channels = {};
12327
+ for (let ch = 1; ch <= 4; ch++) {
12328
+ const offset = 36 + (ch - 1) * 24;
12329
+ let crossfaderAssign = 'thru';
12330
+ const assignVal = packet[offset + 12];
12331
+ if (assignVal === 0x01) {
12332
+ crossfaderAssign = 'A';
12333
+ }
12334
+ else if (assignVal === 0x02) {
12335
+ crossfaderAssign = 'B';
12336
+ }
12337
+ channels[ch] = {
12338
+ trim: packet[offset + 1],
12339
+ eqHi: packet[offset + 3],
12340
+ eqMid: packet[offset + 4],
12341
+ eqLow: packet[offset + 6],
12342
+ colorFx: packet[offset + 7],
12343
+ fader: packet[offset + 11],
12344
+ crossfaderAssign,
12345
+ };
12346
+ }
12347
+ return {
12348
+ deviceId: 33, // Mixers are typically device 33 on ProDJLink
12349
+ deviceName,
12350
+ channels,
12351
+ crossfader,
12352
+ };
12353
+ }
12354
+ /**
12355
+ * Parse unicast VU meter packet from DJM-A9 (packet type 0x58 on port 50001).
12356
+ * Contains 15 sample-tuples (16-bit BE left/right levels) per channel.
12357
+ */
12358
+ function vuFromPacket(packet) {
12359
+ if (packet.indexOf(constants_1.PROLINK_HEADER) !== 0) {
12360
+ return undefined;
12361
+ }
12362
+ // Verify packet type 0x58
12363
+ if (packet[10] !== 0x58) {
12364
+ return undefined;
12365
+ }
12366
+ if (packet.length < 584) {
12367
+ return undefined;
12368
+ }
12369
+ const channels = {};
12370
+ for (let ch = 1; ch <= 4; ch++) {
12371
+ const chOffset = 44 + (ch - 1) * 60; // 15 frames * 4 bytes per frame = 60 bytes
12372
+ const frames = [];
12373
+ for (let i = 0; i < 15; i++) {
12374
+ const frameOffset = chOffset + i * 4;
12375
+ frames.push({
12376
+ left: packet.readUInt16BE(frameOffset),
12377
+ right: packet.readUInt16BE(frameOffset + 2),
12378
+ });
12379
+ }
12380
+ channels[ch] = frames;
12381
+ }
12382
+ return {
12383
+ deviceId: 33, // Mixers are typically device 33 on ProDJLink
12384
+ channels,
12385
+ };
12386
+ }
12061
12387
 
12062
12388
 
12063
12389
  /***/ },
@@ -12114,6 +12440,7 @@ var DeviceType;
12114
12440
  DeviceType[DeviceType["CDJ"] = 1] = "CDJ";
12115
12441
  DeviceType[DeviceType["Mixer"] = 3] = "Mixer";
12116
12442
  DeviceType[DeviceType["Rekordbox"] = 4] = "Rekordbox";
12443
+ DeviceType[DeviceType["Stagehand"] = 5] = "Stagehand";
12117
12444
  })(DeviceType || (exports.DeviceType = DeviceType = {}));
12118
12445
  var MediaColor;
12119
12446
  (function (MediaColor) {
@@ -12154,9 +12481,6 @@ var TrackType;
12154
12481
  TrackType[TrackType["AudioCD"] = 5] = "AudioCD";
12155
12482
  TrackType[TrackType["Streaming"] = 6] = "Streaming";
12156
12483
  })(TrackType || (exports.TrackType = TrackType = {}));
12157
- /**
12158
- * Re-export cue types from onelibrary-connect
12159
- */
12160
12484
  var onelibrary_connect_1 = __webpack_require__(/*! onelibrary-connect */ "onelibrary-connect");
12161
12485
  Object.defineProperty(exports, "CueColor", ({ enumerable: true, get: function () { return onelibrary_connect_1.CueColor; } }));
12162
12486
  Object.defineProperty(exports, "HotcueButton", ({ enumerable: true, get: function () { return onelibrary_connect_1.HotcueButton; } }));
@@ -12613,6 +12937,9 @@ var __importStar = (this && this.__importStar) || (function () {
12613
12937
  return result;
12614
12938
  };
12615
12939
  })();
12940
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
12941
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
12942
+ };
12616
12943
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
12617
12944
  if (kind === "m") throw new TypeError("Private method is not writable");
12618
12945
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
@@ -13105,6 +13432,271 @@ _Announcer_announceSocket = new WeakMap(), _Announcer_deviceManager = new WeakMa
13105
13432
  // Then schedule regular keep-alives
13106
13433
  __classPrivateFieldSet(this, _Announcer_intervalHandle, setInterval(sendKeepAlive, constants_1.ANNOUNCE_INTERVAL), "f");
13107
13434
  };
13435
+ __exportStar(__webpack_require__(/*! ./stagehand */ "./src/virtualcdj/stagehand.ts"), exports);
13436
+
13437
+
13438
+ /***/ },
13439
+
13440
+ /***/ "./src/virtualcdj/stagehand.ts"
13441
+ /*!*************************************!*\
13442
+ !*** ./src/virtualcdj/stagehand.ts ***!
13443
+ \*************************************/
13444
+ (__unused_webpack_module, exports, __webpack_require__) {
13445
+
13446
+ "use strict";
13447
+
13448
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13449
+ if (k2 === undefined) k2 = k;
13450
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13451
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13452
+ desc = { enumerable: true, get: function() { return m[k]; } };
13453
+ }
13454
+ Object.defineProperty(o, k2, desc);
13455
+ }) : (function(o, m, k, k2) {
13456
+ if (k2 === undefined) k2 = k;
13457
+ o[k2] = m[k];
13458
+ }));
13459
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
13460
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
13461
+ }) : function(o, v) {
13462
+ o["default"] = v;
13463
+ });
13464
+ var __importStar = (this && this.__importStar) || (function () {
13465
+ var ownKeys = function(o) {
13466
+ ownKeys = Object.getOwnPropertyNames || function (o) {
13467
+ var ar = [];
13468
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
13469
+ return ar;
13470
+ };
13471
+ return ownKeys(o);
13472
+ };
13473
+ return function (mod) {
13474
+ if (mod && mod.__esModule) return mod;
13475
+ var result = {};
13476
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
13477
+ __setModuleDefault(result, mod);
13478
+ return result;
13479
+ };
13480
+ })();
13481
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
13482
+ if (kind === "m") throw new TypeError("Private method is not writable");
13483
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
13484
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
13485
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
13486
+ };
13487
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
13488
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
13489
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
13490
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
13491
+ };
13492
+ var _StagehandAnnouncer_instances, _StagehandAnnouncer_announceSocket, _StagehandAnnouncer_vcdj, _StagehandAnnouncer_intervalHandle, _StagehandAnnouncer_currentStage, _StagehandAnnouncer_stageCounter, _StagehandAnnouncer_iface, _StagehandAnnouncer_logger, _StagehandAnnouncer_onStartupComplete, _StagehandAnnouncer_mac, _StagehandAnnouncer_startStartup, _StagehandAnnouncer_sendPacket, _StagehandAnnouncer_sendStagePackets, _StagehandAnnouncer_advanceStage, _StagehandAnnouncer_startKeepAlive;
13493
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
13494
+ exports.StagehandAnnouncer = exports.getVirtualStagehand = exports.StagehandStartupStage = exports.STAGEHAND_KEEP_ALIVE_INTERVAL = exports.STAGEHAND_STARTUP_INTERVAL = void 0;
13495
+ exports.generateStagehandMac = generateStagehandMac;
13496
+ exports.generateStagehandDeviceId = generateStagehandDeviceId;
13497
+ exports.makeStagehand0aPacket = makeStagehand0aPacket;
13498
+ exports.makeStagehand02Packet = makeStagehand02Packet;
13499
+ exports.makeStagehand06Packet = makeStagehand06Packet;
13500
+ const ip = __importStar(__webpack_require__(/*! ip-address */ "ip-address"));
13501
+ const constants_1 = __webpack_require__(/*! src/constants */ "./src/constants.ts");
13502
+ const logger_1 = __webpack_require__(/*! src/logger */ "./src/logger.ts");
13503
+ const types_1 = __webpack_require__(/*! src/types */ "./src/types.ts");
13504
+ const utils_1 = __webpack_require__(/*! src/utils */ "./src/utils/index.ts");
13505
+ exports.STAGEHAND_STARTUP_INTERVAL = 305;
13506
+ exports.STAGEHAND_KEEP_ALIVE_INTERVAL = 2000;
13507
+ var StagehandStartupStage;
13508
+ (function (StagehandStartupStage) {
13509
+ StagehandStartupStage[StagehandStartupStage["InitialAnnounce"] = 10] = "InitialAnnounce";
13510
+ StagehandStartupStage[StagehandStartupStage["SecondStageClaim"] = 2] = "SecondStageClaim";
13511
+ StagehandStartupStage[StagehandStartupStage["KeepAlive"] = 6] = "KeepAlive";
13512
+ })(StagehandStartupStage || (exports.StagehandStartupStage = StagehandStartupStage = {}));
13513
+ /**
13514
+ * Generates a randomized MAC address with the AlphaTheta OUI (c8:3d:fc).
13515
+ */
13516
+ function generateStagehandMac() {
13517
+ const mac = new Uint8Array(6);
13518
+ mac[0] = 0xc8;
13519
+ mac[1] = 0x3d;
13520
+ mac[2] = 0xfc;
13521
+ mac[3] = Math.floor(Math.random() * 256);
13522
+ mac[4] = Math.floor(Math.random() * 256);
13523
+ mac[5] = Math.floor(Math.random() * 256);
13524
+ return mac;
13525
+ }
13526
+ /**
13527
+ * Generates a random Stagehand device ID in the observed range of 141 to 211.
13528
+ */
13529
+ function generateStagehandDeviceId() {
13530
+ return Math.floor(Math.random() * (211 - 141 + 1)) + 141;
13531
+ }
13532
+ /**
13533
+ * Constructs a virtual Stagehand Device.
13534
+ *
13535
+ * @param iface - The network interface to use
13536
+ * @param id - The device ID to use (defaults to random Stagehand ID)
13537
+ * @param name - The device name (defaults to 'Stagehand')
13538
+ * @param macAddr - The optional randomized MAC address
13539
+ */
13540
+ const getVirtualStagehand = (iface, id = generateStagehandDeviceId(), name = 'Stagehand', macAddr = generateStagehandMac()) => ({
13541
+ id,
13542
+ name,
13543
+ type: types_1.DeviceType.Stagehand,
13544
+ ip: new ip.Address4(iface.address),
13545
+ macAddr,
13546
+ });
13547
+ exports.getVirtualStagehand = getVirtualStagehand;
13548
+ /**
13549
+ * Build Stagehand stage 0x0a packet: Initial announcement.
13550
+ * Sent 3 times at 305ms intervals.
13551
+ */
13552
+ function makeStagehand0aPacket(device) {
13553
+ const parts = [
13554
+ ...constants_1.PROLINK_HEADER, // 10 bytes
13555
+ ...[0x0a, 0x00], // 2 bytes packet type (0x0a)
13556
+ ...(0, utils_1.buildName)(device), // 20 bytes device name
13557
+ ...[0x01, 0x03], // 2 bytes protocol / structure bytes
13558
+ ...[0x00, 0x25], // 2 bytes packet length (37)
13559
+ ...[types_1.DeviceType.Stagehand], // 1 byte device type (0x05)
13560
+ ];
13561
+ return Uint8Array.from(parts);
13562
+ }
13563
+ /**
13564
+ * Build Stagehand stage 0x02 packet: Second-stage device number claim.
13565
+ * Sent 3 times at 305ms intervals with counter N (1, 2, 3).
13566
+ */
13567
+ function makeStagehand02Packet(device, mac, counter) {
13568
+ const parts = [
13569
+ ...constants_1.PROLINK_HEADER, // 10 bytes
13570
+ ...[0x02, 0x00], // 2 bytes packet type (0x02)
13571
+ ...(0, utils_1.buildName)(device), // 20 bytes device name
13572
+ ...[0x01, 0x03], // 2 bytes protocol / structure bytes
13573
+ ...[0x00, 0x32], // 2 bytes packet length (50)
13574
+ ...device.ip.toArray(), // 4 bytes IP
13575
+ ...mac, // 6 bytes identifier
13576
+ ...[0x3a], // 1 byte constant
13577
+ ...[counter], // 1 byte counter
13578
+ ...[types_1.DeviceType.Stagehand], // 1 byte device type (0x05)
13579
+ ...[0x01], // 1 byte constant
13580
+ ];
13581
+ return Uint8Array.from(parts);
13582
+ }
13583
+ /**
13584
+ * Build Stagehand stage 0x06 packet: Keep-alive.
13585
+ * Sent every 2.0s after startup complete.
13586
+ */
13587
+ function makeStagehand06Packet(device, mac) {
13588
+ const parts = [
13589
+ ...constants_1.PROLINK_HEADER, // 10 bytes
13590
+ ...[0x06, 0x00], // 2 bytes packet type (0x06)
13591
+ ...(0, utils_1.buildName)(device), // 20 bytes device name
13592
+ ...[0x01, 0x03], // 2 bytes protocol / structure bytes
13593
+ ...[0x00, 0x36], // 2 bytes packet length (54)
13594
+ ...[device.id], // 1 byte device number
13595
+ ...[0x01], // 1 byte constant
13596
+ ...mac, // 6 bytes identifier
13597
+ ...device.ip.toArray(), // 4 bytes IP
13598
+ ...[0x01, 0x00, 0x00, 0x00], // 4 bytes constant
13599
+ ...[types_1.DeviceType.Stagehand], // 1 byte device-type (0x05)
13600
+ ...[0x20], // 1 byte trailing byte
13601
+ ];
13602
+ return Uint8Array.from(parts);
13603
+ }
13604
+ class StagehandAnnouncer {
13605
+ constructor(vcdj, announceSocket, deviceManager, iface, logger = logger_1.noopLogger) {
13606
+ _StagehandAnnouncer_instances.add(this);
13607
+ _StagehandAnnouncer_announceSocket.set(this, void 0);
13608
+ _StagehandAnnouncer_vcdj.set(this, void 0);
13609
+ _StagehandAnnouncer_intervalHandle.set(this, void 0);
13610
+ _StagehandAnnouncer_currentStage.set(this, StagehandStartupStage.InitialAnnounce);
13611
+ _StagehandAnnouncer_stageCounter.set(this, 0);
13612
+ _StagehandAnnouncer_iface.set(this, void 0);
13613
+ _StagehandAnnouncer_logger.set(this, void 0);
13614
+ _StagehandAnnouncer_onStartupComplete.set(this, void 0);
13615
+ _StagehandAnnouncer_mac.set(this, void 0);
13616
+ __classPrivateFieldSet(this, _StagehandAnnouncer_vcdj, vcdj, "f");
13617
+ __classPrivateFieldSet(this, _StagehandAnnouncer_announceSocket, announceSocket, "f");
13618
+ __classPrivateFieldSet(this, _StagehandAnnouncer_iface, iface, "f");
13619
+ __classPrivateFieldSet(this, _StagehandAnnouncer_logger, logger, "f");
13620
+ __classPrivateFieldSet(this, _StagehandAnnouncer_mac, vcdj.macAddr, "f");
13621
+ }
13622
+ get ready() {
13623
+ if (__classPrivateFieldGet(this, _StagehandAnnouncer_currentStage, "f") === StagehandStartupStage.KeepAlive) {
13624
+ return Promise.resolve();
13625
+ }
13626
+ return new Promise(resolve => {
13627
+ __classPrivateFieldSet(this, _StagehandAnnouncer_onStartupComplete, resolve, "f");
13628
+ });
13629
+ }
13630
+ start() {
13631
+ __classPrivateFieldGet(this, _StagehandAnnouncer_logger, "f").info(`Starting Stagehand announcer: device name "${__classPrivateFieldGet(this, _StagehandAnnouncer_vcdj, "f").name}", ID ${__classPrivateFieldGet(this, _StagehandAnnouncer_vcdj, "f").id}`);
13632
+ __classPrivateFieldGet(this, _StagehandAnnouncer_instances, "m", _StagehandAnnouncer_startStartup).call(this);
13633
+ }
13634
+ stop() {
13635
+ __classPrivateFieldGet(this, _StagehandAnnouncer_logger, "f").info('Stopping Stagehand announcer');
13636
+ if (__classPrivateFieldGet(this, _StagehandAnnouncer_intervalHandle, "f") !== undefined) {
13637
+ clearInterval(__classPrivateFieldGet(this, _StagehandAnnouncer_intervalHandle, "f"));
13638
+ clearTimeout(__classPrivateFieldGet(this, _StagehandAnnouncer_intervalHandle, "f"));
13639
+ __classPrivateFieldSet(this, _StagehandAnnouncer_intervalHandle, undefined, "f");
13640
+ }
13641
+ }
13642
+ }
13643
+ exports.StagehandAnnouncer = StagehandAnnouncer;
13644
+ _StagehandAnnouncer_announceSocket = new WeakMap(), _StagehandAnnouncer_vcdj = new WeakMap(), _StagehandAnnouncer_intervalHandle = new WeakMap(), _StagehandAnnouncer_currentStage = new WeakMap(), _StagehandAnnouncer_stageCounter = new WeakMap(), _StagehandAnnouncer_iface = new WeakMap(), _StagehandAnnouncer_logger = new WeakMap(), _StagehandAnnouncer_onStartupComplete = new WeakMap(), _StagehandAnnouncer_mac = new WeakMap(), _StagehandAnnouncer_instances = new WeakSet(), _StagehandAnnouncer_startStartup = function _StagehandAnnouncer_startStartup() {
13645
+ __classPrivateFieldSet(this, _StagehandAnnouncer_currentStage, StagehandStartupStage.InitialAnnounce, "f");
13646
+ __classPrivateFieldSet(this, _StagehandAnnouncer_stageCounter, 0, "f");
13647
+ __classPrivateFieldGet(this, _StagehandAnnouncer_instances, "m", _StagehandAnnouncer_sendStagePackets).call(this);
13648
+ }, _StagehandAnnouncer_sendPacket = function _StagehandAnnouncer_sendPacket(packet) {
13649
+ const broadcastAddr = (0, utils_1.getBroadcastAddress)(__classPrivateFieldGet(this, _StagehandAnnouncer_iface, "f"));
13650
+ __classPrivateFieldGet(this, _StagehandAnnouncer_announceSocket, "f").send(packet, constants_1.ANNOUNCE_PORT, broadcastAddr);
13651
+ }, _StagehandAnnouncer_sendStagePackets = function _StagehandAnnouncer_sendStagePackets() {
13652
+ var _a;
13653
+ var _b;
13654
+ __classPrivateFieldSet(this, _StagehandAnnouncer_stageCounter, (_b = __classPrivateFieldGet(this, _StagehandAnnouncer_stageCounter, "f"), _b++, _b), "f");
13655
+ let packet;
13656
+ switch (__classPrivateFieldGet(this, _StagehandAnnouncer_currentStage, "f")) {
13657
+ case StagehandStartupStage.InitialAnnounce:
13658
+ packet = makeStagehand0aPacket(__classPrivateFieldGet(this, _StagehandAnnouncer_vcdj, "f"));
13659
+ __classPrivateFieldGet(this, _StagehandAnnouncer_logger, "f").debug(`Stagehand sending stage 0x0a (announce) packet ${__classPrivateFieldGet(this, _StagehandAnnouncer_stageCounter, "f")}/3`);
13660
+ break;
13661
+ case StagehandStartupStage.SecondStageClaim:
13662
+ packet = makeStagehand02Packet(__classPrivateFieldGet(this, _StagehandAnnouncer_vcdj, "f"), __classPrivateFieldGet(this, _StagehandAnnouncer_mac, "f"), __classPrivateFieldGet(this, _StagehandAnnouncer_stageCounter, "f"));
13663
+ __classPrivateFieldGet(this, _StagehandAnnouncer_logger, "f").debug(`Stagehand sending stage 0x02 (claim) packet ${__classPrivateFieldGet(this, _StagehandAnnouncer_stageCounter, "f")}/3`);
13664
+ break;
13665
+ case StagehandStartupStage.KeepAlive:
13666
+ __classPrivateFieldGet(this, _StagehandAnnouncer_logger, "f").info('Stagehand join sequence complete, transitioning to keep-alive');
13667
+ __classPrivateFieldGet(this, _StagehandAnnouncer_instances, "m", _StagehandAnnouncer_startKeepAlive).call(this);
13668
+ (_a = __classPrivateFieldGet(this, _StagehandAnnouncer_onStartupComplete, "f")) === null || _a === void 0 ? void 0 : _a.call(this);
13669
+ __classPrivateFieldSet(this, _StagehandAnnouncer_onStartupComplete, undefined, "f");
13670
+ return;
13671
+ }
13672
+ __classPrivateFieldGet(this, _StagehandAnnouncer_instances, "m", _StagehandAnnouncer_sendPacket).call(this, packet);
13673
+ if (__classPrivateFieldGet(this, _StagehandAnnouncer_stageCounter, "f") >= 3) {
13674
+ __classPrivateFieldGet(this, _StagehandAnnouncer_instances, "m", _StagehandAnnouncer_advanceStage).call(this);
13675
+ }
13676
+ __classPrivateFieldSet(this, _StagehandAnnouncer_intervalHandle, setTimeout(() => __classPrivateFieldGet(this, _StagehandAnnouncer_instances, "m", _StagehandAnnouncer_sendStagePackets).call(this), exports.STAGEHAND_STARTUP_INTERVAL), "f");
13677
+ }, _StagehandAnnouncer_advanceStage = function _StagehandAnnouncer_advanceStage() {
13678
+ __classPrivateFieldSet(this, _StagehandAnnouncer_stageCounter, 0, "f");
13679
+ switch (__classPrivateFieldGet(this, _StagehandAnnouncer_currentStage, "f")) {
13680
+ case StagehandStartupStage.InitialAnnounce:
13681
+ __classPrivateFieldSet(this, _StagehandAnnouncer_currentStage, StagehandStartupStage.SecondStageClaim, "f");
13682
+ break;
13683
+ case StagehandStartupStage.SecondStageClaim:
13684
+ __classPrivateFieldSet(this, _StagehandAnnouncer_currentStage, StagehandStartupStage.KeepAlive, "f");
13685
+ break;
13686
+ }
13687
+ }, _StagehandAnnouncer_startKeepAlive = function _StagehandAnnouncer_startKeepAlive() {
13688
+ if (__classPrivateFieldGet(this, _StagehandAnnouncer_intervalHandle, "f")) {
13689
+ clearTimeout(__classPrivateFieldGet(this, _StagehandAnnouncer_intervalHandle, "f"));
13690
+ __classPrivateFieldSet(this, _StagehandAnnouncer_intervalHandle, undefined, "f");
13691
+ }
13692
+ const sendKeepAlive = () => {
13693
+ const packet = makeStagehand06Packet(__classPrivateFieldGet(this, _StagehandAnnouncer_vcdj, "f"), __classPrivateFieldGet(this, _StagehandAnnouncer_mac, "f"));
13694
+ __classPrivateFieldGet(this, _StagehandAnnouncer_logger, "f").debug('Stagehand sending keep-alive packet');
13695
+ __classPrivateFieldGet(this, _StagehandAnnouncer_instances, "m", _StagehandAnnouncer_sendPacket).call(this, packet);
13696
+ };
13697
+ sendKeepAlive();
13698
+ __classPrivateFieldSet(this, _StagehandAnnouncer_intervalHandle, setInterval(sendKeepAlive, exports.STAGEHAND_KEEP_ALIVE_INTERVAL), "f");
13699
+ };
13108
13700
 
13109
13701
 
13110
13702
  /***/ },