@basmilius/apple-raop 0.10.1 → 0.11.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/dist/index.d.mts CHANGED
@@ -663,4 +663,4 @@ declare class RaopClient extends EventEmitter<EventMap> {
663
663
  static discover(deviceId: string, timingServer: TimingServer): Promise<RaopClient>;
664
664
  }
665
665
  //#endregion
666
- export { AudioPacketHeader, ControlClient, EncryptionType, MediaMetadata, MetadataType, PacketFifo, PlaybackInfo, RaopClient, RaopListener, RetransmitRequest, RaopRtspClient as RtspClient, Settings, Statistics, StreamClient, StreamContext, type StreamOptions, StreamProtocol, SyncPacket, decodeRetransmitRequest, getAudioProperties, getEncryptionTypes, getMetadataTypes, pctToDbfs };
666
+ export { AudioPacketHeader, ControlClient, EncryptionType, type EventMap, type MediaMetadata, MetadataType, PacketFifo, type PlaybackInfo, RaopClient, type RaopListener, type RetransmitRequest, RaopRtspClient as RtspClient, type Settings, Statistics, StreamClient, type StreamContext, type StreamOptions, type StreamProtocol, SyncPacket, decodeRetransmitRequest, getAudioProperties, getEncryptionTypes, getMetadataTypes, pctToDbfs };
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { createSocket } from "node:dgram";
2
2
  import { EventEmitter } from "node:events";
3
3
  import { DAAP, NTP, Plist } from "@basmilius/apple-encoding";
4
4
  import { createHash } from "node:crypto";
5
- import { Context, Discovery, generateActiveRemoteId, generateDacpId, generateSessionId, waitFor } from "@basmilius/apple-common";
5
+ import { AUDIO_BYTES_PER_CHANNEL, AUDIO_CHANNELS, AUDIO_FRAMES_PER_PACKET, AUDIO_SAMPLE_RATE, Context, Discovery, generateActiveRemoteId, generateDacpId, generateSessionId, waitFor } from "@basmilius/apple-common";
6
6
  import { RtspClient } from "@basmilius/apple-rtsp";
7
7
 
8
8
  //#region src/types.ts
