opus-go/decoder.go

75 lines
1.9 KiB
Go

package opus
import (
"fmt"
"github.com/pion/opus/internal/bitdepth"
"github.com/pion/opus/internal/silk"
)
// Decoder decodes the Opus bitstream into PCM
type Decoder struct {
silkDecoder silk.Decoder
silkBuffer []float32
}
// NewDecoder creates a new Opus Decoder
func NewDecoder() Decoder {
return Decoder{
silkDecoder: silk.NewDecoder(),
silkBuffer: make([]float32, 320),
}
}
func (d *Decoder) decode(in []byte) (bandwidth Bandwidth, isStereo bool, err error) {
if len(in) < 1 {
return 0, false, errTooShortForTableOfContentsHeader
}
tocHeader := tableOfContentsHeader(in[0])
cfg := tocHeader.configuration()
var encodedFrames [][]byte
switch tocHeader.frameCode() {
case frameCodeOneFrame:
encodedFrames = append(encodedFrames, in[1:])
default:
return 0, false, fmt.Errorf("%w: %d", errUnsupportedFrameCode, tocHeader.frameCode())
}
if cfg.mode() != configurationModeSilkOnly {
return 0, false, fmt.Errorf("%w: %d", errUnsupportedConfigurationMode, cfg.mode())
}
for _, encodedFrame := range encodedFrames {
err := d.silkDecoder.Decode(encodedFrame, d.silkBuffer, tocHeader.isStereo(), cfg.frameDuration().nanoseconds(), silk.Bandwidth(cfg.bandwidth()))
if err != nil {
return 0, false, err
}
}
return cfg.bandwidth(), tocHeader.isStereo(), nil
}
// Decode decodes the Opus bitstream into PCM
func (d *Decoder) Decode(in []byte, out []byte) (bandwidth Bandwidth, isStereo bool, err error) {
if bandwidth, isStereo, err = d.decode(in); err != nil {
return
} else {
if err := bitdepth.ConvertFloat32LittleEndianToSigned16LittleEndian(d.silkBuffer, out, 3); err != nil {
return 0, false, err
}
return
}
}
// DecodeFloat decodes the Opus bitstream into native float
func (d *Decoder) DecodeFloat(in []byte, out []float32) (bandwidth Bandwidth, isStereo bool, err error) {
if bandwidth, isStereo, err = d.decode(in); err != nil {
return
} else {
copy(out, d.silkBuffer)
return
}
}