feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

This commit is contained in:
AskaEth committed 2026-10-05 13:02:28 +08:00
1 parent 89715d1813
commit 4a2d276881
100 files changed
+11319

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
package transcode
import (
"bytes"
"strings"
)
// Format 是小写、无点的音频格式标识("amr" / "wav" / …)。
//
// 口径与 mediafetch.AudioFormatOf(internal/channel/mediafetch/inline_voice.go:62)
// 归一出的格式名、以及 voice.Audio{Format}(internal/runtime/multimodal/voice)
// 的格式名**同一份**:全仓的「字符串 ↔ Format」转换只有本文件的 FormatOf /
// FormatName 两处,调用方不得各写一份映射(design/25 §6.2)。
type Format string
const (
// FormatAMR 是 AMR-NB(窄带),魔数 `#!AMR\n`。
FormatAMR Format = "amr"
// FormatAMRWB 是 AMR-WB(宽带),魔数 `#!AMR-WB\n`。**本期不实现**
// (design/25 §3.3 后置):登记它是为了让嗅探与报错诚实——「认得出但没这条路」
// 比「认不出」更能说清问题。
FormatAMRWB Format = "amr-wb"
// FormatWAV 是 RIFF/WAVE 容器(本期只发 PCM16 一种载荷)。
FormatWAV Format = "wav"
)
// 魔数与容器标识。AMR 文件的头来自 RFC 4867 §5(存储格式);RIFF/WAVE 的四块
// 结构见 design/25 §0.5 登记的 WAV/RIFF 规范。
const (
amrNBMagic = "#!AMR\n"
amrWBMagic = "#!AMR-WB\n"
riffMagic = "RIFF"
waveMagic = "WAVE"
// riffChunkSizeOffset 是 RIFF 头里 "WAVE" 标识的起始偏移("RIFF" + 4 字节长度)。
riffChunkSizeOffset = 8
)
// FormatOf 把外部格式名归一成 Format:去空白、转小写、去掉开头的点
// (`.amr` → `amr`)。它不判断格式是否支持——「认不认得」由 Sniff /
// FormatOf 决定,「支不支持」由 Registry.Lookup 决定,两件事分开。
func FormatOf(name string) Format {
return Format(strings.ToLower(strings.TrimPrefix(strings.TrimSpace(name), ".")))
}
// FormatName 返回 Format 的规范字符串形式(= 归一化后的格式名)。
func FormatName(f Format) string { return string(f) }
// Sniff 按魔数嗅探 data 的音频格式。嗅不出即返回 false(deny-by-default:
// 类型不明的字节绝不进解码器)。
func Sniff(data []byte) (Format, bool) {
switch {
case bytes.HasPrefix(data, []byte(amrWBMagic)):
return FormatAMRWB, true
case bytes.HasPrefix(data, []byte(amrNBMagic)):
return FormatAMR, true
case len(data) >= riffChunkSizeOffset+len(waveMagic) &&
bytes.HasPrefix(data, []byte(riffMagic)) &&
bytes.HasPrefix(data[riffChunkSizeOffset:], []byte(waveMagic)):
return FormatWAV, true
default:
return "", false
}
}