Skip to content

feat(stream): expose active session telemetry - #801

Merged
qiin2333 merged 2 commits into
masterfrom
agent/active-session-observability
Jul 15, 2026
Merged

qiin2333 merged 2 commits into
masterfrom
agent/active-session-observability

Conversation

@qiin2333

Copy link
Copy Markdown
Collaborator

改了啥呀

  • 把已认证的客户端证书 UUID 带进活动串流会话,并在本地会话 API 中返回
  • 为控制通道、视频发送和音频发送记录最近活动时间,同时暴露会话运行时长与控制连接状态
  • 记录首个终止原因,并在停止/回收日志里带上会话 ID、客户端 UUID 和原因
  • 补齐终止原因名称的单元测试

为啥要改

多客户端断开异常现在只能看到一个笼统的 -1,很难判断是控制通道断开、超时、协议错误,还是音视频线程结束。先把会话身份和生命周期信号补齐,后续才能安全地做按客户端取消和陈旧会话回收,哼,这次不靠猜啦。

这层只增加观测信息,不新增超时、不主动回收会话,也不改变现有串流与全局终止逻辑。*_idle_ms 表示主机侧最近一次控制事件/媒体发送活动;活动尚未出现时返回 null。客户端 UUID 仅通过现有本地管理接口暴露。

验证

  • git diff --check
  • 核对所有现有 session::stop() 调用均标注具体终止原因
  • 单元测试覆盖全部终止原因字符串
  • 完整 Windows 构建交给 CI:隔离 worktree 的子模块拉取发生网络超时,未继续阻塞本地发布

@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • 新功能
    • 会话信息现包含客户端标识、会话运行时长、控制/视频/音频空闲时长以及控制连接状态。
    • 会话停止信息更明确:可展示控制断开、控制超时、协议错误、媒体结束与主机终止等原因。
    • 当对应空闲时长不可用时,将以空值呈现,避免误导。
  • 可观测性
    • 会话生命周期与最新活动时间统计更准确;日志与状态查询会同时体现停止原因与相关状态。

Walkthrough

扩展会话生命周期观测能力,记录停止原因、客户端标识、运行时长、通道活动时间和连接状态,并通过会话查询 JSON 返回;控制、视频、音频及主机终止路径均传递具体停止原因。

Changes

会话生命周期可观测性

Layer / File(s) Summary
会话观测数据契约
src/stream.h, src/stream.cpp
新增停止原因枚举、生命周期状态管理、会话标识、运行与空闲计时字段、连接状态字段,并扩展 session::stop 声明。
生命周期停止原因与活动跟踪
src/stream.cpp, src/rtsp.cpp
控制、视频、音频及主机终止路径传递具体停止原因;生命周期状态统一管理,广播线程记录最近活动时间,停止日志输出原因和客户端标识。
会话信息统计与接口输出
src/stream.cpp, src/nvhttp/sessions.h, src/nvhttp/sessions.cpp, tests/unit/test_stream_session_observability.cpp
会话查询返回运行时长、通道空闲时长、停止原因、客户端 UUID 和连接状态;负数空闲时长输出为 null,并测试生命周期停止原因和 JSON 序列化。

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ControlServer
  participant CaptureThreads
  participant stream_session_stop
  participant SessionsAPI
  ControlServer->>stream_session_stop: 传递控制断开、超时或协议错误原因
  CaptureThreads->>stream_session_stop: 传递视频或音频结束原因
  stream_session_stop->>SessionsAPI: 保存停止原因和活动时间
  SessionsAPI-->>ControlServer: 返回运行、空闲和连接状态字段
Loading

Possibly related PRs

  • AlkaidLab/foundation-sunshine#793:同样涉及 src/rtsp.cpp 中 RTSP 会话的启动、清理和终止流程,与本次显式传递主机终止原因的改动相交。
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确概括了本次新增活动会话遥测的主要改动。
Description check ✅ Passed 描述与改动内容一致,覆盖了 UUID、活动时间、终止原因和测试。
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/active-session-observability

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.

@qiin2333
qiin2333 marked this pull request as ready for review July 13, 2026 09:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/unit/test_stream_session_observability.cpp (1)

10-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

补充会话遥测边界测试

