Files
overlord/Overlord-Client/cmd/agent/webrtcpub/audio_opus.go
T

80 lines
1.7 KiB
Go

//go:build overlord_webrtc
package webrtcpub
import (
"sync"
"time"
"github.com/pion/webrtc/v4"
"github.com/pion/webrtc/v4/pkg/media"
"github.com/thesyncim/gopus"
)
const (
opusInputRate = 48000
opusChannels = 2
opusPacketMs = 20
opusSamplesPerFrame = opusInputRate * opusPacketMs / 1000
opusBitrate = 96000
)
type opusAudioWriter struct {
t *webrtc.TrackLocalStaticSample
encoder *gopus.Encoder
mu sync.Mutex
pcm []int16
packet []byte
}
func newOpusAudioWriter(t *webrtc.TrackLocalStaticSample) (*opusAudioWriter, error) {
encoder, err := gopus.NewEncoder(gopus.EncoderConfig{
SampleRate: opusInputRate,
Channels: opusChannels,
Application: gopus.ApplicationAudio,
})
if err != nil {
return nil, err
}
if err := encoder.SetBitrate(opusBitrate); err != nil {
return nil, err
}
if err := encoder.SetInBandFEC(gopus.InBandFECEnabled); err != nil {
return nil, err
}
return &opusAudioWriter{
t: t,
encoder: encoder,
pcm: make([]int16, 0, opusSamplesPerFrame*4),
packet: make([]byte, 4000),
}, nil
}
func (w *opusAudioWriter) WriteAudio(pcm []int16) error {
if len(pcm) == 0 {
return nil
}
w.mu.Lock()
defer w.mu.Unlock()
w.pcm = append(w.pcm, pcm...)
frameValues := opusSamplesPerFrame * opusChannels
for len(w.pcm) >= frameValues {
n, err := w.encoder.EncodeInt16(w.pcm[:frameValues], w.packet)
if err != nil {
w.pcm = w.pcm[:0]
return err
}
if n > 0 {
if err := w.t.WriteSample(media.Sample{
Data: w.packet[:n],
Duration: opusPacketMs * time.Millisecond,
}); err != nil {
w.pcm = w.pcm[:0]
return err
}
}
w.pcm = w.pcm[frameValues:]
}
return nil
}