@clappr/telemetry:为 Clappr 播放器构建统一可扩展的遥测采集插件

发布时间:2026/9/28 2:21:27
@clappr/telemetry:为 Clappr 播放器构建统一可扩展的遥测采集插件 前端音视频插件系统【免费下载链接】clapprAn extensible, plugin-oriented, HTML5-first media player for the web项目地址https://gitcode.com/gh_mirrors/cl/clappr点击查看免费下载导读clappr/telemetry是 Clappr 生态中的官方遥测插件作为ContainerPlugin挂载在播放器容器上自动探测当前生效的播放引擎如 Shaka、HLS.js采集网络请求、缓冲状态、解码质量、播放状态、播放时序与流信息六大类指标并统一通过容器总线上的单一事件CONTAINER_TELEMETRY_TRACE对外分发。读完本文你将掌握该插件的安装接入方式、完整配置项语义、信封envelope数据格式以及如何基于网络适配器Adapters、采样器注册表SamplerRegistry和观察者注册表ObserverRegistry三大可扩展子系统自定义遥测能力用于构建 HUD 面板、播放质量监控和数据分析管线。一、插件定位与三大可扩展子系统clappr/telemetry是一个面向 Clappr 播放器的遥测采集插件它自动检测当前激活的播放引擎并激活对应的适配器。无论数据来自哪种引擎、哪种事件类型所有遥测数据都经由同一注册事件通道以带版本号的信封格式流动从而让消费者与内部实现细节彻底解耦。从源码结构看插件围绕三个可扩展子系统构建对应 packages/clappr-telemetry/src 下的三个目录网络适配器Network Adapters挂钩流媒体引擎Shaka、HLS.js的请求生命周期采集请求耗时、码率切换与 DRM 事件。注册表实现在 adapters/network_adapters.js两个内置适配器分别位于 adapters/shaka_network_adapter.js 与 adapters/hls_network_adapter.js。采样器注册表Sampler Registry由单一定时器驱动一组周期采样器每个 tick 发出一次mse.sample事件数据按 key 分组buffer、decoding、playbackState等。实现见 samplers/sampler_registry.js。观察者注册表Observer Registry管理处于激活状态的观察者并对每个观察者触发生命周期回调支持通过ObserverRegistry.register()扩展自定义观察者无需 fork 本包。实现见 observers/observer_registry.js。插件主类TelemetryPlugin继承自ContainerPlugin其supportedVersion声明为{ min: 0.13.1 }即要求 Clappr core 不低于 0.13.1实例化时通过Events.register(CONTAINER_TELEMETRY_TRACE)注册遥测事件通道见 telemetry_plugin.js。二、安装方式2.1 通过包管理器yarn add clappr/telemetry2.2 通过 CDNjsDelivrscript srchttps://cdn.jsdelivr.net/npm/clappr/telemetry/dist/clappr-telemetry.js/script三、快速接入完整可运行示例3.1 CDN 全局变量方式按顺序引入clappr/core、dash-shaka-playback与clappr/telemetry从全局ClapprTelemetry中解构需要的组件再通过telemetry配置项激活script srchttps://cdn.jsdelivr.net/npm/clappr/core/dist/clappr-core.js/script script srchttps://cdn.jsdelivr.net/npm/dash-shaka-playback/dist/dash-shaka-playback.js/script script srchttps://cdn.jsdelivr.net/npm/clappr/telemetry/dist/clappr-telemetry.js/script div idplayer/div script const { ShakaNetworkAdapter, HlsNetworkAdapter, BufferSampler, DecodingSampler, PlaybackStateSampler, NetworkSampler, PlaybackTimingSampler, StreamInfoSampler, VideoEventObserver } ClapprTelemetry const player new Clappr.Player({ parentId: #player, source: https://example.com/stream.mpd, plugins: [DashShakaPlayback, ClapprTelemetry], telemetry: { adapters: [ShakaNetworkAdapter, HlsNetworkAdapter], samplers: [ BufferSampler, DecodingSampler, PlaybackStateSampler, NetworkSampler, PlaybackTimingSampler, StreamInfoSampler ], observers: [VideoEventObserver], sampleIntervalMs: 1000 } }) /script3.2 npm/ESM 方式import Clappr from clappr/core import DashShakaPlayback from dash-shaka-playback import ClapprTelemetry, { ShakaNetworkAdapter, HlsNetworkAdapter, BufferSampler, DecodingSampler, PlaybackStateSampler, NetworkSampler, PlaybackTimingSampler, StreamInfoSampler, VideoEventObserver } from clappr/telemetry const player new Clappr.Player({ parentId: #player, source: https://example.com/stream.mpd, plugins: [DashShakaPlayback, ClapprTelemetry], telemetry: { adapters: [ShakaNetworkAdapter, HlsNetworkAdapter], samplers: [ BufferSampler, DecodingSampler, PlaybackStateSampler, NetworkSampler, PlaybackTimingSampler, StreamInfoSampler ], observers: [VideoEventObserver], sampleIntervalMs: 1000 } })注意sampleIntervalMs: 1000表示每隔 1000ms 触发一次采样 tick若设为默认值0则不启动定时器只能通过snapshot()按需采集详见后文。四、Named exports完整的模块导出清单ES Modules 构建产物为dist/clappr-telemetry.esm.js。以下导出均可从包名直接导入。4.1 适配器AdaptersExportDescriptionNetworkAdapters注册表类——用于注册/注销适配器默认不预注册任何适配器ShakaNetworkAdapterShaka 网络指标适配器类——必须显式注册HlsNetworkAdapterHLS.js 网络指标适配器类——必须显式注册4.2 采样器SamplersExportDescriptionSamplerRegistry注册表类——用于注册自定义采样器BufferSampler内置缓冲状态采样器DecodingSampler内置解码质量采样器PlaybackStateSampler内置采样器采集networkState、paused、playbackRate与码率NetworkSampler内置采样器采集请求计数器、吞吐量与分段指标PlaybackTimingSampler内置采样器采集timePlayingMs、timeWaitingMs与joinTimeMsStreamInfoSampler内置采样器采集流元数据容器格式、编解码器、变体数量4.3 观察者ObserversExportDescriptionObserverRegistry注册表类——用于注册自定义观察者VideoEventObserver内置观察者监听原生videoDOM 事件4.4 工具函数UtilsExportDescriptionTELEMETRY_CONTRACT_VERSION每个信封v字段携带的语义化版本字符串EVENT_TYPES规范化的type字符串request:start、mse.sample等TELEMETRY_SOURCES规范化的source取值如networkcreateEnvelope构建带版本的信封对象emitTelemetry在 emitter 上触发Events.Custom.CONTAINER_TELEMETRY_TRACEcalculateThroughput网络适配器使用的 Mbps 吞吐量计算辅助函数getBufferAhead返回当前位置前方已缓冲的秒数getBufferedRanges将TimeRanges转换为紧凑的[[start, end], ...]数组DEFAULT_VIDEO_EVENTS包含 14 个默认HTMLVideoElement事件名的数组需要特别说明的是UMD 构建dist/clappr-telemetry.js/ CDN只暴露插件本身作为全局ClapprTelemetry。在任何构建中适配器都不会预注册必须通过ClapprTelemetry.NetworkAdapters显式注册。五、配置项全解5.1 顶层配置表所有选项均为选配opt-in——默认不采集任何数据。组件通过在对应数组中放入其类来激活。OptionTypeDefaultDescriptiontelemetry.enabledBooleantrue设为false可整体禁用此播放器实例的遥测插件telemetry.adaptersClass[][]本实例要激活的网络适配器类。数组中第一个isSupported(playback)返回true的适配器被使用telemetry.samplersClass[][]本实例要注册的采样器类telemetry.observersClass[][]本实例要注册的观察者类telemetry.sampleIntervalMsNumber0采样间隔毫秒。为0默认时不启动自动定时器——改用snapshot()按需采集telemetry.id.enabledBooleantrue对任意已注册组件的退出开关。key 为组件的static get id()值如buffer、decoding、videoStatetelemetry.bufferSample.includeRangesBooleantrue是否在mse.sample载荷中包含缓冲时间范围telemetry.videoState.videoEventsString[]14 eventsVideoEventObserver要监听的HTMLVideoElement事件名。默认为完整列表见VideoEventObserver一节5.2 按组件粒度禁用opt-out每个实例只激活自己的samplers/observers/adapters数组。当多个播放器共享同一个配置对象时可用id.enabled: false只禁用某一个实例中的某个组件而不必改动共享数组new Clappr.Player({ telemetry: { samplers: [BufferSampler, DecodingSampler, NetworkSampler, ...], observers: [VideoEventObserver], // 按 static get id() 的值禁用指定组件 decoding: { enabled: false }, videoState: { enabled: false }, } })idkey 与各组件类的static get id()的映射关系ClassKeyBufferSamplerbufferDecodingSamplerdecodingPlaybackStateSamplerplaybackStateNetworkSamplernetworkPlaybackTimingSamplertimingStreamInfoSamplerstreamInfoVideoEventObservervideoState从源码看这个 opt-out 判断由工具函数isComponentEnabled统一实现utils/index.js先检查类上是否定义了static isEnabled(cfg)且返回 falsy再检查cfg[Cls.id]?.enabled ! false两个条件都必须通过AND 关系。采样器注册表在构造函数中正是用isComponentEnabled(S, cfg)过滤cfg.samplers见 sampler_registry.js观察者注册表同理observer_registry.js。5.3 插件内部初始化流程从 telemetry_plugin.js 的onPlaybackRead实现可以梳理出插件的激活时序理解这个顺序有助于排查配置不生效的问题读取container.options.telemetry若缺失或enabled false直接返回先注销上一轮配置的采样器/适配器/观察者再按当前配置注册注册失败返回false的类会被剔除并记录本次实际注册成功的类以便销毁时清理先绑定 SamplerRegistry再绑定适配器——这样适配器bind()期间触发的事件如 ShakaattachFilters时的STREAM_INFO才能被采样器捕获创建 ObserverRegistry 并绑定先销毁旧适配器避免切换源后旧适配器仍挂在过期 playback 上再通过NetworkAdapters.find(playback, cfg)寻找可用适配器实例化并bind()若配置了适配器但无匹配则输出No network adapter for playback: ...的警告日志。插件的snapshotgetter 直接委托给samplerRegistry.snapshot()在注册表尚未初始化时返回空对象telemetry_plugin.js。六、消费遥测事件所有遥测数据都通过插件注册的唯一事件发出Clappr.Events.Custom.CONTAINER_TELEMETRY_TRACE推荐在自定义ContainerPlugin中消费该事件由容器自动处理生命周期与清理class MyTelemetryConsumer extends Clappr.ContainerPlugin { get name() { return my_telemetry_consumer } get supportedVersion() { return { min: 0.13.1 } } bindEvents() { this.listenTo(this.container, Clappr.Events.Custom.CONTAINER_TELEMETRY_TRACE, this.onTrace) } onTrace(envelope) { if (envelope.type mse.sample) { const { buffer, decoding, playbackState } envelope.data } if (envelope.type media.event) { const { name, currentTime, readyState, snapshot } envelope.data } } }该事件在 TelemetryPlugin 实例化时注册是插件对外承诺的公共契约。消费者永远不需要知道当前激活的是哪个适配器或引擎——它们始终监听同一个事件、收到同一种信封结构。七、信封Envelope格式每次在CONTAINER_TELEMETRY_TRACE上发出的事件都携带一个带版本的信封FieldTypeDescriptiontypestring发生了什么——标识事件在其来源领域内的具体类型sourcestring来自哪里——哪个遥测领域发出了该事件dataobject事件专属载荷随type变化tnumber单调时间戳来自performance.now()tsnumber墙钟时间戳来自Date.now()vstring信封契约版本当前为1.0信封的构造实现在 utils/helpers.js 的createEnvelope版本常量TELEMETRY_CONTRACT_VERSION 1.0定义于 utils/constants.js。发送过程由emitTelemetry封装构造信封后调用emitter.trigger(Events.Custom.CONTAINER_TELEMETRY_TRACE, envelope)触发失败仅打印警告、不会抛出helpers.js。八、网络适配器Adapters8.1 适配器与引擎对应关系适配器将插件连接到具体的播放引擎。每个适配器实现static isSupported(playback)与bind()。AdapterEngineStatusShakaNetworkAdapterdash-shaka-playbackAvailableHlsNetworkAdapterhlsjs-playbackAvailableShakaNetworkAdapter.isSupported判断playback.name dash_shaka_playbackHlsNetworkAdapter.isSupported判断playback.name hls。8.2 注册适配器所有适配器——包括内置的——都必须在播放器实例化之前注册。最先注册的适配器优先级最高import { NetworkAdapters, ShakaNetworkAdapter, HlsNetworkAdapter } from clappr/telemetry NetworkAdapters.register(ShakaNetworkAdapter) NetworkAdapters.register(HlsNetworkAdapter) // 自定义适配器同样可以注册 NetworkAdapters.register(MyCustomAdapter) // 不再需要时注销 NetworkAdapters.unregister(MyCustomAdapter)NetworkAdapters.find会按cfg.adapters数组顺序查找跳过未注册、isEnabled(cfg)返回 falsy、或cfg[adapter.id]?.enabled false的类返回第一个isSupported(playback)为 true 的适配器network_adapters.js。注册是引用计数的unregister只有在引用计数归零时才真正从注册表移除network_adapters.js同时校验类上必须存在静态isSupported方法network_adapters.js。8.3 适配器契约MemberDescriptionstatic get id()Opt-out keyid.enabled由NetworkAdapters.find()读取。需要按组件退出时必填static isSupported(playback)当该适配器能处理给定 playback 时返回trueconstructor(playback, container)接收播放引擎与容器bind()向引擎挂接监听器/钩子destroy()摘除监听器并释放资源8.4 适配器的数据采集原理源码视角Shaka 适配器通过shakaPlayer.getNetworkingEngine()注册请求过滤器request filter与响应过滤器response filter并监听trackschanged、variantchanged、drmsessionupdate、expirationupdated等 Shaka 事件。请求过滤器发出request:start响应过滤器发出request:end附带durationMs、bytes、throughputMbps与throughputEwmaMbps变体切换发出bitrate:change携带前后 bitrate/width/heightdrmsessionupdate发出drm:session:updateexpirationupdated发出drm:expiration:updated。值得注意的隐私设计DRM 许可服务器 URI 会经sanitizeLicenseUri处理只保留 origin 与查询参数名、剥离参数值避免泄露凭证或设备标识helpers.jsURL 本身则用 FNV-1a 32 位哈希为 8 位十六进制urlHash避免在遥测载荷中传输原始 URLhelpers.js。HLS.js 适配器在hls.on()上挂接hlsFragLoading/hlsFragLoaded/hlsManifestLoading/hlsManifestLoaded/hlsKeyLoading/hlsKeyLoaded/hlsLevelSwitched/hlsError事件用fragKey${sn}_${level}_${url}把 loading/loaded 事件配对以计算请求时长分段请求被归类为segment/init/subtitle三种 kind支持从分片扩展名推断容器为HLS/fMP4或HLS/TS。若 HLS 实例尚未就绪会在CONTAINER_PLAY时重试挂接hls_network_adapter.js。hlsError中type networkError的错误会发request:errorhls_network_adapter.jspendingRequests 达到上限100 条时按批次20 条淘汰最旧条目并补发request:errorhls_network_adapter.js。8.5 SourcessourcesourceAreanetwork网络请求指标分段、manifest、许可sampler-registry周期性的 MSE 指标buffer、decoding、播放状态video-event-observer原生videoDOM 事件九、事件类型type总表typesourceDescriptionrequest:startnetwork一个网络请求已发起request:endnetwork一个网络请求已完成request:errornetwork一个网络请求失败bitrate:initnetwork初始质量变体已知首个分段加载完成bitrate:changenetworkABR 算法切换到了不同的质量变体stream:infonetwork流元数据可用manifest 加载完成或变体切换drm:session:updatenetworkDRM 会话被更新drm:expiration:updatednetworkDRM 许可过期时间被更新mse.samplesampler-registrybuffer、decoding 与/或播放状态的周期性快照media.eventvideo-event-observer一个原生HTMLVideoElementDOM 事件触发这些规范字符串在 utils/constants.js 中统一定义EVENT_TYPES并额外包含内部使用的error与telemetry_bus两个值。十、mse.sample载荷详解SamplerRegistry每个 tick 发出一次。只有当对应采样器启用且有数据可报时对应 key 才会出现decodingkey 在首个 tick 缺失因为基线正在建立。以下为完整载荷示例{ buffer: { bufferAhead: 20, // 当前位置前方已缓冲的秒数 currentTime: 10, // 当前播放位置秒 rangesCompact: [[0, 30]] // 缓冲时间范围includeRanges: false 时省略 }, decoding: { decodedFps: 24, // 区间内每秒解码帧数 droppedFps: 1, // 区间内每秒丢帧数 dropRatio: 0.04, // 区间内丢帧占总帧数比例 currentTime: 10, // 当前播放位置秒 totalDropped: 2, // 播放开始以来的累计丢帧数 totalDecoded: 537 // 播放开始以来的累计解码帧数 }, playbackState: { networkState: 2, // HTMLVideoElement.networkState0–3 paused: false, // 是否暂停 playbackRate: 1, // 当前播放速率 currentTime: 10, // 当前播放位置秒 bitrateKbps: 4500, // 当前 ABR 变体码率kbps首个分段前为 null width: 1920, // 当前变体水平分辨率首个分段前为 null height: 1080, // 当前变体垂直分辨率首个分段前为 null switchesUp: 2, // 播放开始以来 ABR 升级累计次数 switchesDown: 0 // 播放开始以来 ABR 降级累计次数 }, network: { throughputEwmaMbps: 18.4, // 指数加权移动平均吞吐量Mbps lastThroughputMbps: 20.1, // 最近一次完成的分段请求吞吐量 activeRequests: 1, // 在途请求数 segmentsLoaded: 42, // 成功加载的分段累计数 segmentErrors: 0, // 分段请求失败累计数 totalBytesKB: 8320, // 累计下载字节数仅分段 avgSegmentLoadTimeMs: 210, // 平均分段加载耗时ms首个分段前为 null licenseRequests: 1, // DRM 许可请求累计数 licenseErrors: 0, // DRM 许可失败累计数 fatalErrors: 0, // 适配器致命错误累计数 drmExpirationTime: null, // DRM 许可过期时间戳ms未设置时为 null networkQuality: { label: good, score: 0.9 }, // 吞吐量档位分类 networkAdequacy: { label: adequate, score: 0.8 }, // 相对当前码率的吞吐量充分度 segmentHistory: [...] // 近期的分段加载记录 }, timing: { timePlayingMs: 120000, // 处于播放状态的累计毫秒数 timeWaitingMs: 3200, // 处于等待/缓冲状态的累计毫秒数 joinTimeMs: 850, // 从 play() 到首个 playing 事件的毫秒数首次播放前为 null autoplayStartupTimeMs: 1200, // 未调用 play() 时到达首帧的毫秒数手动播放时为 null manifestLoadTimeMs: 320, // 首次 manifest 加载耗时ms未收到网络 trace 前为 null firstSegmentLoadTimeMs: 180 // 首个分段加载耗时ms未收到网络 trace 前为 null }, streamInfo: { container: MP4, // 由视频 MIME 类型推导的容器格式 videoCodec: avc1, // 解析出的视频编解码器字符串 audioCodec: mp4a, // 解析出的音频编解码器字符串 levelsCount: 8 // 变体轨道总数 } }采样器注册表的_tick实现印证了这一点先调用snapshot()汇总所有采样器数据仅当结果非空时才发出mse.samplesampler_registry.js。snapshot()会逐个调用每个采样器的collect()返回null的采样器其 key 被省略collect()抛出的异常会被捕获并仅记录警告sampler_registry.js。十一、VideoEventObserver原生 video 事件观察者VideoEventObserver监听原生HTMLVideoElement与引擎无关——无论 Shaka、HLS.js 还是其他播放引擎其行为完全一致。每当video元素上触发某个被观察的 DOM 事件它就发出media.event{ name: waiting, // DOM 事件名 currentTime: 10.4, // 事件发生瞬间的位置 readyState: 2, // HTMLVideoElement.readyState snapshot: { // 事件瞬间的采样器数据 buffer: { bufferAhead: 0.2, currentTime: 10.4 }, decoding: { decodedFps: 24, droppedFps: 0, ... }, playbackState: { networkState: 2, paused: false, playbackRate: 1, currentTime: 10.4 } } }snapshot反映的是最近一次采样 tick 的数据。只有对应采样器启用时 key 才会出现若没有任何采样器激活snapshot为{}。观察者通过addEventListener(eventName, handler, { passive: true })挂接监听video_event_observer.js事件名列表经Set去重。默认观察的事件14 个waiting、playing、stalled、seeking、seeked、ended、canplay、canplaythrough、loadedmetadata、loadeddata、error、emptied、suspend、abort。该列表定义于DEFAULT_VIDEO_EVENTSconstants.js。配置方式把VideoEventObserver放进observers数组即可激活。用videoState.videoEvents收窄观察的事件列表new Clappr.Player({ plugins: [ClapprTelemetry], telemetry: { observers: [VideoEventObserver], videoState: { videoEvents: [waiting, stalled, error] // 默认上文完整列表 } } })十二、自定义采样器采样器注册表是可扩展的。你可以添加自己的采样器让它参与同一个mse.sampletick而无需 fork 本包。12.1 契约MemberRequiredDescriptionstatic get id()Yes唯一字符串 key——用作注册表标识同时用作mse.sample载荷中的 keycollect()Yes每个 tick 被调用。返回一个包含待上报数据的普通对象或返回null跳过本次 tickdestroy()Yes注册表销毁时被调用。在此清理内部状态static isEnabled(cfg)No覆盖注册表默认的启用/禁用判断。cfg为container.options.telemetry。省略则使用标准的cfg[id].enabled退出开关注册校验在SamplerRegistry.register中完成要求类有非空static get id()原型上有collect()与destroy()方法缺失任何一项都会打印警告并返回false若新注册的类与已有同 id 类冲突会警告并覆盖已有类sampler_registry.js。12.2 示例AudioSamplerimport { SamplerRegistry } from clappr/telemetry class AudioSampler { static get id() { return audio } constructor(playback) { this._playback playback } collect() { const videoEl this._playback?.el if (!videoEl) return null return { volume: videoEl.volume, muted: videoEl.muted } } destroy() { this._playback null } } // 在实例化播放器之前注册 SamplerRegistry.register(AudioSampler) new Clappr.Player({ plugins: [ClapprTelemetry], telemetry: { samplers: [AudioSampler], sampleIntervalMs: 1000 } })结果会以audio为 key 出现在mse.sample载荷中{ buffer: { ... }, decoding: { ... }, playbackState: { ... }, audio: { volume: 1, muted: false } }移除已注册的采样器SamplerRegistry.unregister(AudioSampler)12.3 按需快照on-demand snapshotTelemetryPlugin暴露一个snapshotgetter可立即返回当前采样器数据无需等待下一个 tick也不发出任何事件const telemetry player.getPlugin(telemetry) const data telemetry.snapshot // { buffer: { bufferAhead: 20, currentTime: 10 }, decoding: { ... }, playbackState: { ... } }在播放器就绪之前调用会返回空对象这也是snapshotgetter 用?? {}兜底的原因见 telemetry_plugin.js。十三、自定义观察者观察者注册表同样可扩展自定义观察者可与内置观察者一起被统一管理。13.1 契约MemberRequiredDescriptionstatic get id()Yes唯一字符串 key——用作注册表标识bind()Yes实例化后被调用。在此挂接事件监听器并开始采集destroy()Yes注册表销毁时被调用。移除监听器并清理状态static isEnabled(cfg)No覆盖注册表默认的启用/禁用判断。省略则使用标准的cfg[id].enabled退出开关构造函数接收(playback, container, samplerRegistry)——与VideoEventObserver的参数相同。注册时同样校验静态 id、原型bind()与destroy()三个要件observer_registry.js。13.2 示例PlaybackEventObserverimport { ObserverRegistry } from clappr/telemetry class PlaybackEventObserver { static get id() { return playbackEvents } constructor(playback, container, samplerRegistry) { this._container container this._samplerRegistry samplerRegistry } bind() { this._container.on(playback:play, () { console.log(play, this._samplerRegistry?.snapshot()) }) } destroy() { this._container null this._samplerRegistry null } } // 在实例化播放器之前注册 ObserverRegistry.register(PlaybackEventObserver) new Clappr.Player({ plugins: [ClapprTelemetry], telemetry: { observers: [PlaybackEventObserver] } })移除已注册的观察者ObserverRegistry.unregister(PlaybackEventObserver)十四、在 monorepo 中开发调试本包位于 Clappr monorepo 的packages/clappr-telemetry目录。依赖需在仓库根目录一次性安装构建、开发服务器与测试应通过yarn workspace clappr/telemetry运行以确保 Yarn 正确解析 workspace# 在 monorepo 根目录而不是只在包内执行 yarn install yarn workspace clappr/telemetry build yarn workspace clappr/telemetry dev # Vite demo地址 http://localhost:8080 yarn workspace clappr/telemetry test # Vitest yarn workspace clappr/telemetry test:watch演示页面demo直接从源码解析兄弟包无需先构建clappr/core或dash-shaka-playback即可打开 Vite 开发服务器。本包源码结构如下插件主类位于 telemetry_plugin.js模块出口汇总于 main.js适配器、采样器、观察者与工具函数分别位于 src/adapters、src/samplers、src/observers 与 src/utils每个模块均配有对应的*.test.js测试文件如 sampler_registry.test.js、video_event_observer.test.js可作契约参考。十五、典型应用场景小结结合上述机制clappr/telemetry的典型落地场景包括播放质量 HUD/仪表盘用自定义ContainerPlugin监听CONTAINER_TELEMETRY_TRACE将mse.sample中的buffer、decoding、network数据实时渲染为面板QoE 指标上报消费timing中的joinTimeMs、timeWaitingMs与media.event中的waiting/stalled事件计算首屏耗时与卡顿率ABR 行为分析跟踪bitrate:init/bitrate:change与playbackState中的switchesUp/switchesDown评估码率自适应策略DRM 与许可监控消费drm:session:update与drm:expiration:updated在许可过期前预警多实例差异化配置通过共享配置 id.enabled: false按实例粒度关闭不需要的采集项。许可证BSD-3-Clause。赞分享前端音视频插件系统【免费下载链接】clapprAn extensible, plugin-oriented, HTML5-first media player for the web项目地址https://gitcode.com/gh_mirrors/cl/clappr点击查看免费下载相关推荐Clappr一个高度可扩展的Web媒体播放器Clappr一个高度可扩展的Web媒体播放器 项目介绍 Clappr 是一款专为Web应用程序设计的高度可扩展媒体播放器。它基于HTML5技术优先考虑现代浏前端音视频插件系统Clappr错误日志收集终极指南5步构建播放器问题反馈系统Clappr错误日志收集终极指南5步构建播放器问题反馈系统 Clappr作为一款开源的HTML5视频播放器在实际应用中难免会遇到各种播放问题。如何快速定位并前端音视频插件系统如何在Intel GPU上高效运行CUDA应用ZLUDA完整实战配置指南如何在Intel GPU上高效运行CUDA应用ZLUDA完整实战配置指南 ZLUDA是一款创新的开源工具能够让CUDA应用在非NVIDIA GPU上运行特高性能计算编译器上一篇Vim-dirvish配置指南打造个性化的目录浏览体验下一篇TerraBoard: 可视化并查询Terraform状态的Web控制台创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考