rivmux 1.0.0-rc.1 → 1.0.1
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 +130 -62
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -10
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
# Rivmux Player
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> A Rust/WebAssembly-powered, low-latency HTTP-FLV player for modern browsers.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`rivmux`(Riv 源自拉丁语 _rivus_,意为“河流”;Mux 指媒体封装/复用;读作 `/ˈrɪvmʌks/`)是一款面向现代浏览器的低延迟 HTTP-FLV 播放器。它在 Dedicated Worker 中读取流数据,通过 Rust/WebAssembly 转封装核心生成 fragmented MP4,再借助 Worker MSE 驱动 `<video>`。网络读取与媒体处理远离主线程,同时向应用提供清晰的生命周期、可调缓冲策略和结构化诊断。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 安装与运行要求
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
10
|
pnpm add rivmux
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
npm install rivmux
|
|
15
|
-
```
|
|
13
|
+
`rivmux` 以 ESM-only 格式发布,面向浏览器 ESM Bundler,不提供 CommonJS、UMD 或全局变量构建。Vite 已完成验证,其他 bundler 暂不形成兼容承诺。
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
Node.js 仅支持 ESM 导入以及 SSR/能力探测调用,不提供播放运行时。浏览器播放依赖 Dedicated Worker、Worker MSE、流式 Fetch、ReadableStream 和 WebAssembly;当前没有主线程 MSE 降级路径。
|
|
18
16
|
|
|
19
|
-
##
|
|
17
|
+
## 快速开始
|
|
20
18
|
|
|
21
|
-
调用 `start()` 前必须等待 `attach()` 完成。`attach()` 会初始化 Worker
|
|
19
|
+
调用 `start()` 前必须等待 `attach()` 完成。`attach()` 会初始化 Worker,并将内部 `MediaSourceHandle` 连接到 `<video>` 元素。
|
|
22
20
|
|
|
23
21
|
```ts
|
|
24
22
|
import { RivmuxPlayer } from 'rivmux'
|
|
@@ -51,7 +49,23 @@ await player.stop()
|
|
|
51
49
|
await player.destroy()
|
|
52
50
|
```
|
|
53
51
|
|
|
54
|
-
##
|
|
52
|
+
## 支持范围与能力探测
|
|
53
|
+
|
|
54
|
+
### Codec 支持边界
|
|
55
|
+
|
|
56
|
+
| 输入 | 等级 | 说明 |
|
|
57
|
+
| ---------------------------------------- | ------------ | ---------------------------------- |
|
|
58
|
+
| HTTP-FLV + AVC/H.264 + AAC-LC | Stable | 受浏览器基础 MSE 能力约束 |
|
|
59
|
+
| Enhanced HTTP-FLV + HEVC/`hvc1` + AAC-LC | Stable | 浏览器解码能力是条件化的 |
|
|
60
|
+
| Enhanced HTTP-FLV + AV1 | Experimental | 实现层实验能力,组合与兼容性未承诺 |
|
|
61
|
+
| Enhanced HTTP-FLV + Opus | Experimental | 实现层实验能力,组合与兼容性未承诺 |
|
|
62
|
+
| MPEG-TS | 不支持 | 不属于当前产品输入边界 |
|
|
63
|
+
|
|
64
|
+
HEVC Stable 的具体范围是单视频轨、固定 codec 配置、Enhanced FLV `SequenceStart`、`CodedFrames` 和 HEVC `CodedFramesX`,输出 sample entry 为 `hvc1`。最终解码能力取决于浏览器、操作系统、设备以及具体 HEVC profile、level、bit depth 和 chroma format;Rivmux 不维护固定 profile/level allowlist。结构合法但环境不支持准确 MIME 时会产生终止错误 `RIVMUX_UNSUPPORTED_MSE_CODEC`。
|
|
65
|
+
|
|
66
|
+
`hev1`、多轨 HEVC、播放期间动态 codec 配置切换和 HEVC + Opus 不属于 Stable 范围。AV1 与 Opus 仍为 Experimental;当前未承诺它们与其他音视频 codec 的组合、浏览器兼容矩阵或稳定错误语义。
|
|
67
|
+
|
|
68
|
+
### 运行环境探测
|
|
55
69
|
|
|
56
70
|
创建播放器前可同步读取基础运行环境和解码能力:
|
|
57
71
|
|
|
@@ -63,7 +77,7 @@ if (!isSupported()) {
|
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
const capabilities = getCapabilities()
|
|
66
|
-
console.log(capabilities
|
|
80
|
+
console.log(capabilities)
|
|
67
81
|
```
|
|
68
82
|
|
|
69
83
|
```ts
|
|
@@ -88,15 +102,11 @@ type RivmuxCapabilities = {
|
|
|
88
102
|
aac: SupportStatus
|
|
89
103
|
opus: SupportStatus
|
|
90
104
|
}
|
|
91
|
-
stableProfiles: {
|
|
92
|
-
avcAac: SupportStatus
|
|
93
|
-
hevcAac: SupportStatus
|
|
94
|
-
}
|
|
95
105
|
}
|
|
96
106
|
}
|
|
97
107
|
```
|
|
98
108
|
|
|
99
|
-
`isSupported()` 始终等于 `getCapabilities().supported`。这里的 `supported`
|
|
109
|
+
`isSupported()` 始终等于 `getCapabilities().supported`。这里的 `supported` 只表示基础运行条件可用,不保证具体媒体流能够播放。
|
|
100
110
|
|
|
101
111
|
解码矩阵通过同步的 `MediaSource.isTypeSupported()` 对代表性 codec 执行前置判断:`supported` 表示环境报告支持,`unsupported` 表示环境明确拒绝,`unknown` 表示 API 不可用或无法可靠判断。该结果不会改变输入的 Stable、Experimental 或不支持边界,也不替代真实流校验。Rivmux 取得实际 codec、profile 和 level 后,仍会使用准确 MIME 做最终 MSE 校验。
|
|
102
112
|
|
|
@@ -108,23 +118,22 @@ type RivmuxCapabilities = {
|
|
|
108
118
|
const player = new RivmuxPlayer(url, options)
|
|
109
119
|
```
|
|
110
120
|
|
|
111
|
-
|
|
|
121
|
+
| 调用或属性 | 含义 |
|
|
112
122
|
| --------------------------------- | ------------------------------------------------------------ |
|
|
113
123
|
| `new RivmuxPlayer(url, options?)` | 为一个流地址创建播放器实例。 |
|
|
124
|
+
| `player.url` | 构造播放器时传入的只读流地址。 |
|
|
114
125
|
| `await player.attach(video)` | 绑定 `<video>` 元素并准备 Worker/MSE 链路。 |
|
|
115
126
|
| `await player.start()` | 启动加载、转封装、缓冲与播放控制;必须在 `attach()` 后调用。 |
|
|
116
|
-
| `await player.stop()` |
|
|
127
|
+
| `await player.stop()` | 停止加载并解绑媒体源;无需重新 `attach()` 即可再次启动。 |
|
|
117
128
|
| `await player.destroy()` | 释放 Worker、定时器、监听器和媒体源;实例不可再用。 |
|
|
118
129
|
| `player.on(type, listener)` | 订阅播放器事件。 |
|
|
119
130
|
| `player.off(type, listener)` | 移除先前注册的监听器。 |
|
|
120
131
|
|
|
121
|
-
`attach()` 完成只表示媒体源句柄已经连接;`start()` 完成只表示 Worker
|
|
122
|
-
|
|
123
|
-
同一启动过程中的并发 `start()` 调用会等待同一个操作,不会重复发送启动命令。播放器已经启动后再次调用 `start()` 会直接完成。若 `stop()` 或 `destroy()` 在启动确认前开始,待处理的 `start()` 会以 `RIVMUX_START_CANCELLED` 拒绝,而停止或销毁操作仍会正常完成。终止错误会使 `start()` 以相同错误码拒绝。
|
|
132
|
+
`attach()` 完成只表示媒体源句柄已经连接;`start()` 完成只表示 Worker 已建立本次启动所需的加载、转封装和 MSE 会话。两者都不表示已经解析出媒体信息、已经追加首个媒体片段,也不表示 `<video>` 已触发 `canplay` 或开始播放。请通过 `mediaInfo`、`stats`、`error` 和 video 元素事件观察后续结果。
|
|
124
133
|
|
|
125
|
-
|
|
134
|
+
同一启动过程中的并发 `start()` 调用会等待同一个操作,不会重复发送启动命令。播放器已经启动后再次调用 `start()` 会直接完成。若 `stop()` 或 `destroy()` 在启动确认前开始,待处理的 `start()` 会以 `RIVMUX_START_CANCELLED` 拒绝,而停止或销毁操作仍会正常完成。启动确认前发生的终止错误会使待处理的 `start()` 以相同错误码拒绝;启动确认后的错误通过 `error` 事件报告。
|
|
126
135
|
|
|
127
|
-
##
|
|
136
|
+
## 配置
|
|
128
137
|
|
|
129
138
|
所有配置均为可选项,缺省字段会由播放器内部默认值补齐。
|
|
130
139
|
|
|
@@ -164,10 +173,10 @@ const player = new RivmuxPlayer('https://example.com/live.flv', {
|
|
|
164
173
|
|
|
165
174
|
### `playback`
|
|
166
175
|
|
|
167
|
-
| 配置项 | 默认值 | 含义
|
|
168
|
-
| ---------- | ------- |
|
|
169
|
-
| `autoPlay` | `true` | 启动缓冲足够时,由运行时请求 `video.play()`。
|
|
170
|
-
| `muted` | `false` | 设置 `video.muted
|
|
176
|
+
| 配置项 | 默认值 | 含义 |
|
|
177
|
+
| ---------- | ------- | -------------------------------------------------------------------- |
|
|
178
|
+
| `autoPlay` | `true` | 启动缓冲足够时,由运行时请求 `video.play()`。 |
|
|
179
|
+
| `muted` | `false` | 设置 `video.muted`;浏览器通常要求媒体静音后才能无用户手势自动播放。 |
|
|
171
180
|
|
|
172
181
|
### `latency`
|
|
173
182
|
|
|
@@ -193,6 +202,8 @@ const player = new RivmuxPlayer('https://example.com/live.flv', {
|
|
|
193
202
|
| `retry.maxBackoffMs` | `8000` | 应用抖动后的最大退避延迟,单位为毫秒。 |
|
|
194
203
|
| `retry.jitterRatio` | `0.2` | 对称抖动比例,取值范围为 `0` 至 `1`;`0` 表示关闭抖动。 |
|
|
195
204
|
|
|
205
|
+
跨源 HTTP-FLV 地址必须满足浏览器 CORS 规则。使用自定义请求头或 `credentials: 'include'` 时,流服务还需正确处理预检请求并允许相应的请求头和凭据;配置错误可能表现为网络异常并进入重试,但不会通过重连自行恢复。
|
|
206
|
+
|
|
196
207
|
### `runtime`
|
|
197
208
|
|
|
198
209
|
`runtime.workerUrl` 和 `runtime.wasmUrl` 是 Experimental 资产部署覆盖项;它们嵌套在稳定的 `RivmuxPlayerOptions` 形状中,但不改变当前固定的 Worker MSE runtime,也不承诺跨 bundler、CSP 或部署方式的长期兼容性。
|
|
@@ -202,30 +213,15 @@ const player = new RivmuxPlayer('https://example.com/live.flv', {
|
|
|
202
213
|
| `workerUrl` | 包内 Worker URL | 高级配置,用于覆盖包内 Dedicated Worker 脚本 URL。 |
|
|
203
214
|
| `wasmUrl` | 包内 WASM 模块 URL | 高级配置,用于覆盖 WASM URL;必须与包含 wasm-bindgen 胶水的 Worker 版本匹配。 |
|
|
204
215
|
|
|
205
|
-
### Worker/WASM 资产部署
|
|
206
|
-
|
|
207
|
-
多数应用无需设置 `runtime.workerUrl` 和 `runtime.wasmUrl`。默认资产 URL 会被 Vite 等打包工具跟踪,并随应用构建输出。
|
|
208
|
-
|
|
209
|
-
只有在固定公共路径或 CDN 部署 Rivmux 资产时才需要覆盖:
|
|
210
|
-
|
|
211
|
-
```ts
|
|
212
|
-
const player = new RivmuxPlayer('https://example.com/live.flv', {
|
|
213
|
-
runtime: {
|
|
214
|
-
workerUrl: 'https://cdn.example.com/rivmux/0.5.0/rivmux-runtime-worker.js',
|
|
215
|
-
wasmUrl: 'https://cdn.example.com/rivmux/0.5.0/rivmux-transmux-core.wasm',
|
|
216
|
-
},
|
|
217
|
-
})
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
`workerUrl` 不会推导 `wasmUrl`。覆盖两项时必须发布同一版本的 Worker/WASM 资产对,并使用相同缓存版本策略。两者都是可执行资产地址,不得由不可信输入拼接。宿主应用需配置兼容的 CSP 和 CORS,并以 `application/wasm` 提供 WASM 文件。
|
|
221
|
-
|
|
222
216
|
### `diagnostics`
|
|
223
217
|
|
|
224
218
|
| 配置项 | 默认值 | 含义 |
|
|
225
219
|
| ----------------- | ------ | ------------------------------------------------------------ |
|
|
226
220
|
| `statsIntervalMs` | `1000` | 请求的统计上报间隔,单位为毫秒;运行时会在内部限制实际范围。 |
|
|
227
221
|
|
|
228
|
-
##
|
|
222
|
+
## 事件与错误
|
|
223
|
+
|
|
224
|
+
### 事件
|
|
229
225
|
|
|
230
226
|
```ts
|
|
231
227
|
import type { MediaInfo, PlayerError, PlayerStats, PlayerWarning, ReconnectInfo, RecoveryInfo } from 'rivmux'
|
|
@@ -255,7 +251,63 @@ player.on('destroyed', () => {})
|
|
|
255
251
|
|
|
256
252
|
用户事件监听器中的异常属于宿主应用异常,不属于 Rivmux 播放错误,也不会转换为 `PlayerError`。单个监听器抛出异常时,其他监听器仍会继续执行,`stop()`、`destroy()` 等生命周期 Promise 也会按内部状态正常完成。Rivmux 会优先通过平台的 `globalThis.reportError()` 报告该异常;平台不支持时使用 `console.error()` 降级报告。
|
|
257
253
|
|
|
258
|
-
|
|
254
|
+
### 错误与 warning
|
|
255
|
+
|
|
256
|
+
`error` 事件提供结构化的 `PlayerError`,`warning` 事件提供可恢复的 `PlayerWarning`:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
type PlayerErrorKind = 'network' | 'unsupported' | 'demux' | 'codec' | 'mux' | 'mse' | 'runtime'
|
|
260
|
+
|
|
261
|
+
type PlayerErrorCause = {
|
|
262
|
+
name: string
|
|
263
|
+
message: string
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
type PlayerError = {
|
|
267
|
+
kind: PlayerErrorKind
|
|
268
|
+
code: string
|
|
269
|
+
message: string
|
|
270
|
+
terminal: boolean
|
|
271
|
+
cause?: PlayerErrorCause
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
type PlayerWarning = {
|
|
275
|
+
code: string
|
|
276
|
+
message: string
|
|
277
|
+
cause?: PlayerErrorCause
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`terminal: true` 表示当前播放器实例不能继续正常工作。非终止错误仍通过 `error` 事件报告;warning 不会进入终止错误路径。
|
|
282
|
+
|
|
283
|
+
当前 Stable error/warning code 如下:
|
|
284
|
+
|
|
285
|
+
| 类别 | code | 说明 |
|
|
286
|
+
| -------------- | ------------------------------------ | ---------------------------------------------------- |
|
|
287
|
+
| 生命周期与调用 | `RIVMUX_ALREADY_ATTACHED` | 播放器已绑定其他 video 元素,不能重复绑定。 |
|
|
288
|
+
| 生命周期与调用 | `RIVMUX_START_REQUIRES_ATTACH` | 尚未成功完成 `attach()` 就调用了 `start()`。 |
|
|
289
|
+
| 生命周期与调用 | `RIVMUX_START_CANCELLED` | 待处理的 `start()` 被 `stop()` 或 `destroy()` 取消。 |
|
|
290
|
+
| 生命周期与调用 | `RIVMUX_PLAYER_STOPPING` | `stop()` 尚未完成时调用了冲突的生命周期操作。 |
|
|
291
|
+
| 生命周期与调用 | `RIVMUX_PLAYER_DESTROYING` | `destroy()` 进行中,播放器已不再接受新操作。 |
|
|
292
|
+
| 生命周期与调用 | `RIVMUX_PLAYER_DESTROYED` | 播放器已销毁,实例不能继续使用。 |
|
|
293
|
+
| 配置 | `RIVMUX_INVALID_LATENCY_OPTION` | 延迟配置数值无效或配置项之间不满足约束。 |
|
|
294
|
+
| 配置 | `RIVMUX_INVALID_NETWORK_OPTION` | 读取超时或重试配置无效。 |
|
|
295
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_WORKER` | 当前环境不支持 Dedicated Worker。 |
|
|
296
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_FETCH` | 当前环境不具备所需的流式 Fetch 能力。 |
|
|
297
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_READABLE_STREAM` | 当前环境不支持 `ReadableStream`。 |
|
|
298
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_WASM` | 当前环境不支持 WebAssembly。 |
|
|
299
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_MSE` | 当前环境不支持 Media Source Extensions。 |
|
|
300
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_WORKER_MSE` | Dedicated Worker 中无法构造 `MediaSource`。 |
|
|
301
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_MSE_TYPE_CHECK` | 当前环境缺少 `MediaSource.isTypeSupported()`。 |
|
|
302
|
+
| 能力与媒体 | `RIVMUX_UNSUPPORTED_MSE_CODEC` | MSE 不支持实际媒体流对应的准确 codec MIME。 |
|
|
303
|
+
| 运行行为 | `RIVMUX_RECONNECT_EXHAUSTED` | 当前故障恢复周期已用尽允许的连接次数。 |
|
|
304
|
+
| warning | `RIVMUX_AUTOPLAY_REJECTED` | 浏览器拒绝自动播放,可在用户手势中恢复播放。 |
|
|
305
|
+
|
|
306
|
+
未列出的 Worker、Loader、MSE 队列和内部生命周期错误码属于内部实现,应用不应依赖其具体字符串。
|
|
307
|
+
|
|
308
|
+
## 常见运行行为
|
|
309
|
+
|
|
310
|
+
### 自动播放拒绝
|
|
259
311
|
|
|
260
312
|
浏览器可能根据自动播放策略拒绝 Rivmux 请求的 `video.play()`。无用户手势的直播场景建议设置 `playback.muted: true`,以提高自动播放成功率。拒绝会产生非终止 warning `RIVMUX_AUTOPLAY_REJECTED`,其 `cause` 保留浏览器错误的 `name` 和 `message`;该 warning 不会中断网络加载、转封装或缓冲,也不会触发 `error` 事件。
|
|
261
313
|
|
|
@@ -269,7 +321,7 @@ button.addEventListener('click', () => {
|
|
|
269
321
|
|
|
270
322
|
设置 `playback.autoPlay: false` 后,Rivmux 不会主动请求启动播放,也不会产生该 warning。
|
|
271
323
|
|
|
272
|
-
|
|
324
|
+
### 直播连接恢复
|
|
273
325
|
|
|
274
326
|
Rivmux 会为以下直播网络故障重建 Loader、转封装核心和 MSE 播放会话:
|
|
275
327
|
|
|
@@ -282,34 +334,41 @@ HTTP `401`、`403` 和其他不可恢复的 `4xx` 不会重试。媒体解析、
|
|
|
282
334
|
|
|
283
335
|
恢复采用指数退避、最大延迟和抖动。等待重连或重建会话期间调用 `stop()` 或 `destroy()` 会立即取消恢复,不会继续创建连接。恢复会更换 `MediaSourceHandle`,因此可能出现短暂中断和时间线重置;当前不承诺无缝续播或跨连接连续时间线。
|
|
284
336
|
|
|
285
|
-
##
|
|
337
|
+
## Worker/WASM 部署
|
|
286
338
|
|
|
287
|
-
|
|
288
|
-
| ---------------------------------------- | ------------ | ---------------------------------- |
|
|
289
|
-
| HTTP-FLV + AVC/H.264 + AAC-LC | Stable | 受浏览器基础 MSE 能力约束 |
|
|
290
|
-
| Enhanced HTTP-FLV + HEVC/`hvc1` + AAC-LC | Stable | 浏览器解码能力是条件化的 |
|
|
291
|
-
| Enhanced HTTP-FLV + AV1 | Experimental | 实现层实验能力,组合与兼容性未承诺 |
|
|
292
|
-
| Enhanced HTTP-FLV + Opus | Experimental | 实现层实验能力,组合与兼容性未承诺 |
|
|
293
|
-
| MPEG-TS | 不支持 | 不属于当前产品输入边界 |
|
|
339
|
+
多数应用无需设置 `runtime.workerUrl` 和 `runtime.wasmUrl`。默认资产 URL 会被 Vite 跟踪,并随应用构建输出。
|
|
294
340
|
|
|
295
|
-
|
|
341
|
+
只有在固定公共路径或 CDN 部署 Rivmux 资产时才需要覆盖:
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
const player = new RivmuxPlayer('https://example.com/live.flv', {
|
|
345
|
+
runtime: {
|
|
346
|
+
workerUrl: 'https://cdn.example.com/rivmux/<version>/rivmux-runtime-worker.js',
|
|
347
|
+
wasmUrl: 'https://cdn.example.com/rivmux/<version>/rivmux-transmux-core.wasm',
|
|
348
|
+
},
|
|
349
|
+
})
|
|
350
|
+
```
|
|
296
351
|
|
|
297
|
-
`
|
|
352
|
+
`workerUrl` 不会推导 `wasmUrl`。覆盖两项时必须发布同一版本的 Worker/WASM 资产对,并使用相同缓存版本策略。两者都是可执行资产地址,不得由不可信输入拼接。`workerUrl` 还必须满足目标浏览器对 module Dedicated Worker 的加载限制;不允许直接加载跨源 Worker 时,应通过同源公共路径提供该脚本。宿主应用需配置兼容的 CSP 和 CORS,并以 `application/wasm` 提供 WASM 文件。
|
|
298
353
|
|
|
299
|
-
##
|
|
354
|
+
## 公共类型
|
|
300
355
|
|
|
301
|
-
|
|
356
|
+
主包会重新导出以下 Stable 类型:
|
|
302
357
|
|
|
303
358
|
```ts
|
|
304
359
|
import type {
|
|
305
|
-
DiagnosticsOptions,
|
|
306
360
|
DecodingCapabilities,
|
|
361
|
+
DiagnosticsOptions,
|
|
307
362
|
LatencyOptions,
|
|
308
363
|
MediaInfo,
|
|
309
364
|
NetworkOptions,
|
|
310
365
|
PlaybackOptions,
|
|
311
366
|
PlayerError,
|
|
312
367
|
PlayerErrorCause,
|
|
368
|
+
PlayerErrorKind,
|
|
369
|
+
PlayerEventListener,
|
|
370
|
+
PlayerEventMap,
|
|
371
|
+
PlayerEventType,
|
|
313
372
|
PlayerStats,
|
|
314
373
|
PlayerWarning,
|
|
315
374
|
ReconnectInfo,
|
|
@@ -318,9 +377,18 @@ import type {
|
|
|
318
377
|
RivmuxCapabilities,
|
|
319
378
|
RivmuxPlayerOptions,
|
|
320
379
|
RuntimeCapabilities,
|
|
321
|
-
RuntimeOptions,
|
|
322
380
|
SupportStatus,
|
|
323
381
|
} from 'rivmux'
|
|
324
382
|
```
|
|
325
383
|
|
|
326
|
-
|
|
384
|
+
`RivmuxPlayerOptions` 的整体配置形状属于 Stable,其中嵌套的 `runtime` 字段用于承载 Experimental 资产部署选项。主包也会导出对应的 Experimental 类型:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
import type { RuntimeOptions } from 'rivmux'
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
配置归一化、错误构造函数和 Worker 通信契约属于内部实现,不构成应用 API。
|
|
391
|
+
|
|
392
|
+
## 许可证
|
|
393
|
+
|
|
394
|
+
[Apache License 2.0](./LICENSE)
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/player.ts","../src/feature-detect.ts"],"mappings":";;;;;;;;qBAgCa;;WAEF;mBAIQ;mBACA;mBACA;mBACA;mBACA;UACT;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;;;;;EAOI,YAAA,aAAa,UAAU;;;;;;EAkB7B,OAAO,OAAO,mBAAmB;;;;;;;;EA8BvC,SAAS;UAiCK;;;;;;;EA0Bd,QAAQ;UAyBM;;;;;;;EAkCR,WAAW;UAeH;;EA6Bd,GAAG,UAAU,mBAAiB,MAAM,GAAG,UAAU,sBAAoB;;EAKrE,IAAI,UAAU,mBAAiB,MAAM,GAAG,UAAU,sBAAoB;UAI9D;UAgBA;UAmDA;UAiBA;UAcM;UA4BN;UAWA;UAmBA;UAIA;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/player.ts","../src/feature-detect.ts"],"mappings":";;;;;;;;qBAgCa;;WAEF;mBAIQ;mBACA;mBACA;mBACA;mBACA;UACT;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;;;;;EAOI,YAAA,aAAa,UAAU;;;;;;EAkB7B,OAAO,OAAO,mBAAmB;;;;;;;;EA8BvC,SAAS;UAiCK;;;;;;;EA0Bd,QAAQ;UAyBM;;;;;;;EAkCR,WAAW;UAeH;;EA6Bd,GAAG,UAAU,mBAAiB,MAAM,GAAG,UAAU,sBAAoB;;EAKrE,IAAI,UAAU,mBAAiB,MAAM,GAAG,UAAU,sBAAoB;UAI9D;UAgBA;UAmDA;UAiBA;UAcM;UA4BN;UAWA;UAmBA;UAIA;;;;wBCnVM,mBAAmB;wBAInB"}
|
package/dist/index.js
CHANGED
|
@@ -119,11 +119,6 @@ function probeMime(isTypeSupported, mime) {
|
|
|
119
119
|
return "unknown";
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
function combineProfile(video, audio) {
|
|
123
|
-
if (video === "unsupported" || audio === "unsupported") return "unsupported";
|
|
124
|
-
if (video === "supported" && audio === "supported") return "supported";
|
|
125
|
-
return "unknown";
|
|
126
|
-
}
|
|
127
122
|
function getCapabilitiesForEnvironment(environment) {
|
|
128
123
|
const runtime = {
|
|
129
124
|
dedicatedWorker: environment.dedicatedWorker,
|
|
@@ -146,11 +141,7 @@ function getCapabilitiesForEnvironment(environment) {
|
|
|
146
141
|
runtime,
|
|
147
142
|
decoding: {
|
|
148
143
|
video,
|
|
149
|
-
audio
|
|
150
|
-
stableProfiles: {
|
|
151
|
-
avcAac: combineProfile(video.avc, audio.aac),
|
|
152
|
-
hevcAac: combineProfile(video.hevc, audio.aac)
|
|
153
|
-
}
|
|
144
|
+
audio
|
|
154
145
|
}
|
|
155
146
|
};
|
|
156
147
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/events.ts","../src/errors.ts","../src/feature-detect.ts","../src/options.ts","../src/playback-controller.ts","../src/player.ts"],"sourcesContent":["import type { PlayerEventListener, PlayerEventMap, PlayerEventType } from '@rivmux/protocol'\n\nexport class PlayerEventEmitter {\n private readonly listeners = new Map<PlayerEventType, Set<PlayerEventListener<PlayerEventType>>>()\n\n on<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n const typedListener = listener as PlayerEventListener<PlayerEventType>\n const listeners = this.listeners.get(type)\n\n if (listeners === undefined) {\n this.listeners.set(type, new Set([typedListener]))\n return\n }\n\n listeners.add(typedListener)\n }\n\n off<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n this.listeners.get(type)?.delete(listener as PlayerEventListener<PlayerEventType>)\n }\n\n emit<T extends PlayerEventType>(type: T, payload: PlayerEventMap[T]): void {\n for (const listener of this.listeners.get(type) ?? []) {\n try {\n listener(payload)\n } catch (error) {\n reportListenerError(error)\n }\n }\n }\n\n clear(): void {\n this.listeners.clear()\n }\n}\n\nfunction reportListenerError(error: unknown): void {\n try {\n const reportError = (globalThis as typeof globalThis & { reportError?: (error: unknown) => void }).reportError\n if (typeof reportError === 'function') {\n reportError(error)\n return\n }\n } catch {\n // Fall through to the non-throwing console fallback.\n }\n\n try {\n globalThis.console?.error(error)\n } catch {\n // Error reporting must never affect player behavior.\n }\n}\n","import type { PlayerError, PlayerErrorKind } from '@rivmux/protocol'\n\nexport function createPlayerError(kind: PlayerErrorKind, code: string, message: string, terminal: boolean, cause?: unknown): PlayerError {\n return cause === undefined ? { kind, code, message, terminal } : { kind, code, message, terminal, cause: serializeCause(cause) }\n}\n\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\nexport function playerErrorToException(error: PlayerError): Error {\n const exception = new Error(error.message)\n exception.name = error.code\n return exception\n}\n\nfunction serializeCause(cause: unknown): { name: string; message: string } {\n if (cause instanceof Error) {\n return { name: cause.name, message: cause.message }\n }\n\n if (typeof cause === 'object' && cause !== null) {\n const value = cause as { name?: unknown; message?: unknown }\n return {\n name: typeof value.name === 'string' ? value.name : 'Error',\n message: typeof value.message === 'string' ? value.message : String(cause),\n }\n }\n\n return { name: 'Error', message: String(cause) }\n}\n","import { createPlayerError } from './errors'\n\nimport type { PlayerError, RivmuxCapabilities, RuntimeCapabilities, SupportStatus } from '@rivmux/protocol'\n\ninterface CapabilityEnvironment {\n dedicatedWorker: boolean\n fetchStreaming: boolean\n readableStream: boolean\n webAssembly: boolean\n mediaSource: boolean\n workerMseConstructable: boolean\n isTypeSupported?: (mime: string) => boolean\n}\n\nconst MIME = {\n avc: 'video/mp4; codecs=\"avc1.42E01E\"',\n hevc: 'video/mp4; codecs=\"hvc1.1.6.L93.B0\"',\n av1: 'video/mp4; codecs=\"av01.0.08M.08\"',\n aac: 'audio/mp4; codecs=\"mp4a.40.2\"',\n opus: 'audio/mp4; codecs=\"opus\"',\n} as const\n\nfunction safelyRead<T>(read: () => T, fallback: T): T {\n try {\n return read()\n } catch {\n return fallback\n }\n}\n\nfunction readCapabilityEnvironment(): CapabilityEnvironment {\n const dedicatedWorker = safelyRead(() => typeof Worker === 'function', false)\n const fetchAvailable = safelyRead(() => typeof fetch === 'function', false)\n const responseBodyAvailable = safelyRead(() => typeof Response === 'function' && Response.prototype !== undefined && 'body' in Response.prototype, false)\n const readableStream = safelyRead(() => typeof ReadableStream === 'function', false)\n const webAssembly = safelyRead(() => typeof WebAssembly === 'object' && typeof WebAssembly.instantiate === 'function', false)\n const mediaSourceConstructor = safelyRead(() => (typeof MediaSource === 'function' ? MediaSource : undefined), undefined as typeof MediaSource | undefined)\n const mediaSource = mediaSourceConstructor !== undefined\n const workerMseConstructable = mediaSource && safelyRead(() => mediaSourceConstructor.canConstructInDedicatedWorker === true, false)\n const isTypeSupported = mediaSource\n ? safelyRead(\n () => (typeof mediaSourceConstructor.isTypeSupported === 'function' ? mediaSourceConstructor.isTypeSupported.bind(mediaSourceConstructor) : undefined),\n undefined\n )\n : undefined\n\n return {\n dedicatedWorker,\n fetchStreaming: fetchAvailable && responseBodyAvailable,\n readableStream,\n webAssembly,\n mediaSource,\n workerMseConstructable,\n isTypeSupported,\n }\n}\n\nfunction probeMime(isTypeSupported: CapabilityEnvironment['isTypeSupported'], mime: string): SupportStatus {\n if (isTypeSupported === undefined) {\n return 'unknown'\n }\n\n try {\n return isTypeSupported(mime) ? 'supported' : 'unsupported'\n } catch {\n return 'unknown'\n }\n}\n\nfunction combineProfile(video: SupportStatus, audio: SupportStatus): SupportStatus {\n if (video === 'unsupported' || audio === 'unsupported') {\n return 'unsupported'\n }\n if (video === 'supported' && audio === 'supported') {\n return 'supported'\n }\n return 'unknown'\n}\n\nfunction getCapabilitiesForEnvironment(environment: CapabilityEnvironment): RivmuxCapabilities {\n const runtime: RuntimeCapabilities = {\n dedicatedWorker: environment.dedicatedWorker,\n workerMse: environment.workerMseConstructable && environment.isTypeSupported !== undefined,\n fetchStreaming: environment.fetchStreaming,\n readableStream: environment.readableStream,\n webAssembly: environment.webAssembly,\n }\n const video = {\n avc: probeMime(environment.isTypeSupported, MIME.avc),\n hevc: probeMime(environment.isTypeSupported, MIME.hevc),\n av1: probeMime(environment.isTypeSupported, MIME.av1),\n }\n const audio = {\n aac: probeMime(environment.isTypeSupported, MIME.aac),\n opus: probeMime(environment.isTypeSupported, MIME.opus),\n }\n\n return {\n supported: Object.values(runtime).every(Boolean),\n runtime,\n decoding: {\n video,\n audio,\n stableProfiles: {\n avcAac: combineProfile(video.avc, audio.aac),\n hevcAac: combineProfile(video.hevc, audio.aac),\n },\n },\n }\n}\n\nexport function getCapabilities(): RivmuxCapabilities {\n return getCapabilitiesForEnvironment(readCapabilityEnvironment())\n}\n\nexport function isSupported(): boolean {\n return getCapabilities().supported\n}\n\nexport function detectMainThreadRuntime(environment = readCapabilityEnvironment()): PlayerError | undefined {\n if (!environment.dedicatedWorker) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_WORKER', 'Dedicated Worker is not available in this runtime.', true)\n }\n\n if (!environment.fetchStreaming) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_FETCH', 'Fetch is not available in this runtime.', true)\n }\n\n if (!environment.readableStream) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_READABLE_STREAM', 'ReadableStream is not available in this runtime.', true)\n }\n\n if (!environment.webAssembly) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_WASM', 'WebAssembly is not available in this runtime.', true)\n }\n\n if (!environment.mediaSource) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_MSE', 'MediaSource is not available in this runtime.', true)\n }\n\n if (!environment.workerMseConstructable) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_WORKER_MSE', 'MediaSource cannot be constructed in a dedicated worker in this runtime.', true)\n }\n\n if (environment.isTypeSupported === undefined) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_MSE_TYPE_CHECK', 'MediaSource.isTypeSupported is not available in this runtime.', true)\n }\n\n return undefined\n}\n","import { createPlayerError, playerErrorToException } from './errors'\n\nimport type { NormalizedRivmuxPlayerOptions, PlayerErrorKind, RivmuxPlayerOptions } from '@rivmux/protocol'\n\nconst DEFAULT_RIVMUX_PLAYER_OPTIONS: NormalizedRivmuxPlayerOptions = {\n playback: {\n autoPlay: true,\n muted: false,\n },\n latency: {\n startupBuffer: 0.35,\n target: 1.2,\n max: 2.5,\n maxForwardBuffer: 4,\n backwardBuffer: 1.5,\n },\n network: {\n headers: {},\n credentials: 'same-origin',\n readIdleTimeoutMs: 10_000,\n retry: {\n maxAttempts: 3,\n backoffMs: 500,\n maxBackoffMs: 8_000,\n jitterRatio: 0.2,\n },\n },\n runtime: {},\n diagnostics: { statsIntervalMs: 1000 },\n}\n\nexport function normalizePlayerOptions(options: RivmuxPlayerOptions = {}): NormalizedRivmuxPlayerOptions {\n const normalizedOptions = {\n playback: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.playback,\n ...options.playback,\n },\n latency: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.latency,\n ...options.latency,\n },\n network: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.network,\n ...options.network,\n headers: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.network.headers,\n ...options.network?.headers,\n },\n retry: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.network.retry,\n ...options.network?.retry,\n },\n },\n runtime: normalizeRuntimeOptions(options),\n diagnostics: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.diagnostics,\n ...options.diagnostics,\n },\n }\n\n validateNormalizedOptions(normalizedOptions)\n return normalizedOptions\n}\n\nfunction validateNormalizedOptions(options: NormalizedRivmuxPlayerOptions): void {\n validateLatencyOptions(options)\n validateNetworkOptions(options)\n}\n\nfunction validateLatencyOptions(options: NormalizedRivmuxPlayerOptions): void {\n const latency = options.latency\n\n assertFiniteNonNegativeLatency(latency.startupBuffer, 'latency.startupBuffer')\n assertFinitePositiveLatency(latency.target, 'latency.target')\n assertFiniteNonNegativeLatency(latency.max, 'latency.max')\n assertFiniteNonNegativeLatency(latency.maxForwardBuffer, 'latency.maxForwardBuffer')\n assertFiniteNonNegativeLatency(latency.backwardBuffer, 'latency.backwardBuffer')\n\n if (latency.max < latency.target) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', 'latency.max must be greater than or equal to latency.target.')\n }\n\n if (latency.maxForwardBuffer < latency.target) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', 'latency.maxForwardBuffer must be greater than or equal to latency.target.')\n }\n}\n\nfunction validateNetworkOptions(options: NormalizedRivmuxPlayerOptions): void {\n const network = options.network\n const retry = network.retry\n\n assertPositiveInteger(network.readIdleTimeoutMs, 'network.readIdleTimeoutMs')\n assertPositiveInteger(retry.maxAttempts, 'network.retry.maxAttempts')\n assertNonNegativeInteger(retry.backoffMs, 'network.retry.backoffMs')\n assertNonNegativeInteger(retry.maxBackoffMs, 'network.retry.maxBackoffMs')\n\n if (retry.maxBackoffMs < retry.backoffMs) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', 'network.retry.maxBackoffMs must be greater than or equal to network.retry.backoffMs.')\n }\n\n if (!Number.isFinite(retry.jitterRatio) || retry.jitterRatio < 0 || retry.jitterRatio > 1) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', 'network.retry.jitterRatio must be a finite number between 0 and 1.')\n }\n}\n\nfunction normalizeRuntimeOptions(options: RivmuxPlayerOptions): NormalizedRivmuxPlayerOptions['runtime'] {\n return {\n ...(options.runtime?.workerUrl === undefined ? {} : { workerUrl: options.runtime.workerUrl }),\n ...(options.runtime?.wasmUrl === undefined ? {} : { wasmUrl: options.runtime.wasmUrl }),\n }\n}\n\nfunction assertFiniteNonNegativeLatency(value: number, field: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', `${field} must be a finite number greater than or equal to 0.`)\n }\n}\n\nfunction assertFinitePositiveLatency(value: number, field: string): void {\n if (!Number.isFinite(value) || value <= 0) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', `${field} must be a finite number greater than 0.`)\n }\n}\n\nfunction assertPositiveInteger(value: number, field: string): void {\n if (!Number.isInteger(value) || value < 1) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', `${field} must be an integer greater than or equal to 1.`)\n }\n}\n\nfunction assertNonNegativeInteger(value: number, field: string): void {\n if (!Number.isInteger(value) || value < 0) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', `${field} must be an integer greater than or equal to 0.`)\n }\n}\n\nfunction throwOptionError(kind: PlayerErrorKind, code: string, message: string): never {\n throw playerErrorToException(createPlayerError(kind, code, message, true))\n}\n","import type { NormalizedPlaybackOptions, PlaybackControlAction, PlaybackControlResult, VideoElementState } from '@rivmux/protocol'\n\nexport class PlaybackController {\n private readonly options: NormalizedPlaybackOptions\n private video?: HTMLVideoElement\n private stateTimer?: ReturnType<typeof setInterval>\n\n constructor(options: NormalizedPlaybackOptions) {\n this.options = options\n }\n\n get attached(): boolean {\n return this.video !== undefined\n }\n\n isAttachedTo(video: HTMLVideoElement): boolean {\n return this.video === video\n }\n\n attach(video: HTMLVideoElement): void {\n this.video = video\n video.muted = this.options.muted\n video.autoplay = this.options.autoPlay\n }\n\n attachMediaSourceHandle(handle: MediaSourceHandle): boolean {\n if (this.video === undefined) {\n return false\n }\n\n Reflect.set(this.video, 'srcObject', handle)\n return true\n }\n\n startStateReporting(intervalMs: number, report: (state: VideoElementState) => void): void {\n this.stopStateReporting()\n const reportCurrentState = (): void => {\n const state = this.snapshot()\n if (state !== undefined) {\n report(state)\n }\n }\n\n reportCurrentState()\n this.stateTimer = setInterval(reportCurrentState, intervalMs)\n }\n\n stopStateReporting(): void {\n if (this.stateTimer !== undefined) {\n clearInterval(this.stateTimer)\n this.stateTimer = undefined\n }\n }\n\n async applyControl(action: PlaybackControlAction): Promise<PlaybackControlResult> {\n const video = this.video\n if (video === undefined) {\n return {\n type: action.type,\n accepted: false,\n error: {\n name: 'NotAttachedError',\n message: 'No video element is attached.',\n },\n }\n }\n\n try {\n switch (action.type) {\n case 'play':\n await video.play()\n break\n case 'set-playback-rate':\n video.playbackRate = action.playbackRate\n break\n case 'seek':\n video.currentTime = action.targetTime\n break\n }\n return { type: action.type, accepted: true }\n } catch (cause) {\n return {\n type: action.type,\n accepted: false,\n error: normalizePlaybackControlError(cause),\n }\n }\n }\n\n detachSource(): void {\n if (this.video === undefined) {\n return\n }\n\n this.video.pause()\n this.video.playbackRate = 1\n this.video.removeAttribute('src')\n this.video.srcObject = null\n this.video.load()\n }\n\n release(): void {\n this.stopStateReporting()\n this.detachSource()\n this.video = undefined\n }\n\n private snapshot(): VideoElementState | undefined {\n const video = this.video\n if (video === undefined) {\n return undefined\n }\n\n const droppedFrames = getDroppedFrames(video)\n return {\n currentTime: Number.isFinite(video.currentTime) ? video.currentTime : 0,\n readyState: video.readyState,\n playbackRate: video.playbackRate,\n paused: video.paused,\n ...(droppedFrames === undefined ? {} : { droppedFrames }),\n }\n }\n}\n\nfunction normalizePlaybackControlError(cause: unknown): { name: string; message: string } {\n if (cause instanceof Error) {\n return {\n name: safelyStringifyErrorField(() => cause.name, 'Error'),\n message: safelyStringifyErrorField(() => cause.message, 'Unknown playback control error.'),\n }\n }\n\n try {\n return {\n name: 'Error',\n message: String(cause),\n }\n } catch {\n return {\n name: 'Error',\n message: 'Unknown playback control error.',\n }\n }\n}\n\nfunction safelyStringifyErrorField(read: () => unknown, fallback: string): string {\n try {\n return String(read())\n } catch {\n return fallback\n }\n}\n\nfunction getDroppedFrames(video: HTMLVideoElement): number | undefined {\n const quality = video.getVideoPlaybackQuality?.()\n if (quality !== undefined && Number.isFinite(quality.droppedVideoFrames)) {\n return quality.droppedVideoFrames\n }\n\n const webkitDroppedFrameCount = (video as HTMLVideoElement & { webkitDroppedFrameCount?: number }).webkitDroppedFrameCount\n return Number.isFinite(webkitDroppedFrameCount) ? webkitDroppedFrameCount : undefined\n}\n","import { PlayerEventEmitter } from './events'\nimport { createPlayerError, playerErrorToException } from './errors'\nimport { detectMainThreadRuntime } from './feature-detect'\nimport { normalizePlayerOptions } from './options'\nimport { PlaybackController } from './playback-controller'\nimport { createRuntimeWorker, getBundledWasmUrl, WorkerClient } from '@rivmux/runtime-worker'\n\nimport type {\n NormalizedRivmuxPlayerOptions,\n PlaybackControlAction,\n PlayerError,\n PlayerEventListener,\n PlayerEventType,\n RivmuxPlayerOptions,\n WorkerMessage,\n} from '@rivmux/protocol'\nimport type { RuntimeWorkerFactory } from '@rivmux/runtime-worker'\n\ntype PlayerState = 'idle' | 'attached' | 'starting' | 'started' | 'stopping' | 'stopped' | 'fatal-error' | 'destroying' | 'destroyed'\n\ntype RivmuxPlayerInternals = {\n workerFactory?: RuntimeWorkerFactory\n detectRuntime?: () => PlayerError | undefined\n idFactory?: () => string\n}\n\n/**\n * Public browser player facade for one HTTP-FLV stream.\n *\n * Create one instance per stream URL, call `attach(video)` first, then\n * `start()`. Call `destroy()` when the instance is no longer needed.\n */\nexport class RivmuxPlayer {\n /** Original stream URL passed to the constructor. */\n readonly url: string\n\n /** @internal Fully normalized options with defaults applied. */\n readonly options: NormalizedRivmuxPlayerOptions\n private readonly id: string\n private readonly events = new PlayerEventEmitter()\n private readonly workerFactory: RuntimeWorkerFactory\n private readonly detectRuntime: () => PlayerError | undefined\n private readonly playback: PlaybackController\n private workerClient?: WorkerClient\n private state: PlayerState = 'idle'\n private lifecycleGeneration = 0\n private terminalError?: PlayerError\n private autoplayWarningEmitted = false\n private startPromise?: Promise<void>\n private stopPromise?: Promise<void>\n private destroyPromise?: Promise<void>\n\n /**\n * Creates a player instance for one stream URL.\n *\n * The instance does not start network loading until `start()` is called.\n */\n constructor(url: string, options?: RivmuxPlayerOptions)\n /** @internal Test-only dependency injection; omitted from generated declarations. */\n constructor(url: string, options?: RivmuxPlayerOptions, internals?: RivmuxPlayerInternals)\n constructor(url: string, options?: RivmuxPlayerOptions, internals?: RivmuxPlayerInternals) {\n internals ??= {}\n this.url = url\n this.options = normalizePlayerOptions(options)\n this.id = internals.idFactory?.() ?? createPlayerId()\n this.workerFactory = internals.workerFactory ?? createRuntimeWorker\n this.detectRuntime = internals.detectRuntime ?? detectMainThreadRuntime\n this.playback = new PlaybackController(this.options.playback)\n }\n\n /**\n * Attaches this player to a video element and prepares the worker/MSE pipe.\n *\n * Await this method before calling `start()`.\n */\n async attach(video: HTMLVideoElement): Promise<void> {\n this.assertOperational('attach')\n const lifecycleGeneration = this.lifecycleGeneration\n\n if (this.playback.attached && !this.playback.isAttachedTo(video)) {\n throw playerErrorToException(createPlayerError('runtime', 'RIVMUX_ALREADY_ATTACHED', 'This player is already attached to a video element.', false))\n }\n\n const runtimeError = this.detectRuntime()\n if (runtimeError !== undefined) {\n this.events.emit('error', runtimeError)\n throw playerErrorToException(runtimeError)\n }\n\n this.playback.attach(video)\n this.ensureWorkerClient()\n await this.workerClient?.waitForMediaSourceHandle({ type: 'attach-media-source' })\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n return\n }\n this.state = 'attached'\n }\n\n /**\n * Waits until the worker has created the transmux core and scheduled stream\n * consumption for this playback session.\n *\n * This does not wait for media data, `canplay`, or `video.play()`. Requires a\n * successful `attach(video)` call first.\n */\n start(): Promise<void> {\n try {\n this.assertOperational('start')\n } catch (cause) {\n return Promise.reject(cause)\n }\n\n if (!this.playback.attached || this.workerClient === undefined) {\n return Promise.reject(\n playerErrorToException(createPlayerError('runtime', 'RIVMUX_START_REQUIRES_ATTACH', 'start() requires a previously attached video element.', false))\n )\n }\n\n if (this.state === 'started') {\n return Promise.resolve()\n }\n\n if (this.startPromise !== undefined) {\n return this.startPromise\n }\n\n const lifecycleGeneration = this.lifecycleGeneration\n const previousState = this.state\n this.state = 'starting'\n const starting = this.performStart(this.workerClient, lifecycleGeneration, previousState === 'stopped').finally(() => {\n if (this.startPromise === starting) {\n this.startPromise = undefined\n }\n })\n this.startPromise = starting\n return starting\n }\n\n private async performStart(workerClient: WorkerClient, lifecycleGeneration: number, restart: boolean): Promise<void> {\n try {\n if (restart) {\n await workerClient.waitForMediaSourceHandle({ type: 'attach-media-source' })\n this.assertStartOperationCurrent(lifecycleGeneration)\n }\n\n await workerClient.waitForStarted({ type: 'start' })\n this.assertStartOperationCurrent(lifecycleGeneration)\n } catch (cause) {\n if (this.isLifecycleOperationCurrent(lifecycleGeneration) && this.state === 'starting') {\n this.state = restart ? 'stopped' : 'attached'\n }\n throw toPublicStartError(cause)\n }\n\n this.state = 'started'\n this.startVideoStateReporting()\n }\n\n /**\n * Stops loading and detaches the current media source.\n *\n * The instance remains reusable; call `start()` again to restart the same\n * stream after the player has stopped.\n */\n stop(): Promise<void> {\n if (this.state === 'destroyed' || this.state === 'destroying') {\n return Promise.resolve()\n }\n\n if (this.state === 'fatal-error') {\n return Promise.resolve()\n }\n\n if (this.stopPromise !== undefined) {\n return this.stopPromise\n }\n\n this.lifecycleGeneration += 1\n this.state = 'stopping'\n const lifecycleGeneration = this.lifecycleGeneration\n const stopping = this.performStop(lifecycleGeneration).finally(() => {\n if (this.stopPromise === stopping) {\n this.stopPromise = undefined\n }\n })\n this.stopPromise = stopping\n return stopping\n }\n\n private async performStop(lifecycleGeneration: number): Promise<void> {\n const workerClient = this.workerClient\n if (workerClient === undefined) {\n if (this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n this.autoplayWarningEmitted = false\n this.state = 'stopped'\n this.events.emit('stopped', undefined)\n }\n return\n }\n\n this.playback.stopStateReporting()\n try {\n await workerClient.waitForStopped({ type: 'stop' })\n } catch (error) {\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n return\n }\n throw error\n }\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n return\n }\n this.playback.detachSource()\n this.autoplayWarningEmitted = false\n this.state = 'stopped'\n }\n\n /**\n * Releases worker resources, timers, listeners, and the attached video source.\n *\n * The instance is terminal after destroy and cannot be attached or started\n * again.\n */\n async destroy(): Promise<void> {\n if (this.state === 'destroyed') {\n return\n }\n\n if (this.destroyPromise !== undefined) {\n return this.destroyPromise\n }\n\n this.lifecycleGeneration += 1\n this.state = 'destroying'\n this.destroyPromise = this.performDestroy()\n return this.destroyPromise\n }\n\n private async performDestroy(): Promise<void> {\n const workerClient = this.workerClient\n this.workerClient = undefined\n this.playback.stopStateReporting()\n let destroyError: unknown\n\n if (workerClient !== undefined) {\n try {\n await workerClient.waitForDestroyed({ type: 'destroy' })\n } catch (error) {\n destroyError = error\n } finally {\n workerClient.dispose()\n }\n } else {\n this.events.emit('destroyed', undefined)\n }\n\n this.playback.release()\n\n this.state = 'destroyed'\n this.events.clear()\n\n if (destroyError !== undefined) {\n throw destroyError\n }\n }\n\n /** Registers an event listener for a typed player event. */\n on<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n this.events.on(type, listener)\n }\n\n /** Removes a previously registered event listener. */\n off<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n this.events.off(type, listener)\n }\n\n private ensureWorkerClient(): void {\n if (this.workerClient !== undefined) {\n return\n }\n\n const worker = this.workerFactory(this.options)\n this.workerClient = new WorkerClient(worker, {\n onMessage: (message) => this.handleWorkerMessage(message),\n onError: (error) => {\n this.enterFatalErrorState(error)\n this.events.emit('error', error)\n },\n })\n this.workerClient.post({ type: 'init', id: this.id, url: this.url, options: withBundledWasmUrl(this.options) })\n }\n\n private handleWorkerMessage(message: WorkerMessage): void {\n if (this.state === 'destroyed') {\n return\n }\n\n if ((this.state === 'destroying' && message.type !== 'destroyed') || this.state === 'fatal-error') {\n return\n }\n\n switch (message.type) {\n case 'ready':\n this.events.emit('initialized', undefined)\n return\n case 'media-source-handle':\n this.attachMediaSourceHandle(message.handle)\n return\n case 'started':\n return\n case 'media-info':\n this.events.emit('mediaInfo', message.mediaInfo)\n return\n case 'stats':\n this.events.emit('stats', message.stats)\n return\n case 'warning':\n this.events.emit('warning', message.warning)\n return\n case 'reconnecting':\n this.events.emit('reconnecting', message.info)\n return\n case 'recovered':\n this.events.emit('recovered', message.info)\n return\n case 'error':\n if (message.error.terminal) {\n this.enterFatalErrorState(message.error)\n }\n this.events.emit('error', message.error)\n return\n case 'playback-control':\n void this.applyPlaybackControl(message.action)\n return\n case 'stopped':\n this.events.emit('stopped', undefined)\n return\n case 'destroyed':\n this.events.emit('destroyed', undefined)\n return\n }\n }\n\n private attachMediaSourceHandle(handle: MediaSourceHandle): void {\n if (this.state === 'started') {\n this.autoplayWarningEmitted = false\n this.playback.detachSource()\n }\n if (!this.playback.attachMediaSourceHandle(handle)) {\n const error = createPlayerError(\n 'runtime',\n 'RIVMUX_ATTACH_HANDLE_WITHOUT_VIDEO',\n 'Worker returned a MediaSourceHandle before a video element was attached.',\n true\n )\n this.events.emit('error', error)\n throw playerErrorToException(error)\n }\n }\n\n private startVideoStateReporting(): void {\n const intervalMs = Math.max(100, Math.min(this.options.diagnostics.statsIntervalMs, 250))\n const workerClient = this.workerClient\n if (workerClient === undefined) {\n return\n }\n\n this.playback.startStateReporting(intervalMs, (state) => {\n if (this.state === 'started' && this.workerClient === workerClient) {\n workerClient.post({ type: 'video-state', state })\n }\n })\n }\n\n private async applyPlaybackControl(action: PlaybackControlAction): Promise<void> {\n const workerClient = this.workerClient\n const lifecycleGeneration = this.lifecycleGeneration\n if (!this.playback.attached || workerClient === undefined || this.state !== 'started') {\n return\n }\n\n const result = await this.playback.applyControl(action)\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration) || this.state !== 'started' || this.workerClient !== workerClient) {\n return\n }\n workerClient.post({ type: 'playback-control-result', result })\n if (\n action.type === 'play' &&\n action.reason === 'startup-buffer-ready' &&\n this.options.playback.autoPlay &&\n !result.accepted &&\n !this.autoplayWarningEmitted\n ) {\n this.autoplayWarningEmitted = true\n this.events.emit('warning', {\n code: 'RIVMUX_AUTOPLAY_REJECTED',\n message: '浏览器拒绝了自动播放;请在用户手势处理器中调用 video.play() 恢复播放。',\n cause: result.error,\n })\n }\n }\n\n private enterFatalErrorState(error: PlayerError): void {\n if (this.state === 'destroyed' || this.state === 'destroying' || this.state === 'fatal-error') {\n return\n }\n\n this.lifecycleGeneration += 1\n this.terminalError = error\n this.state = 'fatal-error'\n this.playback.release()\n }\n\n private assertOperational(method: string): void {\n if (this.state === 'fatal-error' && this.terminalError !== undefined) {\n throw playerErrorToException(this.terminalError)\n }\n\n if (this.state === 'stopping') {\n throw playerErrorToException(\n createPlayerError('runtime', 'RIVMUX_PLAYER_STOPPING', `RivmuxPlayer.${method}() cannot be called while stop() is pending.`, false)\n )\n }\n\n if (this.state !== 'destroyed' && this.state !== 'destroying') {\n return\n }\n\n const code = this.state === 'destroying' ? 'RIVMUX_PLAYER_DESTROYING' : 'RIVMUX_PLAYER_DESTROYED'\n throw playerErrorToException(createPlayerError('runtime', code, `RivmuxPlayer.${method}() cannot be called after destroy() begins.`, true))\n }\n\n private isLifecycleOperationCurrent(generation: number): boolean {\n return generation === this.lifecycleGeneration && this.state !== 'fatal-error' && this.state !== 'destroying' && this.state !== 'destroyed'\n }\n\n private assertStartOperationCurrent(generation: number): void {\n if (this.isLifecycleOperationCurrent(generation) && this.state === 'starting') {\n return\n }\n\n const action = this.state === 'destroying' || this.state === 'destroyed' ? 'destroy' : 'stop'\n throw createPlayerError('runtime', 'RIVMUX_START_CANCELLED', `Start was cancelled by ${action}.`, false)\n }\n}\n\nfunction toPublicStartError(cause: unknown): Error {\n return isPlayerError(cause) ? playerErrorToException(cause) : cause instanceof Error ? cause : new Error(String(cause))\n}\n\nfunction isPlayerError(value: unknown): value is PlayerError {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n\n const candidate = value as Partial<PlayerError>\n return (\n typeof candidate.kind === 'string' && typeof candidate.code === 'string' && typeof candidate.message === 'string' && typeof candidate.terminal === 'boolean'\n )\n}\n\nfunction createPlayerId(): string {\n const random = globalThis.crypto?.randomUUID?.()\n return random ?? `rivmux-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n}\n\nfunction withBundledWasmUrl(options: NormalizedRivmuxPlayerOptions): NormalizedRivmuxPlayerOptions {\n if (options.runtime.wasmUrl !== undefined) {\n return options\n }\n\n return {\n ...options,\n runtime: {\n ...options.runtime,\n wasmUrl: getBundledWasmUrl(),\n },\n }\n}\n"],"mappings":";;AAEA,IAAa,qBAAb,MAAgC;CAC9B,4BAA6B,IAAI,IAAgE;CAEjG,GAA8B,MAAS,UAAwC;EAC7E,MAAM,gBAAgB;EACtB,MAAM,YAAY,KAAK,UAAU,IAAI,IAAI;EAEzC,IAAI,cAAc,KAAA,GAAW;GAC3B,KAAK,UAAU,IAAI,sBAAM,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC;GACjD;EACF;EAEA,UAAU,IAAI,aAAa;CAC7B;CAEA,IAA+B,MAAS,UAAwC;EAC9E,KAAK,UAAU,IAAI,IAAI,CAAC,EAAE,OAAO,QAAgD;CACnF;CAEA,KAAgC,MAAS,SAAkC;EACzE,KAAK,MAAM,YAAY,KAAK,UAAU,IAAI,IAAI,KAAK,CAAC,GAClD,IAAI;GACF,SAAS,OAAO;EAClB,SAAS,OAAO;GACd,oBAAoB,KAAK;EAC3B;CAEJ;CAEA,QAAc;EACZ,KAAK,UAAU,MAAM;CACvB;AACF;AAEA,SAAS,oBAAoB,OAAsB;CACjD,IAAI;EACF,MAAM,cAAe,WAA8E;EACnG,IAAI,OAAO,gBAAgB,YAAY;GACrC,YAAY,KAAK;GACjB;EACF;CACF,QAAQ,CAER;CAEA,IAAI;EACF,WAAW,SAAS,MAAM,KAAK;CACjC,QAAQ,CAER;AACF;;;AClDA,SAAgB,kBAAkB,MAAuB,MAAc,SAAiB,UAAmB,OAA8B;CACvI,OAAO,UAAU,KAAA,IAAY;EAAE;EAAM;EAAM;EAAS;CAAS,IAAI;EAAE;EAAM;EAAM;EAAS;EAAU,OAAO,eAAe,KAAK;CAAE;AACjI;AAMA,SAAgB,uBAAuB,OAA2B;CAChE,MAAM,YAAY,IAAI,MAAM,MAAM,OAAO;CACzC,UAAU,OAAO,MAAM;CACvB,OAAO;AACT;AAEA,SAAS,eAAe,OAAmD;CACzE,IAAI,iBAAiB,OACnB,OAAO;EAAE,MAAM,MAAM;EAAM,SAAS,MAAM;CAAQ;CAGpD,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EAC/C,MAAM,QAAQ;EACd,OAAO;GACL,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;GACpD,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,OAAO,KAAK;EAC3E;CACF;CAEA,OAAO;EAAE,MAAM;EAAS,SAAS,OAAO,KAAK;CAAE;AACjD;;;AChBA,MAAM,OAAO;CACX,KAAK;CACL,MAAM;CACN,KAAK;CACL,KAAK;CACL,MAAM;AACR;AAEA,SAAS,WAAc,MAAe,UAAgB;CACpD,IAAI;EACF,OAAO,KAAK;CACd,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,4BAAmD;CAC1D,MAAM,kBAAkB,iBAAiB,OAAO,WAAW,YAAY,KAAK;CAC5E,MAAM,iBAAiB,iBAAiB,OAAO,UAAU,YAAY,KAAK;CAC1E,MAAM,wBAAwB,iBAAiB,OAAO,aAAa,cAAc,SAAS,cAAc,KAAA,KAAa,UAAU,SAAS,WAAW,KAAK;CACxJ,MAAM,iBAAiB,iBAAiB,OAAO,mBAAmB,YAAY,KAAK;CACnF,MAAM,cAAc,iBAAiB,OAAO,gBAAgB,YAAY,OAAO,YAAY,gBAAgB,YAAY,KAAK;CAC5H,MAAM,yBAAyB,iBAAkB,OAAO,gBAAgB,aAAa,cAAc,KAAA,GAAY,KAAA,CAA2C;CAC1J,MAAM,cAAc,2BAA2B,KAAA;CAC/C,MAAM,yBAAyB,eAAe,iBAAiB,uBAAuB,kCAAkC,MAAM,KAAK;CACnI,MAAM,kBAAkB,cACpB,iBACS,OAAO,uBAAuB,oBAAoB,aAAa,uBAAuB,gBAAgB,KAAK,sBAAsB,IAAI,KAAA,GAC5I,KAAA,CACF,IACA,KAAA;CAEJ,OAAO;EACL;EACA,gBAAgB,kBAAkB;EAClC;EACA;EACA;EACA;EACA;CACF;AACF;AAEA,SAAS,UAAU,iBAA2D,MAA6B;CACzG,IAAI,oBAAoB,KAAA,GACtB,OAAO;CAGT,IAAI;EACF,OAAO,gBAAgB,IAAI,IAAI,cAAc;CAC/C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,eAAe,OAAsB,OAAqC;CACjF,IAAI,UAAU,iBAAiB,UAAU,eACvC,OAAO;CAET,IAAI,UAAU,eAAe,UAAU,aACrC,OAAO;CAET,OAAO;AACT;AAEA,SAAS,8BAA8B,aAAwD;CAC7F,MAAM,UAA+B;EACnC,iBAAiB,YAAY;EAC7B,WAAW,YAAY,0BAA0B,YAAY,oBAAoB,KAAA;EACjF,gBAAgB,YAAY;EAC5B,gBAAgB,YAAY;EAC5B,aAAa,YAAY;CAC3B;CACA,MAAM,QAAQ;EACZ,KAAK,UAAU,YAAY,iBAAiB,KAAK,GAAG;EACpD,MAAM,UAAU,YAAY,iBAAiB,KAAK,IAAI;EACtD,KAAK,UAAU,YAAY,iBAAiB,KAAK,GAAG;CACtD;CACA,MAAM,QAAQ;EACZ,KAAK,UAAU,YAAY,iBAAiB,KAAK,GAAG;EACpD,MAAM,UAAU,YAAY,iBAAiB,KAAK,IAAI;CACxD;CAEA,OAAO;EACL,WAAW,OAAO,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO;EAC/C;EACA,UAAU;GACR;GACA;GACA,gBAAgB;IACd,QAAQ,eAAe,MAAM,KAAK,MAAM,GAAG;IAC3C,SAAS,eAAe,MAAM,MAAM,MAAM,GAAG;GAC/C;EACF;CACF;AACF;AAEA,SAAgB,kBAAsC;CACpD,OAAO,8BAA8B,0BAA0B,CAAC;AAClE;AAEA,SAAgB,cAAuB;CACrC,OAAO,gBAAgB,CAAC,CAAC;AAC3B;AAEA,SAAgB,wBAAwB,cAAc,0BAA0B,GAA4B;CAC1G,IAAI,CAAC,YAAY,iBACf,OAAO,kBAAkB,eAAe,6BAA6B,sDAAsD,IAAI;CAGjI,IAAI,CAAC,YAAY,gBACf,OAAO,kBAAkB,eAAe,4BAA4B,2CAA2C,IAAI;CAGrH,IAAI,CAAC,YAAY,gBACf,OAAO,kBAAkB,eAAe,sCAAsC,oDAAoD,IAAI;CAGxI,IAAI,CAAC,YAAY,aACf,OAAO,kBAAkB,eAAe,2BAA2B,iDAAiD,IAAI;CAG1H,IAAI,CAAC,YAAY,aACf,OAAO,kBAAkB,eAAe,0BAA0B,iDAAiD,IAAI;CAGzH,IAAI,CAAC,YAAY,wBACf,OAAO,kBAAkB,eAAe,iCAAiC,4EAA4E,IAAI;CAG3J,IAAI,YAAY,oBAAoB,KAAA,GAClC,OAAO,kBAAkB,eAAe,qCAAqC,iEAAiE,IAAI;AAItJ;;;ACjJA,MAAM,gCAA+D;CACnE,UAAU;EACR,UAAU;EACV,OAAO;CACT;CACA,SAAS;EACP,eAAe;EACf,QAAQ;EACR,KAAK;EACL,kBAAkB;EAClB,gBAAgB;CAClB;CACA,SAAS;EACP,SAAS,CAAC;EACV,aAAa;EACb,mBAAmB;EACnB,OAAO;GACL,aAAa;GACb,WAAW;GACX,cAAc;GACd,aAAa;EACf;CACF;CACA,SAAS,CAAC;CACV,aAAa,EAAE,iBAAiB,IAAK;AACvC;AAEA,SAAgB,uBAAuB,UAA+B,CAAC,GAAkC;CACvG,MAAM,oBAAoB;EACxB,UAAU;GACR,GAAG,8BAA8B;GACjC,GAAG,QAAQ;EACb;EACA,SAAS;GACP,GAAG,8BAA8B;GACjC,GAAG,QAAQ;EACb;EACA,SAAS;GACP,GAAG,8BAA8B;GACjC,GAAG,QAAQ;GACX,SAAS;IACP,GAAG,8BAA8B,QAAQ;IACzC,GAAG,QAAQ,SAAS;GACtB;GACA,OAAO;IACL,GAAG,8BAA8B,QAAQ;IACzC,GAAG,QAAQ,SAAS;GACtB;EACF;EACA,SAAS,wBAAwB,OAAO;EACxC,aAAa;GACX,GAAG,8BAA8B;GACjC,GAAG,QAAQ;EACb;CACF;CAEA,0BAA0B,iBAAiB;CAC3C,OAAO;AACT;AAEA,SAAS,0BAA0B,SAA8C;CAC/E,uBAAuB,OAAO;CAC9B,uBAAuB,OAAO;AAChC;AAEA,SAAS,uBAAuB,SAA8C;CAC5E,MAAM,UAAU,QAAQ;CAExB,+BAA+B,QAAQ,eAAe,uBAAuB;CAC7E,4BAA4B,QAAQ,QAAQ,gBAAgB;CAC5D,+BAA+B,QAAQ,KAAK,aAAa;CACzD,+BAA+B,QAAQ,kBAAkB,0BAA0B;CACnF,+BAA+B,QAAQ,gBAAgB,wBAAwB;CAE/E,IAAI,QAAQ,MAAM,QAAQ,QACxB,iBAAiB,WAAW,iCAAiC,8DAA8D;CAG7H,IAAI,QAAQ,mBAAmB,QAAQ,QACrC,iBAAiB,WAAW,iCAAiC,2EAA2E;AAE5I;AAEA,SAAS,uBAAuB,SAA8C;CAC5E,MAAM,UAAU,QAAQ;CACxB,MAAM,QAAQ,QAAQ;CAEtB,sBAAsB,QAAQ,mBAAmB,2BAA2B;CAC5E,sBAAsB,MAAM,aAAa,2BAA2B;CACpE,yBAAyB,MAAM,WAAW,yBAAyB;CACnE,yBAAyB,MAAM,cAAc,4BAA4B;CAEzE,IAAI,MAAM,eAAe,MAAM,WAC7B,iBAAiB,WAAW,iCAAiC,sFAAsF;CAGrJ,IAAI,CAAC,OAAO,SAAS,MAAM,WAAW,KAAK,MAAM,cAAc,KAAK,MAAM,cAAc,GACtF,iBAAiB,WAAW,iCAAiC,oEAAoE;AAErI;AAEA,SAAS,wBAAwB,SAAwE;CACvG,OAAO;EACL,GAAI,QAAQ,SAAS,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,QAAQ,UAAU;EAC3F,GAAI,QAAQ,SAAS,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ,QAAQ;CACvF;AACF;AAEA,SAAS,+BAA+B,OAAe,OAAqB;CAC1E,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GACrC,iBAAiB,WAAW,iCAAiC,GAAG,MAAM,qDAAqD;AAE/H;AAEA,SAAS,4BAA4B,OAAe,OAAqB;CACvE,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GACtC,iBAAiB,WAAW,iCAAiC,GAAG,MAAM,yCAAyC;AAEnH;AAEA,SAAS,sBAAsB,OAAe,OAAqB;CACjE,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,iBAAiB,WAAW,iCAAiC,GAAG,MAAM,gDAAgD;AAE1H;AAEA,SAAS,yBAAyB,OAAe,OAAqB;CACpE,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,iBAAiB,WAAW,iCAAiC,GAAG,MAAM,gDAAgD;AAE1H;AAEA,SAAS,iBAAiB,MAAuB,MAAc,SAAwB;CACrF,MAAM,uBAAuB,kBAAkB,MAAM,MAAM,SAAS,IAAI,CAAC;AAC3E;;;ACxIA,IAAa,qBAAb,MAAgC;CAC9B;CACA;CACA;CAEA,YAAY,SAAoC;EAC9C,KAAK,UAAU;CACjB;CAEA,IAAI,WAAoB;EACtB,OAAO,KAAK,UAAU,KAAA;CACxB;CAEA,aAAa,OAAkC;EAC7C,OAAO,KAAK,UAAU;CACxB;CAEA,OAAO,OAA+B;EACpC,KAAK,QAAQ;EACb,MAAM,QAAQ,KAAK,QAAQ;EAC3B,MAAM,WAAW,KAAK,QAAQ;CAChC;CAEA,wBAAwB,QAAoC;EAC1D,IAAI,KAAK,UAAU,KAAA,GACjB,OAAO;EAGT,QAAQ,IAAI,KAAK,OAAO,aAAa,MAAM;EAC3C,OAAO;CACT;CAEA,oBAAoB,YAAoB,QAAkD;EACxF,KAAK,mBAAmB;EACxB,MAAM,2BAAiC;GACrC,MAAM,QAAQ,KAAK,SAAS;GAC5B,IAAI,UAAU,KAAA,GACZ,OAAO,KAAK;EAEhB;EAEA,mBAAmB;EACnB,KAAK,aAAa,YAAY,oBAAoB,UAAU;CAC9D;CAEA,qBAA2B;EACzB,IAAI,KAAK,eAAe,KAAA,GAAW;GACjC,cAAc,KAAK,UAAU;GAC7B,KAAK,aAAa,KAAA;EACpB;CACF;CAEA,MAAM,aAAa,QAA+D;EAChF,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,KAAA,GACZ,OAAO;GACL,MAAM,OAAO;GACb,UAAU;GACV,OAAO;IACL,MAAM;IACN,SAAS;GACX;EACF;EAGF,IAAI;GACF,QAAQ,OAAO,MAAf;IACE,KAAK;KACH,MAAM,MAAM,KAAK;KACjB;IACF,KAAK;KACH,MAAM,eAAe,OAAO;KAC5B;IACF,KAAK,QACH,MAAM,cAAc,OAAO;GAE/B;GACA,OAAO;IAAE,MAAM,OAAO;IAAM,UAAU;GAAK;EAC7C,SAAS,OAAO;GACd,OAAO;IACL,MAAM,OAAO;IACb,UAAU;IACV,OAAO,8BAA8B,KAAK;GAC5C;EACF;CACF;CAEA,eAAqB;EACnB,IAAI,KAAK,UAAU,KAAA,GACjB;EAGF,KAAK,MAAM,MAAM;EACjB,KAAK,MAAM,eAAe;EAC1B,KAAK,MAAM,gBAAgB,KAAK;EAChC,KAAK,MAAM,YAAY;EACvB,KAAK,MAAM,KAAK;CAClB;CAEA,UAAgB;EACd,KAAK,mBAAmB;EACxB,KAAK,aAAa;EAClB,KAAK,QAAQ,KAAA;CACf;CAEA,WAAkD;EAChD,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,KAAA,GACZ;EAGF,MAAM,gBAAgB,iBAAiB,KAAK;EAC5C,OAAO;GACL,aAAa,OAAO,SAAS,MAAM,WAAW,IAAI,MAAM,cAAc;GACtE,YAAY,MAAM;GAClB,cAAc,MAAM;GACpB,QAAQ,MAAM;GACd,GAAI,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc;EACzD;CACF;AACF;AAEA,SAAS,8BAA8B,OAAmD;CACxF,IAAI,iBAAiB,OACnB,OAAO;EACL,MAAM,gCAAgC,MAAM,MAAM,OAAO;EACzD,SAAS,gCAAgC,MAAM,SAAS,iCAAiC;CAC3F;CAGF,IAAI;EACF,OAAO;GACL,MAAM;GACN,SAAS,OAAO,KAAK;EACvB;CACF,QAAQ;EACN,OAAO;GACL,MAAM;GACN,SAAS;EACX;CACF;AACF;AAEA,SAAS,0BAA0B,MAAqB,UAA0B;CAChF,IAAI;EACF,OAAO,OAAO,KAAK,CAAC;CACtB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,iBAAiB,OAA6C;CACrE,MAAM,UAAU,MAAM,0BAA0B;CAChD,IAAI,YAAY,KAAA,KAAa,OAAO,SAAS,QAAQ,kBAAkB,GACrE,OAAO,QAAQ;CAGjB,MAAM,0BAA2B,MAAkE;CACnG,OAAO,OAAO,SAAS,uBAAuB,IAAI,0BAA0B,KAAA;AAC9E;;;;;;;;;ACjIA,IAAa,eAAb,MAA0B;;CAExB;;CAGA;CACA;CACA,SAA0B,IAAI,mBAAmB;CACjD;CACA;CACA;CACA;CACA,QAA6B;CAC7B,sBAA8B;CAC9B;CACA,yBAAiC;CACjC;CACA;CACA;CAUA,YAAY,KAAa,SAA+B,WAAmC;EACzF,cAAc,CAAC;EACf,KAAK,MAAM;EACX,KAAK,UAAU,uBAAuB,OAAO;EAC7C,KAAK,KAAK,UAAU,YAAY,KAAK,eAAe;EACpD,KAAK,gBAAgB,UAAU,iBAAiB;EAChD,KAAK,gBAAgB,UAAU,iBAAiB;EAChD,KAAK,WAAW,IAAI,mBAAmB,KAAK,QAAQ,QAAQ;CAC9D;;;;;;CAOA,MAAM,OAAO,OAAwC;EACnD,KAAK,kBAAkB,QAAQ;EAC/B,MAAM,sBAAsB,KAAK;EAEjC,IAAI,KAAK,SAAS,YAAY,CAAC,KAAK,SAAS,aAAa,KAAK,GAC7D,MAAM,uBAAuB,kBAAkB,WAAW,2BAA2B,uDAAuD,KAAK,CAAC;EAGpJ,MAAM,eAAe,KAAK,cAAc;EACxC,IAAI,iBAAiB,KAAA,GAAW;GAC9B,KAAK,OAAO,KAAK,SAAS,YAAY;GACtC,MAAM,uBAAuB,YAAY;EAC3C;EAEA,KAAK,SAAS,OAAO,KAAK;EAC1B,KAAK,mBAAmB;EACxB,MAAM,KAAK,cAAc,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;EACjF,IAAI,CAAC,KAAK,4BAA4B,mBAAmB,GACvD;EAEF,KAAK,QAAQ;CACf;;;;;;;;CASA,QAAuB;EACrB,IAAI;GACF,KAAK,kBAAkB,OAAO;EAChC,SAAS,OAAO;GACd,OAAO,QAAQ,OAAO,KAAK;EAC7B;EAEA,IAAI,CAAC,KAAK,SAAS,YAAY,KAAK,iBAAiB,KAAA,GACnD,OAAO,QAAQ,OACb,uBAAuB,kBAAkB,WAAW,gCAAgC,yDAAyD,KAAK,CAAC,CACrJ;EAGF,IAAI,KAAK,UAAU,WACjB,OAAO,QAAQ,QAAQ;EAGzB,IAAI,KAAK,iBAAiB,KAAA,GACxB,OAAO,KAAK;EAGd,MAAM,sBAAsB,KAAK;EACjC,MAAM,gBAAgB,KAAK;EAC3B,KAAK,QAAQ;EACb,MAAM,WAAW,KAAK,aAAa,KAAK,cAAc,qBAAqB,kBAAkB,SAAS,CAAC,CAAC,cAAc;GACpH,IAAI,KAAK,iBAAiB,UACxB,KAAK,eAAe,KAAA;EAExB,CAAC;EACD,KAAK,eAAe;EACpB,OAAO;CACT;CAEA,MAAc,aAAa,cAA4B,qBAA6B,SAAiC;EACnH,IAAI;GACF,IAAI,SAAS;IACX,MAAM,aAAa,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;IAC3E,KAAK,4BAA4B,mBAAmB;GACtD;GAEA,MAAM,aAAa,eAAe,EAAE,MAAM,QAAQ,CAAC;GACnD,KAAK,4BAA4B,mBAAmB;EACtD,SAAS,OAAO;GACd,IAAI,KAAK,4BAA4B,mBAAmB,KAAK,KAAK,UAAU,YAC1E,KAAK,QAAQ,UAAU,YAAY;GAErC,MAAM,mBAAmB,KAAK;EAChC;EAEA,KAAK,QAAQ;EACb,KAAK,yBAAyB;CAChC;;;;;;;CAQA,OAAsB;EACpB,IAAI,KAAK,UAAU,eAAe,KAAK,UAAU,cAC/C,OAAO,QAAQ,QAAQ;EAGzB,IAAI,KAAK,UAAU,eACjB,OAAO,QAAQ,QAAQ;EAGzB,IAAI,KAAK,gBAAgB,KAAA,GACvB,OAAO,KAAK;EAGd,KAAK,uBAAuB;EAC5B,KAAK,QAAQ;EACb,MAAM,sBAAsB,KAAK;EACjC,MAAM,WAAW,KAAK,YAAY,mBAAmB,CAAC,CAAC,cAAc;GACnE,IAAI,KAAK,gBAAgB,UACvB,KAAK,cAAc,KAAA;EAEvB,CAAC;EACD,KAAK,cAAc;EACnB,OAAO;CACT;CAEA,MAAc,YAAY,qBAA4C;EACpE,MAAM,eAAe,KAAK;EAC1B,IAAI,iBAAiB,KAAA,GAAW;GAC9B,IAAI,KAAK,4BAA4B,mBAAmB,GAAG;IACzD,KAAK,yBAAyB;IAC9B,KAAK,QAAQ;IACb,KAAK,OAAO,KAAK,WAAW,KAAA,CAAS;GACvC;GACA;EACF;EAEA,KAAK,SAAS,mBAAmB;EACjC,IAAI;GACF,MAAM,aAAa,eAAe,EAAE,MAAM,OAAO,CAAC;EACpD,SAAS,OAAO;GACd,IAAI,CAAC,KAAK,4BAA4B,mBAAmB,GACvD;GAEF,MAAM;EACR;EACA,IAAI,CAAC,KAAK,4BAA4B,mBAAmB,GACvD;EAEF,KAAK,SAAS,aAAa;EAC3B,KAAK,yBAAyB;EAC9B,KAAK,QAAQ;CACf;;;;;;;CAQA,MAAM,UAAyB;EAC7B,IAAI,KAAK,UAAU,aACjB;EAGF,IAAI,KAAK,mBAAmB,KAAA,GAC1B,OAAO,KAAK;EAGd,KAAK,uBAAuB;EAC5B,KAAK,QAAQ;EACb,KAAK,iBAAiB,KAAK,eAAe;EAC1C,OAAO,KAAK;CACd;CAEA,MAAc,iBAAgC;EAC5C,MAAM,eAAe,KAAK;EAC1B,KAAK,eAAe,KAAA;EACpB,KAAK,SAAS,mBAAmB;EACjC,IAAI;EAEJ,IAAI,iBAAiB,KAAA,GACnB,IAAI;GACF,MAAM,aAAa,iBAAiB,EAAE,MAAM,UAAU,CAAC;EACzD,SAAS,OAAO;GACd,eAAe;EACjB,UAAU;GACR,aAAa,QAAQ;EACvB;OAEA,KAAK,OAAO,KAAK,aAAa,KAAA,CAAS;EAGzC,KAAK,SAAS,QAAQ;EAEtB,KAAK,QAAQ;EACb,KAAK,OAAO,MAAM;EAElB,IAAI,iBAAiB,KAAA,GACnB,MAAM;CAEV;;CAGA,GAA8B,MAAS,UAAwC;EAC7E,KAAK,OAAO,GAAG,MAAM,QAAQ;CAC/B;;CAGA,IAA+B,MAAS,UAAwC;EAC9E,KAAK,OAAO,IAAI,MAAM,QAAQ;CAChC;CAEA,qBAAmC;EACjC,IAAI,KAAK,iBAAiB,KAAA,GACxB;EAGF,MAAM,SAAS,KAAK,cAAc,KAAK,OAAO;EAC9C,KAAK,eAAe,IAAI,aAAa,QAAQ;GAC3C,YAAY,YAAY,KAAK,oBAAoB,OAAO;GACxD,UAAU,UAAU;IAClB,KAAK,qBAAqB,KAAK;IAC/B,KAAK,OAAO,KAAK,SAAS,KAAK;GACjC;EACF,CAAC;EACD,KAAK,aAAa,KAAK;GAAE,MAAM;GAAQ,IAAI,KAAK;GAAI,KAAK,KAAK;GAAK,SAAS,mBAAmB,KAAK,OAAO;EAAE,CAAC;CAChH;CAEA,oBAA4B,SAA8B;EACxD,IAAI,KAAK,UAAU,aACjB;EAGF,IAAK,KAAK,UAAU,gBAAgB,QAAQ,SAAS,eAAgB,KAAK,UAAU,eAClF;EAGF,QAAQ,QAAQ,MAAhB;GACE,KAAK;IACH,KAAK,OAAO,KAAK,eAAe,KAAA,CAAS;IACzC;GACF,KAAK;IACH,KAAK,wBAAwB,QAAQ,MAAM;IAC3C;GACF,KAAK,WACH;GACF,KAAK;IACH,KAAK,OAAO,KAAK,aAAa,QAAQ,SAAS;IAC/C;GACF,KAAK;IACH,KAAK,OAAO,KAAK,SAAS,QAAQ,KAAK;IACvC;GACF,KAAK;IACH,KAAK,OAAO,KAAK,WAAW,QAAQ,OAAO;IAC3C;GACF,KAAK;IACH,KAAK,OAAO,KAAK,gBAAgB,QAAQ,IAAI;IAC7C;GACF,KAAK;IACH,KAAK,OAAO,KAAK,aAAa,QAAQ,IAAI;IAC1C;GACF,KAAK;IACH,IAAI,QAAQ,MAAM,UAChB,KAAK,qBAAqB,QAAQ,KAAK;IAEzC,KAAK,OAAO,KAAK,SAAS,QAAQ,KAAK;IACvC;GACF,KAAK;IACH,KAAU,qBAAqB,QAAQ,MAAM;IAC7C;GACF,KAAK;IACH,KAAK,OAAO,KAAK,WAAW,KAAA,CAAS;IACrC;GACF,KAAK;IACH,KAAK,OAAO,KAAK,aAAa,KAAA,CAAS;IACvC;EACJ;CACF;CAEA,wBAAgC,QAAiC;EAC/D,IAAI,KAAK,UAAU,WAAW;GAC5B,KAAK,yBAAyB;GAC9B,KAAK,SAAS,aAAa;EAC7B;EACA,IAAI,CAAC,KAAK,SAAS,wBAAwB,MAAM,GAAG;GAClD,MAAM,QAAQ,kBACZ,WACA,sCACA,4EACA,IACF;GACA,KAAK,OAAO,KAAK,SAAS,KAAK;GAC/B,MAAM,uBAAuB,KAAK;EACpC;CACF;CAEA,2BAAyC;EACvC,MAAM,aAAa,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,QAAQ,YAAY,iBAAiB,GAAG,CAAC;EACxF,MAAM,eAAe,KAAK;EAC1B,IAAI,iBAAiB,KAAA,GACnB;EAGF,KAAK,SAAS,oBAAoB,aAAa,UAAU;GACvD,IAAI,KAAK,UAAU,aAAa,KAAK,iBAAiB,cACpD,aAAa,KAAK;IAAE,MAAM;IAAe;GAAM,CAAC;EAEpD,CAAC;CACH;CAEA,MAAc,qBAAqB,QAA8C;EAC/E,MAAM,eAAe,KAAK;EAC1B,MAAM,sBAAsB,KAAK;EACjC,IAAI,CAAC,KAAK,SAAS,YAAY,iBAAiB,KAAA,KAAa,KAAK,UAAU,WAC1E;EAGF,MAAM,SAAS,MAAM,KAAK,SAAS,aAAa,MAAM;EACtD,IAAI,CAAC,KAAK,4BAA4B,mBAAmB,KAAK,KAAK,UAAU,aAAa,KAAK,iBAAiB,cAC9G;EAEF,aAAa,KAAK;GAAE,MAAM;GAA2B;EAAO,CAAC;EAC7D,IACE,OAAO,SAAS,UAChB,OAAO,WAAW,0BAClB,KAAK,QAAQ,SAAS,YACtB,CAAC,OAAO,YACR,CAAC,KAAK,wBACN;GACA,KAAK,yBAAyB;GAC9B,KAAK,OAAO,KAAK,WAAW;IAC1B,MAAM;IACN,SAAS;IACT,OAAO,OAAO;GAChB,CAAC;EACH;CACF;CAEA,qBAA6B,OAA0B;EACrD,IAAI,KAAK,UAAU,eAAe,KAAK,UAAU,gBAAgB,KAAK,UAAU,eAC9E;EAGF,KAAK,uBAAuB;EAC5B,KAAK,gBAAgB;EACrB,KAAK,QAAQ;EACb,KAAK,SAAS,QAAQ;CACxB;CAEA,kBAA0B,QAAsB;EAC9C,IAAI,KAAK,UAAU,iBAAiB,KAAK,kBAAkB,KAAA,GACzD,MAAM,uBAAuB,KAAK,aAAa;EAGjD,IAAI,KAAK,UAAU,YACjB,MAAM,uBACJ,kBAAkB,WAAW,0BAA0B,gBAAgB,OAAO,+CAA+C,KAAK,CACpI;EAGF,IAAI,KAAK,UAAU,eAAe,KAAK,UAAU,cAC/C;EAIF,MAAM,uBAAuB,kBAAkB,WADlC,KAAK,UAAU,eAAe,6BAA6B,2BACR,gBAAgB,OAAO,8CAA8C,IAAI,CAAC;CAC5I;CAEA,4BAAoC,YAA6B;EAC/D,OAAO,eAAe,KAAK,uBAAuB,KAAK,UAAU,iBAAiB,KAAK,UAAU,gBAAgB,KAAK,UAAU;CAClI;CAEA,4BAAoC,YAA0B;EAC5D,IAAI,KAAK,4BAA4B,UAAU,KAAK,KAAK,UAAU,YACjE;EAIF,MAAM,kBAAkB,WAAW,0BAA0B,0BAD9C,KAAK,UAAU,gBAAgB,KAAK,UAAU,cAAc,YAAY,OACO,IAAI,KAAK;CACzG;AACF;AAEA,SAAS,mBAAmB,OAAuB;CACjD,OAAO,cAAc,KAAK,IAAI,uBAAuB,KAAK,IAAI,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACxH;AAEA,SAAS,cAAc,OAAsC;CAC3D,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;CAGT,MAAM,YAAY;CAClB,OACE,OAAO,UAAU,SAAS,YAAY,OAAO,UAAU,SAAS,YAAY,OAAO,UAAU,YAAY,YAAY,OAAO,UAAU,aAAa;AAEvJ;AAEA,SAAS,iBAAyB;CAEhC,OADe,WAAW,QAAQ,aAAa,KAC9B,UAAU,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;AAC1F;AAEA,SAAS,mBAAmB,SAAuE;CACjG,IAAI,QAAQ,QAAQ,YAAY,KAAA,GAC9B,OAAO;CAGT,OAAO;EACL,GAAG;EACH,SAAS;GACP,GAAG,QAAQ;GACX,SAAS,kBAAkB;EAC7B;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/events.ts","../src/errors.ts","../src/feature-detect.ts","../src/options.ts","../src/playback-controller.ts","../src/player.ts"],"sourcesContent":["import type { PlayerEventListener, PlayerEventMap, PlayerEventType } from '@rivmux/protocol'\n\nexport class PlayerEventEmitter {\n private readonly listeners = new Map<PlayerEventType, Set<PlayerEventListener<PlayerEventType>>>()\n\n on<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n const typedListener = listener as PlayerEventListener<PlayerEventType>\n const listeners = this.listeners.get(type)\n\n if (listeners === undefined) {\n this.listeners.set(type, new Set([typedListener]))\n return\n }\n\n listeners.add(typedListener)\n }\n\n off<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n this.listeners.get(type)?.delete(listener as PlayerEventListener<PlayerEventType>)\n }\n\n emit<T extends PlayerEventType>(type: T, payload: PlayerEventMap[T]): void {\n for (const listener of this.listeners.get(type) ?? []) {\n try {\n listener(payload)\n } catch (error) {\n reportListenerError(error)\n }\n }\n }\n\n clear(): void {\n this.listeners.clear()\n }\n}\n\nfunction reportListenerError(error: unknown): void {\n try {\n const reportError = (globalThis as typeof globalThis & { reportError?: (error: unknown) => void }).reportError\n if (typeof reportError === 'function') {\n reportError(error)\n return\n }\n } catch {\n // Fall through to the non-throwing console fallback.\n }\n\n try {\n globalThis.console?.error(error)\n } catch {\n // Error reporting must never affect player behavior.\n }\n}\n","import type { PlayerError, PlayerErrorKind } from '@rivmux/protocol'\n\nexport function createPlayerError(kind: PlayerErrorKind, code: string, message: string, terminal: boolean, cause?: unknown): PlayerError {\n return cause === undefined ? { kind, code, message, terminal } : { kind, code, message, terminal, cause: serializeCause(cause) }\n}\n\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\nexport function playerErrorToException(error: PlayerError): Error {\n const exception = new Error(error.message)\n exception.name = error.code\n return exception\n}\n\nfunction serializeCause(cause: unknown): { name: string; message: string } {\n if (cause instanceof Error) {\n return { name: cause.name, message: cause.message }\n }\n\n if (typeof cause === 'object' && cause !== null) {\n const value = cause as { name?: unknown; message?: unknown }\n return {\n name: typeof value.name === 'string' ? value.name : 'Error',\n message: typeof value.message === 'string' ? value.message : String(cause),\n }\n }\n\n return { name: 'Error', message: String(cause) }\n}\n","import { createPlayerError } from './errors'\n\nimport type { PlayerError, RivmuxCapabilities, RuntimeCapabilities, SupportStatus } from '@rivmux/protocol'\n\ninterface CapabilityEnvironment {\n dedicatedWorker: boolean\n fetchStreaming: boolean\n readableStream: boolean\n webAssembly: boolean\n mediaSource: boolean\n workerMseConstructable: boolean\n isTypeSupported?: (mime: string) => boolean\n}\n\nconst MIME = {\n avc: 'video/mp4; codecs=\"avc1.42E01E\"',\n hevc: 'video/mp4; codecs=\"hvc1.1.6.L93.B0\"',\n av1: 'video/mp4; codecs=\"av01.0.08M.08\"',\n aac: 'audio/mp4; codecs=\"mp4a.40.2\"',\n opus: 'audio/mp4; codecs=\"opus\"',\n} as const\n\nfunction safelyRead<T>(read: () => T, fallback: T): T {\n try {\n return read()\n } catch {\n return fallback\n }\n}\n\nfunction readCapabilityEnvironment(): CapabilityEnvironment {\n const dedicatedWorker = safelyRead(() => typeof Worker === 'function', false)\n const fetchAvailable = safelyRead(() => typeof fetch === 'function', false)\n const responseBodyAvailable = safelyRead(() => typeof Response === 'function' && Response.prototype !== undefined && 'body' in Response.prototype, false)\n const readableStream = safelyRead(() => typeof ReadableStream === 'function', false)\n const webAssembly = safelyRead(() => typeof WebAssembly === 'object' && typeof WebAssembly.instantiate === 'function', false)\n const mediaSourceConstructor = safelyRead(() => (typeof MediaSource === 'function' ? MediaSource : undefined), undefined as typeof MediaSource | undefined)\n const mediaSource = mediaSourceConstructor !== undefined\n const workerMseConstructable = mediaSource && safelyRead(() => mediaSourceConstructor.canConstructInDedicatedWorker === true, false)\n const isTypeSupported = mediaSource\n ? safelyRead(\n () => (typeof mediaSourceConstructor.isTypeSupported === 'function' ? mediaSourceConstructor.isTypeSupported.bind(mediaSourceConstructor) : undefined),\n undefined\n )\n : undefined\n\n return {\n dedicatedWorker,\n fetchStreaming: fetchAvailable && responseBodyAvailable,\n readableStream,\n webAssembly,\n mediaSource,\n workerMseConstructable,\n isTypeSupported,\n }\n}\n\nfunction probeMime(isTypeSupported: CapabilityEnvironment['isTypeSupported'], mime: string): SupportStatus {\n if (isTypeSupported === undefined) {\n return 'unknown'\n }\n\n try {\n return isTypeSupported(mime) ? 'supported' : 'unsupported'\n } catch {\n return 'unknown'\n }\n}\n\nfunction getCapabilitiesForEnvironment(environment: CapabilityEnvironment): RivmuxCapabilities {\n const runtime: RuntimeCapabilities = {\n dedicatedWorker: environment.dedicatedWorker,\n workerMse: environment.workerMseConstructable && environment.isTypeSupported !== undefined,\n fetchStreaming: environment.fetchStreaming,\n readableStream: environment.readableStream,\n webAssembly: environment.webAssembly,\n }\n const video = {\n avc: probeMime(environment.isTypeSupported, MIME.avc),\n hevc: probeMime(environment.isTypeSupported, MIME.hevc),\n av1: probeMime(environment.isTypeSupported, MIME.av1),\n }\n const audio = {\n aac: probeMime(environment.isTypeSupported, MIME.aac),\n opus: probeMime(environment.isTypeSupported, MIME.opus),\n }\n\n return {\n supported: Object.values(runtime).every(Boolean),\n runtime,\n decoding: {\n video,\n audio,\n },\n }\n}\n\nexport function getCapabilities(): RivmuxCapabilities {\n return getCapabilitiesForEnvironment(readCapabilityEnvironment())\n}\n\nexport function isSupported(): boolean {\n return getCapabilities().supported\n}\n\nexport function detectMainThreadRuntime(environment = readCapabilityEnvironment()): PlayerError | undefined {\n if (!environment.dedicatedWorker) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_WORKER', 'Dedicated Worker is not available in this runtime.', true)\n }\n\n if (!environment.fetchStreaming) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_FETCH', 'Fetch is not available in this runtime.', true)\n }\n\n if (!environment.readableStream) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_READABLE_STREAM', 'ReadableStream is not available in this runtime.', true)\n }\n\n if (!environment.webAssembly) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_WASM', 'WebAssembly is not available in this runtime.', true)\n }\n\n if (!environment.mediaSource) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_MSE', 'MediaSource is not available in this runtime.', true)\n }\n\n if (!environment.workerMseConstructable) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_WORKER_MSE', 'MediaSource cannot be constructed in a dedicated worker in this runtime.', true)\n }\n\n if (environment.isTypeSupported === undefined) {\n return createPlayerError('unsupported', 'RIVMUX_UNSUPPORTED_MSE_TYPE_CHECK', 'MediaSource.isTypeSupported is not available in this runtime.', true)\n }\n\n return undefined\n}\n","import { createPlayerError, playerErrorToException } from './errors'\n\nimport type { NormalizedRivmuxPlayerOptions, PlayerErrorKind, RivmuxPlayerOptions } from '@rivmux/protocol'\n\nconst DEFAULT_RIVMUX_PLAYER_OPTIONS: NormalizedRivmuxPlayerOptions = {\n playback: {\n autoPlay: true,\n muted: false,\n },\n latency: {\n startupBuffer: 0.35,\n target: 1.2,\n max: 2.5,\n maxForwardBuffer: 4,\n backwardBuffer: 1.5,\n },\n network: {\n headers: {},\n credentials: 'same-origin',\n readIdleTimeoutMs: 10_000,\n retry: {\n maxAttempts: 3,\n backoffMs: 500,\n maxBackoffMs: 8_000,\n jitterRatio: 0.2,\n },\n },\n runtime: {},\n diagnostics: { statsIntervalMs: 1000 },\n}\n\nexport function normalizePlayerOptions(options: RivmuxPlayerOptions = {}): NormalizedRivmuxPlayerOptions {\n const normalizedOptions = {\n playback: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.playback,\n ...options.playback,\n },\n latency: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.latency,\n ...options.latency,\n },\n network: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.network,\n ...options.network,\n headers: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.network.headers,\n ...options.network?.headers,\n },\n retry: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.network.retry,\n ...options.network?.retry,\n },\n },\n runtime: normalizeRuntimeOptions(options),\n diagnostics: {\n ...DEFAULT_RIVMUX_PLAYER_OPTIONS.diagnostics,\n ...options.diagnostics,\n },\n }\n\n validateNormalizedOptions(normalizedOptions)\n return normalizedOptions\n}\n\nfunction validateNormalizedOptions(options: NormalizedRivmuxPlayerOptions): void {\n validateLatencyOptions(options)\n validateNetworkOptions(options)\n}\n\nfunction validateLatencyOptions(options: NormalizedRivmuxPlayerOptions): void {\n const latency = options.latency\n\n assertFiniteNonNegativeLatency(latency.startupBuffer, 'latency.startupBuffer')\n assertFinitePositiveLatency(latency.target, 'latency.target')\n assertFiniteNonNegativeLatency(latency.max, 'latency.max')\n assertFiniteNonNegativeLatency(latency.maxForwardBuffer, 'latency.maxForwardBuffer')\n assertFiniteNonNegativeLatency(latency.backwardBuffer, 'latency.backwardBuffer')\n\n if (latency.max < latency.target) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', 'latency.max must be greater than or equal to latency.target.')\n }\n\n if (latency.maxForwardBuffer < latency.target) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', 'latency.maxForwardBuffer must be greater than or equal to latency.target.')\n }\n}\n\nfunction validateNetworkOptions(options: NormalizedRivmuxPlayerOptions): void {\n const network = options.network\n const retry = network.retry\n\n assertPositiveInteger(network.readIdleTimeoutMs, 'network.readIdleTimeoutMs')\n assertPositiveInteger(retry.maxAttempts, 'network.retry.maxAttempts')\n assertNonNegativeInteger(retry.backoffMs, 'network.retry.backoffMs')\n assertNonNegativeInteger(retry.maxBackoffMs, 'network.retry.maxBackoffMs')\n\n if (retry.maxBackoffMs < retry.backoffMs) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', 'network.retry.maxBackoffMs must be greater than or equal to network.retry.backoffMs.')\n }\n\n if (!Number.isFinite(retry.jitterRatio) || retry.jitterRatio < 0 || retry.jitterRatio > 1) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', 'network.retry.jitterRatio must be a finite number between 0 and 1.')\n }\n}\n\nfunction normalizeRuntimeOptions(options: RivmuxPlayerOptions): NormalizedRivmuxPlayerOptions['runtime'] {\n return {\n ...(options.runtime?.workerUrl === undefined ? {} : { workerUrl: options.runtime.workerUrl }),\n ...(options.runtime?.wasmUrl === undefined ? {} : { wasmUrl: options.runtime.wasmUrl }),\n }\n}\n\nfunction assertFiniteNonNegativeLatency(value: number, field: string): void {\n if (!Number.isFinite(value) || value < 0) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', `${field} must be a finite number greater than or equal to 0.`)\n }\n}\n\nfunction assertFinitePositiveLatency(value: number, field: string): void {\n if (!Number.isFinite(value) || value <= 0) {\n throwOptionError('runtime', 'RIVMUX_INVALID_LATENCY_OPTION', `${field} must be a finite number greater than 0.`)\n }\n}\n\nfunction assertPositiveInteger(value: number, field: string): void {\n if (!Number.isInteger(value) || value < 1) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', `${field} must be an integer greater than or equal to 1.`)\n }\n}\n\nfunction assertNonNegativeInteger(value: number, field: string): void {\n if (!Number.isInteger(value) || value < 0) {\n throwOptionError('runtime', 'RIVMUX_INVALID_NETWORK_OPTION', `${field} must be an integer greater than or equal to 0.`)\n }\n}\n\nfunction throwOptionError(kind: PlayerErrorKind, code: string, message: string): never {\n throw playerErrorToException(createPlayerError(kind, code, message, true))\n}\n","import type { NormalizedPlaybackOptions, PlaybackControlAction, PlaybackControlResult, VideoElementState } from '@rivmux/protocol'\n\nexport class PlaybackController {\n private readonly options: NormalizedPlaybackOptions\n private video?: HTMLVideoElement\n private stateTimer?: ReturnType<typeof setInterval>\n\n constructor(options: NormalizedPlaybackOptions) {\n this.options = options\n }\n\n get attached(): boolean {\n return this.video !== undefined\n }\n\n isAttachedTo(video: HTMLVideoElement): boolean {\n return this.video === video\n }\n\n attach(video: HTMLVideoElement): void {\n this.video = video\n video.muted = this.options.muted\n video.autoplay = this.options.autoPlay\n }\n\n attachMediaSourceHandle(handle: MediaSourceHandle): boolean {\n if (this.video === undefined) {\n return false\n }\n\n Reflect.set(this.video, 'srcObject', handle)\n return true\n }\n\n startStateReporting(intervalMs: number, report: (state: VideoElementState) => void): void {\n this.stopStateReporting()\n const reportCurrentState = (): void => {\n const state = this.snapshot()\n if (state !== undefined) {\n report(state)\n }\n }\n\n reportCurrentState()\n this.stateTimer = setInterval(reportCurrentState, intervalMs)\n }\n\n stopStateReporting(): void {\n if (this.stateTimer !== undefined) {\n clearInterval(this.stateTimer)\n this.stateTimer = undefined\n }\n }\n\n async applyControl(action: PlaybackControlAction): Promise<PlaybackControlResult> {\n const video = this.video\n if (video === undefined) {\n return {\n type: action.type,\n accepted: false,\n error: {\n name: 'NotAttachedError',\n message: 'No video element is attached.',\n },\n }\n }\n\n try {\n switch (action.type) {\n case 'play':\n await video.play()\n break\n case 'set-playback-rate':\n video.playbackRate = action.playbackRate\n break\n case 'seek':\n video.currentTime = action.targetTime\n break\n }\n return { type: action.type, accepted: true }\n } catch (cause) {\n return {\n type: action.type,\n accepted: false,\n error: normalizePlaybackControlError(cause),\n }\n }\n }\n\n detachSource(): void {\n if (this.video === undefined) {\n return\n }\n\n this.video.pause()\n this.video.playbackRate = 1\n this.video.removeAttribute('src')\n this.video.srcObject = null\n this.video.load()\n }\n\n release(): void {\n this.stopStateReporting()\n this.detachSource()\n this.video = undefined\n }\n\n private snapshot(): VideoElementState | undefined {\n const video = this.video\n if (video === undefined) {\n return undefined\n }\n\n const droppedFrames = getDroppedFrames(video)\n return {\n currentTime: Number.isFinite(video.currentTime) ? video.currentTime : 0,\n readyState: video.readyState,\n playbackRate: video.playbackRate,\n paused: video.paused,\n ...(droppedFrames === undefined ? {} : { droppedFrames }),\n }\n }\n}\n\nfunction normalizePlaybackControlError(cause: unknown): { name: string; message: string } {\n if (cause instanceof Error) {\n return {\n name: safelyStringifyErrorField(() => cause.name, 'Error'),\n message: safelyStringifyErrorField(() => cause.message, 'Unknown playback control error.'),\n }\n }\n\n try {\n return {\n name: 'Error',\n message: String(cause),\n }\n } catch {\n return {\n name: 'Error',\n message: 'Unknown playback control error.',\n }\n }\n}\n\nfunction safelyStringifyErrorField(read: () => unknown, fallback: string): string {\n try {\n return String(read())\n } catch {\n return fallback\n }\n}\n\nfunction getDroppedFrames(video: HTMLVideoElement): number | undefined {\n const quality = video.getVideoPlaybackQuality?.()\n if (quality !== undefined && Number.isFinite(quality.droppedVideoFrames)) {\n return quality.droppedVideoFrames\n }\n\n const webkitDroppedFrameCount = (video as HTMLVideoElement & { webkitDroppedFrameCount?: number }).webkitDroppedFrameCount\n return Number.isFinite(webkitDroppedFrameCount) ? webkitDroppedFrameCount : undefined\n}\n","import { PlayerEventEmitter } from './events'\nimport { createPlayerError, playerErrorToException } from './errors'\nimport { detectMainThreadRuntime } from './feature-detect'\nimport { normalizePlayerOptions } from './options'\nimport { PlaybackController } from './playback-controller'\nimport { createRuntimeWorker, getBundledWasmUrl, WorkerClient } from '@rivmux/runtime-worker'\n\nimport type {\n NormalizedRivmuxPlayerOptions,\n PlaybackControlAction,\n PlayerError,\n PlayerEventListener,\n PlayerEventType,\n RivmuxPlayerOptions,\n WorkerMessage,\n} from '@rivmux/protocol'\nimport type { RuntimeWorkerFactory } from '@rivmux/runtime-worker'\n\ntype PlayerState = 'idle' | 'attached' | 'starting' | 'started' | 'stopping' | 'stopped' | 'fatal-error' | 'destroying' | 'destroyed'\n\ntype RivmuxPlayerInternals = {\n workerFactory?: RuntimeWorkerFactory\n detectRuntime?: () => PlayerError | undefined\n idFactory?: () => string\n}\n\n/**\n * Public browser player facade for one HTTP-FLV stream.\n *\n * Create one instance per stream URL, call `attach(video)` first, then\n * `start()`. Call `destroy()` when the instance is no longer needed.\n */\nexport class RivmuxPlayer {\n /** Original stream URL passed to the constructor. */\n readonly url: string\n\n /** @internal Fully normalized options with defaults applied. */\n readonly options: NormalizedRivmuxPlayerOptions\n private readonly id: string\n private readonly events = new PlayerEventEmitter()\n private readonly workerFactory: RuntimeWorkerFactory\n private readonly detectRuntime: () => PlayerError | undefined\n private readonly playback: PlaybackController\n private workerClient?: WorkerClient\n private state: PlayerState = 'idle'\n private lifecycleGeneration = 0\n private terminalError?: PlayerError\n private autoplayWarningEmitted = false\n private startPromise?: Promise<void>\n private stopPromise?: Promise<void>\n private destroyPromise?: Promise<void>\n\n /**\n * Creates a player instance for one stream URL.\n *\n * The instance does not start network loading until `start()` is called.\n */\n constructor(url: string, options?: RivmuxPlayerOptions)\n /** @internal Test-only dependency injection; omitted from generated declarations. */\n constructor(url: string, options?: RivmuxPlayerOptions, internals?: RivmuxPlayerInternals)\n constructor(url: string, options?: RivmuxPlayerOptions, internals?: RivmuxPlayerInternals) {\n internals ??= {}\n this.url = url\n this.options = normalizePlayerOptions(options)\n this.id = internals.idFactory?.() ?? createPlayerId()\n this.workerFactory = internals.workerFactory ?? createRuntimeWorker\n this.detectRuntime = internals.detectRuntime ?? detectMainThreadRuntime\n this.playback = new PlaybackController(this.options.playback)\n }\n\n /**\n * Attaches this player to a video element and prepares the worker/MSE pipe.\n *\n * Await this method before calling `start()`.\n */\n async attach(video: HTMLVideoElement): Promise<void> {\n this.assertOperational('attach')\n const lifecycleGeneration = this.lifecycleGeneration\n\n if (this.playback.attached && !this.playback.isAttachedTo(video)) {\n throw playerErrorToException(createPlayerError('runtime', 'RIVMUX_ALREADY_ATTACHED', 'This player is already attached to a video element.', false))\n }\n\n const runtimeError = this.detectRuntime()\n if (runtimeError !== undefined) {\n this.events.emit('error', runtimeError)\n throw playerErrorToException(runtimeError)\n }\n\n this.playback.attach(video)\n this.ensureWorkerClient()\n await this.workerClient?.waitForMediaSourceHandle({ type: 'attach-media-source' })\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n return\n }\n this.state = 'attached'\n }\n\n /**\n * Waits until the worker has created the transmux core and scheduled stream\n * consumption for this playback session.\n *\n * This does not wait for media data, `canplay`, or `video.play()`. Requires a\n * successful `attach(video)` call first.\n */\n start(): Promise<void> {\n try {\n this.assertOperational('start')\n } catch (cause) {\n return Promise.reject(cause)\n }\n\n if (!this.playback.attached || this.workerClient === undefined) {\n return Promise.reject(\n playerErrorToException(createPlayerError('runtime', 'RIVMUX_START_REQUIRES_ATTACH', 'start() requires a previously attached video element.', false))\n )\n }\n\n if (this.state === 'started') {\n return Promise.resolve()\n }\n\n if (this.startPromise !== undefined) {\n return this.startPromise\n }\n\n const lifecycleGeneration = this.lifecycleGeneration\n const previousState = this.state\n this.state = 'starting'\n const starting = this.performStart(this.workerClient, lifecycleGeneration, previousState === 'stopped').finally(() => {\n if (this.startPromise === starting) {\n this.startPromise = undefined\n }\n })\n this.startPromise = starting\n return starting\n }\n\n private async performStart(workerClient: WorkerClient, lifecycleGeneration: number, restart: boolean): Promise<void> {\n try {\n if (restart) {\n await workerClient.waitForMediaSourceHandle({ type: 'attach-media-source' })\n this.assertStartOperationCurrent(lifecycleGeneration)\n }\n\n await workerClient.waitForStarted({ type: 'start' })\n this.assertStartOperationCurrent(lifecycleGeneration)\n } catch (cause) {\n if (this.isLifecycleOperationCurrent(lifecycleGeneration) && this.state === 'starting') {\n this.state = restart ? 'stopped' : 'attached'\n }\n throw toPublicStartError(cause)\n }\n\n this.state = 'started'\n this.startVideoStateReporting()\n }\n\n /**\n * Stops loading and detaches the current media source.\n *\n * The instance remains reusable; call `start()` again to restart the same\n * stream after the player has stopped.\n */\n stop(): Promise<void> {\n if (this.state === 'destroyed' || this.state === 'destroying') {\n return Promise.resolve()\n }\n\n if (this.state === 'fatal-error') {\n return Promise.resolve()\n }\n\n if (this.stopPromise !== undefined) {\n return this.stopPromise\n }\n\n this.lifecycleGeneration += 1\n this.state = 'stopping'\n const lifecycleGeneration = this.lifecycleGeneration\n const stopping = this.performStop(lifecycleGeneration).finally(() => {\n if (this.stopPromise === stopping) {\n this.stopPromise = undefined\n }\n })\n this.stopPromise = stopping\n return stopping\n }\n\n private async performStop(lifecycleGeneration: number): Promise<void> {\n const workerClient = this.workerClient\n if (workerClient === undefined) {\n if (this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n this.autoplayWarningEmitted = false\n this.state = 'stopped'\n this.events.emit('stopped', undefined)\n }\n return\n }\n\n this.playback.stopStateReporting()\n try {\n await workerClient.waitForStopped({ type: 'stop' })\n } catch (error) {\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n return\n }\n throw error\n }\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration)) {\n return\n }\n this.playback.detachSource()\n this.autoplayWarningEmitted = false\n this.state = 'stopped'\n }\n\n /**\n * Releases worker resources, timers, listeners, and the attached video source.\n *\n * The instance is terminal after destroy and cannot be attached or started\n * again.\n */\n async destroy(): Promise<void> {\n if (this.state === 'destroyed') {\n return\n }\n\n if (this.destroyPromise !== undefined) {\n return this.destroyPromise\n }\n\n this.lifecycleGeneration += 1\n this.state = 'destroying'\n this.destroyPromise = this.performDestroy()\n return this.destroyPromise\n }\n\n private async performDestroy(): Promise<void> {\n const workerClient = this.workerClient\n this.workerClient = undefined\n this.playback.stopStateReporting()\n let destroyError: unknown\n\n if (workerClient !== undefined) {\n try {\n await workerClient.waitForDestroyed({ type: 'destroy' })\n } catch (error) {\n destroyError = error\n } finally {\n workerClient.dispose()\n }\n } else {\n this.events.emit('destroyed', undefined)\n }\n\n this.playback.release()\n\n this.state = 'destroyed'\n this.events.clear()\n\n if (destroyError !== undefined) {\n throw destroyError\n }\n }\n\n /** Registers an event listener for a typed player event. */\n on<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n this.events.on(type, listener)\n }\n\n /** Removes a previously registered event listener. */\n off<T extends PlayerEventType>(type: T, listener: PlayerEventListener<T>): void {\n this.events.off(type, listener)\n }\n\n private ensureWorkerClient(): void {\n if (this.workerClient !== undefined) {\n return\n }\n\n const worker = this.workerFactory(this.options)\n this.workerClient = new WorkerClient(worker, {\n onMessage: (message) => this.handleWorkerMessage(message),\n onError: (error) => {\n this.enterFatalErrorState(error)\n this.events.emit('error', error)\n },\n })\n this.workerClient.post({ type: 'init', id: this.id, url: this.url, options: withBundledWasmUrl(this.options) })\n }\n\n private handleWorkerMessage(message: WorkerMessage): void {\n if (this.state === 'destroyed') {\n return\n }\n\n if ((this.state === 'destroying' && message.type !== 'destroyed') || this.state === 'fatal-error') {\n return\n }\n\n switch (message.type) {\n case 'ready':\n this.events.emit('initialized', undefined)\n return\n case 'media-source-handle':\n this.attachMediaSourceHandle(message.handle)\n return\n case 'started':\n return\n case 'media-info':\n this.events.emit('mediaInfo', message.mediaInfo)\n return\n case 'stats':\n this.events.emit('stats', message.stats)\n return\n case 'warning':\n this.events.emit('warning', message.warning)\n return\n case 'reconnecting':\n this.events.emit('reconnecting', message.info)\n return\n case 'recovered':\n this.events.emit('recovered', message.info)\n return\n case 'error':\n if (message.error.terminal) {\n this.enterFatalErrorState(message.error)\n }\n this.events.emit('error', message.error)\n return\n case 'playback-control':\n void this.applyPlaybackControl(message.action)\n return\n case 'stopped':\n this.events.emit('stopped', undefined)\n return\n case 'destroyed':\n this.events.emit('destroyed', undefined)\n return\n }\n }\n\n private attachMediaSourceHandle(handle: MediaSourceHandle): void {\n if (this.state === 'started') {\n this.autoplayWarningEmitted = false\n this.playback.detachSource()\n }\n if (!this.playback.attachMediaSourceHandle(handle)) {\n const error = createPlayerError(\n 'runtime',\n 'RIVMUX_ATTACH_HANDLE_WITHOUT_VIDEO',\n 'Worker returned a MediaSourceHandle before a video element was attached.',\n true\n )\n this.events.emit('error', error)\n throw playerErrorToException(error)\n }\n }\n\n private startVideoStateReporting(): void {\n const intervalMs = Math.max(100, Math.min(this.options.diagnostics.statsIntervalMs, 250))\n const workerClient = this.workerClient\n if (workerClient === undefined) {\n return\n }\n\n this.playback.startStateReporting(intervalMs, (state) => {\n if (this.state === 'started' && this.workerClient === workerClient) {\n workerClient.post({ type: 'video-state', state })\n }\n })\n }\n\n private async applyPlaybackControl(action: PlaybackControlAction): Promise<void> {\n const workerClient = this.workerClient\n const lifecycleGeneration = this.lifecycleGeneration\n if (!this.playback.attached || workerClient === undefined || this.state !== 'started') {\n return\n }\n\n const result = await this.playback.applyControl(action)\n if (!this.isLifecycleOperationCurrent(lifecycleGeneration) || this.state !== 'started' || this.workerClient !== workerClient) {\n return\n }\n workerClient.post({ type: 'playback-control-result', result })\n if (\n action.type === 'play' &&\n action.reason === 'startup-buffer-ready' &&\n this.options.playback.autoPlay &&\n !result.accepted &&\n !this.autoplayWarningEmitted\n ) {\n this.autoplayWarningEmitted = true\n this.events.emit('warning', {\n code: 'RIVMUX_AUTOPLAY_REJECTED',\n message: '浏览器拒绝了自动播放;请在用户手势处理器中调用 video.play() 恢复播放。',\n cause: result.error,\n })\n }\n }\n\n private enterFatalErrorState(error: PlayerError): void {\n if (this.state === 'destroyed' || this.state === 'destroying' || this.state === 'fatal-error') {\n return\n }\n\n this.lifecycleGeneration += 1\n this.terminalError = error\n this.state = 'fatal-error'\n this.playback.release()\n }\n\n private assertOperational(method: string): void {\n if (this.state === 'fatal-error' && this.terminalError !== undefined) {\n throw playerErrorToException(this.terminalError)\n }\n\n if (this.state === 'stopping') {\n throw playerErrorToException(\n createPlayerError('runtime', 'RIVMUX_PLAYER_STOPPING', `RivmuxPlayer.${method}() cannot be called while stop() is pending.`, false)\n )\n }\n\n if (this.state !== 'destroyed' && this.state !== 'destroying') {\n return\n }\n\n const code = this.state === 'destroying' ? 'RIVMUX_PLAYER_DESTROYING' : 'RIVMUX_PLAYER_DESTROYED'\n throw playerErrorToException(createPlayerError('runtime', code, `RivmuxPlayer.${method}() cannot be called after destroy() begins.`, true))\n }\n\n private isLifecycleOperationCurrent(generation: number): boolean {\n return generation === this.lifecycleGeneration && this.state !== 'fatal-error' && this.state !== 'destroying' && this.state !== 'destroyed'\n }\n\n private assertStartOperationCurrent(generation: number): void {\n if (this.isLifecycleOperationCurrent(generation) && this.state === 'starting') {\n return\n }\n\n const action = this.state === 'destroying' || this.state === 'destroyed' ? 'destroy' : 'stop'\n throw createPlayerError('runtime', 'RIVMUX_START_CANCELLED', `Start was cancelled by ${action}.`, false)\n }\n}\n\nfunction toPublicStartError(cause: unknown): Error {\n return isPlayerError(cause) ? playerErrorToException(cause) : cause instanceof Error ? cause : new Error(String(cause))\n}\n\nfunction isPlayerError(value: unknown): value is PlayerError {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n\n const candidate = value as Partial<PlayerError>\n return (\n typeof candidate.kind === 'string' && typeof candidate.code === 'string' && typeof candidate.message === 'string' && typeof candidate.terminal === 'boolean'\n )\n}\n\nfunction createPlayerId(): string {\n const random = globalThis.crypto?.randomUUID?.()\n return random ?? `rivmux-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n}\n\nfunction withBundledWasmUrl(options: NormalizedRivmuxPlayerOptions): NormalizedRivmuxPlayerOptions {\n if (options.runtime.wasmUrl !== undefined) {\n return options\n }\n\n return {\n ...options,\n runtime: {\n ...options.runtime,\n wasmUrl: getBundledWasmUrl(),\n },\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rivmux",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Public player package for Rivmux.",
|
|
5
5
|
"homepage": "https://www.npmjs.com/package/rivmux",
|
|
6
6
|
"bugs": {
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"module": "./dist/index.js",
|
|
31
31
|
"types": "./dist/index.d.ts",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@rivmux/
|
|
34
|
-
"@rivmux/
|
|
33
|
+
"@rivmux/protocol": "1.0.1",
|
|
34
|
+
"@rivmux/runtime-worker": "1.0.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"tsdown": "^0.23.0",
|
|
38
38
|
"typescript": "~6.0.3",
|
|
39
|
-
"vitest": "^
|
|
39
|
+
"vitest": "^5.0.1"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsdown",
|