@gentomiyano/optimized-web-audio-player 0.2.1 → 0.2.2
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/README.md +13 -0
- package/dist/config/index.d.ts +1 -1
- package/dist/consumer/index.d.ts +1 -1
- package/dist/contracts/index.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/media-delivery/index.d.ts +1 -1
- package/dist/{media-element-DyMO-PhK.d.ts → media-element-vFtmw4mQ.d.ts} +1 -1
- package/dist/{player-BxNFzRq4.d.ts → player-CE714iU_.d.ts} +2 -1
- package/dist/ports/index.d.ts +2 -2
- package/dist/react/index.d.ts +6 -3
- package/dist/react/index.js +179 -24
- package/dist/react/index.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/ui/index.d.ts +3 -2
- package/dist/ui/index.js +2 -0
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,19 @@ The public npm registry, scoped package name, and release workflow are fixed.
|
|
|
39
39
|
Initial npm publication still requires the scope owner's authentication.
|
|
40
40
|
Release and consumer pinning rules are documented in `docs/RELEASING.md`.
|
|
41
41
|
|
|
42
|
+
## WP-04.4 SSR-transparent Provider
|
|
43
|
+
|
|
44
|
+
Version 0.2.2 renders consumer children inside the same Player Context from
|
|
45
|
+
server rendering through hydration and Runtime readiness. `usePlayer()`
|
|
46
|
+
exposes `runtimeStatus` as `pending` or `ready`; pending state uses an inert,
|
|
47
|
+
SSR-safe Store bridge and never creates browser audio infrastructure.
|
|
48
|
+
|
|
49
|
+
`BoundCompactPlayer` renders its occurrence metadata while pending. Runtime
|
|
50
|
+
attachment updates the shared external Store without replacing or remounting
|
|
51
|
+
the consumer subtree. The built-package smoke now performs server rendering,
|
|
52
|
+
hydration, duplicate-ID, stable-sentinel, shared Mini Player, and single-audio
|
|
53
|
+
checks. See `docs/WP-04.4-SSR-TRANSPARENT-PROVIDER.md`.
|
|
54
|
+
|
|
42
55
|
## WP-04.3 React package boundary
|
|
43
56
|
|
|
44
57
|
Version 0.2.1 keeps React Context consumers in the `/react` entrypoint and
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { p as PlayerExperienceConfig,
|
|
1
|
+
import { p as PlayerExperienceConfig, z as PlayerState } from '../player-CE714iU_.js';
|
|
2
2
|
import { PlayerExperienceConfigValidationResult } from '../contracts/index.js';
|
|
3
3
|
|
|
4
4
|
declare const PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION: 2;
|
package/dist/consumer/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Q as QueueItem, u as PlayerMediaAdapter } from '../player-
|
|
1
|
+
import { Q as QueueItem, u as PlayerMediaAdapter } from '../player-CE714iU_.js';
|
|
2
2
|
|
|
3
3
|
interface PlayerQueueCandidate<TSource> {
|
|
4
4
|
/** Host-owned stable identity for this occurrence in a queue context. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as PlayerExperienceConfig } from '../player-
|
|
2
|
-
export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerDebugController, m as PlayerDebugSnapshot, n as PlayerError, o as PlayerErrorCode, q as PlayerExperienceConfigEnvelope, r as PlayerExperienceConfigStore, s as PlayerExperiencePreset, t as PlayerHostConfig, u as PlayerMediaAdapter, v as PlayerMediaItem, w as PlayerMediaSource, x as PlayerMediaSyncReason, y as
|
|
1
|
+
import { p as PlayerExperienceConfig } from '../player-CE714iU_.js';
|
|
2
|
+
export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerDebugController, m as PlayerDebugSnapshot, n as PlayerError, o as PlayerErrorCode, q as PlayerExperienceConfigEnvelope, r as PlayerExperienceConfigStore, s as PlayerExperiencePreset, t as PlayerHostConfig, u as PlayerMediaAdapter, v as PlayerMediaItem, w as PlayerMediaSource, x as PlayerMediaSyncReason, y as PlayerRuntimeStatus, z as PlayerState, C as PlayerStore, D as PlayerViewProps, E as PlayerWaveform, G as PodcastPreviousMode, Q as QueueItem, R as RepeatMode, S as SeekCommitMode, H as SetQueueOptions, I as StopOptions } from '../player-CE714iU_.js';
|
|
3
3
|
|
|
4
4
|
interface ConfigValidationSuccess {
|
|
5
5
|
readonly ok: true;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ConfigValidationFailure, ConfigValidationSuccess, PlayerExperienceConfigValidationResult } from './contracts/index.js';
|
|
2
|
-
export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerDebugController, m as PlayerDebugSnapshot, n as PlayerError, o as PlayerErrorCode, p as PlayerExperienceConfig, q as PlayerExperienceConfigEnvelope, r as PlayerExperienceConfigStore, s as PlayerExperiencePreset, t as PlayerHostConfig, u as PlayerMediaAdapter, v as PlayerMediaItem, w as PlayerMediaSource, x as PlayerMediaSyncReason, y as
|
|
2
|
+
export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerDebugController, m as PlayerDebugSnapshot, n as PlayerError, o as PlayerErrorCode, p as PlayerExperienceConfig, q as PlayerExperienceConfigEnvelope, r as PlayerExperienceConfigStore, s as PlayerExperiencePreset, t as PlayerHostConfig, u as PlayerMediaAdapter, v as PlayerMediaItem, w as PlayerMediaSource, x as PlayerMediaSyncReason, y as PlayerRuntimeStatus, z as PlayerState, C as PlayerStore, D as PlayerViewProps, E as PlayerWaveform, G as PodcastPreviousMode, Q as QueueItem, R as RepeatMode, S as SeekCommitMode, H as SetQueueOptions, I as StopOptions } from './player-CE714iU_.js';
|
|
3
3
|
export { PLAYER_EXPERIENCE_CONFIG_LIMITS, PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION, PREVIEW_PLAYER_EXPERIENCE_CONFIG, createInitialPlayerState, parsePlayerExperienceConfigJson, resolvePlayerExperienceConfig, serializePlayerExperienceConfig, validatePlayerExperienceConfig, validatePlayerExperienceConfigOverride } from './config/index.js';
|
|
4
4
|
export { AudioSampleEncoding, FutureUploadFormat, MEDIA_DELIVERY_CONTRACT_VERSION, MediaAccessClass, MediaDeliveryDescriptor, MediaDeliverySourceReference, MediaLoudnessMetadata, MediaSourceRole, MediaStorageReferences, MediaUploadEvidence, MediaUploadValidationResult, NormalizedUploadIdentity, PlaybackSourceResolveErrorCode, PlaybackSourceResolveReason, PlaybackSourceResolveRequest, PlaybackSourceResolveResult, PlayerDeliveryHostAdapter, PlayerMediaDescriptor, ProcessedMediaMetadata, ResolvedPlaybackSource, SupportedUploadFormat, UploadHeaderFormat, UploadValidationError, UploadValidationErrorCode, WaveformPeaksV1, validateMediaUploadEvidence, validateWaveformPeaks } from './media-delivery/index.js';
|
|
5
5
|
export { GainPort, GainTransition, PlayerPersistencePort, PodcastProgress, PodcastProgressPort } from './ports/index.js';
|
|
6
|
-
export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from './media-element-
|
|
6
|
+
export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from './media-element-vFtmw4mQ.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { w as PlayerMediaSource, v as PlayerMediaItem } from '../player-
|
|
1
|
+
import { w as PlayerMediaSource, v as PlayerMediaItem } from '../player-CE714iU_.js';
|
|
2
2
|
|
|
3
3
|
declare const MEDIA_DELIVERY_CONTRACT_VERSION: 1;
|
|
4
4
|
type SupportedUploadFormat = "wav" | "mp3";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as PlayerError, w as PlayerMediaSource } from './player-
|
|
1
|
+
import { n as PlayerError, w as PlayerMediaSource } from './player-CE714iU_.js';
|
|
2
2
|
|
|
3
3
|
type PlayerMediaEventType = "loadstart" | "loadedmetadata" | "canplay" | "play" | "playing" | "pause" | "waiting" | "stalled" | "seeking" | "seeked" | "timeupdate" | "ended" | "error" | "durationchange" | "volumechange";
|
|
4
4
|
interface PlayerMediaEvent {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
type PlaybackStatus = "idle" | "loading" | "playing" | "paused" | "seeking" | "ended" | "error";
|
|
2
|
+
type PlayerRuntimeStatus = "pending" | "ready";
|
|
2
3
|
type PlaybackTransitionCause = "user-play" | "user-pause" | "user-stop" | "natural-end" | "os-interruption" | "background-suspension" | "autoplay-blocked" | "source-error";
|
|
3
4
|
type PlayerMediaSyncReason = "visibilitychange" | "pageshow" | "focus" | "audio-context-statechange" | "manual";
|
|
4
5
|
type RepeatMode = "off" | "all" | "one";
|
|
@@ -261,4 +262,4 @@ interface PlayerDebugController {
|
|
|
261
262
|
exportProductionConfigJson(): string;
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
export type { ActivatePlaybackContextOptions as A, BoundPlayerCommands as B,
|
|
265
|
+
export type { ActivatePlaybackContextOptions as A, BoundPlayerCommands as B, PlayerStore as C, PlayerViewProps as D, PlayerWaveform as E, FadeCurve as F, PodcastPreviousMode as G, SetQueueOptions as H, StopOptions as I, MediaKind as M, PauseOptions as P, QueueItem as Q, RepeatMode as R, SeekCommitMode as S, BoundPlayerViewState as a, PersistMode as b, PlaybackContextInput as c, PlaybackContextMode as d, PlaybackContextState as e, PlaybackStatus as f, PlaybackTransitionCause as g, PlayerAppearance as h, PlayerCommandResult as i, PlayerCommands as j, PlayerConfigImportResult as k, PlayerDebugController as l, PlayerDebugSnapshot as m, PlayerError as n, PlayerErrorCode as o, PlayerExperienceConfig as p, PlayerExperienceConfigEnvelope as q, PlayerExperienceConfigStore as r, PlayerExperiencePreset as s, PlayerHostConfig as t, PlayerMediaAdapter as u, PlayerMediaItem as v, PlayerMediaSource as w, PlayerMediaSyncReason as x, PlayerRuntimeStatus as y, PlayerState as z };
|
package/dist/ports/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FadeCurve } from '../player-
|
|
2
|
-
export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from '../media-element-
|
|
1
|
+
import { F as FadeCurve } from '../player-CE714iU_.js';
|
|
2
|
+
export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from '../media-element-vFtmw4mQ.js';
|
|
3
3
|
|
|
4
4
|
interface GainTransition {
|
|
5
5
|
readonly durationMs: number;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { j as PlayerCommands, x as PlayerMediaSyncReason, Q as QueueItem, p as PlayerExperienceConfig,
|
|
4
|
-
import { c as PlayerMediaEventType, a as MediaElementStateSnapshot } from '../media-element-
|
|
3
|
+
import { j as PlayerCommands, x as PlayerMediaSyncReason, Q as QueueItem, p as PlayerExperienceConfig, y as PlayerRuntimeStatus, C as PlayerStore, r as PlayerExperienceConfigStore, z as PlayerState, c as PlaybackContextInput, a as BoundPlayerViewState, B as BoundPlayerCommands, h as PlayerAppearance } from '../player-CE714iU_.js';
|
|
4
|
+
import { c as PlayerMediaEventType, a as MediaElementStateSnapshot } from '../media-element-vFtmw4mQ.js';
|
|
5
5
|
|
|
6
6
|
type PlayerAudioMode = "auto" | "web-audio" | "html-media";
|
|
7
7
|
type ResolvedPlayerAudioMode = "web-audio" | "html-media";
|
|
@@ -44,6 +44,7 @@ interface PlayerProviderProps {
|
|
|
44
44
|
readonly initialQueue?: readonly QueueItem[];
|
|
45
45
|
readonly initialQueueItemId?: string;
|
|
46
46
|
readonly experienceConfig?: Partial<PlayerExperienceConfig>;
|
|
47
|
+
/** Used only when children is null or undefined while Runtime is pending. */
|
|
47
48
|
readonly loadingFallback?: ReactNode;
|
|
48
49
|
/**
|
|
49
50
|
* auto uses native HTML audio on iOS/iPadOS and Web Audio elsewhere.
|
|
@@ -54,6 +55,7 @@ interface PlayerProviderProps {
|
|
|
54
55
|
readonly onDiagnosticEvent?: PlayerRuntimeDiagnosticListener;
|
|
55
56
|
}
|
|
56
57
|
interface PlayerRuntimeContextValue {
|
|
58
|
+
readonly runtimeStatus: PlayerRuntimeStatus;
|
|
57
59
|
readonly store: PlayerStore;
|
|
58
60
|
readonly commands: PlayerCommands;
|
|
59
61
|
readonly experience: PlayerExperienceConfigStore;
|
|
@@ -73,6 +75,7 @@ interface MiniPlayerHostProps {
|
|
|
73
75
|
declare function MiniPlayerHost({ children, className, onInsetChange, visible, }: MiniPlayerHostProps): react.JSX.Element | null;
|
|
74
76
|
|
|
75
77
|
interface UsePlayerResult {
|
|
78
|
+
readonly runtimeStatus: PlayerRuntimeStatus;
|
|
76
79
|
readonly state: Readonly<PlayerState>;
|
|
77
80
|
readonly commands: PlayerCommands;
|
|
78
81
|
readonly experience: PlayerExperienceConfigStore;
|
|
@@ -102,4 +105,4 @@ interface BoundCompactPlayerProps {
|
|
|
102
105
|
}
|
|
103
106
|
declare function BoundCompactPlayer({ appearance, className, context, queueItem, }: BoundCompactPlayerProps): react.JSX.Element;
|
|
104
107
|
|
|
105
|
-
export { BoundCompactPlayer, type BoundCompactPlayerProps, MiniPlayerHost, type MiniPlayerHostProps, PlayerProvider, type PlayerProviderProps, type PlayerRuntimeContextValue, type PlayerRuntimeDiagnosticEvent, type PlayerRuntimeDiagnosticListener, type PlayerRuntimeDiagnosticPayload, type UseBoundPlayerOptions, type UseBoundPlayerResult, type UsePlayerResult, deriveBoundPlayerViewState, useBoundPlayer, usePlayer };
|
|
108
|
+
export { BoundCompactPlayer, type BoundCompactPlayerProps, MiniPlayerHost, type MiniPlayerHostProps, PlayerProvider, type PlayerProviderProps, type PlayerRuntimeContextValue, type PlayerRuntimeDiagnosticEvent, type PlayerRuntimeDiagnosticListener, type PlayerRuntimeDiagnosticPayload, PlayerRuntimeStatus, type UseBoundPlayerOptions, type UseBoundPlayerResult, type UsePlayerResult, deriveBoundPlayerViewState, useBoundPlayer, usePlayer };
|
package/dist/react/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useRef, useState, useEffect,
|
|
1
|
+
import { createContext, useRef, useState, useEffect, useMemo, useSyncExternalStore, useContext, useId } from 'react';
|
|
2
2
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/react/player-provider.tsx
|
|
@@ -2077,6 +2077,147 @@ function createPlayerStore(options) {
|
|
|
2077
2077
|
return new CorePlayerStore(options);
|
|
2078
2078
|
}
|
|
2079
2079
|
|
|
2080
|
+
// src/react/player-runtime-bridge.ts
|
|
2081
|
+
var RUNTIME_PENDING_ERROR = Object.freeze({
|
|
2082
|
+
code: "unknown",
|
|
2083
|
+
recoverable: true,
|
|
2084
|
+
messageKey: "player.error.runtime-pending"
|
|
2085
|
+
});
|
|
2086
|
+
var RUNTIME_PENDING_RESULT = Object.freeze({
|
|
2087
|
+
ok: false,
|
|
2088
|
+
error: RUNTIME_PENDING_ERROR
|
|
2089
|
+
});
|
|
2090
|
+
function notify(listeners) {
|
|
2091
|
+
for (const listener of listeners) {
|
|
2092
|
+
listener();
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
function createPlayerRuntimeBridge(experienceConfig) {
|
|
2096
|
+
let pendingState = createInitialPlayerState(experienceConfig);
|
|
2097
|
+
let activeStore = null;
|
|
2098
|
+
let activeCommands = null;
|
|
2099
|
+
let unsubscribeStore = null;
|
|
2100
|
+
let unsubscribeExperience = null;
|
|
2101
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2102
|
+
const experienceListeners = /* @__PURE__ */ new Set();
|
|
2103
|
+
const pendingResult = () => Promise.resolve(RUNTIME_PENDING_RESULT);
|
|
2104
|
+
const commandsImplementation = {
|
|
2105
|
+
load: (item) => activeCommands?.load(item) ?? pendingResult(),
|
|
2106
|
+
setQueue: (queue, options) => activeCommands?.setQueue(queue, options) ?? pendingResult(),
|
|
2107
|
+
activateContext: (options) => activeCommands?.activateContext(options) ?? pendingResult(),
|
|
2108
|
+
appendToManualHistory: (contextId, item) => {
|
|
2109
|
+
activeCommands?.appendToManualHistory(contextId, item);
|
|
2110
|
+
},
|
|
2111
|
+
play: () => activeCommands?.play() ?? pendingResult(),
|
|
2112
|
+
pause: (options) => activeCommands?.pause(options) ?? Promise.resolve(),
|
|
2113
|
+
stop: (options) => activeCommands?.stop(options) ?? Promise.resolve(),
|
|
2114
|
+
togglePlayback: () => activeCommands?.togglePlayback() ?? pendingResult(),
|
|
2115
|
+
seekTo: (seconds) => {
|
|
2116
|
+
activeCommands?.seekTo(seconds);
|
|
2117
|
+
},
|
|
2118
|
+
seekBy: (deltaSeconds) => {
|
|
2119
|
+
activeCommands?.seekBy(deltaSeconds);
|
|
2120
|
+
},
|
|
2121
|
+
setVolume: (volume) => {
|
|
2122
|
+
activeCommands?.setVolume(volume);
|
|
2123
|
+
},
|
|
2124
|
+
toggleMute: () => {
|
|
2125
|
+
activeCommands?.toggleMute();
|
|
2126
|
+
},
|
|
2127
|
+
setShuffle: (enabled) => {
|
|
2128
|
+
activeCommands?.setShuffle(enabled);
|
|
2129
|
+
},
|
|
2130
|
+
setRepeatMode: (mode) => {
|
|
2131
|
+
activeCommands?.setRepeatMode(mode);
|
|
2132
|
+
},
|
|
2133
|
+
next: () => activeCommands?.next() ?? pendingResult(),
|
|
2134
|
+
previous: () => activeCommands?.previous() ?? pendingResult(),
|
|
2135
|
+
retry: () => activeCommands?.retry() ?? pendingResult(),
|
|
2136
|
+
clear: () => activeCommands?.clear() ?? Promise.resolve()
|
|
2137
|
+
};
|
|
2138
|
+
const commands = Object.freeze(commandsImplementation);
|
|
2139
|
+
const experienceImplementation = {
|
|
2140
|
+
getConfig: () => activeStore?.experience.getConfig() ?? pendingState.experienceConfig,
|
|
2141
|
+
updateConfig: (patch) => {
|
|
2142
|
+
if (activeStore !== null) {
|
|
2143
|
+
activeStore.experience.updateConfig(patch);
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
pendingState = createInitialPlayerState({
|
|
2147
|
+
...pendingState.experienceConfig,
|
|
2148
|
+
...patch
|
|
2149
|
+
});
|
|
2150
|
+
notify(listeners);
|
|
2151
|
+
notify(experienceListeners);
|
|
2152
|
+
},
|
|
2153
|
+
resetConfig: () => {
|
|
2154
|
+
if (activeStore !== null) {
|
|
2155
|
+
activeStore.experience.resetConfig();
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
pendingState = createInitialPlayerState(
|
|
2159
|
+
PREVIEW_PLAYER_EXPERIENCE_CONFIG
|
|
2160
|
+
);
|
|
2161
|
+
notify(listeners);
|
|
2162
|
+
notify(experienceListeners);
|
|
2163
|
+
},
|
|
2164
|
+
subscribe: (listener) => {
|
|
2165
|
+
experienceListeners.add(listener);
|
|
2166
|
+
return () => {
|
|
2167
|
+
experienceListeners.delete(listener);
|
|
2168
|
+
};
|
|
2169
|
+
}
|
|
2170
|
+
};
|
|
2171
|
+
const experience = Object.freeze(experienceImplementation);
|
|
2172
|
+
const storeImplementation = {
|
|
2173
|
+
getState: () => activeStore?.getState() ?? pendingState,
|
|
2174
|
+
subscribe: (listener) => {
|
|
2175
|
+
listeners.add(listener);
|
|
2176
|
+
return () => {
|
|
2177
|
+
listeners.delete(listener);
|
|
2178
|
+
};
|
|
2179
|
+
},
|
|
2180
|
+
commands,
|
|
2181
|
+
experience,
|
|
2182
|
+
synchronizeFromMedia: (reason) => activeStore?.synchronizeFromMedia(reason) ?? Promise.resolve(),
|
|
2183
|
+
destroy: () => activeStore?.destroy() ?? Promise.resolve()
|
|
2184
|
+
};
|
|
2185
|
+
const store = Object.freeze(storeImplementation);
|
|
2186
|
+
const detachActiveStore = () => {
|
|
2187
|
+
unsubscribeStore?.();
|
|
2188
|
+
unsubscribeExperience?.();
|
|
2189
|
+
unsubscribeStore = null;
|
|
2190
|
+
unsubscribeExperience = null;
|
|
2191
|
+
activeStore = null;
|
|
2192
|
+
activeCommands = null;
|
|
2193
|
+
};
|
|
2194
|
+
const bridge = {
|
|
2195
|
+
store,
|
|
2196
|
+
attach(nextStore, nextCommands) {
|
|
2197
|
+
detachActiveStore();
|
|
2198
|
+
activeStore = nextStore;
|
|
2199
|
+
activeCommands = nextCommands;
|
|
2200
|
+
unsubscribeStore = nextStore.subscribe(() => {
|
|
2201
|
+
notify(listeners);
|
|
2202
|
+
});
|
|
2203
|
+
unsubscribeExperience = nextStore.experience.subscribe(() => {
|
|
2204
|
+
notify(experienceListeners);
|
|
2205
|
+
});
|
|
2206
|
+
notify(listeners);
|
|
2207
|
+
notify(experienceListeners);
|
|
2208
|
+
return () => {
|
|
2209
|
+
if (activeStore !== nextStore) {
|
|
2210
|
+
return;
|
|
2211
|
+
}
|
|
2212
|
+
detachActiveStore();
|
|
2213
|
+
notify(listeners);
|
|
2214
|
+
notify(experienceListeners);
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
};
|
|
2218
|
+
return Object.freeze(bridge);
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2080
2221
|
// src/react/runtime-commands.ts
|
|
2081
2222
|
function activate(gain, options) {
|
|
2082
2223
|
options.onUserActivation?.();
|
|
@@ -2216,7 +2357,10 @@ function PlayerProvider({
|
|
|
2216
2357
|
const initialQueueItemIdRef = useRef(initialQueueItemId);
|
|
2217
2358
|
const initialExperienceConfigRef = useRef(experienceConfig);
|
|
2218
2359
|
const diagnosticListenerRef = useRef(onDiagnosticEvent);
|
|
2219
|
-
const [
|
|
2360
|
+
const [runtimeBridge] = useState(
|
|
2361
|
+
() => createPlayerRuntimeBridge(experienceConfig)
|
|
2362
|
+
);
|
|
2363
|
+
const [runtimeStatus, setRuntimeStatus] = useState("pending");
|
|
2220
2364
|
const [audioContextState, setAudioContextState] = useState("uninitialized");
|
|
2221
2365
|
const [resolvedAudioMode, setResolvedAudioMode] = useState("web-audio");
|
|
2222
2366
|
const [mediaSessionSupported, setMediaSessionSupported] = useState(false);
|
|
@@ -2295,6 +2439,7 @@ function PlayerProvider({
|
|
|
2295
2439
|
});
|
|
2296
2440
|
}
|
|
2297
2441
|
});
|
|
2442
|
+
const detachRuntime = runtimeBridge.attach(store, commands);
|
|
2298
2443
|
mediaSessionController = createBrowserMediaSessionController({
|
|
2299
2444
|
commands,
|
|
2300
2445
|
getState: () => store.getState(),
|
|
@@ -2391,16 +2536,7 @@ function PlayerProvider({
|
|
|
2391
2536
|
);
|
|
2392
2537
|
window.addEventListener("pageshow", handlePageShow);
|
|
2393
2538
|
window.addEventListener("focus", handleFocus);
|
|
2394
|
-
|
|
2395
|
-
store,
|
|
2396
|
-
commands,
|
|
2397
|
-
experience: store.experience,
|
|
2398
|
-
audioContextState: "uninitialized",
|
|
2399
|
-
audioMode: nextAudioMode,
|
|
2400
|
-
mediaSessionSupported: activeMediaSessionController.supported,
|
|
2401
|
-
mediaSessionActionsEnabled: false
|
|
2402
|
-
};
|
|
2403
|
-
setRuntime(contextValue2);
|
|
2539
|
+
setRuntimeStatus("ready");
|
|
2404
2540
|
void store.commands.setQueue(initialQueueRef.current, {
|
|
2405
2541
|
...initialQueueItemIdRef.current === void 0 ? {} : { startQueueItemId: initialQueueItemIdRef.current },
|
|
2406
2542
|
autoplay: false
|
|
@@ -2419,21 +2555,35 @@ function PlayerProvider({
|
|
|
2419
2555
|
}
|
|
2420
2556
|
unsubscribeMediaSession();
|
|
2421
2557
|
activeMediaSessionController.destroy();
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
);
|
|
2558
|
+
setRuntimeStatus("pending");
|
|
2559
|
+
detachRuntime();
|
|
2425
2560
|
void store.destroy();
|
|
2426
2561
|
};
|
|
2427
2562
|
}, [
|
|
2428
|
-
audioMode
|
|
2563
|
+
audioMode,
|
|
2564
|
+
runtimeBridge
|
|
2429
2565
|
]);
|
|
2430
|
-
const contextValue =
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2566
|
+
const contextValue = useMemo(
|
|
2567
|
+
() => ({
|
|
2568
|
+
runtimeStatus,
|
|
2569
|
+
store: runtimeBridge.store,
|
|
2570
|
+
commands: runtimeBridge.store.commands,
|
|
2571
|
+
experience: runtimeBridge.store.experience,
|
|
2572
|
+
audioContextState,
|
|
2573
|
+
audioMode: resolvedAudioMode,
|
|
2574
|
+
mediaSessionSupported,
|
|
2575
|
+
mediaSessionActionsEnabled
|
|
2576
|
+
}),
|
|
2577
|
+
[
|
|
2578
|
+
audioContextState,
|
|
2579
|
+
mediaSessionActionsEnabled,
|
|
2580
|
+
mediaSessionSupported,
|
|
2581
|
+
resolvedAudioMode,
|
|
2582
|
+
runtimeBridge,
|
|
2583
|
+
runtimeStatus
|
|
2584
|
+
]
|
|
2585
|
+
);
|
|
2586
|
+
const consumerTree = children ?? (runtimeStatus === "pending" ? loadingFallback : null);
|
|
2437
2587
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2438
2588
|
/* @__PURE__ */ jsx(
|
|
2439
2589
|
"audio",
|
|
@@ -2444,11 +2594,12 @@ function PlayerProvider({
|
|
|
2444
2594
|
"data-media-session-actions": mediaSessionActionsEnabled ? "enabled" : "inactive",
|
|
2445
2595
|
"data-media-session-supported": mediaSessionSupported ? "true" : "false",
|
|
2446
2596
|
"data-player-audio": "true",
|
|
2597
|
+
"data-player-runtime-status": runtimeStatus,
|
|
2447
2598
|
preload: "metadata",
|
|
2448
2599
|
ref: audioRef
|
|
2449
2600
|
}
|
|
2450
2601
|
),
|
|
2451
|
-
|
|
2602
|
+
/* @__PURE__ */ jsx(PlayerRuntimeContext.Provider, { value: contextValue, children: consumerTree })
|
|
2452
2603
|
] });
|
|
2453
2604
|
}
|
|
2454
2605
|
function MiniPlayerHost({
|
|
@@ -2511,6 +2662,7 @@ function usePlayer() {
|
|
|
2511
2662
|
() => context.store.getState()
|
|
2512
2663
|
);
|
|
2513
2664
|
return {
|
|
2665
|
+
runtimeStatus: context.runtimeStatus,
|
|
2514
2666
|
state,
|
|
2515
2667
|
commands: context.commands,
|
|
2516
2668
|
experience: context.experience,
|
|
@@ -2996,6 +3148,7 @@ function BoundCompactPlayerView({
|
|
|
2996
3148
|
contextId,
|
|
2997
3149
|
contextMode,
|
|
2998
3150
|
options,
|
|
3151
|
+
runtimeStatus,
|
|
2999
3152
|
state
|
|
3000
3153
|
}) {
|
|
3001
3154
|
const progress = state.durationSec === null || state.durationSec <= 0 ? 0 : state.currentTimeSec / state.durationSec;
|
|
@@ -3012,6 +3165,7 @@ function BoundCompactPlayerView({
|
|
|
3012
3165
|
"data-active": state.isActive ? "true" : "false",
|
|
3013
3166
|
"data-playback-context-id": contextId,
|
|
3014
3167
|
"data-playback-context-mode": contextMode,
|
|
3168
|
+
"data-player-runtime-status": runtimeStatus,
|
|
3015
3169
|
"data-queue-item-id": state.queueItemId,
|
|
3016
3170
|
children: [
|
|
3017
3171
|
/* @__PURE__ */ jsx(
|
|
@@ -3087,6 +3241,7 @@ function BoundCompactPlayer({
|
|
|
3087
3241
|
commands: bound.commands,
|
|
3088
3242
|
contextId: context.id,
|
|
3089
3243
|
contextMode: context.mode,
|
|
3244
|
+
runtimeStatus: player.runtimeStatus,
|
|
3090
3245
|
options: {
|
|
3091
3246
|
seekCommitMode: player.state.experienceConfig.seekCommitMode,
|
|
3092
3247
|
waveformOpacity: player.state.experienceConfig.waveformOpacity,
|