@@ -403,8 +403,6 @@ var ControlClient = class extends EventEmitter {
403
403
  //#region src/rtspClient.ts
404
404
  /** User-Agent header value sent with all RTSP requests. */
405
405
  const USER_AGENT = "AirPlay/550.10";
406
- /** Number of audio frames per RTP packet, used in SDP ANNOUNCE payload. */
407
- const FRAMES_PER_PACKET$1 = 352;
408
406
  /** Single-byte flag indicating unencrypted auth-setup mode. */
409
407
  const AUTH_SETUP_UNENCRYPTED = Buffer.from([1]);
410
408
  /**
@@ -475,7 +473,7 @@ function buildAnnouncePayload(options) {
475
473
  "t=0 0",
476
474
  "m=audio 0 RTP/AVP 96",
477
475
  `a=rtpmap:96 L16/${options.sampleRate}/${options.channels}`,
478
- `a=fmtp:96 ${FRAMES_PER_PACKET$1} 0 ${options.bitsPerChannel} 40 10 14 ${options.channels} 255 0 0 ${options.sampleRate}`
476
+ `a=fmtp:96 ${AUDIO_FRAMES_PER_PACKET} 0 ${options.bitsPerChannel} 40 10 14 ${options.channels} 255 0 0 ${options.sampleRate}`
479
477
  ].join("\r\n") + "\r\n";
480
478
  }
481
479
  /**
@@ -620,7 +618,7 @@ var RaopRtspClient = class extends RtspClient {
620
618
  const parts = wwwAuthenticate.split("\"");
621
619
  if (parts.length >= 5) {
622
620
  this.#digestInfo = {
623
- username: "pyatv",
621
+ username: "apple-protocols",
624
622
  realm: parts[1],
625
623
  password,
626
624
  nonce: parts[3]
@@ -941,6 +939,7 @@ var StreamClient = class extends EventEmitter {
941
939
  */
942
940
  close() {
943
941
  this.#controlClient?.close();
942
+ this.#controlClient = void 0;
944
943
  }
945
944
  /**
946
945
  * Initializes the streaming session by parsing device capabilities,
@@ -1002,8 +1001,12 @@ var StreamClient = class extends EventEmitter {
1002
1001
  let transport;
1003
1002
  try {
1004
1003
  transport = createSocket("udp4");
1005
- await new Promise((resolve) => {
1006
- transport.connect(this.#streamContext.serverPort, this.#rtsp.connection.remoteIp, resolve);
1004
+ await new Promise((resolve, reject) => {
1005
+ transport.once("error", reject);
1006
+ transport.connect(this.#streamContext.serverPort, this.#rtsp.connection.remoteIp, () => {
1007
+ transport.removeListener("error", reject);
1008
+ resolve();
1009
+ });
1007
1010
  });
1008
1011
  this.#controlClient.start(this.#rtsp.connection.remoteIp);
1009
1012
  if ((this.#metadataTypes & MetadataType.Progress) !== 0) {
@@ -1071,8 +1074,8 @@ var StreamClient = class extends EventEmitter {
1071
1074
  if (numSent === 0) break;
1072
1075
  stats.tick(numSent);
1073
1076
  const framesBehind = stats.framesBehind;
1074
- if (framesBehind >= 352) {
1075
- const maxPackets = Math.min(Math.floor(framesBehind / 352), 3);
1077
+ if (framesBehind >= AUDIO_FRAMES_PER_PACKET) {
1078
+ const maxPackets = Math.min(Math.floor(framesBehind / AUDIO_FRAMES_PER_PACKET), 3);
1076
1079
  this.#context.logger.debug(`Compensating with ${maxPackets} packets (${framesBehind} frames behind)`);
1077
1080
  const [sentFrames, hasMorePackets] = await this.#sendNumberOfPackets(source, transport, maxPackets);
1078
1081
  stats.tick(sentFrames);
@@ -1111,7 +1114,7 @@ var StreamClient = class extends EventEmitter {
1111
1114
  */
1112
1115
  async #sendPacket(source, firstPacket, transport) {
1113
1116
  if (this.#streamContext.paddingSent >= this.#streamContext.latency) return 0;
1114
- let frames = await source.readFrames(352);
1117
+ let frames = await source.readFrames(AUDIO_FRAMES_PER_PACKET);
1115
1118
  if (!frames) {
1116
1119
  frames = Buffer.alloc(this.#streamContext.packetSize);
1117
1120
  this.#streamContext.paddingSent += Math.floor(frames.length / this.#streamContext.frameSize);
@@ -1172,14 +1175,6 @@ var StreamClient = class extends EventEmitter {
1172
1175
 
1173
1176
  //#endregion
1174
1177
  //#region src/raop.ts
1175
- /** Default audio sample rate in Hz (CD quality). */
1176
- const SAMPLE_RATE = 44100;
1177
- /** Default number of audio channels (stereo). */
1178
- const CHANNELS = 2;
1179
- /** Default bytes per channel sample (16-bit). */
1180
- const BYTES_PER_CHANNEL = 2;
1181
- /** Number of audio frames per RTP packet. */
1182
- const FRAMES_PER_PACKET = 352;
1183
1178
  /**
1184
1179
  * High-level RAOP client for streaming audio to AirPlay receivers.
1185
1180
  * Wraps the RTSP handshake, UDP audio transport, control channel,
@@ -1401,20 +1396,20 @@ var RaopStreamProtocol = class {
1401
1396
  function createStreamContext() {
1402
1397
  const rtptime = Math.floor(Math.random() * 4294967295);
1403
1398
  return {
1404
- sampleRate: SAMPLE_RATE,
1405
- channels: CHANNELS,
1406
- bytesPerChannel: BYTES_PER_CHANNEL,
1399
+ sampleRate: AUDIO_SAMPLE_RATE,
1400
+ channels: AUDIO_CHANNELS,
1401
+ bytesPerChannel: AUDIO_BYTES_PER_CHANNEL,
1407
1402
  rtpseq: Math.floor(Math.random() * 65536),
1408
1403
  rtptime,
1409
1404
  headTs: rtptime,
1410
- latency: Math.floor(SAMPLE_RATE * 2),
1405
+ latency: Math.floor(AUDIO_SAMPLE_RATE * 2),
1411
1406
  serverPort: 0,
1412
1407
  controlPort: 0,
1413
1408
  rtspSession: "",
1414
1409
  volume: -20,
1415
1410
  position: 0,
1416
- packetSize: FRAMES_PER_PACKET * CHANNELS * BYTES_PER_CHANNEL,
1417
- frameSize: CHANNELS * BYTES_PER_CHANNEL,
1411
+ packetSize: AUDIO_FRAMES_PER_PACKET * AUDIO_CHANNELS * AUDIO_BYTES_PER_CHANNEL,
1412
+ frameSize: AUDIO_CHANNELS * AUDIO_BYTES_PER_CHANNEL,
1418
1413
  paddingSent: 0,
1419
1414
  reset() {
1420
1415
  this.rtpseq = Math.floor(Math.random() * 65536);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@basmilius/apple-raop",
3
3
  "description": "Implementation of Apple's RAOP protocol in Node.js.",
4
- "version": "0.10.1",
4
+ "version": "0.11.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -46,10 +46,10 @@
46
46
  }
47
47
  },
48
48
  "dependencies": {
49
- "@basmilius/apple-common": "0.10.1",
50
- "@basmilius/apple-encoding": "0.10.1",
51
- "@basmilius/apple-encryption": "0.10.1",
52
- "@basmilius/apple-rtsp": "0.10.1"
49
+ "@basmilius/apple-common": "0.11.0",
50
+ "@basmilius/apple-encoding": "0.11.0",
51
+ "@basmilius/apple-encryption": "0.11.0",
52
+ "@basmilius/apple-rtsp": "0.11.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/bun": "^1.3.11",