🎉 live server seems to be working now
This commit is contained in:
60
third_party/sendspin-go/internal/server/opus_encoder.go
vendored
Normal file
60
third_party/sendspin-go/internal/server/opus_encoder.go
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// ABOUTME: Opus audio encoder for bandwidth-efficient streaming
|
||||
// ABOUTME: Wraps libopus to encode PCM audio to Opus format
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"gopkg.in/hraban/opus.v2"
|
||||
)
|
||||
|
||||
// OpusEncoder wraps the Opus encoder
|
||||
type OpusEncoder struct {
|
||||
encoder *opus.Encoder
|
||||
sampleRate int
|
||||
channels int
|
||||
frameSize int // samples per channel per frame
|
||||
}
|
||||
|
||||
// NewOpusEncoder creates a new Opus encoder.
|
||||
// frameSize is in samples per channel (e.g., 960 for 20ms at 48kHz).
|
||||
func NewOpusEncoder(sampleRate, channels, frameSize int) (*OpusEncoder, error) {
|
||||
// AppAudio mode tunes the encoder for full-bandwidth music rather than speech
|
||||
encoder, err := opus.NewEncoder(sampleRate, channels, opus.AppAudio)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create opus encoder: %w", err)
|
||||
}
|
||||
|
||||
// 128 kbps per channel — aggressive enough for transparent music quality
|
||||
bitrate := 128000 * channels
|
||||
if err := encoder.SetBitrate(bitrate); err != nil {
|
||||
log.Printf("Warning: Failed to set Opus bitrate: %v", err)
|
||||
}
|
||||
|
||||
return &OpusEncoder{
|
||||
encoder: encoder,
|
||||
sampleRate: sampleRate,
|
||||
channels: channels,
|
||||
frameSize: frameSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Encode encodes PCM samples to Opus.
|
||||
// Input: []int16 interleaved samples; output: single Opus packet.
|
||||
func (e *OpusEncoder) Encode(pcm []int16) ([]byte, error) {
|
||||
// Opus spec maximum packet size is 4000 bytes
|
||||
output := make([]byte, 4000)
|
||||
|
||||
n, err := e.encoder.Encode(pcm, output)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opus encode failed: %w", err)
|
||||
}
|
||||
|
||||
return output[:n], nil
|
||||
}
|
||||
|
||||
// Close is a no-op; opus.Encoder has no Close method.
|
||||
func (e *OpusEncoder) Close() error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user