403 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			403 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright © Go Opus Authors (see AUTHORS file)
 | |
| //
 | |
| // License for use of this code is detailed in the LICENSE file
 | |
| 
 | |
| package opus
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| /*
 | |
| #cgo pkg-config: opus
 | |
| #include <opus.h>
 | |
| 
 | |
| int
 | |
| bridge_encoder_set_dtx(OpusEncoder *st, opus_int32 use_dtx)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_SET_DTX(use_dtx));
 | |
| }
 | |
| 
 | |
| int
 | |
| bridge_encoder_get_dtx(OpusEncoder *st, opus_int32 *dtx)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_GET_DTX(dtx));
 | |
| }
 | |
| 
 | |
| int
 | |
| bridge_encoder_get_in_dtx(OpusEncoder *st, opus_int32 *in_dtx)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_GET_IN_DTX(in_dtx));
 | |
| }
 | |
| 
 | |
| 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_get_bitrate(OpusEncoder *st, opus_int32 *bitrate)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_GET_BITRATE(bitrate));
 | |
| }
 | |
| 
 | |
| int
 | |
| bridge_encoder_set_complexity(OpusEncoder *st, opus_int32 complexity)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity));
 | |
| }
 | |
| 
 | |
| int
 | |
| bridge_encoder_get_complexity(OpusEncoder *st, opus_int32 *complexity)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_GET_COMPLEXITY(complexity));
 | |
| }
 | |
| 
 | |
| 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_get_max_bandwidth(OpusEncoder *st, opus_int32 *max_bw)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_GET_MAX_BANDWIDTH(max_bw));
 | |
| }
 | |
| 
 | |
| int
 | |
| bridge_encoder_set_inband_fec(OpusEncoder *st, opus_int32 fec)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_SET_INBAND_FEC(fec));
 | |
| }
 | |
| 
 | |
| int
 | |
| bridge_encoder_get_inband_fec(OpusEncoder *st, opus_int32 *fec)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_GET_INBAND_FEC(fec));
 | |
| }
 | |
| 
 | |
| 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));
 | |
| }
 | |
| 
 | |
| 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_reset_state(OpusEncoder *st)
 | |
| {
 | |
| 	return opus_encoder_ctl(st, OPUS_RESET_STATE);
 | |
| }
 | |
| 
 | |
| */
 | |
| import "C"
 | |
| 
 | |
| type Bandwidth int
 | |
| 
 | |
| const (
 | |
| 	// 4 kHz passband
 | |
| 	Narrowband = Bandwidth(C.OPUS_BANDWIDTH_NARROWBAND)
 | |
| 	// 6 kHz passband
 | |
| 	Mediumband = Bandwidth(C.OPUS_BANDWIDTH_MEDIUMBAND)
 | |
| 	// 8 kHz passband
 | |
| 	Wideband = Bandwidth(C.OPUS_BANDWIDTH_WIDEBAND)
 | |
| 	// 12 kHz passband
 | |
| 	SuperWideband = Bandwidth(C.OPUS_BANDWIDTH_SUPERWIDEBAND)
 | |
| 	// 20 kHz passband
 | |
| 	Fullband = Bandwidth(C.OPUS_BANDWIDTH_FULLBAND)
 | |
| )
 | |
| 
 | |
| var errEncUninitialized = fmt.Errorf("opus encoder uninitialized")
 | |
| 
 | |
| // Encoder contains the state of an Opus encoder for libopus.
 | |
| type Encoder struct {
 | |
| 	p        *C.struct_OpusEncoder
 | |
| 	channels int
 | |
| 	// Memory for the encoder struct allocated on the Go heap to allow Go GC to
 | |
| 	// manage it (and obviate need to free())
 | |
| 	mem []byte
 | |
| }
 | |
| 
 | |
| // 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) {
 | |
| 	var enc Encoder
 | |
| 	err := enc.Init(sample_rate, channels, application)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &enc, nil
 | |
| }
 | |
| 
 | |
| // 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 {
 | |
| 	if enc.p != nil {
 | |
| 		return fmt.Errorf("opus encoder already initialized")
 | |
| 	}
 | |
