From: dh1tw Date: Fri, 30 Dec 2016 14:57:37 +0000 (+0100) Subject: added new encoder methods & tests X-Git-Tag: v2.0.0~38^2~3 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=df37abd4240e8535e80fa517877d479ac089cd52;p=go-opus.git added new encoder methods & tests --- diff --git a/AUTHORS b/AUTHORS index 850bdfd..4a65764 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Hraban Luyat Dejian Xu +Tobias Wellnitz diff --git a/encoder.go b/encoder.go index 683ce58..3e07930 100644 --- a/encoder.go +++ b/encoder.go @@ -34,9 +34,76 @@ bridge_encoder_get_sample_rate(OpusEncoder *st) opus_encoder_ctl(st, OPUS_GET_SAMPLE_RATE(&sample_rate)); return sample_rate; } + + +int +bridge_encoder_set_bitrate(OpusEncoder *st, opus_int32 bitrate) +{ + int res; + res = opus_encoder_ctl(st, OPUS_SET_BITRATE(bitrate)); + return res; +} + +int +bridge_encoder_get_bitrate(OpusEncoder *st, opus_int32 *bitrate) +{ + int res; + res = opus_encoder_ctl(st, OPUS_GET_BITRATE(bitrate)); + return res; +} + +int +bridge_encoder_set_complexity(OpusEncoder *st, opus_int32 complexity) +{ + int res; + res = opus_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity)); + return res; +} + +int +bridge_encoder_get_complexity(OpusEncoder *st, opus_int32 *complexity) +{ + int res; + res = opus_encoder_ctl(st, OPUS_GET_COMPLEXITY(complexity)); + return res; +} + +int +bridge_encoder_set_max_bandwidth(OpusEncoder *st, opus_int32 max_bw) +{ + int res; + res = opus_encoder_ctl(st, OPUS_SET_MAX_BANDWIDTH(max_bw)); + return res; +} + +int +bridge_encoder_get_max_bandwidth(OpusEncoder *st, opus_int32 *max_bw) +{ + int res; + res = opus_encoder_ctl(st, OPUS_GET_MAX_BANDWIDTH(max_bw)); + return res; +} + */ import "C" +const ( + // Auto bitrate + Auto = C.OPUS_AUTO + // Maximum bitrate + BitrateMax = C.OPUS_BITRATE_MAX + //4 kHz passband + BandwidthNarrowband = C.OPUS_BANDWIDTH_NARROWBAND + // 6 kHz passband + BandwidthMediumBand = C.OPUS_BANDWIDTH_MEDIUMBAND + // 8 kHz passband + BandwidthWideBand = C.OPUS_BANDWIDTH_WIDEBAND + // 12 kHz passband + BandwidthSuperWideBand = C.OPUS_BANDWIDTH_SUPERWIDEBAND + // 20 kHz passband + BandwidthFullband = C.OPUS_BANDWIDTH_FULLBAND +) + var errEncUninitialized = fmt.Errorf("opus encoder uninitialized") // Encoder contains the state of an Opus encoder for libopus. @@ -50,7 +117,7 @@ type Encoder struct { // NewEncoder allocates a new Opus encoder and initializes it with the // appropriate parameters. All related memory is managed by the Go GC. -func NewEncoder(sample_rate int, channels int, application Application) (*Encoder, error) { +func NewEncoder(sample_rate int, channels int, application int) (*Encoder, error) { var enc Encoder err := enc.Init(sample_rate, channels, application) if err != nil { @@ -62,7 +129,7 @@ func NewEncoder(sample_rate int, channels int, application Application) (*Encode // Init initializes a pre-allocated opus encoder. Unless the encoder has been // created using NewEncoder, this method must be called exactly once in the // life-time of this object, before calling any other methods. -func (enc *Encoder) Init(sample_rate int, channels int, application Application) error { +func (enc *Encoder) Init(sample_rate int, channels int, application int) error { if enc.p != nil { return fmt.Errorf("opus encoder already initialized") } @@ -162,3 +229,61 @@ func (enc *Encoder) DTX() bool { func (enc *Encoder) SampleRate() int { return int(C.bridge_encoder_get_sample_rate(enc.p)) } + +// SetBitrate sets the bitrate of the Encoder +func (enc *Encoder) SetBitrate(bitrate int) error { + res := C.bridge_encoder_set_bitrate(enc.p, C.opus_int32(bitrate)) + if res != C.OPUS_OK { + return Error(res) + } + return nil +} + +// Bitrate returns the bitrate of the Encoder +func (enc *Encoder) Bitrate() (int, error) { + var bitrate C.opus_int32 + res := C.bridge_encoder_get_bitrate(enc.p, &bitrate) + if res != C.OPUS_OK { + return 0, Error(res) + } + return int(bitrate), nil +} + +// SetComplexity sets the encoder's computational complexity +func (enc *Encoder) SetComplexity(complexity int) error { + res := C.bridge_encoder_set_complexity(enc.p, C.opus_int32(complexity)) + if res != C.OPUS_OK { + return Error(res) + } + return nil +} + +// Complexity returns the bitrate of the Encoder +func (enc *Encoder) Complexity() (int, error) { + var complexity C.opus_int32 + res := C.bridge_encoder_get_complexity(enc.p, &complexity) + if res != C.OPUS_OK { + return 0, Error(res) + } + return int(complexity), nil +} + +// SetMaxBandwidth configures the maximum bandpass that the encoder will select +// automatically +func (enc *Encoder) SetMaxBandwidth(maxBw int) error { + res := C.bridge_encoder_set_max_bandwidth(enc.p, C.opus_int32(maxBw)) + if res != C.OPUS_OK { + return Error(res) + } + return nil +} + +// MaxBandwidth gets the encoder's configured maximum allowed bandpass. +func (enc *Encoder) MaxBandwidth() (int, error) { + var maxBw C.opus_int32 + res := C.bridge_encoder_get_max_bandwidth(enc.p, &maxBw) + if res != C.OPUS_OK { + return 0, Error(res) + } + return int(maxBw), nil +} diff --git a/encoder_test.go b/encoder_test.go index 15d640c..4391791 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -57,3 +57,118 @@ func TestEncoderSampleRate(t *testing.T) { } } } + +func TestEncoder_SetGetBitrate(t *testing.T) { + enc, err := NewEncoder(8000, 1, AppVoIP) + if err != nil || enc == nil { + t.Errorf("Error creating new encoder: %v", err) + } + vals := []int{500, 100000, 300000} + for _, bitrate := range vals { + err := enc.SetBitrate(bitrate) + if err != nil { + t.Error("Error set bitrate:", err) + } + br, err := enc.Bitrate() + if err != nil { + t.Error("Error getting bitrate", err) + } + if br != bitrate { + t.Errorf("Unexpected bitrate. Got %d, but expected %d", br, bitrate) + } + } +} + +func TestEncoder_SetGetInvalidBitrate(t *testing.T) { + enc, err := NewEncoder(8000, 1, AppVoIP) + if err != nil || enc == nil { + t.Errorf("Error creating new encoder: %v", err) + } + invalidVals := []int{-20, 0} + for _, bitrate := range invalidVals { + err := enc.SetBitrate(bitrate) + if err == nil { + t.Errorf("Expected Error invalid bitrate: %d", bitrate) + } + br, err := enc.Bitrate() + if err != nil { + t.Error("Error getting bitrate", err) + } + // default bitrate is 32 kbit/s + if br != 32000 { + t.Errorf("Unexpected bitrate. Got %d, but expected %d", br, bitrate) + } + } +} + +func TestEncoder_SetGetComplexity(t *testing.T) { + enc, err := NewEncoder(8000, 1, AppVoIP) + if err != nil || enc == nil { + t.Errorf("Error creating new encoder: %v", err) + } + vals := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + for _, complexity := range vals { + err := enc.SetComplexity(complexity) + if err != nil { + t.Error("Error setting complexity value:", err) + } + cpx, err := enc.Complexity() + if err != nil { + t.Error("Error getting complexity value", err) + } + if cpx != complexity { + t.Errorf("Unexpected encoder complexity value. Got %d, but expected %d", + cpx, complexity) + } + } +} + +func TestEncoder_SetGetInvalidComplexity(t *testing.T) { + enc, err := NewEncoder(8000, 1, AppVoIP) + if err != nil || enc == nil { + t.Errorf("Error creating new encoder: %v", err) + } + invalidVals := []int{-20, 11, 1000} + for _, complexity := range invalidVals { + err := enc.SetComplexity(complexity) + if err == nil { + t.Errorf("Expected Error invalid complexity value: %d", complexity) + } + cpx, err := enc.Complexity() + if err != nil { + t.Error("Error getting complexity value", err) + } + // default complexity value is 9 + if cpx != 9 { + t.Errorf("Unexpected complexity value. Got %d, but expected %d", + cpx, complexity) + } + } +} + +func TestEncoder_SetGetMaxBandwidth(t *testing.T) { + enc, err := NewEncoder(8000, 1, AppVoIP) + if err != nil || enc == nil { + t.Errorf("Error creating new encoder: %v", err) + } + vals := []int{BandwidthNarrowband, + BandwidthMediumBand, + BandwidthWideBand, + BandwidthSuperWideBand, + BandwidthFullband, + } + for _, maxBw := range vals { + err := enc.SetMaxBandwidth(maxBw) + if err != nil { + t.Error("Error setting max Bandwidth:", err) + } + maxBwRead, err := enc.MaxBandwidth() + if err != nil { + t.Error("Error getting max Bandwidth", err) + } + if maxBwRead != maxBw { + t.Errorf("Unexpected max Bandwidth value. Got %d, but expected %d", + maxBwRead, maxBw) + } + } +} diff --git a/opus.go b/opus.go index 9040d77..c0ea7d3 100644 --- a/opus.go +++ b/opus.go @@ -18,15 +18,13 @@ import "C" type Application int -// These variables should be constants, but for interoperability with CGO -// they're var. Don't change them, though! -var ( +const ( // Optimize encoding for VoIP - AppVoIP = Application(C.CONST_APPLICATION_VOIP) + AppVoIP = C.OPUS_APPLICATION_VOIP // Optimize encoding for non-voice signals like music - AppAudio = Application(C.CONST_APPLICATION_AUDIO) + AppAudio = C.OPUS_APPLICATION_AUDIO // Optimize encoding for low latency applications - AppRestrictedLowdelay = Application(C.CONST_APPLICATION_RESTRICTED_LOWDELAY) + AppRestrictedLowdelay = C.OPUS_APPLICATION_RESTRICTED_LOWDELAY ) // DEPRECATED -- Don't use these. Will be removed end of 2017.