lox-airplay-sender 0.2.1 → 0.3.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/README.md CHANGED
@@ -57,6 +57,7 @@ Creates and starts a sender for one AirPlay device. Returns the instance so you
57
57
  - `startTimeMs` (number) Unix ms to align playback across devices.
58
58
  - `debug` (boolean) Verbose logging from the transport stack.
59
59
  - `log` `(level, message, data?) => void` Hook for library logs.
60
+ - `config` (partial) Override buffer/sync/RTSP tuning at runtime (see `src/utils/config.ts` for keys like `packets_in_buffer`, `stream_latency`, `sync_period`, retry/backoff, etc.).
60
61
 
61
62
  **Events** (sent to `onEvent` callback)
62
63
  - `device`: `{ event: "device", message: status, detail: { key, desc } }`
@@ -82,4 +83,4 @@ Use `startTimeMs` to align multiple senders to the same start clock (Unix ms). F
82
83
  npm install
83
84
  npm run build
84
85
  npm run clean # remove dist
85
- ```
86
+ ```
@@ -1,5 +1,6 @@
1
1
  import { Duplex } from 'node:stream';
2
2
  import Devices from './devices';
3
+ import { type AirplayConfig } from '../utils/config';
3
4
  /**
4
5
  * High-level RAOP/AirPlay sender that wires together devices, buffering, and output.
5
6
  * Acts as a Duplex stream: write PCM/ALAC chunks, listen to status events.
@@ -14,6 +15,7 @@ declare class AirTunes extends Duplex {
14
15
  constructor(options?: {
15
16
  packetSize?: number;
16
17
  startTimeMs?: number;
18
+ config?: Partial<AirplayConfig>;
17
19
  });
18
20
  /** Register an AirTunes (RAOP) device and start streaming to it. */
19
21
  add(host: string, options: Record<string, unknown>, mode?: number, txt?: string[] | string): any;
@@ -1,11 +1,44 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  const node_stream_1 = require("node:stream");
7
40
  const devices_1 = __importDefault(require("./devices"));
8
- const config_1 = __importDefault(require("../utils/config"));
41
+ const config_1 = __importStar(require("../utils/config"));
9
42
  const circularBuffer_1 = __importDefault(require("../utils/circularBuffer"));
10
43
  const audioOut_1 = __importDefault(require("./audioOut"));
11
44
  /**
@@ -21,6 +54,9 @@ class AirTunes extends node_stream_1.Duplex {
21
54
  */
