// Package audiotest provides dummy audio driver for testing. package audiotest import ( "context" "io" "math" "time" "github.com/pion/mediadevices/pkg/driver" "github.com/pion/mediadevices/pkg/io/audio" "github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/wave" ) func init() { driver.GetManager().Register( &dummy{}, driver.Info{Label: "AudioTest", DeviceType: driver.Microphone}, ) } type dummy struct { closed <-chan struct{} cancel func() } func (d *dummy) Open() error { ctx, cancel := context.WithCancel(context.Background()) d.closed = ctx.Done() d.cancel = cancel return nil } func (d *dummy) Close() error { d.cancel() return nil } func (d *dummy) AudioRecord(p prop.Media) (audio.Reader, error) { var sin [100]float32 for i := range sin { sin[i] = float32(math.Sin(2*math.Pi*float64(i)/100) * 0.25) // 480 Hz } if p.Latency == 0 { p.Latency = 20 * time.Millisecond } nSample := int(uint64(p.SampleRate) * uint64(p.Latency) / uint64(time.Second)) nextReadTime := time.Now() var phase int closed := d.closed reader := audio.ReaderFunc(func() (wave.Audio, func(), error) { select { case <-closed: return nil, func() {}, io.EOF default: } time.Sleep(nextReadTime.Sub(time.Now())) nextReadTime = nextReadTime.Add(p.Latency) a := wave.NewFloat32Interleaved( wave.ChunkInfo{ Channels: p.ChannelCount, Len: nSample, SamplingRate: p.SampleRate, }, ) for i := 0; i < nSample; i++ { phase++ if phase >= 100 { phase = 0 } for ch := 0; ch < p.ChannelCount; ch++ { a.SetFloat32(i, ch, wave.Float32Sample(sin[phase])) } } return a, func() {}, nil }) return reader, nil } func (d *dummy) Properties() []prop.Media { return []prop.Media{ { Audio: prop.Audio{ SampleRate: 48000, Latency: time.Millisecond * 20, ChannelCount: 1, }, }, { Audio: prop.Audio{ SampleRate: 48000, Latency: time.Millisecond * 20, ChannelCount: 2, }, }, } }