// +build !amd64,!386,cgo package gopus // #cgo !nopkgconfig pkg-config: opus // // #include // enum { // gopus_ok = OPUS_OK, // gopus_bad_arg = OPUS_BAD_ARG, // gopus_small_buffer = OPUS_BUFFER_TOO_SMALL, // gopus_internal = OPUS_INTERNAL_ERROR, // gopus_invalid_packet = OPUS_INVALID_PACKET, // gopus_unimplemented = OPUS_UNIMPLEMENTED, // gopus_invalid_state = OPUS_INVALID_STATE, // gopus_alloc_fail = OPUS_ALLOC_FAIL, // }; // // // enum { // gopus_application_voip = OPUS_APPLICATION_VOIP, // gopus_application_audio = OPUS_APPLICATION_AUDIO, // gopus_restricted_lowdelay = OPUS_APPLICATION_RESTRICTED_LOWDELAY, // gopus_bitrate_max = OPUS_BITRATE_MAX, // }; // // // void gopus_setvbr(OpusEncoder *encoder, int vbr) { // opus_encoder_ctl(encoder, OPUS_SET_VBR(vbr)); // } // // void gopus_setbitrate(OpusEncoder *encoder, int bitrate) { // opus_encoder_ctl(encoder, OPUS_SET_BITRATE(bitrate)); // } // // opus_int32 gopus_bitrate(OpusEncoder *encoder) { // opus_int32 bitrate; // opus_encoder_ctl(encoder, OPUS_GET_BITRATE(&bitrate)); // return bitrate; // } // // void gopus_setapplication(OpusEncoder *encoder, int application) { // opus_encoder_ctl(encoder, OPUS_SET_APPLICATION(application)); // } // // opus_int32 gopus_application(OpusEncoder *encoder) { // opus_int32 application; // opus_encoder_ctl(encoder, OPUS_GET_APPLICATION(&application)); // return application; // } // // void gopus_encoder_resetstate(OpusEncoder *encoder) { // opus_encoder_ctl(encoder, OPUS_RESET_STATE); // } // // void gopus_decoder_resetstate(OpusDecoder *decoder) { // opus_decoder_ctl(decoder, OPUS_RESET_STATE); // } import "C" import ( "errors" "unsafe" ) type Application int const ( Voip Application = C.gopus_application_voip Audio Application = C.gopus_application_audio RestrictedLowDelay Application = C.gopus_restricted_lowdelay ) const ( BitrateMaximum = C.gopus_bitrate_max ) type Encoder struct { data []byte cEncoder *C.struct_OpusEncoder } func NewEncoder(sampleRate, channels int, application Application) (*Encoder, error) { encoder := &Encoder{} encoder.data = make([]byte, int(C.opus_encoder_get_size(C.int(channels)))) encoder.cEncoder = (*C.struct_OpusEncoder)(unsafe.Pointer(&encoder.data[0])) ret := C.opus_encoder_init(encoder.cEncoder, C.opus_int32(sampleRate), C.int(channels), C.int(application)) if err := getErr(ret); err != nil { return nil, err } return encoder, nil } func (e *Encoder) Encode(pcm []int16, frameSize, maxDataBytes int) ([]byte, error) { pcmPtr := (*C.opus_int16)(unsafe.Pointer(&pcm[0])) data := make([]byte, maxDataBytes) dataPtr := (*C.uchar)(unsafe.Pointer(&data[0])) encodedC := C.opus_encode(e.cEncoder, pcmPtr, C.int(frameSize), dataPtr, C.opus_int32(len(data))) encoded := int(encodedC) if encoded < 0 { return nil, getErr(C.int(encodedC)) } return data[0:encoded], nil } func (e *Encoder) SetVbr(vbr bool) { var cVbr C.int if vbr { cVbr = 1 } else { cVbr = 0 } C.gopus_setvbr(e.cEncoder, cVbr) } func (e *Encoder) SetBitrate(bitrate int) { C.gopus_setbitrate(e.cEncoder, C.int(bitrate)) } func (e *Encoder) Bitrate() int { return int(C.gopus_bitrate(e.cEncoder)) } func (e *Encoder) SetApplication(application Application) { C.gopus_setapplication(e.cEncoder, C.int(application)) } func (e *Encoder) Application() Application { return Application(C.gopus_application(e.cEncoder)) } func (e *Encoder) ResetState() { C.gopus_encoder_resetstate(e.cEncoder) } type Decoder struct { data []byte cDecoder *C.struct_OpusDecoder channels int } func NewDecoder(sampleRate, channels int) (*Decoder, error) { decoder := &Decoder{} decoder.data = make([]byte, int(C.opus_decoder_get_size(C.int(channels)))) decoder.cDecoder = (*C.struct_OpusDecoder)(unsafe.Pointer(&decoder.data[0])) ret := C.opus_decoder_init(decoder.cDecoder, C.opus_int32(sampleRate), C.int(channels)) if err := getErr(ret); err != nil { return nil, err } decoder.channels = channels return decoder, nil } func (d *Decoder) Decode(data []byte, frameSize int, fec bool) ([]int16, error) { var dataPtr *C.uchar if len(data) > 0 { dataPtr = (*C.uchar)(unsafe.Pointer(&data[0])) } dataLen := C.opus_int32(len(data)) output := make([]int16, d.channels*frameSize) outputPtr := (*C.opus_int16)(unsafe.Pointer(&output[0])) var cFec C.int if fec { cFec = 1 } else { cFec = 0 } cRet := C.opus_decode(d.cDecoder, dataPtr, dataLen, outputPtr, C.int(frameSize), cFec) ret := int(cRet) if ret < 0 { return nil, getErr(cRet) } return output[:ret*d.channels], nil } func (d *Decoder) ResetState() { C.gopus_decoder_resetstate(d.cDecoder) } func CountFrames(data []byte) (int, error) { dataPtr := (*C.uchar)(unsafe.Pointer(&data[0])) cLen := C.opus_int32(len(data)) cRet := C.opus_packet_get_nb_frames(dataPtr, cLen) if err := getErr(cRet); err != nil { return 0, err } return int(cRet), nil } var ( ErrBadArgument = errors.New("bad argument") ErrSmallBuffer = errors.New("buffer is too small") ErrInternal = errors.New("internal error") ErrInvalidPacket = errors.New("invalid packet") ErrUnimplemented = errors.New("unimplemented") ErrInvalidState = errors.New("invalid state") ErrAllocFail = errors.New("allocation failed") ErrUnknown = errors.New("unknown error") ) func getErr(code C.int) error { switch code { case C.gopus_ok: return nil case C.gopus_bad_arg: return ErrBadArgument case C.gopus_small_buffer: return ErrSmallBuffer case C.gopus_internal: return ErrInternal case C.gopus_invalid_packet: return ErrInvalidPacket case C.gopus_unimplemented: return ErrUnimplemented case C.gopus_invalid_state: return ErrInvalidState case C.gopus_alloc_fail: return ErrAllocFail default: return ErrUnknown } }