Start to implement Silk decoder
Only parse the LP Headers, not sub-frame aware yet
This commit is contained in:
parent
1df150a6e9
commit
cb80e84c4e
26
decoder.go
26
decoder.go
|
@ -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
45
internal/silk/decoder.go
Normal 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
9
internal/silk/errors.go
Normal 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")
|
||||
)
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue