]> Sergey Matveev's repositories - go-opus.git/commitdiff
Bare API wrapper: encode & decode floats
authorHraban Luyat <hraban@0brg.net>
Thu, 19 Feb 2015 00:51:09 +0000 (00:51 +0000)
committerHraban Luyat <hraban@0brg.net>
Thu, 19 Feb 2015 00:51:09 +0000 (00:51 +0000)
api.go
opus_test.go

diff --git a/api.go b/api.go
index 709b0703563588a91cd3d9dcf7d7799123eb8de2..24f76dbceb71fb0b6d371c4200491bea845c5ccd 100644 (file)
--- a/api.go
+++ b/api.go
@@ -9,44 +9,10 @@ import (
 #cgo CFLAGS: -std=c99 -Wall -Werror -pedantic
 // Statically link libopus
 #cgo LDFLAGS: libopusbuild/lib/libopus.a -lm
-#include <stdio.h>
-#include <stdlib.h>
 #include <opus/opus.h>
-
-int
-engavg(const float *ar, int numfloats, char *buf, int bufsize)
-{
-    double sum = 0;
-
-    for (int i = 0; i < numfloats; i++) {
-        sum += ar[i];
-    }
-
-    int n = snprintf(buf, bufsize, "%g", sum / numfloats);
-    if (n < 0 || n >= bufsize) {
-        return -1;
-    }
-
-    return n;
-}
-
 */
 import "C"
 
-func engavg(ar []float32) string {
-       buf := make([]byte, 30)
-       n := int(C.engavg(
-               (*C.float)(&ar[0]),
-               C.int(len(ar)),
-               (*C.char)(unsafe.Pointer(&buf[0])),
-               C.int(cap(buf))))
-       if n < 0 {
-               return fmt.Sprintf("Error: %d", n)
-       }
-       return string(buf[:n])
-
-}
-
 type Application int
 
 // TODO: Get from lib because #defines can change
@@ -54,19 +20,97 @@ const APPLICATION_VOIP Application = 2048
 const APPLICATION_AUDIO Application = 2049
 const APPLICATION_RESTRICTED_LOWDELAY Application = 2051
 
+const xMAX_BITRATE = 48000
+const xMAX_FRAME_SIZE_MS = 60
+const xMAX_FRAME_SIZE = xMAX_BITRATE * xMAX_FRAME_SIZE_MS / 1000
+
+func Version() string {
+       return C.GoString(C.opus_get_version_string())
+}
+
 type Encoder struct {
-       p unsafe.Pointer
+       p *C.struct_OpusEncoder
+}
+
+func opuserr(code int) error {
+       return fmt.Errorf("opus: %s", C.GoString(C.opus_strerror(C.int(code))))
 }
 
 func NewEncoder(sample_rate int, channels int, application Application) (*Encoder, error) {
        var errno int
-       p := unsafe.Pointer(C.opus_encoder_create(C.opus_int32(sample_rate), C.int(channels), C.int(application), (*C.int)(unsafe.Pointer(&errno))))
+       p := C.opus_encoder_create(C.opus_int32(sample_rate), C.int(channels), C.int(application), (*C.int)(unsafe.Pointer(&errno)))
        if errno != 0 {
-               return nil, fmt.Errorf("opus: %s", C.GoString(C.opus_strerror(C.int(errno))))
+               return nil, opuserr(errno)
        }
        return &Encoder{p: p}, nil
 }
 
-func Version() string {
-       return C.GoString(C.opus_get_version_string())
+func (enc *Encoder) EncodeFloat32(pcm []float32) ([]byte, error) {
+       // I never know how much to allocate
+       data := make([]byte, 10000)
+       n := int(C.opus_encode_float(
+               enc.p,
+               (*C.float)(&pcm[0]),
+               C.int(len(pcm)),
+               (*C.uchar)(&data[0]),
+               C.opus_int32(cap(data))))
+       if n < 0 {
+               return nil, opuserr(n)
+       }
+       return data[:n], nil
+}
+
+// Returns an error if the encoder was already closed
+func (enc *Encoder) Close() error {
+       if enc.p == nil {
+               return fmt.Errorf("opus: encoder already closed")
+       }
+       C.opus_encoder_destroy(enc.p)
+       enc.p = nil
+       return nil
+}
+
+type Decoder struct {
+       p           *C.struct_OpusDecoder
+       sample_rate int
+}
+
+func NewDecoder(sample_rate int, channels int) (*Decoder, error) {
+       var errno int
+       p := C.opus_decoder_create(C.opus_int32(sample_rate), C.int(channels), (*C.int)(unsafe.Pointer(&errno)))
+       if errno != 0 {
+               return nil, opuserr(errno)
+       }
+       dec := &Decoder{
+               p:           p,
+               sample_rate: sample_rate,
+       }
+       return dec, nil
+}
+
+func (dec *Decoder) DecodeFloat32(data []byte) ([]float32, error) {
+       var errno int
+       // I don't know how big this frame will be, but this is the limit
+       pcm := make([]float32, xMAX_FRAME_SIZE_MS*dec.sample_rate/1000)
+       n := int(C.opus_decode_float(
+               dec.p,
+               (*C.uchar)(&data[0]),
+               C.opus_int32(len(data)),
+               (*C.float)(&pcm[0]),
+               C.int(cap(pcm)),
+               0))
+       if n < 0 {
+               return nil, opuserr(errno)
+       }
+       return pcm[:n], nil
+}
+
+// Returns an error if the encoder was already closed
+func (dec *Decoder) Close() error {
+       if dec.p == nil {
+               return fmt.Errorf("opus: decoder already closed")
+       }
+       C.opus_decoder_destroy(dec.p)
+       dec.p = nil
+       return nil
 }
index 97a775b81f06b71d04b5b4a0d659af96767a2293..5109668583d135c3dc3aa0dbf974c83153d04f5d 100644 (file)
@@ -21,3 +21,23 @@ func Test_NewEncoder(t *testing.T) {
                t.Errorf("Expected error for illegal samplerate 12345")
        }
 }
+
+func Test_NewDecoder(t *testing.T) {
+       dec, err := NewDecoder(48000, 1)
+       if err != nil || dec == nil {
+               t.Errorf("Error creating new decoder: %v", err)
+       }
+       dec, err = NewDecoder(12345, 1)
+       if err == nil || dec != nil {
+               t.Errorf("Expected error for illegal samplerate 12345")
+       }
+}
+
+func Test_loop(t *testing.T) {
+       // Create bogus input sound
+       const SAMPLE_RATE = 48000
+       const FRAME_SIZE_MS = 10
+       const FRAME_SIZE = SAMPLE_RATE * FRAME_SIZE_MS / 1000
+       pcm := make([]float32, FRAME_SIZE)
+       //you know what I'll finish this later
+}