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

+86
View File
@@ -0,0 +1,86 @@
package transcode
import (
"fmt"
"sort"
"sync"
)
// Registry 承载「哪些 源→目标 可用」(design/25 §1.3.2 第一层)。它是**包内**的
// 编解码器注册表,与全局能力注册表(internal/capability/registry)是两件事:
// 后者表达「agent 可选用的能力 + 门控策略」,前者表达「本能力认识哪几条路」。
//
// 新增一种格式 = 往这里多一个注册项(见 codecs.go 的 DefaultCodecs);
// 并发安全。
type Registry struct {
mu sync.RWMutex
codecs map[route]Codec
}
// route 是「源→目标」这一对,作注册表的键。用结构体而非字符串拼接:拼接会让
// 格式名里出现分隔符时产生歧义(`a->b` 与 `a-` + `>b`)。
type route struct {
from Format
to Format
}
// NewRegistry 返回一个空且并发安全的编解码器注册表。
func NewRegistry() *Registry {
return &Registry{codecs: make(map[route]Codec)}
}
// Register 注册一条转换路。nil、源/目标为空、源等于目标都返回 ErrInvalidCodec;
// 同一对重复注册返回 ErrDuplicate。
func (r *Registry) Register(c Codec) error {
if c == nil {
return fmt.Errorf("transcode: register codec: %w: nil codec", ErrInvalidCodec)
}
from, to := c.From(), c.To()
if from == "" || to == "" {
return fmt.Errorf("transcode: register codec %q -> %q: %w: empty format", from, to, ErrInvalidCodec)
}
if from == to {
return fmt.Errorf("transcode: register codec %q -> %q: %w: identity route", from, to, ErrInvalidCodec)
}
r.mu.Lock()
defer r.mu.Unlock()
key := route{from: from, to: to}
if _, exists := r.codecs[key]; exists {
return fmt.Errorf("transcode: register codec %q -> %q: %w", from, to, ErrDuplicate)
}
r.codecs[key] = c
return nil
}
// Lookup 返回 from→to 这条路上的编解码器。没有这条路时 ok 为 false。
func (r *Registry) Lookup(from, to Format) (Codec, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
c, ok := r.codecs[route{from: from, to: to}]
return c, ok
}
// Formats 返回当前注册涉及的全部格式(源与目标去重后的并集,已排序)。
// 它是「发现」面:调用方据此知道本能力认识哪些格式名。
func (r *Registry) Formats() []Format {
r.mu.RLock()
defer r.mu.RUnlock()
seen := make(map[Format]struct{}, len(r.codecs)*2)
for key := range r.codecs {
seen[key.from] = struct{}{}
seen[key.to] = struct{}{}
}
out := make([]Format, 0, len(seen))
for f := range seen {
out = append(out, f)
}
sort.Slice(out, func(i, j int) bool { return out[i] < out[j] })
return out
}
// Len 返回已注册的「源→目标」路数。供启动期自检与测试断言使用。
func (r *Registry) Len() int {
r.mu.RLock()
defer r.mu.RUnlock()
return len(r.codecs)
}