119 lines
2.3 KiB
Go
119 lines
2.3 KiB
Go
package audiodriver
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
// Skip riff header and `fmt ` just 16 bytes
|
|
const (
|
|
FmtHeaderOffset = 0x0c
|
|
FmtHeaderIDSize = 4
|
|
FmtHeaderChunkSizeSize = 4
|
|
FmtHeaderSizeDefault = 16
|
|
)
|
|
|
|
type WavHeader struct {
|
|
ID [4]byte
|
|
Size uint32
|
|
AudioFormat uint16
|
|
NumChannels uint16
|
|
SampleRate uint32
|
|
ByteRate uint32
|
|
BlockAlign uint16
|
|
BitsPerSample uint16
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|
|
|
|
func (w *WavHeader) Parse(f io.Reader) error {
|
|
// skip headers
|
|
var headers [FmtHeaderOffset]byte
|
|
if _, err := f.Read(headers[:]); err != nil {
|
|
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
|
|
if _, err := f.Read(bps[:]); err != nil {
|
|
return err
|
|
}
|
|
w.BitsPerSample = binary.LittleEndian.Uint16(bps[:])
|
|
|
|
return nil
|
|
}
|
|
|
|
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)
|
|
}
|