macOS refuses capture without a usage string, and queued remote audio was still handed to the speaker after push-to-talk began. Co-authored-by: Cursor <cursoragent@cursor.com>
125 lines
3.0 KiB
Go
125 lines
3.0 KiB
Go
// Package opus encodes and decodes the reflector's 16 kHz mono frames with libopus.
|
|
package opus
|
|
|
|
/*
|
|
#cgo pkg-config: opus
|
|
#include <opus.h>
|
|
|
|
static int configure_encoder(OpusEncoder *enc) {
|
|
int err;
|
|
err = opus_encoder_ctl(enc, OPUS_SET_BITRATE(20000));
|
|
if (err < 0) return err;
|
|
err = opus_encoder_ctl(enc, OPUS_SET_VBR(1));
|
|
if (err < 0) return err;
|
|
err = opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
|
|
if (err < 0) return err;
|
|
err = opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
|
|
if (err < 0) return err;
|
|
err = opus_encoder_ctl(enc, OPUS_SET_DTX(0));
|
|
return err;
|
|
}
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
// FrameSamples is the 20 ms frame at 16 kHz, which is what the reflector carries.
|
|
const FrameSamples = 320
|
|
|
|
// Encoder produces one raw Opus packet per 20 ms frame.
|
|
type Encoder struct {
|
|
enc *C.OpusEncoder
|
|
}
|
|
|
|
// Decoder turns one raw Opus packet into 320 mono samples.
|
|
type Decoder struct {
|
|
dec *C.OpusDecoder
|
|
}
|
|
|
|
// NewEncoder returns a mono 16 kHz voice encoder at 20 kbit/s.
|
|
func NewEncoder() (*Encoder, error) {
|
|
var err C.int
|
|
enc := C.opus_encoder_create(16000, 1, C.OPUS_APPLICATION_AUDIO, &err)
|
|
if err < 0 || enc == nil {
|
|
return nil, fmt.Errorf("opus encoder %d", int(err))
|
|
}
|
|
if c := C.configure_encoder(enc); c < 0 {
|
|
C.opus_encoder_destroy(enc)
|
|
return nil, fmt.Errorf("opus encoder setup %d", int(c))
|
|
}
|
|
return &Encoder{enc: enc}, nil
|
|
}
|
|
|
|
// Encode encodes exactly 320 samples.
|
|
func (e *Encoder) Encode(pcm []int16) ([]byte, error) {
|
|
if len(pcm) != FrameSamples {
|
|
return nil, fmt.Errorf("opus frame is %d samples", len(pcm))
|
|
}
|
|
out := make([]byte, 4000)
|
|
n := C.opus_encode(
|
|
e.enc,
|
|
(*C.opus_int16)(unsafe.Pointer(&pcm[0])),
|
|
FrameSamples,
|
|
(*C.uchar)(unsafe.Pointer(&out[0])),
|
|
C.opus_int32(len(out)),
|
|
)
|
|
if n < 0 {
|
|
return nil, fmt.Errorf("opus encode %d", int(n))
|
|
}
|
|
return append([]byte(nil), out[:n]...), nil
|
|
}
|
|
|
|
// Close releases the encoder.
|
|
func (e *Encoder) Close() {
|
|
if e == nil || e.enc == nil {
|
|
return
|
|
}
|
|
C.opus_encoder_destroy(e.enc)
|
|
e.enc = nil
|
|
}
|
|
|
|
// NewDecoder returns a mono 16 kHz decoder.
|
|
func NewDecoder() (*Decoder, error) {
|
|
var err C.int
|
|
dec := C.opus_decoder_create(16000, 1, &err)
|
|
if err < 0 || dec == nil {
|
|
return nil, fmt.Errorf("opus decoder %d", int(err))
|
|
}
|
|
return &Decoder{dec: dec}, nil
|
|
}
|
|
|
|
// Decode decodes one packet into 320 samples.
|
|
func (d *Decoder) Decode(packet []byte) ([]int16, error) {
|
|
if len(packet) == 0 {
|
|
return nil, fmt.Errorf("empty opus packet")
|
|
}
|
|
pcm := make([]int16, FrameSamples)
|
|
n := C.opus_decode(
|
|
d.dec,
|
|
(*C.uchar)(unsafe.Pointer(&packet[0])),
|
|
C.opus_int32(len(packet)),
|
|
(*C.opus_int16)(unsafe.Pointer(&pcm[0])),
|
|
FrameSamples,
|
|
0,
|
|
)
|
|
if n < 0 {
|
|
return nil, fmt.Errorf("opus decode %d", int(n))
|
|
}
|
|
if int(n) != FrameSamples {
|
|
return nil, fmt.Errorf("opus decode returned %d samples", int(n))
|
|
}
|
|
return pcm, nil
|
|
}
|
|
|
|
// Close releases the decoder.
|
|
func (d *Decoder) Close() {
|
|
if d == nil || d.dec == nil {
|
|
return
|
|
}
|
|
C.opus_decoder_destroy(d.dec)
|
|
d.dec = nil
|
|
}
|