decoder.go | 37 ++++++++++++++++++++++--------------- encoder.go | 36 ++++++++++++++++++++++-------------- opus_test.go | 27 +++++++++++++++------------ diff --git a/decoder.go b/decoder.go index 16b26288fe1e4895a1b47724d9846e6433883241..94e98386d224d27935c07cff6687f864d6706f55 100644 --- a/decoder.go +++ b/decoder.go @@ -56,15 +56,18 @@ } 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 @@ (*C.opus_int16)(&pcm[0]), 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 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") } - pcm := make([]float32, xMAX_FRAME_SIZE_MS*dec.sample_rate/1000) + if len(pcm) == 0 { + return 0, fmt.Errorf("opus: target buffer empty") + } n := int(C.opus_decode_float( dec.p, (*C.uchar)(&data[0]), @@ -94,7 +101,7 @@ (*C.float)(&pcm[0]), 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 58a541b573517dd46cd1847ef28839059e438332..e6e3ae44097a80d86bd5be36ef3c0ffb4778477a 100644 --- a/encoder.go +++ b/encoder.go @@ -60,14 +60,18 @@ } 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") } - data := make([]byte, maxEncodedFrameSize) + if len(data) == 0 { + return 0, fmt.Errorf("opus: no target buffer") + } n := int(C.opus_encode( enc.p, (*C.opus_int16)(&pcm[0]), @@ -75,19 +79,23 @@ C.int(len(pcm)), (*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 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") } - data := make([]byte, maxEncodedFrameSize) + if len(data) == 0 { + return 0, fmt.Errorf("opus: no target buffer") + } n := int(C.opus_encode_float( enc.p, (*C.float)(&pcm[0]), @@ -95,7 +103,7 @@ C.int(len(pcm)), (*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 c0d0eada007a0f81595a4cacaac5dd5e7817676f..76380eca751587e7a24caf7c5a09e70afc8ef5cd 100644 --- a/opus_test.go +++ b/opus_test.go @@ -40,11 +40,11 @@ } 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 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 @@ if err != nil || enc == nil { 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 @@ if err != nil || enc == nil { 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 @@ dec, err := NewDecoder(SAMPLE_RATE, 1) 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) } }