ace/lib/audiodriver/wavheader.go

119 lines
2.3 KiB
Go
Raw Permalink Normal View History

2022-09-26 03:04:07 +00:00
package audiodriver
import (
"bytes"
"encoding/binary"
2022-09-27 02:21:06 +00:00
"encoding/json"
2022-09-26 03:04:07 +00:00
"errors"
"io"
2022-09-27 02:21:06 +00:00
"time"
2022-09-26 03:04:07 +00:00
)
// Skip riff header and `fmt ` just 16 bytes
const (
FmtHeaderOffset = 0x0c
FmtHeaderIDSize = 4
FmtHeaderChunkSizeSize = 4
FmtHeaderSizeDefault = 16
2022-09-26 03:04:07 +00:00
)
type WavHeader struct {
ID [4]byte
Size uint32
AudioFormat uint16
NumChannels uint16
SampleRate uint32
ByteRate uint32
BlockAlign uint16
BitsPerSample uint16
}
2022-09-27 02:21:06 +00:00
func NewHeader(f io.Reader) (*WavHeader, error) {
w := &WavHeader{}
if err := w.Parse(f); err != nil {
return nil, err
}
return w, nil
}
func DefaultHeader() *WavHeader {
return &WavHeader{
Size: uint32(FmtHeaderSizeDefault),
AudioFormat: 1,
NumChannels: 2,
SampleRate: 48000, // opus only support 48kHz
BlockAlign: 4,
BitsPerSample: 16,
}
}
2022-09-27 02:21:06 +00:00
func (w *WavHeader) Parse(f io.Reader) error {
// skip headers
var headers [FmtHeaderOffset]byte
if _, err := f.Read(headers[:]); err != nil {
2022-09-26 03:04:07 +00:00
return err
}
var id [4]byte
if _, err := f.Read(id[:]); err != nil {
return err
}
if bytes.Equal(id[:], []byte{'f', 'm', 't', '0'}[:]) {
return errors.New("bad header")
}
w.ID = id
var size [4]byte
if _, err := f.Read(size[:]); err != nil {
return err
}
w.Size = binary.LittleEndian.Uint32(size[:])
var af [2]byte
if _, err := f.Read(af[:]); err != nil {
return err
}
w.AudioFormat = binary.LittleEndian.Uint16(af[:])
var nc [2]byte
if _, err := f.Read(nc[:]); err != nil {
return err
}
w.NumChannels = binary.LittleEndian.Uint16(nc[:])
var sr [4]byte
if _, err := f.Read(sr[:]); err != nil {
return err
}
w.SampleRate = binary.LittleEndian.Uint32(sr[:])
var br [4]byte
if _, err := f.Read(br[:]); err != nil {
return err
}
w.ByteRate = binary.LittleEndian.Uint32(br[:])
var ba [2]byte
if _, err := f.Read(ba[:]); err != nil {
return err
}
w.BlockAlign = binary.LittleEndian.Uint16(ba[:])
var bps [2]byte
2022-09-27 02:21:06 +00:00
if _, err := f.Read(bps[:]); err != nil {
2022-09-26 03:04:07 +00:00
return err
}
w.BitsPerSample = binary.LittleEndian.Uint16(bps[:])
return nil
}
2022-09-27 02:21:06 +00:00
func (w *WavHeader) String() string {
b, _ := json.Marshal(w)
return string(b)
}
func (w *WavHeader) GetLatnecy() time.Duration {
return time.Millisecond * time.Duration(BufferSize) / time.Duration(w.SampleRate) / time.Duration(w.NumChannels)
}