@basmilius/apple-airplay 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.
Files changed (3) hide show
  1. package/dist/index.d.mts +763 -311
  2. package/dist/index.mjs +966 -366
  3. package/package.json +5 -5
package/dist/index.mjs CHANGED
@@ -1,30 +1,195 @@
1
1
  import { t as __exportAll } from "./chunk-DQk6qfdC.mjs";
2
+ import { AUDIO_BYTES_PER_CHANNEL, AUDIO_CHANNELS, AUDIO_FRAMES_PER_PACKET, AUDIO_SAMPLE_RATE, AccessoryPair, AccessoryVerify, ConnectionClosedError, Context, EncryptionAwareConnection, EncryptionError, EncryptionState, HTTP_TIMEOUT, PairingError, PlaybackError, SENDER_FEATURES_AUDIO, SENDER_FEATURES_REMOTE_CONTROL, SetupError, TimeoutError, deriveEncryptionKeys, describeFlags, generateActiveRemoteId, generateDacpId, generateSessionId, getMacAddress, hasFeatureFlag, randomInt32, randomInt64, uint16ToBE, uuid, waitFor } from "@basmilius/apple-common";
2
3
  import { randomBytes } from "node:crypto";
3
4
  import { createSocket } from "node:dgram";
4
- import { AccessoryPair, AccessoryVerify, ConnectionClosedError, Context, EncryptionAwareConnection, EncryptionError, EncryptionState, HTTP_TIMEOUT, PairingError, PlaybackError, SetupError, TimeoutError, generateActiveRemoteId, generateDacpId, generateSessionId, getMacAddress, randomInt32, randomInt64, uint16ToBE, uuid, waitFor } from "@basmilius/apple-common";
5
5
  import { NTP, Plist } from "@basmilius/apple-encoding";
6
- import { Chacha20, hkdf } from "@basmilius/apple-encryption";
6
+ import { Chacha20 } from "@basmilius/apple-encryption";
7
7
  import { RtspClient, buildResponse, parseRequest } from "@basmilius/apple-rtsp";
8
8
 
