@tidal-music/player-web-components 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CredentialsProvider } from '@tidal-music/common';
2
2
  import { events } from '@tidal-music/player';
3
3
  import { setCredentialsProvider } from '@tidal-music/player';
4
+ import { setEventSender } from '@tidal-music/player';
4
5
 
5
6
  export { CredentialsProvider }
6
7
 
@@ -8,6 +9,8 @@ export { events }
8
9
 
9
10
  export { setCredentialsProvider }
10
11
 
12
+ export { setEventSender }
13
+
11
14
  export declare const TidalCurrentTime = "tidal-current-time";
12
15
 
13
16
  export declare const TidalDurationTime = "tidal-duration-time";
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
- import { e as i, f as s, m as r, p as d, q as t, y as l, X as o } from "./index-tM9JvbA8.js";
1
+ import { o as s, p as r, r as i, s as t, t as d, b as o, H as l, Q as n } from "./index-vp_MoGvy.js";
2
2
  export {
3
- i as TidalCurrentTime,
4
- s as TidalDurationTime,
5
- r as TidalPlayButton,
6
- d as TidalProgressBar,
7
- t as TidalVideoView,
8
- l as events,
9
- o as setCredentialsProvider
3
+ s as TidalCurrentTime,
4
+ r as TidalDurationTime,
5
+ i as TidalPlayButton,
6
+ t as TidalProgressBar,
7
+ d as TidalVideoView,
8
+ o as events,
9
+ l as setCredentialsProvider,
10
+ n as setEventSender
10
11
  };
