@livepeer-frameworks/player-react 0.1.0 → 0.1.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.
Files changed (187) hide show
  1. package/README.md +7 -9
  2. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +359 -0
  3. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  4. package/dist/cjs/assets/logomark.svg.js +8 -0
  5. package/dist/cjs/assets/logomark.svg.js.map +1 -0
  6. package/dist/cjs/components/DevModePanel.js +826 -0
  7. package/dist/cjs/components/DevModePanel.js.map +1 -0
  8. package/dist/cjs/components/DvdLogo.js +200 -0
  9. package/dist/cjs/components/DvdLogo.js.map +1 -0
  10. package/dist/cjs/components/Icons.js +439 -0
  11. package/dist/cjs/components/Icons.js.map +1 -0
  12. package/dist/cjs/components/IdleScreen.js +587 -0
  13. package/dist/cjs/components/IdleScreen.js.map +1 -0
  14. package/dist/cjs/components/LoadingScreen.js +523 -0
  15. package/dist/cjs/components/LoadingScreen.js.map +1 -0
  16. package/dist/cjs/components/Player.js +420 -0
  17. package/dist/cjs/components/Player.js.map +1 -0
  18. package/dist/cjs/components/PlayerControls.js +798 -0
  19. package/dist/cjs/components/PlayerControls.js.map +1 -0
  20. package/dist/cjs/components/PlayerErrorBoundary.js +80 -0
  21. package/dist/cjs/components/PlayerErrorBoundary.js.map +1 -0
  22. package/dist/cjs/components/SeekBar.js +253 -0
  23. package/dist/cjs/components/SeekBar.js.map +1 -0
  24. package/dist/cjs/components/SkipIndicator.js +92 -0
  25. package/dist/cjs/components/SkipIndicator.js.map +1 -0
  26. package/dist/cjs/components/SpeedIndicator.js +43 -0
  27. package/dist/cjs/components/SpeedIndicator.js.map +1 -0
  28. package/dist/cjs/components/StatsPanel.js +202 -0
  29. package/dist/cjs/components/StatsPanel.js.map +1 -0
  30. package/dist/cjs/components/StreamStateOverlay.js +229 -0
  31. package/dist/cjs/components/StreamStateOverlay.js.map +1 -0
  32. package/dist/cjs/components/ThumbnailOverlay.js +86 -0
  33. package/dist/cjs/components/ThumbnailOverlay.js.map +1 -0
  34. package/dist/cjs/components/TitleOverlay.js +32 -0
  35. package/dist/cjs/components/TitleOverlay.js.map +1 -0
  36. package/dist/cjs/context/PlayerContext.js +46 -0
  37. package/dist/cjs/context/PlayerContext.js.map +1 -0
  38. package/dist/cjs/hooks/useMetaTrack.js +165 -0
  39. package/dist/cjs/hooks/useMetaTrack.js.map +1 -0
  40. package/dist/cjs/hooks/usePlaybackQuality.js +131 -0
  41. package/dist/cjs/hooks/usePlaybackQuality.js.map +1 -0
  42. package/dist/cjs/hooks/usePlayerController.js +518 -0
  43. package/dist/cjs/hooks/usePlayerController.js.map +1 -0
  44. package/dist/cjs/hooks/usePlayerSelection.js +90 -0
  45. package/dist/cjs/hooks/usePlayerSelection.js.map +1 -0
  46. package/dist/cjs/hooks/useStreamState.js +360 -0
  47. package/dist/cjs/hooks/useStreamState.js.map +1 -0
  48. package/dist/cjs/hooks/useTelemetry.js +120 -0
  49. package/dist/cjs/hooks/useTelemetry.js.map +1 -0
  50. package/dist/cjs/hooks/useViewerEndpoints.js +222 -0
  51. package/dist/cjs/hooks/useViewerEndpoints.js.map +1 -0
  52. package/dist/cjs/index.js +97 -1
  53. package/dist/cjs/index.js.map +1 -1
  54. package/dist/cjs/ui/badge.js +34 -0
  55. package/dist/cjs/ui/badge.js.map +1 -0
  56. package/dist/cjs/ui/button.js +74 -0
  57. package/dist/cjs/ui/button.js.map +1 -0
  58. package/dist/cjs/ui/context-menu.js +163 -0
  59. package/dist/cjs/ui/context-menu.js.map +1 -0
  60. package/dist/cjs/ui/slider.js +60 -0
  61. package/dist/cjs/ui/slider.js.map +1 -0
  62. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  63. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  64. package/dist/esm/assets/logomark.svg.js +4 -0
  65. package/dist/esm/assets/logomark.svg.js.map +1 -0
  66. package/dist/esm/components/DevModePanel.js +822 -0
  67. package/dist/esm/components/DevModePanel.js.map +1 -0
  68. package/dist/esm/components/DvdLogo.js +196 -0
  69. package/dist/esm/components/DvdLogo.js.map +1 -0
  70. package/dist/esm/components/Icons.js +421 -0
  71. package/dist/esm/components/Icons.js.map +1 -0
  72. package/dist/esm/components/IdleScreen.js +582 -0
  73. package/dist/esm/components/IdleScreen.js.map +1 -0
  74. package/dist/esm/components/LoadingScreen.js +519 -0
  75. package/dist/esm/components/LoadingScreen.js.map +1 -0
  76. package/dist/esm/components/Player.js +416 -0
  77. package/dist/esm/components/Player.js.map +1 -0
  78. package/dist/esm/components/PlayerControls.js +794 -0
  79. package/dist/esm/components/PlayerControls.js.map +1 -0
  80. package/dist/esm/components/PlayerErrorBoundary.js +76 -0
  81. package/dist/esm/components/PlayerErrorBoundary.js.map +1 -0
  82. package/dist/esm/components/SeekBar.js +249 -0
  83. package/dist/esm/components/SeekBar.js.map +1 -0
  84. package/dist/esm/components/SkipIndicator.js +88 -0
  85. package/dist/esm/components/SkipIndicator.js.map +1 -0
  86. package/dist/esm/components/SpeedIndicator.js +39 -0
  87. package/dist/esm/components/SpeedIndicator.js.map +1 -0
  88. package/dist/esm/components/StatsPanel.js +198 -0
  89. package/dist/esm/components/StatsPanel.js.map +1 -0
  90. package/dist/esm/components/StreamStateOverlay.js +224 -0
  91. package/dist/esm/components/StreamStateOverlay.js.map +1 -0
  92. package/dist/esm/components/ThumbnailOverlay.js +82 -0
  93. package/dist/esm/components/ThumbnailOverlay.js.map +1 -0
  94. package/dist/esm/components/TitleOverlay.js +28 -0
  95. package/dist/esm/components/TitleOverlay.js.map +1 -0
  96. package/dist/esm/context/PlayerContext.js +41 -0
  97. package/dist/esm/context/PlayerContext.js.map +1 -0
  98. package/dist/esm/hooks/useMetaTrack.js +163 -0
  99. package/dist/esm/hooks/useMetaTrack.js.map +1 -0
  100. package/dist/esm/hooks/usePlaybackQuality.js +129 -0
  101. package/dist/esm/hooks/usePlaybackQuality.js.map +1 -0
  102. package/dist/esm/hooks/usePlayerController.js +516 -0
  103. package/dist/esm/hooks/usePlayerController.js.map +1 -0
  104. package/dist/esm/hooks/usePlayerSelection.js +88 -0
  105. package/dist/esm/hooks/usePlayerSelection.js.map +1 -0
  106. package/dist/esm/hooks/useStreamState.js +358 -0
  107. package/dist/esm/hooks/useStreamState.js.map +1 -0
  108. package/dist/esm/hooks/useTelemetry.js +118 -0
  109. package/dist/esm/hooks/useTelemetry.js.map +1 -0
  110. package/dist/esm/hooks/useViewerEndpoints.js +220 -0
  111. package/dist/esm/hooks/useViewerEndpoints.js.map +1 -0
  112. package/dist/esm/index.js +23 -1
  113. package/dist/esm/index.js.map +1 -1
  114. package/dist/esm/ui/badge.js +31 -0
  115. package/dist/esm/ui/badge.js.map +1 -0
  116. package/dist/esm/ui/button.js +52 -0
  117. package/dist/esm/ui/button.js.map +1 -0
  118. package/dist/esm/ui/context-menu.js +132 -0
  119. package/dist/esm/ui/context-menu.js.map +1 -0
  120. package/dist/esm/ui/slider.js +38 -0
  121. package/dist/esm/ui/slider.js.map +1 -0
  122. package/dist/types/components/DvdLogo.d.ts +1 -1
  123. package/dist/types/components/Icons.d.ts +1 -1
  124. package/dist/types/components/Player.d.ts +1 -1
  125. package/dist/types/components/PlayerErrorBoundary.d.ts +2 -1
  126. package/dist/types/components/StreamStateOverlay.d.ts +2 -2
  127. package/dist/types/components/SubtitleRenderer.d.ts +2 -2
  128. package/dist/types/context/PlayerContext.d.ts +2 -2
  129. package/dist/types/context/index.d.ts +2 -2
  130. package/dist/types/hooks/useMetaTrack.d.ts +3 -3
  131. package/dist/types/hooks/usePlaybackQuality.d.ts +2 -2
  132. package/dist/types/hooks/usePlayerController.d.ts +26 -3
  133. package/dist/types/hooks/usePlayerSelection.d.ts +1 -1
  134. package/dist/types/hooks/useStreamState.d.ts +1 -1
  135. package/dist/types/hooks/useTelemetry.d.ts +1 -1
  136. package/dist/types/hooks/useViewerEndpoints.d.ts +3 -3
  137. package/dist/types/index.d.ts +28 -28
  138. package/dist/types/types.d.ts +3 -3
  139. package/dist/types/ui/select.d.ts +1 -1
  140. package/package.json +22 -14
  141. package/src/components/DevModePanel.tsx +244 -143
  142. package/src/components/DvdLogo.tsx +1 -1
  143. package/src/components/Icons.tsx +105 -25
  144. package/src/components/IdleScreen.tsx +262 -128
  145. package/src/components/LoadingScreen.tsx +169 -151
  146. package/src/components/LogoOverlay.tsx +3 -6
  147. package/src/components/Player.tsx +126 -59
  148. package/src/components/PlayerControls.tsx +384 -272
  149. package/src/components/PlayerErrorBoundary.tsx +7 -13
  150. package/src/components/SeekBar.tsx +96 -88
  151. package/src/components/SkipIndicator.tsx +2 -12
  152. package/src/components/SpeedIndicator.tsx +2 -11
  153. package/src/components/StatsPanel.tsx +31 -22
  154. package/src/components/StreamStateOverlay.tsx +105 -49
  155. package/src/components/SubtitleRenderer.tsx +29 -29
  156. package/src/components/ThumbnailOverlay.tsx +5 -6
  157. package/src/components/TitleOverlay.tsx +2 -8
  158. package/src/context/PlayerContext.tsx +4 -8
  159. package/src/context/index.ts +3 -3
  160. package/src/hooks/useMetaTrack.ts +27 -27
  161. package/src/hooks/usePlaybackQuality.ts +3 -3
  162. package/src/hooks/usePlayerController.ts +246 -138
  163. package/src/hooks/usePlayerSelection.ts +6 -6
  164. package/src/hooks/useStreamState.ts +51 -56
  165. package/src/hooks/useTelemetry.ts +18 -3
  166. package/src/hooks/useViewerEndpoints.ts +34 -23
  167. package/src/index.tsx +36 -28
  168. package/src/types.ts +8 -8
  169. package/src/ui/badge.tsx +6 -5
  170. package/src/ui/button.tsx +9 -8
  171. package/src/ui/context-menu.tsx +42 -61
  172. package/src/ui/select.tsx +13 -7
  173. package/src/ui/slider.tsx +18 -29
  174. package/dist/types/components/players/DashJsPlayer.d.ts +0 -18
  175. package/dist/types/components/players/HlsJsPlayer.d.ts +0 -18
  176. package/dist/types/components/players/MewsWsPlayer/index.d.ts +0 -18
  177. package/dist/types/components/players/MistPlayer.d.ts +0 -20
  178. package/dist/types/components/players/MistWebRTCPlayer/index.d.ts +0 -20
  179. package/dist/types/components/players/NativePlayer.d.ts +0 -19
  180. package/dist/types/components/players/VideoJsPlayer.d.ts +0 -18
  181. package/src/components/players/DashJsPlayer.tsx +0 -56
  182. package/src/components/players/HlsJsPlayer.tsx +0 -56
  183. package/src/components/players/MewsWsPlayer/index.tsx +0 -56
  184. package/src/components/players/MistPlayer.tsx +0 -60
  185. package/src/components/players/MistWebRTCPlayer/index.tsx +0 -59
  186. package/src/components/players/NativePlayer.tsx +0 -58
  187. package/src/components/players/VideoJsPlayer.tsx +0 -56
