-
-
Notifications
You must be signed in to change notification settings - Fork 2
Voice Replay
Voice Replay 回放的是 demo 里真实存在的游戏内语音。它不录麦克风、不生成语音、 不做语音转文字,也不从 Discord、TeamSpeak、视频或外部录音里抽音频。
文字聊天 replay 回放的是 demo 里的 chat event。它不手工伪造 UI 文本,而是让匹配到的
安全 replay bot 走 CS2 原生 say / say_team 路径。
两者的时间线策略不同:
- Voice 是连续音频流,严格按当前播放窗口回放。
- Chat 是瞬发事件,早于当前 playback anchor 的 freezetime 消息会在 replay 开始时补发一次。
链路是:
- converter 读取 demo 中的 voice netmessage。
- converter 写出紧凑的每回合
.dtvsidecar。 - CounterStrikeSharp runtime 在加载回合时加载对应 sidecar。
- replay bot 按 demo speaker 身份发送原始 voice payload。
Voice Replay 只会把安全 replay bot 当作 sender;不会把 replay 控制权或 voice sender 权限分配给真人玩家。
链路是:
- converter 读取 demo 中的
chat_message/server_messageevent。 - converter 把轻量聊天 metadata 写入
manifest.json的rounds[].chat_messages。 - CounterStrikeSharp runtime 在加载回合时读取对应 round 的聊天消息。
- replay 开始后,匹配到安全 replay bot 的玩家消息通过
say或say_team发出。 -
server/admin类型消息作为全局 DemoTracer server message 打印。
聊天 metadata 默认导出,不需要 CLI 或 GUI 额外开关。
正常 round replay 语音导出只需要:
cs2-demotracer.exe convert --demo "<demo.dem>" --output "<output-dir>" --export-voice输出里应该出现:
voice/round00.dtv
voice/round01.dtv
如果没有 voice/,先确认命令里确实有 --export-voice,然后再判断 demo 本身是否包含
游戏内语音。更短的操作页见 Export Voice。
并非所有 .dem 都有语音。只有 demo 中存在可用的 CCLCMsg_VoiceData、
非空音频 payload 和有效 speaker XUID 时,才可能导出 voice sidecar。
更可能有语音的 demo:
- 社区服 demo。
- FACEIT demo。
- 5E demo。
- 其他保留游戏内语音 netmessage 的服务器录像。
常见没有语音的原因:
- 平台或服务器没有录 voice data。
- voice data 被剥离。
- 玩家没有使用游戏内语音。
- voice frame 没有有效 XUID。
- parser 没看到可用 payload。
显式导出:
cs2-demotracer.exe convert --demo "<demo.dem>" --output "<output-dir>" --export-voice如果没有可用 frame,转换时可能看到:
warning: voice sidecar export skipped: no voice frames matched the requested filters
或:
warning: voice sidecar export skipped: no voice sidecar windows contained frames
推荐布局:
manifest.json
round00/t/*.dtr
round00/ct/*.dtr
voice/round00.dtv
voice/round01.dtv
voice/round02.dtv
voice/roundXX.dtv 是 voice sidecar,不是路线 replay 文件。它保存:
- demo source metadata。
- map、tick rate、clip start/end tick。
- speaker table:XUID、client id、frame count。
- demo timeline 上的 frame timing。
- 原始 voice audio bytes。
- sample rate、voice level、sequence、section、packet count、packet offsets 等元数据。
核心原则是无损搬运。DemoTracer 不 decode、不 resample、不 denoise、不重新编码语音;
它保留 demo-backed Opus payload 和 runtime 回放所需的元数据。.dtv 是二进制格式,
因此体积应明显小于把每个 frame 和 audio byte 展开成 JSON。
聊天不使用 .dtv。它保存在:
manifest.json -> rounds[].chat_messages
每条消息包含 tick、sender SteamID、可选 sender name、scope 和文本。导出侧会清理空文本、
去重,并跳过没有 sender SteamID 的普通玩家消息。server / admin 范围可以没有玩家
SteamID。
自动播放由 dtr_voice_auto 控制:
dtr_voice_auto status
dtr_voice_auto on
dtr_voice_auto off
自动文字聊天由 dtr_chat_auto 控制,默认开启:
dtr_chat_auto status
dtr_chat_auto on
dtr_chat_auto off
加载回合时:
- DemoTracer 从 selected source round 加载
.dtrreplay。 - 在 manifest 附近查找
voice/roundXX.dtv。 - replay 开始时,把 sidecar speaker XUID 映射到已加载的 replay bot slot。
- 未映射的 speaker 会跳过。
- 已映射的 voice frame 按回合时间线发送。
sequence 回放里的 from_source_round 指 demo 的 source round。每一步都会加载对应
source round、对应 voice/roundXX.dtv,以及 manifest 中的 rounds[].chat_messages。
成功启动时日志类似:
voice_auto=started file=roundXX.dtv speakers=... frames=... recipients=... anchor=live offset=...
路线 replay 可以包含 bounded freeze-time preroll,让开局道具和站位有足够上下文。
自动导出的 voice/roundXX.dtv 对齐的是 live round window。
runtime 行为:
- live replay start 时,语音按 live timeline 播放。
- freeze-preroll start 时,如果
.dtv从 live start 或更晚开始,语音不会提前播。 - 这种情况下,语音会 defer 到 live anchor。
你可能看到:
voice_auto=deferred_live file=roundXX.dtv clip_start=... live_start=...
这是正常状态,意思是移动 replay 正在做 freeze-preroll,但语音等待 live timing, 避免同一句话在 freeze time 和 live start 后各播一次。
文字聊天不同。它是瞬发事件,不是连续媒体。如果 replay 从 live anchor 开始,而某条
freezetime chat 早于当前 anchor,DemoTracer 会把它的播放时间压到 0,在 replay 开始时
补发一次。这样不会丢掉开局文字交流,也不会像语音那样破坏连续时序。
一个 round .dtv 可以包含多个 speaker。
播放规则:
- 每个 speaker XUID 映射到一个已加载 replay bot。
- 多个 speaker 的 frame 可以按同一时间线交错发送。
- 找不到 loaded replay bot 的 speaker 会跳过。
- 只有 live human client 会收到语音;bot 和 HLTV 不作为 recipient。
听音规则按当前本地 CS2 队伍语音语义过滤:
- 观察者可以听到所有 replay voice。
- T 玩家只能听到 T replay bot 的语音。
- CT 玩家只能听到 CT replay bot 的语音。
- 如果某个 speaker 被映射到错误队伍,能否听到取决于该 bot 当前所在队伍。
玩家 chat 使用 CS2 原生 say / say_team,最终显示格式由游戏自己决定。DemoTracer 不用
白字 mirror 伪造聊天 UI。
因此 spectator 是否能看到玩家文字聊天,受 CS2 server cvar 影响。本地测试中如果希望观察者 看到 replay bot 发出的 native text chat,设置:
sv_full_alltalk 1
单独 sv_allchat 1 不足以保证 spectator 可见。
手动测试一条聊天:
dtr_chat_test <loaded|any|slot> [all|team] <message>
例如:
dtr_chat_test loaded all hello
dtr_chat_test 3 team rush B
该命令使用和自动聊天回放相同的 server-side say / say_team 路径。
正常 round/sequence 回放不需要手搓 voice debug 命令;它们主要用于 debug .dtv 文件。
单 speaker 测试:
dtr_voice_test <voice_clip.dtv> <sender_slot> [recipient_slot|all]
多 speaker 混合测试:
dtr_voice_mix <voice_clip.dtv> <xuid=slot[,xuid=slot...]|loaded> [recipient_slot|all]
停止当前 voice test/auto playback:
dtr_voice_stop
dtr_voice_mix ... loaded 会用当前 loaded replay bot 的 SteamID64 自动匹配 sidecar
speaker。
- demo 没有 voice data 就无法回放语音。
- 当前 runtime 支持 demo-backed Opus voice payload。
- speaker 必须能映射到已加载的安全 replay bot。
- recipient 必须是 live human client。
- 队伍语音按当前本地队伍过滤,不复原 demo 中每个 packet 的原始 recipient list。
- 不做转写、降噪、音量归一化或语义分析。
- 只复制
.dtr不会带上语音;必须把voice/roundXX.dtv和 manifest 输出包一起保留。 - 如果 BotController 没有 voice send capability,路线 replay 仍可运行,但语音不能发送。
- chat 使用原生
say/say_team,所以可见性受 CS2 server cvar 和队伍/观察者规则影响。 - 找不到匹配安全 replay bot 的玩家 chat 会被跳过;server/admin chat 会作为
[DTR]server message 打印。
voice sidecars 0:选中的 demo/round 没有可用 voice frame。
voice_auto=unavailable:native runtime 没暴露 voice send capability,或 CSS/native ABI 不匹配。
unsupported voice clip format; expected DTRVOICE v2 .dtv:文件不是当前 DTV sidecar 格式,或文件损坏。
voice frame N format=...; only Opus format=2 is supported:frame 音频格式不是当前 runtime sender 支持的 Opus。
voice_auto=map_failed:sidecar speaker 和当前 loaded replay bot 对不上。检查 source round、partial replay skip 和 identity mapping。
unmapped voice speakers will be skipped:部分 speaker 被跳过;已映射 speaker 仍可播放。
voice_auto=no_human_recipients:没有可接收语音的 live human client。
map mismatch:sidecar/manifest 地图和当前服务器地图不同,或用了错误输出目录。
chat_auto=off:自动文字聊天关闭。执行 dtr_chat_auto on。
chat_auto=no_messages:当前 round 的 manifest 没有可用 rounds[].chat_messages。
观察者看不到文字聊天:先确认聊天区不是被 HUD/过滤隐藏,再设置 sv_full_alltalk 1。
sv_allchat 1 单独不够。
某些玩家聊天缺失:通常是 sender 没有映射到当前 loaded replay bot,或该 slot 不再是安全
replay bot。检查 dtr_status、partial replay skip 和当前 source round 是否匹配。
Start here
Convert
Playback
Reference