mirror of
https://github.com/pion/mediadevices.git
synced 2026-04-22 15:57:27 +08:00
Add audio change detection
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
package audio
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/pion/mediadevices/pkg/prop"
|
||||
"github.com/pion/mediadevices/pkg/wave"
|
||||
)
|
||||
|
||||
// DetectChanges will detect chunk and audio property changes. For audio property detection,
|
||||
// since it's time related, interval will be used to determine the sample rate.
|
||||
func DetectChanges(interval time.Duration, onChange func(prop.Media)) TransformFunc {
|
||||
return func(r Reader) Reader {
|
||||
var currentProp prop.Media
|
||||
var chunkCount uint
|
||||
return ReaderFunc(func() (wave.Audio, error) {
|
||||
var dirty bool
|
||||
|
||||
chunk, err := r.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := chunk.ChunkInfo()
|
||||
if currentProp.ChannelCount != info.Channels {
|
||||
currentProp.ChannelCount = info.Channels
|
||||
dirty = true
|
||||
}
|
||||
|
||||
if currentProp.SampleRate != info.SamplingRate {
|
||||
currentProp.SampleRate = info.SamplingRate
|
||||
dirty = true
|
||||
}
|
||||
|
||||
// TODO: Also detect sample format changes?
|
||||
// TODO: Add audio detect changes. As of now, there's no useful property to track.
|
||||
|
||||
if dirty {
|
||||
onChange(currentProp)
|
||||
}
|
||||
|
||||
chunkCount++
|
||||
return chunk, nil
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package audio
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pion/mediadevices/pkg/prop"
|
||||
"github.com/pion/mediadevices/pkg/wave"
|
||||
)
|
||||
|
||||
func TestDetectChanges(t *testing.T) {
|
||||
buildSource := func(p prop.Media) (Reader, func(prop.Media)) {
|
||||
return ReaderFunc(func() (wave.Audio, error) {
|
||||
return wave.NewFloat32Interleaved(wave.ChunkInfo{
|
||||
Len: 0,
|
||||
Channels: p.ChannelCount,
|
||||
SamplingRate: p.SampleRate,
|
||||
}), nil
|
||||
}), func(newProp prop.Media) {
|
||||
p = newProp
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("OnChangeCalledBeforeFirstFrame", func(t *testing.T) {
|
||||
var detectBeforeFirstChunk bool
|
||||
var expected prop.Media
|
||||
var actual prop.Media
|
||||
expected.ChannelCount = 2
|
||||
expected.SampleRate = 48000
|
||||
src, _ := buildSource(expected)
|
||||
src = DetectChanges(time.Second, func(p prop.Media) {
|
||||
actual = p
|
||||
detectBeforeFirstChunk = true
|
||||
})(src)
|
||||
|
||||
_, err := src.Read()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !detectBeforeFirstChunk {
|
||||
t.Fatal("on change callback should have called before first chunk")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("Received an unexpected prop\nExpected:\n%v\nActual:\n%v\n", expected, actual)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DetectChangesOnEveryUpdate", func(t *testing.T) {
|
||||
var expected prop.Media
|
||||
var actual prop.Media
|
||||
expected.ChannelCount = 2
|
||||
expected.SampleRate = 48000
|
||||
src, update := buildSource(expected)
|
||||
src = DetectChanges(time.Second, func(p prop.Media) {
|
||||
actual = p
|
||||
})(src)
|
||||
|
||||
for channelCount := 1; channelCount < 8; channelCount++ {
|
||||
for sampleRate := 12000; sampleRate <= 48000; sampleRate += 4000 {
|
||||
expected.ChannelCount = channelCount
|
||||
expected.SampleRate = sampleRate
|
||||
update(expected)
|
||||
_, err := src.Read()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("Received an unexpected prop\nExpected:\n%v\nActual:\n%v\n", expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user