| 	if channels != 1 && channels != 2 {
 | |
| 		return fmt.Errorf("Number of channels must be 1 or 2: %d", channels)
 | |
| 	}
 | |
| 	size := C.opus_encoder_get_size(C.int(channels))
 | |
| 	enc.channels = channels
 | |
| 	enc.mem = make([]byte, size)
 | |
| 	enc.p = (*C.OpusEncoder)(unsafe.Pointer(&enc.mem[0]))
 | |
| 	errno := int(C.opus_encoder_init(
 | |
| 		enc.p,
 | |
| 		C.opus_int32(sample_rate),
 | |
| 		C.int(channels),
 | |
| 		C.int(application)))
 | |
| 	if errno != 0 {
 | |
| 		return Error(int(errno))
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Encode raw PCM data and store the result in the supplied buffer. On success,
 | |
| // returns the number of bytes used up by the encoded data.
 | |
| func (enc *Encoder) Encode(pcm []int16, data []byte) (int, error) {
 | |
| 	if enc.p == nil {
 | |
| 		return 0, errEncUninitialized
 | |
| 	}
 | |
| 	if len(pcm) == 0 {
 | |
| 		return 0, fmt.Errorf("opus: no data supplied")
 | |
| 	}
 | |
| 	if len(data) == 0 {
 | |
| 		return 0, fmt.Errorf("opus: no target buffer")
 | |
| 	}
 | |
| 	// libopus talks about samples as 1 sample containing multiple channels. So
 | |
| 	// e.g. 20 samples of 2-channel data is actually 40 raw data points.
 | |
| 	if len(pcm)%enc.channels != 0 {
 | |
| 		return 0, fmt.Errorf("opus: input buffer length must be multiple of channels")
 | |
| 	}
 | |
| 	samples := len(pcm) / enc.channels
 | |
| 	n := int(C.opus_encode(
 | |
| 		enc.p,
 | |
| 		(*C.opus_int16)(&pcm[0]),
 | |
| 		C.int(samples),
 | |
| 		(*C.uchar)(&data[0]),
 | |
| 		C.opus_int32(cap(data))))
 | |
| 	if n < 0 {
 | |
| 		return 0, Error(n)
 | |
| 	}
 | |
| 	return n, nil
 | |
| }
 | |
| 
 | |
| // Encode raw PCM data and store the result in the supplied buffer. On success,
 | |
| // returns the number of bytes used up by the encoded data.
 | |
| func (enc *Encoder) EncodeFloat32(pcm []float32, data []byte) (int, error) {
 | |
| 	if enc.p == nil {
 | |
| 		return 0, errEncUninitialized
 | |
| 	}
 | |
| 	if len(pcm) == 0 {
 | |
| 		return 0, fmt.Errorf("opus: no data supplied")
 | |
| 	}
 | |
| 	if len(data) == 0 {
 | |
| 		return 0, fmt.Errorf("opus: no target buffer")
 | |
| 	}
 | |
| 	if len(pcm)%enc.channels != 0 {
 | |
| 		return 0, fmt.Errorf("opus: input buffer length must be multiple of channels")
 | |
| 	}
 | |
| 	samples := len(pcm) / enc.channels
 | |
| 	n := int(C.opus_encode_float(
 | |
| 		enc.p,
 | |
| 		(*C.float)(&pcm[0]),
 | |
| 		C.int(samples),
 | |
| 		(*C.uchar)(&data[0]),
 | |
| 		C.opus_int32(cap(data))))
 | |
| 	if n < 0 {
 | |
| 		return 0, Error(n)
 | |
| 	}
 | |
| 	return n, nil
 | |
| }
 | |
| 
 | |
| // SetDTX configures the encoder's use of discontinuous transmission (DTX).
 | |
| func (enc *Encoder) SetDTX(dtx bool) error {
 | |
| 	i := 0
 | |
| 	if dtx {
 | |
| 		i = 1
 | |
| 	}
 | |
| 	res := C.bridge_encoder_set_dtx(enc.p, C.opus_int32(i))
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return Error(res)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // DTX reports whether this encoder is configured to use discontinuous
 | |
| // transmission (DTX).
 | |
| func (enc *Encoder) DTX() (bool, error) {
 | |
| 	var dtx C.opus_int32
 | |
| 	res := C.bridge_encoder_get_dtx(enc.p, &dtx)
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return false, Error(res)
 | |
| 	}
 | |
| 	return dtx != 0, nil
 | |
| }
 | |
| 
 | |
| // InDTX returns whether the last encoded frame was either a comfort noise update
 | |
| // during DTX or not encoded because of DTX.
 | |
| func (enc *Encoder) InDTX() (bool, error) {
 | |
| 	var inDTX C.opus_int32
 | |
| 	res := C.bridge_encoder_get_in_dtx(enc.p, &inDTX)
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return false, Error(res)
 | |
| 	}
 | |
| 	return inDTX != 0, nil
 | |
| }
 | |
