64 lines
2.4 KiB
Go
64 lines
2.4 KiB
Go
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
|
||
}
|
||
}
|