@tidal-music/player-web-components 0.1.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/LICENSE +201 -0
- package/README.md +3 -0
- package/dist/_commonjsHelpers-f3sTPFkQ-YKQV-mq1.js +8 -0
- package/dist/basePlayer-a-avZASH-Ux-6s9Ex.js +579 -0
- package/dist/browserPlayer-oNOpDVm6-UW0N6pFH.js +270 -0
- package/dist/index-tM9JvbA8.js +3267 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +10 -0
- package/dist/nativePlayer-U375Dfm5-hUK7oXzY.js +362 -0
- package/dist/output-devices-NXuo75MQ-_vYYuqUm.js +236 -0
- package/dist/shakaPlayer-izGFLVQr--XUsjgT2.js +24740 -0
- package/dist/worker-qh_9Fyf6-Li0uY2-a.js +89 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CredentialsProvider } from '@tidal-music/common';
|
|
2
|
+
import { events } from '@tidal-music/player';
|
|
3
|
+
import { setCredentialsProvider } from '@tidal-music/player';
|
|
4
|
+
|
|
5
|
+
export { CredentialsProvider }
|
|
6
|
+
|
|
7
|
+
export { events }
|
|
8
|
+
|
|
9
|
+
export { setCredentialsProvider }
|
|
10
|
+
|
|
11
|
+
export declare const TidalCurrentTime = "tidal-current-time";
|
|
12
|
+
|
|
13
|
+
export declare const TidalDurationTime = "tidal-duration-time";
|
|
14
|
+
|
|
15
|
+
export declare const TidalPlayButton = "tidal-play-trigger";
|
|
16
|
+
|
|
17
|
+
export declare const TidalProgressBar = "tidal-progress-bar";
|
|
18
|
+
|
|
19
|
+
export declare const TidalVideoView = "tidal-video-view";
|
|
20
|
+
|
|
21
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
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";
|
|
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
|
|
10
|
+
};
|
|
@@ -0,0 +1,362 @@
|
|
|
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);
|
|
6
|
+
}
|
|
7
|
+
const D = {
|
|
8
|
+
file_checksum_mismatch: "NPO02",
|
|
9
|
+
no_such_file: "NPO01",
|
|
10
|
+
unreadable_file: "NPO03"
|
|
11
|
+
}, N = {
|
|
12
|
+
devicedisconnected: "NPD01",
|
|
13
|
+
deviceexclusivemodenotallowed: "NPD02",
|
|
14
|
+
deviceformatnotsupported: "NPD03",
|
|
15
|
+
devicelocked: "NPD04",
|
|
16
|
+
devicenotfound: "NPD05",
|
|
17
|
+
deviceunknownerror: "NPD00"
|
|
18
|
+
};
|
|
19
|
+
let i;
|
|
20
|
+
class A extends f {
|
|
21
|
+
#s = "default";
|
|
22
|
+
/**
|
|
23
|
+
* A Boolean which is true if the media contained in the element has finished playing.
|
|
24
|
+
*
|
|
25
|
+
* (Native player sends multiple "complete" events.
|
|
26
|
+
* This variable should be set to true on the first call
|
|
27
|
+
* to be able to ignore subsequent onces; until reset
|
|
28
|
+
* for a new media product.)
|
|
29
|
+
*
|
|
30
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended
|
|
31
|
+
*/
|
|
32
|
+
#i;
|
|
33
|
+
#r = !0;
|
|
34
|
+
#e;
|
|
35
|
+
#a;
|
|
36
|
+
name = "nativePlayer";
|
|
37
|
+
playbackEngineHandlerAttached = !1;
|
|
38
|
+
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
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
window.NativePlayerComponent.Player(), this.playbackState = "IDLE", this.registerEventListeners(), this.#e.setVolume(100);
|
|
42
|
+
}
|
|
43
|
+
// eslint-disable-next-line class-methods-use-this
|
|
44
|
+
#t(e) {
|
|
45
|
+
s.dispatchError(
|
|
46
|
+
new u("EUnexpected", N[e])
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
#d(e) {
|
|
50
|
+
this.debugLog("handleMediaError", e.target);
|
|
51
|
+
const t = e.target, a = D[t.errorCode];
|
|
52
|
+
this.currentStreamingSessionId && k({
|
|
53
|
+
errorCode: a,
|
|
54
|
+
errorMessage: JSON.stringify(e.target),
|
|
55
|
+
streamingSessionId: this.currentStreamingSessionId
|
|
56
|
+
}), s.dispatchError(new u("EUnexpected", a));
|
|
57
|
+
}
|
|
58
|
+
#n(e) {
|
|
59
|
+
switch (this.debugLog("handleNativePlayerStateChange", e), e) {
|
|
60
|
+
case "paused":
|
|
61
|
+
case "ready":
|
|
62
|
+
this.playbackState = "NOT_PLAYING";
|
|
63
|
+
break;
|
|
64
|
+
case "active":
|
|
65
|
+
this.playbackState = "PLAYING";
|
|
66
|
+
break;
|
|
67
|
+
case "seeking":
|
|
68
|
+
case "idle":
|
|
69
|
+
this.playbackState = "STALLED";
|
|
70
|
+
break;
|
|
71
|
+
case "uninitialized":
|
|
72
|
+
this.playbackState = "IDLE";
|
|
73
|
+
break;
|
|
74
|
+
case "stopped":
|
|
75
|
+
this.playbackState = "NOT_PLAYING";
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
this.debugLog("No handling for state", e);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async #o() {
|
|
83
|
+
this.debugLog("handleNetworkError");
|
|
84
|
+
const e = p.timestamp(
|
|
85
|
+
"streaming_metrics:playback_statistics:actualStartTimestamp"
|
|
86
|
+
);
|
|
87
|
+
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());
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
await Promise.race([
|
|
93
|
+
this.mediaStateChange("idle"),
|
|
94
|
+
new Promise((t) => {
|
|
95
|
+
window.addEventListener("online", () => t("online"));
|
|
96
|
+
})
|
|
97
|
+
]) === "idle" && s.dispatchError(new u("PENetwork", "NPN01"));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clean up native player before leaving for another player.
|
|
101
|
+
*/
|
|
102
|
+
abandon() {
|
|
103
|
+
i && i.deviceMode === "exclusive" && this.#e.selectSystemDevice();
|
|
104
|
+
}
|
|
105
|
+
getPosition() {
|
|
106
|
+
return this.currentTime;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* We cannot run multiple instances of native player so this function is
|
|
110
|
+
* for catching duration for a preloaded item in native player.
|
|
111
|
+
*
|
|
112
|
+
* I.e. wait for player to load it and emit mediaduration event, then we
|
|
113
|
+
* can gather the duration data and send a media product transition.
|
|
114
|
+
*/
|
|
115
|
+
async handleAutomaticTransitionToPreloadedMediaProduct() {
|
|
116
|
+
await this.nativeEvent("mediaduration"), this.#a = void 0;
|
|
117
|
+
const e = o.getMediaProductTransition(
|
|
118
|
+
this.preloadedStreamingSessionId
|
|
119
|
+
);
|
|
120
|
+
if (!e) {
|
|
121
|
+
console.warn(
|
|
122
|
+
"No media product transition saved for next item. Stopping playback."
|
|
123
|
+
), this.playbackState = "NOT_PLAYING";
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const { mediaProduct: t, playbackContext: a } = e, r = {
|
|
127
|
+
...a,
|
|
128
|
+
actualDuration: this.#i
|
|
129
|
+
};
|
|
130
|
+
this.preloadedStreamingSessionId && o.saveMediaProductTransition(
|
|
131
|
+
this.preloadedStreamingSessionId,
|
|
132
|
+
{
|
|
133
|
+
mediaProduct: t,
|
|
134
|
+
playbackContext: r
|
|
135
|
+
}
|
|
136
|
+
), await this.mediaStateChange("active"), s.dispatchEvent(
|
|
137
|
+
y(t, r)
|
|
138
|
+
), this.currentStreamingSessionId = this.preloadedStreamingSessionId, this.mediaProductStarted(this.currentStreamingSessionId);
|
|
139
|
+
}
|
|
140
|
+
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;
|
|
143
|
+
this.currentStreamingSessionId = d.streamingSessionId, t === "explicit" && (this.playbackState = "NOT_PLAYING");
|
|
144
|
+
const I = this.nativeEvent("mediaduration");
|
|
145
|
+
if (n)
|
|
146
|
+
this.#e.load(l, n, c);
|
|
147
|
+
else
|
|
148
|
+
throw new Error("Stream format is undefined.");
|
|
149
|
+
if (await I, this.currentStreamingSessionId !== d.streamingSessionId)
|
|
150
|
+
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;
|
|
153
|
+
})().catch(console.error) : this.currentTime = 0;
|
|
154
|
+
const v = L({
|
|
155
|
+
assetPosition: a,
|
|
156
|
+
duration: this.#i,
|
|
157
|
+
playbackInfo: h,
|
|
158
|
+
streamInfo: d
|
|
159
|
+
});
|
|
160
|
+
o.saveMediaProductTransition(
|
|
161
|
+
d.streamingSessionId,
|
|
162
|
+
{ mediaProduct: r, playbackContext: v }
|
|
163
|
+
), this.debugLog("load() mediaProductTransition"), s.dispatchEvent(
|
|
164
|
+
y(r, v)
|
|
165
|
+
), this.debugLog("load() pb NOT_PLAYING"), this.debugLog("load() done");
|
|
166
|
+
}
|
|
167
|
+
mediaStateChange(e) {
|
|
168
|
+
return new Promise((t) => {
|
|
169
|
+
this.#e.addEventListener(
|
|
170
|
+
"mediastate",
|
|
171
|
+
(a) => {
|
|
172
|
+
a.target === e && t(a.target);
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
nativeEvent(e) {
|
|
178
|
+
return new Promise((t) => {
|
|
179
|
+
this.#e.addEventListener(
|
|
180
|
+
e,
|
|
181
|
+
(a) => t(a)
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
186
|
+
async next(e) {
|
|
187
|
+
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({
|
|
191
|
+
assetPosition: 0,
|
|
192
|
+
duration: 0,
|
|
193
|
+
// TODO: Cannot get duration here, try to solve in some other way...
|
|
194
|
+
playbackInfo: a,
|
|
195
|
+
streamInfo: r
|
|
196
|
+
});
|
|
197
|
+
o.saveMediaProductTransition(n, {
|
|
198
|
+
mediaProduct: t,
|
|
199
|
+
playbackContext: l
|
|
200
|
+
}), this.#a = e;
|
|
201
|
+
}
|
|
202
|
+
pause() {
|
|
203
|
+
this.#e.pause();
|
|
204
|
+
}
|
|
205
|
+
async play() {
|
|
206
|
+
if (this.debugLog("play"), await this.maybeHardReload(), this.playbackState === "IDLE") {
|
|
207
|
+
this.debugLog("play()", this.playbackState, "returning early");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this.setStateToXIfNotYInZMs(1e3, "PLAYING", "STALLED"), await this.updateOutputDevice(), this.mediaProductStarted(this.currentStreamingSessionId), this.debugLog("nativePlayer", "play()"), this.#e.play();
|
|
211
|
+
}
|
|
212
|
+
async playbackEngineEndedHandler(e) {
|
|
213
|
+
if (this.isActivePlayer) {
|
|
214
|
+
const { reason: t } = e.detail;
|
|
215
|
+
t === "completed" && (this.hasNextItem() ? await this.handleAutomaticTransitionToPreloadedMediaProduct() : (g.preloadedStreamingSessionId ? this.debugLog(
|
|
216
|
+
`Switching player from ${this.name} to ${g.preloadPlayer?.name}`
|
|
217
|
+
) : this.debugLog("No next item queued."), this.playbackState = "NOT_PLAYING"));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
registerEventListeners() {
|
|
221
|
+
this.debugLog("registerEventListeners"), this.#e.addEventListener("mediacurrenttime", (e) => {
|
|
222
|
+
this.currentTime = Number(e.target);
|
|
223
|
+
}), this.#e.addEventListener(
|
|
224
|
+
"mediastate",
|
|
225
|
+
(e) => {
|
|
226
|
+
e.target === "completed" ? this.finishCurrentMediaProduct("completed") : this.#n(e.target);
|
|
227
|
+
}
|
|
228
|
+
), this.#e.addEventListener(
|
|
229
|
+
"devices",
|
|
230
|
+
(e) => {
|
|
231
|
+
i ? i.addNativeDevices(e.target) : console.error("Output devices not loaded.");
|
|
232
|
+
}
|
|
233
|
+
), this.#e.addEventListener("devicedisconnected", () => {
|
|
234
|
+
s.dispatchEvent(w()), this.#t("devicedisconnected");
|
|
235
|
+
}), this.#e.addEventListener(
|
|
236
|
+
"deviceexclusivemodenotallowed",
|
|
237
|
+
() => this.#t("deviceexclusivemodenotallowed")
|
|
238
|
+
), this.#e.addEventListener(
|
|
239
|
+
"deviceformatnotsupported",
|
|
240
|
+
() => this.#t("deviceformatnotsupported")
|
|
241
|
+
), this.#e.addEventListener(
|
|
242
|
+
"devicelocked",
|
|
243
|
+
() => this.#t("devicelocked")
|
|
244
|
+
), this.#e.addEventListener(
|
|
245
|
+
"devicenotfound",
|
|
246
|
+
() => this.#t("devicenotfound")
|
|
247
|
+
), this.#e.addEventListener(
|
|
248
|
+
"deviceunknownerror",
|
|
249
|
+
() => this.#t("deviceunknownerror")
|
|
250
|
+
), this.#e.addEventListener(
|
|
251
|
+
"mediaduration",
|
|
252
|
+
(e) => {
|
|
253
|
+
this.#i = Number(e.target);
|
|
254
|
+
}
|
|
255
|
+
), this.#e.addEventListener(
|
|
256
|
+
"mediaerror",
|
|
257
|
+
(e) => this.#d(e)
|
|
258
|
+
), this.#e.addEventListener("mediamaxconnectionsreached", () => {
|
|
259
|
+
this.#o().catch(console.error);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
263
|
+
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);
|
|
265
|
+
}
|
|
266
|
+
async seek(e) {
|
|
267
|
+
this.hasStarted() || await this.mediaStateChange("active"), this.seekStart(), this.currentTime = e, this.#e.seek(e), this.seekEnd();
|
|
268
|
+
}
|
|
269
|
+
// Handles track "skip next" and progressions between shaka and native player
|
|
270
|
+
async skipToPreloadedMediaProduct() {
|
|
271
|
+
this.debugLog(
|
|
272
|
+
"skipToPreloadedMediaProduct",
|
|
273
|
+
this.preloadedStreamingSessionId
|
|
274
|
+
);
|
|
275
|
+
const e = this.currentStreamingSessionId === void 0;
|
|
276
|
+
if (this.preloadedStreamingSessionId && this.#a) {
|
|
277
|
+
const t = o.getMediaProductTransition(
|
|
278
|
+
this.preloadedStreamingSessionId
|
|
279
|
+
);
|
|
280
|
+
t && (this.#a.mediaProduct = t.mediaProduct), await this.load(this.#a, "implicit"), await this.updateOutputDevice(), e && (this.playbackState = "PLAYING"), this.playbackState === "IDLE" && (this.playbackState = "NOT_PLAYING");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
console.warn("No preloaded item in native player.");
|
|
284
|
+
}
|
|
285
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
286
|
+
async unloadPreloadedMediaProduct() {
|
|
287
|
+
this.debugLog(
|
|
288
|
+
"unloadPreloadedMediaProduct",
|
|
289
|
+
this.preloadedStreamingSessionId
|
|
290
|
+
), this.hasNextItem() && (this.cleanUpStoredPreloadInfo(), "cancelPreload" in this.#e ? this.#e.cancelPreload() : console.warn("cancelPreload not available. Update native player."));
|
|
291
|
+
}
|
|
292
|
+
updateDeviceMode() {
|
|
293
|
+
this.updateOutputDevice()?.catch(console.error), i && s.dispatchEvent(
|
|
294
|
+
P(i.deviceMode)
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
updateOutputDevice() {
|
|
298
|
+
if (!i || (this.debugLog("updateOutputDevice", i.activeDevice), !i.activeDevice))
|
|
299
|
+
return Promise.resolve();
|
|
300
|
+
const { nativeDeviceId: e } = i.activeDevice;
|
|
301
|
+
if (this.outputDeviceType = i.activeDevice.type, e === "default")
|
|
302
|
+
this.#s !== "default" && (this.#e.selectSystemDevice(), s.dispatchEvent(S("default")), this.#s = "default");
|
|
303
|
+
else if (e) {
|
|
304
|
+
const t = i.getNativeDevice(e);
|
|
305
|
+
t && (this.#e.selectDevice(t, i.deviceMode), s.dispatchEvent(
|
|
306
|
+
S(i.activeDevice.id)
|
|
307
|
+
), s.dispatchEvent(
|
|
308
|
+
P(i.deviceMode)
|
|
309
|
+
), this.#s = e);
|
|
310
|
+
} else
|
|
311
|
+
console.warn(`Device with sinkId ${e} not found.`);
|
|
312
|
+
return Promise.resolve();
|
|
313
|
+
}
|
|
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
|
+
get ready() {
|
|
350
|
+
return Promise.resolve();
|
|
351
|
+
}
|
|
352
|
+
// eslint-disable-next-line class-methods-use-this
|
|
353
|
+
get volume() {
|
|
354
|
+
return m("desiredVolumeLevel");
|
|
355
|
+
}
|
|
356
|
+
set volume(e) {
|
|
357
|
+
this.debugLog("Setting volume to", e), this.#e.setVolume(e * 100);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
export {
|
|
361
|
+
A as default
|
|
362
|
+
};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { h as V, y as S, l as b, g as T } from "./index-tM9JvbA8.js";
|
|
2
|
+
import { l as W } from "./_commonjsHelpers-f3sTPFkQ-YKQV-mq1.js";
|
|
3
|
+
var q = function() {
|
|
4
|
+
function s(e, t, n, i, a) {
|
|
5
|
+
return e < t || n < t ? e > n ? n + 1 : e + 1 : i === a ? t : t + 1;
|
|
6
|
+
}
|
|
7
|
+
return function(e, t) {
|
|
8
|
+
if (e === t)
|
|
9
|
+
return 0;
|
|
10
|
+
if (e.length > t.length) {
|
|
11
|
+
var n = e;
|
|
12
|
+
e = t, t = n;
|
|
13
|
+
}
|
|
14
|
+
for (var i = e.length, a = t.length; i > 0 && e.charCodeAt(i - 1) === t.charCodeAt(a - 1); )
|
|
15
|
+
i--, a--;
|
|
16
|
+
for (var c = 0; c < i && e.charCodeAt(c) === t.charCodeAt(c); )
|
|
17
|
+
c++;
|
|
18
|
+
if (i -= c, a -= c, i === 0 || a < 3)
|
|
19
|
+
return a;
|
|
20
|
+
var o = 0, r, d, h, l, f, v, m, p, D, C, E, A, u = [];
|
|
21
|
+
for (r = 0; r < i; r++)
|
|
22
|
+
u.push(r + 1), u.push(e.charCodeAt(c + r));
|
|
23
|
+
for (var P = u.length - 1; o < a - 3; )
|
|
24
|
+
for (D = t.charCodeAt(c + (d = o)), C = t.charCodeAt(c + (h = o + 1)), E = t.charCodeAt(c + (l = o + 2)), A = t.charCodeAt(c + (f = o + 3)), v = o += 4, r = 0; r < P; r += 2)
|
|
25
|
+
m = u[r], p = u[r + 1], d = s(m, d, h, D, p), h = s(d, h, l, C, p), l = s(h, l, f, E, p), v = s(l, f, v, A, p), u[r] = v, f = l, l = h, h = d, d = m;
|
|
26
|
+
for (; o < a; )
|
|
27
|
+
for (D = t.charCodeAt(c + (d = o)), v = ++o, r = 0; r < P; r += 2)
|
|
28
|
+
m = u[r], u[r] = v = s(m, d, v, D, u[r + 1]), d = m;
|
|
29
|
+
return v;
|
|
30
|
+
};
|
|
31
|
+
}();
|
|
32
|
+
const O = /* @__PURE__ */ W(q);
|
|
33
|
+
function M(s) {
|
|
34
|
+
return new CustomEvent("device-change", {
|
|
35
|
+
detail: {
|
|
36
|
+
devices: s
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const g = V.parse(navigator.userAgent);
|
|
41
|
+
class w {
|
|
42
|
+
controllableVolume;
|
|
43
|
+
id;
|
|
44
|
+
name;
|
|
45
|
+
nativeDeviceId;
|
|
46
|
+
type;
|
|
47
|
+
webDeviceId;
|
|
48
|
+
constructor({
|
|
49
|
+
controllableVolume: e,
|
|
50
|
+
name: t,
|
|
51
|
+
nativeDeviceId: n,
|
|
52
|
+
type: i,
|
|
53
|
+
webDeviceId: a
|
|
54
|
+
}) {
|
|
55
|
+
this.name = t, this.id = n === "default" && a === "default" ? "default" : T(), this.nativeDeviceId = n, this.webDeviceId = a, this.type = i, this.controllableVolume = e !== !1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function y(s) {
|
|
59
|
+
if (B(s))
|
|
60
|
+
return "windowsCommunication";
|
|
61
|
+
if ("id" in s && s.id === "BuiltInSpeakerDevice")
|
|
62
|
+
return "builtIn";
|
|
63
|
+
if ("type" in s) {
|
|
64
|
+
if (s.type === "airplay")
|
|
65
|
+
return "airplay";
|
|
66
|
+
if (s.type === "mqa")
|
|
67
|
+
return "mqa";
|
|
68
|
+
}
|
|
69
|
+
if ("label" in s) {
|
|
70
|
+
const e = s.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 I(s, e) {
|
|
86
|
+
const t = e.toLowerCase();
|
|
87
|
+
let n = s;
|
|
88
|
+
return t.includes("mac") && (n = s.split("(")[0].trim()), n;
|
|
89
|
+
}
|
|
90
|
+
function B(s) {
|
|
91
|
+
let e;
|
|
92
|
+
return "label" in s && (e = s.label), "name" in s && (e = s.name), e !== void 0 && e.startsWith("Communications");
|
|
93
|
+
}
|
|
94
|
+
function L(s, e) {
|
|
95
|
+
if (e = I(e, g.os.name || ""), [...s].length === 0 || e === "")
|
|
96
|
+
return;
|
|
97
|
+
const t = [...s].filter((i) => i.name === e)[0];
|
|
98
|
+
if (t)
|
|
99
|
+
return t;
|
|
100
|
+
const n = [...s].filter((i) => e.includes(i.name) || i.name.includes(e)).map((i) => ({
|
|
101
|
+
device: i,
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
103
|
+
distance: O(i.name, e)
|
|
104
|
+
})).sort((i, a) => i.distance - a.distance).reverse();
|
|
105
|
+
if (n.length > 0) {
|
|
106
|
+
const i = n.pop();
|
|
107
|
+
if (i && i.distance <= 16)
|
|
108
|
+
return i.device;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
class N {
|
|
112
|
+
#i;
|
|
113
|
+
#s;
|
|
114
|
+
#n = "shared";
|
|
115
|
+
#e;
|
|
116
|
+
#t;
|
|
117
|
+
#a = void 0;
|
|
118
|
+
#r;
|
|
119
|
+
outputDevices;
|
|
120
|
+
constructor() {
|
|
121
|
+
this.#t = /* @__PURE__ */ new Set(), this.#r = /* @__PURE__ */ new Set(), this.#e = new EventTarget(), this.#s = new w({
|
|
122
|
+
name: "System Default",
|
|
123
|
+
nativeDeviceId: "default",
|
|
124
|
+
type: "systemDefault",
|
|
125
|
+
webDeviceId: "default"
|
|
126
|
+
}), this.#i = this.#s, this.outputDevices = /* @__PURE__ */ new Set([this.#s]), this.hydrateWebDevices().then().catch(console.error), navigator.mediaDevices.addEventListener("devicechange", () => {
|
|
127
|
+
this.hydrateWebDevices().then().catch(console.error);
|
|
128
|
+
}), this.#e.addEventListener("native-devices", (e) => {
|
|
129
|
+
this.#t = new Set(e.detail), this.queueUpdate().then().catch(console.error);
|
|
130
|
+
}), this.#e.addEventListener("web-devices", (e) => {
|
|
131
|
+
this.#r = new Set(e.detail), this.queueUpdate().then().catch(console.error);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
addNativeDevices(e) {
|
|
135
|
+
this.#e.dispatchEvent(
|
|
136
|
+
new CustomEvent("native-devices", {
|
|
137
|
+
detail: e
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
addWebDevices(e) {
|
|
142
|
+
e = e.filter((t) => t.deviceId !== "default"), this.#e.dispatchEvent(
|
|
143
|
+
new CustomEvent("web-devices", {
|
|
144
|
+
detail: e
|
|
145
|
+
})
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
emitDeviceChange() {
|
|
149
|
+
S.dispatchEvent(M([...this.outputDevices]));
|
|
150
|
+
}
|
|
151
|
+
getNativeDevice(e) {
|
|
152
|
+
return [...this.#t].find((t) => t.id === e);
|
|
153
|
+
}
|
|
154
|
+
async hydrateWebDevices() {
|
|
155
|
+
const e = (await navigator.mediaDevices.enumerateDevices()).filter((t) => t.kind === "audiooutput");
|
|
156
|
+
this.addWebDevices(e);
|
|
157
|
+
}
|
|
158
|
+
mergeDevices() {
|
|
159
|
+
[...this.outputDevices].filter((e) => e.id !== "default").forEach((e) => {
|
|
160
|
+
e.nativeDeviceId = void 0, e.webDeviceId = void 0;
|
|
161
|
+
}), this.#t.forEach((e) => {
|
|
162
|
+
const t = L(this.outputDevices, e.name);
|
|
163
|
+
t ? (t.nativeDeviceId = e.id, t.controllableVolume = e.controllableVolume, t.type = y(e) || t.type) : this.outputDevices.add(
|
|
164
|
+
new w({
|
|
165
|
+
controllableVolume: e.controllableVolume,
|
|
166
|
+
name: I(e.name, g.os.name || ""),
|
|
167
|
+
nativeDeviceId: e.id,
|
|
168
|
+
type: y(e)
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
}), this.#r.forEach((e) => {
|
|
172
|
+
const t = L(this.outputDevices, e.label);
|
|
173
|
+
t ? (t.webDeviceId = e.deviceId, t.type = y(e) || t.type) : this.outputDevices.add(
|
|
174
|
+
new w({
|
|
175
|
+
name: I(e.label, g.os.name || ""),
|
|
176
|
+
type: y(e),
|
|
177
|
+
webDeviceId: e.deviceId
|
|
178
|
+
})
|
|
179
|
+
);
|
|
180
|
+
}), [...this.outputDevices].filter(
|
|
181
|
+
(e) => e.webDeviceId === void 0 && e.nativeDeviceId === void 0 || e.type === "airplay" || e.type === "windowsCommunication"
|
|
182
|
+
).forEach((e) => this.outputDevices.delete(e));
|
|
183
|
+
}
|
|
184
|
+
async queueUpdate() {
|
|
185
|
+
const e = new Promise(
|
|
186
|
+
(i) => this.#e.addEventListener(
|
|
187
|
+
"native-devices",
|
|
188
|
+
(a) => i(a.detail),
|
|
189
|
+
{ once: !0 }
|
|
190
|
+
)
|
|
191
|
+
), t = new Promise(
|
|
192
|
+
(i) => this.#e.addEventListener(
|
|
193
|
+
"web-devices",
|
|
194
|
+
(a) => i(a.detail),
|
|
195
|
+
{ once: !0 }
|
|
196
|
+
)
|
|
197
|
+
), n = (i) => new Promise((a) => setTimeout(() => a(), i));
|
|
198
|
+
await Promise.any([e, t, n(1e3)]), this.mergeDevices(), this.emitDeviceChange();
|
|
199
|
+
}
|
|
200
|
+
set activeDevice(e) {
|
|
201
|
+
this.#i = e, this.#a = !1, this.#n = "shared", b.activePlayer?.updateOutputDevice()?.catch(console.error);
|
|
202
|
+
}
|
|
203
|
+
get activeDevice() {
|
|
204
|
+
return this.#i;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Set the current device mode for the output device.
|
|
208
|
+
*/
|
|
209
|
+
set deviceMode(e) {
|
|
210
|
+
const { activeDevice: t } = this, { activePlayer: n } = b;
|
|
211
|
+
t && n && n.name === "nativePlayer" && this.deviceMode !== e && (this.#n = e, n.updateDeviceMode());
|
|
212
|
+
}
|
|
213
|
+
get deviceMode() {
|
|
214
|
+
return this.#n;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Set to true to disable software MQA decoder.
|
|
218
|
+
*/
|
|
219
|
+
set passThrough(e) {
|
|
220
|
+
const { activeDevice: t } = this, { activePlayer: n } = b;
|
|
221
|
+
t && n && n.name === "nativePlayer" && this.passThrough !== e && (this.#a = e, n.updatePassThrough());
|
|
222
|
+
}
|
|
223
|
+
get passThrough() {
|
|
224
|
+
return !!this.#a;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const $ = new N();
|
|
228
|
+
export {
|
|
229
|
+
w as OutputDevice,
|
|
230
|
+
N as OutputDevices,
|
|
231
|
+
y as findOutputType,
|
|
232
|
+
L as getOutputDeviceByName,
|
|
233
|
+
B as isWindowsCommunicationsDevice,
|
|
234
|
+
I as marshalLabel,
|
|
235
|
+
$ as outputDevices
|
|
236
|
+
};
|