@lox-audioserver/node-airplay-sender 0.4.5 → 0.4.7

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.
@@ -36,10 +36,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- const elliptic = require('elliptic');
40
39
  const crypto_1 = __importDefault(require("crypto"));
41
40
  const ed = __importStar(require("@noble/ed25519"));
42
41
  const util_1 = require("../utils/util");
42
+ if (!ed.utils.sha512Sync) {
43
+ ed.utils.sha512Sync = (...messages) => {
44
+ const hash = crypto_1.default.createHash('sha512');
45
+ for (const message of messages) {
46
+ hash.update(message);
47
+ }
48
+ return new Uint8Array(hash.digest());
49
+ };
50
+ }
43
51
  // ...
44
52
  // Note: All functions expect parameters to be hex strings.
45
53
  function pair_setup_aes_key(K) {
@@ -75,7 +83,8 @@ function pair_verify_aes_iv(shared) {
75
83
  // ...
76
84
  // Public.
77
85
  function a_pub(a) {
78
- return elliptic.utils.toHex(new elliptic.eddsa('ed25519').keyFromSecret(a).getPublic());
86
+ const publicKey = ed.sync.getPublicKey((0, util_1.hexString2ArrayBuffer)(a));
87
+ return (0, util_1.buf2hex)(publicKey);
79
88
  }
80
89
  function confirm(a, K) {
81
90
  const key = pair_setup_aes_key(K);
@@ -107,8 +116,9 @@ function shared(v_pri, atv_pub) {
107
116
  return (0, util_1.buf2hex)(Buffer.from(ed.curve25519.scalarMult((0, util_1.hexString2ArrayBuffer)(v_pri), (0, util_1.hexString2ArrayBuffer)(atv_pub))));
108
117
  }
109
118
  function signed(a, v_pub, atv_pub) {
110
- const key = new elliptic.eddsa('ed25519').keyFromSecret(a);
111
- return key.sign(v_pub + atv_pub).toHex();
119
+ const message = (0, util_1.hexString2ArrayBuffer)(v_pub + atv_pub);
120
+ const signature = ed.sync.sign(message, (0, util_1.hexString2ArrayBuffer)(a));
121
+ return (0, util_1.buf2hex)(signature);
112
122
  }
113
123
  function signature(shared, atv_data, signed) {
114
124
  const cipher = crypto_1.default.createCipheriv('aes-128-ctr', (0, util_1.hexString2ArrayBuffer)(pair_verify_aes_key(shared)), (0, util_1.hexString2ArrayBuffer)(pair_verify_aes_iv(shared)));
@@ -297,8 +297,7 @@ AirTunesDevice.prototype.doHandshake = function () {
297
297
  this.rtsp.on('ready', () => {
298
298
  this.status = 'playing';
299
299
  this.emit('status', 'playing');
300
- if (this.airplay2)
301
- this.relayAudio();
300
+ this.relayAudio();
302
301
  });
303
302
  this.rtsp.on('need_password', () => {
304
303
  this.emit('status', 'need_password');
@@ -328,6 +327,9 @@ AirTunesDevice.prototype.doHandshake = function () {
328
327
  AirTunesDevice.prototype.relayAudio = function () {
329
328
  this.status = 'ready';
330
329
  this.emit('status', 'ready');
330
+ let packetCount = 0;
331
+ let byteCount = 0;
332
+ let lastLogAt = 0;
331
333
  this.audioCallback = (packet) => {
332
334
  const airTunes = makeAirTunesPacket(packet, this.encoder, this.requireEncryption, this.alacEncoding, this.credentials, this.inputCodec);
333
335
  // if (self.credentials) {
@@ -335,8 +337,37 @@ AirTunesDevice.prototype.relayAudio = function () {
335
337
  // }
336
338
  if (this.audioSocket == null) {
337
339
  this.audioSocket = node_dgram_1.default.createSocket('udp4');
340
+ this.audioSocket.on('error', (err) => {
341
+ this.logLine?.('audio socket error', {
342
+ host: this.host,
343
+ port: this.serverPort,
344
+ message: err instanceof Error ? err.message : String(err),
345
+ });
346
+ });
347
+ }
348
+ this.audioSocket.send(airTunes, 0, airTunes.length, this.serverPort, this.host, (err) => {
349
+ if (err) {
350
+ this.logLine?.('audio packet send failed', {
351
+ host: this.host,
352
+ port: this.serverPort,
353
+ message: err instanceof Error ? err.message : String(err),
354
+ });
355
+ }
356
+ });
357
+ packetCount += 1;
358
+ byteCount += airTunes.length;
359
+ const now = Date.now();
360
+ if (now - lastLogAt > 5000) {
361
+ lastLogAt = now;
362
+ if (this.options?.debug) {
363
+ this.logLine?.('audio packet send stats', {
364
+ host: this.host,
365
+ port: this.serverPort,
366
+ packets: packetCount,
367
+ bytes: byteCount,
368
+ });
369
+ }
338
370
  }
339
- this.audioSocket.send(airTunes, 0, airTunes.length, this.serverPort, this.host);
340
371
  };
341
372
  // this.sendAirTunesPacket = function(airTunes) {
342
373
  // try{
@@ -36,10 +36,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- const elliptic = require('elliptic');
40
39
  const crypto_1 = __importDefault(require("crypto"));
41
40
  const ed = __importStar(require("@noble/ed25519"));
42
41
  const util_1 = require("../utils/util");
42
+ if (!ed.utils.sha512Sync) {
43
+ ed.utils.sha512Sync = (...messages) => {
44
+ const hash = crypto_1.default.createHash('sha512');
45
+ for (const message of messages) {
46
+ hash.update(message);
47
+ }
48
+ return new Uint8Array(hash.digest());
49
+ };
50
+ }
43
51
  // ...
44
52
  // Note: All functions expect parameters to be hex strings.
45
53
  function pair_setup_aes_key(K) {
@@ -75,7 +83,8 @@ function pair_verify_aes_iv(shared) {
75
83
  // ...
76
84
  // Public.
77
85
  function a_pub(a) {
78
- return elliptic.utils.toHex(new elliptic.eddsa('ed25519').keyFromSecret(a).getPublic());
86
+ const publicKey = ed.sync.getPublicKey((0, util_1.hexString2ArrayBuffer)(a));
87
+ return (0, util_1.buf2hex)(publicKey);
79
88
  }
80
89
  function confirm(a, K) {
81
90
  const key = pair_setup_aes_key(K);
@@ -107,8 +116,9 @@ function shared(v_pri, atv_pub) {
107
116
  return (0, util_1.buf2hex)(Buffer.from(ed.curve25519.scalarMult((0, util_1.hexString2ArrayBuffer)(v_pri), (0, util_1.hexString2ArrayBuffer)(atv_pub))));
108
117
  }
109
118
  function signed(a, v_pub, atv_pub) {
110
- const key = new elliptic.eddsa('ed25519').keyFromSecret(a);
111
- return key.sign(v_pub + atv_pub).toHex();
119
+ const message = (0, util_1.hexString2ArrayBuffer)(v_pub + atv_pub);
120
+ const signature = ed.sync.sign(message, (0, util_1.hexString2ArrayBuffer)(a));
121
+ return (0, util_1.buf2hex)(signature);
112
122
  }
113
123
  function signature(shared, atv_data, signed) {
114
124
  const cipher = crypto_1.default.createCipheriv('aes-128-ctr', (0, util_1.hexString2ArrayBuffer)(pair_verify_aes_key(shared)), (0, util_1.hexString2ArrayBuffer)(pair_verify_aes_iv(shared)));
@@ -297,8 +297,7 @@ AirTunesDevice.prototype.doHandshake = function () {
297
297
  this.rtsp.on('ready', () => {
298
298
  this.status = 'playing';
299
299
  this.emit('status', 'playing');
300
- if (this.airplay2)
301
- this.relayAudio();
300
+ this.relayAudio();
302
301
  });
303
302
  this.rtsp.on('need_password', () => {
304
303
  this.emit('status', 'need_password');
@@ -328,6 +327,9 @@ AirTunesDevice.prototype.doHandshake = function () {
328
327
  AirTunesDevice.prototype.relayAudio = function () {
329
328
  this.status = 'ready';
330
329
  this.emit('status', 'ready');
330
+ let packetCount = 0;
331
+ let byteCount = 0;
332
+ let lastLogAt = 0;
331
333
  this.audioCallback = (packet) => {
332
334
  const airTunes = makeAirTunesPacket(packet, this.encoder, this.requireEncryption, this.alacEncoding, this.credentials, this.inputCodec);
333
335
  // if (self.credentials) {
@@ -335,8 +337,37 @@ AirTunesDevice.prototype.relayAudio = function () {
335
337
  // }
336
338
  if (this.audioSocket == null) {
337
339
  this.audioSocket = node_dgram_1.default.createSocket('udp4');
340
+ this.audioSocket.on('error', (err) => {
341
+ this.logLine?.('audio socket error', {
342
+ host: this.host,
343
+ port: this.serverPort,
344
+ message: err instanceof Error ? err.message : String(err),
345
+ });
346
+ });
347
+ }
348
+ this.audioSocket.send(airTunes, 0, airTunes.length, this.serverPort, this.host, (err) => {
349
+ if (err) {
350
+ this.logLine?.('audio packet send failed', {
351
+ host: this.host,
352
+ port: this.serverPort,
353
+ message: err instanceof Error ? err.message : String(err),
354
+ });
355
+ }
356
+ });
357
+ packetCount += 1;
358
+ byteCount += airTunes.length;
359
+ const now = Date.now();
360
+ if (now - lastLogAt > 5000) {
361
+ lastLogAt = now;
362
+ if (this.options?.debug) {
363
+ this.logLine?.('audio packet send stats', {
364
+ host: this.host,
365
+ port: this.serverPort,
366
+ packets: packetCount,
367
+ bytes: byteCount,
368
+ });
369
+ }
338
370
  }
339
- this.audioSocket.send(airTunes, 0, airTunes.length, this.serverPort, this.host);
340
371
  };
341
372
  // this.sendAirTunesPacket = function(airTunes) {
342
373
  // try{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lox-audioserver/node-airplay-sender",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "description": "AirPlay sender (RAOP/AirPlay 1; AirPlay 2 control/auth, best-effort audio)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -52,11 +52,10 @@
52
52
  "bplist-parser": "^0.3.2",
53
53
  "crypto-js": "^4.2.0",
54
54
  "curve25519-js": "^0.0.4",
55
- "elliptic": "^6.5.5",
56
55
  "fast-srp-hap": "^2.0.4",
57
56
  "js-crypto-aes": "^1.0.6",
58
57
  "js-sha1": "^0.7.0",
59
- "lodash": "^4.17.21",
58
+ "lodash": "^4.17.23",
60
59
  "parse-raw-http": "0.0.1",
61
60
  "python-struct": "^1.1.3",
62
61
  "simple-plist": "^1.4.0",