@@ -1,10 +1,10 @@
1
- import { b as m, y as s, H as u, n as k, P as p, k as o, l as g, s as P, t as S, i as b } from "./index-tM9JvbA8.js";
2
- import { Y as f, V as y, O as L } from "./basePlayer-a-avZASH-Ux-6s9Ex.js";
3
- const E = "active-device-disconnected";
4
- function w() {
5
- return new CustomEvent(E);
1
+ import { k as v, b as s, x as u, q as k, y as p, P as o, l as g, j as P, G as S } from "./index-vp_MoGvy.js";
2
+ import { C as I, w as b, R as y } from "./basePlayer-C5QIyqfj-Dxhlf4BZ.js";
3
+ const f = "active-device-disconnected";
4
+ function E() {
5
+ return new CustomEvent(f);
6
6
  }
7
- const D = {
7
+ const w = {
8
8
  file_checksum_mismatch: "NPO02",
9
9
  no_such_file: "NPO01",
10
10
  unreadable_file: "NPO03"
@@ -16,8 +16,8 @@ const D = {
16
16
  devicenotfound: "NPD05",
17
17
  deviceunknownerror: "NPD00"
18
18
  };
19
- let i;
20
- class A extends f {
19
+ let a;
20
+ class x extends I {
21
21
  #s = "default";
22
22
  /**
23
23
  * A Boolean which is true if the media contained in the element has finished playing.
@@ -30,63 +30,61 @@ class A extends f {
30
30
  * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended
31
31
  */
32
32
  #i;
33
- #r = !0;
34
33
  #e;
35
34
  #a;
36
35
  name = "nativePlayer";
37
36
  playbackEngineHandlerAttached = !1;
38
37
  constructor() {
39
- super(), m("outputDevicesEnabled") && (async () => (i = (await import("./output-devices-NXuo75MQ-_vYYuqUm.js")).outputDevices, this.#e.listDevices()))(), this.#e = // eslint-disable-next-line @typescript-eslint/ban-ts-comment
38
+ super(), v("outputDevicesEnabled") && (async () => (a = (await import("./output-devices-Jno8Kp5B-CAnEAv_Z.js")).outputDevices, this.#e.listDevices()))(), this.#e = // eslint-disable-next-line @typescript-eslint/ban-ts-comment
40
39
  // @ts-ignore
41
40
  window.NativePlayerComponent.Player(), this.playbackState = "IDLE", this.registerEventListeners(), this.#e.setVolume(100);
42
41
  }
43
- // eslint-disable-next-line class-methods-use-this
44
42
  #t(e) {
45
43
  s.dispatchError(
46
44
  new u("EUnexpected", N[e])
47
45
  );
48
46
  }
49
- #d(e) {
47
+ #r(e) {
50
48
  this.debugLog("handleMediaError", e.target);
51
- const t = e.target, a = D[t.errorCode];
49
+ const t = e.target, i = w[t.errorCode];
52
50
  this.currentStreamingSessionId && k({
53
- errorCode: a,
51
+ errorCode: i,
54
52
  errorMessage: JSON.stringify(e.target),
55
53
  streamingSessionId: this.currentStreamingSessionId
56
- }), s.dispatchError(new u("EUnexpected", a));
54
+ }), s.dispatchError(new u("EUnexpected", i));
57
55
  }
58
- #n(e) {
56
+ #d(e) {
59
57
  switch (this.debugLog("handleNativePlayerStateChange", e), e) {
60
- case "paused":
61
- case "ready":
62
- this.playbackState = "NOT_PLAYING";
63
- break;
64
58
  case "active":
65
59
  this.playbackState = "PLAYING";
66
60
  break;
67
- case "seeking":
68
61
  case "idle":
62
+ case "seeking":
69
63
  this.playbackState = "STALLED";
70
64
  break;
71
- case "uninitialized":
72
- this.playbackState = "IDLE";
65
+ case "paused":
66
+ case "ready":
67
+ this.playbackState = "NOT_PLAYING";
73
68
  break;
74
69
  case "stopped":
75
70
  this.playbackState = "NOT_PLAYING";
76
71
  break;
72
+ case "uninitialized":
73
+ this.playbackState = "IDLE";
74
+ break;
77
75
  default:
78
76
  this.debugLog("No handling for state", e);
79
77
  break;
80
78
  }
81
79
  }
82
- async #o() {
80
+ async #n() {
83
81
  this.debugLog("handleNetworkError");
84
82
  const e = p.timestamp(
85
83
  "streaming_metrics:playback_statistics:actualStartTimestamp"
86
84
  );
87
85
  if ((e !== void 0 ? Math.abs(p.now() - e) : 0) >= 36e5) {
88
- const t = structuredClone(this.currentMediaProduct), a = this.currentTime;
89
- this.finishCurrentMediaProduct("error"), t && (await this.hardReload(t, a), await this.play());
86
+ const t = structuredClone(this.currentMediaProduct), i = this.currentTime;
87
+ this.finishCurrentMediaProduct("error"), t && (await this.hardReload(t, i), await this.play());
90
88
  return;
91
89
  }
92
90
  await Promise.race([
@@ -100,7 +98,7 @@ class A extends f {
100
98
  * Clean up native player before leaving for another player.
101
99
  */
102
100
  abandon() {
103
- i && i.deviceMode === "exclusive" && this.#e.selectSystemDevice();
101
+ a && a.deviceMode === "exclusive" && this.#e.selectSystemDevice();
104
102
  }
105
103
  getPosition() {
106
104
  return this.currentTime;
@@ -123,8 +121,8 @@ class A extends f {
123
121
  ), this.playbackState = "NOT_PLAYING";
124
122
  return;
125
123
  }
126
- const { mediaProduct: t, playbackContext: a } = e, r = {
127
- ...a,
124
+ const { mediaProduct: t, playbackContext: i } = e, r = {
125
+ ...i,
128
126
  actualDuration: this.#i
129
127
  };
130
128
  this.preloadedStreamingSessionId && o.saveMediaProductTransition(
@@ -134,42 +132,42 @@ class A extends f {
134
132
  playbackContext: r
135
133
  }
136
134
  ), await this.mediaStateChange("active"), s.dispatchEvent(
137
- y(t, r)
135
+ b(t, r)
138
136
  ), this.currentStreamingSessionId = this.preloadedStreamingSessionId, this.mediaProductStarted(this.currentStreamingSessionId);
139
137
  }
140
138
  async load(e, t) {
141
- this.debugLog("load", e), this.currentTime = e.assetPosition, this.startAssetPosition = e.assetPosition, await this.reset(), this.#r = !1;
142
- const { assetPosition: a, mediaProduct: r, playbackInfo: h, streamInfo: d } = e, { securityToken: c, streamFormat: n, streamUrl: l } = d;
139
+ this.debugLog("load", e), this.currentTime = e.assetPosition, this.startAssetPosition = e.assetPosition, await this.reset();
140
+ const { assetPosition: i, mediaProduct: r, playbackInfo: h, streamInfo: d } = e, { securityToken: c, streamFormat: n, streamUrl: l } = d;
143
141
  this.currentStreamingSessionId = d.streamingSessionId, t === "explicit" && (this.playbackState = "NOT_PLAYING");
144
- const I = this.nativeEvent("mediaduration");
142
+ const L = this.nativeEvent("mediaduration");
145
143
  if (n)
146
144
  this.#e.load(l, n, c);
147
145
  else
148
146
  throw new Error("Stream format is undefined.");
149
- if (await I, this.currentStreamingSessionId !== d.streamingSessionId)
147
+ if (await L, this.currentStreamingSessionId !== d.streamingSessionId)
150
148
  return;
151
- this.debugLog("load() duration is", this.#i), a !== 0 && a < this.#i ? (async () => {
152
- await this.mediaStateChange("active"), await this.seek(a), this.currentTime = a;
149
+ this.debugLog("load() duration is", this.#i), i !== 0 && i < this.#i ? (async () => {
150
+ await this.mediaStateChange("active"), await this.seek(i), this.currentTime = i;
153
151
  })().catch(console.error) : this.currentTime = 0;
154
- const v = L({
155
- assetPosition: a,
152
+ const m = y({
153
+ assetPosition: i,
156
154
  duration: this.#i,
157
155
  playbackInfo: h,
158
156
  streamInfo: d
159
157
  });
160
158
  o.saveMediaProductTransition(
161
159
  d.streamingSessionId,
162
- { mediaProduct: r, playbackContext: v }
160
+ { mediaProduct: r, playbackContext: m }
163
161
  ), this.debugLog("load() mediaProductTransition"), s.dispatchEvent(
164
- y(r, v)
162
+ b(r, m)
165
163
  ), this.debugLog("load() pb NOT_PLAYING"), this.debugLog("load() done");
166
164
  }
167
165
  mediaStateChange(e) {
168
166
  return new Promise((t) => {
169
167
  this.#e.addEventListener(
170
168
  "mediastate",
171
- (a) => {
172
- a.target === e && t(a.target);
169
+ (i) => {
170
+ i.target === e && t(i.target);
173
171
  }
174
172
  );
175
173
  });
@@ -178,20 +176,19 @@ class A extends f {
178
176
  return new Promise((t) => {
179
177
  this.#e.addEventListener(
180
178
  e,
181
- (a) => t(a)
179
+ (i) => t(i)
182
180
  );
183
181
  });
184
182
  }
185
- // eslint-disable-next-line @typescript-eslint/require-await
186
183
  async next(e) {
187
184
  this.debugLog("next", e), this.hasNextItem() && await this.unloadPreloadedMediaProduct();
188
- const { mediaProduct: t, playbackInfo: a, streamInfo: r } = e, { securityToken: h, streamFormat: d, streamUrl: c, streamingSessionId: n } = r;
189
- this.preloadedStreamingSessionId = n, this.debugLog("preloading", c, "for", n), d ? this.#e.preload(c, d, h) : console.error("Stream format undefined for preload."), this.debugLog("preloading done");
190
- const l = L({
185
+ const { mediaProduct: t, playbackInfo: i, streamInfo: r } = e, { securityToken: h, streamFormat: d, streamUrl: c, streamingSessionId: n } = r;
186
+ this.preloadedStreamingSessionId = n, this.debugLog("preloading", c, "for", n), d ? (this.#e.preload(c, d, h), this.isActivePlayer || this.#e.pause()) : console.error("Stream format undefined for preload."), this.debugLog("preloading done");
187
+ const l = y({
191
188
  assetPosition: 0,
192
189
  duration: 0,
193
190
  // TODO: Cannot get duration here, try to solve in some other way...
194
- playbackInfo: a,
191
+ playbackInfo: i,
195
192
  streamInfo: r
196
193
  });
197
194
  o.saveMediaProductTransition(n, {
@@ -223,15 +220,15 @@ class A extends f {
223
220
  }), this.#e.addEventListener(
224
221
  "mediastate",
225
222
  (e) => {
226
- e.target === "completed" ? this.finishCurrentMediaProduct("completed") : this.#n(e.target);
223
+ e.target === "completed" ? this.finishCurrentMediaProduct("completed") : this.#d(e.target);
227
224
  }
228
225
  ), this.#e.addEventListener(
229
226
  "devices",
230
227
  (e) => {
231
- i ? i.addNativeDevices(e.target) : console.error("Output devices not loaded.");
228
+ a ? a.addNativeDevices(e.target) : console.error("Output devices not loaded.");
232
229
  }
233
230
  ), this.#e.addEventListener("devicedisconnected", () => {
234
- s.dispatchEvent(w()), this.#t("devicedisconnected");
231
+ s.dispatchEvent(E()), this.#t("devicedisconnected");
235
232
  }), this.#e.addEventListener(
236
233
  "deviceexclusivemodenotallowed",
237
234
  () => this.#t("deviceexclusivemodenotallowed")
@@ -254,17 +251,17 @@ class A extends f {
254
251
  }
255
252
  ), this.#e.addEventListener(
256
253
  "mediaerror",
257
- (e) => this.#d(e)
254
+ (e) => this.#r(e)
258
255
  ), this.#e.addEventListener("mediamaxconnectionsreached", () => {
259
- this.#o().catch(console.error);
256
+ this.#n().catch(console.error);
260
257
  });
261
258
  }
262
- // eslint-disable-next-line @typescript-eslint/require-await
263
259
  async reset({ keepPreload: e } = { keepPreload: !1 }) {
264
- this.#r || (this.debugLog("reset"), e || await this.unloadPreloadedMediaProduct(), this.#e.stop(), this.playbackState !== "IDLE" && this.hasStarted() && this.finishCurrentMediaProduct("skip"), this.detachPlaybackEngineEndedHandler(), this.currentStreamingSessionId = void 0, e || (this.preloadedStreamingSessionId = void 0), this.playbackState = "IDLE", this.#r = !0);
260
+ this.currentStreamingSessionId !== void 0 && (this.debugLog("reset"), e || await this.unloadPreloadedMediaProduct(), this.#e.stop(), this.playbackState !== "IDLE" && this.finishCurrentMediaProduct("skip"), this.detachPlaybackEngineEndedHandler(), this.currentStreamingSessionId = void 0, e || (this.preloadedStreamingSessionId = void 0), this.playbackState = "IDLE");
265
261
  }
262
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
266
263
  async seek(e) {
267
- this.hasStarted() || await this.mediaStateChange("active"), this.seekStart(), this.currentTime = e, this.#e.seek(e), this.seekEnd();
264
+ this.hasStarted() || await this.mediaStateChange("active"), this.seekStart(this.currentTime), this.currentTime = e, this.#e.seek(e), this.seekEnd(this.currentTime);
268
265
  }
269
266
  // Handles track "skip next" and progressions between shaka and native player
270
267
  async skipToPreloadedMediaProduct() {
@@ -290,73 +287,37 @@ class A extends f {
290
287
  ), this.hasNextItem() && (this.cleanUpStoredPreloadInfo(), "cancelPreload" in this.#e ? this.#e.cancelPreload() : console.warn("cancelPreload not available. Update native player."));
291
288
  }
292
289
  updateDeviceMode() {
293
- this.updateOutputDevice()?.catch(console.error), i && s.dispatchEvent(
294
- P(i.deviceMode)
290
+ this.updateOutputDevice()?.catch(console.error), a && s.dispatchEvent(
291
+ P(a.deviceMode)
295
292
  );
296
293
  }
297
294
  updateOutputDevice() {
298
- if (!i || (this.debugLog("updateOutputDevice", i.activeDevice), !i.activeDevice))
295
+ if (!a || (this.debugLog("updateOutputDevice", a.activeDevice), !a.activeDevice))
299
296
  return Promise.resolve();
300
- const { nativeDeviceId: e } = i.activeDevice;
301
- if (this.outputDeviceType = i.activeDevice.type, e === "default")
297
+ const { nativeDeviceId: e } = a.activeDevice;
298
+ if (this.outputDeviceType = a.activeDevice.type, e === "default")
302
299
  this.#s !== "default" && (this.#e.selectSystemDevice(), s.dispatchEvent(S("default")), this.#s = "default");
303
300
  else if (e) {
304
- const t = i.getNativeDevice(e);
305
- t && (this.#e.selectDevice(t, i.deviceMode), s.dispatchEvent(
306
- S(i.activeDevice.id)
301
+ const t = a.getNativeDevice(e);
302
+ t && (this.#e.selectDevice(t, a.deviceMode), s.dispatchEvent(
303
+ S(a.activeDevice.id)
307
304
  ), s.dispatchEvent(
308
- P(i.deviceMode)
305
+ P(a.deviceMode)
309
306
  ), this.#s = e);
310
307
  } else
311
- console.warn(`Device with sinkId ${e} not found.`);
308
+ throw new Error(`Device with sinkId ${e} not found.`);
312
309
  return Promise.resolve();
313
310
  }
314
- /**
315
- * WIMPWC-7901
316
- * This is a temporary fix as there is currently no way to enable
317
- * the MQA decoder in Native Player after disabling it.
318
- *
319
- * Switching devices forces the Native Player to use the new device settings.
320
- * By default `device.passThrough` is `undefined`, that's why we check explicitly for `false`.
321
- *
322
- * TODO: Refactor when `this._player.enableMQADecoder();` works....
323
- */
324
- updatePassThrough() {
325
- if (!i)
326
- return;
327
- const { activeDevice: e } = i;
328
- if (i.passThrough === !0) {
329
- this.#e.disableMQADecoder(), s.dispatchEvent(b(!0));
330
- return;
331
- }
332
- if (i.passThrough === !1)
333
- if (this.#e.selectSystemDevice(), e.nativeDeviceId) {
334
- const t = i.getNativeDevice(
335
- e.nativeDeviceId
336
- );
337
- t && this.#e.selectDevice(
338
- t,
339
- i.deviceMode
340
- );
341
- } else
342
- console.error(
343
- "Passthrough could not be properly disabled since the nativeDeviceId is missing for",
344
- e
345
- );
346
- this.#e.enableMQADecoder(), s.dispatchEvent(b(!1));
347
- }
348
- // eslint-disable-next-line class-methods-use-this
349
311
  get ready() {
350
312
  return Promise.resolve();
351
313
  }
352
- // eslint-disable-next-line class-methods-use-this
353
314
  get volume() {
354
- return m("desiredVolumeLevel");
315
+ return v("desiredVolumeLevel");
355
316
  }
356
317
  set volume(e) {
357
318
  this.debugLog("Setting volume to", e), this.#e.setVolume(e * 100);
358
319
  }
359
320
  }
360
321
  export {
361
- A as default
322
+ x as default
362
323
  };
@@ -0,0 +1,224 @@
1
+ import { b as W, m as O, l as L, n as q } from "./index-vp_MoGvy.js";
2
+ import { l as M } from "./_commonjsHelpers-DaMA6jEr-DtILRGNx.js";
3
+ var P, S;
4
+ function N() {
5
+ return S || (S = 1, P = /* @__PURE__ */ function() {
6
+ function a(e, t, n, i, s) {
7
+ return e < t || n < t ? e > n ? n + 1 : e + 1 : i === s ? t : t + 1;
8
+ }
9
+ return function(e, t) {
10
+ if (e === t)
11
+ return 0;
12
+ if (e.length > t.length) {
13
+ var n = e;
14
+ e = t, t = n;
15
+ }
16
+ for (var i = e.length, s = t.length; i > 0 && e.charCodeAt(i - 1) === t.charCodeAt(s - 1); )
17
+ i--, s--;
18
+ for (var c = 0; c < i && e.charCodeAt(c) === t.charCodeAt(c); )
19
+ c++;
20
+ if (i -= c, s -= c, i === 0 || s < 3)
21
+ return s;
22
+ var o = 0, r, d, l, h, f, v, m, p, D, I, C, E, u = [];
23
+ for (r = 0; r < i; r++)
24
+ u.push(r + 1), u.push(e.charCodeAt(c + r));
25
+ for (var A = u.length - 1; o < s - 3; )
26
+ for (D = t.charCodeAt(c + (d = o)), I = t.charCodeAt(c + (l = o + 1)), C = t.charCodeAt(c + (h = o + 2)), E = t.charCodeAt(c + (f = o + 3)), v = o += 4, r = 0; r < A; r += 2)
27
+ m = u[r], p = u[r + 1], d = a(m, d, l, D, p), l = a(d, l, h, I, p), h = a(l, h, f, C, p), v = a(h, f, v, E, p), u[r] = v, f = h, h = l, l = d, d = m;
28
+ for (; o < s; )
29
+ for (D = t.charCodeAt(c + (d = o)), v = ++o, r = 0; r < A; r += 2)
30
+ m = u[r], u[r] = v = a(m, d, v, D, u[r + 1]), d = m;
31
+ return v;
32
+ };
33
+ }()), P;
34
+ }
35
+ var T = N();
36
+ const U = /* @__PURE__ */ M(T);
37
+ function B(a) {
38
+ return new CustomEvent("device-change", {
39
+ detail: {
40
+ devices: a
41
+ }
42
+ });
43
+ }
44
+ const y = O.parse(navigator.userAgent);
45
+ class w {
46
+ controllableVolume;
47
+ id;
48
+ name;
49
+ nativeDeviceId;
50
+ type;
51
+ webDeviceId;
52
+ constructor({
53
+ controllableVolume: e,
54
+ name: t,
55
+ nativeDeviceId: n,
56
+ type: i,
57
+ webDeviceId: s
58
+ }) {
59
+ this.name = t, this.id = n === "default" && s === "default" ? "default" : q(), this.nativeDeviceId = n, this.webDeviceId = s, this.type = i, this.controllableVolume = e !== !1;
60
+ }
61
+ }
62
+ function b(a) {
63
+ if (k(a))
64
+ return "windowsCommunication";
65
+ if ("id" in a && a.id === "BuiltInSpeakerDevice")
66
+ return "builtIn";
67
+ if ("type" in a && a.type === "airplay")
68
+ return "airplay";
69
+ if ("label" in a) {
70
+ const e = a.label.toLowerCase();
71
+ if (e.includes("bluetooth"))
72
+ return "bluetooth";
73
+ if (e.includes("displayport"))
74
+ return "displayPort";
75
+ if (e.includes("hdmi"))
76
+ return "hdmi";
77
+ if (e.includes("usb"))
78
+ return "usb";
79
+ if (e.includes("built-in"))
80
+ return "builtIn";
81
+ if (e.includes("airplay"))
82
+ return "airplay";
83
+ }
84
+ }
85
+ function g(a, e) {
86
+ const t = e.toLowerCase();
87
+ let n = a;
88
+ return t.includes("mac") && (n = (a.split("(")[0] ?? "").trim()), n;
89
+ }
90
+ function k(a) {
91
+ let e;
92
+ return "label" in a && (e = a.label), "name" in a && (e = a.name), e?.startsWith("Communications") ?? !1;
93
+ }
94
+ function V(a, e) {
95
+ if (e = g(e, y.os.name || ""), [...a].length === 0 || e === "")
96
+ return;
97
+ const t = [...a].find((i) => i.name === e);
98
+ if (t)
99
+ return t;
100
+ const n = [...a].filter((i) => e.includes(i.name) || i.name.includes(e)).map((i) => ({
101
+ device: i,
102
+ distance: U(i.name, e)
103
+ })).sort((i, s) => i.distance - s.distance).reverse();
104
+ if (n.length > 0) {
105
+ const i = n.pop();
106
+ if (i && i.distance <= 16)
107
+ return i.device;
108
+ }
109
+ }
110
+ class $ {
111
+ #i;
112
+ #a;
113
+ #n = "shared";
114
+ #e;
115
+ #t;
116
+ #s;
117
+ outputDevices;
118
+ constructor() {
119
+ this.#t = /* @__PURE__ */ new Set(), this.#s = /* @__PURE__ */ new Set(), this.#e = new EventTarget(), this.#a = new w({
120
+ name: "System Default",
121
+ nativeDeviceId: "default",
122
+ type: "systemDefault",
123
+ webDeviceId: "default"
124
+ }), this.#i = this.#a, this.outputDevices = /* @__PURE__ */ new Set([this.#a]), this.hydrateWebDevices().then().catch(console.error), navigator.mediaDevices.addEventListener("devicechange", () => {
125
+ this.hydrateWebDevices().then().catch(console.error);
126
+ }), this.#e.addEventListener("native-devices", (e) => {
127
+ this.#t = new Set(e.detail), this.queueUpdate().then().catch(console.error);
128
+ }), this.#e.addEventListener("web-devices", (e) => {
129
+ this.#s = new Set(e.detail), this.queueUpdate().then().catch(console.error);
130
+ });
131
+ }
132
+ addNativeDevices(e) {
133
+ this.#e.dispatchEvent(
134
+ new CustomEvent("native-devices", {
135
+ detail: e
136
+ })
137
+ );
138
+ }
139
+ addWebDevices(e) {
140
+ e = e.filter((t) => t.deviceId !== "default"), this.#e.dispatchEvent(
141
+ new CustomEvent("web-devices", {
142
+ detail: e
143
+ })
144
+ );
145
+ }
146
+ emitDeviceChange() {
147
+ W.dispatchEvent(B([...this.outputDevices]));
148
+ }
149
+ getNativeDevice(e) {
150
+ return [...this.#t].find((t) => t.id === e);
151
+ }
152
+ async hydrateWebDevices() {
153
+ const e = (await navigator.mediaDevices.enumerateDevices()).filter((t) => t.kind === "audiooutput");
154
+ this.addWebDevices(e);
155
+ }
156
+ mergeDevices() {
157
+ [...this.outputDevices].filter((e) => e.id !== "default").forEach((e) => {
158
+ e.nativeDeviceId = void 0, e.webDeviceId = void 0;
159
+ }), this.#t.forEach((e) => {
160
+ const t = V(this.outputDevices, e.name);
161
+ t ? (t.nativeDeviceId = e.id, t.controllableVolume = e.controllableVolume, t.type = b(e) || t.type) : this.outputDevices.add(
162
+ new w({
163
+ controllableVolume: e.controllableVolume,
164
+ name: g(e.name, y.os.name || ""),
165
+ nativeDeviceId: e.id,
166
+ type: b(e)
167
+ })
168
+ );
169
+ }), this.#s.forEach((e) => {
170
+ const t = V(this.outputDevices, e.label);
171
+ t ? (t.webDeviceId = e.deviceId, t.type = b(e) || t.type) : this.outputDevices.add(
172
+ new w({
173
+ name: g(e.label, y.os.name || ""),
174
+ type: b(e),
175
+ webDeviceId: e.deviceId
176
+ })
177
+ );
178
+ }), [...this.outputDevices].filter(
179
+ (e) => e.webDeviceId === void 0 && e.nativeDeviceId === void 0 || e.type === "airplay" || e.type === "windowsCommunication"
180
+ ).forEach((e) => this.outputDevices.delete(e));
181
+ }
182
+ async queueUpdate() {
183
+ const e = new Promise(
184
+ (i) => this.#e.addEventListener(
185
+ "native-devices",
186
+ (s) => i(s.detail),
187
+ { once: !0 }
188
+ )
189
+ ), t = new Promise(
190
+ (i) => this.#e.addEventListener(
191
+ "web-devices",
192
+ (s) => i(s.detail),
193
+ { once: !0 }
194
+ )
195
+ ), n = (i) => new Promise((s) => setTimeout(() => s(), i));
196
+ await Promise.any([e, t, n(1e3)]), this.mergeDevices(), this.emitDeviceChange();
197
+ }
198
+ set activeDevice(e) {
199
+ this.#i = e, this.#n = "shared", L.activePlayer?.updateOutputDevice()?.catch(console.error);
200
+ }
201
+ get activeDevice() {
202
+ return this.#i;
203
+ }
204
+ /**
205
+ * Set the current device mode for the output device.
206
+ */
207
+ set deviceMode(e) {
208
+ const { activeDevice: t } = this, { activePlayer: n } = L;
209
+ t && n && n.name === "nativePlayer" && this.deviceMode !== e && (this.#n = e, n.updateDeviceMode());
210
+ }
211
+ get deviceMode() {
212
+ return this.#n;
213
+ }
214
+ }
215
+ const F = new $();
216
+ export {
217
+ w as OutputDevice,
218
+ $ as OutputDevices,
219
+ b as findOutputType,
220
+ V as getOutputDeviceByName,
221
+ k as isWindowsCommunicationsDevice,
222
+ g as marshalLabel,
223
+ F as outputDevices
224
+ };