2022-09-26 03:04:07 +00:00
|
|
|
package audiodriver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/binary"
|
|
|
|
"io"
|
2022-09-27 04:34:57 +00:00
|
|
|
"time"
|
2022-09-26 03:04:07 +00:00
|
|
|
|
|
|
|
"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 {
|
2022-09-27 02:21:06 +00:00
|
|
|
PCM <-chan [BufferSize]byte
|
|
|
|
WaveHeader <-chan *WavHeader
|
2022-09-26 03:04:07 +00:00
|
|
|
closed <-chan struct{}
|
|
|
|
cancel func()
|
|
|
|
}
|
|
|
|
|
2022-09-27 02:21:06 +00:00
|
|
|
func New() *WavFIFODriver {
|
|
|
|
return &WavFIFODriver{}
|
2022-09-26 03:04:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (w *WavFIFODriver) Open() error {
|
2022-09-27 02:21:06 +00:00
|
|
|
defer logrus.Debug("device opened")
|
2022-09-26 03:04:07 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
w.closed = ctx.Done()
|
|
|
|
w.cancel = cancel
|
|
|
|
|
2022-09-27 02:21:06 +00:00
|
|
|
return nil
|
2022-09-26 03:04:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (w *WavFIFODriver) Close() error {
|
|
|
|
defer w.cancel()
|
2022-09-27 02:21:06 +00:00
|
|
|
return nil
|
2022-09-26 03:04:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (w *WavFIFODriver) Properties() []prop.Media {
|
2022-09-27 02:21:06 +00:00
|
|
|
waveHeader := <-w.WaveHeader
|
|
|
|
logrus.Debugf("wave header: %v", waveHeader)
|
2022-09-26 03:04:07 +00:00
|
|
|
return []prop.Media{
|
|
|
|
{
|
|
|
|
Audio: prop.Audio{
|
2022-09-27 02:21:06 +00:00
|
|
|
SampleRate: int(waveHeader.SampleRate),
|
|
|
|
ChannelCount: int(waveHeader.NumChannels),
|
|
|
|
Latency: waveHeader.GetLatnecy(),
|
2022-09-26 03:04:07 +00:00
|
|
|
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) {
|
2022-09-27 04:34:57 +00:00
|
|
|
a := wave.NewInt16Interleaved(wave.ChunkInfo{
|
|
|
|
Len: BufferSize / int(p.SampleSize/BitsPerByte),
|
|
|
|
Channels: p.ChannelCount,
|
|
|
|
SamplingRate: p.SampleRate,
|
|
|
|
})
|
|
|
|
|
2022-09-26 03:04:07 +00:00
|
|
|
reader := func() (wave.Audio, func(), error) {
|
|
|
|
select {
|
|
|
|
case <-w.closed:
|
|
|
|
return nil, func() {}, io.EOF
|
2022-09-27 02:21:06 +00:00
|
|
|
case pcmData, ok := <-w.PCM:
|
2022-09-26 06:54:32 +00:00
|
|
|
logrus.Debug("got %d bytes pcm data", len(pcmData))
|
2022-09-26 03:04:07 +00:00
|
|
|
if !ok {
|
|
|
|
return nil, func() {}, io.ErrClosedPipe
|
|
|
|
}
|
|
|
|
copy(a.Data, bytesTo16BitSamples(pcmData[:]))
|
2022-09-27 04:34:57 +00:00
|
|
|
case <-time.After(p.Latency):
|
2022-09-26 03:04:07 +00:00
|
|
|
}
|
2022-09-27 04:34:57 +00:00
|
|
|
return a, func() {}, nil
|
2022-09-26 03:04:07 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|