9
+ //#region src/latencyManager.ts
10
+ /**
11
+ * Dynamic latency manager for AirPlay audio streaming.
12
+ *
13
+ * Implements a tier-based latency system inspired by Apple's DynamicLatencyManager.
14
+ * Monitors audio glitches (packet loss, late arrivals) and adjusts the latency
15
+ * tier accordingly: glitches increase latency, stable periods decrease it.
16
+ */
17
+ /** Available latency tiers in ascending order (as fractions of sample rate). */
18
+ const LATENCY_TIERS = [
19
+ .25,
20
+ .5,
21
+ 1,
22
+ 2
23
+ ];
24
+ /** Number of consecutive successful packets needed to drop one latency tier. */
25
+ const STABILITY_THRESHOLD = 500;
26
+ /** Number of glitches within the glitch window that trigger a tier increase. */
27
+ const GLITCH_THRESHOLD = 3;
28
+ /** Time window in milliseconds for counting glitches. */
29
+ const GLITCH_WINDOW_MS = 5e3;
30
+ /**
31
+ * Manages dynamic latency for an audio stream.
32
+ *
33
+ * Usage:
34
+ * 1. Create with `new LatencyManager(sampleRate)`
35
+ * 2. Call `getLatency()` to get the current latency in samples
36
+ * 3. Call `reportSuccess()` after each successful packet
37
+ * 4. Call `reportGlitch()` when a glitch is detected (packet loss, NACK, late arrival)
38
+ * 5. The manager automatically adjusts the latency tier
39
+ */
40
+ var LatencyManager = class {
41
+ #sampleRate;
42
+ #tierIndex = 0;
43
+ #consecutiveSuccesses = 0;
44
+ #glitchTimestamps = [];
45
+ /**
46
+ * Creates a new LatencyManager.
47
+ *
48
+ * @param sampleRate - The audio sample rate in Hz (e.g. 44100, 48000).
49
+ * @param initialTierIndex - Starting tier index (defaults to 0, lowest latency).
50
+ */
51
+ constructor(sampleRate, initialTierIndex = 0) {
52
+ this.#sampleRate = sampleRate;
53
+ this.#tierIndex = Math.min(Math.max(0, initialTierIndex), LATENCY_TIERS.length - 1);
54
+ }
55
+ /** Current latency tier index (0 = lowest latency, 3 = highest). */
56
+ get tierIndex() {
57
+ return this.#tierIndex;
58
+ }
59
+ /** Current latency in samples. */
60
+ get latency() {
61
+ return Math.round(this.#sampleRate * LATENCY_TIERS[this.#tierIndex]);
62
+ }
63
+ /** Current latency in milliseconds. */
64
+ get latencyMs() {
65
+ return Math.round(LATENCY_TIERS[this.#tierIndex] * 1e3);
66
+ }
67
+ /** Whether the manager is at the maximum latency tier. */
68
+ get isMaxTier() {
69
+ return this.#tierIndex >= LATENCY_TIERS.length - 1;
70
+ }
71
+ /** Whether the manager is at the minimum latency tier. */
72
+ get isMinTier() {
73
+ return this.#tierIndex <= 0;
74
+ }
75
+ /**
76
+ * Returns the current latency in samples.
77
+ * Alias for the `latency` getter for use in streaming loops.
78
+ */
79
+ getLatency() {
80
+ return this.latency;
81
+ }
82
+ /**
83
+ * Reports a successfully sent and acknowledged packet.
84
+ * After enough consecutive successes, drops to a lower latency tier.
85
+ */
86
+ reportSuccess() {
87
+ this.#consecutiveSuccesses++;
88
+ if (this.#consecutiveSuccesses >= STABILITY_THRESHOLD && !this.isMinTier) {
89
+ this.#tierIndex--;
90
+ this.#consecutiveSuccesses = 0;
91
+ }
92
+ }
93
+ /**
94
+ * Reports a glitch (packet loss, retransmission request, late arrival).
95
+ * If enough glitches occur within the time window, increases the latency tier.
96
+ */
97
+ reportGlitch() {
98
+ this.#consecutiveSuccesses = 0;
99
+ const now = Date.now();
100
+ this.#glitchTimestamps.push(now);
101
+ const windowStart = now - GLITCH_WINDOW_MS;
102
+ this.#glitchTimestamps = this.#glitchTimestamps.filter((ts) => ts >= windowStart);
103
+ if (this.#glitchTimestamps.length >= GLITCH_THRESHOLD && !this.isMaxTier) {
104
+ this.#tierIndex++;
105
+ this.#glitchTimestamps = [];
106
+ }
107
+ }
108
+ /**
109
+ * Returns the recommended RFC 2198 redundancy level based on the current latency tier.
110
+ * Higher latency tiers (more glitches) recommend more redundancy.
111
+ */
112
+ get recommendedRedundancy() {
113
+ if (this.#tierIndex >= 2) return 3;
114
+ if (this.#tierIndex >= 1) return 2;
115
+ return 1;
116
+ }
117
+ /** Resets the manager to the initial (lowest) latency tier. */
118
+ reset() {
119
+ this.#tierIndex = 0;
120
+ this.#consecutiveSuccesses = 0;
121
+ this.#glitchTimestamps = [];
122
+ }
123
+ };
124
+
125
+ //#endregion
126
+ //#region src/streamTiming.ts
127
+ /** Maximum number of extra packets to send when catching up from being behind schedule. */
128
+ const MAX_PACKETS_COMPENSATE = 3;
129
+ /** Number of consecutive slow packets before logging a warning. */
130
+ const SLOW_WARNING_THRESHOLD = 5;
131
+ /**
132
+ * Runs a real-time audio streaming loop with wall-clock timing compensation.
133
+ *
134
+ * Reads and sends packets via the provided {@link sendPacket} callback, pacing
135
+ * them to match real-time playback. When the loop falls behind schedule, it
136
+ * sends up to {@link MAX_PACKETS_COMPENSATE} extra packets per cycle to catch
137
+ * up. Logs progress every 100 packets and warns when consistently behind.
138
+ *
139
+ * @param sendPacket - Callback that sends one packet and returns frames sent (0 = done).
140
+ * @param options - Timing configuration (sample rate, logger, log prefix).
141
+ * @returns Total number of packets sent.
142
+ */
143
+ async function streamWithTiming(sendPacket, options) {
144
+ const { sampleRate, logger, logPrefix } = options;
145
+ let firstPacket = true;
146
+ let packetCount = 0;
147
+ let slowCount = 0;
148
+ let totalFrames = 0;
149
+ const startTime = performance.now();
150
+ while (true) {
151
+ const framesSent = await sendPacket(firstPacket);
152
+ if (framesSent === 0) {
153
+ logger.debug(logPrefix, `End of stream after ${packetCount} packets`);
154
+ break;
155
+ }
156
+ totalFrames += framesSent;
157
+ packetCount++;
158
+ firstPacket = false;
159
+ if (packetCount % 100 === 0) logger.debug(logPrefix, `Sent ${packetCount} packets, ${totalFrames} frames`);
160
+ const sleepTime = totalFrames / sampleRate * 1e3 - (performance.now() - startTime);
161
+ if (sleepTime > 0) {
162
+ slowCount = 0;
163
+ await waitFor(sleepTime);
164
+ } else {
165
+ const framesBehind = Math.floor(-sleepTime / 1e3 * sampleRate);
166
+ if (framesBehind >= AUDIO_FRAMES_PER_PACKET) {
167
+ const extraPackets = Math.min(Math.floor(framesBehind / AUDIO_FRAMES_PER_PACKET), MAX_PACKETS_COMPENSATE);
168
+ for (let idx = 0; idx < extraPackets; idx++) {
169
+ const extra = await sendPacket(false);
170
+ if (extra === 0) break;
171
+ totalFrames += extra;
172
+ packetCount++;
173
+ }
174
+ }
175
+ slowCount++;
176
+ if (slowCount >= SLOW_WARNING_THRESHOLD) {
177
+ logger.warn(logPrefix, `Stream behind schedule (${slowCount} consecutive, ${Math.abs(sleepTime).toFixed(1)}ms behind)`);
178
+ slowCount = 0;
179
+ }
180
+ }
181
+ }
182
+ return packetCount;
183
+ }
184
+
185
+ //#endregion
9
186
  //#region src/audioStream.ts
10
- /** Default sample rate for audio streaming (CD quality). */
11
- const SAMPLE_RATE = 44100;
12
- /** Number of audio channels (stereo). */
13
- const CHANNELS = 2;
14
- /** Bytes per sample per channel (16-bit PCM). */
15
- const BYTES_PER_CHANNEL = 2;
16
- /** Number of audio frames per RTP packet. Matches Apple's ALAC/PCM packet size. */
17
- const FRAMES_PER_PACKET = 352;
18
187
  /** Maximum number of packets to keep in the retransmission backlog. */
19
188
  const PACKET_BACKLOG_SIZE = 1e3;
20
189
  /** Interval in milliseconds between RTCP sync packets. */
21
190
  const SYNC_INTERVAL = 1e3;
22
- /** Maximum number of extra packets to send when catching up from being behind schedule. */
23
- const MAX_PACKETS_COMPENSATE$1 = 3;
24
- /** Number of consecutive slow packets before logging a warning. */
25
- const SLOW_WARNING_THRESHOLD$1 = 5;
26
- /** Number of previous frames to include as RFC 2198 redundancy (0 = disabled). */
27
- const REDUNDANCY_COUNT = 0;
191
+ /** Default number of previous frames to include as RFC 2198 redundancy (0 = disabled). */
192
+ const DEFAULT_REDUNDANCY_COUNT = 0;
28
193
  /**
29
194
  * Audio compression type values for the `ct` field in the SETUP request body.
30
195
  *
@@ -64,14 +229,21 @@ const AudioFormat = {
64
229
  AAC_LC_44100_2: 131072,
65
230
  AAC_ELD_44100_2: 262144,
66
231
  AAC_ELD_16000_1: 1048576,
232
+ AAC_ELD_24000_1: 2097152,
67
233
  ALAC_44100_16_2: 4194304,
68
- ALAC_44100_24_2: 8388608
234
+ ALAC_44100_24_2: 8388608,
235
+ AAC_ELD_32000_1: 16777216,
236
+ AAC_ELD_48000_1: 33554432,
237
+ AAC_ELD_48000_2: 67108864,
238
+ ALAC_48000_16_2: 134217728,
239
+ ALAC_48000_24_2: 268435456,
240
+ AAC_LC_48000_2: 536870912
69
241
  };
70
242
  /**
71
243
  * Convert an RTP timestamp to a wall-clock NTP timestamp.
72
244
  *
73
245
  * Uses a fixed anchor point established when the stream starts: at that moment
74
- * we record both the RTP timestamp and the wall-clock NTP time. For subsequent
246
+ * we record both the RTP timestamp and the wall-clock NTP time. For further
75
247
  * packets we compute the elapsed time from the RTP delta and add it to the
76
248
  * anchor NTP time. This gives the receiver a real NTP timestamp it can use for
77
249
  * multi-room synchronization.
@@ -97,12 +269,14 @@ const rtpToNtp = (rtpTimestamp, sampleRate, anchorRtp, anchorNtp) => {
97
269
  * - ChaCha20-Poly1305 audio encryption with per-packet nonces
98
270
  * - RTCP sync packets for receiver clock synchronization
99
271
  * - Packet retransmission backlog for handling receiver NACK requests
100
- * - RFC 2198 audio redundancy support (configurable via REDUNDANCY_COUNT)
272
+ * - RFC 2198 audio redundancy support (configurable via AudioStreamOptions)
101
273
  * - Wall-clock-based timing to maintain real-time audio pace
102
274
  */
103
275
  var AudioStream = class {
104
276
  #protocol;
105
277
  #context;
278
+ /** Configurable RFC 2198 redundancy count (0 = disabled). */
279
+ #redundancyCount;
106
280
  /** Local RTCP control port. */
107
281
  #controlPort = 0;
108
282
  /** UDP socket for RTCP control messages (sync, retransmit requests). */
@@ -114,9 +288,9 @@ var AudioStream = class {
114
288
  /** Connected UDP socket for sending RTP audio packets. */
115
289
  #dataSocket;
116
290
  /** Negotiated bytes per channel from format negotiation. */
117
- #negotiatedBytesPerChannel = BYTES_PER_CHANNEL;
291
+ #negotiatedBytesPerChannel = AUDIO_BYTES_PER_CHANNEL;
118
292
  /** Negotiated sample rate from format negotiation. */
119
- #negotiatedSampleRate = SAMPLE_RATE;
293
+ #negotiatedSampleRate = AUDIO_SAMPLE_RATE;
120
294
  /** RTP timestamp at the anchor point for NTP conversion. */
121
295
  #anchorRtp = 0;
122
296
  /** NTP timestamp at the anchor point for RTP-to-NTP conversion. */
@@ -133,12 +307,35 @@ var AudioStream = class {
133
307
  #syncInterval;
134
308
  /** Mutable stream state (RTP counters, timing, etc.). */
135
309
  #streamContext;
310
+ /** Dynamic latency manager for adaptive latency control. */
311
+ #latencyManager;
312
+ /** Monotonic encryption counter for ChaCha20 nonce (independent of RTP sequence). */
313
+ #encryptionCounter = 0;
314
+ /** Streaming statistics for feedback and adaptive redundancy. */
315
+ #packetsSent = 0;
316
+ #retransmitRequests = 0;
317
+ #retransmitsFulfilled = 0;
318
+ #retransmitsFailed = 0;
319
+ #totalBytesSent = 0;
320
+ /** Current streaming statistics for feedback and adaptive redundancy. */
321
+ get stats() {
322
+ return {
323
+ packetsSent: this.#packetsSent,
324
+ retransmitRequests: this.#retransmitRequests,
325
+ retransmitsFulfilled: this.#retransmitsFulfilled,
326
+ retransmitsFailed: this.#retransmitsFailed,
327
+ packetLossRate: this.#packetsSent > 0 ? this.#retransmitRequests / this.#packetsSent : 0,
328
+ totalBytesSent: this.#totalBytesSent
329
+ };
330
+ }
136
331
  /**
137
332
  * @param protocol - The AirPlay protocol instance providing control stream and context.
333
+ * @param options - Optional configuration for redundancy and other settings.
138
334
  */
139
- constructor(protocol) {
335
+ constructor(protocol, options) {
140
336
  this.#protocol = protocol;
141
337
  this.#context = protocol.context;
338
+ this.#redundancyCount = options?.redundancyCount ?? DEFAULT_REDUNDANCY_COUNT;
142
339
  }
143
340
  /**
144
341
  * Performs RTSP SETUP to negotiate audio format and get port assignments.
@@ -169,9 +366,9 @@ var AudioStream = class {
169
366
  const supportedFormats = this.#protocol.receiverInfo?.supportedAudioFormats;
170
367
  let ct = CompressionType.PCM;
171
368
  let audioFormat = AudioFormat.PCM_44100_24_2;
172
- let sampleRate = SAMPLE_RATE;
369
+ let sampleRate = AUDIO_SAMPLE_RATE;
173
370
  if (supportedFormats) this.#context.logger.info("[audio]", `Receiver supported formats: 0x${supportedFormats.toString(16)}`);
174
- let bytesPerChannel = BYTES_PER_CHANNEL;
371
+ let bytesPerChannel = AUDIO_BYTES_PER_CHANNEL;
175
372
  const setupBody = Plist.serialize({ streams: [{
176
373
  audioFormat,
177
374
  audioMode: "default",
@@ -181,12 +378,12 @@ var AudioStream = class {
181
378
  latencyMax: sampleRate * 2,
182
379
  latencyMin: Math.round(sampleRate * .25),
183
380
  shk: shkArrayBuffer,
184
- spf: 352,
381
+ spf: AUDIO_FRAMES_PER_PACKET,
185
382
  sr: sampleRate,
186
383
  streamConnectionID,
187
384
  supportsDynamicStreamID: false,
188
- redundantAudio: REDUNDANCY_COUNT > 0,
189
- supportsRTPPacketRedundancy: REDUNDANCY_COUNT > 0,
385
+ redundantAudio: this.#redundancyCount > 0,
386
+ supportsRTPPacketRedundancy: this.#redundancyCount > 0,
190
387
  type: 96
191
388
  }] });
192
389
  this.#context.logger.debug("[audio]", "Sending audio stream SETUP...");
@@ -228,15 +425,16 @@ var AudioStream = class {
228
425
  resolve();
229
426
  });
230
427
  });
231
- const frameSize = CHANNELS * this.#negotiatedBytesPerChannel;
232
- const packetSize = 352 * frameSize;
233
- const latency = Math.round(this.#negotiatedSampleRate * .25);
428
+ const frameSize = AUDIO_CHANNELS * this.#negotiatedBytesPerChannel;
429
+ const packetSize = AUDIO_FRAMES_PER_PACKET * frameSize;
430
+ this.#latencyManager = new LatencyManager(this.#negotiatedSampleRate);
431
+ const latency = this.#latencyManager.getLatency();
234
432
  const initialRtpTime = 0;
235
433
  this.#anchorRtp = initialRtpTime;
236
434
  this.#anchorNtp = NTP.now();
237
435
  const ctx = {
238
436
  sampleRate: this.#negotiatedSampleRate,
239
- channels: CHANNELS,
437
+ channels: AUDIO_CHANNELS,
240
438
  bytesPerChannel: this.#negotiatedBytesPerChannel,
241
439
  frameSize,
242
440
  packetSize,
@@ -313,39 +511,12 @@ var AudioStream = class {
313
511
  async stream(source, remoteAddress) {
314
512
  const ctx = await this.prepare(remoteAddress);
315
513
  try {
316
- let firstPacket = true;
317
- let packetCount = 0;
318
- let slowCount = 0;
319
- const startTime = performance.now();
320
514
  this.#context.logger.info("[audio]", "Starting audio stream...");
321
- while (true) {
322
- if (await this.#sendPacket(source, firstPacket, ctx) === 0) {
323
- this.#context.logger.debug("[audio]", `End of audio stream after ${packetCount} packets (padding complete)`);
324
- break;
325
- }
326
- packetCount++;
327
- firstPacket = false;
328
- if (packetCount % 100 === 0) this.#context.logger.debug("[audio]", `Sent ${packetCount} packets, ${ctx.totalFrames} frames`);
329
- const sleepTime = ctx.totalFrames / ctx.sampleRate * 1e3 - (performance.now() - startTime);
330
- if (sleepTime > 0) {
331
- slowCount = 0;
332
- await this.#sleep(sleepTime);
333
- } else {
334
- const framesBehind = Math.floor(-sleepTime / 1e3 * ctx.sampleRate);
335
- if (framesBehind >= 352) {
336
- const extraPackets = Math.min(Math.floor(framesBehind / 352), MAX_PACKETS_COMPENSATE$1);
337
- for (let i = 0; i < extraPackets; i++) {
338
- if (await this.#sendPacket(source, false, ctx) === 0) break;
339
- packetCount++;
340
- }
341
- }
342
- slowCount++;
343
- if (slowCount >= SLOW_WARNING_THRESHOLD$1) {
344
- this.#context.logger.warn("[audio]", `Stream is behind schedule (${slowCount} consecutive slow packets, ${Math.abs(sleepTime).toFixed(1)}ms behind)`);
345
- slowCount = 0;
346
- }
347
- }
348
- }
515
+ const packetCount = await streamWithTiming((firstPacket) => this.#sendPacket(source, firstPacket, ctx), {
516
+ sampleRate: ctx.sampleRate,
517
+ logger: this.#context.logger,
518
+ logPrefix: "[audio]"
519
+ });
349
520
  this.#context.logger.info("[audio]", `Audio stream finished, sent ${packetCount} packets`);
350
521
  this.#stopSync();
351
522
  this.#context.logger.debug("[audio]", "Sending TEARDOWN...");
@@ -370,7 +541,7 @@ var AudioStream = class {
370
541
  */
371
542
  async #sendPacket(source, firstPacket, ctx) {
372
543
  if (ctx.paddingSent >= ctx.latency) return 0;
373
- let frames = await source.readFrames(352);
544
+ let frames = await source.readFrames(AUDIO_FRAMES_PER_PACKET);
374
545
  if (!frames || frames.length === 0) {
375
546
  frames = Buffer.alloc(ctx.packetSize, 0);
376
547
  ctx.paddingSent += Math.floor(frames.length / ctx.frameSize);
@@ -394,7 +565,7 @@ var AudioStream = class {
394
565
  * @returns Promise resolving to the number of frames sent.
395
566
  */
396
567
  #sendFrameBuffer(frames, firstPacket, ctx) {
397
- const hasRedundancy = REDUNDANCY_COUNT > 0 && this.#previousFrames.length > 0;
568
+ const hasRedundancy = this.#redundancyCount > 0 && this.#previousFrames.length > 0;
398
569
  const pt = hasRedundancy ? 97 : 96;
399
570
  const rtpHeader = Buffer.allocUnsafe(12);
400
571
  rtpHeader.writeUInt8(128, 0);
@@ -404,10 +575,10 @@ var AudioStream = class {
404
575
  rtpHeader.writeUInt32BE(this.#ssrc, 8);
405
576
  let audioPayload;
406
577
  if (hasRedundancy) {
407
- const redundantFrames = this.#previousFrames.slice(-REDUNDANCY_COUNT);
578
+ const redundantFrames = this.#previousFrames.slice(-this.#redundancyCount);
408
579
  const headers = [];
409
580
  for (let i = 0; i < redundantFrames.length; i++) {
410
- const tsOffset = (redundantFrames.length - i) * 352;
581
+ const tsOffset = (redundantFrames.length - i) * AUDIO_FRAMES_PER_PACKET;
411
582
  const blockLen = redundantFrames[i].length;
412
583
  const header = Buffer.allocUnsafe(4);
413
584
  header[0] = 224;
@@ -424,16 +595,28 @@ var AudioStream = class {
424
595
  ]);
425
596
  } else audioPayload = frames;
426
597
  this.#previousFrames.push(Buffer.from(frames));
427
- if (this.#previousFrames.length > REDUNDANCY_COUNT) this.#previousFrames.shift();
598
+ if (this.#previousFrames.length > this.#redundancyCount) this.#previousFrames.shift();
428
599
  const aad = rtpHeader.subarray(4, 12);
429
- const payload = this.#encryptAudio(audioPayload, aad, ctx.rtpSeq);
600
+ const payload = this.#encryptAudio(audioPayload, aad, this.#encryptionCounter++);
430
601
  const packet = Buffer.concat([rtpHeader, payload]);
431
602
  this.#storePacket(ctx.rtpSeq, packet);
432
603
  const framesSent = Math.floor(frames.length / ctx.frameSize);
433
604
  ctx.rtpSeq = ctx.rtpSeq + 1 & 65535;
434
605
  ctx.headTs = ctx.headTs + framesSent >>> 0;
435
606
  ctx.totalFrames += framesSent;
436
- return this.#send(packet).then(() => framesSent);
607
+ return this.#send(packet).then(() => {
608
+ this.#packetsSent++;
609
+ this.#totalBytesSent += packet.length;
610
+ this.#latencyManager?.reportSuccess();
611
+ if (this.#redundancyCount > 0 && this.#latencyManager && this.#packetsSent % 50 === 0) {
612
+ const recommended = this.#latencyManager.recommendedRedundancy;
613
+ if (recommended !== this.#redundancyCount) {
614
+ this.#context.logger.debug("[audio]", `Adjusting redundancy: ${this.#redundancyCount} → ${recommended}`);
615
+ this.#redundancyCount = recommended;
616
+ }
617
+ }
618
+ return framesSent;
619
+ });
437
620
  }
438
621
  /**
439
622
  * Stores a sent packet in the retransmission backlog.
@@ -569,6 +752,8 @@ var AudioStream = class {
569
752
  #retransmitPackets(data, addr) {
570
753
  const lostSeqno = data.readUInt16BE(4);
571
754
  const lostPackets = data.readUInt16BE(6);
755
+ this.#latencyManager?.reportGlitch();
756
+ this.#retransmitRequests += lostPackets;
572
757
  for (let i = 0; i < lostPackets; i++) {
573
758
  const seqno = lostSeqno + i & 65535;
574
759
  const packet = this.#packetBacklog.get(seqno);
@@ -580,6 +765,7 @@ var AudioStream = class {
580
765
  packet
581
766
  ]);
582
767
  this.#controlSocket?.send(resp, addr.port, addr.address);
768
+ this.#retransmitsFulfilled++;
583
769
  } else {
584
770
  const seqBuf = Buffer.alloc(2);
585
771
  seqBuf.writeUInt16BE(seqno);
@@ -589,6 +775,7 @@ var AudioStream = class {
589
775
  Buffer.alloc(4)
590
776
  ]);
591
777
  this.#controlSocket?.send(resp, addr.port, addr.address);
778
+ this.#retransmitsFailed++;
592
779
  }
593
780
  }
594
781
  }
@@ -615,10 +802,6 @@ var AudioStream = class {
615
802
 
616
803
  //#endregion
617
804
  //#region src/audioMultiplexer.ts
618
- /** Maximum number of extra packets to send when catching up from being behind schedule. */
619
- const MAX_PACKETS_COMPENSATE = 3;
620
- /** Number of consecutive slow packets before logging a warning. */
621
- const SLOW_WARNING_THRESHOLD = 5;
622
805
  /**
623
806
  * Streams audio from a single source to multiple AirPlay devices simultaneously.
624
807
  *
@@ -629,7 +812,8 @@ const SLOW_WARNING_THRESHOLD = 5;
629
812
  *
630
813
  * Timing is maintained by comparing wall-clock elapsed time against the expected
631
814
  * time based on the number of frames sent. When falling behind, extra packets
632
- * are sent to catch up (up to {@link MAX_PACKETS_COMPENSATE} per cycle).
815
+ * are sent to catch up. Timing logic is shared with {@link AudioStream} via
816
+ * {@link streamWithTiming}.
633
817
  */
634
818
  var AudioMultiplexer = class {
635
819
  #context;
@@ -646,9 +830,10 @@ var AudioMultiplexer = class {
646
830
  * Creates a new {@link AudioStream} for the device's protocol instance.
647
831
  *
648
832
  * @param protocol - The AirPlay protocol instance for the target device.
833
+ * @param options - Optional audio stream configuration (e.g. redundancy count).
649
834
  */
650
- addTarget(protocol) {
651
- const stream = new AudioStream(protocol);
835
+ addTarget(protocol, options) {
836
+ const stream = new AudioStream(protocol, options);
652
837
  this.#targets.push({
653
838
  protocol,
654
839
  stream
@@ -666,7 +851,7 @@ var AudioMultiplexer = class {
666
851
  *
667
852
  * Orchestrates the full lifecycle: setup all streams, prepare (connect UDP,
668
853
  * FLUSH, start sync), stream audio packets with timing compensation, and
669
- * finish (padding + TEARDOWN). On error, all streams are closed.
854
+ * finish (padding and TEARDOWN). On error, all streams are closed.
670
855
  *
671
856
  * @param source - Audio source to read PCM frames from.
672
857
  * @throws Re-throws any error after cleaning up all streams.
@@ -683,18 +868,10 @@ var AudioMultiplexer = class {
683
868
  const sampleRate = contexts[0].sampleRate;
684
869
  const packetSize = contexts[0].packetSize;
685
870
  try {
686
- let firstPacket = true;
687
- let packetCount = 0;
688
- let slowCount = 0;
689
- let totalFrames = 0;
690
- const startTime = performance.now();
691
871
  this.#context.logger.info("[multiplexer]", "Starting multi-room audio stream...");
692
- while (true) {
693
- let frames = await source.readFrames(352);
694
- if (!frames || frames.length === 0) {
695
- this.#context.logger.debug("[multiplexer]", `End of source after ${packetCount} packets`);
696
- break;
697
- }
872
+ const sendPacket = async (firstPacket) => {
873
+ let frames = await source.readFrames(AUDIO_FRAMES_PER_PACKET);
874
+ if (!frames || frames.length === 0) return 0;
698
875
  if (frames.length < packetSize) {
699
876
  const padded = Buffer.alloc(packetSize, 0);
700
877
  frames.copy(padded);
@@ -703,40 +880,13 @@ var AudioMultiplexer = class {
703
880
  await Promise.all(this.#targets.map(async (target) => {
704
881
  await target.stream.sendFrameData(frames, firstPacket);
705
882
  }));
706
- totalFrames += 352;
707
- packetCount++;
708
- firstPacket = false;
709
- if (packetCount % 100 === 0) this.#context.logger.debug("[multiplexer]", `Sent ${packetCount} packets to ${this.#targets.length} device(s)`);
710
- const sleepTime = totalFrames / sampleRate * 1e3 - (performance.now() - startTime);
711
- if (sleepTime > 0) {
712
- slowCount = 0;
713
- await this.#sleep(sleepTime);
714
- } else {
715
- const framesBehind = Math.floor(-sleepTime / 1e3 * sampleRate);
716
- if (framesBehind >= 352) {
717
- const extraPackets = Math.min(Math.floor(framesBehind / 352), MAX_PACKETS_COMPENSATE);
718
- for (let i = 0; i < extraPackets; i++) {
719
- let extraFrames = await source.readFrames(352);
720
- if (!extraFrames || extraFrames.length === 0) break;
721
- if (extraFrames.length < packetSize) {
722
- const padded = Buffer.alloc(packetSize, 0);
723
- extraFrames.copy(padded);
724
- extraFrames = padded;
725
- }
726
- await Promise.all(this.#targets.map(async (target) => {
727
- await target.stream.sendFrameData(extraFrames, false);
728
- }));
729
- totalFrames += 352;
730
- packetCount++;
731
- }
732
- }
733
- slowCount++;
734
- if (slowCount >= SLOW_WARNING_THRESHOLD) {
735
- this.#context.logger.warn("[multiplexer]", `Stream behind schedule (${slowCount} consecutive, ${Math.abs(sleepTime).toFixed(1)}ms behind)`);
736
- slowCount = 0;
737
- }
738
- }
739
- }
883
+ return AUDIO_FRAMES_PER_PACKET;
884
+ };
885
+ const packetCount = await streamWithTiming(sendPacket, {
886
+ sampleRate,
887
+ logger: this.#context.logger,
888
+ logPrefix: "[multiplexer]"
889
+ });
740
890
  this.#context.logger.info("[multiplexer]", `Multi-room stream finished, sent ${packetCount} packets to ${this.#targets.length} device(s)`);
741
891
  await Promise.all(this.#targets.map(async (target) => {
742
892
  await target.stream.finish();
@@ -747,14 +897,6 @@ var AudioMultiplexer = class {
747
897
  throw err;
748
898
  }
749
899
  }
750
- /**
751
- * Sleeps for the given number of milliseconds.
752
- *
753
- * @param ms - Duration to sleep in milliseconds.
754
- */
755
- #sleep(ms) {
756
- return new Promise((resolve) => setTimeout(resolve, ms));
757
- }
758
900
  };
759
901
 
760
902
  //#endregion
@@ -6587,7 +6729,7 @@ function assertExtendee(extension, message) {
6587
6729
  /**
6588
6730
  * Describes the file ProtocolMessage.proto.
6589
6731
  */
6590
- const file_ProtocolMessage = /* @__PURE__ */ fileDesc("ChVQcm90b2NvbE1lc3NhZ2UucHJvdG8i4RQKCUVycm9yQ29kZSLTFAoERW51bRILCgdOb0Vycm9yEAASEAoMVW5rbm93bkVycm9yEAESFAoQSW52YWxpZE9wZXJhdGlvbhACEhkKFU9wZXJhdGlvbk5vdFBlcm1pdHRlZBADEhYKEkNsaWVudERvZXNOb3RFeGlzdBAEEhYKEk9yaWdpbkRvZXNOb3RFeGlzdBAFEhgKFFVuc3VwcG9ydGVkT3BlcmF0aW9uEAYSGgoWRmFpbGVkVG9TZXRQaWNrZWRSb3V0ZRAHEiAKHEZhaWxlZFRvUmVnaXN0ZXJDdXN0b21PcmlnaW4QCBIeChpGYWlsZWRUb1JlbW92ZUN1c3RvbU9yaWdpbhAJEiYKIlRoZUFwcGxpY2F0aW9uQWN0aXZpdHlEb2VzTm90RXhpc3QQChIuCipUaGVBcHBIYXNOb3RTZXR1cEFCcm93c2FibGVDb250ZW50RW5kcG9pbnQQCxJBCj1UaGVSZXF1ZXN0ZWRCcm93c2FibGVDb250ZW50QXBpSXNOb3RTdXBwb3J0ZWRCeVRoZUFwcGxpY2F0aW9uEAwSMgouVGhlTm90ZmljYXRpb25IYXNOb3RCZWVuV2hpdGVsaXN0ZWRCeVRoZVNlcnZlchANEjgKNE9wZXJhdGlvblJlcXVpcmVzQUNsaWVudENhbGxiYWNrVG9IYXZlQmVlblJlZ2lzdGVyZWQQDhI6CjZPcGVyYXRpb25SZXF1aXJlc0FDbGllbnREYXRhU291cmNlVG9IYXZlQmVlblJlZ2lzdGVyZWQQDxI1CjFSZXF1ZXN0ZWREYXRhSXNPdXRPZkRhdGVBbmRTaG91bGRCZVJlcXVlc3RlZEFnYWluEBASMAosVGhlRGV2aWNlc0VuZm9yY2VkVm9sdW1lTGltaXRIYXNCZWVuRXhjZWVkZWQQERIbChdWb2x1bWVWYWx1ZUlzT3V0T2ZSYW5nZRASEiQKIFZvbHVtZUlzQWxyZWFkeUF0VGhlTWF4aW11bVZhbHVlEBMSGAoUVm9sdW1lSXNBbHJlYWR5TXV0ZWQQFBIiCh5Wb2ljZUlucHV0RW5kcG9pbnREb2VzTm90RXhpc3QQFRI0CjBUaGVWb2ljZUlucHV0RGV2aWNlSXNOb3RSZWdpc3RlcmVkT3JEb2VzTm90RXhpc3QQFhIVChFFbmNyeXB0aW9uRmFpbHVyZRAXEhgKFEVuZHBvaW50RG9lc05vdEV4aXN0EBgSLgoqVGhlQ2xpZW50c0FwcGxpY2F0aW9uQ2FuY2VsbGVkVGhlT3BlcmF0aW9uEBkSGAoUVGhlT3BlcmF0aW9uVGltZWRPdXQQGhIqCiZUaGVTcGVjaWZpZWRQbGF5ZXJQYXRoT2JqZWN0V2FzSW52YWxpZBAbEjoKNkFkZGluZ09yUmVtb3ZpbmdEZXZpY2VzRnJvbVRoZUF2T3V0cHV0Q29udGV4dEhhc0ZhaWxlZBAcEiwKKENvdWxkTm90RmluZFRoZVNwZWNpZmllZE5vd1BsYXlpbmdQbGF5ZXIQHRInCiNUaGVTcGVjaWZpZWRDb250ZW50SXRlbURvZXNOb3RFeGlzdBAeEh8KG1RoZVNwZWNpZmllZE9mZnNldElzSW52YWxpZBAfEiYKIlRoZVNwZWNpZmllZE91dHB1dENvbnRleHRJc0ludmFsaWQQIBIyCi5PbmVPck1vcmVTcGVjaWZpZWRPdXRwdXREZXZpY2VzQXJlTm90R3JvdXBhYmxlECESSApEVGhlU3BlY2lmaWVkT3V0cHV0Q29udGV4dERvZXNOb3RTdXBwb3J0QWRkaW5nTW9yZVRoYW5PbmVPdXRwdXREZXZpY2UQIhIsCihDb3VsZE5vdEZpbmRUaGVTcGVjaWZpZWROb3dQbGF5aW5nQ2xpZW50ECMSUApMRW5kcG9pbnRWb2x1bWVDb250cm9sSXNPbmx5UG9zc2libGVJZlRoZUVuZHBvaW50SXNQaWNrZWRPclJlbW90ZUNvbnRyb2xsYWJsZRAkElQKUE91dHB1dERldmljZVZvbHVtZUNvbnRyb2xJc09ubHlQb3NzaWJsZUlmVGhlRW5kcG9pbnRJc1BpY2tlZE9yUmVtb3RlQ29udHJvbGxhYmxlECUSIgoeQ29kZXJNdXN0U3VwcG9ydEtleVZhbHVlQ29kaW5nECYSJAogQ291bGROb3RGaW5kVGhlR2l2ZW5PdXRwdXRkZXZpY2UQJxIhCh1GYWlsZWRUb0Nvbm5lY3RUb1JlbW90ZURldmljZRBkEiAKHEF1dGhlbnRpY2F0aW9uVG9rZW5Jc0ludmFsaWQQZRIzCi9SZWNvcmRpbmdTZXNzaW9uSXNBbHJlYWR5SW5Qcm9ncmVzc09uVGhpc0RldmljZRBmEiQKIFRoZURldmljZUlzTm90Q3VycmVudGx5UmVjb3JkaW5nEGcSHAoYVGhlQ2xpZW50SGFzRGlzY29ubmVjdGVkEGgSHAoYVGhlU2VydmVySGFzRGlzY29ubmVjdGVkEGkSLAooVGhlQ29ubmVjdGlvbkhhc0JlZW5DYW5jZWxsZWRCeVRoZUNsaWVudBBqEjQKMFBhaXJpbmdGdW5jdGlvbmFsaXR5SXNMb2NrZWREdWVUb1NlY3VyaXR5UmVhc29ucxBrEiwKKFRoZUNsaWVudHNPcGVyYXRpbmdTeXN0ZW1WZXJzaW9uSXNUb29PbGQQbBIoCiRUaGVDbGllbnRzQXBwbGljYXRpb25WZXJzaW9uSXNUb29PbGQQbRIYChRUaGVEZXZpY2VJc05vdFBhaXJlZBBuEj8KO1RoZVBpblBhaXJpbmdEaWFsb2dXYXNSZW1vdmVkQnlUaGVVc2VyQmVmb3JlUGFpcmluZ09jY291cmVkEG8SQAo8VGhlUGluUGFpcmluZ0RpYWxvZ1dhc1JlbW92ZWRCeUFUaW1lb3V0QmVmb3JlUGFpcmluZ09jY291cmVkEHASGQoVVGhlQ29ubmVjdGlvblRpbWVkb3V0EHESIgoeUGFpcmluZ1dpdGhUaGlzRGV2aWNlSXNCbG9ja2VkEHISGwoXVGhlRGV2aWNlSXNHb2luZ1RvU2xlZXAQcxIdChlDb25uZWN0aW9uQmxvY2tlZEJ5U2VydmVyEHQSPAo4TXJhdmVuZHBvaW50V2FzRGVhbGxvY2F0ZWRXaGlsZVdhaXRpbmdGb3JEZXZpY2VUb0Nvbm5lY3QQdRJICkNPdXRwdXRDb250ZXh0TW9kaWZpY2F0aW9uQ2F1c2VkQURldmljZVRvTm9Mb25nZXJCZUFQcm94eUdyb3VwUGxheWVyEMgBEkQKP091dHB1dENvbnRleHRNb2RpZmljYXRpb25DYXVzZWRBRGV2aWNlVG9CZWNvbWVBUHJveHlHcm91cFBsYXllchDJARI3CjJPdXRwdXRDb250ZXh0TW9kaWZpY2F0aW9uUmVxdWVzdGVkTm9Ub3BvbG9neUNoYW5nZRDKARIWChFPdGhlclVua25vd25FcnJvchCrAiKlHwoPUHJvdG9jb2xNZXNzYWdlEiMKBHR5cGUYASABKA4yFS5Qcm90b2NvbE1lc3NhZ2UuVHlwZRISCgppZGVudGlmaWVyGAIgASgJEhsKE2F1dGhlbnRpY2F0aW9uVG9rZW4YAyABKAkSIgoJZXJyb3JDb2RlGAQgASgOMg8uRXJyb3JDb2RlLkVudW0SEQoJdGltZXN0YW1wGAUgASgEEhgKEGVycm9yRGVzY3JpcHRpb24YTiABKAkSGAoQdW5pcXVlSWRlbnRpZmllchhVIAEoCSK6HQoEVHlwZRITCg9VTktOT1dOX01FU1NBR0UQABIYChRTRU5EX0NPTU1BTkRfTUVTU0FHRRABEh8KG1NFTkRfQ09NTUFORF9SRVNVTFRfTUVTU0FHRRACEhUKEUdFVF9TVEFURV9NRVNTQUdFEAMSFQoRU0VUX1NUQVRFX01FU1NBR0UQBBIXChNTRVRfQVJUV09SS19NRVNTQUdFEAUSHwobUkVHSVNURVJfSElEX0RFVklDRV9NRVNTQUdFEAYSJgoiUkVHSVNURVJfSElEX0RFVklDRV9SRVNVTFRfTUVTU0FHRRAHEhoKFlNFTkRfSElEX0VWRU5UX01FU1NBR0UQCBIbChdTRU5EX0hJRF9SRVBPUlRfTUVTU0FHRRAJEiQKIFNFTkRfVklSVFVBTF9UT1VDSF9FVkVOVF9NRVNTQUdFEAoSGAoUTk9USUZJQ0FUSU9OX01FU1NBR0UQCxIuCipDT05URU5UX0lURU1TX0NIQU5HRURfTk9USUZJQ0FUSU9OX01FU1NBR0UQDBIXChNERVZJQ0VfSU5GT19NRVNTQUdFEA8SIQodQ0xJRU5UX1VQREFURVNfQ09ORklHX01FU1NBR0UQEBInCiNWT0xVTUVfQ09OVFJPTF9BVkFJTEFCSUxJVFlfTUVTU0FHRRAREhsKF0dBTUVfQ09OVFJPTExFUl9NRVNTQUdFEBISJAogUkVHSVNURVJfR0FNRV9DT05UUk9MTEVSX01FU1NBR0UQExItCilSRUdJU1RFUl9HQU1FX0NPTlRST0xMRVJfUkVTUE9OU0VfTUVTU0FHRRAUEiYKIlVOUkVHSVNURVJfR0FNRV9DT05UUk9MTEVSX01FU1NBR0UQFRIvCitSRUdJU1RFUl9GT1JfR0FNRV9DT05UUk9MTEVSX0VWRU5UU19NRVNTQUdFEBYSFAoQS0VZQk9BUkRfTUVTU0FHRRAXEiAKHEdFVF9LRVlCT0FSRF9TRVNTSU9OX01FU1NBR0UQGBIWChJURVhUX0lOUFVUX01FU1NBR0UQGRIjCh9HRVRfVk9JQ0VfSU5QVVRfREVWSUNFU19NRVNTQUdFEBoSLAooR0VUX1ZPSUNFX0lOUFVUX0RFVklDRVNfUkVTUE9OU0VfTUVTU0FHRRAbEicKI1JFR0lTVEVSX1ZPSUNFX0lOUFVUX0RFVklDRV9NRVNTQUdFEBwSMAosUkVHSVNURVJfVk9JQ0VfSU5QVVRfREVWSUNFX1JFU1BPTlNFX01FU1NBR0UQHRIfChtTRVRfUkVDT1JESU5HX1NUQVRFX01FU1NBR0UQHhIcChhTRU5EX1ZPSUNFX0lOUFVUX01FU1NBR0UQHxIiCh5QTEFZQkFDS19RVUVVRV9SRVFVRVNUX01FU1NBR0UQIBIXChNUUkFOU0FDVElPTl9NRVNTQUdFECESGgoWQ1JZUFRPX1BBSVJJTkdfTUVTU0FHRRAiEiYKIkdBTUVfQ09OVFJPTExFUl9QUk9QRVJUSUVTX01FU1NBR0UQIxIbChdTRVRfUkVBRFlfU1RBVEVfTUVTU0FHRRAkEh4KGkRFVklDRV9JTkZPX1VQREFURV9NRVNTQUdFECUSIAocU0VUX0NPTk5FQ1RJT05fU1RBVEVfTUVTU0FHRRAmEh0KGVNFTkRfQlVUVE9OX0VWRU5UX01FU1NBR0UQJxIbChdTRVRfSElMSVRFX01PREVfTUVTU0FHRRAoEhcKE1dBS0VfREVWSUNFX01FU1NBR0UQKRITCg9HRU5FUklDX01FU1NBR0UQKhIrCidTRU5EX1BBQ0tFRF9WSVJUVUFMX1RPVUNIX0VWRU5UX01FU1NBR0UQKxIVChFTRU5EX0xZUklDU19FVkVOVBAsEiIKHlNFVF9OT1dfUExBWUlOR19DTElFTlRfTUVTU0FHRRAuEiIKHlNFVF9OT1dfUExBWUlOR19QTEFZRVJfTUVTU0FHRRAvEikKJU1PRElGWV9PVVRQVVRfQ09OVEVYVF9SRVFVRVNUX01FU1NBR0UQMBIWChJHRVRfVk9MVU1FX01FU1NBR0UQMRIdChlHRVRfVk9MVU1FX1JFU1VMVF9NRVNTQUdFEDISFgoSU0VUX1ZPTFVNRV9NRVNTQUdFEDMSHQoZVk9MVU1FX0RJRF9DSEFOR0VfTUVTU0FHRRA0EhkKFVJFTU9WRV9DTElFTlRfTUVTU0FHRRA1EhkKFVJFTU9WRV9QTEFZRVJfTUVTU0FHRRA2EhkKFVVQREFURV9DTElFTlRfTUVTU0FHRRA3Eh8KG1VQREFURV9DT05URU5UX0lURU1fTUVTU0FHRRA4EicKI1VQREFURV9DT05URU5UX0lURU1fQVJUV09SS19NRVNTQUdFEDkSGQoVVVBEQVRFX1BMQVlFUl9NRVNTQUdFEDoSKgomUFJPTVBUX0ZPUl9ST1VURV9BVVRIT1JJWkFUSU9OX01FU1NBR0UQOxIzCi9QUk9NUFRfRk9SX1JPVVRFX0FVVEhPUklaQVRJT05fUkVTUE9OU0VfTUVTU0FHRRA8Ei4KKlBSRVNFTlRfUk9VVEVfQVVUSE9SSVpBVElPTl9TVEFUVVNfTUVTU0FHRRA9EisKJ0dFVF9WT0xVTUVfQ09OVFJPTF9DQVBBQklMSVRJRVNfTUVTU0FHRRA+EjIKLkdFVF9WT0xVTUVfQ09OVFJPTF9DQVBBQklMSVRJRVNfUkVTVUxUX01FU1NBR0UQPxIyCi5WT0xVTUVfQ09OVFJPTF9DQVBBQklMSVRJRVNfRElEX0NIQU5HRV9NRVNTQUdFEEASIAocVVBEQVRFX09VVFBVVF9ERVZJQ0VfTUVTU0FHRRBBEiEKHVJFTU9WRV9PVVRQVVRfREVWSUNFU19NRVNTQUdFEEISHQoZUkVNT1RFX1RFWFRfSU5QVVRfTUVTU0FHRRBDEikKJUdFVF9SRU1PVEVfVEVYVF9JTlBVVF9TRVNTSU9OX01FU1NBR0UQRBIiCh5SRU1PVkVfT1VUUFVUX0RFVklDRVNfTUVTU0FHRTIQRRIkCiBQTEFZQkFDS19TRVNTSU9OX1JFUVVFU1RfTUVTU0FHRRBGEiUKIVBMQVlCQUNLX1NFU1NJT05fUkVTUE9OU0VfTUVTU0FHRRBHEioKJlNFVF9ERUZBVUxUX1NVUFBPUlRFRF9DT01NQU5EU19NRVNTQUdFEEgSLAooUExBWUJBQ0tfU0VTU0lPTl9NSUdSQVRFX1JFUVVFU1RfTUVTU0FHRRBJEi0KKVBMQVlCQUNLX1NFU1NJT05fTUlHUkFURV9SRVNQT05TRV9NRVNTQUdFEEoSKgomUExBWUJBQ0tfU0VTU0lPTl9NSUdSQVRFX0JFR0lOX01FU1NBR0UQSxIoCiRQTEFZQkFDS19TRVNTSU9OX01JR1JBVEVfRU5EX01FU1NBR0UQTBIpCiVVUERBVEVfQUNUSVZFX1NZU1RFTV9FTkRQT0lOVF9NRVNTQUdFEE0SHgoaU0VUX0RJU0NPVkVSWV9NT0RFX01FU1NBR0UQZRIdChlVUERBVEVfRU5EX1BPSU5UU19NRVNTQUdFEGYSHAoYUkVNT1ZFX0VORFBPSU5UU19NRVNTQUdFEGcSJAogUExBWUVSX0NMSUVOVF9QUk9QRVJUSUVTX01FU1NBR0UQaBIkCiBPUklHSU5fQ0xJRU5UX1BST1BFUlRJRVNfTUVTU0FHRRBpEhYKEkFVRElPX0ZBREVfTUVTU0FHRRBqEh8KG0FVRElPX0ZBREVfUkVTUE9OU0VfTUVTU0FHRRBrEikKJVBMQVlCQUNLX1NFU1NJT05fTUlHUkFURV9QT1NUX01FU1NBR0UQbBIuCipTRVRfQ09OVkVSU0FUSU9OX0RFVEVDVElPTl9FTkFCTEVEX01FU1NBR0UQbRItCilQTEFZRVJfQ0xJRU5UX1BBUlRJQ0lQQU5UU19VUERBVEVfTUVTU0FHRRBuEikKJU1JQ1JPUEhPTkVfQ09OTkVDVElPTl9SRVFVRVNUX01FU1NBR0UQbxIqCiZNSUNST1BIT05FX0NPTk5FQ1RJT05fUkVTUE9OU0VfTUVTU0FHRRBwEikKJUNSRUFURV9BUFBMSUNBVElPTl9DT05ORUNUSU9OX01FU1NBR0UQcRIqCiZDUkVBVEVfSE9TVEVEX0VORFBPSU5UX1JFUVVFU1RfTUVTU0FHRRByEisKJ0NSRUFURV9IT1NURURfRU5EUE9JTlRfUkVTUE9OU0VfTUVTU0FHRRBzEiEKHVJFUVVFU1RfR1JPVVBfU0VTU0lPTl9NRVNTQUdFEHQSJwojR1JPVVBfU0VTU0lPTl9KT0lOX1JFU1BPTlNFX01FU1NBR0UQdRIjCh9HUk9VUF9TRVNTSU9OX0ZBU1RfU1lOQ19NRVNTQUdFEHYSKAokR1JPVVBfU0VTU0lPTl9JREVOVElUWV9TSEFSRV9NRVNTQUdFEHcSIAocQ09ORklHVVJFX0NPTk5FQ1RJT05fTUVTU0FHRRB4Ei4KKkdST1VQX1NFU1NJT05fSURFTlRJVFlfU0hBUkVfUkVQTFlfTUVTU0FHRRB5EioKJkdST1VQX1NFU1NJT05fTEVBREVSX0RJU0NPVkVSWV9NRVNTQUdFEHoSJQohR1JPVVBfU0VTU0lPTl9NRU1CRVJfU1lOQ19NRVNTQUdFEHsSJQohR1JPVVBfU0VTU0lPTl9FUlJPUl9SRVBMWV9NRVNTQUdFEHwSMQotTk9XX1BMQVlJTkdfQVVESU9fRk9STUFUX0NPTlRFTlRfSU5GT19NRVNTQUdFEH0SHAoYR0VUX1ZPTFVNRV9NVVRFRF9NRVNTQUdFEH4SIwofR0VUX1ZPTFVNRV9NVVRFRF9SRVNVTFRfTUVTU0FHRRB/Eh0KGFNFVF9WT0xVTUVfTVVURURfTUVTU0FHRRCAARIkCh9WT0xVTUVfTVVURURfRElEX0NIQU5HRV9NRVNTQUdFEIEBKgQIBhBOKgQITxBVKggIVhCAgICAAg");
6732
+ const file_ProtocolMessage = /* @__PURE__ */ fileDesc("ChVQcm90b2NvbE1lc3NhZ2UucHJvdG8i4RQKCUVycm9yQ29kZSLTFAoERW51bRILCgdOb0Vycm9yEAASEAoMVW5rbm93bkVycm9yEAESFAoQSW52YWxpZE9wZXJhdGlvbhACEhkKFU9wZXJhdGlvbk5vdFBlcm1pdHRlZBADEhYKEkNsaWVudERvZXNOb3RFeGlzdBAEEhYKEk9yaWdpbkRvZXNOb3RFeGlzdBAFEhgKFFVuc3VwcG9ydGVkT3BlcmF0aW9uEAYSGgoWRmFpbGVkVG9TZXRQaWNrZWRSb3V0ZRAHEiAKHEZhaWxlZFRvUmVnaXN0ZXJDdXN0b21PcmlnaW4QCBIeChpGYWlsZWRUb1JlbW92ZUN1c3RvbU9yaWdpbhAJEiYKIlRoZUFwcGxpY2F0aW9uQWN0aXZpdHlEb2VzTm90RXhpc3QQChIuCipUaGVBcHBIYXNOb3RTZXR1cEFCcm93c2FibGVDb250ZW50RW5kcG9pbnQQCxJBCj1UaGVSZXF1ZXN0ZWRCcm93c2FibGVDb250ZW50QXBpSXNOb3RTdXBwb3J0ZWRCeVRoZUFwcGxpY2F0aW9uEAwSMgouVGhlTm90ZmljYXRpb25IYXNOb3RCZWVuV2hpdGVsaXN0ZWRCeVRoZVNlcnZlchANEjgKNE9wZXJhdGlvblJlcXVpcmVzQUNsaWVudENhbGxiYWNrVG9IYXZlQmVlblJlZ2lzdGVyZWQQDhI6CjZPcGVyYXRpb25SZXF1aXJlc0FDbGllbnREYXRhU291cmNlVG9IYXZlQmVlblJlZ2lzdGVyZWQQDxI1CjFSZXF1ZXN0ZWREYXRhSXNPdXRPZkRhdGVBbmRTaG91bGRCZVJlcXVlc3RlZEFnYWluEBASMAosVGhlRGV2aWNlc0VuZm9yY2VkVm9sdW1lTGltaXRIYXNCZWVuRXhjZWVkZWQQERIbChdWb2x1bWVWYWx1ZUlzT3V0T2ZSYW5nZRASEiQKIFZvbHVtZUlzQWxyZWFkeUF0VGhlTWF4aW11bVZhbHVlEBMSGAoUVm9sdW1lSXNBbHJlYWR5TXV0ZWQQFBIiCh5Wb2ljZUlucHV0RW5kcG9pbnREb2VzTm90RXhpc3QQFRI0CjBUaGVWb2ljZUlucHV0RGV2aWNlSXNOb3RSZWdpc3RlcmVkT3JEb2VzTm90RXhpc3QQFhIVChFFbmNyeXB0aW9uRmFpbHVyZRAXEhgKFEVuZHBvaW50RG9lc05vdEV4aXN0EBgSLgoqVGhlQ2xpZW50c0FwcGxpY2F0aW9uQ2FuY2VsbGVkVGhlT3BlcmF0aW9uEBkSGAoUVGhlT3BlcmF0aW9uVGltZWRPdXQQGhIqCiZUaGVTcGVjaWZpZWRQbGF5ZXJQYXRoT2JqZWN0V2FzSW52YWxpZBAbEjoKNkFkZGluZ09yUmVtb3ZpbmdEZXZpY2VzRnJvbVRoZUF2T3V0cHV0Q29udGV4dEhhc0ZhaWxlZBAcEiwKKENvdWxkTm90RmluZFRoZVNwZWNpZmllZE5vd1BsYXlpbmdQbGF5ZXIQHRInCiNUaGVTcGVjaWZpZWRDb250ZW50SXRlbURvZXNOb3RFeGlzdBAeEh8KG1RoZVNwZWNpZmllZE9mZnNldElzSW52YWxpZBAfEiYKIlRoZVNwZWNpZmllZE91dHB1dENvbnRleHRJc0ludmFsaWQQIBIyCi5PbmVPck1vcmVTcGVjaWZpZWRPdXRwdXREZXZpY2VzQXJlTm90R3JvdXBhYmxlECESSApEVGhlU3BlY2lmaWVkT3V0cHV0Q29udGV4dERvZXNOb3RTdXBwb3J0QWRkaW5nTW9yZVRoYW5PbmVPdXRwdXREZXZpY2UQIhIsCihDb3VsZE5vdEZpbmRUaGVTcGVjaWZpZWROb3dQbGF5aW5nQ2xpZW50ECMSUApMRW5kcG9pbnRWb2x1bWVDb250cm9sSXNPbmx5UG9zc2libGVJZlRoZUVuZHBvaW50SXNQaWNrZWRPclJlbW90ZUNvbnRyb2xsYWJsZRAkElQKUE91dHB1dERldmljZVZvbHVtZUNvbnRyb2xJc09ubHlQb3NzaWJsZUlmVGhlRW5kcG9pbnRJc1BpY2tlZE9yUmVtb3RlQ29udHJvbGxhYmxlECUSIgoeQ29kZXJNdXN0U3VwcG9ydEtleVZhbHVlQ29kaW5nECYSJAogQ291bGROb3RGaW5kVGhlR2l2ZW5PdXRwdXRkZXZpY2UQJxIhCh1GYWlsZWRUb0Nvbm5lY3RUb1JlbW90ZURldmljZRBkEiAKHEF1dGhlbnRpY2F0aW9uVG9rZW5Jc0ludmFsaWQQZRIzCi9SZWNvcmRpbmdTZXNzaW9uSXNBbHJlYWR5SW5Qcm9ncmVzc09uVGhpc0RldmljZRBmEiQKIFRoZURldmljZUlzTm90Q3VycmVudGx5UmVjb3JkaW5nEGcSHAoYVGhlQ2xpZW50SGFzRGlzY29ubmVjdGVkEGgSHAoYVGhlU2VydmVySGFzRGlzY29ubmVjdGVkEGkSLAooVGhlQ29ubmVjdGlvbkhhc0JlZW5DYW5jZWxsZWRCeVRoZUNsaWVudBBqEjQKMFBhaXJpbmdGdW5jdGlvbmFsaXR5SXNMb2NrZWREdWVUb1NlY3VyaXR5UmVhc29ucxBrEiwKKFRoZUNsaWVudHNPcGVyYXRpbmdTeXN0ZW1WZXJzaW9uSXNUb29PbGQQbBIoCiRUaGVDbGllbnRzQXBwbGljYXRpb25WZXJzaW9uSXNUb29PbGQQbRIYChRUaGVEZXZpY2VJc05vdFBhaXJlZBBuEj8KO1RoZVBpblBhaXJpbmdEaWFsb2dXYXNSZW1vdmVkQnlUaGVVc2VyQmVmb3JlUGFpcmluZ09jY291cmVkEG8SQAo8VGhlUGluUGFpcmluZ0RpYWxvZ1dhc1JlbW92ZWRCeUFUaW1lb3V0QmVmb3JlUGFpcmluZ09jY291cmVkEHASGQoVVGhlQ29ubmVjdGlvblRpbWVkb3V0EHESIgoeUGFpcmluZ1dpdGhUaGlzRGV2aWNlSXNCbG9ja2VkEHISGwoXVGhlRGV2aWNlSXNHb2luZ1RvU2xlZXAQcxIdChlDb25uZWN0aW9uQmxvY2tlZEJ5U2VydmVyEHQSPAo4TXJhdmVuZHBvaW50V2FzRGVhbGxvY2F0ZWRXaGlsZVdhaXRpbmdGb3JEZXZpY2VUb0Nvbm5lY3QQdRJICkNPdXRwdXRDb250ZXh0TW9kaWZpY2F0aW9uQ2F1c2VkQURldmljZVRvTm9Mb25nZXJCZUFQcm94eUdyb3VwUGxheWVyEMgBEkQKP091dHB1dENvbnRleHRNb2RpZmljYXRpb25DYXVzZWRBRGV2aWNlVG9CZWNvbWVBUHJveHlHcm91cFBsYXllchDJARI3CjJPdXRwdXRDb250ZXh0TW9kaWZpY2F0aW9uUmVxdWVzdGVkTm9Ub3BvbG9neUNoYW5nZRDKARIWChFPdGhlclVua25vd25FcnJvchCrAiKEHwoPUHJvdG9jb2xNZXNzYWdlEiMKBHR5cGUYASABKA4yFS5Qcm90b2NvbE1lc3NhZ2UuVHlwZRISCgppZGVudGlmaWVyGAIgASgJEhsKE2F1dGhlbnRpY2F0aW9uVG9rZW4YAyABKAkSIgoJZXJyb3JDb2RlGAQgASgOMg8uRXJyb3JDb2RlLkVudW0SEQoJdGltZXN0YW1wGAUgASgEEhgKEGVycm9yRGVzY3JpcHRpb24YTiABKAkSGAoQdW5pcXVlSWRlbnRpZmllchhVIAEoCSKZHQoEVHlwZRITCg9VTktOT1dOX01FU1NBR0UQABIYChRTRU5EX0NPTU1BTkRfTUVTU0FHRRABEh8KG1NFTkRfQ09NTUFORF9SRVNVTFRfTUVTU0FHRRACEhUKEUdFVF9TVEFURV9NRVNTQUdFEAMSFQoRU0VUX1NUQVRFX01FU1NBR0UQBBIXChNTRVRfQVJUV09SS19NRVNTQUdFEAUSHwobUkVHSVNURVJfSElEX0RFVklDRV9NRVNTQUdFEAYSJgoiUkVHSVNURVJfSElEX0RFVklDRV9SRVNVTFRfTUVTU0FHRRAHEhoKFlNFTkRfSElEX0VWRU5UX01FU1NBR0UQCBIbChdTRU5EX0hJRF9SRVBPUlRfTUVTU0FHRRAJEiQKIFNFTkRfVklSVFVBTF9UT1VDSF9FVkVOVF9NRVNTQUdFEAoSGAoUTk9USUZJQ0FUSU9OX01FU1NBR0UQCxIuCipDT05URU5UX0lURU1TX0NIQU5HRURfTk9USUZJQ0FUSU9OX01FU1NBR0UQDBIXChNERVZJQ0VfSU5GT19NRVNTQUdFEA8SIQodQ0xJRU5UX1VQREFURVNfQ09ORklHX01FU1NBR0UQEBInCiNWT0xVTUVfQ09OVFJPTF9BVkFJTEFCSUxJVFlfTUVTU0FHRRAREhsKF0dBTUVfQ09OVFJPTExFUl9NRVNTQUdFEBISJAogUkVHSVNURVJfR0FNRV9DT05UUk9MTEVSX01FU1NBR0UQExItCilSRUdJU1RFUl9HQU1FX0NPTlRST0xMRVJfUkVTUE9OU0VfTUVTU0FHRRAUEiYKIlVOUkVHSVNURVJfR0FNRV9DT05UUk9MTEVSX01FU1NBR0UQFRIvCitSRUdJU1RFUl9GT1JfR0FNRV9DT05UUk9MTEVSX0VWRU5UU19NRVNTQUdFEBYSFAoQS0VZQk9BUkRfTUVTU0FHRRAXEiAKHEdFVF9LRVlCT0FSRF9TRVNTSU9OX01FU1NBR0UQGBIWChJURVhUX0lOUFVUX01FU1NBR0UQGRIjCh9HRVRfVk9JQ0VfSU5QVVRfREVWSUNFU19NRVNTQUdFEBoSLAooR0VUX1ZPSUNFX0lOUFVUX0RFVklDRVNfUkVTUE9OU0VfTUVTU0FHRRAbEicKI1JFR0lTVEVSX1ZPSUNFX0lOUFVUX0RFVklDRV9NRVNTQUdFEBwSMAosUkVHSVNURVJfVk9JQ0VfSU5QVVRfREVWSUNFX1JFU1BPTlNFX01FU1NBR0UQHRIfChtTRVRfUkVDT1JESU5HX1NUQVRFX01FU1NBR0UQHhIcChhTRU5EX1ZPSUNFX0lOUFVUX01FU1NBR0UQHxIiCh5QTEFZQkFDS19RVUVVRV9SRVFVRVNUX01FU1NBR0UQIBIXChNUUkFOU0FDVElPTl9NRVNTQUdFECESGgoWQ1JZUFRPX1BBSVJJTkdfTUVTU0FHRRAiEiYKIkdBTUVfQ09OVFJPTExFUl9QUk9QRVJUSUVTX01FU1NBR0UQIxIbChdTRVRfUkVBRFlfU1RBVEVfTUVTU0FHRRAkEh4KGkRFVklDRV9JTkZPX1VQREFURV9NRVNTQUdFECUSIAocU0VUX0NPTk5FQ1RJT05fU1RBVEVfTUVTU0FHRRAmEh0KGVNFTkRfQlVUVE9OX0VWRU5UX01FU1NBR0UQJxIbChdTRVRfSElMSVRFX01PREVfTUVTU0FHRRAoEhcKE1dBS0VfREVWSUNFX01FU1NBR0UQKRITCg9HRU5FUklDX01FU1NBR0UQKhIrCidTRU5EX1BBQ0tFRF9WSVJUVUFMX1RPVUNIX0VWRU5UX01FU1NBR0UQKxIVChFTRU5EX0xZUklDU19FVkVOVBAsEiIKHlNFVF9OT1dfUExBWUlOR19DTElFTlRfTUVTU0FHRRAuEiIKHlNFVF9OT1dfUExBWUlOR19QTEFZRVJfTUVTU0FHRRAvEikKJU1PRElGWV9PVVRQVVRfQ09OVEVYVF9SRVFVRVNUX01FU1NBR0UQMBIWChJHRVRfVk9MVU1FX01FU1NBR0UQMRIdChlHRVRfVk9MVU1FX1JFU1VMVF9NRVNTQUdFEDISFgoSU0VUX1ZPTFVNRV9NRVNTQUdFEDMSHQoZVk9MVU1FX0RJRF9DSEFOR0VfTUVTU0FHRRA0EhkKFVJFTU9WRV9DTElFTlRfTUVTU0FHRRA1EhkKFVJFTU9WRV9QTEFZRVJfTUVTU0FHRRA2EhkKFVVQREFURV9DTElFTlRfTUVTU0FHRRA3Eh8KG1VQREFURV9DT05URU5UX0lURU1fTUVTU0FHRRA4EicKI1VQREFURV9DT05URU5UX0lURU1fQVJUV09SS19NRVNTQUdFEDkSGQoVVVBEQVRFX1BMQVlFUl9NRVNTQUdFEDoSKgomUFJPTVBUX0ZPUl9ST1VURV9BVVRIT1JJWkFUSU9OX01FU1NBR0UQOxIzCi9QUk9NUFRfRk9SX1JPVVRFX0FVVEhPUklaQVRJT05fUkVTUE9OU0VfTUVTU0FHRRA8Ei4KKlBSRVNFTlRfUk9VVEVfQVVUSE9SSVpBVElPTl9TVEFUVVNfTUVTU0FHRRA9EisKJ0dFVF9WT0xVTUVfQ09OVFJPTF9DQVBBQklMSVRJRVNfTUVTU0FHRRA+EjIKLkdFVF9WT0xVTUVfQ09OVFJPTF9DQVBBQklMSVRJRVNfUkVTVUxUX01FU1NBR0UQPxIyCi5WT0xVTUVfQ09OVFJPTF9DQVBBQklMSVRJRVNfRElEX0NIQU5HRV9NRVNTQUdFEEASHwobU1lOQ19PVVRQVVRfREVWSUNFU19NRVNTQUdFEEESKAokUkVNT1ZFX1NZTkNFRF9PVVRQVVRfREVWSUNFU19NRVNTQUdFEEISHQoZUkVNT1RFX1RFWFRfSU5QVVRfTUVTU0FHRRBDEikKJUdFVF9SRU1PVEVfVEVYVF9JTlBVVF9TRVNTSU9OX01FU1NBR0UQRBIkCiBSRU1PVkVfRlJPTV9QQVJFTlRfR1JPVVBfTUVTU0FHRRBFEiQKIFBMQVlCQUNLX1NFU1NJT05fUkVRVUVTVF9NRVNTQUdFEEYSJQohUExBWUJBQ0tfU0VTU0lPTl9SRVNQT05TRV9NRVNTQUdFEEcSKgomU0VUX0RFRkFVTFRfU1VQUE9SVEVEX0NPTU1BTkRTX01FU1NBR0UQSBIsCihQTEFZQkFDS19TRVNTSU9OX01JR1JBVEVfUkVRVUVTVF9NRVNTQUdFEEkSLQopUExBWUJBQ0tfU0VTU0lPTl9NSUdSQVRFX1JFU1BPTlNFX01FU1NBR0UQShIqCiZQTEFZQkFDS19TRVNTSU9OX01JR1JBVEVfQkVHSU5fTUVTU0FHRRBLEigKJFBMQVlCQUNLX1NFU1NJT05fTUlHUkFURV9FTkRfTUVTU0FHRRBMEikKJVVQREFURV9BQ1RJVkVfU1lTVEVNX0VORFBPSU5UX01FU1NBR0UQTRIpCiVQTEFZQkFDS19TRVNTSU9OX01JR1JBVEVfUE9TVF9NRVNTQUdFEE4SHgoaU0VUX0RJU0NPVkVSWV9NT0RFX01FU1NBR0UQZRIjCh9VUERBVEVfU1lOQ0VEX0VORFBPSU5UU19NRVNTQUdFEGYSIwofUkVNT1ZFX1NZTkNFRF9FTkRQT0lOVFNfTUVTU0FHRRBnEiQKIFBMQVlFUl9DTElFTlRfUFJPUEVSVElFU19NRVNTQUdFEGgSJAogT1JJR0lOX0NMSUVOVF9QUk9QRVJUSUVTX01FU1NBR0UQaRIWChJBVURJT19GQURFX01FU1NBR0UQahIfChtBVURJT19GQURFX1JFU1BPTlNFX01FU1NBR0UQaxImCiJESVNDT1ZFUllfVVBEQVRFX0VORFBPSU5UU19NRVNTQUdFEGwSKwonRElTQ09WRVJZX1VQREFURV9PVVRQVVRfREVWSUNFU19NRVNTQUdFEG0SHgoaU0VUX0xJU1RFTklOR19NT0RFX01FU1NBR0UQbhIgChxDT05GSUdVUkVfQ09OTkVDVElPTl9NRVNTQUdFEHgSKgomQ1JFQVRFX0hPU1RFRF9FTkRQT0lOVF9SRVFVRVNUX01FU1NBR0UQeRIrCidDUkVBVEVfSE9TVEVEX0VORFBPSU5UX1JFU1BPTlNFX01FU1NBR0UQehIZChVBREpVU1RfVk9MVU1FX01FU1NBR0UQfRIcChhHRVRfVk9MVU1FX01VVEVEX01FU1NBR0UQfhIjCh9HRVRfVk9MVU1FX01VVEVEX1JFU1VMVF9NRVNTQUdFEH8SHQoYU0VUX1ZPTFVNRV9NVVRFRF9NRVNTQUdFEIABEiQKH1ZPTFVNRV9NVVRFRF9ESURfQ0hBTkdFX01FU1NBR0UQgQESLwoqU0VUX0NPTlZFUlNBVElPTl9ERVRFQ1RJT05fRU5BQkxFRF9NRVNTQUdFEIIBEi4KKVBMQVlFUl9DTElFTlRfUEFSVElDSVBBTlRTX1VQREFURV9NRVNTQUdFEIMBEiIKHVJFUVVFU1RfR1JPVVBfU0VTU0lPTl9NRVNTQUdFEIQBEikKJENPTkZJR1VSRV9DT05ORUNUSU9OX1NFUlZJQ0VfTUVTU0FHRRCFARIqCiVDUkVBVEVfQVBQTElDQVRJT05fQ09OTkVDVElPTl9NRVNTQUdFEIYBEiwKJ0FQUExJQ0FUSU9OX0NPTk5FQ1RJT05fUFJPVE9DT0xfTUVTU0FHRRCHARIuCilJTlZBTElEQVRFX0FQUExJQ0FUSU9OX0NPTk5FQ1RJT05fTUVTU0FHRRCIARIqCiVNSUNST1BIT05FX0NPTk5FQ1RJT05fUkVRVUVTVF9NRVNTQUdFEIkBEisKJk1JQ1JPUEhPTkVfQ09OTkVDVElPTl9SRVNQT05TRV9NRVNTQUdFEIoBKgQIBhBOKgQITxBVKggIVhCAgICAAg");
6591
6733
  /**
6592
6734
  * Describes the message ErrorCode.
6593
6735
  * Use `create(ErrorCodeSchema)` to create a new message.
@@ -7113,13 +7255,17 @@ let ProtocolMessage_Type = /* @__PURE__ */ function(ProtocolMessage_Type) {
7113
7255
  */
7114
7256
  ProtocolMessage_Type[ProtocolMessage_Type["VOLUME_CONTROL_CAPABILITIES_DID_CHANGE_MESSAGE"] = 64] = "VOLUME_CONTROL_CAPABILITIES_DID_CHANGE_MESSAGE";
7115
7257
  /**
7116
- * @generated from enum value: UPDATE_OUTPUT_DEVICE_MESSAGE = 65;
7258
+ * Apple: SyncOutputDevicesMessage
7259
+ *
7260
+ * @generated from enum value: SYNC_OUTPUT_DEVICES_MESSAGE = 65;
7117
7261
  */
7118
- ProtocolMessage_Type[ProtocolMessage_Type["UPDATE_OUTPUT_DEVICE_MESSAGE"] = 65] = "UPDATE_OUTPUT_DEVICE_MESSAGE";
7262
+ ProtocolMessage_Type[ProtocolMessage_Type["SYNC_OUTPUT_DEVICES_MESSAGE"] = 65] = "SYNC_OUTPUT_DEVICES_MESSAGE";
7119
7263
  /**
7120
- * @generated from enum value: REMOVE_OUTPUT_DEVICES_MESSAGE = 66;
7264
+ * Apple: RemoveSyncedOutputDevicesMessage
7265
+ *
7266
+ * @generated from enum value: REMOVE_SYNCED_OUTPUT_DEVICES_MESSAGE = 66;
7121
7267
  */
7122
- ProtocolMessage_Type[ProtocolMessage_Type["REMOVE_OUTPUT_DEVICES_MESSAGE"] = 66] = "REMOVE_OUTPUT_DEVICES_MESSAGE";
7268
+ ProtocolMessage_Type[ProtocolMessage_Type["REMOVE_SYNCED_OUTPUT_DEVICES_MESSAGE"] = 66] = "REMOVE_SYNCED_OUTPUT_DEVICES_MESSAGE";
7123
7269
  /**
7124
7270
  * @generated from enum value: REMOTE_TEXT_INPUT_MESSAGE = 67;
7125
7271
  */
@@ -7129,11 +7275,11 @@ let ProtocolMessage_Type = /* @__PURE__ */ function(ProtocolMessage_Type) {
7129
7275
  */
7130
7276
  ProtocolMessage_Type[ProtocolMessage_Type["GET_REMOTE_TEXT_INPUT_SESSION_MESSAGE"] = 68] = "GET_REMOTE_TEXT_INPUT_SESSION_MESSAGE";
7131
7277
  /**
7132
- * Same as 66?
7278
+ * Apple: RemoveFromParentGroupMessage
7133
7279
  *
7134
- * @generated from enum value: REMOVE_OUTPUT_DEVICES_MESSAGE2 = 69;
7280
+ * @generated from enum value: REMOVE_FROM_PARENT_GROUP_MESSAGE = 69;
7135
7281
  */
7136
- ProtocolMessage_Type[ProtocolMessage_Type["REMOVE_OUTPUT_DEVICES_MESSAGE2"] = 69] = "REMOVE_OUTPUT_DEVICES_MESSAGE2";
7282
+ ProtocolMessage_Type[ProtocolMessage_Type["REMOVE_FROM_PARENT_GROUP_MESSAGE"] = 69] = "REMOVE_FROM_PARENT_GROUP_MESSAGE";
7137
7283
  /**
7138
7284
  * @generated from enum value: PLAYBACK_SESSION_REQUEST_MESSAGE = 70;
7139
7285
  */
@@ -7167,17 +7313,27 @@ let ProtocolMessage_Type = /* @__PURE__ */ function(ProtocolMessage_Type) {
7167
7313
  */
7168
7314
  ProtocolMessage_Type[ProtocolMessage_Type["UPDATE_ACTIVE_SYSTEM_ENDPOINT_MESSAGE"] = 77] = "UPDATE_ACTIVE_SYSTEM_ENDPOINT_MESSAGE";
7169
7315
  /**
7316
+ * Apple: 0x4E
7317
+ *
7318
+ * @generated from enum value: PLAYBACK_SESSION_MIGRATE_POST_MESSAGE = 78;
7319
+ */
7320
+ ProtocolMessage_Type[ProtocolMessage_Type["PLAYBACK_SESSION_MIGRATE_POST_MESSAGE"] = 78] = "PLAYBACK_SESSION_MIGRATE_POST_MESSAGE";
7321
+ /**
7170
7322
  * @generated from enum value: SET_DISCOVERY_MODE_MESSAGE = 101;
7171
7323
  */
7172
7324
  ProtocolMessage_Type[ProtocolMessage_Type["SET_DISCOVERY_MODE_MESSAGE"] = 101] = "SET_DISCOVERY_MODE_MESSAGE";
7173
7325
  /**
7174
- * @generated from enum value: UPDATE_END_POINTS_MESSAGE = 102;
7326
+ * Apple: UpdateSyncedEndpointsMessage
7327
+ *
7328
+ * @generated from enum value: UPDATE_SYNCED_ENDPOINTS_MESSAGE = 102;
7175
7329
  */
7176
- ProtocolMessage_Type[ProtocolMessage_Type["UPDATE_END_POINTS_MESSAGE"] = 102] = "UPDATE_END_POINTS_MESSAGE";
7330
+ ProtocolMessage_Type[ProtocolMessage_Type["UPDATE_SYNCED_ENDPOINTS_MESSAGE"] = 102] = "UPDATE_SYNCED_ENDPOINTS_MESSAGE";
7177
7331
  /**
7178
- * @generated from enum value: REMOVE_ENDPOINTS_MESSAGE = 103;
7332
+ * Apple: RemoveSyncedEndpointsMessage
7333
+ *
7334
+ * @generated from enum value: REMOVE_SYNCED_ENDPOINTS_MESSAGE = 103;
7179
7335
  */
7180
- ProtocolMessage_Type[ProtocolMessage_Type["REMOVE_ENDPOINTS_MESSAGE"] = 103] = "REMOVE_ENDPOINTS_MESSAGE";
7336
+ ProtocolMessage_Type[ProtocolMessage_Type["REMOVE_SYNCED_ENDPOINTS_MESSAGE"] = 103] = "REMOVE_SYNCED_ENDPOINTS_MESSAGE";
7181
7337
  /**
7182
7338
  * @generated from enum value: PLAYER_CLIENT_PROPERTIES_MESSAGE = 104;
7183
7339
  */
@@ -7195,93 +7351,117 @@ let ProtocolMessage_Type = /* @__PURE__ */ function(ProtocolMessage_Type) {
7195
7351
  */
7196
7352
  ProtocolMessage_Type[ProtocolMessage_Type["AUDIO_FADE_RESPONSE_MESSAGE"] = 107] = "AUDIO_FADE_RESPONSE_MESSAGE";
7197
7353
  /**
7198
- * @generated from enum value: PLAYBACK_SESSION_MIGRATE_POST_MESSAGE = 108;
7199
- */
7200
- ProtocolMessage_Type[ProtocolMessage_Type["PLAYBACK_SESSION_MIGRATE_POST_MESSAGE"] = 108] = "PLAYBACK_SESSION_MIGRATE_POST_MESSAGE";
7201
- /**
7202
- * @generated from enum value: SET_CONVERSATION_DETECTION_ENABLED_MESSAGE = 109;
7203
- */
7204
- ProtocolMessage_Type[ProtocolMessage_Type["SET_CONVERSATION_DETECTION_ENABLED_MESSAGE"] = 109] = "SET_CONVERSATION_DETECTION_ENABLED_MESSAGE";
7205
- /**
7206
- * @generated from enum value: PLAYER_CLIENT_PARTICIPANTS_UPDATE_MESSAGE = 110;
7354
+ * Apple: DiscoveryUpdateEndpointsMessage NIEUW
7355
+ *
7356
+ * @generated from enum value: DISCOVERY_UPDATE_ENDPOINTS_MESSAGE = 108;
7207
7357
  */
7208
- ProtocolMessage_Type[ProtocolMessage_Type["PLAYER_CLIENT_PARTICIPANTS_UPDATE_MESSAGE"] = 110] = "PLAYER_CLIENT_PARTICIPANTS_UPDATE_MESSAGE";
7358
+ ProtocolMessage_Type[ProtocolMessage_Type["DISCOVERY_UPDATE_ENDPOINTS_MESSAGE"] = 108] = "DISCOVERY_UPDATE_ENDPOINTS_MESSAGE";
7209
7359
  /**
7210
- * @generated from enum value: MICROPHONE_CONNECTION_REQUEST_MESSAGE = 111;
7360
+ * Apple: DiscoveryUpdateOutputDevicesMessage NIEUW
7361
+ *
7362
+ * @generated from enum value: DISCOVERY_UPDATE_OUTPUT_DEVICES_MESSAGE = 109;
7211
7363
  */
7212
- ProtocolMessage_Type[ProtocolMessage_Type["MICROPHONE_CONNECTION_REQUEST_MESSAGE"] = 111] = "MICROPHONE_CONNECTION_REQUEST_MESSAGE";
7364
+ ProtocolMessage_Type[ProtocolMessage_Type["DISCOVERY_UPDATE_OUTPUT_DEVICES_MESSAGE"] = 109] = "DISCOVERY_UPDATE_OUTPUT_DEVICES_MESSAGE";
7213
7365
  /**
7214
- * @generated from enum value: MICROPHONE_CONNECTION_RESPONSE_MESSAGE = 112;
7366
+ * Apple: SetListeningModeMessage NIEUW
7367
+ *
7368
+ * @generated from enum value: SET_LISTENING_MODE_MESSAGE = 110;
7215
7369
  */
7216
- ProtocolMessage_Type[ProtocolMessage_Type["MICROPHONE_CONNECTION_RESPONSE_MESSAGE"] = 112] = "MICROPHONE_CONNECTION_RESPONSE_MESSAGE";
7370
+ ProtocolMessage_Type[ProtocolMessage_Type["SET_LISTENING_MODE_MESSAGE"] = 110] = "SET_LISTENING_MODE_MESSAGE";
7217
7371
  /**
7218
- * @generated from enum value: CREATE_APPLICATION_CONNECTION_MESSAGE = 113;
7372
+ * @generated from enum value: CONFIGURE_CONNECTION_MESSAGE = 120;
7219
7373
  */
7220
- ProtocolMessage_Type[ProtocolMessage_Type["CREATE_APPLICATION_CONNECTION_MESSAGE"] = 113] = "CREATE_APPLICATION_CONNECTION_MESSAGE";
7374
+ ProtocolMessage_Type[ProtocolMessage_Type["CONFIGURE_CONNECTION_MESSAGE"] = 120] = "CONFIGURE_CONNECTION_MESSAGE";
7221
7375
  /**
7222
- * @generated from enum value: CREATE_HOSTED_ENDPOINT_REQUEST_MESSAGE = 114;
7376
+ * Apple: 0x79
7377
+ *
7378
+ * @generated from enum value: CREATE_HOSTED_ENDPOINT_REQUEST_MESSAGE = 121;
7223
7379
  */
7224
- ProtocolMessage_Type[ProtocolMessage_Type["CREATE_HOSTED_ENDPOINT_REQUEST_MESSAGE"] = 114] = "CREATE_HOSTED_ENDPOINT_REQUEST_MESSAGE";
7380
+ ProtocolMessage_Type[ProtocolMessage_Type["CREATE_HOSTED_ENDPOINT_REQUEST_MESSAGE"] = 121] = "CREATE_HOSTED_ENDPOINT_REQUEST_MESSAGE";
7225
7381
  /**
7226
- * @generated from enum value: CREATE_HOSTED_ENDPOINT_RESPONSE_MESSAGE = 115;
7382
+ * Apple: 0x7A
7383
+ *
7384
+ * @generated from enum value: CREATE_HOSTED_ENDPOINT_RESPONSE_MESSAGE = 122;
7227
7385
  */
7228
- ProtocolMessage_Type[ProtocolMessage_Type["CREATE_HOSTED_ENDPOINT_RESPONSE_MESSAGE"] = 115] = "CREATE_HOSTED_ENDPOINT_RESPONSE_MESSAGE";
7386
+ ProtocolMessage_Type[ProtocolMessage_Type["CREATE_HOSTED_ENDPOINT_RESPONSE_MESSAGE"] = 122] = "CREATE_HOSTED_ENDPOINT_RESPONSE_MESSAGE";
7229
7387
  /**
7230
- * @generated from enum value: REQUEST_GROUP_SESSION_MESSAGE = 116;
7388
+ * Apple: AdjustVolumeMessage NIEUW
7389
+ *
7390
+ * @generated from enum value: ADJUST_VOLUME_MESSAGE = 125;
7231
7391
  */
7232
- ProtocolMessage_Type[ProtocolMessage_Type["REQUEST_GROUP_SESSION_MESSAGE"] = 116] = "REQUEST_GROUP_SESSION_MESSAGE";
7392
+ ProtocolMessage_Type[ProtocolMessage_Type["ADJUST_VOLUME_MESSAGE"] = 125] = "ADJUST_VOLUME_MESSAGE";
7233
7393
  /**
7234
- * @generated from enum value: GROUP_SESSION_JOIN_RESPONSE_MESSAGE = 117;
7394
+ * @generated from enum value: GET_VOLUME_MUTED_MESSAGE = 126;
7235
7395
  */
7236
- ProtocolMessage_Type[ProtocolMessage_Type["GROUP_SESSION_JOIN_RESPONSE_MESSAGE"] = 117] = "GROUP_SESSION_JOIN_RESPONSE_MESSAGE";
7396
+ ProtocolMessage_Type[ProtocolMessage_Type["GET_VOLUME_MUTED_MESSAGE"] = 126] = "GET_VOLUME_MUTED_MESSAGE";
7237
7397
  /**
7238
- * @generated from enum value: GROUP_SESSION_FAST_SYNC_MESSAGE = 118;
7398
+ * @generated from enum value: GET_VOLUME_MUTED_RESULT_MESSAGE = 127;
7239
7399
  */
7240
- ProtocolMessage_Type[ProtocolMessage_Type["GROUP_SESSION_FAST_SYNC_MESSAGE"] = 118] = "GROUP_SESSION_FAST_SYNC_MESSAGE";
7400
+ ProtocolMessage_Type[ProtocolMessage_Type["GET_VOLUME_MUTED_RESULT_MESSAGE"] = 127] = "GET_VOLUME_MUTED_RESULT_MESSAGE";
7241
7401
  /**
7242
- * @generated from enum value: GROUP_SESSION_IDENTITY_SHARE_MESSAGE = 119;
7402
+ * Apple: MuteVolumeMessage
7403
+ *
7404
+ * @generated from enum value: SET_VOLUME_MUTED_MESSAGE = 128;
7243
7405
  */
7244
- ProtocolMessage_Type[ProtocolMessage_Type["GROUP_SESSION_IDENTITY_SHARE_MESSAGE"] = 119] = "GROUP_SESSION_IDENTITY_SHARE_MESSAGE";
7406
+ ProtocolMessage_Type[ProtocolMessage_Type["SET_VOLUME_MUTED_MESSAGE"] = 128] = "SET_VOLUME_MUTED_MESSAGE";
7245
7407
  /**
7246
- * @generated from enum value: CONFIGURE_CONNECTION_MESSAGE = 120;
7408
+ * @generated from enum value: VOLUME_MUTED_DID_CHANGE_MESSAGE = 129;
7247
7409
  */
7248
- ProtocolMessage_Type[ProtocolMessage_Type["CONFIGURE_CONNECTION_MESSAGE"] = 120] = "CONFIGURE_CONNECTION_MESSAGE";
7410
+ ProtocolMessage_Type[ProtocolMessage_Type["VOLUME_MUTED_DID_CHANGE_MESSAGE"] = 129] = "VOLUME_MUTED_DID_CHANGE_MESSAGE";
7249
7411
  /**
7250
- * @generated from enum value: GROUP_SESSION_IDENTITY_SHARE_REPLY_MESSAGE = 121;
7412
+ * Apple: 0x82
7413
+ *
7414
+ * @generated from enum value: SET_CONVERSATION_DETECTION_ENABLED_MESSAGE = 130;
7251
7415
  */
7252
- ProtocolMessage_Type[ProtocolMessage_Type["GROUP_SESSION_IDENTITY_SHARE_REPLY_MESSAGE"] = 121] = "GROUP_SESSION_IDENTITY_SHARE_REPLY_MESSAGE";
7416
+ ProtocolMessage_Type[ProtocolMessage_Type["SET_CONVERSATION_DETECTION_ENABLED_MESSAGE"] = 130] = "SET_CONVERSATION_DETECTION_ENABLED_MESSAGE";
7253
7417
  /**
7254
- * @generated from enum value: GROUP_SESSION_LEADER_DISCOVERY_MESSAGE = 122;
7418
+ * Apple: 0x83
7419
+ *
7420
+ * @generated from enum value: PLAYER_CLIENT_PARTICIPANTS_UPDATE_MESSAGE = 131;
7255
7421
  */
7256
- ProtocolMessage_Type[ProtocolMessage_Type["GROUP_SESSION_LEADER_DISCOVERY_MESSAGE"] = 122] = "GROUP_SESSION_LEADER_DISCOVERY_MESSAGE";
7422
+ ProtocolMessage_Type[ProtocolMessage_Type["PLAYER_CLIENT_PARTICIPANTS_UPDATE_MESSAGE"] = 131] = "PLAYER_CLIENT_PARTICIPANTS_UPDATE_MESSAGE";
7257
7423
  /**
7258
- * @generated from enum value: GROUP_SESSION_MEMBER_SYNC_MESSAGE = 123;
7424
+ * Apple: 0x84
7425
+ *
7426
+ * @generated from enum value: REQUEST_GROUP_SESSION_MESSAGE = 132;
7259
7427
  */
7260
- ProtocolMessage_Type[ProtocolMessage_Type["GROUP_SESSION_MEMBER_SYNC_MESSAGE"] = 123] = "GROUP_SESSION_MEMBER_SYNC_MESSAGE";
7428
+ ProtocolMessage_Type[ProtocolMessage_Type["REQUEST_GROUP_SESSION_MESSAGE"] = 132] = "REQUEST_GROUP_SESSION_MESSAGE";
7261
7429
  /**
7262
- * @generated from enum value: GROUP_SESSION_ERROR_REPLY_MESSAGE = 124;
7430
+ * Apple: ConfigureConnectionServiceMessage NIEUW
7431
+ *
7432
+ * @generated from enum value: CONFIGURE_CONNECTION_SERVICE_MESSAGE = 133;
7263
7433
  */
7264
- ProtocolMessage_Type[ProtocolMessage_Type["GROUP_SESSION_ERROR_REPLY_MESSAGE"] = 124] = "GROUP_SESSION_ERROR_REPLY_MESSAGE";
7434
+ ProtocolMessage_Type[ProtocolMessage_Type["CONFIGURE_CONNECTION_SERVICE_MESSAGE"] = 133] = "CONFIGURE_CONNECTION_SERVICE_MESSAGE";
7265
7435
  /**
7266
- * @generated from enum value: NOW_PLAYING_AUDIO_FORMAT_CONTENT_INFO_MESSAGE = 125;
7436
+ * Apple: 0x86
7437
+ *
7438
+ * @generated from enum value: CREATE_APPLICATION_CONNECTION_MESSAGE = 134;
7267
7439
  */
7268
- ProtocolMessage_Type[ProtocolMessage_Type["NOW_PLAYING_AUDIO_FORMAT_CONTENT_INFO_MESSAGE"] = 125] = "NOW_PLAYING_AUDIO_FORMAT_CONTENT_INFO_MESSAGE";
7440
+ ProtocolMessage_Type[ProtocolMessage_Type["CREATE_APPLICATION_CONNECTION_MESSAGE"] = 134] = "CREATE_APPLICATION_CONNECTION_MESSAGE";
7269
7441
  /**
7270
- * @generated from enum value: GET_VOLUME_MUTED_MESSAGE = 126;
7442
+ * Apple: 0x87 NIEUW
7443
+ *
7444
+ * @generated from enum value: APPLICATION_CONNECTION_PROTOCOL_MESSAGE = 135;
7271
7445
  */
7272
- ProtocolMessage_Type[ProtocolMessage_Type["GET_VOLUME_MUTED_MESSAGE"] = 126] = "GET_VOLUME_MUTED_MESSAGE";
7446
+ ProtocolMessage_Type[ProtocolMessage_Type["APPLICATION_CONNECTION_PROTOCOL_MESSAGE"] = 135] = "APPLICATION_CONNECTION_PROTOCOL_MESSAGE";
7273
7447
  /**
7274
- * @generated from enum value: GET_VOLUME_MUTED_RESULT_MESSAGE = 127;
7448
+ * Apple: 0x88 NIEUW
7449
+ *
7450
+ * @generated from enum value: INVALIDATE_APPLICATION_CONNECTION_MESSAGE = 136;
7275
7451
  */
7276
- ProtocolMessage_Type[ProtocolMessage_Type["GET_VOLUME_MUTED_RESULT_MESSAGE"] = 127] = "GET_VOLUME_MUTED_RESULT_MESSAGE";
7452
+ ProtocolMessage_Type[ProtocolMessage_Type["INVALIDATE_APPLICATION_CONNECTION_MESSAGE"] = 136] = "INVALIDATE_APPLICATION_CONNECTION_MESSAGE";
7277
7453
  /**
7278
- * @generated from enum value: SET_VOLUME_MUTED_MESSAGE = 128;
7454
+ * Apple: 0x89
7455
+ *
7456
+ * @generated from enum value: MICROPHONE_CONNECTION_REQUEST_MESSAGE = 137;
7279
7457
  */
7280
- ProtocolMessage_Type[ProtocolMessage_Type["SET_VOLUME_MUTED_MESSAGE"] = 128] = "SET_VOLUME_MUTED_MESSAGE";
7458
+ ProtocolMessage_Type[ProtocolMessage_Type["MICROPHONE_CONNECTION_REQUEST_MESSAGE"] = 137] = "MICROPHONE_CONNECTION_REQUEST_MESSAGE";
7281
7459
  /**
7282
- * @generated from enum value: VOLUME_MUTED_DID_CHANGE_MESSAGE = 129;
7460
+ * Apple: 0x8A
7461
+ *
7462
+ * @generated from enum value: MICROPHONE_CONNECTION_RESPONSE_MESSAGE = 138;
7283
7463
  */
7284
- ProtocolMessage_Type[ProtocolMessage_Type["VOLUME_MUTED_DID_CHANGE_MESSAGE"] = 129] = "VOLUME_MUTED_DID_CHANGE_MESSAGE";
7464
+ ProtocolMessage_Type[ProtocolMessage_Type["MICROPHONE_CONNECTION_RESPONSE_MESSAGE"] = 138] = "MICROPHONE_CONNECTION_RESPONSE_MESSAGE";
7285
7465
  return ProtocolMessage_Type;
7286
7466
  }({});
7287
7467
  /**
@@ -8019,7 +8199,7 @@ const PlaybackQueueType_EnumSchema = /* @__PURE__ */ enumDesc(file_Common, 15, 0
8019
8199
  /**
8020
8200
  * Describes the file DeviceInfoMessage.proto.
8021
8201
  */
8022
- const file_DeviceInfoMessage = /* @__PURE__ */ fileDesc("ChdEZXZpY2VJbmZvTWVzc2FnZS5wcm90byIyChFQcmVmZXJyZWRFbmNvZGluZyIdCgRFbnVtEgsKB0RlZmF1bHQQABIICgRKU09OEAEinA0KEURldmljZUluZm9NZXNzYWdlEhgKEHVuaXF1ZUlkZW50aWZpZXIYASABKAkSDAoEbmFtZRgCIAIoCRIaChJsb2NhbGl6ZWRNb2RlbE5hbWUYAyABKAkSGgoSc3lzdGVtQnVpbGRWZXJzaW9uGAQgASgJEiMKG2FwcGxpY2F0aW9uQnVuZGxlSWRlbnRpZmllchgFIAEoCRIgChhhcHBsaWNhdGlvbkJ1bmRsZVZlcnNpb24YBiABKAkSFwoPcHJvdG9jb2xWZXJzaW9uGAcgASgFEiAKGGxhc3RTdXBwb3J0ZWRNZXNzYWdlVHlwZRgIIAEoDRIdChVzdXBwb3J0c1N5c3RlbVBhaXJpbmcYCSABKAgSFQoNYWxsb3dzUGFpcmluZxgKIAEoCBIRCgljb25uZWN0ZWQYCyABKAgSHgoWc3lzdGVtTWVkaWFBcHBsaWNhdGlvbhgMIAEoCRITCgtzdXBwb3J0c0FDTBgNIAEoCBIbChNzdXBwb3J0c1NoYXJlZFF1ZXVlGA4gASgIEh4KFnN1cHBvcnRzRXh0ZW5kZWRNb3Rpb24YDyABKAgSGAoQYmx1ZXRvb3RoQWRkcmVzcxgQIAEoDBIaChJzaGFyZWRRdWV1ZVZlcnNpb24YESABKA0SEQoJZGV2aWNlVUlEGBMgASgJEh0KFW1hbmFnZWRDb25maWdEZXZpY2VJRBgUIAEoCRImCgtkZXZpY2VDbGFzcxgVIAEoDjIRLkRldmljZUNsYXNzLkVudW0SGgoSbG9naWNhbERldmljZUNvdW50GBYgASgNEhoKEnRpZ2h0bHlTeW5jZWRHcm91cBgXIAEoCBIaChJpc1Byb3h5R3JvdXBQbGF5ZXIYGCABKAgSFAoMdGlnaHRTeW5jVUlEGBkgASgJEhAKCGdyb3VwVUlEGBogASgJEhEKCWdyb3VwTmFtZRgbIAEoCRIqCg5ncm91cGVkRGV2aWNlcxgcIAMoCzISLkRldmljZUluZm9NZXNzYWdlEhUKDWlzR3JvdXBMZWFkZXIYHSABKAgSFwoPaXNBaXJwbGF5QWN0aXZlGB4gASgIEiAKGHN5c3RlbVBvZGNhc3RBcHBsaWNhdGlvbhgfIAEoCRIdChVzZW5kZXJEZWZhdWx0R3JvdXBVSUQYICABKAkSGAoQYWlycGxheVJlY2VpdmVycxghIAMoCRIRCglsaW5rQWdlbnQYIiABKAkSEQoJY2x1c3RlcklEGCMgASgJEhcKD2NsdXN0ZXJMZWFkZXJJRBgkIAEoCRITCgtjbHVzdGVyVHlwZRglIAEoDRIWCg5pc0NsdXN0ZXJBd2FyZRgmIAEoCBIPCgdtb2RlbElEGCcgASgJEhsKE3N1cHBvcnRzTXVsdGlwbGF5ZXIYKCABKAgSGAoQcm91dGluZ0NvbnRleHRJRBgpIAEoCRIWCg5haXJQbGF5R3JvdXBJRBgqIAEoCRIeChZzeXN0ZW1Cb29rc0FwcGxpY2F0aW9uGCsgASgJEiwKEGNsdXN0ZXJlZERldmljZXMYLCADKAsyEi5EZXZpY2VJbmZvTWVzc2FnZRIyCipwYXJlbnRHcm91cENvbnRhaW5zRGlzY292ZXJhYmxlR3JvdXBMZWFkZXIYLSABKA0SLAokZ3JvdXBDb250YWluc0Rpc2NvdmVyYWJsZUdyb3VwTGVhZGVyGC4gASgNEhwKFGxhc3RLbm93bkNsdXN0ZXJUeXBlGC8gASgNEiEKGXN1cHBvcnRzT3V0cHV0Q29udGV4dFN5bmMYMSABKAgSFAoMY29tcHV0ZXJOYW1lGDIgASgJEh0KFWNvbmZpZ3VyZWRDbHVzdGVyU2l6ZRgzIAEoDRIyChFwcmVmZXJyZWRFbmNvZGluZxg0IAEoDjIXLlByZWZlcnJlZEVuY29kaW5nLkVudW0SGQoRZ3JvdXBTZXNzaW9uVG9rZW4YNSABKAwSLAoQbGVhZGVyRGV2aWNlSW5mbxg2IAEoCzISLkRldmljZUluZm9NZXNzYWdlEhcKD2lzQ2x1c3RlckxlYWRlchg3IAEoCBIfChdhY3RpdmVTeXN0ZW1FbmRwb2ludFVJRBg4IAEoCRJBCjlpc0VsaWdpYmxlRm9ySG9zdGluZ0dyb3VwU2Vzc2lvbkV4Y2x1ZGluZ0Fja25vd2xlZGdlbWVudHMYOSABKAgSKAogcGFyZW50R3JvdXBTdXBwb3J0c0dyb3VwQ29oZXNpb24YOiABKAg6UgoRZGV2aWNlSW5mb01lc3NhZ2USEC5Qcm90b2NvbE1lc3NhZ2UYFCABKAsyEi5EZXZpY2VJbmZvTWVzc2FnZVIRZGV2aWNlSW5mb01lc3NhZ2U", [file_ProtocolMessage, file_Common]);
8202
+ const file_DeviceInfoMessage = /* @__PURE__ */ fileDesc("ChdEZXZpY2VJbmZvTWVzc2FnZS5wcm90byIyChFQcmVmZXJyZWRFbmNvZGluZyIdCgRFbnVtEgsKB0RlZmF1bHQQABIICgRKU09OEAEizQ0KEURldmljZUluZm9NZXNzYWdlEhgKEHVuaXF1ZUlkZW50aWZpZXIYASABKAkSDAoEbmFtZRgCIAIoCRIaChJsb2NhbGl6ZWRNb2RlbE5hbWUYAyABKAkSGgoSc3lzdGVtQnVpbGRWZXJzaW9uGAQgASgJEiMKG2FwcGxpY2F0aW9uQnVuZGxlSWRlbnRpZmllchgFIAEoCRIgChhhcHBsaWNhdGlvbkJ1bmRsZVZlcnNpb24YBiABKAkSFwoPcHJvdG9jb2xWZXJzaW9uGAcgASgFEiAKGGxhc3RTdXBwb3J0ZWRNZXNzYWdlVHlwZRgIIAEoDRIdChVzdXBwb3J0c1N5c3RlbVBhaXJpbmcYCSABKAgSFQoNYWxsb3dzUGFpcmluZxgKIAEoCBIRCgljb25uZWN0ZWQYCyABKAgSHgoWc3lzdGVtTWVkaWFBcHBsaWNhdGlvbhgMIAEoCRITCgtzdXBwb3J0c0FDTBgNIAEoCBIbChNzdXBwb3J0c1NoYXJlZFF1ZXVlGA4gASgIEh4KFnN1cHBvcnRzRXh0ZW5kZWRNb3Rpb24YDyABKAgSGAoQYmx1ZXRvb3RoQWRkcmVzcxgQIAEoDBIaChJzaGFyZWRRdWV1ZVZlcnNpb24YESABKA0SEQoJZGV2aWNlVUlEGBMgASgJEh0KFW1hbmFnZWRDb25maWdEZXZpY2VJRBgUIAEoCRImCgtkZXZpY2VDbGFzcxgVIAEoDjIRLkRldmljZUNsYXNzLkVudW0SGgoSbG9naWNhbERldmljZUNvdW50GBYgASgNEhoKEnRpZ2h0bHlTeW5jZWRHcm91cBgXIAEoCBIaChJpc1Byb3h5R3JvdXBQbGF5ZXIYGCABKAgSFAoMdGlnaHRTeW5jVUlEGBkgASgJEhAKCGdyb3VwVUlEGBogASgJEhEKCWdyb3VwTmFtZRgbIAEoCRIqCg5ncm91cGVkRGV2aWNlcxgcIAMoCzISLkRldmljZUluZm9NZXNzYWdlEhUKDWlzR3JvdXBMZWFkZXIYHSABKAgSFwoPaXNBaXJwbGF5QWN0aXZlGB4gASgIEiAKGHN5c3RlbVBvZGNhc3RBcHBsaWNhdGlvbhgfIAEoCRIdChVzZW5kZXJEZWZhdWx0R3JvdXBVSUQYICABKAkSGAoQYWlycGxheVJlY2VpdmVycxghIAMoCRIRCglsaW5rQWdlbnQYIiABKAkSEQoJY2x1c3RlcklEGCMgASgJEhcKD2NsdXN0ZXJMZWFkZXJJRBgkIAEoCRITCgtjbHVzdGVyVHlwZRglIAEoDRIWCg5pc0NsdXN0ZXJBd2FyZRgmIAEoCBIPCgdtb2RlbElEGCcgASgJEhsKE3N1cHBvcnRzTXVsdGlwbGF5ZXIYKCABKAgSGAoQcm91dGluZ0NvbnRleHRJRBgpIAEoCRIWCg5haXJQbGF5R3JvdXBJRBgqIAEoCRIeChZzeXN0ZW1Cb29rc0FwcGxpY2F0aW9uGCsgASgJEiwKEGNsdXN0ZXJlZERldmljZXMYLCADKAsyEi5EZXZpY2VJbmZvTWVzc2FnZRIyCipwYXJlbnRHcm91cENvbnRhaW5zRGlzY292ZXJhYmxlR3JvdXBMZWFkZXIYLSABKA0SLAokZ3JvdXBDb250YWluc0Rpc2NvdmVyYWJsZUdyb3VwTGVhZGVyGC4gASgNEhwKFGxhc3RLbm93bkNsdXN0ZXJUeXBlGC8gASgNEi8KE2FsbENsdXN0ZXJlZERldmljZXMYMCADKAsyEi5EZXZpY2VJbmZvTWVzc2FnZRIhChlzdXBwb3J0c091dHB1dENvbnRleHRTeW5jGDEgASgIEhQKDGNvbXB1dGVyTmFtZRgyIAEoCRIdChVjb25maWd1cmVkQ2x1c3RlclNpemUYMyABKA0SMgoRcHJlZmVycmVkRW5jb2RpbmcYNCABKA4yFy5QcmVmZXJyZWRFbmNvZGluZy5FbnVtEhkKEWdyb3VwU2Vzc2lvblRva2VuGDUgASgMEiwKEGxlYWRlckRldmljZUluZm8YNiABKAsyEi5EZXZpY2VJbmZvTWVzc2FnZRIXCg9pc0NsdXN0ZXJMZWFkZXIYNyABKAgSHwoXYWN0aXZlU3lzdGVtRW5kcG9pbnRVSUQYOCABKAkSQQo5aXNFbGlnaWJsZUZvckhvc3RpbmdHcm91cFNlc3Npb25FeGNsdWRpbmdBY2tub3dsZWRnZW1lbnRzGDkgASgIEigKIHBhcmVudEdyb3VwU3VwcG9ydHNHcm91cENvaGVzaW9uGDogASgIOlIKEWRldmljZUluZm9NZXNzYWdlEhAuUHJvdG9jb2xNZXNzYWdlGBQgASgLMhIuRGV2aWNlSW5mb01lc3NhZ2VSEWRldmljZUluZm9NZXNzYWdl", [file_ProtocolMessage, file_Common]);
8023
8203
  /**
8024
8204
  * Describes the message PreferredEncoding.
8025
8205
  * Use `create(PreferredEncodingSchema)` to create a new message.
@@ -8104,7 +8284,7 @@ const Origin_TypeSchema = /* @__PURE__ */ enumDesc(file_Origin, 0, 0);
8104
8284
  /**
8105
8285
  * Describes the file NowPlayingClient.proto.
8106
8286
  */
8107
- const file_NowPlayingClient = /* @__PURE__ */ fileDesc("ChZOb3dQbGF5aW5nQ2xpZW50LnByb3RvIqcCChBOb3dQbGF5aW5nQ2xpZW50EhkKEXByb2Nlc3NJZGVudGlmaWVyGAEgASgFEhgKEGJ1bmRsZUlkZW50aWZpZXIYAiABKAkSKQohcGFyZW50QXBwbGljYXRpb25CdW5kbGVJZGVudGlmaWVyGAMgASgJEh0KFXByb2Nlc3NVc2VySWRlbnRpZmllchgEIAEoBRIcChRub3dQbGF5aW5nVmlzaWJpbGl0eRgFIAEoBRIRCgl0aW50Q29sb3IYBiABKAwSEwoLZGlzcGxheU5hbWUYByABKAkSIgoaYnVuZGxlSWRlbnRpZmllckhpZXJhcmNoeXMYCCADKAkSDwoHaWNvblVSTBgJIAEoCRIZChFpc0VtcHR5RGVwcmVjYXRlZBgKIAEoCA");
8287
+ const file_NowPlayingClient = /* @__PURE__ */ fileDesc("ChZOb3dQbGF5aW5nQ2xpZW50LnByb3RvIq8CChBOb3dQbGF5aW5nQ2xpZW50EhkKEXByb2Nlc3NJZGVudGlmaWVyGAEgASgFEhgKEGJ1bmRsZUlkZW50aWZpZXIYAiABKAkSKQohcGFyZW50QXBwbGljYXRpb25CdW5kbGVJZGVudGlmaWVyGAMgASgJEh0KFXByb2Nlc3NVc2VySWRlbnRpZmllchgEIAEoBRIcChRub3dQbGF5aW5nVmlzaWJpbGl0eRgFIAEoBRIRCgl0aW50Q29sb3IYBiABKAwSEwoLZGlzcGxheU5hbWUYByABKAkSKgoiZXh0ZW5kZWRCdW5kbGVJZGVudGlmaWVySGllcmFyY2h5cxgIIAMoCRIPCgdpY29uVVJMGAkgASgJEhkKEWlzRW1wdHlEZXByZWNhdGVkGAogASgI");
8108
8288
  /**
8109
8289
  * Describes the message NowPlayingClient.
8110
8290
  * Use `create(NowPlayingClientSchema)` to create a new message.
@@ -8116,7 +8296,7 @@ const NowPlayingClientSchema = /* @__PURE__ */ messageDesc(file_NowPlayingClient
8116
8296
  /**
8117
8297
  * Describes the file NowPlayingPlayer.proto.
8118
8298
  */
8119
- const file_NowPlayingPlayer = /* @__PURE__ */ fileDesc("ChZOb3dQbGF5aW5nUGxheWVyLnByb3RvIq0BChBOb3dQbGF5aW5nUGxheWVyEhIKCmlkZW50aWZpZXIYASABKAkSEwoLZGlzcGxheU5hbWUYAiABKAkSFwoPaXNEZWZhdWx0UGxheWVyGAMgASgIEhgKEGF1ZGlvU2Vzc2lvblR5cGUYBCABKAUSFAoMbXhTZXNzaW9uSURzGAUgASgDEhYKDmF1ZGlvU2Vzc2lvbklEGAYgASgNEg8KB2ljb25VUkwYByABKAk");
8299
+ const file_NowPlayingPlayer = /* @__PURE__ */ fileDesc("ChZOb3dQbGF5aW5nUGxheWVyLnByb3RvIpQBChBOb3dQbGF5aW5nUGxheWVyEhIKCmlkZW50aWZpZXIYASABKAkSEwoLZGlzcGxheU5hbWUYAiABKAkSGAoQYXVkaW9TZXNzaW9uVHlwZRgEIAEoBRIUCgxteFNlc3Npb25JRHMYBSABKAMSFgoOYXVkaW9TZXNzaW9uSUQYBiABKA0SDwoHaWNvblVSTBgHIAEoCQ");
8120
8300
  /**
8121
8301
  * Describes the message NowPlayingPlayer.
8122
8302
  * Use `create(NowPlayingPlayerSchema)` to create a new message.
@@ -8301,7 +8481,7 @@ const ColorSchema = /* @__PURE__ */ messageDesc(file_Color, 0);
8301
8481
  /**
8302
8482
  * Describes the file CommandInfo.proto.
8303
8483
  */
8304
- const file_CommandInfo = /* @__PURE__ */ fileDesc("ChFDb21tYW5kSW5mby5wcm90byJMCg5RdWV1ZUVuZEFjdGlvbiI6CgRFbnVtEg8KC0NsZWFyQWN0aW9uEAASCAoETm9uZRABEgkKBVJlc2V0EAISDAoIQXV0b1BsYXkQAyJKCg1EaXNhYmxlUmVhc29uIjkKBEVudW0SCwoHVW5rbm93bhAAEg4KCkFkUGxheWJhY2sQARIUChBTa2lwTGltaXRSZWFjaGVkEAIigwEKHFByZWxvYWRlZFBsYXliYWNrU2Vzc2lvbkluZm8SIQoZcGxheWJhY2tTZXNzaW9uSWRlbnRpZmllchgBIAEoCRIfChdwbGF5YmFja1Nlc3Npb25SZXZpc2lvbhgCIAEoCRIfChdwbGF5YmFja1Nlc3Npb25Qcmlvcml0eRgDIAEoBSLiCgoLQ29tbWFuZEluZm8SGQoHY29tbWFuZBgBIAEoDjIILkNvbW1hbmQSDwoHZW5hYmxlZBgCIAEoCBIOCgZhY3RpdmUYAyABKAgSGgoScHJlZmVycmVkSW50ZXJ2YWxzGAQgAygBEhYKDmxvY2FsaXplZFRpdGxlGAUgASgJEhUKDW1pbmltdW1SYXRpbmcYBiABKAISFQoNbWF4aW11bVJhdGluZxgHIAEoAhIWCg5zdXBwb3J0ZWRSYXRlcxgIIAMoAhIbChNsb2NhbGl6ZWRTaG9ydFRpdGxlGAkgASgJEiQKCnJlcGVhdE1vZGUYCiABKA4yEC5SZXBlYXRNb2RlLkVudW0SJgoLc2h1ZmZsZU1vZGUYCyABKA4yES5TaHVmZmxlTW9kZS5FbnVtEhkKEXByZXNlbnRhdGlvblN0eWxlGAwgASgFEhQKDHNraXBJbnRlcnZhbBgNIAEoBRIZChFudW1BdmFpbGFibGVTa2lwcxgOIAEoBRIVCg1za2lwRnJlcXVlbmN5GA8gASgFEhAKCGNhblNjcnViGBAgASgFEiMKG3N1cHBvcnRlZFBsYXliYWNrUXVldWVUeXBlcxgRIAMoBRInCh9zdXBwb3J0ZWRDdXN0b21RdWV1ZUlkZW50aWZpZXJzGBIgAygJEiMKG3N1cHBvcnRlZEluc2VydGlvblBvc2l0aW9ucxgTIAMoBRIbChNzdXBwb3J0c1NoYXJlZFF1ZXVlGBQgASgIEhcKD3VwTmV4dEl0ZW1Db3VudBgVIAEoBRIdChVwcmVmZXJyZWRQbGF5YmFja1JhdGUYFiABKAISJQodc3VwcG9ydGVkUGxheWJhY2tTZXNzaW9uVHlwZXMYFyADKAkSIwobY3VycmVudFBsYXliYWNrU2Vzc2lvblR5cGVzGBggAygJEiEKGXBsYXliYWNrU2Vzc2lvbklkZW50aWZpZXIYGSABKAkSMwoVY3VycmVudFF1ZXVlRW5kQWN0aW9uGBogASgOMhQuUXVldWVFbmRBY3Rpb24uRW51bRI2ChhzdXBwb3J0ZWRFbmRRdWV1ZUFjdGlvbnMYGyADKA4yFC5RdWV1ZUVuZEFjdGlvbi5FbnVtEioKDWRpc2FibGVSZWFzb24YHCABKA4yEy5EaXNhYmxlUmVhc29uLkVudW0SSgojc3VwcG9ydGVkUGxheWJhY2tTZXNzaW9uSWRlbnRpZmllcnMYHSADKAsyHS5QcmVsb2FkZWRQbGF5YmFja1Nlc3Npb25JbmZvEh8KF3Byb2FjdGl2ZUNvbW1hbmRPcHRpb25zGB4gASgMEhsKE3ZvY2Fsc0NvbnRyb2xBY3RpdmUYHyABKAgSGgoSdm9jYWxzQ29udHJvbExldmVsGCAgASgNEh0KFXZvY2Fsc0NvbnRyb2xNYXhMZXZlbBghIAEoDRIdChV2b2NhbHNDb250cm9sTWluTGV2ZWwYIiABKA0SHwoXdm9jYWxzQ29udHJvbENvbnRpbnVvdXMYIyABKAgSFgoOc2xlZXBUaW1lclRpbWUYJCABKAYSGgoSc2xlZXBUaW1lclN0b3BNb2RlGCUgASgNEhoKEnNsZWVwVGltZXJGaXJlRGF0ZRgmIAEoARIVCg1kaWFsb2dPcHRpb25zGCcgASgMEiAKGGxhc3RTZWN0aW9uQ29udGVudEl0ZW1JRBgoIAEoCRIhChlzdXBwb3J0c1JlZmVyZW5jZVBvc2l0aW9uGCkgASgIEiMKG3BsYXliYWNrU2Vzc2lvblJlcXVpcmVtZW50cxgqIAMoCRIXCg90cmFuc2l0aW9uU3R5bGUYKyABKA0q+wsKB0NvbW1hbmQSCwoHVW5rbm93bhAAEggKBFBsYXkQARIJCgVQYXVzZRACEhMKD1RvZ2dsZVBsYXlQYXVzZRADEggKBFN0b3AQBBINCglOZXh0VHJhY2sQBRIRCg1QcmV2aW91c1RyYWNrEAYSFgoSQWR2YW5jZVNodWZmbGVNb2RlEAcSFQoRQWR2YW5jZVJlcGVhdE1vZGUQCBIUChBCZWdpbkZhc3RGb3J3YXJkEAkSEgoORW5kRmFzdEZvcndhcmQQChIPCgtCZWdpblJld2luZBALEg0KCUVuZFJld2luZBAMEhMKD1Jld2luZDE1U2Vjb25kcxANEhgKFEZhc3RGb3J3YXJkMTVTZWNvbmRzEA4SEwoPUmV3aW5kMzBTZWNvbmRzEA8SGAoURmFzdEZvcndhcmQzMFNlY29uZHMQEBIPCgtTa2lwRm9yd2FyZBASEhAKDFNraXBCYWNrd2FyZBATEhYKEkNoYW5nZVBsYXliYWNrUmF0ZRAUEg0KCVJhdGVUcmFjaxAVEg0KCUxpa2VUcmFjaxAWEhAKDERpc2xpa2VUcmFjaxAXEhEKDUJvb2ttYXJrVHJhY2sQGBIaChZTZWVrVG9QbGF5YmFja1Bvc2l0aW9uEC0SFAoQQ2hhbmdlUmVwZWF0TW9kZRAuEhUKEUNoYW5nZVNodWZmbGVNb2RlEC8SGAoURW5hYmxlTGFuZ3VhZ2VPcHRpb24QNRIZChVEaXNhYmxlTGFuZ3VhZ2VPcHRpb24QNhIPCgtOZXh0Q2hhcHRlchAZEhMKD1ByZXZpb3VzQ2hhcHRlchAaEg0KCU5leHRBbGJ1bRAbEhEKDVByZXZpb3VzQWxidW0QHBIQCgxOZXh0UGxheWxpc3QQHRIUChBQcmV2aW91c1BsYXlsaXN0EB4SDAoIQmFuVHJhY2sQHxIWChJBZGRUcmFja1RvV2lzaExpc3QQIBIbChdSZW1vdmVUcmFja0Zyb21XaXNoTGlzdBAhEhEKDU5leHRJbkNvbnRleHQQIhIVChFQcmV2aW91c0luQ29udGV4dBAjEhgKFFJlc2V0UGxheWJhY2tUaW1lb3V0ECkSFAoQU2V0UGxheWJhY2tRdWV1ZRAwEh4KGkFkZE5vd1BsYXlpbmdJdGVtVG9MaWJyYXJ5EDESFgoSQ3JlYXRlUmFkaW9TdGF0aW9uEDISFAoQQWRkSXRlbVRvTGlicmFyeRAzEhsKF0luc2VydEludG9QbGF5YmFja1F1ZXVlEDQSGAoUUmVvcmRlclBsYXliYWNrUXVldWUQNxIbChdSZW1vdmVGcm9tUGxheWJhY2tRdWV1ZRA4EhsKF1BsYXlJdGVtSW5QbGF5YmFja1F1ZXVlEDkSFgoSUHJlcGFyZUZvclNldFF1ZXVlEDoSFgoSU2V0UGxheWJhY2tTZXNzaW9uEDsSHAoYUHJlbG9hZGVkUGxheWJhY2tTZXNzaW9uEDwSIQodU2V0UHJpb3JpdHlGb3JQbGF5YmFja1Nlc3Npb24QPRIaChZEaXNjYXJkUGxheWJhY2tTZXNzaW9uED4SDQoJUmVzaHVmZmxlED8SEQoNU2V0UmVwZWF0TW9kZRBAEhIKDlNldFNodWZmbGVNb2RlEEESEQoNU2V0U2xlZXBUaW1lchBCEg0KCVNldFZvbHVtZRBDEhAKDEFkanVzdFZvbHVtZRBEEhQKEEluaXRpYXRlUGxheWJhY2sQRRIbChdJbml0aWFsaXplUGxheWJhY2tRdWV1ZRBGEhQKEEdldFBsYXliYWNrUXVldWUQRxIUChBHZXRQbGF5YmFja1N0YXRlEEgSFgoSR2V0UGxheWJhY2tTZXNzaW9uEEkSFgoSQ29vcmRpbmF0ZVBsYXliYWNrEEoSHgoaTGVhdmVTaGFyZWRQbGF5YmFja1Nlc3Npb24QSxIYChRQcmVwYXJlVm9jYWxzQ29udHJvbBBMEhMKD0VuaGFuY2VEaWFsb2d1ZRBNEhkKFENoYW5nZVF1ZXVlRW5kQWN0aW9uEIcB", [file_Common]);
8484
+ const file_CommandInfo = /* @__PURE__ */ fileDesc("ChFDb21tYW5kSW5mby5wcm90byJMCg5RdWV1ZUVuZEFjdGlvbiI6CgRFbnVtEg8KC0NsZWFyQWN0aW9uEAASCAoETm9uZRABEgkKBVJlc2V0EAISDAoIQXV0b1BsYXkQAyJKCg1EaXNhYmxlUmVhc29uIjkKBEVudW0SCwoHVW5rbm93bhAAEg4KCkFkUGxheWJhY2sQARIUChBTa2lwTGltaXRSZWFjaGVkEAIigwEKHFByZWxvYWRlZFBsYXliYWNrU2Vzc2lvbkluZm8SIQoZcGxheWJhY2tTZXNzaW9uSWRlbnRpZmllchgBIAEoCRIfChdwbGF5YmFja1Nlc3Npb25SZXZpc2lvbhgCIAEoCRIfChdwbGF5YmFja1Nlc3Npb25Qcmlvcml0eRgDIAEoBSKHCgoLQ29tbWFuZEluZm8SGQoHY29tbWFuZBgBIAEoDjIILkNvbW1hbmQSDwoHZW5hYmxlZBgCIAEoCBIOCgZhY3RpdmUYAyABKAgSGgoScHJlZmVycmVkSW50ZXJ2YWxzGAQgAygBEhYKDmxvY2FsaXplZFRpdGxlGAUgASgJEhUKDW1pbmltdW1SYXRpbmcYBiABKAISFQoNbWF4aW11bVJhdGluZxgHIAEoAhIWCg5zdXBwb3J0ZWRSYXRlcxgIIAMoAhIbChNsb2NhbGl6ZWRTaG9ydFRpdGxlGAkgASgJEiQKCnJlcGVhdE1vZGUYCiABKA4yEC5SZXBlYXRNb2RlLkVudW0SJgoLc2h1ZmZsZU1vZGUYCyABKA4yES5TaHVmZmxlTW9kZS5FbnVtEhkKEXByZXNlbnRhdGlvblN0eWxlGAwgASgFEhQKDHNraXBJbnRlcnZhbBgNIAEoBRIZChFudW1BdmFpbGFibGVTa2lwcxgOIAEoBRIVCg1za2lwRnJlcXVlbmN5GA8gASgFEhAKCGNhblNjcnViGBAgASgFEiMKG3N1cHBvcnRlZFBsYXliYWNrUXVldWVUeXBlcxgRIAMoBRInCh9zdXBwb3J0ZWRDdXN0b21RdWV1ZUlkZW50aWZpZXJzGBIgAygJEiMKG3N1cHBvcnRlZEluc2VydGlvblBvc2l0aW9ucxgTIAMoBRIXCg91cE5leHRJdGVtQ291bnQYFSABKAUSHQoVcHJlZmVycmVkUGxheWJhY2tSYXRlGBYgASgCEiUKHXN1cHBvcnRlZFBsYXliYWNrU2Vzc2lvblR5cGVzGBcgAygJEiMKG2N1cnJlbnRQbGF5YmFja1Nlc3Npb25UeXBlcxgYIAMoCRIhChlwbGF5YmFja1Nlc3Npb25JZGVudGlmaWVyGBkgASgJEjMKFWN1cnJlbnRRdWV1ZUVuZEFjdGlvbhgaIAEoDjIULlF1ZXVlRW5kQWN0aW9uLkVudW0SNgoYc3VwcG9ydGVkUXVldWVFbmRBY3Rpb25zGBsgAygOMhQuUXVldWVFbmRBY3Rpb24uRW51bRIqCg1kaXNhYmxlUmVhc29uGBwgASgOMhMuRGlzYWJsZVJlYXNvbi5FbnVtEkoKI3N1cHBvcnRlZFBsYXliYWNrU2Vzc2lvbklkZW50aWZpZXJzGB0gAygLMh0uUHJlbG9hZGVkUGxheWJhY2tTZXNzaW9uSW5mbxIfChdwcm9hY3RpdmVDb21tYW5kT3B0aW9ucxgeIAEoDBIbChN2b2NhbHNDb250cm9sQWN0aXZlGB8gASgIEhoKEnZvY2Fsc0NvbnRyb2xMZXZlbBggIAEoDRIdChV2b2NhbHNDb250cm9sTWF4TGV2ZWwYISABKA0SHQoVdm9jYWxzQ29udHJvbE1pbkxldmVsGCIgASgNEh8KF3ZvY2Fsc0NvbnRyb2xDb250aW51b3VzGCMgASgIEhYKDnNsZWVwVGltZXJUaW1lGCQgASgGEhoKEnNsZWVwVGltZXJGaXJlRGF0ZRgmIAEoARIVCg1kaWFsb2dPcHRpb25zGCcgASgMEiEKGXN1cHBvcnRzUmVmZXJlbmNlUG9zaXRpb24YKSABKAgSIwobcGxheWJhY2tTZXNzaW9uUmVxdWlyZW1lbnRzGCogAygJEhcKD3RyYW5zaXRpb25TdHlsZRgrIAEoDSr7CwoHQ29tbWFuZBILCgdVbmtub3duEAASCAoEUGxheRABEgkKBVBhdXNlEAISEwoPVG9nZ2xlUGxheVBhdXNlEAMSCAoEU3RvcBAEEg0KCU5leHRUcmFjaxAFEhEKDVByZXZpb3VzVHJhY2sQBhIWChJBZHZhbmNlU2h1ZmZsZU1vZGUQBxIVChFBZHZhbmNlUmVwZWF0TW9kZRAIEhQKEEJlZ2luRmFzdEZvcndhcmQQCRISCg5FbmRGYXN0Rm9yd2FyZBAKEg8KC0JlZ2luUmV3aW5kEAsSDQoJRW5kUmV3aW5kEAwSEwoPUmV3aW5kMTVTZWNvbmRzEA0SGAoURmFzdEZvcndhcmQxNVNlY29uZHMQDhITCg9SZXdpbmQzMFNlY29uZHMQDxIYChRGYXN0Rm9yd2FyZDMwU2Vjb25kcxAQEg8KC1NraXBGb3J3YXJkEBISEAoMU2tpcEJhY2t3YXJkEBMSFgoSQ2hhbmdlUGxheWJhY2tSYXRlEBQSDQoJUmF0ZVRyYWNrEBUSDQoJTGlrZVRyYWNrEBYSEAoMRGlzbGlrZVRyYWNrEBcSEQoNQm9va21hcmtUcmFjaxAYEhoKFlNlZWtUb1BsYXliYWNrUG9zaXRpb24QLRIUChBDaGFuZ2VSZXBlYXRNb2RlEC4SFQoRQ2hhbmdlU2h1ZmZsZU1vZGUQLxIYChRFbmFibGVMYW5ndWFnZU9wdGlvbhA1EhkKFURpc2FibGVMYW5ndWFnZU9wdGlvbhA2Eg8KC05leHRDaGFwdGVyEBkSEwoPUHJldmlvdXNDaGFwdGVyEBoSDQoJTmV4dEFsYnVtEBsSEQoNUHJldmlvdXNBbGJ1bRAcEhAKDE5leHRQbGF5bGlzdBAdEhQKEFByZXZpb3VzUGxheWxpc3QQHhIMCghCYW5UcmFjaxAfEhYKEkFkZFRyYWNrVG9XaXNoTGlzdBAgEhsKF1JlbW92ZVRyYWNrRnJvbVdpc2hMaXN0ECESEQoNTmV4dEluQ29udGV4dBAiEhUKEVByZXZpb3VzSW5Db250ZXh0ECMSGAoUUmVzZXRQbGF5YmFja1RpbWVvdXQQKRIUChBTZXRQbGF5YmFja1F1ZXVlEDASHgoaQWRkTm93UGxheWluZ0l0ZW1Ub0xpYnJhcnkQMRIWChJDcmVhdGVSYWRpb1N0YXRpb24QMhIUChBBZGRJdGVtVG9MaWJyYXJ5EDMSGwoXSW5zZXJ0SW50b1BsYXliYWNrUXVldWUQNBIYChRSZW9yZGVyUGxheWJhY2tRdWV1ZRA3EhsKF1JlbW92ZUZyb21QbGF5YmFja1F1ZXVlEDgSGwoXUGxheUl0ZW1JblBsYXliYWNrUXVldWUQORIWChJQcmVwYXJlRm9yU2V0UXVldWUQOhIWChJTZXRQbGF5YmFja1Nlc3Npb24QOxIcChhQcmVsb2FkZWRQbGF5YmFja1Nlc3Npb24QPBIhCh1TZXRQcmlvcml0eUZvclBsYXliYWNrU2Vzc2lvbhA9EhoKFkRpc2NhcmRQbGF5YmFja1Nlc3Npb24QPhINCglSZXNodWZmbGUQPxIRCg1TZXRSZXBlYXRNb2RlEEASEgoOU2V0U2h1ZmZsZU1vZGUQQRIRCg1TZXRTbGVlcFRpbWVyEEISDQoJU2V0Vm9sdW1lEEMSEAoMQWRqdXN0Vm9sdW1lEEQSFAoQSW5pdGlhdGVQbGF5YmFjaxBFEhsKF0luaXRpYWxpemVQbGF5YmFja1F1ZXVlEEYSFAoQR2V0UGxheWJhY2tRdWV1ZRBHEhQKEEdldFBsYXliYWNrU3RhdGUQSBIWChJHZXRQbGF5YmFja1Nlc3Npb24QSRIWChJDb29yZGluYXRlUGxheWJhY2sQShIeChpMZWF2ZVNoYXJlZFBsYXliYWNrU2Vzc2lvbhBLEhgKFFByZXBhcmVWb2NhbHNDb250cm9sEEwSEwoPRW5oYW5jZURpYWxvZ3VlEE0SGQoUQ2hhbmdlUXVldWVFbmRBY3Rpb24QhwE", [file_Common]);
8305
8485
  /**
8306
8486
  * Describes the message QueueEndAction.
8307
8487
  * Use `create(QueueEndActionSchema)` to create a new message.
@@ -8710,7 +8890,7 @@ const SystemPlaybackGenericTracklistQueueSchema = /* @__PURE__ */ messageDesc(fi
8710
8890
  /**
8711
8891
  * Describes the file CommandOptions.proto.
8712
8892
  */
8713
- const file_CommandOptions = /* @__PURE__ */ fileDesc("ChRDb21tYW5kT3B0aW9ucy5wcm90byK/FAoOQ29tbWFuZE9wdGlvbnMSEAoIc291cmNlSWQYAiABKAkSEQoJbWVkaWFUeXBlGAMgASgJEh0KFWV4dGVybmFsUGxheWVyQ29tbWFuZBgEIAEoCBIUCgxza2lwSW50ZXJ2YWwYBSABKAISFAoMcGxheWJhY2tSYXRlGAYgASgCEg4KBnJhdGluZxgHIAEoAhIQCghuZWdhdGl2ZRgIIAEoCBIYChBwbGF5YmFja1Bvc2l0aW9uGAkgASgBEiQKCnJlcGVhdE1vZGUYCiABKA4yEC5SZXBlYXRNb2RlLkVudW0SJgoLc2h1ZmZsZU1vZGUYCyABKA4yES5TaHVmZmxlTW9kZS5FbnVtEg8KB3RyYWNrSUQYDCABKAQSFgoOcmFkaW9TdGF0aW9uSUQYDSABKAMSGAoQcmFkaW9TdGF0aW9uSGFzaBgOIAEoCRIiChpzeXN0ZW1BcHBQbGF5YmFja1F1ZXVlRGF0YRgPIAEoDBIfChdkZXN0aW5hdGlvbkFwcERpc3BsYXlJRBgQIAEoCRITCgtzZW5kT3B0aW9ucxgRIAEoDRIvCidyZXF1ZXN0RGVmZXJtZW50VG9QbGF5YmFja1F1ZXVlUG9zaXRpb24YEiABKAgSEQoJY29udGV4dElEGBMgASgJEioKInNob3VsZE92ZXJyaWRlTWFudWFsbHlDdXJhdGVkUXVldWUYFCABKAgSEgoKc3RhdGlvblVSTBgVIAEoCRIgChhzaG91bGRCZWdpblJhZGlvUGxheWJhY2sYFiABKAgSJgoecGxheWJhY2tRdWV1ZUluc2VydGlvblBvc2l0aW9uGBcgASgFEhUKDWNvbnRlbnRJdGVtSUQYGCABKAkSGwoTcGxheWJhY2tRdWV1ZU9mZnNldBgZIAEoBRImCh5wbGF5YmFja1F1ZXVlRGVzdGluYXRpb25PZmZzZXQYGiABKAUSFgoObGFuZ3VhZ2VPcHRpb24YGyABKAwSHAoUcGxheWJhY2tRdWV1ZUNvbnRleHQYHCABKAwSIAoYaW5zZXJ0QWZ0ZXJDb250ZW50SXRlbUlEGB0gASgJEh8KF25vd1BsYXlpbmdDb250ZW50SXRlbUlEGB4gASgJEhUKDXJlcGxhY2VJbnRlbnQYHyABKAUSEQoJY29tbWFuZElEGCAgASgJEhAKCHNlbmRlcklEGCEgASgJEh4KFnJlbW90ZUNvbnRyb2xJbnRlcmZhY2UYIiABKAkSEQoJYmVnaW5TZWVrGCggASgEEg8KB2VuZFNlZWsYKSABKAQSFwoPcGxheWJhY2tTZXNzaW9uGCogASgMEhgKEHVzZXJJZGVudGl0eURhdGEYKyABKAwSIQoZaW5zZXJ0QmVmb3JlQ29udGVudEl0ZW1JRBgsIAEoCRIWCg5xdWV1ZUVuZEFjdGlvbhgtIAEoDRIbChNwcmVzZXJ2ZXNSZXBlYXRNb2RlGC4gASgIEhwKFHByZXNlcnZlc1NodWZmbGVNb2RlGC8gASgIEh8KF3ByZXNlcnZlc1F1ZXVlRW5kQWN0aW9uGDAgASgIEh0KFWhvbWVLaXRVc2VySWRlbnRpZmllchgxIAEoCRIfChd2ZXJpZnlTdXBwb3J0ZWRDb21tYW5kcxgyIAEoCBIhChlwbGF5YmFja1Nlc3Npb25JZGVudGlmaWVyGDMgASgJEh8KF3BsYXliYWNrU2Vzc2lvblByaW9yaXR5GDQgASgNEh8KF3BsYXliYWNrU2Vzc2lvbkZpbGVQYXRoGDUgASgJEh8KF3BsYXliYWNrU2Vzc2lvblJldmlzaW9uGDYgASgJEh8KF3BsYXliYWNrU2Vzc2lvbk1ldGFkYXRhGDcgASgMEhsKE3BsYXliYWNrU2Vzc2lvblR5cGUYOCABKAkSFgoOdHJ1ZUNvbXBsZXRpb24YOSABKAgSIgoacGxheWJhY2tBdXRob3JpemF0aW9uVG9rZW4YOiABKAkSFwoPZXZlbnROb3RpY2VUeXBlGDsgASgJEh0KFWV2ZW50Tm90aWNlSWRlbnRpZmllchg8IAEoCRInCh9zaGFyZWRQbGF5YmFja1Nlc3Npb25JZGVudGlmaWVyGD0gASgJEhYKDmNvbW1hbmRUaW1lb3V0GD4gASgEEiAKGGFzc2lzdGFudFRUU0VuZFRpbWVzdGFtcBg/IAEoBBIlCh1hc3Npc3RhbnRDb21tYW5kU2VuZFRpbWVzdGFtcBhAIAEoBBIcChRvcmlnaW5hdGluZ0RldmljZVVJRBhBIAEoCRIdChVkZXN0aW5hdGlvbkRldmljZVVJRHMYQiABKAwSGAoQZGVzaXJlZFNlc3Npb25JRBhDIAEoCRIeChZhbHdheXNJZ25vcmVEdXJpbmdDYWxsGEQgASgIEiMKG2Fsd2F5c0lnbm9yZUR1cmluZ1NoYXJlUGxheRhFIAEoCBIbChNjb21tYW5kU2VxdWVuY2VVVUlEGEYgASgJEiIKGm9yaWdpbmF0ZWRGcm9tUmVtb3RlRGV2aWNlGEcgASgIEhoKEnNpcmlUdXJuSWRlbnRpZmllchhIIAEoCRIjChtzaXJpU2VhcmNoRGF0YVNldElkZW50aWZpZXIYSSABKAkSJQodcHJlcGFyZUZvclNldFF1ZXVlSXNQcm9hY3RpdmUYSiABKAgSKQohcHJlcGFyZUZvclNldFF1ZXVlUHJvYWN0aXZlUmVhc29uGEsgASgJEi0KJXByZXBhcmVGb3JTZXRRdWV1ZVByb2FjdGl2ZVJlYXNvblR5cGUYTCABKA0SHwoXYXBwbGljYXRpb25Vc2VySWRlbnRpdHkYTSABKAwSNAoWc3lzdGVtQXBwUGxheWJhY2tRdWV1ZRhOIAEoCzIULlN5c3RlbVBsYXliYWNrUXVldWUSGwoTdm9jYWxzQ29udHJvbEFjdGl2ZRhPIAEoCBIaChJ2b2NhbHNDb250cm9sTGV2ZWwYUCABKA0SHQoVdm9jYWxzQ29udHJvbE1pbkxldmVsGFEgASgNEh0KFXZvY2Fsc0NvbnRyb2xNYXhMZXZlbBhSIAEoDRIfChd2b2NhbHNDb250cm9sQ29udGludW91cxhTIAEoCBInCh9hc3NvY2lhdGVkUGFydGljaXBhbnRJZGVudGlmaWVyGFQgASgJEhYKDnNsZWVwVGltZXJUaW1lGFUgASgGEhoKEnNsZWVwVGltZXJTdG9wTW9kZRhWIAEoDRIiCg1kaWFsb2dPcHRpb25zGFcgASgLMgsuRGljdGlvbmFyeRIgChhjbGllbnRQcmVmZXJyZWRMYW5ndWFnZXMYWCABKAkSGQoRcmVmZXJlbmNlUG9zaXRpb24YWSABKAYSGwoTZGVsZWdhdGVBY2NvdW50RGF0YRhaIAEoDBIfChdkZWxlZ2F0ZUFjY291bnREYXRhVHlwZRhbIAEoCRIdChVlbmhhbmNlRGlhbG9ndWVBY3RpdmUYXCABKAg", [
8893
+ const file_CommandOptions = /* @__PURE__ */ fileDesc("ChRDb21tYW5kT3B0aW9ucy5wcm90byLcFAoOQ29tbWFuZE9wdGlvbnMSEAoIc291cmNlSUQYAiABKAkSEQoJbWVkaWFUeXBlGAMgASgJEh0KFWV4dGVybmFsUGxheWVyQ29tbWFuZBgEIAEoCBIUCgxza2lwSW50ZXJ2YWwYBSABKAISFAoMcGxheWJhY2tSYXRlGAYgASgCEg4KBnJhdGluZxgHIAEoAhIQCghuZWdhdGl2ZRgIIAEoCBIYChBwbGF5YmFja1Bvc2l0aW9uGAkgASgBEiQKCnJlcGVhdE1vZGUYCiABKA4yEC5SZXBlYXRNb2RlLkVudW0SJgoLc2h1ZmZsZU1vZGUYCyABKA4yES5TaHVmZmxlTW9kZS5FbnVtEg8KB3RyYWNrSUQYDCABKAQSFgoOcmFkaW9TdGF0aW9uSUQYDSABKAMSGAoQcmFkaW9TdGF0aW9uSGFzaBgOIAEoCRIiChpzeXN0ZW1BcHBQbGF5YmFja1F1ZXVlRGF0YRgPIAEoDBIfChdkZXN0aW5hdGlvbkFwcERpc3BsYXlJRBgQIAEoCRITCgtzZW5kT3B0aW9ucxgRIAEoDRIvCidyZXF1ZXN0RGVmZXJtZW50VG9QbGF5YmFja1F1ZXVlUG9zaXRpb24YEiABKAgSEQoJY29udGV4dElEGBMgASgJEioKInNob3VsZE92ZXJyaWRlTWFudWFsbHlDdXJhdGVkUXVldWUYFCABKAgSEgoKc3RhdGlvblVSTBgVIAEoCRIgChhzaG91bGRCZWdpblJhZGlvUGxheWJhY2sYFiABKAgSJgoecGxheWJhY2tRdWV1ZUluc2VydGlvblBvc2l0aW9uGBcgASgFEhUKDWNvbnRlbnRJdGVtSUQYGCABKAkSGwoTcGxheWJhY2tRdWV1ZU9mZnNldBgZIAEoBRImCh5wbGF5YmFja1F1ZXVlRGVzdGluYXRpb25PZmZzZXQYGiABKAUSFgoObGFuZ3VhZ2VPcHRpb24YGyABKAwSHAoUcGxheWJhY2tRdWV1ZUNvbnRleHQYHCABKAwSIAoYaW5zZXJ0QWZ0ZXJDb250ZW50SXRlbUlEGB0gASgJEh8KF25vd1BsYXlpbmdDb250ZW50SXRlbUlEGB4gASgJEhUKDXJlcGxhY2VJbnRlbnQYHyABKAUSEQoJY29tbWFuZElEGCAgASgJEhAKCHNlbmRlcklEGCEgASgJEh4KFnJlbW90ZUNvbnRyb2xJbnRlcmZhY2UYIiABKAkSEQoJYmVnaW5TZWVrGCggASgEEg8KB2VuZFNlZWsYKSABKAQSFwoPcGxheWJhY2tTZXNzaW9uGCogASgMEhgKEHVzZXJJZGVudGl0eURhdGEYKyABKAwSIQoZaW5zZXJ0QmVmb3JlQ29udGVudEl0ZW1JRBgsIAEoCRIWCg5xdWV1ZUVuZEFjdGlvbhgtIAEoDRIbChNwcmVzZXJ2ZXNSZXBlYXRNb2RlGC4gASgIEhwKFHByZXNlcnZlc1NodWZmbGVNb2RlGC8gASgIEh8KF3ByZXNlcnZlc1F1ZXVlRW5kQWN0aW9uGDAgASgIEh0KFWhvbWVLaXRVc2VySWRlbnRpZmllchgxIAEoCRIfChd2ZXJpZnlTdXBwb3J0ZWRDb21tYW5kcxgyIAEoCBIhChlwbGF5YmFja1Nlc3Npb25JZGVudGlmaWVyGDMgASgJEh8KF3BsYXliYWNrU2Vzc2lvblByaW9yaXR5GDQgASgNEh8KF3BsYXliYWNrU2Vzc2lvbkZpbGVQYXRoGDUgASgJEh8KF3BsYXliYWNrU2Vzc2lvblJldmlzaW9uGDYgASgJEh8KF3BsYXliYWNrU2Vzc2lvbk1ldGFkYXRhGDcgASgMEhsKE3BsYXliYWNrU2Vzc2lvblR5cGUYOCABKAkSFgoOdHJ1ZUNvbXBsZXRpb24YOSABKAgSIgoacGxheWJhY2tBdXRob3JpemF0aW9uVG9rZW4YOiABKAkSFwoPZXZlbnROb3RpY2VUeXBlGDsgASgJEh0KFWV2ZW50Tm90aWNlSWRlbnRpZmllchg8IAEoCRInCh9zaGFyZWRQbGF5YmFja1Nlc3Npb25JZGVudGlmaWVyGD0gASgJEhYKDmNvbW1hbmRUaW1lb3V0GD4gASgEEiAKGGFzc2lzdGFudFRUU0VuZFRpbWVzdGFtcBg/IAEoBBIlCh1hc3Npc3RhbnRDb21tYW5kU2VuZFRpbWVzdGFtcBhAIAEoBBIcChRvcmlnaW5hdGluZ0RldmljZVVJRBhBIAEoCRIdChVkZXN0aW5hdGlvbkRldmljZVVJRHMYQiABKAwSGAoQZGVzaXJlZFNlc3Npb25JRBhDIAEoCRIeChZhbHdheXNJZ25vcmVEdXJpbmdDYWxsGEQgASgIEiMKG2Fsd2F5c0lnbm9yZUR1cmluZ1NoYXJlUGxheRhFIAEoCBIbChNjb21tYW5kU2VxdWVuY2VVVUlEGEYgASgJEiIKGm9yaWdpbmF0ZWRGcm9tUmVtb3RlRGV2aWNlGEcgASgIEhoKEnNpcmlUdXJuSWRlbnRpZmllchhIIAEoCRIjChtzaXJpU2VhcmNoRGF0YVNldElkZW50aWZpZXIYSSABKAkSJQodcHJlcGFyZUZvclNldFF1ZXVlSXNQcm9hY3RpdmUYSiABKAgSKQohcHJlcGFyZUZvclNldFF1ZXVlUHJvYWN0aXZlUmVhc29uGEsgASgJEi0KJXByZXBhcmVGb3JTZXRRdWV1ZVByb2FjdGl2ZVJlYXNvblR5cGUYTCABKA0SHwoXYXBwbGljYXRpb25Vc2VySWRlbnRpdHkYTSABKAwSNAoWc3lzdGVtQXBwUGxheWJhY2tRdWV1ZRhOIAEoCzIULlN5c3RlbVBsYXliYWNrUXVldWUSGwoTdm9jYWxzQ29udHJvbEFjdGl2ZRhPIAEoCBIaChJ2b2NhbHNDb250cm9sTGV2ZWwYUCABKA0SHQoVdm9jYWxzQ29udHJvbE1pbkxldmVsGFEgASgNEh0KFXZvY2Fsc0NvbnRyb2xNYXhMZXZlbBhSIAEoDRIfChd2b2NhbHNDb250cm9sQ29udGludW91cxhTIAEoCBInCh9hc3NvY2lhdGVkUGFydGljaXBhbnRJZGVudGlmaWVyGFQgASgJEhYKDnNsZWVwVGltZXJUaW1lGFUgASgGEhoKEnNsZWVwVGltZXJTdG9wTW9kZRhWIAEoDRIiCg1kaWFsb2dPcHRpb25zGFcgASgLMgsuRGljdGlvbmFyeRIgChhjbGllbnRQcmVmZXJyZWRMYW5ndWFnZXMYWCABKAkSGQoRcmVmZXJlbmNlUG9zaXRpb24YWSABKAYSGwoTZGVsZWdhdGVBY2NvdW50RGF0YRhaIAEoDBIfChdkZWxlZ2F0ZUFjY291bnREYXRhVHlwZRhbIAEoCRIdChVlbmhhbmNlRGlhbG9ndWVBY3RpdmUYXCABKAgSGwoTdXNlckFjdGlvblRpbWVzdGFtcBhfIAEoAQ", [
8714
8894
  file_Common,
8715
8895
  file_Dictionary,
8716
8896
  file_SystemPlaybackQueue
@@ -8742,7 +8922,7 @@ const configureConnectionMessage = /* @__PURE__ */ extDesc(file_ConfigureConnect
8742
8922
  /**
8743
8923
  * Describes the file ContentItemMetadata.proto.
8744
8924
  */
8745
- const file_ContentItemMetadata = /* @__PURE__ */ fileDesc("ChlDb250ZW50SXRlbU1ldGFkYXRhLnByb3RvIrkBCg5BdWRpb1JvdXRlVHlwZSKmAQoERW51bRILCgdVbmtub3duEAASEgoORGV2aWNlc1NwZWFrZXIQARILCgdMaW5lT3V0EAISDgoKSGVhZHBob25lcxADEhcKE0JsdWV0b290aEhlYWRwaG9uZXMQBBIUChBCbHVldG9vdGhTcGVha2VyEAUSDAoIVVNCQXVkaW8QBhIMCghDYXJBdWRpbxAHEggKBEhETUkQCBILCgdBaXJQbGF5EAkiWQoKQXVkaW9Sb3V0ZRIdCgR0eXBlGAEgASgLMg8uQXVkaW9Sb3V0ZVR5cGUSDAoEbmFtZRgCIAEoCRIeChZzdXBwb3J0c1NwYXRpYWxpemF0aW9uGAMgASgIInkKCUF1ZGlvVGllciJsCgRFbnVtEhYKEkxvd0JhbmR3aWR0aFN0ZXJlbxABEhUKEUhpZ2hRdWFsaXR5U3RlcmVvEAISDAoITG9zc2xlc3MQAxIaChZIaWdoUmVzb2x1dGlvbkxvc3NsZXNzEAQSCwoHU3BhdGlhbBAFIocBCgpTb25nVHJhaXRzInkKBEVudW0SCAoETm9uZRAAEhcKE0FwcGxlRGlnaXRpYWxNYXN0ZXIQARIMCghMb3NzbGVzcxACEhoKFkhpZ2hSZXNvbHV0aW9uTG9zc2xlc3MQBBILCgdTcGF0aWFsEAgSCQoFQXRtb3MQEBIMCghTdXJyb3VuZBAgIogBCgtBbGJ1bVRyYWl0cyJ5CgRFbnVtEggKBE5vbmUQABIXChNBcHBsZURpZ2l0aWFsTWFzdGVyEAESDAoITG9zc2xlc3MQAhIaChZIaWdoUmVzb2x1dGlvbkxvc3NsZXNzEAQSCwoHU3BhdGlhbBAIEgkKBUF0bW9zEBASDAoIU3Vycm91bmQQICJICg5QbGF5bGlzdFRyYWl0cyI2CgRFbnVtEggKBE5vbmUQABILCgdTcGF0aWFsEAgSCQoFQXRtb3MQEBIMCghTdXJyb3VuZBAgIrwBChlBY3RpdmVGb3JtYXRKdXN0aWZpY2F0aW9uIp4BCgRFbnVtEgsKB1Vua25vd24QABIPCgtVbmF2YWlsYWJsZRABEhIKDlVzZXJQcmVmZXJlbmNlEGQSEAoMVXNlckRvd25sb2FkEGUSFgoRUm91dGVJbmNvbXBhdGlibGUQ9AMSHgoZUm91dGVVbmtub3duQ29tcGF0aWJpbGl0eRD1AxIaChVCYW5kd2lkdGhJbnN1ZmZpY2llbnQQ6AciegoKRm9ybWF0VGllciJsCgRFbnVtEhYKEkxvd0JhbmR3aWR0aFN0ZXJlbxABEhUKEUhpZ2hRdWFsaXR5U3RlcmVvEAISDAoITG9zc2xlc3MQBBIaChZIaWdoUmVzb2x1dGlvbkxvc3NsZXNzEAgSCwoHU3BhdGlhbBAQIoUCCgtBdWRpb0Zvcm1hdBIdCgR0aWVyGAEgASgOMg8uQXVkaW9UaWVyLkVudW0SDwoHYml0cmF0ZRgCIAEoAxISCgpzYW1wbGVSYXRlGAMgASgDEhAKCGJpdERlcHRoGAQgASgDEg0KBWNvZGVjGAUgASgNEhMKC3NwYXRpYWxpemVkGAYgASgIEhQKDG11bHRpQ2hhbm5lbBgHIAEoCBIVCg1jaGFubmVsTGF5b3V0GAggASgNEiUKHWF1ZGlvQ2hhbm5lbExheW91dERlc2NyaXB0aW9uGAkgASgJEg8KB2dyb3VwSUQYCiABKAkSFwoPc3RhYmxlVmFyaWFudElEGAsgASgJIs0YChNDb250ZW50SXRlbU1ldGFkYXRhEg0KBXRpdGxlGAEgASgJEhAKCHN1YnRpdGxlGAIgASgJEhMKC2lzQ29udGFpbmVyGAMgASgIEhIKCmlzUGxheWFibGUYBCABKAgSGAoQcGxheWJhY2tQcm9ncmVzcxgFIAEoAhIRCglhbGJ1bU5hbWUYBiABKAkSFwoPdHJhY2tBcnRpc3ROYW1lGAcgASgJEhcKD2FsYnVtQXJ0aXN0TmFtZRgIIAEoCRIUCgxkaXJlY3Rvck5hbWUYCSABKAkSFAoMc2Vhc29uTnVtYmVyGAogASgFEhUKDWVwaXNvZGVOdW1iZXIYCyABKAUSEwoLcmVsZWFzZURhdGUYDCABKAESEQoJcGxheUNvdW50GA0gASgFEhAKCGR1cmF0aW9uGA4gASgBEh4KFmxvY2FsaXplZENvbnRlbnRSYXRpbmcYDyABKAkSFgoOaXNFeHBsaWNpdEl0ZW0YECABKAgSFAoMcGxheWxpc3RUeXBlGBEgASgFEhgKEHJhZGlvU3RhdGlvblR5cGUYEiABKAUSGAoQYXJ0d29ya0F2YWlsYWJsZRgTIAEoCBIVCg1pbmZvQXZhaWxhYmxlGBUgASgIEiAKGGxhbmd1YWdlT3B0aW9uc0F2YWlsYWJsZRgWIAEoCBIYChBudW1iZXJPZlNlY3Rpb25zGBcgASgFEhcKD2x5cmljc0F2YWlsYWJsZRgYIAEoCBIZChFlZGl0aW5nU3R5bGVGbGFncxgZIAEoBRIaChJpc1N0cmVhbWluZ0NvbnRlbnQYGiABKAgSGgoSaXNDdXJyZW50bHlQbGF5aW5nGBsgASgIEhwKFGNvbGxlY3Rpb25JZGVudGlmaWVyGBwgASgJEhkKEXByb2ZpbGVJZGVudGlmaWVyGB0gASgJEhEKCXN0YXJ0VGltZRgeIAEoARIXCg9hcnR3b3JrTUlNRVR5cGUYHyABKAkSFgoOYXNzZXRVUkxTdHJpbmcYICABKAkSEAoIY29tcG9zZXIYISABKAkSEgoKZGlzY051bWJlchgiIAEoBRITCgtlbGFwc2VkVGltZRgjIAEoARINCgVnZW5yZRgkIAEoCRIUCgxpc0Fsd2F5c0xpdmUYJSABKAgSFAoMcGxheWJhY2tSYXRlGCcgASgCEhQKDGNoYXB0ZXJDb3VudBgoIAEoBRIWCg50b3RhbERpc2NDb3VudBgpIAEoBRIXCg90b3RhbFRyYWNrQ291bnQYKiABKAUSEwoLdHJhY2tOdW1iZXIYKyABKAUSGQoRY29udGVudElkZW50aWZpZXIYLCABKAkSEgoKaXNTaGFyYWJsZRguIAEoCBIPCgdpc0xpa2VkGDAgASgIEhQKDGlzSW5XaXNoTGlzdBgxIAEoCBIeChZyYWRpb1N0YXRpb25JZGVudGlmaWVyGDIgASgDEhgKEHJhZGlvU3RhdGlvbk5hbWUYNCABKAkSGgoScmFkaW9TdGF0aW9uU3RyaW5nGDUgASgJEh0KFWlUdW5lc1N0b3JlSWRlbnRpZmllchg2IAEoAxIpCiFpVHVuZXNTdG9yZVN1YnNjcmlwdGlvbklkZW50aWZpZXIYNyABKAMSIwobaVR1bmVzU3RvcmVBcnRpc3RJZGVudGlmaWVyGDggASgDEiIKGmlUdW5lc1N0b3JlQWxidW1JZGVudGlmaWVyGDkgASgDEhgKEHB1cmNoYXNlSW5mb0RhdGEYOiABKAwSGwoTZGVmYXVsdFBsYXliYWNrUmF0ZRg7IAEoAhIVCg1kb3dubG9hZFN0YXRlGDwgASgFEhgKEGRvd25sb2FkUHJvZ3Jlc3MYPSABKAISFgoOYXBwTWV0cmljc0RhdGEYPiABKAwSEgoKc2VyaWVzTmFtZRg/IAEoCRIxCgltZWRpYVR5cGUYQCABKA4yHi5Db250ZW50SXRlbU1ldGFkYXRhLk1lZGlhVHlwZRI3CgxtZWRpYVN1YlR5cGUYQSABKA4yIS5Db250ZW50SXRlbU1ldGFkYXRhLk1lZGlhU3ViVHlwZRIaChJub3dQbGF5aW5nSW5mb0RhdGEYQyABKAwSFAoMdXNlckluZm9EYXRhGEQgASgMEhMKC2lzU3RlZXJhYmxlGEUgASgIEhIKCmFydHdvcmtVUkwYRiABKAkSEQoJbHlyaWNzVVJMGEcgASgJEiIKGmRldmljZVNwZWNpZmljVXNlckluZm9EYXRhGEggASgMEhoKEmNvbGxlY3Rpb25JbmZvRGF0YRhJIAEoDBIcChRlbGFwc2VkVGltZVRpbWVzdGFtcBhKIAEoARIZChFpbmZlcnJlZFRpbWVzdGFtcBhLIAEoARIZChFzZXJ2aWNlSWRlbnRpZmllchhMIAEoCRIYChBhcnR3b3JrRGF0YVdpZHRoGE0gASgFEhkKEWFydHdvcmtEYXRhSGVpZ2h0GE4gASgFEh8KF2N1cnJlbnRQbGF5YmFja0RhdGVEYXRhGE8gASgMEhkKEWFydHdvcmtJZGVudGlmaWVyGFAgASgJEhEKCWlzTG9hZGluZxhRIAEoCBIfChdhcnR3b3JrVVJMVGVtcGxhdGVzRGF0YRhSIAEoDBIeChZsZWdhY3lVbmlxdWVJZGVudGlmaWVyGFMgASgDEhMKC2VwaXNvZGVUeXBlGFQgASgFEhYKDmFydHdvcmtGaWxlVVJMGFUgASgJEhcKD2JyYW5kSWRlbnRpZmllchhWIAEoCRIfChdsb2NhbGl6ZWREdXJhdGlvblN0cmluZxhXIAEoCRIRCglhbGJ1bVllYXIYWCABKAkSJAoKc29uZ1RyYWl0cxhZIAEoDjIQLlNvbmdUcmFpdHMuRW51bRImCgthbGJ1bVRyYWl0cxhaIAEoDjIRLkFsYnVtVHJhaXRzLkVudW0SLAoOcGxheWxpc3RUcmFpdHMYWyABKA4yFC5QbGF5bGlzdFRyYWl0cy5FbnVtEiUKD3ByZWZlcnJlZEZvcm1hdBhcIAEoCzIMLkF1ZGlvRm9ybWF0EiIKDGFjdGl2ZUZvcm1hdBhdIAEoCzIMLkF1ZGlvRm9ybWF0EkIKGWFjdGl2ZUZvcm1hdEp1c3RpZmljYXRpb24YXiABKA4yHy5BY3RpdmVGb3JtYXRKdXN0aWZpY2F0aW9uLkVudW0SLgoUZm9ybWF0VGllclByZWZlcmVuY2UYXyABKA4yEC5Gb3JtYXRUaWVyLkVudW0SHwoKYXVkaW9Sb3V0ZRhgIAEoCzILLkF1ZGlvUm91dGUSKAoSYWx0ZXJuYXRpdmVGb3JtYXRzGGEgAygLMgwuQXVkaW9Gb3JtYXQSFwoPaXNBZHZlcnRpc2VtZW50GGIgASgIEh0KFWhhc0FsdGVybmF0aXZlRm9ybWF0cxhjIAEoCBIXCg9wYXJ0aWNpcGFudE5hbWUYZCABKAkSHQoVcGFydGljaXBhbnRJZGVudGlmaWVyGGUgASgJEhUKDWNsYXNzaWNhbFdvcmsYZiABKAkSFwoPcmVwb3J0aW5nQWRhbUlEGGcgASgDEhQKDGx5cmljc0FkYW1JRBhoIAEoAxIoCiBpVHVuZXNTdG9yZUFsYnVtQXJ0aXN0SWRlbnRpZmllchhpIAEoAxIlCh1kdXJhdGlvblN0cmluZ0xvY2FsaXphdGlvbktleRhqIAEoCRIfChdpc1Jlc29sdmFibGVQYXJ0aWNpcGFudBhrIAEoCBIqCiJpbnRlcm5hdGlvbmFsU3RhbmRhcmRSZWNvcmRpbmdDb2RlGGwgASgJEhYKDmlzSW5UcmFuc2l0aW9uGG0gASgIEh4KFmV4Y2x1ZGVGcm9tU3VnZ2VzdGlvbnMYbiABKAgSJQoddHJhbnNjcmlwdEFsaWdubWVudHNBdmFpbGFibGUYbyABKAgSFQoNc3VidGl0bGVTaG9ydBhwIAEoCRIaChJ0cmFuc2l0aW9uSW5mb0RhdGEYcSABKAwiNwoJTWVkaWFUeXBlEhQKEFVua25vd25NZWRpYVR5cGUQABIJCgVBdWRpbxABEgkKBVZpZGVvEAIiWwoMTWVkaWFTdWJUeXBlEhcKE1Vua25vd25NZWRpYVN1YlR5cGUQABIJCgVNdXNpYxABEgsKB1BvZGNhc3QQBBINCglBdWRpb0Jvb2sQBRILCgdJVHVuZXNVEAY");
8925
+ const file_ContentItemMetadata = /* @__PURE__ */ fileDesc("ChlDb250ZW50SXRlbU1ldGFkYXRhLnByb3RvIrkBCg5BdWRpb1JvdXRlVHlwZSKmAQoERW51bRILCgdVbmtub3duEAASEgoORGV2aWNlc1NwZWFrZXIQARILCgdMaW5lT3V0EAISDgoKSGVhZHBob25lcxADEhcKE0JsdWV0b290aEhlYWRwaG9uZXMQBBIUChBCbHVldG9vdGhTcGVha2VyEAUSDAoIVVNCQXVkaW8QBhIMCghDYXJBdWRpbxAHEggKBEhETUkQCBILCgdBaXJQbGF5EAkiWQoKQXVkaW9Sb3V0ZRIdCgR0eXBlGAEgASgLMg8uQXVkaW9Sb3V0ZVR5cGUSDAoEbmFtZRgCIAEoCRIeChZzdXBwb3J0c1NwYXRpYWxpemF0aW9uGAMgASgIInkKCUF1ZGlvVGllciJsCgRFbnVtEhYKEkxvd0JhbmR3aWR0aFN0ZXJlbxABEhUKEUhpZ2hRdWFsaXR5U3RlcmVvEAISDAoITG9zc2xlc3MQAxIaChZIaWdoUmVzb2x1dGlvbkxvc3NsZXNzEAQSCwoHU3BhdGlhbBAFIocBCgpTb25nVHJhaXRzInkKBEVudW0SCAoETm9uZRAAEhcKE0FwcGxlRGlnaXRpYWxNYXN0ZXIQARIMCghMb3NzbGVzcxACEhoKFkhpZ2hSZXNvbHV0aW9uTG9zc2xlc3MQBBILCgdTcGF0aWFsEAgSCQoFQXRtb3MQEBIMCghTdXJyb3VuZBAgIogBCgtBbGJ1bVRyYWl0cyJ5CgRFbnVtEggKBE5vbmUQABIXChNBcHBsZURpZ2l0aWFsTWFzdGVyEAESDAoITG9zc2xlc3MQAhIaChZIaWdoUmVzb2x1dGlvbkxvc3NsZXNzEAQSCwoHU3BhdGlhbBAIEgkKBUF0bW9zEBASDAoIU3Vycm91bmQQICJICg5QbGF5bGlzdFRyYWl0cyI2CgRFbnVtEggKBE5vbmUQABILCgdTcGF0aWFsEAgSCQoFQXRtb3MQEBIMCghTdXJyb3VuZBAgIrwBChlBY3RpdmVGb3JtYXRKdXN0aWZpY2F0aW9uIp4BCgRFbnVtEgsKB1Vua25vd24QABIPCgtVbmF2YWlsYWJsZRABEhIKDlVzZXJQcmVmZXJlbmNlEGQSEAoMVXNlckRvd25sb2FkEGUSFgoRUm91dGVJbmNvbXBhdGlibGUQ9AMSHgoZUm91dGVVbmtub3duQ29tcGF0aWJpbGl0eRD1AxIaChVCYW5kd2lkdGhJbnN1ZmZpY2llbnQQ6AciegoKRm9ybWF0VGllciJsCgRFbnVtEhYKEkxvd0JhbmR3aWR0aFN0ZXJlbxABEhUKEUhpZ2hRdWFsaXR5U3RlcmVvEAISDAoITG9zc2xlc3MQBBIaChZIaWdoUmVzb2x1dGlvbkxvc3NsZXNzEAgSCwoHU3BhdGlhbBAQIoUCCgtBdWRpb0Zvcm1hdBIdCgR0aWVyGAEgASgOMg8uQXVkaW9UaWVyLkVudW0SDwoHYml0cmF0ZRgCIAEoAxISCgpzYW1wbGVSYXRlGAMgASgDEhAKCGJpdERlcHRoGAQgASgDEg0KBWNvZGVjGAUgASgNEhMKC3NwYXRpYWxpemVkGAYgASgIEhQKDG11bHRpQ2hhbm5lbBgHIAEoCBIVCg1jaGFubmVsTGF5b3V0GAggASgNEiUKHWF1ZGlvQ2hhbm5lbExheW91dERlc2NyaXB0aW9uGAkgASgJEg8KB2dyb3VwSUQYCiABKAkSFwoPc3RhYmxlVmFyaWFudElEGAsgASgJIvYYChNDb250ZW50SXRlbU1ldGFkYXRhEg0KBXRpdGxlGAEgASgJEhAKCHN1YnRpdGxlGAIgASgJEhMKC2lzQ29udGFpbmVyGAMgASgIEhIKCmlzUGxheWFibGUYBCABKAgSGAoQcGxheWJhY2tQcm9ncmVzcxgFIAEoAhIRCglhbGJ1bU5hbWUYBiABKAkSFwoPdHJhY2tBcnRpc3ROYW1lGAcgASgJEhcKD2FsYnVtQXJ0aXN0TmFtZRgIIAEoCRIUCgxkaXJlY3Rvck5hbWUYCSABKAkSFAoMc2Vhc29uTnVtYmVyGAogASgFEhUKDWVwaXNvZGVOdW1iZXIYCyABKAUSEwoLcmVsZWFzZURhdGUYDCABKAESEQoJcGxheUNvdW50GA0gASgFEhAKCGR1cmF0aW9uGA4gASgBEh4KFmxvY2FsaXplZENvbnRlbnRSYXRpbmcYDyABKAkSFgoOaXNFeHBsaWNpdEl0ZW0YECABKAgSFAoMcGxheWxpc3RUeXBlGBEgASgFEhgKEHJhZGlvU3RhdGlvblR5cGUYEiABKAUSGAoQYXJ0d29ya0F2YWlsYWJsZRgTIAEoCBIVCg1pbmZvQXZhaWxhYmxlGBUgASgIEiAKGGxhbmd1YWdlT3B0aW9uc0F2YWlsYWJsZRgWIAEoCBIYChBudW1iZXJPZlNlY3Rpb25zGBcgASgFEhcKD2x5cmljc0F2YWlsYWJsZRgYIAEoCBIZChFlZGl0aW5nU3R5bGVGbGFncxgZIAEoBRIaChJpc1N0cmVhbWluZ0NvbnRlbnQYGiABKAgSGgoSaXNDdXJyZW50bHlQbGF5aW5nGBsgASgIEhwKFGNvbGxlY3Rpb25JZGVudGlmaWVyGBwgASgJEhkKEXByb2ZpbGVJZGVudGlmaWVyGB0gASgJEhEKCXN0YXJ0VGltZRgeIAEoARIXCg9hcnR3b3JrTUlNRVR5cGUYHyABKAkSFgoOYXNzZXRVUkxTdHJpbmcYICABKAkSEAoIY29tcG9zZXIYISABKAkSEgoKZGlzY051bWJlchgiIAEoBRITCgtlbGFwc2VkVGltZRgjIAEoARINCgVnZW5yZRgkIAEoCRIUCgxpc0Fsd2F5c0xpdmUYJSABKAgSFAoMcGxheWJhY2tSYXRlGCcgASgCEhQKDGNoYXB0ZXJDb3VudBgoIAEoBRIWCg50b3RhbERpc2NDb3VudBgpIAEoBRIXCg90b3RhbFRyYWNrQ291bnQYKiABKAUSEwoLdHJhY2tOdW1iZXIYKyABKAUSGQoRY29udGVudElkZW50aWZpZXIYLCABKAkSEgoKaXNTaGFyYWJsZRguIAEoCBIPCgdpc0xpa2VkGDAgASgIEhQKDGlzSW5XaXNoTGlzdBgxIAEoCBIeChZyYWRpb1N0YXRpb25JZGVudGlmaWVyGDIgASgDEhgKEHJhZGlvU3RhdGlvbk5hbWUYNCABKAkSGgoScmFkaW9TdGF0aW9uU3RyaW5nGDUgASgJEh0KFWlUdW5lc1N0b3JlSWRlbnRpZmllchg2IAEoAxIpCiFpVHVuZXNTdG9yZVN1YnNjcmlwdGlvbklkZW50aWZpZXIYNyABKAMSIwobaVR1bmVzU3RvcmVBcnRpc3RJZGVudGlmaWVyGDggASgDEiIKGmlUdW5lc1N0b3JlQWxidW1JZGVudGlmaWVyGDkgASgDEhgKEHB1cmNoYXNlSW5mb0RhdGEYOiABKAwSGwoTZGVmYXVsdFBsYXliYWNrUmF0ZRg7IAEoAhIVCg1kb3dubG9hZFN0YXRlGDwgASgFEhgKEGRvd25sb2FkUHJvZ3Jlc3MYPSABKAISFgoOYXBwTWV0cmljc0RhdGEYPiABKAwSEgoKc2VyaWVzTmFtZRg/IAEoCRIxCgltZWRpYVR5cGUYQCABKA4yHi5Db250ZW50SXRlbU1ldGFkYXRhLk1lZGlhVHlwZRI3CgxtZWRpYVN1YlR5cGUYQSABKA4yIS5Db250ZW50SXRlbU1ldGFkYXRhLk1lZGlhU3ViVHlwZRIaChJub3dQbGF5aW5nSW5mb0RhdGEYQyABKAwSFAoMdXNlckluZm9EYXRhGEQgASgMEhMKC2lzU3RlZXJhYmxlGEUgASgIEhIKCmFydHdvcmtVUkwYRiABKAkSEQoJbHlyaWNzVVJMGEcgASgJEiIKGmRldmljZVNwZWNpZmljVXNlckluZm9EYXRhGEggASgMEhoKEmNvbGxlY3Rpb25JbmZvRGF0YRhJIAEoDBIcChRlbGFwc2VkVGltZVRpbWVzdGFtcBhKIAEoARIZChFpbmZlcnJlZFRpbWVzdGFtcBhLIAEoARIZChFzZXJ2aWNlSWRlbnRpZmllchhMIAEoCRIiChphcnR3b3JrRGF0YVdpZHRoRGVwcmVjYXRlZBhNIAEoBRIjChthcnR3b3JrRGF0YUhlaWdodERlcHJlY2F0ZWQYTiABKAUSHwoXY3VycmVudFBsYXliYWNrRGF0ZURhdGEYTyABKAwSGQoRYXJ0d29ya0lkZW50aWZpZXIYUCABKAkSEQoJaXNMb2FkaW5nGFEgASgIEh8KF2FydHdvcmtVUkxUZW1wbGF0ZXNEYXRhGFIgASgMEh4KFmxlZ2FjeVVuaXF1ZUlkZW50aWZpZXIYUyABKAMSEwoLZXBpc29kZVR5cGUYVCABKAUSFgoOYXJ0d29ya0ZpbGVVUkwYVSABKAkSFwoPYnJhbmRJZGVudGlmaWVyGFYgASgJEh8KF2xvY2FsaXplZER1cmF0aW9uU3RyaW5nGFcgASgJEhEKCWFsYnVtWWVhchhYIAEoCRIkCgpzb25nVHJhaXRzGFkgASgOMhAuU29uZ1RyYWl0cy5FbnVtEiYKC2FsYnVtVHJhaXRzGFogASgOMhEuQWxidW1UcmFpdHMuRW51bRIsCg5wbGF5bGlzdFRyYWl0cxhbIAEoDjIULlBsYXlsaXN0VHJhaXRzLkVudW0SJQoPcHJlZmVycmVkRm9ybWF0GFwgASgLMgwuQXVkaW9Gb3JtYXQSIgoMYWN0aXZlRm9ybWF0GF0gASgLMgwuQXVkaW9Gb3JtYXQSQgoZYWN0aXZlRm9ybWF0SnVzdGlmaWNhdGlvbhheIAEoDjIfLkFjdGl2ZUZvcm1hdEp1c3RpZmljYXRpb24uRW51bRIuChRmb3JtYXRUaWVyUHJlZmVyZW5jZRhfIAEoDjIQLkZvcm1hdFRpZXIuRW51bRIfCgphdWRpb1JvdXRlGGAgASgLMgsuQXVkaW9Sb3V0ZRIoChJhbHRlcm5hdGl2ZUZvcm1hdHMYYSADKAsyDC5BdWRpb0Zvcm1hdBIXCg9pc0FkdmVydGlzZW1lbnQYYiABKAgSHQoVaGFzQWx0ZXJuYXRpdmVGb3JtYXRzGGMgASgIEhcKD3BhcnRpY2lwYW50TmFtZRhkIAEoCRIdChVwYXJ0aWNpcGFudElkZW50aWZpZXIYZSABKAkSFQoNY2xhc3NpY2FsV29yaxhmIAEoCRIXCg9yZXBvcnRpbmdBZGFtSUQYZyABKAMSFAoMbHlyaWNzQWRhbUlEGGggASgDEigKIGlUdW5lc1N0b3JlQWxidW1BcnRpc3RJZGVudGlmaWVyGGkgASgDEiUKHWR1cmF0aW9uU3RyaW5nTG9jYWxpemF0aW9uS2V5GGogASgJEh8KF2lzUmVzb2x2YWJsZVBhcnRpY2lwYW50GGsgASgIEioKImludGVybmF0aW9uYWxTdGFuZGFyZFJlY29yZGluZ0NvZGUYbCABKAkSFgoOaXNJblRyYW5zaXRpb24YbSABKAgSHgoWZXhjbHVkZUZyb21TdWdnZXN0aW9ucxhuIAEoCBIlCh10cmFuc2NyaXB0QWxpZ25tZW50c0F2YWlsYWJsZRhvIAEoCBIVCg1zdWJ0aXRsZVNob3J0GHAgASgJEhoKEnRyYW5zaXRpb25JbmZvRGF0YRhxIAEoDBITCgtlbnRpdHlQYXRocxhyIAMoDCI3CglNZWRpYVR5cGUSFAoQVW5rbm93bk1lZGlhVHlwZRAAEgkKBUF1ZGlvEAESCQoFVmlkZW8QAiJbCgxNZWRpYVN1YlR5cGUSFwoTVW5rbm93bk1lZGlhU3ViVHlwZRAAEgkKBU11c2ljEAESCwoHUG9kY2FzdBAEEg0KCUF1ZGlvQm9vaxAFEgsKB0lUdW5lc1UQBg");
8746
8926
  /**
8747
8927
  * Describes the message AudioRouteType.
8748
8928
  * Use `create(AudioRouteTypeSchema)` to create a new message.
@@ -9224,6 +9404,53 @@ const CryptoPairingMessageSchema = /* @__PURE__ */ messageDesc(file_CryptoPairin
9224
9404
  */
9225
9405
  const cryptoPairingMessage = /* @__PURE__ */ extDesc(file_CryptoPairingMessage, 0);
9226
9406
 
9407
+ //#endregion
9408
+ //#region src/proto/DelegationServiceMessage_pb.ts
9409
+ /**
9410
+ * Describes the file DelegationServiceMessage.proto.
9411
+ */
9412
+ const file_DelegationServiceMessage = /* @__PURE__ */ fileDesc("Ch5EZWxlZ2F0aW9uU2VydmljZU1lc3NhZ2UucHJvdG8ihgIKGERlbGVnYXRpb25TZXJ2aWNlTWVzc2FnZRI3ChZzdGFydERlbGVnYXRpb25SZXF1ZXN0GAEgASgLMhcuU3RhcnREZWxlZ2F0aW9uUmVxdWVzdBI5ChdzdGFydERlbGVnYXRpb25SZXNwb25zZRgCIAEoCzIYLlN0YXJ0RGVsZWdhdGlvblJlc3BvbnNlEjkKF2ZpbmlzaERlbGVnYXRpb25SZXF1ZXN0GAMgASgLMhguRmluaXNoRGVsZWdhdGlvblJlcXVlc3QSOwoYZmluaXNoRGVsZWdhdGlvblJlc3BvbnNlGAQgASgLMhkuRmluaXNoRGVsZWdhdGlvblJlc3BvbnNlIkMKFlN0YXJ0RGVsZWdhdGlvblJlcXVlc3QSEQoJc2VydmljZUlEGAEgASgNEhYKDmRlbGVnYXRpb25VVUlEGAIgASgJIkIKF1N0YXJ0RGVsZWdhdGlvblJlc3BvbnNlEhEKCXNlcnZpY2VJRBgBIAEoDRIUCgxyZXNwb25zZURhdGEYAiABKAwiQQoXRmluaXNoRGVsZWdhdGlvblJlcXVlc3QSEQoJc2VydmljZUlEGAEgASgNEhMKC3JlcXVlc3REYXRhGAIgASgMIj4KGEZpbmlzaERlbGVnYXRpb25SZXNwb25zZRIRCglzZXJ2aWNlSUQYASABKA0SDwoHc3VjY2VzcxgCIAEoCCIrChZQbGF5ZXJJbmZvQ29udGV4dFRva2VuEhEKCXRva2VuRGF0YRgBIAEoCSI/ChdQbGF5ZXJEZWxlZ2F0ZUluZm9Ub2tlbhIRCgl0b2tlbkRhdGEYASABKAkSEQoJc2VydmljZUlEGAIgASgNIkUKHVBsYXllckluZm9Db250ZXh0UmVxdWVzdFRva2VuEhEKCXRva2VuRGF0YRgBIAEoCRIRCglzZXJ2aWNlSUQYAiABKA0", [file_ProtocolMessage]);
9413
+ /**
9414
+ * Describes the message DelegationServiceMessage.
9415
+ * Use `create(DelegationServiceMessageSchema)` to create a new message.
9416
+ */
9417
+ const DelegationServiceMessageSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 0);
9418
+ /**
9419
+ * Describes the message StartDelegationRequest.
9420
+ * Use `create(StartDelegationRequestSchema)` to create a new message.
9421
+ */
9422
+ const StartDelegationRequestSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 1);
9423
+ /**
9424
+ * Describes the message StartDelegationResponse.
9425
+ * Use `create(StartDelegationResponseSchema)` to create a new message.
9426
+ */
9427
+ const StartDelegationResponseSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 2);
9428
+ /**
9429
+ * Describes the message FinishDelegationRequest.
9430
+ * Use `create(FinishDelegationRequestSchema)` to create a new message.
9431
+ */
9432
+ const FinishDelegationRequestSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 3);
9433
+ /**
9434
+ * Describes the message FinishDelegationResponse.
9435
+ * Use `create(FinishDelegationResponseSchema)` to create a new message.
9436
+ */
9437
+ const FinishDelegationResponseSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 4);
9438
+ /**
9439
+ * Describes the message PlayerInfoContextToken.
9440
+ * Use `create(PlayerInfoContextTokenSchema)` to create a new message.
9441
+ */
9442
+ const PlayerInfoContextTokenSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 5);
9443
+ /**
9444
+ * Describes the message PlayerDelegateInfoToken.
9445
+ * Use `create(PlayerDelegateInfoTokenSchema)` to create a new message.
9446
+ */
9447
+ const PlayerDelegateInfoTokenSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 6);
9448
+ /**
9449
+ * Describes the message PlayerInfoContextRequestToken.
9450
+ * Use `create(PlayerInfoContextRequestTokenSchema)` to create a new message.
9451
+ */
9452
+ const PlayerInfoContextRequestTokenSchema = /* @__PURE__ */ messageDesc(file_DelegationServiceMessage, 7);
9453
+
9227
9454
  //#endregion
9228
9455
  //#region src/proto/Destination_pb.ts
9229
9456
  /**
@@ -10062,7 +10289,7 @@ const microphoneConnectionResponseMessage = /* @__PURE__ */ extDesc(file_Microph
10062
10289
  /**
10063
10290
  * Describes the file ModifyOutputContextRequestMessage.proto.
10064
10291
  */
10065
- const file_ModifyOutputContextRequestMessage = /* @__PURE__ */ fileDesc("CidNb2RpZnlPdXRwdXRDb250ZXh0UmVxdWVzdE1lc3NhZ2UucHJvdG8iRQoeTW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RUeXBlIiMKBEVudW0SGwoXU2hhcmVkQXVkaW9QcmVzZW50YXRpb24QASKLAgohTW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RNZXNzYWdlEjIKBHR5cGUYASABKA4yJC5Nb2RpZnlPdXRwdXRDb250ZXh0UmVxdWVzdFR5cGUuRW51bRIVCg1hZGRpbmdEZXZpY2VzGAIgAygJEhcKD3JlbW92aW5nRGV2aWNlcxgDIAMoCRIWCg5zZXR0aW5nRGV2aWNlcxgEIAMoCRIhChljbHVzdGVyQXdhcmVBZGRpbmdEZXZpY2VzGAUgAygJEiMKG2NsdXN0ZXJBd2FyZVJlbW92aW5nRGV2aWNlcxgGIAMoCRIiChpjbHVzdGVyQXdhcmVTZXR0aW5nRGV2aWNlcxgHIAMoCTqCAQohbW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RNZXNzYWdlEhAuUHJvdG9jb2xNZXNzYWdlGDQgASgLMiIuTW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RNZXNzYWdlUiFtb2RpZnlPdXRwdXRDb250ZXh0UmVxdWVzdE1lc3NhZ2U", [file_ProtocolMessage]);
10292
+ const file_ModifyOutputContextRequestMessage = /* @__PURE__ */ fileDesc("CidNb2RpZnlPdXRwdXRDb250ZXh0UmVxdWVzdE1lc3NhZ2UucHJvdG8iRQoeTW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RUeXBlIiMKBEVudW0SGwoXU2hhcmVkQXVkaW9QcmVzZW50YXRpb24QASLOAgohTW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RNZXNzYWdlEj8KEW91dHB1dENvbnRleHRUeXBlGAEgASgOMiQuTW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RUeXBlLkVudW0SHgoWYWRkaW5nT3V0cHV0RGV2aWNlVUlEcxgCIAMoCRIgChhyZW1vdmluZ091dHB1dERldmljZVVJRHMYAyADKAkSHwoXc2V0dGluZ091dHB1dERldmljZVVJRHMYBCADKAkSKgoiY2x1c3RlckF3YXJlQWRkaW5nT3V0cHV0RGV2aWNlVUlEcxgFIAMoCRIsCiRjbHVzdGVyQXdhcmVSZW1vdmluZ091dHB1dERldmljZVVJRHMYBiADKAkSKwojY2x1c3RlckF3YXJlU2V0dGluZ091dHB1dERldmljZVVJRHMYByADKAk6ggEKIW1vZGlmeU91dHB1dENvbnRleHRSZXF1ZXN0TWVzc2FnZRIQLlByb3RvY29sTWVzc2FnZRg0IAEoCzIiLk1vZGlmeU91dHB1dENvbnRleHRSZXF1ZXN0TWVzc2FnZVIhbW9kaWZ5T3V0cHV0Q29udGV4dFJlcXVlc3RNZXNzYWdl", [file_ProtocolMessage]);
10066
10293
  /**
10067
10294
  * Describes the message ModifyOutputContextRequestType.
10068
10295
  * Use `create(ModifyOutputContextRequestTypeSchema)` to create a new message.
@@ -10204,7 +10431,7 @@ const PlaybackQueueContextSchema = /* @__PURE__ */ messageDesc(file_PlaybackQueu
10204
10431
  /**
10205
10432
  * Describes the file PlaybackQueue.proto.
10206
10433
  */
10207
- const file_PlaybackQueue = /* @__PURE__ */ fileDesc("ChNQbGF5YmFja1F1ZXVlLnByb3RvIvsCCg1QbGF5YmFja1F1ZXVlEhAKCGxvY2F0aW9uGAEgASgFEiIKDGNvbnRlbnRJdGVtcxgCIAMoCzIMLkNvbnRlbnRJdGVtEiYKB2NvbnRleHQYAyABKAsyFS5QbGF5YmFja1F1ZXVlQ29udGV4dBIRCglyZXF1ZXN0SWQYBCABKAkSJwoScmVzb2x2ZWRQbGF5ZXJQYXRoGAUgASgLMgsuUGxheWVyUGF0aBInCh9zZW5kaW5nUGxheWJhY2tRdWV1ZVRyYW5zYWN0aW9uGAYgASgIEhcKD3F1ZXVlSWRlbnRpZmllchgHIAEoCRIiCgxwYXJ0aWNpcGFudHMYCCADKAsyDC5Db250ZW50SXRlbRIbChNob21lVXNlcklkZW50aWZpZXJzGAkgAygJEh8KCnByb3BlcnRpZXMYCiABKAsyCy5EaWN0aW9uYXJ5EiwKF2F1eGlsaWFyeU5vd1BsYXlpbmdJbmZvGAsgASgLMgsuRGljdGlvbmFyeQ", [
10434
+ const file_PlaybackQueue = /* @__PURE__ */ fileDesc("ChNQbGF5YmFja1F1ZXVlLnByb3RvIvsCCg1QbGF5YmFja1F1ZXVlEhAKCGxvY2F0aW9uGAEgASgFEiIKDGNvbnRlbnRJdGVtcxgCIAMoCzIMLkNvbnRlbnRJdGVtEiYKB2NvbnRleHQYAyABKAsyFS5QbGF5YmFja1F1ZXVlQ29udGV4dBIRCglyZXF1ZXN0SUQYBCABKAkSJwoScmVzb2x2ZWRQbGF5ZXJQYXRoGAUgASgLMgsuUGxheWVyUGF0aBInCh9zZW5kaW5nUGxheWJhY2tRdWV1ZVRyYW5zYWN0aW9uGAYgASgIEhcKD3F1ZXVlSWRlbnRpZmllchgHIAEoCRIiCgxwYXJ0aWNpcGFudHMYCCADKAsyDC5Db250ZW50SXRlbRIbChNob21lVXNlcklkZW50aWZpZXJzGAkgAygJEh8KCnByb3BlcnRpZXMYCiABKAsyCy5EaWN0aW9uYXJ5EiwKF2F1eGlsaWFyeU5vd1BsYXlpbmdJbmZvGAsgASgLMgsuRGljdGlvbmFyeQ", [
10208
10435
  file_ContentItem,
10209
10436
  file_Dictionary,
10210
10437
  file_PlaybackQueueContext,
@@ -12016,6 +12243,7 @@ var proto_exports = /* @__PURE__ */ __exportAll({
12016
12243
  CreateHostedEndpointResponseSchema: () => CreateHostedEndpointResponseSchema,
12017
12244
  CryptoPairingMessageSchema: () => CryptoPairingMessageSchema,
12018
12245
  DataArtworkSchema: () => DataArtworkSchema,
12246
+ DelegationServiceMessageSchema: () => DelegationServiceMessageSchema,
12019
12247
  DestinationSchema: () => DestinationSchema,
12020
12248
  DeviceClassSchema: () => DeviceClassSchema,
12021
12249
  DeviceClass_Enum: () => DeviceClass_Enum,
@@ -12040,6 +12268,8 @@ var proto_exports = /* @__PURE__ */ __exportAll({
12040
12268
  ErrorCode_Enum: () => ErrorCode_Enum,
12041
12269
  ErrorCode_EnumSchema: () => ErrorCode_EnumSchema,
12042
12270
  ErrorSchema: () => ErrorSchema,
12271
+ FinishDelegationRequestSchema: () => FinishDelegationRequestSchema,
12272
+ FinishDelegationResponseSchema: () => FinishDelegationResponseSchema,
12043
12273
  FormatTierSchema: () => FormatTierSchema,
12044
12274
  FormatTier_Enum: () => FormatTier_Enum,
12045
12275
  FormatTier_EnumSchema: () => FormatTier_EnumSchema,
@@ -12141,6 +12371,9 @@ var proto_exports = /* @__PURE__ */ __exportAll({
12141
12371
  PlaybackState_EnumSchema: () => PlaybackState_EnumSchema,
12142
12372
  PlayerClientParticipantsUpdateMessageSchema: () => PlayerClientParticipantsUpdateMessageSchema,
12143
12373
  PlayerClientPropertiesMessageSchema: () => PlayerClientPropertiesMessageSchema,
12374
+ PlayerDelegateInfoTokenSchema: () => PlayerDelegateInfoTokenSchema,
12375
+ PlayerInfoContextRequestTokenSchema: () => PlayerInfoContextRequestTokenSchema,
12376
+ PlayerInfoContextTokenSchema: () => PlayerInfoContextTokenSchema,
12144
12377
  PlayerOptionsSchema: () => PlayerOptionsSchema,
12145
12378
  PlayerOptions_Enum: () => PlayerOptions_Enum,
12146
12379
  PlayerOptions_EnumSchema: () => PlayerOptions_EnumSchema,
@@ -12238,6 +12471,8 @@ var proto_exports = /* @__PURE__ */ __exportAll({
12238
12471
  SongTraitsSchema: () => SongTraitsSchema,
12239
12472
  SongTraits_Enum: () => SongTraits_Enum,
12240
12473
  SongTraits_EnumSchema: () => SongTraits_EnumSchema,
12474
+ StartDelegationRequestSchema: () => StartDelegationRequestSchema,
12475
+ StartDelegationResponseSchema: () => StartDelegationResponseSchema,
12241
12476
  SupportedCommandsSchema: () => SupportedCommandsSchema,
12242
12477
  SystemPlaybackCustomDataSchema: () => SystemPlaybackCustomDataSchema,
12243
12478
  SystemPlaybackGenericTracklistQueueSchema: () => SystemPlaybackGenericTracklistQueueSchema,
@@ -12311,6 +12546,7 @@ var proto_exports = /* @__PURE__ */ __exportAll({
12311
12546
  file_CreateHostedEndpointRequestMessage: () => file_CreateHostedEndpointRequestMessage,
12312
12547
  file_CreateHostedEndpointResponseMessage: () => file_CreateHostedEndpointResponseMessage,
12313
12548
  file_CryptoPairingMessage: () => file_CryptoPairingMessage,
12549
+ file_DelegationServiceMessage: () => file_DelegationServiceMessage,
12314
12550
  file_Destination: () => file_Destination,
12315
12551
  file_DeviceInfoMessage: () => file_DeviceInfoMessage,
12316
12552
  file_Diagnostic: () => file_Diagnostic,
@@ -12945,6 +13181,121 @@ var ControlStream = class extends RtspClient {
12945
13181
  return await this.exchange("POST", `/volume?volume=${volume.toFixed(6)}`, { allowError: true });
12946
13182
  }
12947
13183
  /**
13184
+ * Sets the audio routing mode on the receiver.
13185
+ *
13186
+ * @param mode - The audio mode to set (e.g. 'default', 'moviePlayback', 'spoken').
13187
+ * @returns The response.
13188
+ */
13189
+ async setAudioMode(mode) {
13190
+ const body = Plist.serialize({ audioMode: mode });
13191
+ return await this.exchange("POST", "/audioMode", {
13192
+ body: Buffer.from(body),
13193
+ headers: { "Content-Type": "application/x-apple-binary-plist" },
13194
+ allowError: true
13195
+ });
13196
+ }
13197
+ /**
13198
+ * Stops the current URL playback session.
13199
+ *
13200
+ * @returns The response.
13201
+ */
13202
+ async stop() {
13203
+ return await this.exchange("POST", "/stop", { allowError: true });
13204
+ }
13205
+ /**
13206
+ * Seeks to a specific position during URL playback.
13207
+ *
13208
+ * @param position - The position in seconds to seek to.
13209
+ * @returns The response.
13210
+ */
13211
+ async scrub(position) {
13212
+ return await this.exchange("POST", `/scrub?position=${position.toFixed(6)}`, { allowError: true });
13213
+ }
13214
+ /**
13215
+ * Sends an RTSP FLUSHBUFFERED request to flush buffered audio.
13216
+ *
13217
+ * More targeted than FLUSH — specifically for buffered audio sessions.
13218
+ * Supports range-based flushing via flushFromSeq/TS and flushUntilSeq/TS headers.
13219
+ *
13220
+ * @param uri - RTSP resource URI (typically `/{sessionId}`).
13221
+ * @param headers - Additional headers (e.g. flush range parameters).
13222
+ * @returns The RTSP response.
13223
+ */
13224
+ async flushBuffered(uri, headers = {}) {
13225
+ return await this.exchange("FLUSHBUFFERED", uri, {
13226
+ headers,
13227
+ allowError: true
13228
+ });
13229
+ }
13230
+ /**
13231
+ * Gets a property from the AirPlay receiver.
13232
+ *
13233
+ * Known property keys (from AirPlayReceiver framework):
13234
+ *
13235
+ * **Volume:**
13236
+ * - `Volume` — current volume
13237
+ * - `VolumeDB` — volume in decibels
13238
+ * - `VolumeLinear` — linear volume (0.0-1.0)
13239
+ * - `SoftwareVolume` — software volume level
13240
+ * - `VolumeControlType` / `VolumeControlTypeEx` — volume control capabilities
13241
+ * - `IsMuted` / `MuteForStream` — mute state
13242
+ *
13243
+ * **Playback:**
13244
+ * - `ReceiverDeviceIsPlaying` — whether the device is currently playing
13245
+ * - `IsPlayingBufferedAudio` — whether buffered audio is active
13246
+ * - `DenyInterruptions` — interruption prevention state
13247
+ *
13248
+ * **Audio:**
13249
+ * - `AudioFormat` — current audio format
13250
+ * - `AudioLatencyMs` / `AudioLatencyMax` / `AudioLatencyMin` — latency info
13251
+ * - `RedundantAudio` — redundancy status
13252
+ * - `SpatialAudio` / `SpatialAudioActive` / `SpatialAudioAllowed` — spatial audio state
13253
+ *
13254
+ * **Device:**
13255
+ * - `DeviceID` / `DeviceName` — device identity
13256
+ * - `IdleTimeout` — idle timeout value
13257
+ * - `SecurityMode` — security mode
13258
+ * - `ReceiverMode` — current receiver mode
13259
+ *
13260
+ * **Display:**
13261
+ * - `DisplayHDRMode` — HDR mode
13262
+ * - `DisplaySize` / `DisplaySizeMax` — display dimensions
13263
+ * - `DisplayUUID` — display identifier
13264
+ *
13265
+ * **Cluster/Multi-room:**
13266
+ * - `ClusterUUID` / `ClusterType` / `ClusterSize` — cluster info
13267
+ * - `IsClusterLeader` / `ClusterLeaderUUID` — cluster leadership
13268
+ * - `TightSyncUUID` / `IsTightSyncGroupLeader` — tight sync state
13269
+ * - `GroupContainsDiscoverableLeader` / `GroupContextID` — group info
13270
+ *
13271
+ * **Network:**
13272
+ * - `UsePTPClock` — PTP clock usage
13273
+ * - `NetworkClock` — network clock type
13274
+ *
13275
+ * **DACP-style (via setproperty? URL):**
13276
+ * - `dmcp.device-volume` — DACP device volume
13277
+ * - `dmcp.device-prevent-playback` — DACP prevent playback
13278
+ *
13279
+ * @param property - The property key to query.
13280
+ * @returns The response (body contains the property value, typically as plist).
13281
+ */
13282
+ async getProperty(property) {
13283
+ return await this.get(`/getProperty?${property}`);
13284
+ }
13285
+ /**
13286
+ * Sets a property on the AirPlay receiver.
13287
+ *
13288
+ * See {@link getProperty} for the full list of known property keys.
13289
+ * For set operations, the property string contains key=value pairs.
13290
+ *
13291
+ * @param property - The property key=value to set (e.g. `Volume=0.5`).
13292
+ * @param body - Optional request body for complex property values (plist).
13293
+ * @returns The response.
13294
+ */
13295
+ async setProperty(property, body) {
13296
+ return await this.put(`/setProperty?${property}`, body);
13297
+ }
13298
+ /**
12948
13299
  * Sends an RTSP TEARDOWN request to end a stream session.
12949
13300
  *
12950
13301
  * @param path - RTSP resource URI (typically `/{sessionId}`).
@@ -13053,13 +13404,220 @@ var DataStream = class extends BaseStream {
13053
13404
  this.#handlers[ProtocolMessage_Type.UPDATE_CONTENT_ITEM_MESSAGE] = [updateContentItemMessage, this.#onUpdateContentItemMessage.bind(this)];
13054
13405
  this.#handlers[ProtocolMessage_Type.UPDATE_CONTENT_ITEM_ARTWORK_MESSAGE] = [updateContentItemArtworkMessage, this.#onUpdateContentItemArtworkMessage.bind(this)];
13055
13406
  this.#handlers[ProtocolMessage_Type.UPDATE_PLAYER_MESSAGE] = [updatePlayerMessage, this.#onUpdatePlayerMessage.bind(this)];
13056
- this.#handlers[ProtocolMessage_Type.UPDATE_OUTPUT_DEVICE_MESSAGE] = [updateOutputDeviceMessage, this.#onUpdateOutputDeviceMessage.bind(this)];
13407
+ this.#handlers[ProtocolMessage_Type.SYNC_OUTPUT_DEVICES_MESSAGE] = [updateOutputDeviceMessage, this.#onUpdateOutputDeviceMessage.bind(this)];
13057
13408
  this.#handlers[ProtocolMessage_Type.VOLUME_CONTROL_AVAILABILITY_MESSAGE] = [volumeControlAvailabilityMessage, this.#onVolumeControlAvailabilityMessage.bind(this)];
13058
13409
  this.#handlers[ProtocolMessage_Type.VOLUME_CONTROL_CAPABILITIES_DID_CHANGE_MESSAGE] = [volumeControlCapabilitiesDidChangeMessage, this.#onVolumeControlCapabilitiesDidChangeMessage.bind(this)];
13059
13410
  this.#handlers[ProtocolMessage_Type.VOLUME_DID_CHANGE_MESSAGE] = [volumeDidChangeMessage, this.#onVolumeDidChangeMessage.bind(this)];
13060
13411
  this.#handlers[ProtocolMessage_Type.VOLUME_MUTED_DID_CHANGE_MESSAGE] = [volumeMutedDidChangeMessage, this.#onVolumeMutedDidChangeMessage.bind(this)];
13061
13412
  this.#handlers[ProtocolMessage_Type.SEND_LYRICS_EVENT] = [sendLyricsEventMessage, this.#onSendLyricsEventMessage.bind(this)];
13062
13413
  this.#handlers[ProtocolMessage_Type.CONFIGURE_CONNECTION_MESSAGE] = [configureConnectionMessage, this.#onConfigureConnectionMessage.bind(this)];
13414
+ this.#handlers[ProtocolMessage_Type.PLAYER_CLIENT_PARTICIPANTS_UPDATE_MESSAGE] = [playerClientParticipantsUpdateMessage, this.#onPlayerClientParticipantsUpdateMessage.bind(this)];
13415
+ const auto = [
13416
+ [
13417
+ ProtocolMessage_Type.AUDIO_FADE_MESSAGE,
13418
+ audioFadeMessage,
13419
+ "audioFade"
13420
+ ],
13421
+ [
13422
+ ProtocolMessage_Type.AUDIO_FADE_RESPONSE_MESSAGE,
13423
+ audioFadeResponseMessage,
13424
+ "audioFadeResponse"
13425
+ ],
13426
+ [
13427
+ ProtocolMessage_Type.ADJUST_VOLUME_MESSAGE,
13428
+ adjustVolumeMessage,
13429
+ "adjustVolume"
13430
+ ],
13431
+ [
13432
+ ProtocolMessage_Type.GET_VOLUME_RESULT_MESSAGE,
13433
+ getVolumeResultMessage,
13434
+ "getVolumeResult"
13435
+ ],
13436
+ [
13437
+ ProtocolMessage_Type.GET_VOLUME_MUTED_RESULT_MESSAGE,
13438
+ getVolumeMutedResultMessage,
13439
+ "getVolumeMutedResult"
13440
+ ],
13441
+ [
13442
+ ProtocolMessage_Type.NOTIFICATION_MESSAGE,
13443
+ notificationMessage,
13444
+ "notification"
13445
+ ],
13446
+ [
13447
+ ProtocolMessage_Type.SET_CONNECTION_STATE_MESSAGE,
13448
+ setConnectionStateMessage,
13449
+ "setConnectionState"
13450
+ ],
13451
+ [
13452
+ ProtocolMessage_Type.SET_DISCOVERY_MODE_MESSAGE,
13453
+ setDiscoveryModeMessage,
13454
+ "setDiscoveryMode"
13455
+ ],
13456
+ [
13457
+ ProtocolMessage_Type.SET_LISTENING_MODE_MESSAGE,
13458
+ setListeningModeMessage,
13459
+ "setListeningMode"
13460
+ ],
13461
+ [
13462
+ ProtocolMessage_Type.TRANSACTION_MESSAGE,
13463
+ transactionMessage,
13464
+ "transaction"
13465
+ ],
13466
+ [
13467
+ ProtocolMessage_Type.UPDATE_ACTIVE_SYSTEM_ENDPOINT_MESSAGE,
13468
+ updateActiveSystemEndpointMessage,
13469
+ "updateActiveSystemEndpoint"
13470
+ ],
13471
+ [
13472
+ ProtocolMessage_Type.UPDATE_SYNCED_ENDPOINTS_MESSAGE,
13473
+ updateEndPointsMessage,
13474
+ "updateEndpoints"
13475
+ ],
13476
+ [
13477
+ ProtocolMessage_Type.REMOVE_SYNCED_ENDPOINTS_MESSAGE,
13478
+ removeEndpointsMessage,
13479
+ "removeEndpoints"
13480
+ ],
13481
+ [
13482
+ ProtocolMessage_Type.REMOVE_SYNCED_OUTPUT_DEVICES_MESSAGE,
13483
+ removeOutputDevicesMessage,
13484
+ "removeOutputDevices"
13485
+ ],
13486
+ [
13487
+ ProtocolMessage_Type.WAKE_DEVICE_MESSAGE,
13488
+ wakeDeviceMessage,
13489
+ "wakeDevice"
13490
+ ],
13491
+ [
13492
+ ProtocolMessage_Type.GENERIC_MESSAGE,
13493
+ genericMessage,
13494
+ "genericMessage"
13495
+ ],
13496
+ [
13497
+ ProtocolMessage_Type.PLAYBACK_SESSION_REQUEST_MESSAGE,
13498
+ playbackSessionRequestMessage,
13499
+ "playbackSessionRequest"
13500
+ ],
13501
+ [
13502
+ ProtocolMessage_Type.PLAYBACK_SESSION_RESPONSE_MESSAGE,
13503
+ playbackSessionResponseMessage,
13504
+ "playbackSessionResponse"
13505
+ ],
13506
+ [
13507
+ ProtocolMessage_Type.PLAYBACK_SESSION_MIGRATE_REQUEST_MESSAGE,
13508
+ playbackSessionMigrateRequestMessage,
13509
+ "playbackSessionMigrateRequest"
13510
+ ],
13511
+ [
13512
+ ProtocolMessage_Type.PLAYBACK_SESSION_MIGRATE_RESPONSE_MESSAGE,
13513
+ playbackSessionMigrateResponseMessage,
13514
+ "playbackSessionMigrateResponse"
13515
+ ],
13516
+ [
13517
+ ProtocolMessage_Type.PLAYBACK_SESSION_MIGRATE_BEGIN_MESSAGE,
13518
+ playbackSessionMigrateBeginMessage,
13519
+ "playbackSessionMigrateBegin"
13520
+ ],
13521
+ [
13522
+ ProtocolMessage_Type.PLAYBACK_SESSION_MIGRATE_END_MESSAGE,
13523
+ playbackSessionMigrateEndMessage,
13524
+ "playbackSessionMigrateEnd"
13525
+ ],
13526
+ [
13527
+ ProtocolMessage_Type.PLAYBACK_SESSION_MIGRATE_POST_MESSAGE,
13528
+ playbackSessionMigratePostMessage,
13529
+ "playbackSessionMigratePost"
13530
+ ],
13531
+ [
13532
+ ProtocolMessage_Type.CREATE_HOSTED_ENDPOINT_REQUEST_MESSAGE,
13533
+ createHostedEndpointRequest,
13534
+ "createHostedEndpointRequest"
13535
+ ],
13536
+ [
13537
+ ProtocolMessage_Type.CREATE_HOSTED_ENDPOINT_RESPONSE_MESSAGE,
13538
+ createHostedEndpointResponse,
13539
+ "createHostedEndpointResponse"
13540
+ ],
13541
+ [
13542
+ ProtocolMessage_Type.PROMPT_FOR_ROUTE_AUTHORIZATION_MESSAGE,
13543
+ promptForRouteAuthorizationMessage,
13544
+ "promptForRouteAuthorization"
13545
+ ],
13546
+ [
13547
+ ProtocolMessage_Type.PROMPT_FOR_ROUTE_AUTHORIZATION_RESPONSE_MESSAGE,
13548
+ promptForRouteAuthorizationResponseMessage,
13549
+ "promptForRouteAuthorizationResponse"
13550
+ ],
13551
+ [
13552
+ ProtocolMessage_Type.PRESENT_ROUTE_AUTHORIZATION_STATUS_MESSAGE,
13553
+ presentRouteAuthorizationStatusMessage,
13554
+ "presentRouteAuthorizationStatus"
13555
+ ],
13556
+ [
13557
+ ProtocolMessage_Type.REQUEST_GROUP_SESSION_MESSAGE,
13558
+ requestGroupSessionMessage,
13559
+ "requestGroupSession"
13560
+ ],
13561
+ [
13562
+ ProtocolMessage_Type.MICROPHONE_CONNECTION_REQUEST_MESSAGE,
13563
+ microphoneConnectionRequestMessage,
13564
+ "microphoneConnectionRequest"
13565
+ ],
13566
+ [
13567
+ ProtocolMessage_Type.MICROPHONE_CONNECTION_RESPONSE_MESSAGE,
13568
+ microphoneConnectionResponseMessage,
13569
+ "microphoneConnectionResponse"
13570
+ ],
13571
+ [
13572
+ ProtocolMessage_Type.CREATE_APPLICATION_CONNECTION_MESSAGE,
13573
+ createApplicationConnectionMessage,
13574
+ "createApplicationConnection"
13575
+ ],
13576
+ [
13577
+ ProtocolMessage_Type.SET_HILITE_MODE_MESSAGE,
13578
+ setHiliteModeMessage,
13579
+ "setHiliteMode"
13580
+ ],
13581
+ [
13582
+ ProtocolMessage_Type.TEXT_INPUT_MESSAGE,
13583
+ textInputMessage,
13584
+ "textInput"
13585
+ ],
13586
+ [
13587
+ ProtocolMessage_Type.REMOTE_TEXT_INPUT_MESSAGE,
13588
+ remoteTextInputMessage,
13589
+ "remoteTextInput"
13590
+ ],
13591
+ [
13592
+ ProtocolMessage_Type.CRYPTO_PAIRING_MESSAGE,
13593
+ cryptoPairingMessage,
13594
+ "cryptoPairing"
13595
+ ],
13596
+ [
13597
+ ProtocolMessage_Type.GAME_CONTROLLER_MESSAGE,
13598
+ gameControllerMessage,
13599
+ "gameController"
13600
+ ],
13601
+ [
13602
+ ProtocolMessage_Type.GAME_CONTROLLER_PROPERTIES_MESSAGE,
13603
+ gameControllerPropertiesMessage,
13604
+ "gameControllerProperties"
13605
+ ],
13606
+ [
13607
+ ProtocolMessage_Type.REGISTER_GAME_CONTROLLER_MESSAGE,
13608
+ registerGameControllerMessage,
13609
+ "registerGameController"
13610
+ ],
13611
+ [
13612
+ ProtocolMessage_Type.REGISTER_GAME_CONTROLLER_RESPONSE_MESSAGE,
13613
+ registerGameControllerResponseMessage,
13614
+ "registerGameControllerResponse"
13615
+ ]
13616
+ ];
13617
+ for (const [type, extension, eventName] of auto) if (!(type in this.#handlers)) this.#handlers[type] = [extension, (msg) => {
13618
+ this.context.logger.info("[data]", `${eventName}`, msg);
13619
+ this.emit(eventName, msg);
13620
+ }];
13063
13621
  }
13064
13622
  /**
13065
13623
  * Disconnects the data stream, rejecting all outstanding exchanges and clearing buffers.
@@ -13148,20 +13706,7 @@ var DataStream = class extends BaseStream {
13148
13706
  * @param seed - Random 64-bit seed sent in the SETUP request.
13149
13707
  */
13150
13708
  setup(sharedSecret, seed) {
13151
- const readKey = hkdf({
13152
- hash: "sha512",
13153
- key: sharedSecret,
13154
- length: 32,
13155
- salt: Buffer.from(`DataStream-Salt${seed}`),
13156
- info: Buffer.from("DataStream-Input-Encryption-Key")
13157
- });
13158
- const writeKey = hkdf({
13159
- hash: "sha512",
13160
- key: sharedSecret,
13161
- length: 32,
13162
- salt: Buffer.from(`DataStream-Salt${seed}`),
13163
- info: Buffer.from("DataStream-Output-Encryption-Key")
13164
- });
13709
+ const { readKey, writeKey } = deriveEncryptionKeys(sharedSecret, `DataStream-Salt${seed}`, "DataStream-Input-Encryption-Key", "DataStream-Output-Encryption-Key");
13165
13710
  this.enableEncryption(readKey, writeKey);
13166
13711
  }
13167
13712
  /**
@@ -13444,6 +13989,15 @@ var DataStream = class extends BaseStream {
13444
13989
  this.emit("updateOutputDevice", message);
13445
13990
  }
13446
13991
  /**
13992
+ * Handles playback queue participant updates (e.g. SharePlay users).
13993
+ *
13994
+ * @param message - The decoded PlayerClientParticipantsUpdateMessage.
13995
+ */
13996
+ #onPlayerClientParticipantsUpdateMessage(message) {
13997
+ this.context.logger.info("[data]", "Player client participants update", message);
13998
+ this.emit("playerClientParticipantsUpdate", message);
13999
+ }
14000
+ /**
13447
14001
  * Handles volume control availability changes.
13448
14002
  *
13449
14003
  * @param message - The decoded VolumeControlAvailabilityMessage.
@@ -13512,7 +14066,7 @@ var DataStream = class extends BaseStream {
13512
14066
  * The stream is encrypted with ChaCha20-Poly1305 after setup. Note that the
13513
14067
  * HKDF info strings are swapped compared to what you might expect: the key
13514
14068
  * derived from 'Events-Write-Encryption-Key' becomes our read key, because
13515
- * these names are from the Apple TV's perspective (see CLAUDE.md for details).
14069
+ * these names are from the Apple TV's perspective.
13516
14070
  */
13517
14071
  var EventStream = class extends BaseStream {
13518
14072
  /** Accumulated plaintext buffer for partial RTSP request reassembly. */
@@ -13569,20 +14123,7 @@ var EventStream = class extends BaseStream {
13569
14123
  * @param sharedSecret - Shared secret from pair-verify.
13570
14124
  */
13571
14125
  setup(sharedSecret) {
13572
- const readKey = hkdf({
13573
- hash: "sha512",
13574
- key: sharedSecret,
13575
- length: 32,
13576
- salt: Buffer.from("Events-Salt"),
13577
- info: Buffer.from("Events-Read-Encryption-Key")
13578
- });
13579
- const writeKey = hkdf({
13580
- hash: "sha512",
13581
- key: sharedSecret,
13582
- length: 32,
13583
- salt: Buffer.from("Events-Salt"),
13584
- info: Buffer.from("Events-Write-Encryption-Key")
13585
- });
14126
+ const { readKey, writeKey } = deriveEncryptionKeys(sharedSecret, "Events-Salt", "Events-Read-Encryption-Key", "Events-Write-Encryption-Key");
13586
14127
  this.enableEncryption(writeKey, readKey);
13587
14128
  }
13588
14129
  /**
@@ -13606,14 +14147,20 @@ var EventStream = class extends BaseStream {
13606
14147
  async #handle(method, path, headers, body) {
13607
14148
  const key = `${method} ${path}`;
13608
14149
  switch (key) {
13609
- case "POST /command":
14150
+ case "POST /command": {
13610
14151
  const data = Plist.parse(body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength));
13611
- this.context.logger.info("[event]", "Received event stream request.", data);
14152
+ const commandType = data.type;
14153
+ this.context.logger.info("[event]", "Received command:", commandType ?? "unknown", data);
14154
+ this.emit("command", data);
14155
+ if (commandType === "cycleUsePickedRoute" || commandType === "duckAudio") this.emit("duckAudio", data);
14156
+ else if (commandType === "unduckAudio") this.emit("unduckAudio", data);
14157
+ else if (commandType === "died") this.emit("sessionDied");
13612
14158
  this.respond(200, "OK", {
13613
14159
  "Audio-Latency": 0,
13614
14160
  "CSeq": headers["CSeq"] ?? 0
13615
14161
  });
13616
14162
  break;
14163
+ }
13617
14164
  default:
13618
14165
  this.context.logger.warn("[event]", "No handler for url", key);
13619
14166
  this.respond(200, "OK", { "CSeq": headers["CSeq"] ?? 0 });
@@ -13809,21 +14356,10 @@ var Verify = class {
13809
14356
  */
13810
14357
  async start(credentials) {
13811
14358
  const keys = await this.#internal.start(credentials);
14359
+ const { readKey: accessoryToControllerKey, writeKey: controllerToAccessoryKey } = deriveEncryptionKeys(keys.sharedSecret, "Control-Salt", "Control-Read-Encryption-Key", "Control-Write-Encryption-Key");
13812
14360
  return {
13813
- accessoryToControllerKey: hkdf({
13814
- hash: "sha512",
13815
- key: keys.sharedSecret,
13816
- length: 32,
13817
- salt: Buffer.from("Control-Salt"),
13818
- info: Buffer.from("Control-Read-Encryption-Key")
13819
- }),
13820
- controllerToAccessoryKey: hkdf({
13821
- hash: "sha512",
13822
- key: keys.sharedSecret,
13823
- length: 32,
13824
- salt: Buffer.from("Control-Salt"),
13825
- info: Buffer.from("Control-Write-Encryption-Key")
13826
- }),
14361
+ accessoryToControllerKey,
14362
+ controllerToAccessoryKey,
13827
14363
  pairingId: keys.pairingId,
13828
14364
  sharedSecret: keys.sharedSecret
13829
14365
  };
@@ -13844,106 +14380,9 @@ var Verify = class {
13844
14380
  }
13845
14381
  };
13846
14382
 
13847
- //#endregion
13848
- //#region src/features.ts
13849
- /**
13850
- * AirPlay feature flags as a 64-bit bitmask.
13851
- *
13852
- * Each flag represents a capability advertised by AirPlay senders or receivers
13853
- * in the `features`/`featuresEx` fields of SETUP and /info responses. The lower
13854
- * 32 bits map to `features`, the upper 32 bits to `featuresEx`.
13855
- *
13856
- * Sources: pyatv, Apple framework disassembly (AirPlayReceiver sysInfo_createFeaturesInternal),
13857
- * https://emanuelecozzi.net/docs/airplay2/features/
13858
- */
13859
- const AirPlayFeature = {
13860
- SupportsAirPlayVideoV1: 1n << 0n,
13861
- SupportsAirPlayPhoto: 1n << 1n,
13862
- SupportsAirPlaySlideShow: 1n << 5n,
13863
- SupportsAirPlayScreen: 1n << 7n,
13864
- SupportsAirPlayAudio: 1n << 9n,
13865
- AudioRedundant: 1n << 11n,
13866
- Authentication4: 1n << 14n,
13867
- MetadataFeatures0: 1n << 15n,
13868
- MetadataFeatures1: 1n << 16n,
13869
- MetadataFeatures2: 1n << 17n,
13870
- AudioFormats0: 1n << 18n,
13871
- AudioFormats1: 1n << 19n,
13872
- AudioFormats2: 1n << 20n,
13873
- AudioFormats3: 1n << 21n,
13874
- Authentication1: 1n << 23n,
13875
- Authentication8: 1n << 26n,
13876
- SupportsLegacyPairing: 1n << 27n,
13877
- HasUnifiedAdvertiserInfo: 1n << 30n,
13878
- SupportsVolume: 1n << 32n,
13879
- SupportsAirPlayVideoPlayQueue: 1n << 33n,
13880
- SupportsAirPlayFromCloud: 1n << 34n,
13881
- SupportsTLSPSK: 1n << 35n,
13882
- SupportsUnifiedMediaControl: 1n << 38n,
13883
- SupportsBufferedAudio: 1n << 40n,
13884
- SupportsPTP: 1n << 41n,
13885
- SupportsScreenMultiCodec: 1n << 42n,
13886
- SupportsSystemPairing: 1n << 43n,
13887
- IsAPValeriaScreenSender: 1n << 44n,
13888
- SupportsHKPairingAndAccessControl: 1n << 46n,
13889
- SupportsCoreUtilsPairingAndEncryption: 1n << 48n,
13890
- SupportsAirPlayVideoV2: 1n << 49n,
13891
- MetadataFeatures3: 1n << 50n,
13892
- SupportsUnifiedPairSetupAndMFi: 1n << 51n,
13893
- SupportsSetPeersExtendedMessage: 1n << 52n,
13894
- SupportsAPSync: 1n << 54n,
13895
- SupportsWoL: 1n << 55n,
13896
- SupportsWoL2: 1n << 56n,
13897
- SupportsHangdogRemoteControl: 1n << 58n,
13898
- SupportsAudioStreamConnectionSetup: 1n << 59n,
13899
- SupportsAudioMetadataControl: 1n << 60n,
13900
- SupportsRFC2198Redundancy: 1n << 61n
13901
- };
13902
- /**
13903
- * Feature bitmask advertised when connecting for remote control sessions.
13904
- *
13905
- * Includes media control, system pairing, encryption, volume, and
13906
- * hangdog remote control capabilities.
13907
- */
13908
- const SENDER_FEATURES_REMOTE_CONTROL = AirPlayFeature.SupportsAirPlayAudio | AirPlayFeature.AudioRedundant | AirPlayFeature.MetadataFeatures0 | AirPlayFeature.MetadataFeatures1 | AirPlayFeature.MetadataFeatures2 | AirPlayFeature.MetadataFeatures3 | AirPlayFeature.Authentication4 | AirPlayFeature.Authentication1 | AirPlayFeature.HasUnifiedAdvertiserInfo | AirPlayFeature.SupportsUnifiedMediaControl | AirPlayFeature.SupportsSystemPairing | AirPlayFeature.SupportsCoreUtilsPairingAndEncryption | AirPlayFeature.SupportsHKPairingAndAccessControl | AirPlayFeature.SupportsHangdogRemoteControl | AirPlayFeature.SupportsAPSync | AirPlayFeature.SupportsSetPeersExtendedMessage | AirPlayFeature.SupportsVolume;
13909
- /**
13910
- * Feature bitmask advertised when connecting for audio streaming sessions.
13911
- *
13912
- * Extends the remote control features with buffered audio, audio stream
13913
- * connection setup, metadata control, format negotiation, and PTP
13914
- * synchronization support.
13915
- */
13916
- const SENDER_FEATURES_AUDIO = SENDER_FEATURES_REMOTE_CONTROL | AirPlayFeature.SupportsBufferedAudio | AirPlayFeature.SupportsAudioStreamConnectionSetup | AirPlayFeature.SupportsAudioMetadataControl | AirPlayFeature.AudioFormats0 | AirPlayFeature.AudioFormats1 | AirPlayFeature.AudioFormats2 | AirPlayFeature.AudioFormats3 | AirPlayFeature.SupportsPTP;
13917
- /**
13918
- * Checks whether a feature bitmask contains a specific feature flag.
13919
- *
13920
- * @param features - The combined feature bitmask to test.
13921
- * @param feature - The individual feature flag to check for.
13922
- * @returns `true` if the feature is present.
13923
- */
13924
- const hasFeature = (features, feature) => (features & feature) === feature;
13925
- /**
13926
- * Decodes a feature bitmask into a list of human-readable flag names.
13927
- *
13928
- * @param features - The combined feature bitmask to decode.
13929
- * @returns Array of feature names that are set in the bitmask.
13930
- */
13931
- const decodeFeatures = (features) => {
13932
- const result = [];
13933
- for (const [name, bit] of Object.entries(AirPlayFeature)) if ((features & bit) === bit) result.push(name);
13934
- return result;
13935
- };
13936
-
13937
14383
  //#endregion
13938
14384
  //#region src/protocol.ts
13939
14385
  /**
13940
- * Compares two semver-like version strings component by component.
13941
- *
13942
- * @param a - First version string (e.g. "935.7.1").
13943
- * @param b - Second version string (e.g. "935.7").
13944
- * @returns Negative if a < b, positive if a > b, 0 if equal.
13945
- */
13946
- /**
13947
14386
  * Parses a feature value from /info which can be a number, hex string, or decimal string.
13948
14387
  */
13949
14388
  function parseFeatureValue(value) {
@@ -14008,6 +14447,14 @@ var Protocol = class {
14008
14447
  get discoveryResult() {
14009
14448
  return this.#discoveryResult;
14010
14449
  }
14450
+ /**
14451
+ * The receiver's dedicated keep-alive port, or undefined if not provided.
14452
+ * Returned by the receiver in the SETUP response. Can be used for a
14453
+ * separate low-power keep-alive TCP connection.
14454
+ */
14455
+ get keepAlivePort() {
14456
+ return this.#keepAlivePort;
14457
+ }
14011
14458
  /** The active audio stream, or undefined if not streaming audio. */
14012
14459
  get audioStream() {
14013
14460
  return this.#audioStream;
@@ -14038,6 +14485,7 @@ var Protocol = class {
14038
14485
  #dataStream;
14039
14486
  #effectiveSourceVersion;
14040
14487
  #eventStream;
14488
+ #keepAlivePort;
14041
14489
  #playUrlFeedbackInterval;
14042
14490
  #receiverFeatures = 0n;
14043
14491
  #receiverInfo;
@@ -14049,7 +14497,7 @@ var Protocol = class {
14049
14497
  constructor(discoveryResult, identity) {
14050
14498
  this.#context = new Context(discoveryResult.id, identity);
14051
14499
  this.#discoveryResult = discoveryResult;
14052
- this.#sessionUUID = uuid();
14500
+ this.#sessionUUID = uuid().toUpperCase();
14053
14501
  this.#controlStream = new ControlStream(this.#context, discoveryResult.address, discoveryResult.service.port);
14054
14502
  this.#pairing = new Pairing(this);
14055
14503
  this.#verify = new Verify(this);
@@ -14069,7 +14517,7 @@ var Protocol = class {
14069
14517
  * @returns `true` if the receiver advertises support for this feature.
14070
14518
  */
14071
14519
  hasReceiverFeature(feature) {
14072
- return hasFeature(this.#receiverFeatures, feature);
14520
+ return hasFeatureFlag(this.#receiverFeatures, feature);
14073
14521
  }
14074
14522
  /**
14075
14523
  * Opens the TCP connection to the AirPlay RTSP server.
@@ -14101,7 +14549,7 @@ var Protocol = class {
14101
14549
  this.#receiverFeatures = features;
14102
14550
  }
14103
14551
  this.context.logger.info("[protocol]", `Receiver: ${info.name ?? "unknown"}, model=${info.model ?? "?"}, sourceVersion=${receiverSourceVersion ?? "?"}`);
14104
- this.context.logger.info("[protocol]", `Receiver features: ${decodeFeatures(this.#receiverFeatures).join(", ")}`);
14552
+ this.context.logger.info("[protocol]", `Receiver features: ${describeFlags(this.#receiverFeatures).join(", ")}`);
14105
14553
  if (info.initialVolume != null) this.context.logger.info("[protocol]", `Receiver initial volume: ${info.initialVolume}`);
14106
14554
  if (receiverSourceVersion) {
14107
14555
  if (compareVersions(String(this.#context.identity.sourceVersion), receiverSourceVersion) > 0) {
@@ -14162,9 +14610,14 @@ var Protocol = class {
14162
14610
  *
14163
14611
  * The feedback loop keeps the AirPlay session alive. Uses a 1.9s timeout
14164
14612
  * (slightly less than the 2s interval) to avoid overlapping requests.
14613
+ *
14614
+ * Optionally includes session stats in the body (Apple's `keepAliveSendStatsAsBody`
14615
+ * pattern), which gives the receiver better information about connection quality.
14616
+ *
14617
+ * @param stats - Optional stats to include in the feedback body (plist-serializable).
14165
14618
  */
14166
- async feedback() {
14167
- await this.#controlStream.post("/feedback", void 0, void 0, 1900);
14619
+ async feedback(stats) {
14620
+ await this.#controlStream.post("/feedback", stats, void 0, 1900);
14168
14621
  }
14169
14622
  /**
14170
14623
  * Sets the playback volume on the receiver.
@@ -14175,6 +14628,25 @@ var Protocol = class {
14175
14628
  await this.#controlStream.setVolume(volume);
14176
14629
  }
14177
14630
  /**
14631
+ * Gets a property value from the AirPlay receiver.
14632
+ *
14633
+ * @param property - The property key to query (e.g. 'dmcp.device-volume').
14634
+ * @returns The RTSP response (body contains the value, typically plist-encoded).
14635
+ */
14636
+ async getProperty(property) {
14637
+ return await this.#controlStream.getProperty(property);
14638
+ }
14639
+ /**
14640
+ * Sets a property value on the AirPlay receiver.
14641
+ *
14642
+ * @param property - The property key=value string (e.g. 'dmcp.device-volume=0.5').
14643
+ * @param body - Optional body for complex property values.
14644
+ * @returns The RTSP response.
14645
+ */
14646
+ async setProperty(property, body) {
14647
+ return await this.#controlStream.setProperty(property, body);
14648
+ }
14649
+ /**
14178
14650
  * Sets up and connects the MRP data stream for protobuf-based remote control.
14179
14651
  *
14180
14652
  * Sends an RTSP SETUP request for a type 130 (MRP) stream with a dedicated
@@ -14211,11 +14683,10 @@ var Protocol = class {
14211
14683
  * Sends an RTSP SETUP request and parses the plist response.
14212
14684
  *
14213
14685
  * @param body - Plist body for the SETUP request.
14214
- * @param sharedSecret - Optional shared secret (unused, reserved for future use).
14215
14686
  * @returns Parsed plist response from the receiver.
14216
14687
  * @throws SetupError if the SETUP request returns a non-200 status.
14217
14688
  */
14218
- async #performSetup(body, sharedSecret) {
14689
+ async #performSetup(body) {
14219
14690
  const response = await this.#controlStream.setup(`/${this.#controlStream.sessionId}`, body);
14220
14691
  if (response.status !== 200) {
14221
14692
  this.context.logger.error("[protocol]", "Failed SETUP request.", response.status, response.statusText, await response.text());
@@ -14223,7 +14694,10 @@ var Protocol = class {
14223
14694
  }
14224
14695
  const plist = Plist.parse(await response.arrayBuffer());
14225
14696
  if (plist.enabledFeatures != null) this.context.logger.info("[protocol]", `Receiver enabled features: 0x${BigInt(plist.enabledFeatures).toString(16)}`);
14226
- if (plist.keepAlivePort != null) this.context.logger.info("[protocol]", `Receiver keep-alive port: ${plist.keepAlivePort}`);
14697
+ if (plist.keepAlivePort != null) {
14698
+ this.#keepAlivePort = plist.keepAlivePort;
14699
+ this.context.logger.info("[protocol]", `Receiver keep-alive port: ${plist.keepAlivePort}`);
14700
+ }
14227
14701
  return plist;
14228
14702
  }
14229
14703
  /**
@@ -14269,7 +14743,7 @@ var Protocol = class {
14269
14743
  body.timingPort = this.#timingServer.port;
14270
14744
  body.timingProtocol = "NTP";
14271
14745
  }
14272
- const eventPort = (await this.#performSetup(body, sharedSecret)).eventPort & 65535;
14746
+ const eventPort = (await this.#performSetup(body)).eventPort & 65535;
14273
14747
  this.context.logger.net("[protocol]", `Connecting to event stream on port ${eventPort}...`);
14274
14748
  this.#eventStream?.destroy();
14275
14749
  this.#eventStream = new EventStream(this.#context, this.#controlStream.address, eventPort);
@@ -14304,7 +14778,7 @@ var Protocol = class {
14304
14778
  body.timingPort = this.#timingServer.port;
14305
14779
  body.timingProtocol = "NTP";
14306
14780
  }
14307
- const eventPort = (await this.#performSetup(body, sharedSecret)).eventPort & 65535;
14781
+ const eventPort = (await this.#performSetup(body)).eventPort & 65535;
14308
14782
  this.context.logger.net("[protocol]", `Connecting to event stream on port ${eventPort}...`);
14309
14783
  this.#eventStream?.destroy();
14310
14784
  this.#eventStream = new EventStream(this.#context, this.#controlStream.address, eventPort);
@@ -14333,10 +14807,13 @@ var Protocol = class {
14333
14807
  async playUrl(url, sharedSecret, pairingId, position = 0) {
14334
14808
  const setupBody = {
14335
14809
  ...this.#setupBody(pairingId, SENDER_FEATURES_AUDIO),
14336
- isMultiSelectAirPlay: true,
14337
14810
  groupContainsGroupLeader: false,
14811
+ groupUUID: uuid(),
14812
+ isMultiSelectAirPlay: true,
14338
14813
  senderSupportsRelay: false,
14339
- statsCollectionEnabled: false
14814
+ statsCollectionEnabled: false,
14815
+ supportsGroupCohesion: true,
14816
+ updateSessionRequest: false
14340
14817
  };
14341
14818
  if (this.#timingServer) {
14342
14819
  setupBody.timingPort = this.#timingServer.port;
@@ -14531,6 +15008,8 @@ var Protocol = class {
14531
15008
  //#endregion
14532
15009
  //#region src/dataStreamMessages.ts
14533
15010
  var dataStreamMessages_exports = /* @__PURE__ */ __exportAll({
15011
+ adjustVolume: () => adjustVolume,
15012
+ audioFade: () => audioFade,
14534
15013
  clientUpdatesConfig: () => clientUpdatesConfig,
14535
15014
  configureConnection: () => configureConnection,
14536
15015
  deviceInfo: () => deviceInfo,
@@ -14542,7 +15021,10 @@ var dataStreamMessages_exports = /* @__PURE__ */ __exportAll({
14542
15021
  modifyOutputContext: () => modifyOutputContext,
14543
15022
  notification: () => notification,
14544
15023
  playbackQueueRequest: () => playbackQueueRequest,
15024
+ playbackSessionMigrateBegin: () => playbackSessionMigrateBegin,
15025
+ playbackSessionMigrateEnd: () => playbackSessionMigrateEnd,
14545
15026
  protocol: () => protocol,
15027
+ requestGroupSession: () => requestGroupSession,
14546
15028
  sendButtonEvent: () => sendButtonEvent,
14547
15029
  sendCommand: () => sendCommand,
14548
15030
  sendCommandWithPlaybackPosition: () => sendCommandWithPlaybackPosition,
@@ -14550,10 +15032,13 @@ var dataStreamMessages_exports = /* @__PURE__ */ __exportAll({
14550
15032
  sendCommandWithRepeatMode: () => sendCommandWithRepeatMode,
14551
15033
  sendCommandWithShuffleMode: () => sendCommandWithShuffleMode,
14552
15034
  sendCommandWithSkipInterval: () => sendCommandWithSkipInterval,
15035
+ sendCommandWithSleepTimer: () => sendCommandWithSleepTimer,
14553
15036
  sendHIDEvent: () => sendHIDEvent,
14554
15037
  sendVirtualTouchEvent: () => sendVirtualTouchEvent,
14555
15038
  setConnectionState: () => setConnectionState,
14556
15039
  setConversationDetectionEnabled: () => setConversationDetectionEnabled,
15040
+ setDiscoveryMode: () => setDiscoveryMode,
15041
+ setListeningMode: () => setListeningMode,
14557
15042
  setReadyState: () => setReadyState,
14558
15043
  setVolume: () => setVolume,
14559
15044
  setVolumeMuted: () => setVolumeMuted,
@@ -14593,7 +15078,7 @@ function protocol(type, errorCode = ErrorCode_Enum.NoError) {
14593
15078
  * @param systemEndpointUpdates - Subscribe to system endpoint changes.
14594
15079
  * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
14595
15080
  */
14596
- function clientUpdatesConfig(artworkUpdates = true, nowPlayingUpdates = true, volumeUpdates = true, keyboardUpdates = false, outputDeviceUpdates = true, systemEndpointUpdates = true) {
15081
+ function clientUpdatesConfig(artworkUpdates = true, nowPlayingUpdates = true, volumeUpdates = true, keyboardUpdates = false, outputDeviceUpdates = false, systemEndpointUpdates = true, subscribedPlayerPaths = []) {
14597
15082
  const protocolMessage = protocol(ProtocolMessage_Type.CLIENT_UPDATES_CONFIG_MESSAGE);
14598
15083
  const message = create(ClientUpdatesConfigMessageSchema, {
14599
15084
  artworkUpdates,
@@ -14601,7 +15086,8 @@ function clientUpdatesConfig(artworkUpdates = true, nowPlayingUpdates = true, vo
14601
15086
  volumeUpdates,
14602
15087
  keyboardUpdates,
14603
15088
  outputDeviceUpdates,
14604
- systemEndpointUpdates
15089
+ systemEndpointUpdates,
15090
+ subscribedPlayerPaths
14605
15091
  });
14606
15092
  setExtension(protocolMessage, clientUpdatesConfigMessage, message);
14607
15093
  return [protocolMessage, clientUpdatesConfigMessage];
@@ -14638,19 +15124,22 @@ function deviceInfo(pairingId, identity) {
14638
15124
  applicationBundleIdentifier: identity.applicationBundleIdentifier,
14639
15125
  applicationBundleVersion: identity.applicationBundleVersion,
14640
15126
  protocolVersion: 1,
14641
- lastSupportedMessageType: 129,
15127
+ lastSupportedMessageType: 139,
14642
15128
  supportsSystemPairing: true,
14643
15129
  allowsPairing: true,
14644
15130
  systemMediaApplication: "com.apple.TVMusic",
14645
15131
  supportsACL: true,
14646
15132
  supportsSharedQueue: true,
14647
15133
  supportsExtendedMotion: true,
14648
- sharedQueueVersion: 2,
15134
+ sharedQueueVersion: 3,
14649
15135
  deviceClass: DeviceClass_Enum.iPhone,
14650
15136
  logicalDeviceCount: 1,
14651
15137
  modelID: identity.model,
14652
15138
  clusterType: 0,
14653
15139
  isClusterAware: true,
15140
+ isGroupLeader: false,
15141
+ isProxyGroupPlayer: false,
15142
+ groupContainsDiscoverableGroupLeader: 0,
14654
15143
  supportsOutputContextSync: true,
14655
15144
  computerName: identity.name
14656
15145
  });
@@ -14670,13 +15159,13 @@ function deviceInfo(pairingId, identity) {
14670
15159
  function modifyOutputContext(addingDevices = [], removingDevices = [], settingDevices = []) {
14671
15160
  const protocolMessage = protocol(ProtocolMessage_Type.MODIFY_OUTPUT_CONTEXT_REQUEST_MESSAGE);
14672
15161
  const message = create(ModifyOutputContextRequestMessageSchema, {
14673
- type: ModifyOutputContextRequestType_Enum.SharedAudioPresentation,
14674
- addingDevices,
14675
- removingDevices,
14676
- settingDevices,
14677
- clusterAwareAddingDevices: addingDevices,
14678
- clusterAwareRemovingDevices: removingDevices,
14679
- clusterAwareSettingDevices: settingDevices
15162
+ outputContextType: ModifyOutputContextRequestType_Enum.SharedAudioPresentation,
15163
+ addingOutputDeviceUIDs: addingDevices,
15164
+ removingOutputDeviceUIDs: removingDevices,
15165
+ settingOutputDeviceUIDs: settingDevices,
15166
+ clusterAwareAddingOutputDeviceUIDs: addingDevices,
15167
+ clusterAwareRemovingOutputDeviceUIDs: removingDevices,
15168
+ clusterAwareSettingOutputDeviceUIDs: settingDevices
14680
15169
  });
14681
15170
  setExtension(protocolMessage, modifyOutputContextRequestMessage, message);
14682
15171
  return [protocolMessage, modifyOutputContextRequestMessage];
@@ -14881,6 +15370,19 @@ function sendCommand(command, options) {
14881
15370
  return [protocolMessage, sendCommandMessage];
14882
15371
  }
14883
15372
  /**
15373
+ * Builds a SEND_COMMAND message with sleep timer options.
15374
+ *
15375
+ * @param seconds - Timer duration in seconds. Use 0 to cancel.
15376
+ * @param stopMode - Stop mode: 0 = stop, 1 = pause, 2 = end of track, 3 = end of queue.
15377
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15378
+ */
15379
+ function sendCommandWithSleepTimer(seconds, stopMode = 0) {
15380
+ return sendCommand(Command.Pause, create(CommandOptionsSchema, {
15381
+ sleepTimerTime: BigInt(seconds),
15382
+ sleepTimerStopMode: stopMode
15383
+ }));
15384
+ }
15385
+ /**
14884
15386
  * Builds a SEND_VIRTUAL_TOUCH_EVENT message for touchpad simulation.
14885
15387
  *
14886
15388
  * Simulates touch input on a virtual trackpad, used for gesture-based
@@ -15007,6 +15509,104 @@ function setConversationDetectionEnabled(enabled, outputDeviceUID) {
15007
15509
  return [protocolMessage, setConversationDetectionEnabledMessage];
15008
15510
  }
15009
15511
  /**
15512
+ * Builds an ADJUST_VOLUME message for relative volume changes.
15513
+ *
15514
+ * Uses the dedicated AdjustVolumeMessage (extension field 97) for incremental
15515
+ * volume adjustments without needing to know the current volume level.
15516
+ *
15517
+ * @param adjustment - The volume adjustment type (e.g. IncrementSmall, DecrementSmall).
15518
+ * @param outputDeviceUID - UID of the target output device.
15519
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15520
+ */
15521
+ function adjustVolume(adjustment, outputDeviceUID) {
15522
+ const protocolMessage = protocol(ProtocolMessage_Type.ADJUST_VOLUME_MESSAGE);
15523
+ const message = create(AdjustVolumeMessageSchema, {
15524
+ adjustment,
15525
+ outputDeviceUID
15526
+ });
15527
+ setExtension(protocolMessage, adjustVolumeMessage, message);
15528
+ return [protocolMessage, adjustVolumeMessage];
15529
+ }
15530
+ /**
15531
+ * Builds an AUDIO_FADE message to trigger a cross-fade between audio sources.
15532
+ *
15533
+ * @param fadeType - The type of audio fade to perform.
15534
+ * @param playerPath - Optional player path to target a specific player.
15535
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15536
+ */
15537
+ function audioFade(fadeType, playerPath) {
15538
+ const protocolMessage = protocol(ProtocolMessage_Type.AUDIO_FADE_MESSAGE);
15539
+ const message = create(AudioFadeMessageSchema, {
15540
+ fadeType,
15541
+ playerPath
15542
+ });
15543
+ setExtension(protocolMessage, audioFadeMessage, message);
15544
+ return [protocolMessage, audioFadeMessage];
15545
+ }
15546
+ /**
15547
+ * Builds a SET_LISTENING_MODE message to change the audio listening mode on a HomePod.
15548
+ *
15549
+ * @param listeningMode - The listening mode string (e.g. 'Default', 'Vivid', 'LateNight').
15550
+ * @param outputDeviceUID - The output device UID to target.
15551
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15552
+ */
15553
+ function setListeningMode(listeningMode, outputDeviceUID) {
15554
+ const protocolMessage = protocol(ProtocolMessage_Type.SET_LISTENING_MODE_MESSAGE);
15555
+ const message = create(SetListeningModeMessageSchema, {
15556
+ listeningMode,
15557
+ outputDeviceUID
15558
+ });
15559
+ setExtension(protocolMessage, setListeningModeMessage, message);
15560
+ return [protocolMessage, setListeningModeMessage];
15561
+ }
15562
+ /**
15563
+ * Builds a SET_DISCOVERY_MODE message to enable or disable device discovery.
15564
+ *
15565
+ * @param mode - The discovery mode to set.
15566
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15567
+ */
15568
+ function setDiscoveryMode(mode) {
15569
+ const protocolMessage = protocol(ProtocolMessage_Type.SET_DISCOVERY_MODE_MESSAGE);
15570
+ const message = create(SetDiscoveryModeMessageSchema, { mode });
15571
+ setExtension(protocolMessage, setDiscoveryModeMessage, message);
15572
+ return [protocolMessage, setDiscoveryModeMessage];
15573
+ }
15574
+ /**
15575
+ * Builds a REQUEST_GROUP_SESSION message to initiate a SharePlay/group listening session.
15576
+ *
15577
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15578
+ */
15579
+ function requestGroupSession() {
15580
+ const protocolMessage = protocol(ProtocolMessage_Type.REQUEST_GROUP_SESSION_MESSAGE);
15581
+ const message = create(RequestGroupSessionMessageSchema, {});
15582
+ setExtension(protocolMessage, requestGroupSessionMessage, message);
15583
+ return [protocolMessage, requestGroupSessionMessage];
15584
+ }
15585
+ /**
15586
+ * Builds a PLAYBACK_SESSION_MIGRATE_BEGIN message to start migrating playback to another device.
15587
+ *
15588
+ * @param playerPath - The player path of the session to migrate.
15589
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15590
+ */
15591
+ function playbackSessionMigrateBegin(playerPath) {
15592
+ const protocolMessage = protocol(ProtocolMessage_Type.PLAYBACK_SESSION_MIGRATE_BEGIN_MESSAGE);
15593
+ const message = create(PlaybackSessionMigrateBeginMessageSchema, { playerPath });
15594
+ setExtension(protocolMessage, playbackSessionMigrateBeginMessage, message);
15595
+ return [protocolMessage, playbackSessionMigrateBeginMessage];
15596
+ }
15597
+ /**
15598
+ * Builds a PLAYBACK_SESSION_MIGRATE_END message to complete a playback migration.
15599
+ *
15600
+ * @param playerPath - The player path of the migrated session.
15601
+ * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
15602
+ */
15603
+ function playbackSessionMigrateEnd(playerPath) {
15604
+ const protocolMessage = protocol(ProtocolMessage_Type.PLAYBACK_SESSION_MIGRATE_END_MESSAGE);
15605
+ const message = create(PlaybackSessionMigrateEndMessageSchema, { playerPath });
15606
+ setExtension(protocolMessage, playbackSessionMigrateEndMessage, message);
15607
+ return [protocolMessage, playbackSessionMigrateEndMessage];
15608
+ }
15609
+ /**
15010
15610
  * Builds a WAKE_DEVICE message to wake a sleeping Apple TV or HomePod.
15011
15611
  *
15012
15612
  * @returns Tuple of [ProtocolMessage, extension descriptor] for sending via DataStream.
@@ -15032,4 +15632,4 @@ function getExtension(message, extension) {
15032
15632
  }
15033
15633
 
15034
15634
  //#endregion
15035
- export { AirPlayFeature, AudioMultiplexer, AudioStream, ControlStream, DataStream, dataStreamMessages_exports as DataStreamMessage, EventStream, Pairing, proto_exports as Proto, Protocol, SENDER_FEATURES_AUDIO, SENDER_FEATURES_REMOTE_CONTROL, Verify, decodeFeatures, hasFeature };
15635
+ export { AudioMultiplexer, AudioStream, ControlStream, DataStream, dataStreamMessages_exports as DataStreamMessage, EventStream, LatencyManager, Pairing, proto_exports as Proto, Protocol, Verify };