@@ -0,0 +1,826 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var React = require('react');
8
+ var playerCore = require('@livepeer-frameworks/player-core');
9
+
10
+ /** Short labels for source types */
11
+ var SOURCE_TYPE_LABELS = {
12
+ "html5/application/vnd.apple.mpegurl": "HLS",
13
+ "dash/video/mp4": "DASH",
14
+ "html5/video/mp4": "MP4",
15
+ "html5/video/webm": "WebM",
16
+ whep: "WHEP",
17
+ "mist/html": "Mist",
18
+ "mist/legacy": "Auto",
19
+ "ws/video/mp4": "MEWS"
20
+ };
21
+ /**
22
+ * DevModePanel - Advanced Settings overlay for testing player configurations
23
+ * Similar to MistPlayer's skin: "dev" mode
24
+ */
25
+ var DevModePanel = function DevModePanel(_ref) {
26
+ var _playerStats$levels, _mistStreamInfo$meta, _mistStreamInfo$meta2;
27
+ var onSettingsChange = _ref.onSettingsChange,
28
+ _ref$playbackMode = _ref.playbackMode,
29
+ playbackMode = _ref$playbackMode === void 0 ? "auto" : _ref$playbackMode,
30
+ onModeChange = _ref.onModeChange,
31
+ onReload = _ref.onReload,
32
+ streamInfo = _ref.streamInfo,
33
+ mistStreamInfo = _ref.mistStreamInfo,
34
+ currentPlayer = _ref.currentPlayer,
35
+ currentSource = _ref.currentSource,
36
+ videoElement = _ref.videoElement,
37
+ protocol = _ref.protocol,
38
+ nodeId = _ref.nodeId;
39
+ _ref.isVisible;
40
+ var controlledIsOpen = _ref.isOpen,
41
+ onOpenChange = _ref.onOpenChange;
42
+ // Support both controlled and uncontrolled modes
43
+ var _useState = React.useState(false),
44
+ _useState2 = _rollupPluginBabelHelpers.slicedToArray(_useState, 2),
45
+ internalIsOpen = _useState2[0],
46
+ setInternalIsOpen = _useState2[1];
47
+ var isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen;
48
+ var setIsOpen = React.useCallback(function (value) {
49
+ if (onOpenChange) {
50
+ onOpenChange(value);
51
+ } else {
52
+ setInternalIsOpen(value);
53
+ }
54
+ }, [onOpenChange]);
55
+ var _useState3 = React.useState("config"),
56
+ _useState4 = _rollupPluginBabelHelpers.slicedToArray(_useState3, 2),
57
+ activeTab = _useState4[0],
58
+ setActiveTab = _useState4[1];
59
+ var _useState5 = React.useState(0),
60
+ _useState6 = _rollupPluginBabelHelpers.slicedToArray(_useState5, 2),
61
+ setCurrentComboIndex = _useState6[1];
62
+ var _useState7 = React.useState(null),
63
+ _useState8 = _rollupPluginBabelHelpers.slicedToArray(_useState7, 2),
64
+ hoveredComboIndex = _useState8[0],
65
+ setHoveredComboIndex = _useState8[1];
66
+ var _useState9 = React.useState(false),
67
+ _useState0 = _rollupPluginBabelHelpers.slicedToArray(_useState9, 2),
68
+ tooltipAbove = _useState0[0],
69
+ setTooltipAbove = _useState0[1];
70
+ var _useState1 = React.useState(false),
71
+ _useState10 = _rollupPluginBabelHelpers.slicedToArray(_useState1, 2),
72
+ showDisabledPlayers = _useState10[0],
73
+ setShowDisabledPlayers = _useState10[1];
74
+ var comboListRef = React.useRef(null);
75
+ // Quality monitoring for playback score
76
+ var qualityMonitorRef = React.useRef(null);
77
+ var _useState11 = React.useState(1.0),
78
+ _useState12 = _rollupPluginBabelHelpers.slicedToArray(_useState11, 2),
79
+ playbackScore = _useState12[0],
80
+ setPlaybackScore = _useState12[1];
81
+ var _useState13 = React.useState(100),
82
+ _useState14 = _rollupPluginBabelHelpers.slicedToArray(_useState13, 2),
83
+ qualityScore = _useState14[0],
84
+ setQualityScore = _useState14[1];
85
+ var _useState15 = React.useState(0),
86
+ _useState16 = _rollupPluginBabelHelpers.slicedToArray(_useState15, 2),
87
+ stallCount = _useState16[0],
88
+ setStallCount = _useState16[1];
89
+ var _useState17 = React.useState(0),
90
+ _useState18 = _rollupPluginBabelHelpers.slicedToArray(_useState17, 2),
91
+ frameDropRate = _useState18[0],
92
+ setFrameDropRate = _useState18[1];
93
+ // Player-specific stats (from getStats())
94
+ var _useState19 = React.useState(null),
95
+ _useState20 = _rollupPluginBabelHelpers.slicedToArray(_useState19, 2),
96
+ playerStats = _useState20[0],
97
+ setPlayerStats = _useState20[1];
98
+ var statsIntervalRef = React.useRef(null);
99
+ // Start/stop quality monitoring based on video element
100
+ React.useEffect(function () {
101
+ if (videoElement && isOpen) {
102
+ if (!qualityMonitorRef.current) {
103
+ qualityMonitorRef.current = new playerCore.QualityMonitor({
104
+ sampleInterval: 500,
105
+ onSample: function onSample(quality) {
106
+ setQualityScore(quality.score);
107
+ setStallCount(quality.stallCount);
108
+ setFrameDropRate(quality.frameDropRate);
109
+ // Get playback score from monitor
110
+ if (qualityMonitorRef.current) {
111
+ setPlaybackScore(qualityMonitorRef.current.getPlaybackScore());
112
+ }
113
+ }
114
+ });
115
+ }
116
+ qualityMonitorRef.current.start(videoElement);
117
+ }
118
+ return function () {
119
+ if (qualityMonitorRef.current) {
120
+ qualityMonitorRef.current.stop();
121
+ }
122
+ };
123
+ }, [videoElement, isOpen]);
124
+ // Poll player-specific stats when stats tab is open
125
+ React.useEffect(function () {
126
+ if (isOpen && activeTab === "stats") {
127
+ var pollStats = /*#__PURE__*/function () {
128
+ var _ref2 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee() {
129
+ var player, _stats;
130
+ return _rollupPluginBabelHelpers.regenerator().w(function (_context) {
131
+ while (1) switch (_context.p = _context.n) {
132
+ case 0:
133
+ _context.p = 0;
134
+ player = playerCore.globalPlayerManager.getCurrentPlayer();
135
+ if (!(player && player.getStats)) {
136
+ _context.n = 2;
137
+ break;
138
+ }
139
+ _context.n = 1;
140
+ return player.getStats();
141
+ case 1:
142
+ _stats = _context.v;
143
+ if (_stats) {
144
+ setPlayerStats(_stats);
145
+ }
146
+ case 2:
147
+ _context.n = 4;
148
+ break;
149
+ case 3:
150
+ _context.p = 3;
151
+ _context.v;
152
+ case 4:
153
+ return _context.a(2);
154
+ }
155
+ }, _callee, null, [[0, 3]]);
156
+ }));
157
+ return function pollStats() {
158
+ return _ref2.apply(this, arguments);
159
+ };
160
+ }();
161
+ // Poll immediately and then every 500ms
162
+ pollStats();
163
+ statsIntervalRef.current = setInterval(pollStats, 500);
164
+ return function () {
165
+ if (statsIntervalRef.current) {
166
+ clearInterval(statsIntervalRef.current);
167
+ statsIntervalRef.current = null;
168
+ }
169
+ };
170
+ }
171
+ }, [isOpen, activeTab]);
172
+ // Get all player-source combinations with scores (including incompatible)
173
+ // Uses cached results from PlayerManager - won't recompute if data unchanged
174
+ var allCombinations = React.useMemo(function () {
175
+ if (!streamInfo) return [];
176
+ try {
177
+ // getAllCombinations now includes all combos (compatible + incompatible)
178
+ // and uses content-based caching - won't spam on every render
179
+ return playerCore.globalPlayerManager.getAllCombinations(streamInfo, playbackMode);
180
+ } catch (_unused2) {
181
+ return [];
182
+ }
183
+ }, [streamInfo, playbackMode]);
184
+ // For backward compatibility (Next Option only cycles compatible)
185
+ var combinations = React.useMemo(function () {
186
+ return allCombinations.filter(function (c) {
187
+ return c.compatible;
188
+ });
189
+ }, [allCombinations]);
190
+ // Find current active combo index based on current player/source (in allCombinations)
191
+ var activeComboIndex = React.useMemo(function () {
192
+ if (!currentPlayer || !currentSource || allCombinations.length === 0) return -1;
193
+ return allCombinations.findIndex(function (c) {
194
+ return c.player === currentPlayer.shortname && c.sourceType === currentSource.type;
195
+ });
196
+ }, [currentPlayer, currentSource, allCombinations]);
197
+ // Find index in compatible-only list for Next Option cycling
198
+ var activeCompatibleIndex = React.useMemo(function () {
199
+ if (!currentPlayer || !currentSource || combinations.length === 0) return -1;
200
+ return combinations.findIndex(function (c) {
201
+ return c.player === currentPlayer.shortname && c.sourceType === currentSource.type;
202
+ });
203
+ }, [currentPlayer, currentSource, combinations]);
204
+ var handleReload = React.useCallback(function () {
205
+ // Just trigger reload - controller manages the state
206
+ onReload === null || onReload === void 0 || onReload();
207
+ }, [onReload]);
208
+ var handleNextCombo = React.useCallback(function () {
209
+ if (combinations.length === 0) return;
210
+ // Start from active combo or 0, then move to next (only cycles compatible)
211
+ var startIdx = activeCompatibleIndex >= 0 ? activeCompatibleIndex : -1;
212
+ var nextIdx = (startIdx + 1) % combinations.length;
213
+ var combo = combinations[nextIdx];
214
+ setCurrentComboIndex(nextIdx);
215
+ onSettingsChange({
216
+ forcePlayer: combo.player,
217
+ forceType: combo.sourceType,
218
+ forceSource: combo.sourceIndex
219
+ });
220
+ }, [combinations, activeCompatibleIndex, onSettingsChange]);
221
+ var handleSelectCombo = React.useCallback(function (index) {
222
+ var combo = allCombinations[index];
223
+ if (!combo) return;
224
+ // Allow selecting even incompatible combos in dev mode (for testing)
225
+ setCurrentComboIndex(index);
226
+ onSettingsChange({
227
+ forcePlayer: combo.player,
228
+ forceType: combo.sourceType,
229
+ forceSource: combo.sourceIndex
230
+ });
231
+ }, [allCombinations, onSettingsChange]);
232
+ // Video stats - poll periodically when stats tab is open
233
+ var _useState21 = React.useState(null),
234
+ _useState22 = _rollupPluginBabelHelpers.slicedToArray(_useState21, 2),
235
+ stats = _useState22[0],
236
+ setStats = _useState22[1];
237
+ React.useEffect(function () {
238
+ if (!isOpen || activeTab !== "stats") return;
239
+ var updateStats = function updateStats() {
240
+ // Get fresh video element from player manager
241
+ var player = playerCore.globalPlayerManager.getCurrentPlayer();
242
+ var v = (player === null || player === void 0 ? void 0 : player.getVideoElement()) || videoElement;
243
+ if (!v) {
244
+ setStats(null);
245
+ return;
246
+ }
247
+ setStats({
248
+ resolution: "".concat(v.videoWidth, "x").concat(v.videoHeight),
249
+ buffered: v.buffered.length > 0 ? (v.buffered.end(v.buffered.length - 1) - v.currentTime).toFixed(1) : "0",
250
+ playbackRate: v.playbackRate.toFixed(2),
251
+ currentTime: v.currentTime.toFixed(1),
252
+ duration: isFinite(v.duration) ? v.duration.toFixed(1) : "live",
253
+ readyState: v.readyState,
254
+ networkState: v.networkState
255
+ });
256
+ };
257
+ updateStats();
258
+ var interval = setInterval(updateStats, 500);
259
+ return function () {
260
+ return clearInterval(interval);
261
+ };
262
+ }, [isOpen, activeTab, videoElement]);
263
+ // Panel is only rendered when open (no floating toggle button)
264
+ if (!isOpen) {
265
+ return null;
266
+ }
267
+ return jsxRuntime.jsxs("div", {
268
+ className: "fw-dev-panel",
269
+ children: [jsxRuntime.jsxs("div", {
270
+ className: "fw-dev-header",
271
+ children: [jsxRuntime.jsx("button", {
272
+ type: "button",
273
+ onClick: function onClick() {
274
+ return setActiveTab("config");
275
+ },
276
+ className: playerCore.cn("fw-dev-tab", activeTab === "config" && "fw-dev-tab--active"),
277
+ children: "Config"
278
+ }), jsxRuntime.jsx("button", {
279
+ type: "button",
280
+ onClick: function onClick() {
281
+ return setActiveTab("stats");
282
+ },
283
+ className: playerCore.cn("fw-dev-tab", activeTab === "stats" && "fw-dev-tab--active"),
284
+ children: "Stats"
285
+ }), jsxRuntime.jsx("div", {
286
+ className: "fw-dev-spacer"
287
+ }), jsxRuntime.jsx("button", {
288
+ type: "button",
289
+ onClick: function onClick() {
290
+ return setIsOpen(false);
291
+ },
292
+ className: "fw-dev-close",
293
+ "aria-label": "Close dev mode panel",
294
+ children: jsxRuntime.jsx("svg", {
295
+ width: "12",
296
+ height: "12",
297
+ viewBox: "0 0 12 12",
298
+ fill: "none",
299
+ stroke: "currentColor",
300
+ strokeWidth: "1.5",
301
+ children: jsxRuntime.jsx("path", {
302
+ d: "M2 2l8 8M10 2l-8 8"
303
+ })
304
+ })
305
+ })]
306
+ }), activeTab === "config" && jsxRuntime.jsxs("div", {
307
+ ref: comboListRef,
308
+ className: "fw-dev-body",
309
+ children: [jsxRuntime.jsxs("div", {
310
+ className: "fw-dev-section",
311
+ children: [jsxRuntime.jsx("div", {
312
+ className: "fw-dev-label",
313
+ children: "Active"
314
+ }), jsxRuntime.jsxs("div", {
315
+ className: "fw-dev-value",
316
+ children: [(currentPlayer === null || currentPlayer === void 0 ? void 0 : currentPlayer.name) || "None", " ", jsxRuntime.jsx("span", {
317
+ className: "fw-dev-value-arrow",
318
+ children: "\u2192"
319
+ }), " ", SOURCE_TYPE_LABELS[(currentSource === null || currentSource === void 0 ? void 0 : currentSource.type) || ""] || (currentSource === null || currentSource === void 0 ? void 0 : currentSource.type) || "—"]
320
+ }), nodeId && jsxRuntime.jsxs("div", {
321
+ className: "fw-dev-value-muted",
322
+ children: ["Node: ", nodeId]
323
+ })]
324
+ }), jsxRuntime.jsxs("div", {
325
+ className: "fw-dev-section",
326
+ children: [jsxRuntime.jsx("div", {
327
+ className: "fw-dev-label",
328
+ children: "Playback Mode"
329
+ }), jsxRuntime.jsx("div", {
330
+ className: "fw-dev-mode-group",
331
+ children: ["auto", "low-latency", "quality"].map(function (mode) {
332
+ return jsxRuntime.jsx("button", {
333
+ type: "button",
334
+ onClick: function onClick() {
335
+ return onModeChange === null || onModeChange === void 0 ? void 0 : onModeChange(mode);
336
+ },
337
+ className: playerCore.cn("fw-dev-mode-btn", playbackMode === mode && "fw-dev-mode-btn--active"),
338
+ children: mode === "low-latency" ? "Low Lat" : mode.charAt(0).toUpperCase() + mode.slice(1)
339
+ }, mode);
340
+ })
341
+ }), jsxRuntime.jsxs("div", {
342
+ className: "fw-dev-mode-desc",
343
+ children: [playbackMode === "auto" && "Balanced: MP4/WS → WHEP → HLS", playbackMode === "low-latency" && "WHEP/WebRTC first (<1s delay)", playbackMode === "quality" && "MP4/WS first, HLS fallback"]
344
+ })]
345
+ }), jsxRuntime.jsxs("div", {
346
+ className: "fw-dev-actions",
347
+ children: [jsxRuntime.jsx("button", {
348
+ type: "button",
349
+ onClick: handleReload,
350
+ className: "fw-dev-action-btn",
351
+ children: "Reload"
352
+ }), jsxRuntime.jsx("button", {
353
+ type: "button",
354
+ onClick: handleNextCombo,
355
+ className: "fw-dev-action-btn",
356
+ children: "Next Option"
357
+ })]
358
+ }), jsxRuntime.jsxs("div", {
359
+ className: "fw-dev-section",
360
+ style: {
361
+ padding: 0,
362
+ borderBottom: 0
363
+ },
364
+ children: [jsxRuntime.jsxs("div", {
365
+ className: "fw-dev-list-header",
366
+ children: [jsxRuntime.jsxs("span", {
367
+ className: "fw-dev-list-title",
368
+ children: ["Player Options (", combinations.length, ")"]
369
+ }), allCombinations.length > combinations.length && jsxRuntime.jsxs("button", {
370
+ type: "button",
371
+ onClick: function onClick() {
372
+ return setShowDisabledPlayers(!showDisabledPlayers);
373
+ },
374
+ className: "fw-dev-list-toggle",
375
+ children: [jsxRuntime.jsx("svg", {
376
+ width: "10",
377
+ height: "10",
378
+ viewBox: "0 0 24 24",
379
+ fill: "none",
380
+ stroke: "currentColor",
381
+ strokeWidth: "2",
382
+ className: playerCore.cn("fw-dev-chevron", showDisabledPlayers && "fw-dev-chevron--open"),
383
+ children: jsxRuntime.jsx("path", {
384
+ d: "M6 9l6 6 6-6"
385
+ })
386
+ }), showDisabledPlayers ? "Hide" : "Show", " disabled (", allCombinations.length - combinations.length, ")"]
387
+ })]
388
+ }), allCombinations.length === 0 ? jsxRuntime.jsx("div", {
389
+ className: "fw-dev-list-empty",
390
+ children: "No stream info available"
391
+ }) : jsxRuntime.jsx("div", {
392
+ children: allCombinations.map(function (combo, index) {
393
+ var _combo$scoreBreakdown, _combo$scoreBreakdown2, _combo$scoreBreakdown3, _combo$scoreBreakdown4;
394
+ // Codec-incompatible items always show (with warning), MIME-incompatible hide in "disabled"
395
+ var isCodecIncompat = combo.codecIncompatible === true;
396
+ if (!combo.compatible && !isCodecIncompat && !showDisabledPlayers) return null;
397
+ var isActive = activeComboIndex === index;
398
+ var typeLabel = SOURCE_TYPE_LABELS[combo.sourceType] || combo.sourceType.split("/").pop();
399
+ // Determine score class
400
+ var getScoreClass = function getScoreClass() {
401
+ if (!combo.compatible && !isCodecIncompat) return "fw-dev-combo-score--disabled";
402
+ if (isCodecIncompat) return "fw-dev-combo-score--low";
403
+ if (combo.score >= 2) return "fw-dev-combo-score--high";
404
+ if (combo.score >= 1.5) return "fw-dev-combo-score--mid";
405
+ return "fw-dev-combo-score--low";
406
+ };
407
+ // Determine rank class
408
+ var getRankClass = function getRankClass() {
409
+ if (isActive) return "fw-dev-combo-rank--active";
410
+ if (!combo.compatible && !isCodecIncompat) return "fw-dev-combo-rank--disabled";
411
+ if (isCodecIncompat) return "fw-dev-combo-rank--warn";
412
+ return "";
413
+ };
414
+ // Determine type class
415
+ var getTypeClass = function getTypeClass() {
416
+ if (!combo.compatible && !isCodecIncompat) return "fw-dev-combo-type--disabled";
417
+ if (isCodecIncompat) return "fw-dev-combo-type--warn";
418
+ return "";
419
+ };
420
+ return jsxRuntime.jsxs("div", {
421
+ onMouseEnter: function onMouseEnter(e) {
422
+ setHoveredComboIndex(index);
423
+ if (comboListRef.current) {
424
+ var container = comboListRef.current;
425
+ var row = e.currentTarget;
426
+ var containerRect = container.getBoundingClientRect();
427
+ var rowRect = row.getBoundingClientRect();
428
+ var relativePosition = (rowRect.top - containerRect.top) / containerRect.height;
429
+ setTooltipAbove(relativePosition > 0.6);
430
+ }
431
+ },
432
+ onMouseLeave: function onMouseLeave() {
433
+ return setHoveredComboIndex(null);
434
+ },
435
+ className: "fw-dev-combo",
436
+ children: [jsxRuntime.jsxs("button", {
437
+ type: "button",
438
+ onClick: function onClick() {
439
+ return handleSelectCombo(index);
440
+ },
441
+ className: playerCore.cn("fw-dev-combo-btn", isActive && "fw-dev-combo-btn--active", !combo.compatible && !isCodecIncompat && "fw-dev-combo-btn--disabled", isCodecIncompat && "fw-dev-combo-btn--codec-warn"),
442
+ children: [jsxRuntime.jsx("span", {
443
+ className: playerCore.cn("fw-dev-combo-rank", getRankClass()),
444
+ children: combo.compatible ? index + 1 : isCodecIncompat ? "⚠" : "—"
445
+ }), jsxRuntime.jsxs("span", {
446
+ className: "fw-dev-combo-name",
447
+ children: [combo.playerName, " ", jsxRuntime.jsx("span", {
448
+ className: "fw-dev-combo-arrow",
449
+ children: "\u2192"
450
+ }), " ", jsxRuntime.jsx("span", {
451
+ className: playerCore.cn("fw-dev-combo-type", getTypeClass()),
452
+ children: typeLabel
453
+ })]
454
+ }), jsxRuntime.jsx("span", {
455
+ className: playerCore.cn("fw-dev-combo-score", getScoreClass()),
456
+ children: combo.score.toFixed(2)
457
+ })]
458
+ }), hoveredComboIndex === index && jsxRuntime.jsxs("div", {
459
+ className: playerCore.cn("fw-dev-tooltip", tooltipAbove ? "fw-dev-tooltip--above" : "fw-dev-tooltip--below"),
460
+ children: [jsxRuntime.jsxs("div", {
461
+ className: "fw-dev-tooltip-header",
462
+ children: [jsxRuntime.jsx("div", {
463
+ className: "fw-dev-tooltip-title",
464
+ children: combo.playerName
465
+ }), jsxRuntime.jsx("div", {
466
+ className: "fw-dev-tooltip-subtitle",
467
+ children: combo.sourceType
468
+ }), ((_combo$scoreBreakdown = combo.scoreBreakdown) === null || _combo$scoreBreakdown === void 0 ? void 0 : _combo$scoreBreakdown.trackTypes) && combo.scoreBreakdown.trackTypes.length > 0 && jsxRuntime.jsxs("div", {
469
+ className: "fw-dev-tooltip-tracks",
470
+ children: ["Tracks:", " ", jsxRuntime.jsx("span", {
471
+ className: "fw-dev-tooltip-value",
472
+ children: combo.scoreBreakdown.trackTypes.join(", ")
473
+ })]
474
+ })]
475
+ }), combo.compatible && combo.scoreBreakdown ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
476
+ children: [jsxRuntime.jsxs("div", {
477
+ className: "fw-dev-tooltip-score",
478
+ children: ["Score: ", combo.score.toFixed(2)]
479
+ }), jsxRuntime.jsxs("div", {
480
+ className: "fw-dev-tooltip-row",
481
+ children: ["Tracks [", combo.scoreBreakdown.trackTypes.join(", "), "]:", " ", jsxRuntime.jsx("span", {
482
+ className: "fw-dev-tooltip-value",
483
+ children: combo.scoreBreakdown.trackScore.toFixed(2)
484
+ }), " ", jsxRuntime.jsxs("span", {
485
+ className: "fw-dev-tooltip-weight",
486
+ children: ["x", combo.scoreBreakdown.weights.tracks]
487
+ })]
488
+ }), jsxRuntime.jsxs("div", {
489
+ className: "fw-dev-tooltip-row",
490
+ children: ["Priority:", " ", jsxRuntime.jsx("span", {
491
+ className: "fw-dev-tooltip-value",
492
+ children: combo.scoreBreakdown.priorityScore.toFixed(2)
493
+ }), " ", jsxRuntime.jsxs("span", {
494
+ className: "fw-dev-tooltip-weight",
495
+ children: ["x", combo.scoreBreakdown.weights.priority]
496
+ })]
497
+ }), jsxRuntime.jsxs("div", {
498
+ className: "fw-dev-tooltip-row",
499
+ children: ["Source:", " ", jsxRuntime.jsx("span", {
500
+ className: "fw-dev-tooltip-value",
501
+ children: combo.scoreBreakdown.sourceScore.toFixed(2)
502
+ }), " ", jsxRuntime.jsxs("span", {
503
+ className: "fw-dev-tooltip-weight",
504
+ children: ["x", combo.scoreBreakdown.weights.source]
505
+ })]
506
+ }), combo.scoreBreakdown.reliabilityScore !== undefined && jsxRuntime.jsxs("div", {
507
+ className: "fw-dev-tooltip-row",
508
+ children: ["Reliability:", " ", jsxRuntime.jsx("span", {
509
+ className: "fw-dev-tooltip-value",
510
+ children: combo.scoreBreakdown.reliabilityScore.toFixed(2)
511
+ }), " ", jsxRuntime.jsxs("span", {
512
+ className: "fw-dev-tooltip-weight",
513
+ children: ["x", (_combo$scoreBreakdown2 = combo.scoreBreakdown.weights.reliability) !== null && _combo$scoreBreakdown2 !== void 0 ? _combo$scoreBreakdown2 : 0]
514
+ })]
515
+ }), combo.scoreBreakdown.modeBonus !== undefined && combo.scoreBreakdown.modeBonus !== 0 && jsxRuntime.jsxs("div", {
516
+ className: "fw-dev-tooltip-row",
517
+ children: ["Mode (", playbackMode, "):", " ", jsxRuntime.jsxs("span", {
518
+ className: "fw-dev-tooltip-bonus",
519
+ children: ["+", combo.scoreBreakdown.modeBonus.toFixed(2)]
520
+ }), " ", jsxRuntime.jsxs("span", {
521
+ className: "fw-dev-tooltip-weight",
522
+ children: ["x", (_combo$scoreBreakdown3 = combo.scoreBreakdown.weights.mode) !== null && _combo$scoreBreakdown3 !== void 0 ? _combo$scoreBreakdown3 : 0]
523
+ })]
524
+ }), combo.scoreBreakdown.routingBonus !== undefined && combo.scoreBreakdown.routingBonus !== 0 && jsxRuntime.jsxs("div", {
525
+ className: "fw-dev-tooltip-row",
526
+ children: ["Routing:", " ", jsxRuntime.jsxs("span", {
527
+ className: combo.scoreBreakdown.routingBonus > 0 ? "fw-dev-tooltip-bonus" : "fw-dev-tooltip-penalty",
528
+ children: [combo.scoreBreakdown.routingBonus > 0 ? "+" : "", combo.scoreBreakdown.routingBonus.toFixed(2)]
529
+ }), " ", jsxRuntime.jsxs("span", {
530
+ className: "fw-dev-tooltip-weight",
531
+ children: ["x", (_combo$scoreBreakdown4 = combo.scoreBreakdown.weights.routing) !== null && _combo$scoreBreakdown4 !== void 0 ? _combo$scoreBreakdown4 : 0]
532
+ })]
533
+ })]
534
+ }) : jsxRuntime.jsx("div", {
535
+ className: "fw-dev-tooltip-error",
536
+ children: combo.incompatibleReason || "Incompatible"
537
+ })]
538
+ })]
539
+ }, "".concat(combo.player, "-").concat(combo.sourceType));
540
+ })
541
+ })]
542
+ })]
543
+ }), activeTab === "stats" && jsxRuntime.jsxs("div", {
544
+ className: "fw-dev-body",
545
+ children: [jsxRuntime.jsxs("div", {
546
+ className: "fw-dev-section",
547
+ children: [jsxRuntime.jsx("div", {
548
+ className: "fw-dev-label",
549
+ children: "Playback Rate"
550
+ }), jsxRuntime.jsxs("div", {
551
+ className: "fw-dev-rate",
552
+ children: [jsxRuntime.jsxs("div", {
553
+ className: playerCore.cn("fw-dev-rate-value", playbackScore >= 0.95 && playbackScore <= 1.05 ? "fw-dev-stat-value--good" : playbackScore > 1.05 ? "fw-dev-stat-value--accent" : playbackScore >= 0.75 ? "fw-dev-stat-value--warn" : "fw-dev-stat-value--bad"),
554
+ children: [playbackScore.toFixed(2), "\xD7"]
555
+ }), jsxRuntime.jsx("div", {
556
+ className: "fw-dev-rate-status",
557
+ children: playbackScore >= 0.95 && playbackScore <= 1.05 ? "realtime" : playbackScore > 1.05 ? "catching up" : playbackScore >= 0.75 ? "slightly slow" : "stalling"
558
+ })]
559
+ }), jsxRuntime.jsxs("div", {
560
+ className: "fw-dev-rate-stats",
561
+ children: [jsxRuntime.jsxs("span", {
562
+ className: qualityScore >= 75 ? "fw-dev-stat-value--good" : "fw-dev-stat-value--bad",
563
+ children: ["Quality: ", qualityScore, "/100"]
564
+ }), jsxRuntime.jsxs("span", {
565
+ className: stallCount === 0 ? "fw-dev-stat-value--good" : "fw-dev-stat-value--warn",
566
+ children: ["Stalls: ", stallCount]
567
+ }), jsxRuntime.jsxs("span", {
568
+ className: frameDropRate < 1 ? "fw-dev-stat-value--good" : "fw-dev-stat-value--bad",
569
+ children: ["Drops: ", frameDropRate.toFixed(1), "%"]
570
+ })]
571
+ })]
572
+ }), stats ? jsxRuntime.jsxs("div", {
573
+ children: [jsxRuntime.jsxs("div", {
574
+ className: "fw-dev-stat",
575
+ children: [jsxRuntime.jsx("span", {
576
+ className: "fw-dev-stat-label",
577
+ children: "Resolution"
578
+ }), jsxRuntime.jsx("span", {
579
+ className: "fw-dev-stat-value",
580
+ children: stats.resolution
581
+ })]
582
+ }), jsxRuntime.jsxs("div", {
583
+ className: "fw-dev-stat",
584
+ children: [jsxRuntime.jsx("span", {
585
+ className: "fw-dev-stat-label",
586
+ children: "Buffer"
587
+ }), jsxRuntime.jsxs("span", {
588
+ className: "fw-dev-stat-value",
589
+ children: [stats.buffered, "s"]
590
+ })]
591
+ }), jsxRuntime.jsxs("div", {
592
+ className: "fw-dev-stat",
593
+ children: [jsxRuntime.jsx("span", {
594
+ className: "fw-dev-stat-label",
595
+ children: "Playback Rate"
596
+ }), jsxRuntime.jsxs("span", {
597
+ className: "fw-dev-stat-value",
598
+ children: [stats.playbackRate, "x"]
599
+ })]
600
+ }), jsxRuntime.jsxs("div", {
601
+ className: "fw-dev-stat",
602
+ children: [jsxRuntime.jsx("span", {
603
+ className: "fw-dev-stat-label",
604
+ children: "Time"
605
+ }), jsxRuntime.jsxs("span", {
606
+ className: "fw-dev-stat-value",
607
+ children: [stats.currentTime, " / ", stats.duration]
608
+ })]
609
+ }), jsxRuntime.jsxs("div", {
610
+ className: "fw-dev-stat",
611
+ children: [jsxRuntime.jsx("span", {
612
+ className: "fw-dev-stat-label",
613
+ children: "Ready State"
614
+ }), jsxRuntime.jsx("span", {
615
+ className: "fw-dev-stat-value",
616
+ children: stats.readyState
617
+ })]
618
+ }), jsxRuntime.jsxs("div", {
619
+ className: "fw-dev-stat",
620
+ children: [jsxRuntime.jsx("span", {
621
+ className: "fw-dev-stat-label",
622
+ children: "Network State"
623
+ }), jsxRuntime.jsx("span", {
624
+ className: "fw-dev-stat-value",
625
+ children: stats.networkState
626
+ })]
627
+ }), protocol && jsxRuntime.jsxs("div", {
628
+ className: "fw-dev-stat",
629
+ children: [jsxRuntime.jsx("span", {
630
+ className: "fw-dev-stat-label",
631
+ children: "Protocol"
632
+ }), jsxRuntime.jsx("span", {
633
+ className: "fw-dev-stat-value",
634
+ children: protocol
635
+ })]
636
+ }), nodeId && jsxRuntime.jsxs("div", {
637
+ className: "fw-dev-stat",
638
+ children: [jsxRuntime.jsx("span", {
639
+ className: "fw-dev-stat-label",
640
+ children: "Node ID"
641
+ }), jsxRuntime.jsx("span", {
642
+ className: "fw-dev-stat-value truncate",
643
+ style: {
644
+ maxWidth: "150px"
645
+ },
646
+ children: nodeId
647
+ })]
648
+ })]
649
+ }) : jsxRuntime.jsx("div", {
650
+ className: "fw-dev-list-empty",
651
+ children: "No video element available"
652
+ }), playerStats && jsxRuntime.jsxs("div", {
653
+ children: [jsxRuntime.jsx("div", {
654
+ className: "fw-dev-list-header fw-dev-section-header",
655
+ children: jsxRuntime.jsx("span", {
656
+ className: "fw-dev-list-title",
657
+ children: playerStats.type === "hls" ? "HLS.js Stats" : playerStats.type === "webrtc" ? "WebRTC Stats" : "Player Stats"
658
+ })
659
+ }), playerStats.type === "hls" && jsxRuntime.jsxs(jsxRuntime.Fragment, {
660
+ children: [jsxRuntime.jsxs("div", {
661
+ className: "fw-dev-stat",
662
+ children: [jsxRuntime.jsx("span", {
663
+ className: "fw-dev-stat-label",
664
+ children: "Bitrate"
665
+ }), jsxRuntime.jsx("span", {
666
+ className: "fw-dev-stat-value--accent",
667
+ children: playerStats.currentBitrate > 0 ? "".concat(Math.round(playerStats.currentBitrate / 1000), " kbps") : "N/A"
668
+ })]
669
+ }), jsxRuntime.jsxs("div", {
670
+ className: "fw-dev-stat",
671
+ children: [jsxRuntime.jsx("span", {
672
+ className: "fw-dev-stat-label",
673
+ children: "Bandwidth Est."
674
+ }), jsxRuntime.jsx("span", {
675
+ className: "fw-dev-stat-value",
676
+ children: playerStats.bandwidthEstimate > 0 ? "".concat(Math.round(playerStats.bandwidthEstimate / 1000), " kbps") : "N/A"
677
+ })]
678
+ }), jsxRuntime.jsxs("div", {
679
+ className: "fw-dev-stat",
680
+ children: [jsxRuntime.jsx("span", {
681
+ className: "fw-dev-stat-label",
682
+ children: "Level"
683
+ }), jsxRuntime.jsxs("span", {
684
+ className: "fw-dev-stat-value",
685
+ children: [playerStats.currentLevel >= 0 ? playerStats.currentLevel : "Auto", " /", " ", ((_playerStats$levels = playerStats.levels) === null || _playerStats$levels === void 0 ? void 0 : _playerStats$levels.length) || 0]
686
+ })]
687
+ }), playerStats.latency !== undefined && jsxRuntime.jsxs("div", {
688
+ className: "fw-dev-stat",
689
+ children: [jsxRuntime.jsx("span", {
690
+ className: "fw-dev-stat-label",
691
+ children: "Latency"
692
+ }), jsxRuntime.jsxs("span", {
693
+ className: playerStats.latency > 5000 ? "fw-dev-stat-value--warn" : "fw-dev-stat-value",
694
+ children: [Math.round(playerStats.latency), " ms"]
695
+ })]
696
+ })]
697
+ }), playerStats.type === "webrtc" && jsxRuntime.jsxs(jsxRuntime.Fragment, {
698
+ children: [playerStats.video && jsxRuntime.jsxs(jsxRuntime.Fragment, {
699
+ children: [jsxRuntime.jsxs("div", {
700
+ className: "fw-dev-stat",
701
+ children: [jsxRuntime.jsx("span", {
702
+ className: "fw-dev-stat-label",
703
+ children: "Video Bitrate"
704
+ }), jsxRuntime.jsx("span", {
705
+ className: "fw-dev-stat-value--accent",
706
+ children: playerStats.video.bitrate > 0 ? "".concat(Math.round(playerStats.video.bitrate / 1000), " kbps") : "N/A"
707
+ })]
708
+ }), jsxRuntime.jsxs("div", {
709
+ className: "fw-dev-stat",
710
+ children: [jsxRuntime.jsx("span", {
711
+ className: "fw-dev-stat-label",
712
+ children: "FPS"
713
+ }), jsxRuntime.jsx("span", {
714
+ className: "fw-dev-stat-value",
715
+ children: Math.round(playerStats.video.framesPerSecond || 0)
716
+ })]
717
+ }), jsxRuntime.jsxs("div", {
718
+ className: "fw-dev-stat",
719
+ children: [jsxRuntime.jsx("span", {
720
+ className: "fw-dev-stat-label",
721
+ children: "Frames"
722
+ }), jsxRuntime.jsxs("span", {
723
+ className: "fw-dev-stat-value",
724
+ children: [playerStats.video.framesDecoded, " decoded,", " ", jsxRuntime.jsxs("span", {
725
+ className: playerStats.video.frameDropRate > 1 ? "fw-dev-stat-value--bad" : "fw-dev-stat-value--good",
726
+ children: [playerStats.video.framesDropped, " dropped"]
727
+ })]
728
+ })]
729
+ }), jsxRuntime.jsxs("div", {
730
+ className: "fw-dev-stat",
731
+ children: [jsxRuntime.jsx("span", {
732
+ className: "fw-dev-stat-label",
733
+ children: "Packet Loss"
734
+ }), jsxRuntime.jsxs("span", {
735
+ className: playerStats.video.packetLossRate > 1 ? "fw-dev-stat-value--bad" : "fw-dev-stat-value--good",
736
+ children: [playerStats.video.packetLossRate.toFixed(2), "%"]
737
+ })]
738
+ }), jsxRuntime.jsxs("div", {
739
+ className: "fw-dev-stat",
740
+ children: [jsxRuntime.jsx("span", {
741
+ className: "fw-dev-stat-label",
742
+ children: "Jitter"
743
+ }), jsxRuntime.jsxs("span", {
744
+ className: playerStats.video.jitter > 30 ? "fw-dev-stat-value--warn" : "fw-dev-stat-value",
745
+ children: [playerStats.video.jitter.toFixed(1), " ms"]
746
+ })]
747
+ }), jsxRuntime.jsxs("div", {
748
+ className: "fw-dev-stat",
749
+ children: [jsxRuntime.jsx("span", {
750
+ className: "fw-dev-stat-label",
751
+ children: "Jitter Buffer"
752
+ }), jsxRuntime.jsxs("span", {
753
+ className: "fw-dev-stat-value",
754
+ children: [playerStats.video.jitterBufferDelay.toFixed(1), " ms"]
755
+ })]
756
+ })]
757
+ }), playerStats.network && jsxRuntime.jsxs("div", {
758
+ className: "fw-dev-stat",
759
+ children: [jsxRuntime.jsx("span", {
760
+ className: "fw-dev-stat-label",
761
+ children: "RTT"
762
+ }), jsxRuntime.jsxs("span", {
763
+ className: playerStats.network.rtt > 200 ? "fw-dev-stat-value--warn" : "fw-dev-stat-value",
764
+ children: [Math.round(playerStats.network.rtt), " ms"]
765
+ })]
766
+ })]
767
+ })]
768
+ }), (mistStreamInfo === null || mistStreamInfo === void 0 || (_mistStreamInfo$meta = mistStreamInfo.meta) === null || _mistStreamInfo$meta === void 0 ? void 0 : _mistStreamInfo$meta.tracks) && Object.keys(mistStreamInfo.meta.tracks).length > 0 && jsxRuntime.jsxs("div", {
769
+ children: [jsxRuntime.jsx("div", {
770
+ className: "fw-dev-list-header fw-dev-section-header",
771
+ children: jsxRuntime.jsxs("span", {
772
+ className: "fw-dev-list-title",
773
+ children: ["Tracks (", Object.keys(mistStreamInfo.meta.tracks).length, ")"]
774
+ })
775
+ }), Object.entries(mistStreamInfo.meta.tracks).map(function (_ref3) {
776
+ var _ref4 = _rollupPluginBabelHelpers.slicedToArray(_ref3, 2),
777
+ id = _ref4[0],
778
+ track = _ref4[1];
779
+ return jsxRuntime.jsxs("div", {
780
+ className: "fw-dev-track",
781
+ children: [jsxRuntime.jsxs("div", {
782
+ className: "fw-dev-track-header",
783
+ children: [jsxRuntime.jsx("span", {
784
+ className: playerCore.cn("fw-dev-track-badge", track.type === "video" ? "fw-dev-track-badge--video" : track.type === "audio" ? "fw-dev-track-badge--audio" : "fw-dev-track-badge--other"),
785
+ children: track.type
786
+ }), jsxRuntime.jsx("span", {
787
+ className: "fw-dev-track-codec",
788
+ children: track.codec
789
+ }), jsxRuntime.jsxs("span", {
790
+ className: "fw-dev-track-id",
791
+ children: ["#", id]
792
+ })]
793
+ }), jsxRuntime.jsxs("div", {
794
+ className: "fw-dev-track-meta",
795
+ children: [track.type === "video" && track.width && track.height && jsxRuntime.jsxs("span", {
796
+ children: [track.width, "\xD7", track.height]
797
+ }), track.bps && jsxRuntime.jsxs("span", {
798
+ children: [Math.round(track.bps / 1000), " kbps"]
799
+ }), track.fpks && jsxRuntime.jsxs("span", {
800
+ children: [Math.round(track.fpks / 1000), " fps"]
801
+ }), track.type === "audio" && track.channels && jsxRuntime.jsxs("span", {
802
+ children: [track.channels, "ch"]
803
+ }), track.type === "audio" && track.rate && jsxRuntime.jsxs("span", {
804
+ children: [track.rate, " Hz"]
805
+ }), track.lang && jsxRuntime.jsx("span", {
806
+ children: track.lang
807
+ })]
808
+ })]
809
+ }, id);
810
+ })]
811
+ }), mistStreamInfo && (!((_mistStreamInfo$meta2 = mistStreamInfo.meta) !== null && _mistStreamInfo$meta2 !== void 0 && _mistStreamInfo$meta2.tracks) || Object.keys(mistStreamInfo.meta.tracks).length === 0) && jsxRuntime.jsx("div", {
812
+ className: "fw-dev-no-tracks",
813
+ children: jsxRuntime.jsxs("span", {
814
+ className: "fw-dev-no-tracks-text",
815
+ children: ["No track data available", mistStreamInfo.type && jsxRuntime.jsxs("span", {
816
+ className: "fw-dev-no-tracks-type",
817
+ children: ["(", mistStreamInfo.type, ")"]
818
+ })]
819
+ })
820
+ })]
821
+ })]
822
+ });
823
+ };
824
+
825
+ exports.default = DevModePanel;
826
+ //# sourceMappingURL=DevModePanel.js.map