diff --git a/pkg/media/pcm.go b/pkg/media/pcm.go index ae2c5009..93b6a2c2 100644 --- a/pkg/media/pcm.go +++ b/pkg/media/pcm.go @@ -38,6 +38,8 @@ func PlayAudio[T any](w Writer[T], sampleDur time.Duration, frames []T) error { type PCM16Sample []int16 +type PCM16Writer = Writer[PCM16Sample] + type MediaSampleWriter interface { WriteSample(sample media.Sample) error } diff --git a/pkg/media/ulaw/g711.go b/pkg/media/ulaw/g711.go index f39ee470..d6abfdc6 100644 --- a/pkg/media/ulaw/g711.go +++ b/pkg/media/ulaw/g711.go @@ -101,6 +101,16 @@ func EncodeUlaw(lpcm []int16) []byte { return out } +// EncodeUlawTo encodes 16bit LPCM data to an existing G711 u-law PCM buffer. +func EncodeUlawTo(out []byte, lpcm []int16) { + if len(out) != len(lpcm) { + panic("short buffer") + } + for i := range lpcm { + out[i] = EncodeUlawFrame(lpcm[i]) + } +} + // EncodeUlawFrame encodes a 16bit LPCM frame to G711 u-law PCM func EncodeUlawFrame(frame int16) uint8 { /* @@ -127,14 +137,24 @@ func EncodeUlawFrame(frame int16) uint8 { } // DecodeUlaw decodes u-law PCM data to 16bit PCM. -func DecodeUlaw(pcm []byte) []int16 { - out := make([]int16, len(pcm)) - for i := 0; i < len(pcm); i++ { - out[i] = ulaw2lpcm[pcm[i]] +func DecodeUlaw(ulaw []byte) []int16 { + out := make([]int16, len(ulaw)) + for i := 0; i < len(ulaw); i++ { + out[i] = ulaw2lpcm[ulaw[i]] } return out } +// DecodeUlawTo decodes u-law PCM data to an existing 16bit PCM buffer. +func DecodeUlawTo(out []int16, ulaw []byte) { + if len(out) != len(ulaw) { + panic("short buffer") + } + for i := 0; i < len(ulaw); i++ { + out[i] = ulaw2lpcm[ulaw[i]] + } +} + // DecodeUlawFrame decodes a u-law PCM frame to 16bit LPCM func DecodeUlawFrame(frame uint8) int16 { return ulaw2lpcm[frame] diff --git a/pkg/media/ulaw/ulaw.go b/pkg/media/ulaw/ulaw.go index a35e6d80..c9a9112e 100644 --- a/pkg/media/ulaw/ulaw.go +++ b/pkg/media/ulaw/ulaw.go @@ -28,17 +28,42 @@ func (s *Sample) Encode(data media.PCM16Sample) { *s = EncodeUlaw(data) } -func Decode(w media.Writer[media.PCM16Sample]) media.Writer[Sample] { - return media.WriterFunc[Sample](func(in Sample) error { - out := in.Decode() - return w.WriteSample(out) - }) -} - -func Encode(w media.Writer[Sample]) media.Writer[media.PCM16Sample] { - return media.WriterFunc[media.PCM16Sample](func(in media.PCM16Sample) error { - var s Sample - s.Encode(in) - return w.WriteSample(s) - }) +type Writer = media.Writer[Sample] + +type Decoder struct { + w media.PCM16Writer + buf media.PCM16Sample +} + +func (d *Decoder) WriteSample(in Sample) error { + if len(in) >= cap(d.buf) { + d.buf = make(media.PCM16Sample, len(in)) + } else { + d.buf = d.buf[:len(in)] + } + DecodeUlawTo(d.buf, in) + return d.w.WriteSample(d.buf) +} + +func Decode(w media.PCM16Writer) Writer { + return &Decoder{w: w} +} + +type Encoder struct { + w Writer + buf Sample +} + +func (e *Encoder) WriteSample(in media.PCM16Sample) error { + if len(in) >= cap(e.buf) { + e.buf = make(Sample, len(in)) + } else { + e.buf = e.buf[:len(in)] + } + EncodeUlawTo(e.buf, in) + return e.w.WriteSample(e.buf) +} + +func Encode(w Writer) media.PCM16Writer { + return &Encoder{w: w} }