Files
Cyrene_v2/internal/capability/transcode/format.go
T
AskaEth 4a2d276881
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
2026-10-05 13:02:28 +08:00

64 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
}