# 问题分析：BUG-e289b43c-6c66-49c2-8853-eb158a243d6a

## 日志时间线还原

| 时间 | 事件 | 关键信息 |
|------|------|----------|
| 09:36:13 | SDK destroy (旧实例) | `ar call stop` → `destroy start` → `destroy end` |
| 09:36:36 | SDK 重新初始化 | Electron, lazy init mode, video frame processor |
| 09:36:39 | 初始化完成，获取输入 | 输入 1280x720@15fps, deviceId `008f2a60` |
| 09:36:39 | initCore 完成 | `core initworker:::done` |
| 09:36:39 | **`lost context`** | 上下文丢失，触发 `resetCore` |
| 09:36:39 | resetCore 开始 | 重建 WorkerCore + 新 VideoInputVideoFrame |
| 09:36:40 | resetCore 后 getOutput | output track = `live`, 新 deviceId `c98cdd3c` |
| 09:36:40 | **再次 destroy** | `ar call stop` → `destroy start`（客户短时间内再次重建）|
| 09:36:41 | 第三次初始化 | 又一个新 SDK 实例 |
| 09:36:41 | **尺寸突变** | `Track settings changed: 1280x720 -> 160x120` |
| 09:36:42 | initCore done | 分辨率降为 160x120@15fps |
| 09:36:42 | getOutput | output track = `live`, 新 deviceId `fba28b0b` |
| 09:36:44 | **`outputVideoTrack muted`** | output 流进入 muted 状态 |
| 09:36:55 | `outputVideoTrack unmuted` | 暂时恢复 |
| 09:37:00 | **页面隐藏** | `visibilitychange:hidden:paused` → 切换 tab |
| 09:37:02 | **`outputVideoTrack muted`** | 再次 muted |
| 09:38:56 | 页面恢复可见 | `clear hidden loop` |
| 09:38:57 | **再次页面隐藏** | 又切到其他 tab |
| 09:39:07 | 页面恢复 | |
| 09:39:15 | **再次隐藏** | 频繁切换 tab |
| 09:39:19 | 页面恢复 | |
| 09:39:21 | **`updateInputStream` 调用** | 客户尝试重置输入流 |
| 09:39:21 | **"VideoTrack is not changed"** | SDK 判断 track 未变，跳过更新 |
| 09:39:21 | **output track = `ended`** | getOutput 输出的 track 已经 ended！|
| 09:39:21 | 第二次 updateInputStream | 同样被跳过 |
| 09:39:41 | `init worker timeout` | worker 超时 |
| 09:39:45 | SDK destroy | 客户放弃，销毁 SDK |
| 09:39:47 | 第四次初始化 | 重新创建 |
| 09:39:50 | 初始化成功 | output = `live` |
| 09:39:55 | **`outputVideoTrack muted`** | 问题再现 |

## 根因

**核心问题：`resetCore` 重建了 core（包含新的 `VideoInputVideoFrame` 和新的 `generator`），但 `outputStream` 仍然持有旧 generator 创建的 track。旧 generator 的 writable 被关闭后，其产生的 output track 变为 `ended` 状态。**

具体链路：
1. SDK 初始化完成后触发 `getOutput`，此时 `outputStream` 持有当前 `core.inputNode.generator` 对应的 track
2. 当 `contextlost` 事件触发（或 `uncaughtError`）时，`resetCore` 被调用
3. `resetCore` 创建了全新的 `WorkerCore`，里面有新的 `VideoInputVideoFrame`（新的 processor/generator）
4. **但 `resetCore` 没有更新 `this.outputStream`**——`outputStream` 仍然引用旧 generator 产生的 MediaStream
5. 旧 core 被 destroy 后，旧 generator 的 writable 关闭 → output track 变为 `ended`

**次要问题：`updateInputStream` 无法修复这种情况**

客户发现 output 流失活后调用 `updateInputStream` 尝试恢复，但：
- 传入的是同一个 MediaStream（同一个 videoTrack deviceId）
- SDK 判断 `oldVideoTrack === newVideoTrack`（同一个 track 引用）→ "VideoTrack is not changed" → 提前返回
- **即使 track 没变，output 已经 ended 也不会被修复**

## 影响范围

- 使用 `videoframe` 模式（即 `MediaStreamTrackProcessor` 路径）的所有 H5 场景
- 当发生 `contextlost`/`uncaughtError` 导致 `resetCore` 时，output 流会永久失活
- Electron 环境下页面频繁隐藏/显示更容易触发 context lost
- 客户调用 `updateInputStream` 传入相同流时无法恢复

## 修复思路

### 修复 1：`resetCore` 后同步更新 `outputStream`（核心修复）

在 `resetCore` 完成后，检查 `this.outputStream` 是否存在，如果存在且新 core 使用 videoframe 模式，则用新 generator 更新 `outputStream`。

### 修复 2：`updateInputStream` 增加 output track 状态检查（兼容性修复）

即使 videoTrack 引用未变，如果 output track 已经 `ended`，也应该强制重建 output stream 链路。