当前断言正确覆盖了所有停止原因名称,但未验证首个停止原因、uptime_ms、control_connected,以及首次活动前空闲字段应输出 null。建议补充会话/API 层测试保护这些跨文件契约。

As per path instructions:tests/** 需要验证测试覆盖率、边界情况和断言正确性。

🤖 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 `@tests/unit/test_stream_session_observability.cpp` around lines 10 - 20, 在
StreamSessionObservability 测试中补充会话/API 层边界断言:验证首个停止原因、uptime_ms 和
control_connected,并确认首次活动前的空闲字段输出为 null。保留现有 stop_reason_name
全量断言,并确保新增断言覆盖这些跨文件遥测契约且断言值正确。

Source: Path instructions

🤖 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 `@src/rtsp.cpp`:
- Around line 834-835: 在全局 shutdown 流程中,将 stream::session::stop 的
stop_reason_e::host_terminate 写入前移至广播关闭或终止发起处,确保其先于视频/音频线程写入 video_ended 或
audio_ended;保留 stream::session::join(slot) 的等待逻辑,并避免仅依赖 clear() 在 RUNNING
状态下覆盖已有原因。

In `@src/stream.cpp`:
- Around line 3052-3064: 在 stop(session_t&, stop_reason_e) 中,将 stop_reason 与
STOPPING 状态的发布改为原子一致的快照,并同步更新 get_all_sessions_info() 的读取逻辑,使其不会观察到 STOPPING 但仍为
none;确保并发停止调用仍只记录首个终止原因。仅调整内存序不足以解决问题,应复用锁或单一原子状态封装完成同步。
- Around line 3448-3457: Update the ENET_EVENT_TYPE_DISCONNECT handling so
stopping a session also clears its control connection state before API status is
read. Ensure the status-building code around session_p->control.peer no longer
reports control_connected=true after disconnect, using synchronized access or an
atomic connection-state field as appropriate; preserve the existing STOPPING
state behavior.

---

Nitpick comments:
In `@tests/unit/test_stream_session_observability.cpp`:
- Around line 10-20: 在 StreamSessionObservability 测试中补充会话/API
层边界断言:验证首个停止原因、uptime_ms 和 control_connected,并确认首次活动前的空闲字段输出为 null。保留现有
stop_reason_name 全量断言,并确保新增断言覆盖这些跨文件遥测契约且断言值正确。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9df35dcc-0d94-442b-917e-1b6f40505eb0

📥 Commits

Reviewing files that changed from the base of the PR and between 3741b3e and ec8ba04.

📒 Files selected for processing (5)
  • src/nvhttp/sessions.cpp
  • src/rtsp.cpp
  • src/stream.cpp
  • src/stream.h
  • tests/unit/test_stream_session_observability.cpp
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
tests/**

⚙️ CodeRabbit configuration file

tests/**: 测试文件。验证测试覆盖率、边界情况和断言正确性。

Files:

  • tests/unit/test_stream_session_observability.cpp
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/rtsp.cpp
  • src/nvhttp/sessions.cpp
  • src/stream.h
  • src/stream.cpp
🔇 Additional comments (3)
src/stream.h (1)

6-6: LGTM!

Also applies to: 40-67, 92-92

src/stream.cpp (1)

111-124: LGTM!

Also applies to: 506-512, 876-876, 891-894, 1668-1669, 1724-1725, 1733-1734, 1774-1774, 2313-2313, 2665-2665, 2972-2973, 2997-2998, 3021-3040, 3170-3172, 3278-3282

src/nvhttp/sessions.cpp (1)

69-78: LGTM!

Comment thread src/rtsp.cpp
Comment thread src/stream.cpp
Comment thread src/stream.cpp Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/stream.cpp (1)

3204-3219: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

给 session::start() 补上异常边界和半启动清理

这里没有 try/catch 包住命令分发;std::thread 构造一旦抛出 std::system_error,异常会直接逃出 handle_msg(),RTSP 线程随即终止。需要在 src/rtsp.cpp 的调用链外层兜住异常,并对已启动的线程执行 stop/join 后再返回错误。

🤖 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 `@src/stream.cpp` around lines 3204 - 3219, 在 session::start() 的调用链外层增加异常边界,捕获
std::thread 创建等操作抛出的异常,避免其从 handle_msg() 继续传播并终止 RTSP 线程;若 audioThread 或
videoThread 仅部分启动,先执行 session 的 stop 流程并 join 已启动线程,完成半启动清理后再返回错误。

Source: Path instructions

🧹 Nitpick comments (2)
src/stream.h (1)

116-138: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

为 session_info_t 的标量字段补充默认初始值。

新增的 session_id、uptime_ms、control_idle_ms、video_idle_ms、audio_idle_ms、control_connected 等标量字段均未提供默认初始值。当前 get_all_sessions_info() 通过 session_info_t info;(非 info{})构造后在 try 块内逐一赋值,异常路径会整体跳过 push_back,目前不会真正暴露未初始化值,但这依赖于调用方始终完整赋值每个字段,一旦未来新增字段或调整赋值顺序遗漏某个分支,就会把未初始化的垂圾值序列化进遥测 JSON。建议直接给标量成员加默认值,消除这一隐患。

🛡️ 建议的修复
   struct session_info_t {
     std::string client_name;
     std::string client_uuid;
     std::string client_address;
     std::string state;
     std::string stop_reason;
-    uint32_t session_id;
-    std::int64_t uptime_ms;
-    std::int64_t control_idle_ms;
-    std::int64_t video_idle_ms;
-    std::int64_t audio_idle_ms;
-    bool control_connected;
-    int width;
-    int height;
-    int fps;
-    int bitrate;  // Current bitrate in Kbps
-    bool host_audio;
-    bool enable_hdr;
-    bool enable_mic;
+    uint32_t session_id { 0 };
+    std::int64_t uptime_ms { 0 };
+    std::int64_t control_idle_ms { -1 };
+    std::int64_t video_idle_ms { -1 };
+    std::int64_t audio_idle_ms { -1 };
+    bool control_connected { false };
+    int width { 0 };
+    int height { 0 };
+    int fps { 0 };
+    int bitrate { 0 };  // Current bitrate in Kbps
+    bool host_audio { false };
+    bool enable_hdr { false };
+    bool enable_mic { false };
     std::string app_name;
-    int app_id;
+    int app_id { 0 };
   };

As per path instructions, src/**/*.{cpp,c,h} 审查要点包括内存安全,未初始化的 POD 成员属于此类隐患。