22
55
  constructor(options = {}) {
23
56
  super({ readableObjectMode: false, writableObjectMode: false });
57
+ if (options.config) {
58
+ (0, config_1.applyConfig)(options.config);
59
+ }
24
60
  const audioOut = new audioOut_1.default();
25
61
  this.devices = new devices_1.default(audioOut);
26
62
  this.devices.init();
@@ -1,11 +1,44 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  const node_stream_1 = require("node:stream");
7
40
  const devices_1 = __importDefault(require("./devices"));
8
- const config_1 = __importDefault(require("../utils/config"));
41
+ const config_1 = __importStar(require("../utils/config"));
9
42
  const circularBuffer_1 = __importDefault(require("../utils/circularBuffer"));
10
43
  const audioOut_1 = __importDefault(require("./audioOut"));
11
44
  /**
@@ -21,6 +54,9 @@ class AirTunes extends node_stream_1.Duplex {
21
54
  */
22
55
  constructor(options = {}) {
23
56
  super({ readableObjectMode: false, writableObjectMode: false });
57
+ if (options.config) {
58
+ (0, config_1.applyConfig)(options.config);
59
+ }
24
60
  const audioOut = new audioOut_1.default();
25
61
  this.devices = new devices_1.default(audioOut);
26
62
  this.devices.init();
package/dist/esm/index.js CHANGED
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -8,7 +41,7 @@ exports.start = start;
8
41
  const node_events_1 = require("node:events");
9
42
  // Airtunes implementation (node_airtunes2 port) in src/core.
10
43
  const index_1 = __importDefault(require("./core/index"));
11
- const config_1 = __importDefault(require("./utils/config"));
44
+ const config_1 = __importStar(require("./utils/config"));
12
45
  class LoxAirplaySender extends node_events_1.EventEmitter {
13
46
  airtunes = null;
14
47
  deviceKey = null;
@@ -32,11 +65,15 @@ class LoxAirplaySender extends node_events_1.EventEmitter {
32
65
  this.stop();
33
66
  }
34
67
  this.log = options.log;
68
+ if (options.config) {
69
+ (0, config_1.applyConfig)(options.config);
70
+ }
35
71
  const inputCodec = options.inputCodec ?? 'pcm';
36
72
  config_1.default.packet_size = inputCodec === 'alac' ? config_1.default.alac_packet_size : config_1.default.pcm_packet_size;
37
73
  this.airtunes = new index_1.default({
38
74
  packetSize: config_1.default.packet_size,
39
75
  startTimeMs: options.startTimeMs,
76
+ config: options.config,
40
77
  });
41
78
  this.airtunes.on('device', (key, status, desc) => {
42
79
  onEvent?.({ event: 'device', message: status, detail: { key, desc } });
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.config = void 0;
4
+ exports.applyConfig = applyConfig;
4
5
  const numUtil_1 = require("./numUtil");
5
6
  exports.config = {
6
7
  user_agent: 'iTunes/11.3.1 (Windows; Microsoft Windows 10 x64 (Build 19044); x64) (dt:2)',
@@ -31,4 +32,8 @@ exports.config = {
31
32
  iv_base64: 'ePRBLI0XN5ArFaaz7ncNZw',
32
33
  rsa_aeskey_base64: 'VjVbxWcmYgbBbhwBNlCh3K0CMNtWoB844BuiHGUJT51zQS7SDpMnlbBIobsKbfEJ3SCgWHRXjYWf7VQWRYtEcfx7ejA8xDIk5PSBYTvXP5dU2QoGrSBv0leDS6uxlEWuxBq3lIxCxpWO2YswHYKJBt06Uz9P2Fq2hDUwl3qOQ8oXb0OateTKtfXEwHJMprkhsJsGDrIc5W5NJFMAo6zCiM9bGSDeH2nvTlyW6bfI/Q0v0cDGUNeY3ut6fsoafRkfpCwYId+bg3diJh+uzw5htHDyZ2sN+BFYHzEfo8iv4KDxzeya9llqg6fRNQ8d5YjpvTnoeEQ9ye9ivjkBjcAfVw',
33
34
  };
35
+ function applyConfig(overrides) {
36
+ Object.assign(exports.config, overrides);
37
+ return exports.config;
38
+ }
34
39
  exports.default = exports.config;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import { Readable } from 'node:stream';
3
+ import { type AirplayConfig } from './utils/config';
3
4
  /**
4
5
  * Configuration for a single AirPlay sender.
5
6
  */
@@ -31,6 +32,8 @@ export interface LoxAirplaySenderOptions {
31
32
  startTimeMs?: number;
32
33
  /** Logger hook for internal messages. */
33
34
  log?: (level: 'debug' | 'info' | 'warn' | 'error', message: string, data?: unknown) => void;
35
+ /** Override transport/buffer tuning without patching the module. */
36
+ config?: Partial<AirplayConfig>;
34
37
  }
35
38
  /**
36
39
  * Metadata sent to receivers for UI display.
package/dist/index.js CHANGED
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -8,7 +41,7 @@ exports.start = start;
8
41
  const node_events_1 = require("node:events");
9
42
  // Airtunes implementation (node_airtunes2 port) in src/core.
10
43
  const index_1 = __importDefault(require("./core/index"));
11
- const config_1 = __importDefault(require("./utils/config"));
44
+ const config_1 = __importStar(require("./utils/config"));
12
45
  class LoxAirplaySender extends node_events_1.EventEmitter {
13
46
  airtunes = null;
14
47
  deviceKey = null;
@@ -32,11 +65,15 @@ class LoxAirplaySender extends node_events_1.EventEmitter {
32
65
  this.stop();
33
66
  }
34
67
  this.log = options.log;
68
+ if (options.config) {
69
+ (0, config_1.applyConfig)(options.config);
70
+ }
35
71
  const inputCodec = options.inputCodec ?? 'pcm';
36
72
  config_1.default.packet_size = inputCodec === 'alac' ? config_1.default.alac_packet_size : config_1.default.pcm_packet_size;
37
73
  this.airtunes = new index_1.default({
38
74
  packetSize: config_1.default.packet_size,
39
75
  startTimeMs: options.startTimeMs,
76
+ config: options.config,
40
77
  });
41
78
  this.airtunes.on('device', (key, status, desc) => {
42
79
  onEvent?.({ event: 'device', message: status, detail: { key, desc } });
@@ -28,4 +28,5 @@ export interface AirplayConfig {
28
28
  rsa_aeskey_base64: string;
29
29
  }
30
30
  export declare const config: AirplayConfig;
31
+ export declare function applyConfig(overrides: Partial<AirplayConfig>): AirplayConfig;
31
32
  export default config;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.config = void 0;
4
+ exports.applyConfig = applyConfig;
4
5
  const numUtil_1 = require("./numUtil");
5
6
  exports.config = {
6
7
  user_agent: 'iTunes/11.3.1 (Windows; Microsoft Windows 10 x64 (Build 19044); x64) (dt:2)',
@@ -31,4 +32,8 @@ exports.config = {
31
32
  iv_base64: 'ePRBLI0XN5ArFaaz7ncNZw',
32
33
  rsa_aeskey_base64: 'VjVbxWcmYgbBbhwBNlCh3K0CMNtWoB844BuiHGUJT51zQS7SDpMnlbBIobsKbfEJ3SCgWHRXjYWf7VQWRYtEcfx7ejA8xDIk5PSBYTvXP5dU2QoGrSBv0leDS6uxlEWuxBq3lIxCxpWO2YswHYKJBt06Uz9P2Fq2hDUwl3qOQ8oXb0OateTKtfXEwHJMprkhsJsGDrIc5W5NJFMAo6zCiM9bGSDeH2nvTlyW6bfI/Q0v0cDGUNeY3ut6fsoafRkfpCwYId+bg3diJh+uzw5htHDyZ2sN+BFYHzEfo8iv4KDxzeya9llqg6fRNQ8d5YjpvTnoeEQ9ye9ivjkBjcAfVw',
33
34
  };
35
+ function applyConfig(overrides) {
36
+ Object.assign(exports.config, overrides);
37
+ return exports.config;
38
+ }
34
39
  exports.default = exports.config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lox-airplay-sender",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "AirPlay sender (RAOP/AirPlay 1 + AirPlay 2 auth flows) ",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",