Skip to content

feat(stream): 优化连接中→首帧过渡 + RTSP 瞬态错误自动重试#28

Merged
qiin2333 merged 2 commits into
masterfrom
feat/connecting-overlay-smooth
May 14, 2026
Merged

feat(stream): 优化连接中→首帧过渡 + RTSP 瞬态错误自动重试#28
qiin2333 merged 2 commits into
masterfrom
feat/connecting-overlay-smooth

Conversation

@qiin2333
Copy link
Copy Markdown
Contributor

@qiin2333 qiin2333 commented May 14, 2026

背景

用户反馈两个问题:

  1. loading → 首帧 视觉跳跃:连接中遮罩在 drStart(MediaCodec 启动完成)瞬间就消失,但首帧真正上屏还要再等 ~150-300ms(IDR 到达 + 解码 + 渲染),中间会露出尚未填充画面的 XComponent → 黑屏闪烁。
  2. 偶发"错误码 4":远程/弱网场景下 RTSP ANNOUNCE 阶段偶尔失败,错误码 4 = errno EINTR(系统调用被中断);用户立即手动重试基本必然成功,但体验割裂。

改动

视觉过渡

  • 首帧对齐drStart 后改为轮询 framesDecoded,等到首帧实际解码完成才切 CONNECTED(1500ms 兜底),让遮罩淡出与首帧出现严丝合缝。
  • 遮罩重做:背景从纯黑 #CC000000 改为应用海报模糊 + 渐变暗化,消除等待期的纯黑感。
  • 离场动画TransitionEffect.asymmetric,进入 IDENTITY、离开 320ms 淡出 + 轻微放大(×1.04),与首帧浮现自然交错。
  • 小课堂提示:等待期随机展示一条隐藏手势 / 快捷键 / 彩蛋(45 条池子),让等待时间有趣可学。

自动重试

  • startConnection 包一层重试:返回值为 4 / 32 / 104 / 110(EINTR / EPIPE / ECONNRESET / ETIMEDOUT)时认定为传输层瞬态错误,自动 stopConnection + 等待 1.5s + 重试一次。
  • 其他错误(参数不兼容、host 拒绝)直接抛出,避免对真实失败进行无效重试。
  • 重试期间 UI 仍停留"正在初始化控制通道...",用户无感知。

