From 2216e81897450fd5339c14b36ba7c2567412bebe Mon Sep 17 00:00:00 2001 From: Hraban Luyat Date: Thu, 19 Feb 2015 00:51:09 +0000 Subject: [PATCH] Bare API wrapper: encode & decode floats --- api.go | 122 +++++++++++++++++++++++++++++++++++---------------- opus_test.go | 20 +++++++++ 2 files changed, 103 insertions(+), 39 deletions(-) diff --git a/api.go b/api.go index 709b070..24f76db 100644 --- 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 -#include #include - -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 } diff --git a/opus_test.go b/opus_test.go index 97a775b..5109668 100644 --- a/opus_test.go +++ b/opus_test.go @@ -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 +} -- 2.48.1