Skip to content

fix: detect audio format from file content - #9612

Open
xiaoxuan010 wants to merge 1 commit into
AstrBotDevs:masterfrom
xiaoxuan010:codex/fix-audio-format-detection
Open

fix: detect audio format from file content#9612
xiaoxuan010 wants to merge 1 commit into
AstrBotDevs:masterfrom
xiaoxuan010:codex/fix-audio-format-detection

Conversation

@xiaoxuan010

@xiaoxuan010 xiaoxuan010 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Motivation / 动机

This issue occurs when AstrBot receives a QQ voice message through a NapCat/OneBot Record component.

QQ multimedia voice URLs commonly have no filename extension, while their downloaded bytes are AMR. The audio resolver explicitly passes default_suffix=".wav". When materializing an extensionless URL, it chooses the temporary-file suffix through Path(parsed.path).suffix or suffix. As a result, AMR bytes from a QQ voice message can be saved as a *.wav temporary file.

When a caller then requests WAV output, the previous convert_audio_format() fast path trusted only the .wav suffix and returned the AMR file without invoking ffmpeg. Downstream duration probing or an audio-capable Provider consequently receives AMR bytes declared as WAV, which can make probing fail or cause the Provider to reject the audio request.

该问题出现在 AstrBot 通过 NapCat/OneBot 的 Record 组件接收 QQ 语音消息时。

QQ 多媒体语音 URL 通常没有文件扩展名,但下载到的实际字节为 AMR。音频解析入口会传入 default_suffix=".wav"。实体化无扩展名 URL 时,则以 Path(parsed.path).suffix or suffix 选择临时文件后缀。因此,QQ 语音消息的 AMR 字节可能被保存为 *.wav 临时文件。

当调用方随后请求 WAV 输出时,旧版 convert_audio_format() 的快速路径仅依据 .wav 后缀直接返回该 AMR 文件,不会调用 ffmpeg。后续时长探测或音频模型因而收到“声明为 WAV、实际为 AMR”的字节,可能导致探测失败,或被 Provider 拒绝音频请求。

Modifications / 改动点

  • Only skip conversion when the source suffix matches the target format and the existing file's magic type also matches the target format.
    / 仅当文件后缀和文件头识别出的真实格式都等于目标格式时,才跳过转码。

  • Preserve the existing behavior for missing source paths.
    / 保持源路径不存在时的既有直接返回行为。

  • Add regression tests for AMR bytes misnamed as .wav, rewriting a misnamed target-format file, and preserving missing-path behavior.
    / 新增 AMR 内容误命名为 .wav、目标格式误命名以及缺失路径兼容行为的回归测试。

  • This is NOT a breaking change.
    / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

Chat screenshot: user catches Paimon lying about not hearing a voice message, Paimon admits she was caught.
python -m pytest -q tests/test_media_utils.py -k "transcodes_amr_bytes_misnamed_as_wav or rewrites_misnamed_target_format or keeps_missing_target_path"
3 passed, 50 deselected

python -m ruff check astrbot/core/utils/media_utils.py tests/test_media_utils.py
All checks passed!

Checklist / 检查清单

  • 😊 This is a bug fix and introduces no new feature or dependency.
    / 这是修复,不引入新功能或依赖。

  • 👀 The change has regression coverage and the relevant checks pass.
    / 已添加回归测试,相关检查通过。

  • 🤓 No new dependency is introduced.
    / 未引入新依赖。

  • 😮 This change does not introduce malicious code.
    / 未引入恶意代码。

@xiaoxuan010
xiaoxuan010 marked this pull request as ready for review August 9, 2026 13:51
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend labels Aug 9, 2026

@sourcery-ai sourcery-ai 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.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant