package audiodriver import ( "context" "encoding/binary" "io" "time" "github.com/pion/mediadevices/pkg/io/audio" "github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/wave" "github.com/sirupsen/logrus" ) const ( DataChunkIDSize = 4 DataChunkSizeSize = 4 ) // BufferSize for pcm bytes const BufferSize = 512 const BitsPerByte = 8 type WavFIFODriver struct { PCM <-chan [BufferSize]byte WaveHeader <-chan *WavHeader closed <-chan struct{} cancel func() } func New() *WavFIFODriver { return &WavFIFODriver{} } func (w *WavFIFODriver) Open() error { defer logrus.Debug("device opened") ctx, cancel := context.WithCancel(context.Background()) w.closed = ctx.Done() w.cancel = cancel return nil } func (w *WavFIFODriver) Close() error { defer w.cancel() return nil } func (w *WavFIFODriver) Properties() []prop.Media { waveHeader := <-w.WaveHeader logrus.Debugf("wave header: %v", waveHeader) return []prop.Media{ { Audio: prop.Audio{ SampleRate: int(waveHeader.SampleRate), ChannelCount: int(waveHeader.NumChannels), Latency: waveHeader.GetLatnecy(), IsFloat: false, // just 8bit or 16bit with qemu IsBigEndian: false, // qemu should be little endian IsInterleaved: true, }, }, } } func (w *WavFIFODriver) AudioRecord(p prop.Media) (audio.Reader, error) { a := wave.NewInt16Interleaved(wave.ChunkInfo{ Len: BufferSize / int(p.SampleSize/BitsPerByte), Channels: p.ChannelCount, SamplingRate: p.SampleRate, }) reader := func() (wave.Audio, func(), error) { select { case <-w.closed: return nil, func() {}, io.EOF case pcmData, ok := <-w.PCM: logrus.Debug("got %d bytes pcm data", len(pcmData)) if !ok { return nil, func() {}, io.ErrClosedPipe } copy(a.Data, bytesTo16BitSamples(pcmData[:])) case <-time.After(p.Latency): } return a, func() {}, nil } return audio.ReaderFunc(reader), nil } func bytesTo16BitSamples(b []byte) []int16 { samples := make([]int16, 0) for i := 0; i < len(b); i += 2 { sample := binary.LittleEndian.Uint16(b[i : i+1]) samples = append(samples, int16(sample)) } return samples }