2022-09-28 06:14:26 +00:00
|
|
|
package audio
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/binary"
|
|
|
|
"io"
|
2022-10-02 10:50:08 +00:00
|
|
|
"time"
|
2022-09-28 06:14:26 +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 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)
|
2022-10-10 11:12:26 +00:00
|
|
|
ticker := time.NewTicker(p.Latency)
|
|
|
|
defer ticker.Stop()
|
2022-09-28 06:14:26 +00:00
|
|
|
select {
|
|
|
|
case <-w.closed:
|
|
|
|
return nil, func() {}, io.EOF
|
2022-10-02 10:50:08 +00:00
|
|
|
case pcmData := <-w.PCM:
|
2022-09-28 06:14:26 +00:00
|
|
|
copy(a.Data, bytesTo16BitSamples(pcmData[:]))
|
2022-10-10 11:12:26 +00:00
|
|
|
case <-ticker.C:
|
2022-10-02 10:50:08 +00:00
|
|
|
// no stuck
|
2022-09-28 06:14:26 +00:00
|
|
|
}
|
|
|
|
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 {
|
2022-09-30 04:24:32 +00:00
|
|
|
sample := binary.LittleEndian.Uint16(b[i : i+2])
|
2022-09-28 06:14:26 +00:00
|
|
|
samples = append(samples, int16(sample))
|
|
|
|
}
|
|
|
|
return samples
|
|
|
|
}
|