From: Hraban Luyat <hraban@0brg.net>
Date: Wed, 22 Jul 2015 05:52:38 +0000 (+0100)
Subject: Let user pass the target buffers (noalloc)
X-Git-Tag: v2.0.0~79
X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=b6c362cf3b96075bbad96ea1778138e90201b012;p=go-opus.git

Let user pass the target buffers (noalloc)
---

diff --git a/decoder.go b/decoder.go
index 16b2628..94e9838 100644
--- a/decoder.go
+++ b/decoder.go
@@ -56,15 +56,18 @@ func (dec *Decoder) Init(sample_rate int, channels int) error {
 	return nil
 }
 
-func (dec *Decoder) Decode(data []byte) ([]int16, error) {
+// Decode encoded Opus data into the supplied buffer. On success, returns the
+// number of samples correctly written to the target buffer.
+func (dec *Decoder) Decode(data []byte, pcm []int16) (int, error) {
 	if dec.p == nil {
-		return nil, errDecUninitialized
+		return 0, errDecUninitialized
 	}
-	if data == nil || len(data) == 0 {
-		return nil, fmt.Errorf("opus: no data supplied")
+	if len(data) == 0 {
+		return 0, fmt.Errorf("opus: no data supplied")
+	}
+	if len(pcm) == 0 {
+		return 0, fmt.Errorf("opus: target buffer empty")
 	}
-	// I don't know how big this frame will be, but this is the limit
-	pcm := make([]int16, xMAX_FRAME_SIZE_MS*dec.sample_rate/1000)
 	n := int(C.opus_decode(
 		dec.p,
 		(*C.uchar)(&data[0]),
@@ -73,19 +76,23 @@ func (dec *Decoder) Decode(data []byte) ([]int16, error) {
 		C.int(cap(pcm)),
 		0))
 	if n < 0 {
-		return nil, opuserr(n)
+		return 0, opuserr(n)
 	}
-	return pcm[:n], nil
+	return n, nil
 }
 
-func (dec *Decoder) DecodeFloat32(data []byte) ([]float32, error) {
+// Decode encoded Opus data into the supplied buffer. On success, returns the
+// number of samples correctly written to the target buffer.
+func (dec *Decoder) DecodeFloat32(data []byte, pcm []float32) (int, error) {
 	if dec.p == nil {
-		return nil, errDecUninitialized
+		return 0, errDecUninitialized
+	}
+	if len(data) == 0 {
+		return 0, fmt.Errorf("opus: no data supplied")
 	}
-	if data == nil || len(data) == 0 {
-		return nil, fmt.Errorf("opus: no data supplied")
+	if len(pcm) == 0 {
+		return 0, fmt.Errorf("opus: target buffer empty")
 	}
-	pcm := make([]float32, xMAX_FRAME_SIZE_MS*dec.sample_rate/1000)
 	n := int(C.opus_decode_float(
 		dec.p,
 		(*C.uchar)(&data[0]),
@@ -94,7 +101,7 @@ func (dec *Decoder) DecodeFloat32(data []byte) ([]float32, error) {
 		C.int(cap(pcm)),
 		0))
 	if n < 0 {
-		return nil, opuserr(n)
+		return 0, opuserr(n)
 	}
-	return pcm[:n], nil
+	return n, nil
 }
diff --git a/encoder.go b/encoder.go
index 58a541b..e6e3ae4 100644
--- a/encoder.go
+++ b/encoder.go
@@ -60,14 +60,18 @@ func (enc *Encoder) Init(sample_rate int, channels int, application Application)
 	return nil
 }
 
-func (enc *Encoder) Encode(pcm []int16) ([]byte, error) {
+// Encode raw PCM data and store the result in the supplied buffer. On success,
+// returns the number of bytes used up by the encoded data.
+func (enc *Encoder) Encode(pcm []int16, data []byte) (int, error) {
 	if enc.p == nil {
-		return nil, errEncUninitialized
+		return 0, errEncUninitialized
 	}
-	if pcm == nil || len(pcm) == 0 {
-		return nil, fmt.Errorf("opus: no data supplied")
+	if len(pcm) == 0 {
+		return 0, fmt.Errorf("opus: no data supplied")
+	}
+	if len(data) == 0 {
+		return 0, fmt.Errorf("opus: no target buffer")
 	}
-	data := make([]byte, maxEncodedFrameSize)
 	n := int(C.opus_encode(
 		enc.p,
 		(*C.opus_int16)(&pcm[0]),
@@ -75,19 +79,23 @@ func (enc *Encoder) Encode(pcm []int16) ([]byte, error) {
 		(*C.uchar)(&data[0]),
 		C.opus_int32(cap(data))))
 	if n < 0 {
-		return nil, opuserr(n)
+		return 0, opuserr(n)
 	}
-	return data[:n], nil
+	return n, nil
 }
 
-func (enc *Encoder) EncodeFloat32(pcm []float32) ([]byte, error) {
+// Encode raw PCM data and store the result in the supplied buffer. On success,
+// returns the number of bytes used up by the encoded data.
+func (enc *Encoder) EncodeFloat32(pcm []float32, data []byte) (int, error) {
 	if enc.p == nil {
-		return nil, errEncUninitialized
+		return 0, errEncUninitialized
+	}
+	if len(pcm) == 0 {
+		return 0, fmt.Errorf("opus: no data supplied")
 	}
-	if pcm == nil || len(pcm) == 0 {
-		return nil, fmt.Errorf("opus: no data supplied")
+	if len(data) == 0 {
+		return 0, fmt.Errorf("opus: no target buffer")
 	}
-	data := make([]byte, maxEncodedFrameSize)
 	n := int(C.opus_encode_float(
 		enc.p,
 		(*C.float)(&pcm[0]),
@@ -95,7 +103,7 @@ func (enc *Encoder) EncodeFloat32(pcm []float32) ([]byte, error) {
 		(*C.uchar)(&data[0]),
 		C.opus_int32(cap(data))))
 	if n < 0 {
-		return nil, opuserr(n)
+		return 0, opuserr(n)
 	}
-	return data[:n], nil
+	return n, nil
 }
diff --git a/opus_test.go b/opus_test.go
index c0d0ead..76380ec 100644
--- a/opus_test.go
+++ b/opus_test.go
@@ -40,11 +40,11 @@ func TestDecoderNew(t *testing.T) {
 
 func TestEncoderUnitialized(t *testing.T) {
 	var enc Encoder
-	_, err := enc.Encode(nil)
+	_, err := enc.Encode(nil, nil)
 	if err != errEncUninitialized {
 		t.Errorf("Expected \"unitialized encoder\" error: %v", err)
 	}
-	_, err = enc.EncodeFloat32(nil)
+	_, err = enc.EncodeFloat32(nil, nil)
 	if err != errEncUninitialized {
 		t.Errorf("Expected \"unitialized encoder\" error: %v", err)
 	}
@@ -52,11 +52,11 @@ func TestEncoderUnitialized(t *testing.T) {
 
 func TestDecoderUnitialized(t *testing.T) {
 	var dec Decoder
-	_, err := dec.Decode(nil)
+	_, err := dec.Decode(nil, nil)
 	if err != errDecUninitialized {
 		t.Errorf("Expected \"unitialized decoder\" error: %v", err)
 	}
-	_, err = dec.DecodeFloat32(nil)
+	_, err = dec.DecodeFloat32(nil, nil)
 	if err != errDecUninitialized {
 		t.Errorf("Expected \"unitialized decoder\" error: %v", err)
 	}
@@ -98,20 +98,22 @@ func TestCodec(t *testing.T) {
 		t.Fatalf("Error creating new encoder: %v", err)
 	}
 	addSine(pcm, SAMPLE_RATE, G4)
-	data, err := enc.Encode(pcm)
+	data := make([]byte, 1000)
+	n, err := enc.Encode(pcm, data)
 	if err != nil {
 		t.Fatalf("Couldn't encode data: %v", err)
 	}
+	data = data[:n]
 	dec, err := NewDecoder(SAMPLE_RATE, 1)
 	if err != nil || dec == nil {
 		t.Fatalf("Error creating new decoder: %v", err)
 	}
-	pcm2, err := dec.Decode(data)
+	n, err = dec.Decode(data, pcm)
 	if err != nil {
 		t.Fatalf("Couldn't decode data: %v", err)
 	}
-	if len(pcm) != len(pcm2) {
-		t.Fatalf("Length mismatch: %d samples in, %d out", len(pcm), len(pcm2))
+	if len(pcm) != n {
+		t.Fatalf("Length mismatch: %d samples in, %d out", len(pcm), n)
 	}
 	// Checking the output programmatically is seriously not easy. I checked it
 	// by hand and by ear, it looks fine. I'll just assume the API faithfully
@@ -130,7 +132,8 @@ func TestCodecFloat32(t *testing.T) {
 		t.Fatalf("Error creating new encoder: %v", err)
 	}
 	addSineFloat32(pcm, SAMPLE_RATE, G4)
-	data, err := enc.EncodeFloat32(pcm)
+	data := make([]byte, 1000)
+	n, err := enc.EncodeFloat32(pcm, data)
 	if err != nil {
 		t.Fatalf("Couldn't encode data: %v", err)
 	}
@@ -138,11 +141,11 @@ func TestCodecFloat32(t *testing.T) {
 	if err != nil || dec == nil {
 		t.Fatalf("Error creating new decoder: %v", err)
 	}
-	pcm2, err := dec.DecodeFloat32(data)
+	n, err = dec.DecodeFloat32(data, pcm)
 	if err != nil {
 		t.Fatalf("Couldn't decode data: %v", err)
 	}
-	if len(pcm) != len(pcm2) {
-		t.Fatalf("Length mismatch: %d samples in, %d out", len(pcm), len(pcm2))
+	if len(pcm) != n {
+		t.Fatalf("Length mismatch: %d samples in, %d out", len(pcm), n)
 	}
 }