// Package opus encodes and decodes the reflector's 16 kHz mono frames with libopus. package opus /* #cgo pkg-config: opus #include 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 }