-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdecoder_root.go
More file actions
88 lines (80 loc) · 2.88 KB
/
Copy pathdecoder_root.go
File metadata and controls
88 lines (80 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package g729
import (
"github.com/hunydev/g729/internal/decoder"
)
// Decoder holds G.729 Annex A decoder state for one logical stream.
//
// All buffers are preallocated; DecodeFrame allocates 0 in steady state.
// Concurrent calls on the same Decoder are a data race; callers needing
// parallel decoding must own one Decoder per channel.
type Decoder struct {
inner decoder.Decoder
}
// NewDecoder returns a Decoder in initial state.
func NewDecoder() *Decoder {
return &Decoder{}
}
// Reset returns the Decoder to initial state. Equivalent to using a
// fresh NewDecoder, but reuses the existing memory.
func (d *Decoder) Reset() {
d.inner.Reset()
}
// DecodeFrame consumes exactly FrameBytes (10) bytes from bits and
// writes exactly FrameSamples (80) int16 samples (8 kHz mono) to out.
//
// Returns ErrUnsupportedAnnexB for the 2-byte RTP Annex B SID/CNG frame
// shape, ErrShortBitstream if len(bits) != FrameBytes, or ErrShortOutput if
// len(out) < FrameSamples. Internal state (LSP history, adaptive codebook,
// postfilter memories) is retained across calls. The decoder treats every
// 10-byte speech frame as good; Annex B SID/CNG/DTX and network
// erasure-concealment handling are out of scope.
func (d *Decoder) DecodeFrame(bits []byte, out []int16) error {
if isAnnexBSIDFrame(bits) {
return ErrUnsupportedAnnexB
}
if len(bits) != FrameBytes {
return ErrShortBitstream
}
if len(out) < FrameSamples {
return ErrShortOutput
}
return d.inner.Decode(bits, false, out)
}
// DecodeFrameEnhanced is an opt-in, non-strict decoder path for local
// listening diagnostics. Use DecodeFrame when strict decoder behavior is
// required; use this only as an audible fallback while the decoder core is
// still under black-box verification.
func (d *Decoder) DecodeFrameEnhanced(bits []byte, out []int16) error {
if isAnnexBSIDFrame(bits) {
return ErrUnsupportedAnnexB
}
if len(bits) != FrameBytes {
return ErrShortBitstream
}
if len(out) < FrameSamples {
return ErrShortOutput
}
return d.inner.DecodeEnvelopeRecovered(bits, false, out)
}
// DecodeFramePostfilterBlend is an opt-in, non-strict listening diagnostic.
// It blends the decoder postfilter output with the pre-postfilter synthesis
// before the output high-pass filter. synthNum/den controls the synthesis
// share; for example 1/2 means 50% postfilter + 50% synthesis.
//
// Use DecodeFrame for the strict decoder path. This method exists to A/B test
// decoder-side grit/noise reduction without changing the emitted G.729 payload.
func (d *Decoder) DecodeFramePostfilterBlend(bits []byte, out []int16, synthNum, den int) error {
if isAnnexBSIDFrame(bits) {
return ErrUnsupportedAnnexB
}
if len(bits) != FrameBytes {
return ErrShortBitstream
}
if len(out) < FrameSamples {
return ErrShortOutput
}
return d.inner.DecodePostfilterBlend(bits, false, out, synthNum, den)
}
func isAnnexBSIDFrame(bits []byte) bool {
return len(bits) == 2
}