mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-01-23 18:46:11 +00:00
199 lines
6.4 KiB
Go
199 lines
6.4 KiB
Go
package opus
|
|
|
|
/*
|
|
#cgo pkg-config: opus
|
|
#cgo st LDFLAGS: -l:libopus.a
|
|
|
|
#include <opus.h>
|
|
|
|
int get_bitrate(OpusEncoder *st, opus_int32 *bitrate) { return opus_encoder_ctl(st, OPUS_GET_BITRATE(bitrate)); }
|
|
int get_complexity(OpusEncoder *st, opus_int32 *complexity) { return opus_encoder_ctl(st, OPUS_GET_COMPLEXITY(complexity)); }
|
|
int get_dtx(OpusEncoder *st, opus_int32 *dtx) { return opus_encoder_ctl(st, OPUS_GET_DTX(dtx)); }
|
|
int get_inband_fec(OpusEncoder *st, opus_int32 *fec) { return opus_encoder_ctl(st, OPUS_GET_INBAND_FEC(fec)); }
|
|
int get_max_bandwidth(OpusEncoder *st, opus_int32 *max_bw) { return opus_encoder_ctl(st, OPUS_GET_MAX_BANDWIDTH(max_bw)); }
|
|
int get_packet_loss_perc(OpusEncoder *st, opus_int32 *loss_perc) { return opus_encoder_ctl(st, OPUS_GET_PACKET_LOSS_PERC(loss_perc)); }
|
|
int get_sample_rate(OpusEncoder *st, opus_int32 *sample_rate) { return opus_encoder_ctl(st, OPUS_GET_SAMPLE_RATE(sample_rate)); }
|
|
int set_bitrate(OpusEncoder *st, opus_int32 bitrate) { return opus_encoder_ctl(st, OPUS_SET_BITRATE(bitrate)); }
|
|
int set_complexity(OpusEncoder *st, opus_int32 complexity) { return opus_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity)); }
|
|
int set_dtx(OpusEncoder *st, opus_int32 use_dtx) { return opus_encoder_ctl(st, OPUS_SET_DTX(use_dtx)); }
|
|
int set_inband_fec(OpusEncoder *st, opus_int32 fec) { return opus_encoder_ctl(st, OPUS_SET_INBAND_FEC(fec)); }
|
|
int set_max_bandwidth(OpusEncoder *st, opus_int32 max_bw) { return opus_encoder_ctl(st, OPUS_SET_MAX_BANDWIDTH(max_bw)); }
|
|
int set_packet_loss_perc(OpusEncoder *st, opus_int32 loss_perc) { return opus_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(loss_perc)); }
|
|
int reset_state(OpusEncoder *st) { return opus_encoder_ctl(st, OPUS_RESET_STATE); }
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
type (
|
|
Application int
|
|
Bandwidth int
|
|
Bitrate int
|
|
Error int
|
|
)
|
|
|
|
const (
|
|
// AppRestrictedLowDelay optimizes encoding for low latency applications
|
|
AppRestrictedLowDelay = Application(C.OPUS_APPLICATION_RESTRICTED_LOWDELAY)
|
|
// FullBand is 20 kHz bandpass
|
|
FullBand = Bandwidth(C.OPUS_BANDWIDTH_FULLBAND)
|
|
)
|
|
const stereo = C.int(2)
|
|
|
|
type Encoder struct {
|
|
mem []byte
|
|
out []byte
|
|
st *C.struct_OpusEncoder
|
|
}
|
|
|
|
func NewEncoder(outFq int) (*Encoder, error) {
|
|
mem := make([]byte, C.opus_encoder_get_size(stereo))
|
|
out := make([]byte, 1024)
|
|
enc := Encoder{
|
|
mem: mem,
|
|
st: (*C.OpusEncoder)(unsafe.Pointer(&mem[0])),
|
|
out: out,
|
|
}
|
|
err := unwrap(C.opus_encoder_init(enc.st, C.opus_int32(outFq), stereo, C.int(AppRestrictedLowDelay)))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("opus: initializatoin error (%v)", err)
|
|
}
|
|
_ = enc.SetMaxBandwidth(FullBand)
|
|
_ = enc.SetBitrate(96000)
|
|
_ = enc.SetComplexity(5)
|
|
|
|
return &enc, nil
|
|
}
|
|
|
|
func (e *Encoder) Reset() error { return e.ResetState() }
|
|
|
|
func (e *Encoder) Encode(pcm []int16) ([]byte, error) {
|
|
if len(pcm) == 0 {
|
|
return nil, nil
|
|
}
|
|
n := C.opus_encode(e.st, (*C.opus_int16)(&pcm[0]), C.int(len(pcm)>>1), (*C.uchar)(&e.out[0]), C.opus_int32(cap(pcm)))
|
|
err := unwrap(n)
|
|
// n = 1 is DTX
|
|
if err != nil || n == 1 {
|
|
return []byte{}, err
|
|
}
|
|
return e.out[:int(n)], nil
|
|
}
|
|
|
|
func (e *Encoder) GetInfo() string {
|
|
bitrate, _ := e.Bitrate()
|
|
complexity, _ := e.Complexity()
|
|
dtx, _ := e.DTX()
|
|
fec, _ := e.FEC()
|
|
maxBandwidth, _ := e.MaxBandwidth()
|
|
lossPercent, _ := e.PacketLossPerc()
|
|
sampleRate, _ := e.SampleRate()
|
|
return fmt.Sprintf(
|
|
"%v, Bitrate: %v bps, Complexity: %v, DTX: %v, FEC: %v, Max bandwidth: *%v, Loss%%: %v, Rate: %v Hz",
|
|
CodecVersion(), bitrate, complexity, dtx, fec, maxBandwidth, lossPercent, sampleRate,
|
|
)
|
|
}
|
|
|
|
// SampleRate returns the sample rate of the encoder.
|
|
func (e *Encoder) SampleRate() (int, error) {
|
|
var sampleRate C.opus_int32
|
|
res := C.get_sample_rate(e.st, &sampleRate)
|
|
return int(sampleRate), unwrap(res)
|
|
}
|
|
|
|
// Bitrate returns the bitrate of the encoder.
|
|
func (e *Encoder) Bitrate() (int, error) {
|
|
var bitrate C.opus_int32
|
|
res := C.get_bitrate(e.st, &bitrate)
|
|
return int(bitrate), unwrap(res)
|
|
}
|
|
|
|
// SetBitrate sets the bitrate of the encoder.
|
|
// BitrateMax / BitrateAuto can be used here.
|
|
func (e *Encoder) SetBitrate(b Bitrate) error {
|
|
return unwrap(C.set_bitrate(e.st, C.opus_int32(b)))
|
|
}
|
|
|
|
// Complexity returns the value of the complexity.
|
|
func (e *Encoder) Complexity() (int, error) {
|
|
var complexity C.opus_int32
|
|
res := C.get_complexity(e.st, &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 (e *Encoder) SetComplexity(complexity int) error {
|
|
return unwrap(C.set_complexity(e.st, C.opus_int32(complexity)))
|
|
}
|
|
|
|
// DTX says if discontinuous transmission is enabled.
|
|
func (e *Encoder) DTX() (bool, error) {
|
|
var dtx C.opus_int32
|
|
res := C.get_dtx(e.st, &dtx)
|
|
return dtx > 0, unwrap(res)
|
|
}
|
|
|
|
// SetDTX switches discontinuous transmission.
|
|
func (e *Encoder) SetDTX(dtx bool) error {
|
|
var i int
|
|
if dtx {
|
|
i = 1
|
|
}
|
|
return unwrap(C.set_dtx(e.st, C.opus_int32(i)))
|
|
}
|
|
|
|
// MaxBandwidth returns the maximum allowed bandpass value.
|
|
func (e *Encoder) MaxBandwidth() (Bandwidth, error) {
|
|
var b C.opus_int32
|
|
res := C.get_max_bandwidth(e.st, &b)
|
|
return Bandwidth(b), unwrap(res)
|
|
}
|
|
|
|
// SetMaxBandwidth sets the upper limit of the bandpass.
|
|
func (e *Encoder) SetMaxBandwidth(b Bandwidth) error {
|
|
return unwrap(C.set_max_bandwidth(e.st, C.opus_int32(b)))
|
|
}
|
|
|
|
// FEC says if forward error correction (FEC) is enabled.
|
|
func (e *Encoder) FEC() (bool, error) {
|
|
var fec C.opus_int32
|
|
res := C.get_inband_fec(e.st, &fec)
|
|
return fec > 0, unwrap(res)
|
|
}
|
|
|
|
// SetFEC switches the forward error correction (FEC).
|
|
func (e *Encoder) SetFEC(fec bool) error {
|
|
var i int
|
|
if fec {
|
|
i = 1
|
|
}
|
|
return unwrap(C.set_inband_fec(e.st, C.opus_int32(i)))
|
|
}
|
|
|
|
// PacketLossPerc returns configured packet loss percentage.
|
|
func (e *Encoder) PacketLossPerc() (int, error) {
|
|
var lossPerc C.opus_int32
|
|
res := C.get_packet_loss_perc(e.st, &lossPerc)
|
|
return int(lossPerc), unwrap(res)
|
|
}
|
|
|
|
// SetPacketLossPerc sets expected packet loss percentage.
|
|
func (e *Encoder) SetPacketLossPerc(lossPerc int) error {
|
|
return unwrap(C.set_packet_loss_perc(e.st, C.opus_int32(lossPerc)))
|
|
}
|
|
|
|
func (e *Encoder) ResetState() error { return unwrap(C.reset_state(e.st)) }
|
|
|
|
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()) }
|