package opus import ( "errors" "fmt" "math" "github.com/lherman-cs/opus" "github.com/pion/mediadevices/pkg/codec" "github.com/pion/mediadevices/pkg/io/audio" "github.com/pion/mediadevices/pkg/prop" "github.com/pion/mediadevices/pkg/wave" "github.com/pion/mediadevices/pkg/wave/mixer" ) type encoder struct { engine *opus.Encoder inBuff wave.Audio reader audio.Reader } var latencies = []float64{5, 10, 20, 40, 60} func newEncoder(r audio.Reader, p prop.Media, params Params) (codec.ReadCloser, error) { if p.SampleRate == 0 { return nil, fmt.Errorf("opus: inProp.SampleRate is required") } if p.Latency == 0 { p.Latency = 20 } if params.BitRate == 0 { params.BitRate = 32000 } if params.ChannelMixer == nil { params.ChannelMixer = &mixer.MonoMixer{} } // Select the nearest supported latency var targetLatency float64 // TODO: use p.Latency.Milliseconds() after Go 1.12 EOL latencyInMS := float64(p.Latency.Nanoseconds() / 1000000) nearestDist := math.Inf(+1) for _, latency := range latencies { dist := math.Abs(latency - latencyInMS) if dist >= nearestDist { break } nearestDist = dist targetLatency = latency } channels := p.ChannelCount engine, err := opus.NewEncoder(p.SampleRate, channels, opus.AppVoIP) if err != nil { return nil, err } if err := engine.SetBitrate(params.BitRate); err != nil { return nil, err } rMix := audio.NewChannelMixer(channels, params.ChannelMixer) rBuf := audio.NewBuffer(int(targetLatency * float64(p.SampleRate) / 1000)) e := encoder{ engine: engine, reader: rMix(rBuf(r)), } return &e, nil } func (e *encoder) Read(p []byte) (int, error) { buff, err := e.reader.Read() if err != nil { return 0, err } switch b := buff.(type) { case *wave.Int16Interleaved: n, err := e.engine.EncodeBytes(b.Data, p, false) if err != nil { return n, err } return n, nil case *wave.Float32Interleaved: n, err := e.engine.EncodeBytes(b.Data, p, true) if err != nil { return n, err } return n, nil default: return 0, errors.New("unknown type of audio buffer") } } func (e *encoder) SetBitRate(b int) error { panic("SetBitRate is not implemented") } func (e *encoder) ForceKeyFrame() error { panic("ForceKeyFrame is not implemented") } func (e *encoder) Close() error { return nil }