feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
This commit is contained in:
1 parent
89715d1813
commit
4a2d276881
100 files changed
+11319
No files matched your search
@@ -0,0 +1,103 @@
|
||||
package amrnb
|
||||
|
||||
import "errors"
|
||||
|
||||
// Encoder encodes 8 kHz mono PCM into AMR-NB RFC 4867 RTP payloads.
|
||||
//
|
||||
// It satisfies the codec.Encoder interface: Encode takes one 20 ms frame
|
||||
// (160 int16 samples) and returns a complete RTP payload (CMR + ToC + speech
|
||||
// bits) in the configured payload format.
|
||||
type Encoder struct {
|
||||
mode Mode
|
||||
octetAligned bool
|
||||
st encoderState
|
||||
}
|
||||
|
||||
// EncoderConfig configures a new AMR-NB encoder.
|
||||
type EncoderConfig struct {
|
||||
Mode Mode // active speech mode (0..7)
|
||||
OctetAligned bool // true: octet-aligned framing; false: bandwidth-efficient
|
||||
}
|
||||
|
||||
// NewEncoder creates an AMR-NB encoder for the given mode and payload format.
|
||||
func NewEncoder(cfg EncoderConfig) (*Encoder, error) {
|
||||
if !cfg.Mode.Valid() {
|
||||
return nil, errors.New("amrnb: invalid encoder mode")
|
||||
}
|
||||
e := &Encoder{mode: cfg.Mode, octetAligned: cfg.OctetAligned}
|
||||
e.st.reset()
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Encode encodes one 20 ms frame (160 samples) into an RTP payload.
|
||||
func (e *Encoder) Encode(samples []int16) ([]byte, error) {
|
||||
if len(samples) != FrameSamples {
|
||||
return nil, errors.New("amrnb: encode expects exactly 160 samples")
|
||||
}
|
||||
bits, err := e.st.encodeFrame(e.mode, samples)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f := frame{ft: e.mode.FrameType(), q: true, data: bits}
|
||||
if e.octetAligned {
|
||||
return packPayloadOctet(noCMR, []frame{f}), nil
|
||||
}
|
||||
return packPayloadBandwidthEfficient(noCMR, []frame{f}), nil
|
||||
}
|
||||
|
||||
// SetMode changes the active speech mode (e.g. in response to a peer CMR).
|
||||
func (e *Encoder) SetMode(m Mode) {
|
||||
if m.Valid() {
|
||||
e.mode = m
|
||||
}
|
||||
}
|
||||
|
||||
// Reset clears all encoder state.
|
||||
func (e *Encoder) Reset() { e.st.reset() }
|
||||
|
||||
// Decoder decodes AMR-NB RFC 4867 RTP payloads into 8 kHz mono PCM.
|
||||
type Decoder struct {
|
||||
octetAligned bool
|
||||
st decoderState
|
||||
}
|
||||
|
||||
// DecoderConfig configures a new AMR-NB decoder.
|
||||
type DecoderConfig struct {
|
||||
OctetAligned bool // must match the negotiated payload format
|
||||
}
|
||||
|
||||
// NewDecoder creates an AMR-NB decoder for the given payload format.
|
||||
func NewDecoder(cfg DecoderConfig) *Decoder {
|
||||
d := &Decoder{octetAligned: cfg.OctetAligned}
|
||||
d.st.reset()
|
||||
return d
|
||||
}
|
||||
|
||||
// Decode decodes one RTP payload, returning concatenated PCM for all frames it
|
||||
// carries (one 160-sample frame per speech/SID/no-data ToC entry).
|
||||
func (d *Decoder) Decode(payload []byte) ([]int16, error) {
|
||||
var (
|
||||
frames []frame
|
||||
err error
|
||||
)
|
||||
if d.octetAligned {
|
||||
_, frames, err = unpackPayloadOctet(payload)
|
||||
} else {
|
||||
_, frames, err = unpackPayloadBandwidthEfficient(payload)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]int16, 0, len(frames)*FrameSamples)
|
||||
for _, f := range frames {
|
||||
pcm, derr := d.st.decodeFrame(f)
|
||||
if derr != nil {
|
||||
return nil, derr
|
||||
}
|
||||
out = append(out, pcm...)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Reset clears all decoder state.
|
||||
func (d *Decoder) Reset() { d.st.reset() }
|
||||
Reference in new issue
Block a user