Web SDK Advanced Usage
Use this page after completing Web SDK Quick integration. Service Worker transport, existing-player adapters, dynamic URLs and authorization, low-latency tuning, diagnostics, and staged rollout are advanced capabilities; none is required for the base playback path.
Service Worker transport
Service Worker is optional and is not required for Web SDK integration. The SDK uses an available browser acceleration path by default; when Service Worker cannot be used, the current session continues through the existing media delivery path.
Run npm run build:web-sdk:release, then deploy dist/meshstream-sw.js to a same-origin HTTPS location such as /meshstream-sw.js. localhost is allowed for local development.
import { attach } from "@meshstream/p2p-web";
const session = attach({
key,
url,
video,
transportPreference: "auto",
serviceWorker: {
url: "/meshstream-sw.js",
scope: "/",
autoRegister: true,
p2pTimeoutMs: 5000,
onSegmentStats: ({ source, bytes }) => {
console.debug("MeshStream segment", source, bytes);
},
},
});
await session.start();
transportPreference | Use case |
|---|---|
auto | Default. Prefers MSE and uses an available Service Worker only when needed. |
mse | Use MSE acceleration only; use to roll back Service Worker. |
service-worker | Forces the Worker path; use only for controlled rollout and compatibility checks. |
cdn | Disables acceleration for this session, for playback comparison or emergency mitigation. |
The Worker can control only same-origin pages under its scope. onSegmentStats reports whether each segment used acceleration in source, which helps measure the actual result.
Rollout checklist
- Confirm the Worker is served through HTTPS and the page is within its scope.
- Verify normal playback with
auto, then verify playback remains normal when acceleration is disabled. - With two clients playing the same content, confirm P2P download bytes rather than relying on connection count alone.
- Roll out
service-workerto a controlled cohort. Roll back by removingserviceWorkeror usingmse.
Dynamic URLs and origin authorization
For URLs with rotating signatures, use a stable contentId to identify the same asset consistently and preserve acceleration effectiveness. originHeaders are used only for requests to your media origin and are never sent to other viewers.
const session = attach({
key,
url: signedM3u8Url,
contentId: "asset-12345",
video,
originHeaders: {
Authorization: `Bearer ${token}`,
"X-Playback-Session": playbackSession,
},
});
await session.start();
window.addEventListener("pagehide", () => session.dispose(), { once: true });
Use synchronous originHeadersProvider for a token that rotates during playback. Refresh the token in application state before the callback; it must not return a Promise:
const session = attach({
key,
url: signedM3u8Url,
video,
originHeadersProvider: ({ kind }) =>
kind === "segment" ? { Authorization: `Bearer ${currentToken}` } : undefined,
});
Browser CORS and restricted-header rules still apply. Cross-origin media requests retain their original request behavior and do not receive SDK authorization headers. Do not log origin tokens, cookies, or signed URLs.
Direct MP4 / MP3 playback
Direct playback means loading a .mp4 or .mp3 file URL directly in the player, rather than loading an HLS .m3u8 or DASH .mpd manifest. MP4 and MP3 acceleration is available only through a same-origin Service Worker. When its prerequisites are not met, the current session continues through the existing media delivery path.
Before enabling this path, make sure that:
- The page and Worker use HTTPS (
localhostis allowed for development), and the Worker has activated and controls the page. - The Worker is same-origin with the page and the site deploys
meshstream-sw.js. The SDK attempts to register it by default for direct media; use theserviceWorkerconfiguration above to set an explicit path and scope. - The origin supports a single Range request and returns a valid
Content-Range. - A cross-origin response exposes
Content-Length,Content-Type, andAccept-Ranges, and permits theRangerequest header.
The following examples show video and audio direct playback. Both use the same Service Worker and origin requirements.
const session = attach({
key,
url: "https://cdn.example.com/video/trailer.mp4",
contentId: "trailer-2026",
video: document.querySelector("video")!,
serviceWorker: {
url: "/meshstream-sw.js",
scope: "/",
autoRegister: true,
},
});
await session.start();
window.addEventListener("pagehide", () => session.dispose(), { once: true });
const session = attach({
key,
url: "https://cdn.example.com/audio/episode-01.mp3",
contentId: "podcast-episode-01",
video: document.querySelector("audio")!,
serviceWorker: {
url: "/meshstream-sw.js",
scope: "/",
autoRegister: true,
},
});
await session.start();
window.addEventListener("pagehide", () => session.dispose(), { once: true });
For an authenticated direct URL without a file extension, add mimeType: "mp4" or mimeType: "mp3" so the SDK does not need to infer the type from the URL.
Full-file requests, suffix ranges, multi-range requests, media metadata, and requests that cannot be safely split retain their original media-request behavior. If the Worker cannot start or the origin does not meet the Range requirements, MP4/MP3 playback is not blocked; it simply does not use acceleration.
Existing-player adapters
Use the adapter entry point when the application already owns a player. The SDK manages the P2P session and media request path; the application keeps ABR, decoding, rendering, and player teardown.
import Hls from "hls.js";
import { attachToHls } from "@meshstream/p2p-web/adapters";
const hls = new Hls({ maxBufferLength: 30 });
const session = attachToHls({ key, url, video, player: hls });
await session.start();
hls.loadSource(url);
hls.attachMedia(video);
window.addEventListener("pagehide", () => {
session.dispose();
hls.destroy();
}, { once: true });
Call session.start() before loadSource so the first media requests can participate in acceleration. Do not use attach and attachToHls on the same media element or URL.
| Integration | Use when | Notes |
|---|---|---|
attach | New page or media element | Basic path; SDK creates the required player. |
attachToHls | Application owns hls.js | Application retains hls.js lifecycle and ABR options. |
attachToShaka | Existing Shaka HLS/DASH instance | Application destroys the supplied instance. |
attachToDashJs | dash.js >=3.1.0 <6 | Installs the request loader before initialization. |
attachToRxPlayer | RxPlayer DASH | Regular audio/video segments enter P2P routing. |
attachToVhs | Video.js VHS HLS | Requires a same-origin Service Worker. |
attachToVideoJs, Plyr, DPlayer, ArtPlayer | Media-element bridge | Not a native loader plugin for the player engine. |
HLS and low-latency configuration
The SDK detects live/VOD automatically. For an HLS live stream with no explicit latency settings, it applies liveSyncDurationCount: 3 and liveMaxLatencyDurationCount: 6 after recognizing the media playlist.
hlsConfig is currently the only player-tuning option exposed by the Web SDK. Pass it to attach to tune an SDK-created hls.js instance's buffering, ABR, or latency; configure a caller-owned hls.js instance at creation. There is no equivalent dashConfig: configure Shaka, dash.js, or RxPlayer on the application-owned player instance. MP4/MP3 do not use player-tuning options and always use Service Worker range transport.
const session = attach({
key,
url,
video,
hlsConfig: {
liveSyncDurationCount: 3,
liveMaxLatencyDurationCount: 6,
},
});
LL-HLS/DASH CMAF partial segments, DRM, subtitles, and unsafe range requests stay on the player/CDN path. The SDK distributes complete media segments only, preserving cancellation and latency semantics.
Runtime controls and observability
setP2pEnabled(false) disables acceleration during playback without interrupting normal playback. statistics() returns traffic and error counters; diagnostics() returns recent connection diagnostics; qoe() is a safe, anonymous quality snapshot for application telemetry.
const unsubscribe = session.addEventListener({
onP2pReady() {
console.info("P2P ready");
},
onP2pUnavailable(reason) {
console.info("CDN fallback", reason);
},
onPeerCountChanged(count) {
updatePeerCount(count);
},
onStatistics(stats) {
reportDeliveryStats(stats);
},
});
const qoe = session.qoe();
// qoe.p2pDownloadRatio, qoe.firstPeerConnectMs, qoe.fallbackCount
window.addEventListener("pagehide", () => {
unsubscribe();
session.dispose();
}, { once: true });
Diagnostic or telemetry failures must never affect playback. Do not write SDK Keys, origin headers, cookies, or user identifiers to application logs.
Production boundaries
- The SDK owns playback sessions and acceleration handling; the player keeps manifests, ABR, decoding, rendering, and its lifecycle.
- When acceleration, network, configuration, or telemetry is temporarily unavailable, keep the player URL managed by the current session; do not replace it or stop playback solely because acceleration state changes.
- iPhone/iPad Safari has no MSE HLS P2P path and should use native HLS playback with same-origin Service Worker transport. Playback falls back to CDN only when the Worker is inactive, does not control the page, or a runtime prerequisite is not met. Whether macOS Safari uses the MSE path depends on the version and runtime capability; use
getCapability()as the source of truth. To validate the Worker path consistently, settransportPreference: "service-worker"for a controlled rollout. - MP4/MP3 acceleration applies only to safely splittable single-range requests; all other requests retain their original behavior.