cloud-game/pkg/encoder/opus/opus.go
sergystepanov 602b9ea47c
Make executables ready for static linking (#307)
* Disable CGO (C libs) for coordinator

Needed for static linking.

* Fix "error strings should not be capitalized (ST1005)"

* Fix SA1015

Using time.Tick leaks the underlying ticker, consider using it only in endless functions, tests and the main package, and use time.NewTicker here (SA1015)

* Fix SA9004

Only the first constant in this group has an explicit type (SA9004).

* Remove unused code in the webrtc package

* Fix S1000

Should use a simple channel send/receive instead of select with a single case (S1000).

* Force dir creation/check for core downloader

* Update Makefile release script

* Disable ASLR for worker builds

* Remove WORKER_BUILD_PARAMS flag from the CI

* Don't force recompilation in release

* Add Debian packages installer script

* Build worker app without libopusfile

* Test worker app without libopusfile

* Add opus wrapper without opusfile

* Make install.sh executable

* Add opus lib in Win builds

* Make insecure HTTPS requests when downloading libs

* Add ca-certificates for Docker build stage

go mod download works only with SSL certificates installed.

* Move libx264 wrapper into the repo

That way we can get rid of a lot of not needed external Go dependencies.

* Update the dependencies
2021-04-06 18:16:52 +03:00

199 lines
7 KiB
Go

package opus
/*
#cgo pkg-config: opus
#include <opus.h>
int bridge_encoder_get_bitrate(OpusEncoder *st, opus_int32 *bitrate) { return opus_encoder_ctl(st, OPUS_GET_BITRATE(bitrate)); }
int bridge_encoder_get_complexity(OpusEncoder *st, opus_int32 *complexity) { return opus_encoder_ctl(st, OPUS_GET_COMPLEXITY(complexity)); }
int bridge_encoder_get_dtx(OpusEncoder *st, opus_int32 *dtx) { return opus_encoder_ctl(st, OPUS_GET_DTX(dtx)); }
int bridge_encoder_get_inband_fec(OpusEncoder *st, opus_int32 *fec) { return opus_encoder_ctl(st, OPUS_GET_INBAND_FEC(fec)); }
int bridge_encoder_get_max_bandwidth(OpusEncoder *st, opus_int32 *max_bw) { return opus_encoder_ctl(st, OPUS_GET_MAX_BANDWIDTH(max_bw)); }
int bridge_encoder_get_packet_loss_perc(OpusEncoder *st, opus_int32 *loss_perc) { return opus_encoder_ctl(st, OPUS_GET_PACKET_LOSS_PERC(loss_perc)); }
int bridge_encoder_get_sample_rate(OpusEncoder *st, opus_int32 *sample_rate) { return opus_encoder_ctl(st, OPUS_GET_SAMPLE_RATE(sample_rate)); }
int bridge_encoder_set_bitrate(OpusEncoder *st, opus_int32 bitrate) { return opus_encoder_ctl(st, OPUS_SET_BITRATE(bitrate)); }
int bridge_encoder_set_complexity(OpusEncoder *st, opus_int32 complexity) { return opus_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity)); }
int bridge_encoder_set_dtx(OpusEncoder *st, opus_int32 use_dtx) { return opus_encoder_ctl(st, OPUS_SET_DTX(use_dtx)); }
int bridge_encoder_set_inband_fec(OpusEncoder *st, opus_int32 fec) { return opus_encoder_ctl(st, OPUS_SET_INBAND_FEC(fec)); }
int bridge_encoder_set_max_bandwidth(OpusEncoder *st, opus_int32 max_bw) { return opus_encoder_ctl(st, OPUS_SET_MAX_BANDWIDTH(max_bw)); }
int bridge_encoder_set_packet_loss_perc(OpusEncoder *st, opus_int32 loss_perc) { return opus_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(loss_perc)); }
*/
import "C"
import (
"fmt"
"unsafe"
)
type (
Application int
Bandwidth int
Bitrate int
Error int
)
const (
// Optimize encoding for VoIP
AppVoIP = Application(C.OPUS_APPLICATION_VOIP)
// Optimize encoding for non-voice signals like music
AppAudio = Application(C.OPUS_APPLICATION_AUDIO)
// Optimize encoding for low latency applications
AppRestrictedLowdelay = Application(C.OPUS_APPLICATION_RESTRICTED_LOWDELAY)
// Auto/default setting
BitrateAuto = Bitrate(-1000)
BitrateMax = Bitrate(-1)
// 20 kHz bandpass
FullBand = Bandwidth(C.OPUS_BANDWIDTH_FULLBAND)
)
const (
ErrorOK = Error(C.OPUS_OK)
ErrorBadArg = Error(C.OPUS_BAD_ARG)
ErrorBufferTooSmall = Error(C.OPUS_BUFFER_TOO_SMALL)
ErrorInternalError = Error(C.OPUS_INTERNAL_ERROR)
ErrorInvalidPacket = Error(C.OPUS_INVALID_PACKET)
ErrorUnimplemented = Error(C.OPUS_UNIMPLEMENTED)
ErrorInvalidState = Error(C.OPUS_INVALID_STATE)
ErrorAllocFail = Error(C.OPUS_ALLOC_FAIL)
)
type LibOpusEncoder struct {
buf []byte
channels int
ptr *C.struct_OpusEncoder
}
// NewOpusEncoder creates new Opus encoder.
func NewOpusEncoder(sampleRate int, channels int, app Application) (*LibOpusEncoder, error) {
var enc LibOpusEncoder
if enc.ptr != nil {
return nil, fmt.Errorf("opus: encoder reinit")
}
enc.channels = channels
// !to check mem leak
enc.buf = make([]byte, C.opus_encoder_get_size(C.int(channels)))
enc.ptr = (*C.OpusEncoder)(unsafe.Pointer(&enc.buf[0]))
err := unwrap(C.opus_encoder_init(enc.ptr, C.opus_int32(sampleRate), C.int(channels), C.int(app)))
if err != nil {
return nil, fmt.Errorf("opus: initializatoin error (%v)", err)
}
return &enc, nil
}
// Encode converts raw PCM samples into the supplied Opus buffer.
// Returns the number of bytes converted.
func (enc *LibOpusEncoder) Encode(pcm []int16, data []byte) (rez int, err error) {
if len(pcm) == 0 {
return
}
samples := C.int(len(pcm) / enc.channels)
n := C.opus_encode(enc.ptr, (*C.opus_int16)(&pcm[0]), samples, (*C.uchar)(&data[0]), C.opus_int32(cap(data)))
if n > 0 {
rez = int(n)
}
return rez, unwrap(n)
}
// SampleRate returns the sample rate of the encoder.
func (enc *LibOpusEncoder) SampleRate() (int, error) {
var sampleRate C.opus_int32
res := C.bridge_encoder_get_sample_rate(enc.ptr, &sampleRate)
return int(sampleRate), unwrap(res)
}
// Bitrate returns the bitrate of the encoder.
func (enc *LibOpusEncoder) Bitrate() (int, error) {
var bitrate C.opus_int32
res := C.bridge_encoder_get_bitrate(enc.ptr, &bitrate)
return int(bitrate), unwrap(res)
}
// SetBitrate sets the bitrate of the encoder.
// BitrateMax / BitrateAuto can be used here.
func (enc *LibOpusEncoder) SetBitrate(b Bitrate) error {
return unwrap(C.bridge_encoder_set_bitrate(enc.ptr, C.opus_int32(b)))
}
// Complexity returns the value of the complexity.
func (enc *LibOpusEncoder) Complexity() (int, error) {
var complexity C.opus_int32
res := C.bridge_encoder_get_complexity(enc.ptr, &complexity)
return int(complexity), unwrap(res)
}
// SetComplexity sets the complexity factor for the encoder.
// Complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest.
func (enc *LibOpusEncoder) SetComplexity(complexity int) error {
return unwrap(C.bridge_encoder_set_complexity(enc.ptr, C.opus_int32(complexity)))
}
// DTX says if discontinuous transmission is enabled.
func (enc *LibOpusEncoder) DTX() (bool, error) {
var dtx C.opus_int32
res := C.bridge_encoder_get_dtx(enc.ptr, &dtx)
return dtx > 0, unwrap(res)
}
// SetDTX switches discontinuous transmission.
func (enc *LibOpusEncoder) SetDTX(dtx bool) error {
var i int
if dtx {
i = 1
}
return unwrap(C.bridge_encoder_set_dtx(enc.ptr, C.opus_int32(i)))
}
// MaxBandwidth returns the maximum allowed bandpass value.
func (enc *LibOpusEncoder) MaxBandwidth() (Bandwidth, error) {
var b C.opus_int32
res := C.bridge_encoder_get_max_bandwidth(enc.ptr, &b)
return Bandwidth(b), unwrap(res)
}
// SetMaxBandwidth sets the upper limit of the bandpass.
func (enc *LibOpusEncoder) SetMaxBandwidth(b Bandwidth) error {
return unwrap(C.bridge_encoder_set_max_bandwidth(enc.ptr, C.opus_int32(b)))
}
// FEC says if forward error correction (FEC) is enabled.
func (enc *LibOpusEncoder) FEC() (bool, error) {
var fec C.opus_int32
res := C.bridge_encoder_get_inband_fec(enc.ptr, &fec)
return fec > 0, unwrap(res)
}
// SetFEC switches the forward error correction (FEC).
func (enc *LibOpusEncoder) SetFEC(fec bool) error {
var i int
if fec {
i = 1
}
return unwrap(C.bridge_encoder_set_inband_fec(enc.ptr, C.opus_int32(i)))
}
// PacketLossPerc returns configured packet loss percentage.
func (enc *LibOpusEncoder) PacketLossPerc() (int, error) {
var lossPerc C.opus_int32
res := C.bridge_encoder_get_packet_loss_perc(enc.ptr, &lossPerc)
return int(lossPerc), unwrap(res)
}
// SetPacketLossPerc sets expected packet loss percentage.
func (enc *LibOpusEncoder) SetPacketLossPerc(lossPerc int) error {
return unwrap(C.bridge_encoder_set_packet_loss_perc(enc.ptr, C.opus_int32(lossPerc)))
}
func (e Error) Error() string {
return fmt.Sprintf("opus: %v", C.GoString(C.opus_strerror(C.int(e))))
}
func unwrap(error C.int) (err error) {
if error < C.OPUS_OK {
err = Error(int(error))
}
return
}
func CodecVersion() string { return C.GoString(C.opus_get_version_string()) }