@meshstream/p2p-web 0.2.1 → 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.
- package/README.md +394 -391
- package/dist/adapters.js +1 -1
- package/dist/advanced.js +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/hls.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/logging.d.ts +12 -0
- package/dist/session-token.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +43 -43
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# MeshStream P2P Web SDK
|
|
2
2
|
|
|
3
|
+
SDK-owned console diagnostics respect the client `logLevel` (default `none`), with redaction and
|
|
4
|
+
repeated-error limiting. Web does not write local log files. See the [logging guide](../../docs/sdk-logging.md).
|
|
5
|
+
|
|
3
6
|
Browser HLS and DASH P2P delivery SDK for MeshStream P2P-CDN. The SDK wraps
|
|
4
7
|
`hls.js`, Shaka Player, and `p2p-media-loader`, fetches runtime configuration
|
|
5
8
|
from Config API, joins a WebRTC tracker swarm, reports playback/P2P statistics,
|
|
@@ -7,18 +10,18 @@ and keeps CDN playback as the fallback path.
|
|
|
7
10
|
|
|
8
11
|
## Install
|
|
9
12
|
|
|
10
|
-
```bash
|
|
11
|
-
# SDK-managed player: MeshStream bundles its HLS, DASH, and P2P runtimes.
|
|
12
|
-
npm install @meshstream/p2p-web
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
For an application-managed `hls.js` instance, install the player in the
|
|
16
|
-
application as well. MeshStream will bind P2P to that instance without taking
|
|
17
|
-
over its configuration or lifecycle:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install @meshstream/p2p-web hls.js
|
|
21
|
-
```
|
|
13
|
+
```bash
|
|
14
|
+
# SDK-managed player: MeshStream bundles its HLS, DASH, and P2P runtimes.
|
|
15
|
+
npm install @meshstream/p2p-web
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For an application-managed `hls.js` instance, install the player in the
|
|
19
|
+
application as well. MeshStream will bind P2P to that instance without taking
|
|
20
|
+
over its configuration or lifecycle:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @meshstream/p2p-web hls.js
|
|
24
|
+
```
|
|
22
25
|
|
|
23
26
|
In this monorepo the SDK is consumed as a workspace package:
|
|
24
27
|
|
|
@@ -30,190 +33,190 @@ npm run build -w @p2pcdn/web-demo
|
|
|
30
33
|
## Quick Start
|
|
31
34
|
|
|
32
35
|
```ts
|
|
33
|
-
import { attach } from "@meshstream/p2p-web";
|
|
34
|
-
|
|
35
|
-
const player = attach({
|
|
36
|
+
import { attach } from "@meshstream/p2p-web";
|
|
37
|
+
|
|
38
|
+
const player = attach({
|
|
36
39
|
key: "your_sdk_key",
|
|
37
|
-
url: "https://cdn.example.com/live/index.m3u8", // or .mpd / .mp4 / .mp3
|
|
38
|
-
video: document.querySelector("video"),
|
|
40
|
+
url: "https://cdn.example.com/live/index.m3u8", // or .mpd / .mp4 / .mp3
|
|
41
|
+
video: document.querySelector("video"),
|
|
39
42
|
});
|
|
40
43
|
|
|
41
44
|
await player.start();
|
|
42
45
|
|
|
43
|
-
window.addEventListener("pagehide", () => player.dispose(), { once: true });
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
The historic `video` option accepts any `HTMLMediaElement`; pass an `<audio>`
|
|
47
|
-
element for progressive MP3 playback.
|
|
48
|
-
|
|
49
|
-
The SDK fetches SaaS bootstrap configuration, selects trackers/reporting
|
|
50
|
-
endpoints, detects browser capability, starts WebRTC P2P when possible, and
|
|
51
|
-
keeps CDN playback as the automatic fallback path.
|
|
52
|
-
|
|
53
|
-
When MeshStream creates hls.js, use `hlsConfig` to retain normal player tuning
|
|
54
|
-
such as `maxBufferLength`, ABR limits, or low-latency settings:
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
const player = attach({
|
|
58
|
-
key,
|
|
59
|
-
url,
|
|
60
|
-
video,
|
|
61
|
-
hlsConfig: { maxBufferLength: 45, lowLatencyMode: true },
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
MeshStream always reapplies its P2P loader and safe origin request settings
|
|
66
|
-
after the instance is created. For `attachToHls`, configure the caller-owned
|
|
67
|
-
hls.js instance directly instead.
|
|
68
|
-
|
|
69
|
-
To display compatibility information before playback, call `getCapability()`.
|
|
70
|
-
It returns only `mseSupported`, `webrtcSupported`, and `serviceWorkerSupported`;
|
|
71
|
-
it does not override the SDK's playback or fallback decision.
|
|
72
|
-
|
|
73
|
-
The web transport selects one content-affine Tracker for a playback session.
|
|
74
|
-
Tracker nodes keep independent in-memory peer maps; switching or retrying a
|
|
75
|
-
Tracker does not copy peers between nodes. If signaling becomes unavailable,
|
|
76
|
-
the player continues through CDN rather than registering the same session with
|
|
77
|
-
every shard. Configure tested hot-content buckets and same-region fallback
|
|
78
|
-
nodes when a stream needs faster recovery.
|
|
79
|
-
|
|
80
|
-
`player.statistics()` always returns the same complete counter shape. During
|
|
81
|
-
startup and CDN fallback, P2P counters are `0` instead of being omitted, so
|
|
82
|
-
application dashboards can use one schema for HLS, DASH, MP4/MP3, and RxPlayer.
|
|
83
|
-
|
|
84
|
-
## Optional Service Worker Transport
|
|
85
|
-
|
|
86
|
-
Service Worker support is an optional transport layer. MSE P2P remains the
|
|
87
|
-
default and is preferred whenever it is available. To deploy the SW runtime,
|
|
88
|
-
copy the published `dist/meshstream-sw.js` file to a same-origin HTTPS path
|
|
89
|
-
such as `/meshstream-sw.js`, then opt in:
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
import { attach } from "@meshstream/p2p-web";
|
|
93
|
-
|
|
94
|
-
const player = attach({
|
|
95
|
-
key,
|
|
96
|
-
url,
|
|
97
|
-
video,
|
|
98
|
-
transportPreference: "auto",
|
|
99
|
-
serviceWorker: {
|
|
100
|
-
url: "/meshstream-sw.js",
|
|
101
|
-
scope: "/",
|
|
102
|
-
autoRegister: true,
|
|
103
|
-
p2pTimeoutMs: 5000,
|
|
104
|
-
onSegmentStats: ({ source, bytes, url }) => {
|
|
105
|
-
console.debug("segment", source, bytes, url);
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
await player.start();
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
`auto` uses MSE P2P first. If MSE is unavailable and the page is controlled by
|
|
113
|
-
the registered SW, playback uses a virtual manifest URL under
|
|
114
|
-
`/__meshstream__/v1/`; failed or unavailable page-side P2P requests fall back
|
|
115
|
-
to the original CDN URL. `transportPreference: "service-worker"` is available
|
|
116
|
-
for explicit testing. When bootstrap returns a tracker configuration, the SDK
|
|
117
|
-
also starts a page-side `p2p-media-loader-core` engine that works without MSE,
|
|
118
|
-
indexes HLS master/media playlists, and answers SW segment requests from the
|
|
119
|
-
WebRTC swarm with CDN fallback. A custom `segmentProvider` can still be passed
|
|
120
|
-
to replace that engine for application-specific routing.
|
|
121
|
-
|
|
122
|
-
For manual registration, import `registerMeshStreamServiceWorker()` and
|
|
123
|
-
`createMeshStreamServiceWorkerSession()` from `@meshstream/p2p-web/service-worker`.
|
|
124
|
-
Registration requires HTTPS (localhost is allowed by browsers), and the SW script
|
|
125
|
-
must be same-origin with the page. Session metadata and rewritten resource mappings
|
|
126
|
-
are kept in IndexedDB so a browser-restarted SW can recover a registered session;
|
|
127
|
-
unregistering the player removes that metadata. `onSegmentStats` reports whether
|
|
128
|
-
each media request was served by the page provider (`p2p`) or CDN (`cdn`).
|
|
129
|
-
|
|
130
|
-
For a local browser smoke check after building, run
|
|
131
|
-
`node sdks/web/test/sw-browser-fixture.mjs` and open the printed URL. The page
|
|
132
|
-
reports the SW controller state, rewritten segment count, response bodies, and
|
|
133
|
-
per-segment source statistics.
|
|
134
|
-
|
|
135
|
-
For the real two-page WebRTC check, run the automated smoke from the repository
|
|
136
|
-
root:
|
|
137
|
-
|
|
138
|
-
```powershell
|
|
139
|
-
npm run test:web-sw-real
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
It builds the SDK and Tracker, opens seed/follower Chromium pages, and fails
|
|
143
|
-
unless the follower receives a non-empty segment through P2P. For manual
|
|
144
|
-
inspection, build the SDK and start
|
|
145
|
-
`node sdks/web/test/sw-real-p2p-browser-fixture.mjs`, then open the seed URL
|
|
146
|
-
first (`?role=seed`) and the follower URL (`?role=follower`).
|
|
147
|
-
|
|
148
|
-
### Staging rollout checklist
|
|
149
|
-
|
|
150
|
-
1. Build the browser package with `npm run build:web-sdk:release` and publish the
|
|
151
|
-
generated npm tarball. Copy `dist/meshstream-sw.js` from the package to a stable
|
|
152
|
-
same-origin HTTPS URL such as `/meshstream-sw.js`; do not serve it from a CDN
|
|
153
|
-
origin or a path outside the intended registration scope.
|
|
154
|
-
2. Deploy the page with `transportPreference: "auto"` and the SW `url` configured.
|
|
155
|
-
Confirm the normal browser path reports `p2p-hls`; test Safari/iOS or a forced
|
|
156
|
-
`transportPreference: "service-worker"` path and confirm `sw-hls-cdn`.
|
|
157
|
-
3. Check the browser Network panel for the virtual manifest under
|
|
158
|
-
`/__meshstream__/v1/` and verify segment requests return either `p2p` or `cdn`
|
|
159
|
-
in the SDK `onSegmentStats` callback.
|
|
160
|
-
4. Verify the configured report endpoint receives `reportType: "stats"` with
|
|
161
|
-
`p2pDownloaded`, `httpDownloaded`, `connectedPeers`, and tracker diagnostics.
|
|
162
|
-
The SDK sends an initial report, periodic reports, and a final `pagehide`
|
|
163
|
-
report; report failures must not interrupt playback.
|
|
164
|
-
5. Roll back by removing the `serviceWorker` option or setting
|
|
165
|
-
`transportPreference: "mse"`; the SDK then keeps the existing MSE/CDN path.
|
|
166
|
-
|
|
167
|
-
## Advanced Player Adapters
|
|
168
|
-
|
|
169
|
-
Use `@meshstream/p2p-web/adapters` for an existing player instance. Controlled
|
|
170
|
-
test environments that need to construct `MeshStreamHlsPlayer` directly can
|
|
171
|
-
import it from `@meshstream/p2p-web/advanced`; standard integrations should
|
|
172
|
-
continue to use root-level `attach`.
|
|
173
|
-
|
|
174
|
-
For a plain video element:
|
|
46
|
+
window.addEventListener("pagehide", () => player.dispose(), { once: true });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The historic `video` option accepts any `HTMLMediaElement`; pass an `<audio>`
|
|
50
|
+
element for progressive MP3 playback.
|
|
51
|
+
|
|
52
|
+
The SDK fetches SaaS bootstrap configuration, selects trackers/reporting
|
|
53
|
+
endpoints, detects browser capability, starts WebRTC P2P when possible, and
|
|
54
|
+
keeps CDN playback as the automatic fallback path.
|
|
55
|
+
|
|
56
|
+
When MeshStream creates hls.js, use `hlsConfig` to retain normal player tuning
|
|
57
|
+
such as `maxBufferLength`, ABR limits, or low-latency settings:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const player = attach({
|
|
61
|
+
key,
|
|
62
|
+
url,
|
|
63
|
+
video,
|
|
64
|
+
hlsConfig: { maxBufferLength: 45, lowLatencyMode: true },
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
MeshStream always reapplies its P2P loader and safe origin request settings
|
|
69
|
+
after the instance is created. For `attachToHls`, configure the caller-owned
|
|
70
|
+
hls.js instance directly instead.
|
|
71
|
+
|
|
72
|
+
To display compatibility information before playback, call `getCapability()`.
|
|
73
|
+
It returns only `mseSupported`, `webrtcSupported`, and `serviceWorkerSupported`;
|
|
74
|
+
it does not override the SDK's playback or fallback decision.
|
|
75
|
+
|
|
76
|
+
The web transport selects one content-affine Tracker for a playback session.
|
|
77
|
+
Tracker nodes keep independent in-memory peer maps; switching or retrying a
|
|
78
|
+
Tracker does not copy peers between nodes. If signaling becomes unavailable,
|
|
79
|
+
the player continues through CDN rather than registering the same session with
|
|
80
|
+
every shard. Configure tested hot-content buckets and same-region fallback
|
|
81
|
+
nodes when a stream needs faster recovery.
|
|
82
|
+
|
|
83
|
+
`player.statistics()` always returns the same complete counter shape. During
|
|
84
|
+
startup and CDN fallback, P2P counters are `0` instead of being omitted, so
|
|
85
|
+
application dashboards can use one schema for HLS, DASH, MP4/MP3, and RxPlayer.
|
|
86
|
+
|
|
87
|
+
## Optional Service Worker Transport
|
|
88
|
+
|
|
89
|
+
Service Worker support is an optional transport layer. MSE P2P remains the
|
|
90
|
+
default and is preferred whenever it is available. To deploy the SW runtime,
|
|
91
|
+
copy the published `dist/meshstream-sw.js` file to a same-origin HTTPS path
|
|
92
|
+
such as `/meshstream-sw.js`, then opt in:
|
|
175
93
|
|
|
176
94
|
```ts
|
|
177
|
-
import { attach } from "@meshstream/p2p-web";
|
|
178
|
-
|
|
179
|
-
const player = attach({
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
For
|
|
216
|
-
|
|
95
|
+
import { attach } from "@meshstream/p2p-web";
|
|
96
|
+
|
|
97
|
+
const player = attach({
|
|
98
|
+
key,
|
|
99
|
+
url,
|
|
100
|
+
video,
|
|
101
|
+
transportPreference: "auto",
|
|
102
|
+
serviceWorker: {
|
|
103
|
+
url: "/meshstream-sw.js",
|
|
104
|
+
scope: "/",
|
|
105
|
+
autoRegister: true,
|
|
106
|
+
p2pTimeoutMs: 5000,
|
|
107
|
+
onSegmentStats: ({ source, bytes, url }) => {
|
|
108
|
+
console.debug("segment", source, bytes, url);
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
await player.start();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`auto` uses MSE P2P first. If MSE is unavailable and the page is controlled by
|
|
116
|
+
the registered SW, playback uses a virtual manifest URL under
|
|
117
|
+
`/__meshstream__/v1/`; failed or unavailable page-side P2P requests fall back
|
|
118
|
+
to the original CDN URL. `transportPreference: "service-worker"` is available
|
|
119
|
+
for explicit testing. When bootstrap returns a tracker configuration, the SDK
|
|
120
|
+
also starts a page-side `p2p-media-loader-core` engine that works without MSE,
|
|
121
|
+
indexes HLS master/media playlists, and answers SW segment requests from the
|
|
122
|
+
WebRTC swarm with CDN fallback. A custom `segmentProvider` can still be passed
|
|
123
|
+
to replace that engine for application-specific routing.
|
|
124
|
+
|
|
125
|
+
For manual registration, import `registerMeshStreamServiceWorker()` and
|
|
126
|
+
`createMeshStreamServiceWorkerSession()` from `@meshstream/p2p-web/service-worker`.
|
|
127
|
+
Registration requires HTTPS (localhost is allowed by browsers), and the SW script
|
|
128
|
+
must be same-origin with the page. Session metadata and rewritten resource mappings
|
|
129
|
+
are kept in IndexedDB so a browser-restarted SW can recover a registered session;
|
|
130
|
+
unregistering the player removes that metadata. `onSegmentStats` reports whether
|
|
131
|
+
each media request was served by the page provider (`p2p`) or CDN (`cdn`).
|
|
132
|
+
|
|
133
|
+
For a local browser smoke check after building, run
|
|
134
|
+
`node sdks/web/test/sw-browser-fixture.mjs` and open the printed URL. The page
|
|
135
|
+
reports the SW controller state, rewritten segment count, response bodies, and
|
|
136
|
+
per-segment source statistics.
|
|
137
|
+
|
|
138
|
+
For the real two-page WebRTC check, run the automated smoke from the repository
|
|
139
|
+
root:
|
|
140
|
+
|
|
141
|
+
```powershell
|
|
142
|
+
npm run test:web-sw-real
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
It builds the SDK and Tracker, opens seed/follower Chromium pages, and fails
|
|
146
|
+
unless the follower receives a non-empty segment through P2P. For manual
|
|
147
|
+
inspection, build the SDK and start
|
|
148
|
+
`node sdks/web/test/sw-real-p2p-browser-fixture.mjs`, then open the seed URL
|
|
149
|
+
first (`?role=seed`) and the follower URL (`?role=follower`).
|
|
150
|
+
|
|
151
|
+
### Staging rollout checklist
|
|
152
|
+
|
|
153
|
+
1. Build the browser package with `npm run build:web-sdk:release` and publish the
|
|
154
|
+
generated npm tarball. Copy `dist/meshstream-sw.js` from the package to a stable
|
|
155
|
+
same-origin HTTPS URL such as `/meshstream-sw.js`; do not serve it from a CDN
|
|
156
|
+
origin or a path outside the intended registration scope.
|
|
157
|
+
2. Deploy the page with `transportPreference: "auto"` and the SW `url` configured.
|
|
158
|
+
Confirm the normal browser path reports `p2p-hls`; test Safari/iOS or a forced
|
|
159
|
+
`transportPreference: "service-worker"` path and confirm `sw-hls-cdn`.
|
|
160
|
+
3. Check the browser Network panel for the virtual manifest under
|
|
161
|
+
`/__meshstream__/v1/` and verify segment requests return either `p2p` or `cdn`
|
|
162
|
+
in the SDK `onSegmentStats` callback.
|
|
163
|
+
4. Verify the configured report endpoint receives `reportType: "stats"` with
|
|
164
|
+
`p2pDownloaded`, `httpDownloaded`, `connectedPeers`, and tracker diagnostics.
|
|
165
|
+
The SDK sends an initial report, periodic reports, and a final `pagehide`
|
|
166
|
+
report; report failures must not interrupt playback.
|
|
167
|
+
5. Roll back by removing the `serviceWorker` option or setting
|
|
168
|
+
`transportPreference: "mse"`; the SDK then keeps the existing MSE/CDN path.
|
|
169
|
+
|
|
170
|
+
## Advanced Player Adapters
|
|
171
|
+
|
|
172
|
+
Use `@meshstream/p2p-web/adapters` for an existing player instance. Controlled
|
|
173
|
+
test environments that need to construct `MeshStreamHlsPlayer` directly can
|
|
174
|
+
import it from `@meshstream/p2p-web/advanced`; standard integrations should
|
|
175
|
+
continue to use root-level `attach`.
|
|
176
|
+
|
|
177
|
+
For a plain video element:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { attach } from "@meshstream/p2p-web";
|
|
181
|
+
|
|
182
|
+
const player = attach({ key, url, video });
|
|
183
|
+
await player.start();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Choosing an HLS integration
|
|
187
|
+
|
|
188
|
+
Both HLS modes use the same P2P scheduling, authorization, and telemetry.
|
|
189
|
+
Use `attach` when the SDK should create and manage hls.js. Use `attachToHls`
|
|
190
|
+
when the application already owns an hls.js instance and must retain its
|
|
191
|
+
buffering, ABR, event, or plugin configuration. In the latter mode, the
|
|
192
|
+
application remains responsible for `loadSource`, `attachMedia`, and
|
|
193
|
+
`destroy`; call `session.start()` before `loadSource`. Do not use both modes
|
|
194
|
+
for the same media element or playback URL.
|
|
195
|
+
|
|
196
|
+
For an existing hls.js instance, bind MeshStream before the application starts
|
|
197
|
+
media loading. This is a native HLS P2P integration: the SDK keeps the caller's
|
|
198
|
+
hls.js configuration and P2P-enables that same instance. It never calls
|
|
199
|
+
`loadSource`, `attachMedia`, or `destroy` on the caller-owned player.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import Hls from "hls.js";
|
|
203
|
+
import { attachToHls } from "@meshstream/p2p-web";
|
|
204
|
+
|
|
205
|
+
const hls = new Hls({ maxBufferLength: 30 });
|
|
206
|
+
const session = attachToHls({ key, url, video, player: hls });
|
|
207
|
+
|
|
208
|
+
await session.start(); // Bind P2P before hls.js makes media requests.
|
|
209
|
+
hls.loadSource(url);
|
|
210
|
+
hls.attachMedia(video);
|
|
211
|
+
|
|
212
|
+
window.addEventListener("pagehide", () => {
|
|
213
|
+
session.dispose(); // Does not destroy hls.
|
|
214
|
+
hls.destroy(); // The application owns this lifecycle.
|
|
215
|
+
}, { once: true });
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
For rotating signed URLs, pass a stable business identity so viewers join the
|
|
219
|
+
same swarm. `mimeType` is useful when the media URL has no `.m3u8`, `.mpd`, `.mp4`, or `.mp3`
|
|
217
220
|
suffix. `originHeaders` are sent only to same-origin manifest, segment, and key requests on the
|
|
218
221
|
configured media origin. SDK-controlled headers such as `Range` and hop-by-hop headers are ignored;
|
|
219
222
|
the browser still applies its own forbidden-header and CORS rules. For Shaka and dash.js
|
|
@@ -221,94 +224,94 @@ adapter objects, the player must expose its request interception API; otherwise
|
|
|
221
224
|
the SDK fails explicitly instead of starting without the requested headers.
|
|
222
225
|
|
|
223
226
|
```ts
|
|
224
|
-
const player = attach({
|
|
225
|
-
key,
|
|
226
|
-
url: signedManifestUrl,
|
|
227
|
-
video,
|
|
228
|
-
contentId: "live-channel-123",
|
|
229
|
-
mimeType: "m3u8",
|
|
230
|
-
originHeaders: { Authorization: "Bearer ...", "X-Playback-Session": "..." },
|
|
231
|
-
});
|
|
232
|
-
await player.start();
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
For tokens that rotate during a long playback session, provide the current
|
|
236
|
-
value with a synchronous callback. The callback runs immediately before an
|
|
237
|
-
eligible CDN-origin request; it must not refresh a token or return a Promise.
|
|
238
|
-
Refresh credentials in application state first. Dynamic values override static
|
|
239
|
-
headers with the same name and, like static values, are never sent to peers.
|
|
240
|
-
|
|
241
|
-
```ts
|
|
242
|
-
let playbackToken = initialToken;
|
|
243
|
-
|
|
244
|
-
const player = attach({
|
|
245
|
-
key,
|
|
246
|
-
url: signedManifestUrl,
|
|
247
|
-
video,
|
|
248
|
-
originHeaders: { "X-Playback-Session": playbackSession },
|
|
249
|
-
originHeadersProvider: ({ kind }) =>
|
|
250
|
-
kind === "segment" ? { Authorization: `Bearer ${playbackToken}` } : undefined,
|
|
251
|
-
});
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
For Video.js:
|
|
227
|
+
const player = attach({
|
|
228
|
+
key,
|
|
229
|
+
url: signedManifestUrl,
|
|
230
|
+
video,
|
|
231
|
+
contentId: "live-channel-123",
|
|
232
|
+
mimeType: "m3u8",
|
|
233
|
+
originHeaders: { Authorization: "Bearer ...", "X-Playback-Session": "..." },
|
|
234
|
+
});
|
|
235
|
+
await player.start();
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
For tokens that rotate during a long playback session, provide the current
|
|
239
|
+
value with a synchronous callback. The callback runs immediately before an
|
|
240
|
+
eligible CDN-origin request; it must not refresh a token or return a Promise.
|
|
241
|
+
Refresh credentials in application state first. Dynamic values override static
|
|
242
|
+
headers with the same name and, like static values, are never sent to peers.
|
|
255
243
|
|
|
256
244
|
```ts
|
|
257
|
-
|
|
245
|
+
let playbackToken = initialToken;
|
|
258
246
|
|
|
259
|
-
const player =
|
|
247
|
+
const player = attach({
|
|
248
|
+
key,
|
|
249
|
+
url: signedManifestUrl,
|
|
250
|
+
video,
|
|
251
|
+
originHeaders: { "X-Playback-Session": playbackSession },
|
|
252
|
+
originHeadersProvider: ({ kind }) =>
|
|
253
|
+
kind === "segment" ? { Authorization: `Bearer ${playbackToken}` } : undefined,
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
For Video.js:
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
import { attachToVideoJs } from "@meshstream/p2p-web/adapters";
|
|
261
|
+
|
|
262
|
+
const player = attachToVideoJs({
|
|
260
263
|
key,
|
|
261
264
|
url,
|
|
262
265
|
player: videojs("player"),
|
|
263
266
|
});
|
|
264
|
-
await player.start();
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
This adapter follows the Video.js instance lifecycle and disposes the
|
|
268
|
-
MeshStream session automatically when Video.js is destroyed. It is a
|
|
269
|
-
media-element bridge: MeshStream owns protocol-compatible playback for that
|
|
270
|
-
element. For HLS, do not also load the same URL through Video.js VHS.
|
|
271
|
-
|
|
272
|
-
For Video.js HLS playback that must retain VHS and Video.js ABR ownership, use
|
|
273
|
-
the native VHS adapter instead. It gives VHS a same-origin virtual manifest and
|
|
274
|
-
routes the resulting segment traffic through the Service Worker P2P path. The
|
|
275
|
-
SDK releases its session automatically when Video.js is disposed; if the
|
|
276
|
-
Service Worker cannot start, VHS continues with the original CDN manifest.
|
|
277
|
-
|
|
278
|
-
```ts
|
|
279
|
-
import { attachToVhs } from "@meshstream/p2p-web/adapters";
|
|
280
|
-
|
|
281
|
-
const session = attachToVhs({
|
|
282
|
-
key,
|
|
283
|
-
url: "https://cdn.example.com/live/index.m3u8",
|
|
284
|
-
player: videojs("player"),
|
|
285
|
-
serviceWorker: { url: "/meshstream-sw.js" },
|
|
286
|
-
});
|
|
287
|
-
await session.start();
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
For players built on top of a standard `<video>` element:
|
|
267
|
+
await player.start();
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
This adapter follows the Video.js instance lifecycle and disposes the
|
|
271
|
+
MeshStream session automatically when Video.js is destroyed. It is a
|
|
272
|
+
media-element bridge: MeshStream owns protocol-compatible playback for that
|
|
273
|
+
element. For HLS, do not also load the same URL through Video.js VHS.
|
|
274
|
+
|
|
275
|
+
For Video.js HLS playback that must retain VHS and Video.js ABR ownership, use
|
|
276
|
+
the native VHS adapter instead. It gives VHS a same-origin virtual manifest and
|
|
277
|
+
routes the resulting segment traffic through the Service Worker P2P path. The
|
|
278
|
+
SDK releases its session automatically when Video.js is disposed; if the
|
|
279
|
+
Service Worker cannot start, VHS continues with the original CDN manifest.
|
|
291
280
|
|
|
292
281
|
```ts
|
|
293
|
-
import {
|
|
282
|
+
import { attachToVhs } from "@meshstream/p2p-web/adapters";
|
|
283
|
+
|
|
284
|
+
const session = attachToVhs({
|
|
285
|
+
key,
|
|
286
|
+
url: "https://cdn.example.com/live/index.m3u8",
|
|
287
|
+
player: videojs("player"),
|
|
288
|
+
serviceWorker: { url: "/meshstream-sw.js" },
|
|
289
|
+
});
|
|
290
|
+
await session.start();
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
For players built on top of a standard `<video>` element:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
import { attachToArtPlayer, attachToDPlayer, attachToPlyr } from "@meshstream/p2p-web/adapters";
|
|
294
297
|
|
|
295
298
|
await attachToPlyr({ key, url, player: plyr }).start();
|
|
296
299
|
await attachToDPlayer({ key, url, player: dplayer }).start();
|
|
297
300
|
await attachToArtPlayer({ key, url, player: art }).start();
|
|
298
301
|
```
|
|
299
302
|
|
|
300
|
-
The named adapters resolve common `video` or `media` fields, or a `<video>` nested
|
|
301
|
-
inside the player's root element, and then use the
|
|
302
|
-
same automatic HLS, DASH, and progressive-media path as the plain video adapter. They are media-element bridges,
|
|
303
|
-
not native Video.js, Plyr, DPlayer, or ArtPlayer engine plugins: MeshStream
|
|
304
|
-
owns the playback instance used for the supplied media element.
|
|
303
|
+
The named adapters resolve common `video` or `media` fields, or a `<video>` nested
|
|
304
|
+
inside the player's root element, and then use the
|
|
305
|
+
same automatic HLS, DASH, and progressive-media path as the plain video adapter. They are media-element bridges,
|
|
306
|
+
not native Video.js, Plyr, DPlayer, or ArtPlayer engine plugins: MeshStream
|
|
307
|
+
owns the playback instance used for the supplied media element.
|
|
305
308
|
|
|
306
309
|
For DASH with the standard SDK path:
|
|
307
310
|
|
|
308
311
|
```ts
|
|
309
|
-
import { attach } from "@meshstream/p2p-web";
|
|
310
|
-
|
|
311
|
-
const player = attach({
|
|
312
|
+
import { attach } from "@meshstream/p2p-web";
|
|
313
|
+
|
|
314
|
+
const player = attach({
|
|
312
315
|
key,
|
|
313
316
|
url: "https://cdn.example.com/live/index.mpd",
|
|
314
317
|
video,
|
|
@@ -316,82 +319,82 @@ const player = attach({
|
|
|
316
319
|
await player.start();
|
|
317
320
|
```
|
|
318
321
|
|
|
319
|
-
`attach` selects DASH for `.mpd` URLs and HLS for `.m3u8` URLs. Customers
|
|
322
|
+
`attach` selects DASH for `.mpd` URLs and HLS for `.m3u8` URLs. Customers
|
|
320
323
|
do not pass a protocol flag. DASH P2P uses Shaka Player internally for the
|
|
321
324
|
standard SDK path.
|
|
322
325
|
|
|
323
326
|
For an existing Shaka Player:
|
|
324
327
|
|
|
325
328
|
```ts
|
|
326
|
-
import { attachToShaka } from "@meshstream/p2p-web/adapters";
|
|
329
|
+
import { attachToShaka } from "@meshstream/p2p-web/adapters";
|
|
327
330
|
|
|
328
331
|
const player = attachToShaka({
|
|
329
332
|
key,
|
|
330
333
|
url: "https://cdn.example.com/live/index.mpd",
|
|
331
334
|
player: shakaPlayer,
|
|
332
335
|
});
|
|
333
|
-
await player.start();
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
`attachToShaka()` binds and releases only the MeshStream P2P session. The
|
|
337
|
-
application retains ownership of the supplied Shaka instance and must destroy
|
|
338
|
-
it when appropriate.
|
|
339
|
-
|
|
340
|
-
For an existing dash.js player:
|
|
336
|
+
await player.start();
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`attachToShaka()` binds and releases only the MeshStream P2P session. The
|
|
340
|
+
application retains ownership of the supplied Shaka instance and must destroy
|
|
341
|
+
it when appropriate.
|
|
342
|
+
|
|
343
|
+
For an existing dash.js player:
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import { attachToDashJs } from "@meshstream/p2p-web/adapters";
|
|
347
|
+
|
|
348
|
+
const player = attachToDashJs({
|
|
349
|
+
key,
|
|
350
|
+
url: "https://cdn.example.com/live/index.mpd",
|
|
351
|
+
video,
|
|
352
|
+
player: dashJsPlayer,
|
|
353
|
+
});
|
|
354
|
+
await player.start();
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
`attachToDashJs` provides native DASH P2P for dash.js `>= 3.1.0 < 6`. Create
|
|
358
|
+
the dash.js instance first, but do not initialize it or load the MPD before
|
|
359
|
+
`session.start()`: MeshStream installs its `XHRLoader` extension first, then
|
|
360
|
+
initializes the supplied instance. Regular audio/video initialization, index,
|
|
361
|
+
and media segments use P2P with CDN fallback. MPD, DRM licenses, subtitles,
|
|
362
|
+
low-latency partial segments, and credentialed cookie requests remain on the
|
|
363
|
+
customer's dash.js/CDN path. When passing
|
|
364
|
+
`originHeaders` to an existing dash.js or Shaka instance, its request interception
|
|
365
|
+
API is required; native Safari HLS cannot accept arbitrary custom headers, so use
|
|
366
|
+
hls.js or signed URLs for that case.
|
|
367
|
+
|
|
368
|
+
### Adapter capability matrix
|
|
369
|
+
|
|
370
|
+
| Player path | P2P integration | Notes |
|
|
371
|
+
| --- | --- | --- |
|
|
372
|
+
| `attach` with HLS | Native hls.js P2P | MeshStream creates and owns hls.js. |
|
|
373
|
+
| `attachToHls` | Native existing hls.js P2P | Application keeps the hls.js lifecycle. |
|
|
374
|
+
| `attach` with DASH; `attachToShaka` with HLS/DASH | Native Shaka P2P | Uses Shaka's networking integration. |
|
|
375
|
+
| `attachToRxPlayer` with DASH | Native RxPlayer segment P2P | Regular DASH segments; same-origin origin headers are supported. |
|
|
376
|
+
| `attachToDashJs` with dash.js `>= 3.1.0 < 6` | Native dash.js P2P | Installs a supported `XHRLoader` extension before dash.js initialization. |
|
|
377
|
+
| `attachToVhs` with Video.js VHS | Native VHS via Service Worker | VHS retains player and ABR ownership; requires a same-origin Service Worker. |
|
|
378
|
+
| `attachToVideoJs`, Plyr, DPlayer, ArtPlayer | Media-element bridge | Not a native plugin for the player's own media engine. |
|
|
379
|
+
|
|
380
|
+
For an existing RxPlayer DASH instance:
|
|
341
381
|
|
|
342
382
|
```ts
|
|
343
|
-
import
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
and media segments use P2P with CDN fallback. MPD, DRM licenses, subtitles,
|
|
359
|
-
low-latency partial segments, and credentialed cookie requests remain on the
|
|
360
|
-
customer's dash.js/CDN path. When passing
|
|
361
|
-
`originHeaders` to an existing dash.js or Shaka instance, its request interception
|
|
362
|
-
API is required; native Safari HLS cannot accept arbitrary custom headers, so use
|
|
363
|
-
hls.js or signed URLs for that case.
|
|
364
|
-
|
|
365
|
-
### Adapter capability matrix
|
|
366
|
-
|
|
367
|
-
| Player path | P2P integration | Notes |
|
|
368
|
-
| --- | --- | --- |
|
|
369
|
-
| `attach` with HLS | Native hls.js P2P | MeshStream creates and owns hls.js. |
|
|
370
|
-
| `attachToHls` | Native existing hls.js P2P | Application keeps the hls.js lifecycle. |
|
|
371
|
-
| `attach` with DASH; `attachToShaka` with HLS/DASH | Native Shaka P2P | Uses Shaka's networking integration. |
|
|
372
|
-
| `attachToRxPlayer` with DASH | Native RxPlayer segment P2P | Regular DASH segments; same-origin origin headers are supported. |
|
|
373
|
-
| `attachToDashJs` with dash.js `>= 3.1.0 < 6` | Native dash.js P2P | Installs a supported `XHRLoader` extension before dash.js initialization. |
|
|
374
|
-
| `attachToVhs` with Video.js VHS | Native VHS via Service Worker | VHS retains player and ABR ownership; requires a same-origin Service Worker. |
|
|
375
|
-
| `attachToVideoJs`, Plyr, DPlayer, ArtPlayer | Media-element bridge | Not a native plugin for the player's own media engine. |
|
|
376
|
-
|
|
377
|
-
For an existing RxPlayer DASH instance:
|
|
378
|
-
|
|
379
|
-
```ts
|
|
380
|
-
import RxPlayer from "rx-player";
|
|
381
|
-
import { attachToRxPlayer } from "@meshstream/p2p-web";
|
|
382
|
-
|
|
383
|
-
const rxPlayer = new RxPlayer({ videoElement: video });
|
|
384
|
-
const player = attachToRxPlayer({ key, url: dashMpdUrl, contentId: "asset-123", player: rxPlayer });
|
|
385
|
-
await player.start();
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
`attachToRxPlayer` intercepts RxPlayer's actual DASH audio/video segment loader and sends those
|
|
389
|
-
requests through MeshStream P2P. When `originHeaders` or
|
|
390
|
-
`originHeadersProvider` are configured, same-origin MPD and regular
|
|
391
|
-
audio/video fallback requests retain those headers; dynamic values override
|
|
392
|
-
static values. Cross-origin media, text, DRM, non-contiguous ranges, and
|
|
393
|
-
RxPlayer low-latency chunked loading remain on the customer's RxPlayer/CDN
|
|
394
|
-
path without SDK-supplied headers.
|
|
383
|
+
import RxPlayer from "rx-player";
|
|
384
|
+
import { attachToRxPlayer } from "@meshstream/p2p-web";
|
|
385
|
+
|
|
386
|
+
const rxPlayer = new RxPlayer({ videoElement: video });
|
|
387
|
+
const player = attachToRxPlayer({ key, url: dashMpdUrl, contentId: "asset-123", player: rxPlayer });
|
|
388
|
+
await player.start();
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
`attachToRxPlayer` intercepts RxPlayer's actual DASH audio/video segment loader and sends those
|
|
392
|
+
requests through MeshStream P2P. When `originHeaders` or
|
|
393
|
+
`originHeadersProvider` are configured, same-origin MPD and regular
|
|
394
|
+
audio/video fallback requests retain those headers; dynamic values override
|
|
395
|
+
static values. Cross-origin media, text, DRM, non-contiguous ranges, and
|
|
396
|
+
RxPlayer low-latency chunked loading remain on the customer's RxPlayer/CDN
|
|
397
|
+
path without SDK-supplied headers.
|
|
395
398
|
|
|
396
399
|
Telemetry keeps the playback host and path for diagnostics but strips query and fragment data,
|
|
397
400
|
so signed playback credentials are not included in reports.
|
|
@@ -399,11 +402,11 @@ so signed playback credentials are not included in reports.
|
|
|
399
402
|
## Runtime Contract
|
|
400
403
|
|
|
401
404
|
- `key` is the customer-facing SDK Key and can be embedded in Web pages.
|
|
402
|
-
- `homeRegion` is resolved from the SDK Key and identifies the tenant's registered data-home
|
|
403
|
-
region. It is returned by bootstrap for diagnostics and future regional routing; customer code
|
|
404
|
-
cannot override it.
|
|
405
|
-
- Request-network GeoIP is used only for access-side Tracker/ICE locality and is not a data-residency
|
|
406
|
-
selection.
|
|
405
|
+
- `homeRegion` is resolved from the SDK Key and identifies the tenant's registered data-home
|
|
406
|
+
region. It is returned by bootstrap for diagnostics and future regional routing; customer code
|
|
407
|
+
cannot override it.
|
|
408
|
+
- Request-network GeoIP is used only for access-side Tracker/ICE locality and is not a data-residency
|
|
409
|
+
selection.
|
|
407
410
|
- Customer integrations should only need `key`, the media `url`, and a `video`
|
|
408
411
|
element for the standard Web path.
|
|
409
412
|
- The SaaS bootstrap endpoint, tracker pool, ICE servers, reporting route, and
|
|
@@ -415,71 +418,71 @@ so signed playback credentials are not included in reports.
|
|
|
415
418
|
- Fallback reporting uses the service-owned endpoint returned by bootstrap.
|
|
416
419
|
- Signed CDN URL query fields such as `token`, `signature`, `expires`,
|
|
417
420
|
`x-amz-*`, `x-oss-*`, and `x-goog-*` are excluded from URL-derived swarm IDs.
|
|
418
|
-
- `contentId` is optional. When supplied, the SDK derives the internal swarm ID
|
|
419
|
-
from it so rotating signed URL paths remain in the same swarm; otherwise it
|
|
420
|
-
derives identity from the canonical playback URL.
|
|
421
|
-
- `swarmId` and rendition/quality identifiers are internal runtime values. They
|
|
422
|
-
are intentionally not part of the customer-facing configuration; the SDK
|
|
423
|
-
derives and manages them from the content and manifest.
|
|
424
|
-
- Direct progressive `.mp4` and `.mp3` files use the same P2P Service Worker transport as a
|
|
425
|
-
byte-range stream. The SDK registers the Worker by default for this path and divides the file
|
|
426
|
-
into deterministic 1 MiB pieces. Large and open-ended ranges are returned as a backpressure-aware
|
|
427
|
-
stream, so they do not require buffering the whole response in the page. Full-file requests
|
|
428
|
-
without `Range`, suffix ranges, multi-range requests, and metadata remain on CDN.
|
|
429
|
-
Use a stable `contentId` when signed URLs have per-viewer path differences.
|
|
430
|
-
- The direct-file origin must support byte ranges, expose `Content-Length`, `Content-Type`, and
|
|
431
|
-
`Accept-Ranges` through CORS, and allow `GET`, `HEAD`, `OPTIONS`, and the `Range` request header.
|
|
432
|
-
`HEAD` is recommended; if the origin explicitly returns `405` or `501`, extensionless URL detection
|
|
433
|
-
uses a one-byte range `GET` instead. Missing metadata or any P2P error falls back to the original CDN URL.
|
|
421
|
+
- `contentId` is optional. When supplied, the SDK derives the internal swarm ID
|
|
422
|
+
from it so rotating signed URL paths remain in the same swarm; otherwise it
|
|
423
|
+
derives identity from the canonical playback URL.
|
|
424
|
+
- `swarmId` and rendition/quality identifiers are internal runtime values. They
|
|
425
|
+
are intentionally not part of the customer-facing configuration; the SDK
|
|
426
|
+
derives and manages them from the content and manifest.
|
|
427
|
+
- Direct progressive `.mp4` and `.mp3` files use the same P2P Service Worker transport as a
|
|
428
|
+
byte-range stream. The SDK registers the Worker by default for this path and divides the file
|
|
429
|
+
into deterministic 1 MiB pieces. Large and open-ended ranges are returned as a backpressure-aware
|
|
430
|
+
stream, so they do not require buffering the whole response in the page. Full-file requests
|
|
431
|
+
without `Range`, suffix ranges, multi-range requests, and metadata remain on CDN.
|
|
432
|
+
Use a stable `contentId` when signed URLs have per-viewer path differences.
|
|
433
|
+
- The direct-file origin must support byte ranges, expose `Content-Length`, `Content-Type`, and
|
|
434
|
+
`Accept-Ranges` through CORS, and allow `GET`, `HEAD`, `OPTIONS`, and the `Range` request header.
|
|
435
|
+
`HEAD` is recommended; if the origin explicitly returns `405` or `501`, extensionless URL detection
|
|
436
|
+
uses a one-byte range `GET` instead. Missing metadata or any P2P error falls back to the original CDN URL.
|
|
434
437
|
|
|
435
438
|
## Public API
|
|
436
439
|
|
|
437
440
|
```ts
|
|
438
|
-
// Standard customer-facing entry point
|
|
439
|
-
attach(options)
|
|
440
|
-
|
|
441
|
-
// Advanced player adapters
|
|
442
|
-
import { attachToShaka, attachToDashJs, attachToVhs, attachToVideoJs } from "@meshstream/p2p-web/adapters";
|
|
441
|
+
// Standard customer-facing entry point
|
|
442
|
+
attach(options)
|
|
443
|
+
|
|
444
|
+
// Advanced player adapters
|
|
445
|
+
import { attachToShaka, attachToDashJs, attachToVhs, attachToVideoJs } from "@meshstream/p2p-web/adapters";
|
|
443
446
|
|
|
444
447
|
// P2P runtime controls
|
|
445
|
-
player.start()
|
|
446
|
-
player.dispose()
|
|
447
|
-
player.setP2pEnabled(enabled)
|
|
448
|
-
player.addEventListener(listener) // returns unsubscribe
|
|
449
|
-
player.statistics()
|
|
450
|
-
player.diagnostics()
|
|
451
|
-
player.qoe()
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
`setP2pEnabled(false)` may be called before `start()` to force a CDN-only
|
|
455
|
-
session, or during playback to stop P2P without interrupting CDN delivery.
|
|
456
|
-
Repeated `start()` calls share the active session; call `dispose()` before
|
|
457
|
-
starting a fresh session for a different source or player lifecycle.
|
|
458
|
-
|
|
459
|
-
`start()` returns `{ mode, capability, fallbackReason? }`. On a CDN fallback,
|
|
460
|
-
`fallbackReason` is one of `CAPABILITY_UNSUPPORTED`, `P2P_DISABLED`,
|
|
461
|
-
`SDK_CONFIG_UNAVAILABLE`, `TRACKER_UNAVAILABLE`, or
|
|
462
|
-
`P2P_INITIALIZATION_FAILED`. It is intended for customer telemetry and does
|
|
463
|
-
not expose the server bootstrap configuration.
|
|
464
|
-
|
|
465
|
-
`addEventListener()` accepts `onPlaybackStateChanged`, `onP2pReady`,
|
|
466
|
-
`onP2pUnavailable`, `onPeerCountChanged`, `onTrackerError`,
|
|
467
|
-
`onPeerConnectError`, `onCdnFallback`, and `onStatistics`. Register before `start()` when the
|
|
468
|
-
initial connection state matters. Startup CDN fallbacks emit `UNSUPPORTED`,
|
|
469
|
-
`DISABLED`, `CONFIG_UNAVAILABLE`, `TRACKER_ERROR`, or
|
|
470
|
-
`INITIALIZATION_FAILED`; call the returned function during cleanup.
|
|
471
|
-
|
|
472
|
-
`onPlaybackStateChanged` reports `idle`, `initializing`, `connecting`,
|
|
473
|
-
`p2p-ready`, `cdn-fallback`, and `disposed`. `qoe()` returns a safe
|
|
474
|
-
application-telemetry snapshot: total/P2P/CDN download bytes, P2P download
|
|
475
|
-
ratio, connected peers, first-peer latency when available, cold-start CDN
|
|
476
|
-
bytes, and fallback count. It intentionally excludes Tracker, ICE, and peer
|
|
477
|
-
identifiers.
|
|
478
|
-
|
|
479
|
-
Low-latency HLS/DASH partial CMAF segment requests remain on the player CDN
|
|
480
|
-
path. P2P only distributes complete segments: sharing a response before its
|
|
481
|
-
partial body is complete breaks player cancellation semantics and causes
|
|
482
|
-
latency jitter. Playback continues normally through CDN for those parts.
|
|
448
|
+
player.start()
|
|
449
|
+
player.dispose()
|
|
450
|
+
player.setP2pEnabled(enabled)
|
|
451
|
+
player.addEventListener(listener) // returns unsubscribe
|
|
452
|
+
player.statistics()
|
|
453
|
+
player.diagnostics()
|
|
454
|
+
player.qoe()
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
`setP2pEnabled(false)` may be called before `start()` to force a CDN-only
|
|
458
|
+
session, or during playback to stop P2P without interrupting CDN delivery.
|
|
459
|
+
Repeated `start()` calls share the active session; call `dispose()` before
|
|
460
|
+
starting a fresh session for a different source or player lifecycle.
|
|
461
|
+
|
|
462
|
+
`start()` returns `{ mode, capability, fallbackReason? }`. On a CDN fallback,
|
|
463
|
+
`fallbackReason` is one of `CAPABILITY_UNSUPPORTED`, `P2P_DISABLED`,
|
|
464
|
+
`SDK_CONFIG_UNAVAILABLE`, `TRACKER_UNAVAILABLE`, or
|
|
465
|
+
`P2P_INITIALIZATION_FAILED`. It is intended for customer telemetry and does
|
|
466
|
+
not expose the server bootstrap configuration.
|
|
467
|
+
|
|
468
|
+
`addEventListener()` accepts `onPlaybackStateChanged`, `onP2pReady`,
|
|
469
|
+
`onP2pUnavailable`, `onPeerCountChanged`, `onTrackerError`,
|
|
470
|
+
`onPeerConnectError`, `onCdnFallback`, and `onStatistics`. Register before `start()` when the
|
|
471
|
+
initial connection state matters. Startup CDN fallbacks emit `UNSUPPORTED`,
|
|
472
|
+
`DISABLED`, `CONFIG_UNAVAILABLE`, `TRACKER_ERROR`, or
|
|
473
|
+
`INITIALIZATION_FAILED`; call the returned function during cleanup.
|
|
474
|
+
|
|
475
|
+
`onPlaybackStateChanged` reports `idle`, `initializing`, `connecting`,
|
|
476
|
+
`p2p-ready`, `cdn-fallback`, and `disposed`. `qoe()` returns a safe
|
|
477
|
+
application-telemetry snapshot: total/P2P/CDN download bytes, P2P download
|
|
478
|
+
ratio, connected peers, first-peer latency when available, cold-start CDN
|
|
479
|
+
bytes, and fallback count. It intentionally excludes Tracker, ICE, and peer
|
|
480
|
+
identifiers.
|
|
481
|
+
|
|
482
|
+
Low-latency HLS/DASH partial CMAF segment requests remain on the player CDN
|
|
483
|
+
path. P2P only distributes complete segments: sharing a response before its
|
|
484
|
+
partial body is complete breaks player cancellation semantics and causes
|
|
485
|
+
latency jitter. Playback continues normally through CDN for those parts.
|
|
483
486
|
|
|
484
487
|
## Release Checks
|
|
485
488
|
|
|
@@ -489,10 +492,10 @@ npm run build:web-sdk:release
|
|
|
489
492
|
npm run pack:dry-run -w @meshstream/p2p-web
|
|
490
493
|
```
|
|
491
494
|
|
|
492
|
-
`prepack` runs the SDK test suite, bundles the runtime dependencies into the
|
|
493
|
-
public entry points, and then minifies the release output before package
|
|
494
|
-
creation. The published package contains only bundled JavaScript, `.d.ts`
|
|
495
|
-
types, the Service Worker, README, and licenses; customers do not need to
|
|
496
|
-
install the internal player or P2P packages separately. Public exports and
|
|
497
|
-
object property names remain stable, while readable formatting and source maps
|
|
498
|
-
are omitted from the published JavaScript.
|
|
495
|
+
`prepack` runs the SDK test suite, bundles the runtime dependencies into the
|
|
496
|
+
public entry points, and then minifies the release output before package
|
|
497
|
+
creation. The published package contains only bundled JavaScript, `.d.ts`
|
|
498
|
+
types, the Service Worker, README, and licenses; customers do not need to
|
|
499
|
+
install the internal player or P2P packages separately. Public exports and
|
|
500
|
+
object property names remain stable, while readable formatting and source maps
|
|
501
|
+
are omitted from the published JavaScript.
|