Skip to content

Commit

Permalink
Add audio change detection
Browse files Browse the repository at this point in the history
  • Loading branch information
lherman-cs committed Oct 11, 2020
1 parent abdd96e commit 0210ec6
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
46 changes: 46 additions & 0 deletions pkg/io/audio/detect.go
Original file line number Diff line number Diff line change
@@ -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
})
}
}
77 changes: 77 additions & 0 deletions pkg/io/audio/detect_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
})
}

0 comments on commit 0210ec6

Please sign in to comment.