Start to implement Silk decoder

Only parse the LP Headers, not sub-frame aware yet
This commit is contained in:
Sean DuBois 2022-07-07 16:15:51 -04:00
parent 1df150a6e9
commit cb80e84c4e
4 changed files with 96 additions and 3 deletions

View file

@ -1,9 +1,19 @@
package opus
import "fmt"
import (
"fmt"
"github.com/pion/opus/internal/silk"
)
// Decoder decodes the Opus bitstream into PCM
type Decoder struct {
silkDecoder silk.Decoder
}
// NewDecoder creates a new Opus Decoder
func NewDecoder() *Decoder {
return &Decoder{}
}
// Decode decodes the Opus bitstream into PCM
@ -15,9 +25,10 @@ func (d *Decoder) Decode(in []byte) (bandwidth Bandwidth, isStereo bool, frames
tocHeader := tableOfContentsHeader(in[0])
cfg := tocHeader.configuration()
var encodedFrames [][]byte
switch tocHeader.frameCode() {
case frameCodeOneFrame:
frames = append(frames, in[1:])
encodedFrames = append(encodedFrames, in[1:])
default:
return 0, false, nil, fmt.Errorf("%w: %d", errUnsupportedFrameCode, tocHeader.frameCode())
}
@ -26,5 +37,14 @@ func (d *Decoder) Decode(in []byte) (bandwidth Bandwidth, isStereo bool, frames
return 0, false, nil, fmt.Errorf("%w: %d", errUnsupportedConfigurationMode, cfg.mode())
}
return cfg.bandwidth(), tocHeader.isStereo(), nil, nil
for _, encodedFrame := range encodedFrames {
_, decoded, err := d.silkDecoder.Decode(encodedFrame, tocHeader.isStereo(), cfg.frameDuration().nanoseconds())
if err != nil {
return 0, false, nil, err
}
frames = append(frames, decoded)
}
return cfg.bandwidth(), tocHeader.isStereo(), frames, nil
}

45
internal/silk/decoder.go Normal file
View file

@ -0,0 +1,45 @@
package silk
import (
"fmt"
"github.com/pion/opus/internal/rangecoding"
)
const (
nanoseconds20Ms = 20000000
)
// Decoder maintains the state needed to decode a stream
// of Silk frames
type Decoder struct {
rangeDecoder rangecoding.Decoder
}
// NewDecoder creates a new Silk Decoder
func NewDecoder() *Decoder {
return &Decoder{}
}
// Decode decodes many SILK subframes
func (d *Decoder) Decode(in []byte, isStereo bool, nanoseconds int) (samples int, decoded []byte, err error) {
if nanoseconds != nanoseconds20Ms {
return 0, nil, errUnsupportedSilkFrameDuration
} else if isStereo {
return 0, nil, errUnsupportedSilkStereo
}
d.rangeDecoder.Init(in)
voiceActivityDetected := d.rangeDecoder.DecodeSymbolLogP(1) == 1
lowBitRateRedundancy := d.rangeDecoder.DecodeSymbolLogP(1) == 1
if lowBitRateRedundancy {
return 0, nil, errUnsupportedSilkLowBitrateRedundancy
}
if voiceActivityDetected {
fmt.Println("VAD")
}
return
}

9
internal/silk/errors.go Normal file
View file

@ -0,0 +1,9 @@
package silk
import "errors"
var (
errUnsupportedSilkFrameDuration = errors.New("only silk frames with a duration of 20ms supported")
errUnsupportedSilkStereo = errors.New("silk decoder does not support stereo")
errUnsupportedSilkLowBitrateRedundancy = errors.New("silk decoder does not low bit-rate redundancy")
)

View file

@ -189,6 +189,25 @@ func (f frameDuration) String() string {
return "Invalid"
}
func (f frameDuration) nanoseconds() int {
switch f {
case frameDuration2500us:
return 2500
case frameDuration5ms:
return 5000000
case frameDuration10ms:
return 10000000
case frameDuration20ms:
return 20000000
case frameDuration40ms:
return 40000000
case frameDuration60ms:
return 60000000
}
return 0
}
func (c Configuration) frameDuration() frameDuration {
switch c {
case 16, 20, 24, 28: