Repository: pion/mediadevices
Pull request #184 (2020-06-09 04:51:53)

Fix audio transforms
SamplingRate field was not copied and Len of Buffer output was wrong.

related #182 


Patch:
diff --git a/pkg/io/audio/buffer.go b/pkg/io/audio/buffer.go
index 22b494a..0df6d8f 100644
--- a/pkg/io/audio/buffer.go
+++ b/pkg/io/audio/buffer.go
@@ -28,7 +28,11 @@ func NewBuffer(nSamples int) TransformFunc {
 					ib, ok := inBuff.(*wave.Float32Interleaved)
 					if !ok || ib.Size.Channels != b.Size.Channels {
 						ib = wave.NewFloat32Interleaved(
-							wave.ChunkInfo{Channels: b.Size.Channels, Len: nSamples},
+							wave.ChunkInfo{
+								SamplingRate: b.Size.SamplingRate,
+								Channels:     b.Size.Channels,
+								Len:          nSamples,
+							},
 						)
 						ib.Data = ib.Data[:0]
 						ib.Size.Len = 0
@@ -41,7 +45,11 @@ func NewBuffer(nSamples int) TransformFunc {
 					ib, ok := inBuff.(*wave.Int16Interleaved)
 					if !ok || ib.Size.Channels != b.Size.Channels {
 						ib = wave.NewInt16Interleaved(
-							wave.ChunkInfo{Channels: b.Size.Channels, Len: nSamples},
+							wave.ChunkInfo{
+								SamplingRate: b.Size.SamplingRate,
+								Channels:     b.Size.Channels,
+								Len:          nSamples,
+							},
 						)
 						ib.Data = ib.Data[:0]
 						ib.Size.Len = 0
@@ -57,6 +65,7 @@ func NewBuffer(nSamples int) TransformFunc {
 			switch ib := inBuff.(type) {
 			case *wave.Int16Interleaved:
 				ibCopy := *ib
+				ibCopy.Size.Len = nSamples
 				n := nSamples * ib.Size.Channels
 				ibCopy.Data = make([]int16, n)
 				copy(ibCopy.Data, ib.Data)
@@ -66,6 +75,7 @@ func NewBuffer(nSamples int) TransformFunc {
 
 			case *wave.Float32Interleaved:
 				ibCopy := *ib
+				ibCopy.Size.Len = nSamples
 				n := nSamples * ib.Size.Channels
 				ibCopy.Data = make([]float32, n)
 				copy(ibCopy.Data, ib.Data)
diff --git a/pkg/io/audio/mixer.go b/pkg/io/audio/mixer.go
index 6f44507..3259294 100644
--- a/pkg/io/audio/mixer.go
+++ b/pkg/io/audio/mixer.go
@@ -17,24 +17,19 @@ func NewChannelMixer(channels int, mixer mixer.ChannelMixer) TransformFunc {
 			if ci.Channels == channels {
 				return buff, nil
 			}
+
+			ci.Channels = channels
+
 			var mixed wave.Audio
 			switch buff.(type) {
 			case *wave.Int16Interleaved:
-				mixed = wave.NewInt16Interleaved(
-					wave.ChunkInfo{Channels: channels, Len: ci.Len},
-				)
+				mixed = wave.NewInt16Interleaved(ci)
 			case *wave.Int16NonInterleaved:
-				mixed = wave.NewInt16NonInterleaved(
-					wave.ChunkInfo{Channels: channels, Len: ci.Len},
-				)
+				mixed = wave.NewInt16NonInterleaved(ci)
 			case *wave.Float32Interleaved:
-				mixed = wave.NewFloat32Interleaved(
-					wave.ChunkInfo{Channels: channels, Len: ci.Len},
-				)
+				mixed = wave.NewFloat32Interleaved(ci)
 			case *wave.Float32NonInterleaved:
-				mixed = wave.NewFloat32NonInterleaved(
-					wave.ChunkInfo{Channels: channels, Len: ci.Len},
-				)
+				mixed = wave.NewFloat32NonInterleaved(ci)
 			}
 			if err := mixer.Mix(mixed, buff); err != nil {
 				return nil, err


Test patch:
diff --git a/pkg/io/audio/buffer_test.go b/pkg/io/audio/buffer_test.go
new file mode 100644
index 0000000..9f4b511
--- /dev/null
+++ b/pkg/io/audio/buffer_test.go
@@ -0,0 +1,72 @@
+package audio
+
+import (
+	"io"
+	"reflect"
+	"testing"
+
+	"github.com/pion/mediadevices/pkg/wave"
+)
+
+func TestBuffer(t *testing.T) {
+	input := []wave.Audio{
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 1, Channels: 2, SamplingRate: 1234},
+			Data: []int16{1, 2},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 3, Channels: 2, SamplingRate: 1234},
+			Data: []int16{3, 4, 5, 6, 7, 8},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 2, Channels: 2, SamplingRate: 1234},
+			Data: []int16{9, 10, 11, 12},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 7, Channels: 2, SamplingRate: 1234},
+			Data: []int16{13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
+		},
+	}
+	expected := []wave.Audio{
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 3, Channels: 2, SamplingRate: 1234},
+			Data: []int16{1, 2, 3, 4, 5, 6},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 3, Channels: 2, SamplingRate: 1234},
+			Data: []int16{7, 8, 9, 10, 11, 12},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 3, Channels: 2, SamplingRate: 1234},
+			Data: []int16{13, 14, 15, 16, 17, 18},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 3, Channels: 2, SamplingRate: 1234},
+			Data: []int16{19, 20, 21, 22, 23, 24},
+		},
+	}
+
+	trans := NewBuffer(3)
+
+	var iSent int
+	r := trans(ReaderFunc(func() (wave.Audio, error) {
+		if iSent < len(input) {
+			iSent++
+			return input[iSent-1], nil
+		}
+		return nil, io.EOF
+	}))
+
+	for i := 0; ; i++ {
+		a, err := r.Read()
+		if err != nil {
+			if err == io.EOF && i >= len(expected) {
+				break
+			}
+			t.Fatal(err)
+		}
+		if !reflect.DeepEqual(expected[i], a) {
+			t.Errorf("Expected wave[%d]: %v, got: %v", i, expected[i], a)
+		}
+	}
+}
diff --git a/pkg/io/audio/mixer_test.go b/pkg/io/audio/mixer_test.go
new file mode 100644
index 0000000..a31ace9
--- /dev/null
+++ b/pkg/io/audio/mixer_test.go
@@ -0,0 +1,57 @@
+package audio
+
+import (
+	"io"
+	"reflect"
+	"testing"
+
+	"github.com/pion/mediadevices/pkg/wave"
+	"github.com/pion/mediadevices/pkg/wave/mixer"
+)
+
+func TestMixer(t *testing.T) {
+	input := []wave.Audio{
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 1, Channels: 2, SamplingRate: 1234},
+			Data: []int16{1, 3},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 3, Channels: 2, SamplingRate: 1234},
+			Data: []int16{2, 4, 3, 5, 4, 6},
+		},
+	}
+	expected := []wave.Audio{
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 1, Channels: 1, SamplingRate: 1234},
+			Data: []int16{2},
+		},
+		&wave.Int16Interleaved{
+			Size: wave.ChunkInfo{Len: 3, Channels: 1, SamplingRate: 1234},
+			Data: []int16{3, 4, 5},
+		},
+	}
+
+	trans := NewChannelMixer(1, &mixer.MonoMixer{})
+
+	var iSent int
+	r := trans(ReaderFunc(func() (wave.Audio, error) {
+		if iSent < len(input) {
+			iSent++
+			return input[iSent-1], nil
+		}
+		return nil, io.EOF
+	}))
+
+	for i := 0; ; i++ {
+		a, err := r.Read()
+		if err != nil {
+			if err == io.EOF && i >= len(expected) {
+				break
+			}
+			t.Fatal(err)
+		}
+		if !reflect.DeepEqual(expected[i], a) {
+			t.Errorf("Expected wave[%d]: %v, got: %v", i, expected[i], a)
+		}
+	}
+}