artplayer-plugin-p2p 1.0.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.
@@ -0,0 +1,48 @@
1
+ export { B as BANDWIDTH_WINDOW_MS, D as DEFAULT_FATAL_RETRY_MAX, c as DEFAULT_TYPE, d as DownloadChannel, P as P2POptions, b as P2PPluginHandle, e as P2PSettingItemsOptions, f as P2PStats, a as P2PStatsEngine, g as P2PTrackerOptions, h as P2PUIOptions, i as P2P_EVENT_BRIDGE_MAP, S as STATS_POLLING_MS, j as StateChangeDetails, k as applyRuntimeToggle, m as mergeCoreConfig, r as resolveOptions } from './stats-CFbDXEsi.mjs';
2
+ export { CoreConfig, DynamicCoreConfig } from 'p2p-media-loader-core';
3
+ import 'p2p-media-loader-hlsjs';
4
+ import 'hls.js';
5
+
6
+ /**
7
+ * 滑动时间窗带宽计算器
8
+ *
9
+ * 纯逻辑实现:时间源可注入(timestampMs 参数),缺省取
10
+ * performance.now()(单调时钟,与 p2pml 官方带宽计算一致,
11
+ * 不受系统时钟跳变影响),测试可注入固定时间戳
12
+ *
13
+ * @module bandwidth
14
+ */
15
+ /**
16
+ * 滑动时间窗带宽计算器
17
+ *
18
+ * 每笔字节记录为独立样本,读取速率时惰性清理窗口外样本;
19
+ * 样本量与窗口内的 chunk 频次成正比(直播场景上限约数百个),无需主动压缩
20
+ */
21
+ declare class BandwidthCalculator {
22
+ #private;
23
+ /**
24
+ * @param windowMs - 滑动时间窗长度(毫秒),窗口越长速率越平滑
25
+ */
26
+ constructor(windowMs: number);
27
+ /**
28
+ * 记录一笔字节
29
+ *
30
+ * @param bytes - 字节数(非正值直接忽略,防御脏数据)
31
+ * @param timestampMs - 样本时间戳;缺省取 performance.now(),测试可注入固定时间
32
+ */
33
+ record(bytes: number, timestampMs?: number): void;
34
+ /**
35
+ * 计算窗口内平均速率
36
+ *
37
+ * 读取时惰性清理过期样本;速率按整个窗口长度折算而非
38
+ * 首尾样本间隔,保证窗口未填满时(刚启动)读数平滑趋近真实值
39
+ *
40
+ * @param nowMs - 当前时间戳;缺省取 performance.now(),测试可注入固定时间
41
+ * @returns 速率 B/s
42
+ */
43
+ getSpeed(nowMs?: number): number;
44
+ /** 清空全部样本 */
45
+ reset(): void;
46
+ }
47
+
48
+ export { BandwidthCalculator };
package/dist/pure.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ export { B as BANDWIDTH_WINDOW_MS, D as DEFAULT_FATAL_RETRY_MAX, c as DEFAULT_TYPE, d as DownloadChannel, P as P2POptions, b as P2PPluginHandle, e as P2PSettingItemsOptions, f as P2PStats, a as P2PStatsEngine, g as P2PTrackerOptions, h as P2PUIOptions, i as P2P_EVENT_BRIDGE_MAP, S as STATS_POLLING_MS, j as StateChangeDetails, k as applyRuntimeToggle, m as mergeCoreConfig, r as resolveOptions } from './stats-CFbDXEsi.js';
2
+ export { CoreConfig, DynamicCoreConfig } from 'p2p-media-loader-core';
3
+ import 'p2p-media-loader-hlsjs';
4
+ import 'hls.js';
5
+
6
+ /**
7
+ * 滑动时间窗带宽计算器
8
+ *
9
+ * 纯逻辑实现:时间源可注入(timestampMs 参数),缺省取
10
+ * performance.now()(单调时钟,与 p2pml 官方带宽计算一致,
11
+ * 不受系统时钟跳变影响),测试可注入固定时间戳
12
+ *
13
+ * @module bandwidth
14
+ */
15
+ /**
16
+ * 滑动时间窗带宽计算器
17
+ *
18
+ * 每笔字节记录为独立样本,读取速率时惰性清理窗口外样本;
19
+ * 样本量与窗口内的 chunk 频次成正比(直播场景上限约数百个),无需主动压缩
20
+ */
21
+ declare class BandwidthCalculator {
22
+ #private;
23
+ /**
24
+ * @param windowMs - 滑动时间窗长度(毫秒),窗口越长速率越平滑
25
+ */
26
+ constructor(windowMs: number);
27
+ /**
28
+ * 记录一笔字节
29
+ *
30
+ * @param bytes - 字节数(非正值直接忽略,防御脏数据)
31
+ * @param timestampMs - 样本时间戳;缺省取 performance.now(),测试可注入固定时间
32
+ */
33
+ record(bytes: number, timestampMs?: number): void;
34
+ /**
35
+ * 计算窗口内平均速率
36
+ *
37
+ * 读取时惰性清理过期样本;速率按整个窗口长度折算而非
38
+ * 首尾样本间隔,保证窗口未填满时(刚启动)读数平滑趋近真实值
39
+ *
40
+ * @param nowMs - 当前时间戳;缺省取 performance.now(),测试可注入固定时间
41
+ * @returns 速率 B/s
42
+ */
43
+ getSpeed(nowMs?: number): number;
44
+ /** 清空全部样本 */
45
+ reset(): void;
46
+ }
47
+
48
+ export { BandwidthCalculator };
package/dist/pure.js ADDED
@@ -0,0 +1,309 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __typeError = (msg) => {
7
+ throw TypeError(msg);
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
23
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
24
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
25
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
26
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
27
+
28
+ // src/pure.ts
29
+ var pure_exports = {};
30
+ __export(pure_exports, {
31
+ BANDWIDTH_WINDOW_MS: () => BANDWIDTH_WINDOW_MS,
32
+ BandwidthCalculator: () => BandwidthCalculator,
33
+ DEFAULT_FATAL_RETRY_MAX: () => DEFAULT_FATAL_RETRY_MAX,
34
+ DEFAULT_TYPE: () => DEFAULT_TYPE,
35
+ P2PStatsEngine: () => P2PStatsEngine,
36
+ P2P_EVENT_BRIDGE_MAP: () => P2P_EVENT_BRIDGE_MAP,
37
+ STATS_POLLING_MS: () => STATS_POLLING_MS,
38
+ applyRuntimeToggle: () => applyRuntimeToggle,
39
+ mergeCoreConfig: () => mergeCoreConfig,
40
+ resolveOptions: () => resolveOptions
41
+ });
42
+ module.exports = __toCommonJS(pure_exports);
43
+
44
+ // src/constants.ts
45
+ var DEFAULT_TYPE = "m3u8";
46
+ var DEFAULT_FATAL_RETRY_MAX = 2;
47
+ var BANDWIDTH_WINDOW_MS = 1e4;
48
+ var STATS_POLLING_MS = 1e3;
49
+ var P2P_EVENT_BRIDGE_MAP = {
50
+ onStreamAdded: "p2p:streamAdded",
51
+ onStreamRegistrationError: "p2p:streamRegistrationError",
52
+ onSegmentLoaded: "p2p:segmentLoaded",
53
+ onSegmentError: "p2p:segmentError",
54
+ onSegmentAbort: "p2p:segmentAbort",
55
+ onSegmentStart: "p2p:segmentStart",
56
+ onPeerConnect: "p2p:peerConnect",
57
+ onPeerConnectError: "p2p:peerConnectError",
58
+ onPeerClose: "p2p:peerClose",
59
+ onPeerError: "p2p:peerError",
60
+ onPeerWarning: "p2p:peerWarning",
61
+ onChunkDownloaded: "p2p:chunkDownloaded",
62
+ onChunkUploaded: "p2p:chunkUploaded",
63
+ onTrackerError: "p2p:trackerError",
64
+ onTrackerWarning: "p2p:trackerWarning"
65
+ };
66
+
67
+ // src/config.ts
68
+ function resolveUIOptions(ui) {
69
+ return ui.setting !== false;
70
+ }
71
+ function resolveSettingItems(setting) {
72
+ if (setting === void 0 || setting === true) {
73
+ return { p2pEnabled: true, uploadOnly: true, stats: true };
74
+ }
75
+ if (setting === false) {
76
+ return { p2pEnabled: false, uploadOnly: false, stats: false };
77
+ }
78
+ return {
79
+ p2pEnabled: setting.p2pEnabled ?? true,
80
+ uploadOnly: setting.uploadOnly ?? true,
81
+ stats: setting.stats ?? true
82
+ };
83
+ }
84
+ function resolveOptions(options) {
85
+ const uiEnabled = options.ui !== false;
86
+ let settingEnabled;
87
+ let settingItems;
88
+ if (typeof options.ui === "object" && options.ui !== null) {
89
+ settingEnabled = resolveUIOptions(options.ui);
90
+ settingItems = resolveSettingItems(options.ui.setting);
91
+ } else {
92
+ settingEnabled = uiEnabled;
93
+ settingItems = resolveSettingItems(uiEnabled ? void 0 : false);
94
+ }
95
+ return {
96
+ typeName: options.type ?? DEFAULT_TYPE,
97
+ fatalRetryMax: options.fatalRetryMax ?? DEFAULT_FATAL_RETRY_MAX,
98
+ p2pEnabled: options.enabled ?? true,
99
+ uploadEnabled: options.uploadEnabled ?? true,
100
+ uiEnabled,
101
+ statsEnabled: uiEnabled && options.stats !== false,
102
+ settingEnabled,
103
+ settingItems,
104
+ core: options.core,
105
+ tracker: options.tracker,
106
+ hls: options.hls
107
+ };
108
+ }
109
+ function mergeCoreConfig(options) {
110
+ return { ...options.core, ...options.tracker };
111
+ }
112
+ function applyRuntimeToggle(config, p2pEnabled, uploadEnabled) {
113
+ return {
114
+ ...config,
115
+ isP2PDisabled: !p2pEnabled,
116
+ isP2PUploadDisabled: !uploadEnabled
117
+ };
118
+ }
119
+
120
+ // src/bandwidth.ts
121
+ var _windowMs, _samples, _BandwidthCalculator_instances, removeExpired_fn;
122
+ var BandwidthCalculator = class {
123
+ /**
124
+ * @param windowMs - 滑动时间窗长度(毫秒),窗口越长速率越平滑
125
+ */
126
+ constructor(windowMs) {
127
+ __privateAdd(this, _BandwidthCalculator_instances);
128
+ __privateAdd(this, _windowMs);
129
+ __privateAdd(this, _samples, []);
130
+ __privateSet(this, _windowMs, windowMs);
131
+ }
132
+ /**
133
+ * 记录一笔字节
134
+ *
135
+ * @param bytes - 字节数(非正值直接忽略,防御脏数据)
136
+ * @param timestampMs - 样本时间戳;缺省取 performance.now(),测试可注入固定时间
137
+ */
138
+ record(bytes, timestampMs = performance.now()) {
139
+ if (bytes <= 0) return;
140
+ __privateGet(this, _samples).push({ timestampMs, bytes });
141
+ }
142
+ /**
143
+ * 计算窗口内平均速率
144
+ *
145
+ * 读取时惰性清理过期样本;速率按整个窗口长度折算而非
146
+ * 首尾样本间隔,保证窗口未填满时(刚启动)读数平滑趋近真实值
147
+ *
148
+ * @param nowMs - 当前时间戳;缺省取 performance.now(),测试可注入固定时间
149
+ * @returns 速率 B/s
150
+ */
151
+ getSpeed(nowMs = performance.now()) {
152
+ __privateMethod(this, _BandwidthCalculator_instances, removeExpired_fn).call(this, nowMs);
153
+ let totalBytes = 0;
154
+ for (const sample of __privateGet(this, _samples)) {
155
+ totalBytes += sample.bytes;
156
+ }
157
+ return totalBytes / (__privateGet(this, _windowMs) / 1e3);
158
+ }
159
+ /** 清空全部样本 */
160
+ reset() {
161
+ __privateGet(this, _samples).length = 0;
162
+ }
163
+ };
164
+ _windowMs = new WeakMap();
165
+ _samples = new WeakMap();
166
+ _BandwidthCalculator_instances = new WeakSet();
167
+ /**
168
+ * 移除窗口外的过期样本
169
+ *
170
+ * 样本时间戳单调递增(缺省时间源 performance.now 单调;
171
+ * 注入时间戳同样须单调),从头扫描至首个窗口内样本即可。
172
+ * 边界样本(age 恰等于窗口长)保留在窗口内,与 p2pml
173
+ * 官方带宽计算的过期判定语义保持一致
174
+ */
175
+ removeExpired_fn = function(nowMs) {
176
+ const cutoff = nowMs - __privateGet(this, _windowMs);
177
+ let firstValid = __privateGet(this, _samples).length;
178
+ for (let i = 0; i < __privateGet(this, _samples).length; i++) {
179
+ if (__privateGet(this, _samples)[i].timestampMs >= cutoff) {
180
+ firstValid = i;
181
+ break;
182
+ }
183
+ }
184
+ __privateGet(this, _samples).splice(0, firstValid);
185
+ };
186
+
187
+ // src/stats.ts
188
+ var _peers, _peakPeers, _p2pDownloadedBytes, _httpDownloadedBytes, _uploadedBytes, _downloadBandwidths, _uploadBandwidth;
189
+ var P2PStatsEngine = class {
190
+ constructor() {
191
+ __privateAdd(this, _peers, 0);
192
+ __privateAdd(this, _peakPeers, 0);
193
+ __privateAdd(this, _p2pDownloadedBytes, 0);
194
+ __privateAdd(this, _httpDownloadedBytes, 0);
195
+ __privateAdd(this, _uploadedBytes, 0);
196
+ __privateAdd(this, _downloadBandwidths, {
197
+ p2p: new BandwidthCalculator(BANDWIDTH_WINDOW_MS),
198
+ http: new BandwidthCalculator(BANDWIDTH_WINDOW_MS)
199
+ });
200
+ __privateAdd(this, _uploadBandwidth, new BandwidthCalculator(BANDWIDTH_WINDOW_MS));
201
+ }
202
+ /** 记录一个 peer 连接建立(同时维护峰值) */
203
+ recordPeerConnect() {
204
+ __privateSet(this, _peers, __privateGet(this, _peers) + 1);
205
+ if (__privateGet(this, _peers) > __privateGet(this, _peakPeers)) {
206
+ __privateSet(this, _peakPeers, __privateGet(this, _peers));
207
+ }
208
+ }
209
+ /** 记录一个 peer 连接断开(计数不小于零) */
210
+ recordPeerClose() {
211
+ if (__privateGet(this, _peers) > 0) {
212
+ __privateSet(this, _peers, __privateGet(this, _peers) - 1);
213
+ }
214
+ }
215
+ /**
216
+ * 记录一笔下行字节
217
+ *
218
+ * @param bytes - 字节数
219
+ * @param channel - 下载通道(http / p2p)
220
+ * @param timestampMs - 样本时间戳;缺省取 performance.now(),测试可注入固定时间
221
+ */
222
+ recordDownload(bytes, channel, timestampMs) {
223
+ if (bytes <= 0) return;
224
+ if (channel === "p2p") {
225
+ __privateSet(this, _p2pDownloadedBytes, __privateGet(this, _p2pDownloadedBytes) + bytes);
226
+ } else {
227
+ __privateSet(this, _httpDownloadedBytes, __privateGet(this, _httpDownloadedBytes) + bytes);
228
+ }
229
+ __privateGet(this, _downloadBandwidths)[channel].record(bytes, timestampMs);
230
+ }
231
+ /**
232
+ * 记录一笔 P2P 上行字节
233
+ *
234
+ * @param bytes - 字节数
235
+ * @param timestampMs - 样本时间戳;缺省取 performance.now(),测试可注入固定时间
236
+ */
237
+ recordUpload(bytes, timestampMs) {
238
+ if (bytes <= 0) return;
239
+ __privateSet(this, _uploadedBytes, __privateGet(this, _uploadedBytes) + bytes);
240
+ __privateGet(this, _uploadBandwidth).record(bytes, timestampMs);
241
+ }
242
+ /**
243
+ * 输出当前统计快照(累计量 + 派生指标一次算清)
244
+ *
245
+ * 带宽基准时间只取一次、每通道只计算一次,
246
+ * 保证快照内部指标自洽(downloadSpeed 恒等于两通道之和)
247
+ *
248
+ * @param nowMs - 带宽计算基准时间戳;缺省取 performance.now(),测试可注入固定时间
249
+ */
250
+ snapshot(nowMs) {
251
+ const totalDownloadedBytes = __privateGet(this, _p2pDownloadedBytes) + __privateGet(this, _httpDownloadedBytes);
252
+ const now = nowMs ?? performance.now();
253
+ const p2pDownloadSpeed = __privateGet(this, _downloadBandwidths).p2p.getSpeed(now);
254
+ const httpDownloadSpeed = __privateGet(this, _downloadBandwidths).http.getSpeed(now);
255
+ return {
256
+ peers: __privateGet(this, _peers),
257
+ peakPeers: __privateGet(this, _peakPeers),
258
+ p2pDownloadedBytes: __privateGet(this, _p2pDownloadedBytes),
259
+ httpDownloadedBytes: __privateGet(this, _httpDownloadedBytes),
260
+ uploadedBytes: __privateGet(this, _uploadedBytes),
261
+ totalDownloadedBytes,
262
+ p2pDownloadRatio: totalDownloadedBytes > 0 ? __privateGet(this, _p2pDownloadedBytes) / totalDownloadedBytes : 0,
263
+ downloadSpeed: p2pDownloadSpeed + httpDownloadSpeed,
264
+ p2pDownloadSpeed,
265
+ uploadSpeed: __privateGet(this, _uploadBandwidth).getSpeed(now)
266
+ };
267
+ }
268
+ /**
269
+ * 清零当前 peer 计数
270
+ *
271
+ * 动态关闭 P2P 或销毁播放实例后连接已全部断开(引擎销毁不保证
272
+ * 逐个发出 onPeerClose),主动清零防止残留计数污染下一次快照;
273
+ * 峰值与字节累计保留
274
+ */
275
+ resetPeers() {
276
+ __privateSet(this, _peers, 0);
277
+ }
278
+ /** 重置全部计数与样本(换源时调用) */
279
+ reset() {
280
+ __privateSet(this, _peers, 0);
281
+ __privateSet(this, _peakPeers, 0);
282
+ __privateSet(this, _p2pDownloadedBytes, 0);
283
+ __privateSet(this, _httpDownloadedBytes, 0);
284
+ __privateSet(this, _uploadedBytes, 0);
285
+ __privateGet(this, _downloadBandwidths).p2p.reset();
286
+ __privateGet(this, _downloadBandwidths).http.reset();
287
+ __privateGet(this, _uploadBandwidth).reset();
288
+ }
289
+ };
290
+ _peers = new WeakMap();
291
+ _peakPeers = new WeakMap();
292
+ _p2pDownloadedBytes = new WeakMap();
293
+ _httpDownloadedBytes = new WeakMap();
294
+ _uploadedBytes = new WeakMap();
295
+ _downloadBandwidths = new WeakMap();
296
+ _uploadBandwidth = new WeakMap();
297
+ // Annotate the CommonJS export names for ESM import in node:
298
+ 0 && (module.exports = {
299
+ BANDWIDTH_WINDOW_MS,
300
+ BandwidthCalculator,
301
+ DEFAULT_FATAL_RETRY_MAX,
302
+ DEFAULT_TYPE,
303
+ P2PStatsEngine,
304
+ P2P_EVENT_BRIDGE_MAP,
305
+ STATS_POLLING_MS,
306
+ applyRuntimeToggle,
307
+ mergeCoreConfig,
308
+ resolveOptions
309
+ });
package/dist/pure.mjs ADDED
@@ -0,0 +1,24 @@
1
+ import {
2
+ BANDWIDTH_WINDOW_MS,
3
+ BandwidthCalculator,
4
+ DEFAULT_FATAL_RETRY_MAX,
5
+ DEFAULT_TYPE,
6
+ P2PStatsEngine,
7
+ P2P_EVENT_BRIDGE_MAP,
8
+ STATS_POLLING_MS,
9
+ applyRuntimeToggle,
10
+ mergeCoreConfig,
11
+ resolveOptions
12
+ } from "./chunk-IX2RPNML.mjs";
13
+ export {
14
+ BANDWIDTH_WINDOW_MS,
15
+ BandwidthCalculator,
16
+ DEFAULT_FATAL_RETRY_MAX,
17
+ DEFAULT_TYPE,
18
+ P2PStatsEngine,
19
+ P2P_EVENT_BRIDGE_MAP,
20
+ STATS_POLLING_MS,
21
+ applyRuntimeToggle,
22
+ mergeCoreConfig,
23
+ resolveOptions
24
+ };