75 lines
1.9 KiB
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
|
|
}
|
|
}
|