验证

  • 编译通过(hvigorw assembleHap
  • 真机模拟器验证:连接进入更平滑,首帧出现时遮罩淡出与画面浮现完美对齐
  • errno 4 重现场景测试(待持续观察)

文件

  • StreamPage.ets:ConnectingOverlay 重做(海报背景 + 渐变 + 提示 + 离场动画)
  • StreamViewModel.ets:drStart 后改为首帧轮询,1500ms 兜底
  • StreamingSession.ets:startConnection 瞬态错误重试一次
  • AppListPageV2.ets:透传 posterPath 给 StreamPage
  • StreamConnectingTips.ets(新增):45 条小课堂提示池

bump to v771

Summary by CodeRabbit

  • 新功能

    • 添加连接时的随机提示以增强体验
    • 启动应用时在连接遮罩显示应用海报背景
    • 优化连接流程,等待首帧解码或超时后再确认为已连接
  • Bug修复

    • 改进RTSP握手的瞬态错误处理,遇到特定短暂网络错误时进行一次自动重试
  • 版本更新

    • 应用版本更新至 1.0.0.771

Review Change Stack

- ConnectingOverlay 推迟到首帧解码后才退场,并以 320ms 淡出+轻微放大与首帧出现对齐
- 遮罩使用应用海报作模糊背景,不再纯黑等待
- 等待期随机展示一条小课堂提示
- RTSP ANNOUNCE 阶段瞬态 socket 错误(errno 4/32/104/110)自动重试一次
- bump version to 1.0.0.771
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: af7149bd-a63f-4e2c-9b33-f2a080c70669

📥 Commits

Reviewing files that changed from the base of the PR and between cd3fe4c and 170a3e3.

📒 Files selected for processing (2)
  • entry/src/main/ets/service/streaming/StreamingSession.ets
  • entry/src/main/resources/rawfile/CHANGELOG.md
✅ Files skipped from review due to trivial changes (1)
  • entry/src/main/resources/rawfile/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • entry/src/main/ets/service/streaming/StreamingSession.ets

📝 Walkthrough

Walkthrough

此 PR 改进连接流程:为连接遮罩新增海报背景与随机提示,从列表页面传递 poster,延迟至首帧到达再标记 CONNECTED,并在 RTSP ANNOUNCE 阶段对若干瞬态错误进行一次自动重试,同时更新版本与变更日志。

变更总览

本 PR 优化了应用启动时的连接体验和弱网场景下的连接弹性:引入 RTSP 握手瞬态错误自动重试、将连接状态转移延迟至首帧到达、用应用海报与随机小课堂提示重新设计连接遮罩UI,并提升版本号至 1.0.0.771。

变更详解

连接体验与弱网弹性

层级 / 文件 概述
连接中小课堂提示基础设施
entry/src/main/ets/components/StreamConnectingTips.ets
新增 STREAM_CONNECTING_TIPS 常量和 pickRandomConnectingTip() 函数,为连接遮罩提供分类的中文提示文本,支持从中随机选取。
应用海报从列表传递到流页面
entry/src/main/ets/pages/AppListPageV2.ets
doLaunchApp() 在应用图标加载后从 localIconPath 派生 posterPath,通过路由参数与 useVdd 一起传至 StreamPage,避免启动时黑屏。
连接遮罩UI:海报背景与提示文本
entry/src/main/ets/pages/StreamPage.ets
接受可选 posterPath 参数,增加 connectingTip 状态,重构 ConnectingOverlay 组件支持应用海报背景渲染(含模糊)、应用名称显示、随机提示文本注入,并调整过渡动画。
首帧解码延迟连接状态转移
entry/src/main/ets/viewmodel/StreamViewModel.ets
替换原有的 decoder-start 回调直接转换状态的逻辑,改为新增 firstFrameTimer 轮询 decodedFrames,只在首帧出现或 1.5 秒超时后才切换到 CONNECTED;并在连接终止、错误、停止流时清理轮询。
RTSP 握手瞬态错误重试
entry/src/main/ets/service/streaming/StreamingSession.ets
connectToServer() 在识别特定瞬态错误码后(4、32、104、110),自动停止连接、等待 1.5 秒、单次重试;重试失败则走既有错误路径。
版本号与变更日志
AppScope/app.json5, entry/src/main/resources/rawfile/CHANGELOG.md
版本升至 1.0.0.771;新增版本条目记录首帧延迟、遮罩重做、随机提示优化与握手重试修复。

审查工作量评估

🎯 4 (复杂) | ⏱️ ~45 分钟

可能相关的 PR

  • AlkaidLab/moonlight-harmony#27:与本 PR 共同修改 StreamViewModelCONNECTED 状态转移时机,并协调 StreamingSession 的连接与解码器启动行为。
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题准确总结了主要改动:连接中→首帧过渡优化和RTSP瞬态错误自动重试,与文件变更内容完全对应。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/connecting-overlay-smooth

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
entry/src/main/ets/viewmodel/StreamViewModel.ets (1)

839-846: ⚡ Quick win

建议在 dispose() 中添加定时器清理

虽然正常流程下 stopStreaming() 已清理 firstFrameTimer,但 dispose() 作为最后的兜底清理方法,应显式调用 stopFirstFrameWatcher() 以防御异常路径下的定时器泄漏。

🛡️ 建议的防御性修复
 dispose(): void {
   this.resetRotationState();
+  this.stopFirstFrameWatcher();
   if (this.streamingSession) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@entry/src/main/ets/viewmodel/StreamViewModel.ets` around lines 839 - 846, The
dispose() method currently resets rotation and stops the streamingSession but
doesn't explicitly clear the first-frame timer; add a defensive call to
stopFirstFrameWatcher() inside dispose() (before or after resetting state) so
any leftover firstFrameTimer is cleaned up even if stopStreaming() wasn't
reached; reference the existing methods dispose(), resetRotationState(),
stopFirstFrameWatcher(), stopStreaming() and the
firstFrameTimer/streamingSession fields when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@entry/src/main/ets/service/streaming/StreamingSession.ets`:
- Around line 1291-1304: The retry branch can resurrect a user-cancelled
session: before calling the retry path and again after the 1.5s wait check the
cancellation flag and bail if set; specifically, after callStart() returns a
transient code from TRANSIENT_ERRORS, check this.userInitiatedStop and return
immediately if true, call this.nativeModule.stopConnection only when not
cancelled, then after the await new Promise(...) check this.userInitiatedStop
again before invoking callStart() a second time so stop()/quitApp() cannot
re-launch the session.

In `@entry/src/main/resources/rawfile/CHANGELOG.md`:
- Line 32: Replace the nonstandard symbol "≡" in the CHANGELOG sentence
containing "黑底 ≡ 现在推迟到" with a clearer connector (e.g., ",现在推迟到" or "→ 现在推迟到")
so the line describing the mask transition ("连接中 → 首帧动画过渡:... 黑底 ≡ 现在推迟到...")
uses a standard punctuation/arrow; update only that connector to improve
readability while keeping the rest of the phrasing intact.

---

Nitpick comments:
In `@entry/src/main/ets/viewmodel/StreamViewModel.ets`:
- Around line 839-846: The dispose() method currently resets rotation and stops
the streamingSession but doesn't explicitly clear the first-frame timer; add a
defensive call to stopFirstFrameWatcher() inside dispose() (before or after
resetting state) so any leftover firstFrameTimer is cleaned up even if
stopStreaming() wasn't reached; reference the existing methods dispose(),
resetRotationState(), stopFirstFrameWatcher(), stopStreaming() and the
firstFrameTimer/streamingSession fields when making the change.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b575af13-0b52-420a-8221-f42e58be5208

📥 Commits

Reviewing files that changed from the base of the PR and between 8ee0a04 and cd3fe4c.

📒 Files selected for processing (7)
  • AppScope/app.json5
  • entry/src/main/ets/components/StreamConnectingTips.ets
  • entry/src/main/ets/pages/AppListPageV2.ets
  • entry/src/main/ets/pages/StreamPage.ets
  • entry/src/main/ets/service/streaming/StreamingSession.ets
  • entry/src/main/ets/viewmodel/StreamViewModel.ets
  • entry/src/main/resources/rawfile/CHANGELOG.md

Comment thread entry/src/main/ets/service/streaming/StreamingSession.ets
Comment thread entry/src/main/resources/rawfile/CHANGELOG.md Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 2 file(s) based on 2 unresolved review comments.

Files modified:

  • entry/src/main/ets/service/streaming/StreamingSession.ets
  • entry/src/main/resources/rawfile/CHANGELOG.md

Commit: 170a3e3246adaf5d2c85fd712b7cafb86772deb1

The changes have been pushed to the feat/connecting-overlay-smooth branch.

Time taken: 2m 25s

Fixed 2 file(s) based on 2 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@qiin2333 qiin2333 merged commit 6e259d4 into master May 14, 2026
2 checks passed
@qiin2333 qiin2333 deleted the feat/connecting-overlay-smooth branch May 14, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant