@basmilius/apple-raop 0.10.0 → 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 +1 -1
- package/dist/index.mjs +19 -24
- package/package.json +5 -5
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 ${
|
|
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: "
|
|
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.
|
|
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 >=
|
|
1075
|
-
const maxPackets = Math.min(Math.floor(framesBehind /
|
|
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(
|
|
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:
|
|
1405
|
-
channels:
|
|
1406
|
-
bytesPerChannel:
|
|
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(
|
|
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:
|
|
1417
|
-
frameSize:
|
|
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.
|
|
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.
|
|
50
|
-
"@basmilius/apple-encoding": "0.
|
|
51
|
-
"@basmilius/apple-encryption": "0.
|
|
52
|
-
"@basmilius/apple-rtsp": "0.
|
|
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",
|