package audio 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 BitsPerByte = 8 type PCMStreamDriver struct { PCM <-chan []byte BufferSizeByBytes uint16 WaveHeader *WavHeader closed <-chan struct{} cancel func() } func (w *PCMStreamDriver) Open() error { ctx, cancel := context.WithCancel(context.Background()) w.closed = ctx.Done() w.cancel = cancel return nil } func (w *PCMStreamDriver) Close() error { w.cancel() return nil } func (w *PCMStreamDriver) Properties() []prop.Media { logrus.Debugf("wave header: %v", w.WaveHeader) return []prop.Media{ { Audio: prop.Audio{ SampleRate: int(w.WaveHeader.SampleRate), ChannelCount: int(w.WaveHeader.NumChannels), SampleSize: int(w.WaveHeader.BitsPerSample), Latency: w.WaveHeader.GetLatnecy(w.BufferSizeByBytes), IsFloat: false, // just 8bit or 16bit with qemu IsBigEndian: false, // qemu should be little endian IsInterleaved: true, }, }, } } func (w *PCMStreamDriver) AudioRecord(p prop.Media) (audio.Reader, error) { logrus.Debug(p) chunkInfo := wave.ChunkInfo{ Len: int(w.BufferSizeByBytes) / int(p.SampleSize/BitsPerByte), Channels: p.ChannelCount, SamplingRate: p.SampleRate, } reader := func() (wave.Audio, func(), error) { a := wave.NewInt16Interleaved(chunkInfo) select { case <-w.closed: return nil, func() {}, io.EOF case pcmData := <-w.PCM: copy(a.Data, bytesTo16BitSamples(pcmData[:])) case <-time.After(p.Latency): // no stuck } 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+2]) samples = append(samples, int16(sample)) } return samples }