首次推送
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
//go:build android
|
||||
|
||||
package teamspeak
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I${SRCDIR}/../../android/app/src/main/cpp/third_party/opus/include
|
||||
#cgo android,arm64 LDFLAGS: -L${SRCDIR}/.opus/lib/arm64-v8a -l:libopus.a -lm
|
||||
#cgo android,arm LDFLAGS: -L${SRCDIR}/.opus/lib/armeabi-v7a -l:libopus.a -lm
|
||||
#cgo android,386 LDFLAGS: -L${SRCDIR}/.opus/lib/x86 -l:libopus.a -lm
|
||||
#cgo android,amd64 LDFLAGS: -L${SRCDIR}/.opus/lib/x86_64 -l:libopus.a -lm
|
||||
#include "opus.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var errOpusDecoderReleased = errors.New("opus decoder has been released")
|
||||
|
||||
type opusVoiceDecoderFactory struct{}
|
||||
|
||||
type opusVoiceDecoder struct {
|
||||
mu sync.Mutex
|
||||
decoder *C.OpusDecoder
|
||||
channels int
|
||||
}
|
||||
|
||||
func newPlatformVoiceDecoderFactory() voiceDecoderFactory { return opusVoiceDecoderFactory{} }
|
||||
|
||||
func (opusVoiceDecoderFactory) NewvoiceDecoder(_ int, codec int) (voiceDecoder, error) {
|
||||
if codec != 4 && codec != 5 {
|
||||
return nil, fmt.Errorf("unsupported TeamSpeak voice codec %d", codec)
|
||||
}
|
||||
channels := voiceCodecChannels(codec)
|
||||
var opusErr C.int
|
||||
decoder := C.opus_decoder_create(C.opus_int32(receiveSampleRate), C.int(channels), &opusErr)
|
||||
if decoder == nil || opusErr != C.OPUS_OK {
|
||||
return nil, fmt.Errorf("opus_decoder_create: %d", int(opusErr))
|
||||
}
|
||||
return &opusVoiceDecoder{decoder: decoder, channels: channels}, nil
|
||||
}
|
||||
|
||||
func (d *opusVoiceDecoder) Decode(packet []byte) ([]int16, error) {
|
||||
if len(packet) == 0 {
|
||||
return nil, errors.New("empty Opus packet")
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.decoder == nil {
|
||||
return nil, errOpusDecoderReleased
|
||||
}
|
||||
pcm := make([]int16, receiveMaxDecodeSamplesPerChannel*d.channels)
|
||||
decoded := C.opus_decode(
|
||||
d.decoder,
|
||||
(*C.uchar)(unsafe.Pointer(&packet[0])),
|
||||
C.opus_int32(len(packet)),
|
||||
(*C.opus_int16)(unsafe.Pointer(&pcm[0])),
|
||||
C.int(receiveMaxDecodeSamplesPerChannel),
|
||||
0,
|
||||
)
|
||||
runtime.KeepAlive(packet)
|
||||
return decodedPCM(pcm, decoded, d.channels)
|
||||
}
|
||||
|
||||
func (d *opusVoiceDecoder) DecodeLost() ([]int16, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.decoder == nil {
|
||||
return nil, errOpusDecoderReleased
|
||||
}
|
||||
pcm := make([]int16, receiveMaxDecodeSamplesPerChannel*d.channels)
|
||||
decoded := C.opus_decode(
|
||||
d.decoder,
|
||||
nil,
|
||||
0,
|
||||
(*C.opus_int16)(unsafe.Pointer(&pcm[0])),
|
||||
C.int(receiveMaxDecodeSamplesPerChannel),
|
||||
0,
|
||||
)
|
||||
return decodedPCM(pcm, decoded, d.channels)
|
||||
}
|
||||
|
||||
func (d *opusVoiceDecoder) Release() {
|
||||
d.mu.Lock()
|
||||
decoder := d.decoder
|
||||
d.decoder = nil
|
||||
d.mu.Unlock()
|
||||
if decoder != nil {
|
||||
C.opus_decoder_destroy(decoder)
|
||||
}
|
||||
}
|
||||
|
||||
func decodedPCM(pcm []int16, decoded C.int, channels int) ([]int16, error) {
|
||||
if decoded < 0 {
|
||||
return nil, fmt.Errorf("opus_decode: %d", int(decoded))
|
||||
}
|
||||
perChannel := int(decoded)
|
||||
decodedSamples := perChannel * channels
|
||||
if perChannel > receiveMaxDecodeSamplesPerChannel || decodedSamples > len(pcm) {
|
||||
return nil, fmt.Errorf("opus_decode returned %d samples/channel, buffer has %d samples for %d channels", perChannel, len(pcm), channels)
|
||||
}
|
||||
return normalizeDecodedPCM(pcm[:decodedSamples], channels), nil
|
||||
}
|
||||
Reference in New Issue
Block a user