🤖 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 `@src/stream.h` around lines 116 - 138, 为 session_info_t 中所有标量成员补充安全的默认初始值,至少覆盖
session_id、各项
*_ms、control_connected、width、height、fps、bitrate、host_audio、enable_hdr、enable_mic
和 app_id;保持现有字段类型及 get_all_sessions_info() 的赋值逻辑不变,确保默认构造 session_info_t
时不会产生未初始化值。

Source: Path instructions

tests/unit/test_stream_session_observability.cpp (1)

67-84: 🎯 Functional Correctness | 🔵 Trivial | ⚖️ Poor tradeoff

SerializesSessionBoundaries 未覆盖 idle_ms() 哨兵值本身的计算逻辑。

该测试直接手写 control_idle_ms = -1 等值,只验证了 make_session_json 对已知 -1 的序列化(映射为 JSON null),但 stream.cpp 中 idle_ms(now, last_activity) 把 last_activity == 0 判定为"从未活动"并返回 -1 的这段核心逻辑本身并未被单测直接覆盖(该函数位于匿名命名空间,无法从测试文件直接调用)。可考虑通过集成测试(构造真实 session 并调用 get_all_sessions_info())或将该辅助函数移出匿名命名空间以便单测覆盖。

As per path instructions,tests/** 需要验证测试覆盖率、边界情况和断言正确性。

🤖 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 `@tests/unit/test_stream_session_observability.cpp` around lines 67 - 84, 扩展
SerializesSessionBoundaries 测试以覆盖 idle_ms() 对 last_activity == 0 的哨兵值计算逻辑,而不是仅手写
-1 验证 make_session_json 的序列化。优先通过真实 session 调用 get_all_sessions_info() 验证从未活动时返回
-1 并序列化为 JSON null;若现有结构不便集成测试,则将 idle_ms 移出匿名命名空间并直接补充边界单测,同时保留现有序列化断言。

Source: Path instructions

🤖 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.

Outside diff comments:
In `@src/stream.cpp`:
- Around line 3204-3219: 在 session::start() 的调用链外层增加异常边界,捕获 std::thread
创建等操作抛出的异常,避免其从 handle_msg() 继续传播并终止 RTSP 线程;若 audioThread 或 videoThread
仅部分启动,先执行 session 的 stop 流程并 join 已启动线程,完成半启动清理后再返回错误。

---

Nitpick comments:
In `@src/stream.h`:
- Around line 116-138: 为 session_info_t 中所有标量成员补充安全的默认初始值,至少覆盖 session_id、各项
*_ms、control_connected、width、height、fps、bitrate、host_audio、enable_hdr、enable_mic
和 app_id;保持现有字段类型及 get_all_sessions_info() 的赋值逻辑不变,确保默认构造 session_info_t
时不会产生未初始化值。

In `@tests/unit/test_stream_session_observability.cpp`:
- Around line 67-84: 扩展 SerializesSessionBoundaries 测试以覆盖 idle_ms() 对
last_activity == 0 的哨兵值计算逻辑,而不是仅手写 -1 验证 make_session_json 的序列化。优先通过真实 session
调用 get_all_sessions_info() 验证从未活动时返回 -1 并序列化为 JSON null;若现有结构不便集成测试,则将 idle_ms
移出匿名命名空间并直接补充边界单测,同时保留现有序列化断言。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 695de8fa-5c48-4ca8-9e4c-51f368fbdbf5

📥 Commits

Reviewing files that changed from the base of the PR and between ec8ba04 and 5fcad66.

📒 Files selected for processing (5)
  • src/nvhttp/sessions.cpp
  • src/nvhttp/sessions.h
  • src/stream.cpp
  • src/stream.h
  • tests/unit/test_stream_session_observability.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/nvhttp/sessions.cpp
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Windows
🧰 Additional context used
📓 Path-based instructions (2)
tests/**

⚙️ CodeRabbit configuration file

tests/**: 测试文件。验证测试覆盖率、边界情况和断言正确性。

Files:

  • tests/unit/test_stream_session_observability.cpp
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/nvhttp/sessions.h
  • src/stream.h
  • src/stream.cpp
🔇 Additional comments (5)
src/stream.h (2)

6-22: LGTM!

Also applies to: 141-146


59-114: lifecycle_t 的原子 + 互斥锁混合同步设计正确。

request_stop()/snapshot() 均在同一把锁内完成 _state 与 _stop_reason 的写入/读取,避免了"状态已变为 STOPPING 但停止原因仍为 none"的不一致快照问题;state() 仅无锁读取 _state(用于自旋等待),不涉及 _stop_reason,设计自洽。

src/stream.cpp (1)

111-124: LGTM!

while_starting_do_nothing、各停止路径的具体原因传递、lifecycle/stop_reason 的一致快照、以及 control_connected 依赖 state == RUNNING 的判定,均已正确修复此前评审中提到的一致性问题。

Also applies to: 360-364, 506-512, 575-578, 874-874, 891-891, 1664-1664, 1720-1720, 1729-1731, 1770-1773, 2309-2309, 2661-2661, 2967-3000, 3021-3044, 3052-3064, 3167-3169, 3280-3284, 3370-3372, 3398-3398, 3449-3461, 3476-3476

src/nvhttp/sessions.h (1)

5-20: LGTM!

使用 json_fwd.hpp 与前置声明 stream::session_info_t 来声明 make_session_json,减少了头文件的编译期耦合,是不错的实践。

tests/unit/test_stream_session_observability.cpp (1)

1-15: LGTM!

PreservesFirstStopReason、PublishesOneConcurrentStopReason 很好地覆盖了 lifecycle_t 的核心并发契约(首个停止原因保留、并发请求只有一个胜出者)。

Also applies to: 29-42, 44-66

@qiin2333
qiin2333 merged commit 0e79694 into master Jul 15, 2026
5 checks passed
@qiin2333
qiin2333 deleted the agent/active-session-observability branch July 15, 2026 02:41
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