| 
 | |
| // SampleRate returns the encoder sample rate in Hz.
 | |
| func (enc *Encoder) SampleRate() (int, error) {
 | |
| 	var sr C.opus_int32
 | |
| 	res := C.bridge_encoder_get_sample_rate(enc.p, &sr)
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return 0, Error(res)
 | |
| 	}
 | |
| 	return int(sr), nil
 | |
| }
 | |
| 
 | |
| // 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
 | |
| }
 | |
| 
 | |
| // SetBitrateToAuto will allow the encoder to automatically set the bitrate
 | |
| func (enc *Encoder) SetBitrateToAuto() error {
 | |
| 	res := C.bridge_encoder_set_bitrate(enc.p, C.opus_int32(C.OPUS_AUTO))
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return Error(res)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // SetBitrateToMax causes the encoder to use as much rate as it can. This can be
 | |
| // useful for controlling the rate by adjusting the output buffer size.
 | |
| func (enc *Encoder) SetBitrateToMax() error {
 | |
| 	res := C.bridge_encoder_set_bitrate(enc.p, C.opus_int32(C.OPUS_BITRATE_MAX))
 | |
| 	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 computational complexity used by 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 Bandwidth) 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() (Bandwidth, 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 Bandwidth(maxBw), nil
 | |
| }
 | |
| 
 | |
| // SetInBandFEC configures the encoder's use of inband forward error
 | |
| // correction (FEC)
 | |
| func (enc *Encoder) SetInBandFEC(fec bool) error {
 | |
| 	i := 0
 | |
| 	if fec {
 | |
| 		i = 1
 | |
| 	}
 | |
| 	res := C.bridge_encoder_set_inband_fec(enc.p, C.opus_int32(i))
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return Error(res)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // InBandFEC gets the encoder's configured inband forward error correction (FEC)
 | |
| func (enc *Encoder) InBandFEC() (bool, error) {
 | |
| 	var fec C.opus_int32
 | |
| 	res := C.bridge_encoder_get_inband_fec(enc.p, &fec)
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return false, Error(res)
 | |
| 	}
 | |
| 	return fec != 0, nil
 | |
| }
 | |
| 
 | |
| // SetPacketLossPerc configures the encoder's expected packet loss percentage.
 | |
| func (enc *Encoder) SetPacketLossPerc(lossPerc int) error {
 | |
| 	res := C.bridge_encoder_set_packet_loss_perc(enc.p, C.opus_int32(lossPerc))
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return Error(res)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // PacketLossPerc gets the encoder's configured packet loss percentage.
 | |
| func (enc *Encoder) PacketLossPerc() (int, error) {
 | |
| 	var lossPerc C.opus_int32
 | |
| 	res := C.bridge_encoder_get_packet_loss_perc(enc.p, &lossPerc)
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return 0, Error(res)
 | |
| 	}
 | |
| 	return int(lossPerc), nil
 | |
| }
 | |
| 
 | |
| // Reset resets the codec state to be equivalent to a freshly initialized state.
 | |
| func (enc *Encoder) Reset() error {
 | |
| 	res := C.bridge_encoder_reset_state(enc.p)
 | |
| 	if res != C.OPUS_OK {
 | |
| 		return Error(res)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |