Uniapp SDK advanced usage
This guide follows the native SDK workflow: live/VOD, direct files, per-session options, preload, runtime controls, monitoring, and platform policy. Examples use the client from Quick integration; player variables belong to your application.
Live and VOD integration policy
The SDK detects live/VOD automatically; both use the same quick integration. Player feedback is optional and helps P2P scheduling.
Live
Report the continuous playable buffer ahead of the current position to tune P2P prefetch. For example, position 60 s with buffer ending at 70 s means 10,000 ms. Live start position and target latency remain player settings.
await MeshStream.updateBufferedDurationMs(
client.clientId, session.sessionId, bufferedDurationMs,
)
VOD
Also report playback position so the SDK can prefer already-connected peers with nearby progress and the requested segment. Update position immediately after a completed seek.
await MeshStream.updateCurrentPositionMs(
client.clientId, session.sessionId, positionMs,
)
await MeshStream.updateBufferedDurationMs(
client.clientId, session.sessionId, bufferedDurationMs,
)
Use non-negative milliseconds; do not count across buffer gaps. Send valid player state about once per second. Stop and drain updates before closing the session.
Complete player feedback example
Convert your player callbacks to these millisecond inputs. Serialize asynchronous updates and handle bridge errors.
async function syncPlaybackState(positionMs, bufferedDurationMs, isLive) {
if (!isLive && Number.isFinite(positionMs) && positionMs >= 0) {
await MeshStream.updateCurrentPositionMs(
client.clientId, session.sessionId, positionMs,
)
}
if (Number.isFinite(bufferedDurationMs) && bufferedDurationMs >= 0) {
await MeshStream.updateBufferedDurationMs(
client.clientId, session.sessionId, bufferedDurationMs,
)
}
}
Direct MP4 / MP3 playback
MP4 and MP3 use direct file URLs. Keep a stable contentId and set mimeType explicitly when the URL has no extension:
const session = await MeshStream.createPlaybackSession(client.clientId, {
url: 'https://cdn.example.com/video/trailer.mp4',
contentId: 'trailer-2026',
mimeType: 'mp4',
})
Pass session.playbackUrl to a player that supports the format. For MP3, replace the URL and MIME hint with an MP3 URL and mp3. Acceleration requires single-range HTTP requests and a valid Content-Range response from the origin. If the origin does not support that, P2P acceleration is not enabled; playback and seeking still depend on the origin and player. The SDK does not decode media or bypass DRM.
Per-playback configuration and origin authorization
Configure the client once, then provide per-media options when creating each session:
| Scope | Option | Purpose |
|---|---|---|
| Client | key | SDK Key for the target application/platform |
| Client | p2pEnabled | Initial P2P preference, subject to console policy |
| Session | url | Original media URL; required |
| Session | contentId | Stable identity of the same content |
| Session | mimeType | m3u8, mpd, mp4, or mp3 |
| Session | originHeaders | Headers sent only to your media origin |
Pass a stable contentId for a short-lived signed URL and set mimeType when the URL has no extension. Origin request headers go in originHeaders:
const session = await MeshStream.createPlaybackSession(client.clientId, {
url: signedUrl,
contentId: 'movie-2026-001',
mimeType: 'mp4',
originHeaders: { Authorization: `Bearer ${originToken}` },
})
These headers are used only for the origin and are not sent to peers. Renew signatures in the application layer, keep the same contentId, and keep keys, tokens, and full signed URLs out of logs.
Preload and content switching
Explicit preload is an optional HLS/DASH warmup: it fetches the manifest and first media segment in the background, not the entire video. It may also start Tracker/Peer connections early, but a successful queue operation does not guarantee that peers or media are ready. An unplayed candidate session does not upload media to peers. MP4/MP3 direct files do not use this explicit preload path.
Keep the candidate session and reuse its playback URL when selected. Before closing a session, stop and drain its player-state updates and remove its event subscriptions; do not continue callbacks against a closed session. Preload does not prepare a decoder or render a frame.
Use one session per player. For a content list, prepare the next item before switching to it:
Prepare candidate content
const next = await MeshStream.createPlaybackSession(client.clientId, {
url: nextItem.url,
contentId: nextItem.id,
mimeType: 'm3u8',
})
const queued = await MeshStream.preload(client.clientId, next.sessionId)
if (queued) {
// Bind next.playbackUrl to the video player only when it becomes active.
}
preload returning true means that warmup was queued; it does not mean that the first frame is ready. Close discarded candidates promptly so they do not keep connections open.
Switch to the candidate
When switching to the prepared item, detach the old media from the player, close the old session, then use next.playbackUrl and retain next as the active session. Preload does not drive a player, and a queued request does not guarantee that a peer is ready. Warmup can consume network traffic.
Cancel candidate content
If the candidate is discarded, close it instead:
await MeshStream.closeSession(client.clientId, next.sessionId)
Runtime controls
P2P toggles
For a rollout or investigation, disable P2P only for the active session:
await MeshStream.setP2pEnabled(client.clientId, session.sessionId, false)
await MeshStream.setP2pEnabled(client.clientId, session.sessionId, true)
When P2P, Tracker, or configuration is unavailable, keep playing session.playbackUrl. Do not replace the URL or stop playback because the peer count is zero, p2pUnavailable was emitted, or one request used CDN.
Events and monitoring
Register an event listener and remove it when the page is destroyed:
const removeEvents = MeshStream.addEventListener((event) => {
const eventClientId = event.getString ? event.getString('clientId') : event.clientId
const eventSessionId = event.getString ? event.getString('sessionId') : event.sessionId
if (eventClientId !== client.clientId || eventSessionId !== session.sessionId) return
const type = event.getString ? event.getString('type') : event.type
if (type === 'p2pUnavailable') console.info('P2P unavailable', event)
if (type === 'statistics') console.info('statistics', event)
})
const status = await MeshStream.getStatus(client.clientId)
const stats = await MeshStream.getStats(client.clientId, session.sessionId)
const diagnostics = await MeshStream.getDiagnostics(
client.clientId, session.sessionId,
)
removeEvents()
Use subscribeEvents and unsubscribeEvents when you need an explicit numeric subscription ID. statistics carries traffic and peer data. cdnFallback reports a request that used CDN; it does not mean that the whole session switched to CDN.
| Field | Meaning |
|---|---|
httpDownloaded | Bytes downloaded through HTTP/CDN |
p2pDownloaded | Bytes downloaded from peers |
p2pUploaded | Bytes shared with peers |
connectedPeers | Current connected peer count |
downloadOffloadRatio | P2P download bytes / total HTTP and P2P download bytes; 0–1 |
Multiply downloadOffloadRatio by 100 for a percentage. It is a download-offload measure, not an upload ratio. With no downloaded bytes, the value is zero; one peer or one CDN fallback event does not establish an offload result. Inspect getDiagnostics() for connection timing and error details; optional fields may be absent.
Verify P2P delivery
- Start with one device: verify playback, seeking for VOD, and normal playback with P2P disabled.
- Run two devices on the same content with a consistent
contentId. For VOD, use overlapping playback positions; for live, play the same channel. Keep the media bytes and timeline consistent; do not reuse an ID for different assets or personalized manifests. - Check that player updates use milliseconds and continue after the manifest loads. At position 60 seconds with continuous buffer ending at 70 seconds, the buffer value is 10,000 ms; refresh VOD position after a completed seek.
- Observe changes in P2P downloaded bytes and offload ratio over a playback interval. A connected peer alone does not prove that media was downloaded through P2P. Results depend on overlapping available segments, network conditions, and platform policy.
- Disable P2P and verify that playback continues through CDN. Then stop state updates and event subscriptions before closing the session, and verify that switching content creates no calls against the closed session.
Network and platform policy
Wi-Fi, cellular, Ethernet, account eligibility, and quota policy are evaluated by the native SDK and console policy. The local P2P switch cannot override a server-side restriction. Do not pass region, areaCode, or Tracker/ICE endpoints as client options. Use getStatus() to inspect effectiveP2pEnabled and reason; a peer count of zero alone does not indicate a playback failure.
The playback URL uses an HTTP loopback proxy even for HTTPS origins. Configure both Android and iOS as described in Installation and setup, and confirm that the policy applies to Release builds. Merge exceptions into the application network policy. Restrict public HTTP origin exceptions to required domains; prefer HTTPS.
Lifecycle and background playback
When changing content or destroying a screen:
- Stop telemetry updates, await in-flight updates, and remove event subscriptions.
- Stop the player and release its current media reference.
- Close the current session and any unused preload candidates.
- Close the client only after no other active sessions need it.
Keep the player and session alive while authorized background or picture-in-picture playback continues. Configure background modes, audio sessions, and player capabilities in the host application. Navigating away from a page must follow your playback policy rather than automatically closing a background playback session. The SDK does not bypass operating-system limits or guarantee continuous background sharing.
await MeshStream.closeSession(client.clientId, session.sessionId)
await MeshStream.closeClient(client.clientId)
Capability boundary
The following table describes the current public Uniapp wrapper API. Use the wrapper options documented on this page rather than passing native-only properties:
| Capability | Current wrapper API |
|---|---|
| HLS / DASH / MP4 / MP3, origin headers, stable content IDs | Supported through session options |
| Multiple sessions, preload, P2P toggle, player telemetry, statistics | Supported through the methods above |
maxMemoryBytes, peer connection limits, request timeout, native log level | No public wrapper options currently exposed |
Apple setPictureInPictureActive | No public wrapper method currently exposed; not implied by player PiP support |
| Decoder, ABR, DRM, player cache, OS background permissions | Managed by the player and application |
P2P unavailability is not a media playback error. Keep using the valid session URL; base retries or termination on actual player errors and origin responses. Native initialization or bridge failures still need application error handling.
Related guides
Installation and setup · Quick integration · Troubleshooting