From 019c946c55648b4e8daf13d7efa02ee9fb397682 Mon Sep 17 00:00:00 2001 From: Daniel Ponte Date: Sun, 4 Aug 2024 23:32:46 -0400 Subject: [PATCH] config --- cmd/calls/audio.go | 69 ++++++++------ cmd/calls/main.go | 1 - go.mod | 10 +- go.sum | 34 ++++--- internal/mpg123/decode.go | 107 --------------------- internal/mpg123/mpg123.go | 189 -------------------------------------- 6 files changed, 66 insertions(+), 344 deletions(-) delete mode 100644 internal/mpg123/decode.go delete mode 100644 internal/mpg123/mpg123.go diff --git a/cmd/calls/audio.go b/cmd/calls/audio.go index d30021b..cfd9223 100644 --- a/cmd/calls/audio.go +++ b/cmd/calls/audio.go @@ -1,19 +1,15 @@ package main import ( - "bytes" "fmt" - "io" "time" - "github.com/gopxl/beep" - "github.com/gopxl/beep/mp3" - "github.com/gopxl/beep/speaker" - "github.com/gopxl/beep/wav" + "github.com/hajimehoshi/oto" + "github.com/tosone/minimp3" ) type Player struct { - rate beep.SampleRate + ctx *oto.Context } func NewPlayer() *Player { @@ -22,38 +18,53 @@ func NewPlayer() *Player { return p } -func (p *Player) initSpeaker(rate beep.SampleRate) { - if p.rate != rate { - speaker.Init(rate, rate.N(time.Second/10)) +func (p *Player) initOto(samp, channels int) error { + if p.ctx != nil { + return nil } + + var err error + if p.ctx, err = oto.NewContext(samp, channels, 2, 1024); err != nil { + return err + } + + return nil +} + +func (p *Player) playMP3(audio []byte) error { + var dec *minimp3.Decoder + var data []byte + var err error + if dec, data, err = minimp3.DecodeFull(audio); err != nil { + return err + } + + err = p.initOto(dec.SampleRate, dec.Channels) + if err != nil { + return err + } + + var player = p.ctx.NewPlayer() + player.Write(data) + + <-time.After(time.Second) + + dec.Close() + if err = player.Close(); err != nil { + return err + } + + return nil } func (p *Player) Play(audio []byte, mimeType string) error { - var streamer beep.StreamCloser - var err error - var format beep.Format - r := io.NopCloser(bytes.NewBuffer(audio)) switch mimeType { case "audio/mpeg": - streamer, format, err = mp3.Decode(r) - if err != nil { - return err - } - defer streamer.Close() - p.initSpeaker(format.SampleRate) - + return p.playMP3(audio) case "audio/wav": - streamer, format, err = wav.Decode(r) - if err != nil { - return err - } - defer streamer.Close() - p.initSpeaker(format.SampleRate) default: return fmt.Errorf("unknown format %s", mimeType) } - speaker.Play(streamer) - return nil } diff --git a/cmd/calls/main.go b/cmd/calls/main.go index e4f1064..2bab1db 100644 --- a/cmd/calls/main.go +++ b/cmd/calls/main.go @@ -105,7 +105,6 @@ func main() { err := play.Play(v.Call.Audio, v.Call.AudioType) if err != nil { log.Println(err) - os.WriteFile("failed.mp3", v.Call.Audio, 0644) } case *pb.Message_Notification: log.Println(v.Notification.Msg) diff --git a/go.mod b/go.mod index 1eec3d5..d167f7d 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,12 @@ require ( github.com/google/uuid v1.4.0 github.com/gopxl/beep v1.4.1 github.com/gorilla/websocket v1.5.3 + github.com/hajimehoshi/oto v1.0.1 github.com/jackc/pgx/v5 v5.6.0 + github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/spf13/cobra v1.8.1 + github.com/tosone/minimp3 v1.0.2 golang.org/x/crypto v0.21.0 golang.org/x/term v0.18.0 google.golang.org/protobuf v1.33.0 @@ -25,10 +28,7 @@ require ( github.com/ajg/form v1.5.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/ebitengine/oto/v3 v3.1.0 // indirect - github.com/ebitengine/purego v0.7.1 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/hajimehoshi/go-mp3 v0.3.4 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -45,11 +45,13 @@ require ( github.com/lestrrat-go/option v1.0.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect go.uber.org/atomic v1.7.0 // indirect + golang.org/x/exp/shiny v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/image v0.14.0 // indirect + golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index 9a32e49..5ee4ce7 100644 --- a/go.sum +++ b/go.sum @@ -24,10 +24,6 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/ebitengine/oto/v3 v3.1.0 h1:9tChG6rizyeR2w3vsygTTTVVJ9QMMyu00m2yBOCch6U= -github.com/ebitengine/oto/v3 v3.1.0/go.mod h1:IK1QTnlfZK2GIB6ziyECm433hAdTaPpOsGMLhEyEGTg= -github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= -github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= @@ -53,9 +49,8 @@ github.com/gopxl/beep v1.4.1 h1:WqNs9RsDAhG9M3khMyc1FaVY50dTdxG/6S6a3qsUHqE= github.com/gopxl/beep v1.4.1/go.mod h1:A1dmiUkuY8kxsvcNJNUBIEcchmiP6eUyCHSxpXl0YO0= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hajimehoshi/go-mp3 v0.3.4 h1:NUP7pBYH8OguP4diaTZ9wJbUbk3tC0KlfzsEpWmYj68= -github.com/hajimehoshi/go-mp3 v0.3.4/go.mod h1:fRtZraRFcWb0pu7ok0LqyFhCUrPeMsGRSVop0eemFmo= -github.com/hajimehoshi/oto/v2 v2.3.1/go.mod h1:seWLbgHH7AyUMYKfKYT9pg7PhUu9/SisyJvNTT+ASQo= +github.com/hajimehoshi/oto v1.0.1 h1:8AMnq0Yr2YmzaiqTg/k1Yzd6IygUGk2we9nmjgbgPn4= +github.com/hajimehoshi/oto v1.0.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -104,8 +99,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e h1:s2RNOM/IGdY0Y6qfTeUKhDawdHDpK9RGBdx80qN4Ttw= -github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -129,17 +122,29 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tosone/minimp3 v1.0.2 h1:htFE2EbP7Y4CJ8KGW9c55tKWRpzv9kXkEmCYGxFzVjA= +github.com/tosone/minimp3 v1.0.2/go.mod h1:N6vjknGR7PboMTyJVhe/7RHNQiIc0jWZxFKlSWdfzwc= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp/shiny v0.0.0-20240719175910-8a7402abbf56 h1:8jM66xzUJjNInw31Y8bic4AYSLVChztDRT93+kmofUY= +golang.org/x/exp/shiny v0.0.0-20240719175910-8a7402abbf56/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= +golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -147,10 +152,11 @@ golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= diff --git a/internal/mpg123/decode.go b/internal/mpg123/decode.go deleted file mode 100644 index 6b5830d..0000000 --- a/internal/mpg123/decode.go +++ /dev/null @@ -1,107 +0,0 @@ -// Package mp3 implements audio data decoding in MP3 format. -package mpg123 - -import ( - "fmt" - "io" - - "github.com/gopxl/beep" - "github.com/pkg/errors" -) - -const ( - gomp3NumChannels = 2 - gomp3Precision = 2 - gomp3BytesPerFrame = gomp3NumChannels * gomp3Precision -) - -// Decode takes a ReadCloser containing audio data in MP3 format and returns a StreamSeekCloser, -// which streams that audio. The Seek method will panic if rc is not io.Seeker. -// -// Do not close the supplied ReadSeekCloser, instead, use the Close method of the returned -// StreamSeekCloser when you want to release the resources. -func Decode(rc io.ReadCloser) (s beep.StreamCloser, format beep.Format, err error) { - defer func() { - if err != nil { - err = errors.Wrap(err, "mp3") - } - }() - d, err := NewDecoder("") - if err != nil { - return nil, beep.Format{}, err - } - - d.Format(8000, 2, ENC_FLOAT_64) - err = d.OpenFeed() - if err != nil { - return nil, beep.Format{}, err - } - // get 4k of file - buf := make([]byte, 4096) - for { - n, err := rc.Read(buf) - if err != nil && err != io.EOF { - return nil, beep.Format{}, err - } - if n == 0 { - break - } - err = d.Feed(buf) - if err != nil { - return nil, beep.Format{}, err - } - } - rate, channels, enc := d.GetFormat() - fmt.Printf("rate %d chan %d enc %d\n", rate, channels, enc) - - format = beep.Format{ - SampleRate: beep.SampleRate(8000), - NumChannels: 2, - Precision: 4, - } - return &decoder{rc, d, format, 0, nil}, format, nil -} - -type decoder struct { - closer io.Closer - d *Decoder - f beep.Format - pos int - err error -} - -func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) { - if d.err != nil { - return 0, false - } - var tmp [gomp3BytesPerFrame]byte - for i := range samples { - dn, err := d.d.Read(tmp[:]) - if dn == len(tmp) { - samples[i], _ = d.f.DecodeSigned(tmp[:]) - d.pos += dn - n++ - ok = true - } - if err == io.EOF { - break - } - if err != nil { - d.err = errors.Wrap(err, "mp3") - break - } - } - return n, ok -} - -func (d *decoder) Err() error { - return d.err -} - -func (d *decoder) Close() error { - err := d.closer.Close() - if err != nil { - return errors.Wrap(err, "mp3") - } - return d.d.Close() -} diff --git a/internal/mpg123/mpg123.go b/internal/mpg123/mpg123.go deleted file mode 100644 index 0d8211d..0000000 --- a/internal/mpg123/mpg123.go +++ /dev/null @@ -1,189 +0,0 @@ -// mpg123.go contains all bindings to the C library - -package mpg123 - -/* -#include -#include -#cgo LDFLAGS: -lmpg123 - -int do_mpg123_read(mpg123_handle *mh, void *outmemory, size_t outmemsize, size_t *done) { - return mpg123_read(mh, outmemory, outmemsize, done); -} -*/ -import "C" - -import ( - "errors" - "fmt" - "os" - "unsafe" -) - -var EOF = errors.New("EOF") - -// All output encoding formats supported by mpg123 -const ( - ENC_8 = C.MPG123_ENC_8 - ENC_16 = C.MPG123_ENC_16 - ENC_24 = C.MPG123_ENC_24 - ENC_32 = C.MPG123_ENC_32 - ENC_SIGNED = C.MPG123_ENC_SIGNED - ENC_FLOAT = C.MPG123_ENC_FLOAT - ENC_SIGNED_8 = C.MPG123_ENC_SIGNED_8 - ENC_UNSIGNED_8 = C.MPG123_ENC_UNSIGNED_8 - ENC_ULAW_8 = C.MPG123_ENC_ULAW_8 - ENC_ALAW_8 = C.MPG123_ENC_ALAW_8 - ENC_SIGNED_16 = C.MPG123_ENC_SIGNED_16 - ENC_UNSIGNED_16 = C.MPG123_ENC_UNSIGNED_16 - ENC_SIGNED_24 = C.MPG123_ENC_SIGNED_24 - ENC_UNSIGNED_24 = C.MPG123_ENC_UNSIGNED_24 - ENC_SIGNED_32 = C.MPG123_ENC_SIGNED_32 - ENC_UNSIGNED_32 = C.MPG123_ENC_UNSIGNED_32 - ENC_FLOAT_32 = C.MPG123_ENC_FLOAT_32 - ENC_FLOAT_64 = C.MPG123_ENC_FLOAT_64 - ENC_ANY = C.MPG123_ENC_ANY -) - -// Contains a handle for and mpg123 decoder instance -type Decoder struct { - handle *C.mpg123_handle -} - -// init initializes the mpg123 library when package is loaded -func init() { - err := C.mpg123_init() - if err != C.MPG123_OK { - //return fmt.Errorf("error initializing mpg123") - panic("failed to initialize mpg123") - } - //return nil -} - -/////////////////////////// -// DECODER INSTANCE CODE // -/////////////////////////// - -// NewDecoder creates a new mpg123 decoder instance -func NewDecoder(decoder string) (*Decoder, error) { - var err C.int - var mh *C.mpg123_handle - if decoder != "" { - mh = C.mpg123_new(nil, &err) - } else { - cdecoder := C.CString(decoder) - defer C.free(unsafe.Pointer(cdecoder)) - mh = C.mpg123_new(cdecoder, &err) - } - if mh == nil { - errstring := C.mpg123_plain_strerror(err) - err := C.GoString(errstring) - C.free(unsafe.Pointer(errstring)) - return nil, fmt.Errorf("error initializing mpg123 decoder: %s", err) - } - dec := new(Decoder) - dec.handle = mh - return dec, nil -} - -// Delete frees an mpg123 decoder instance -func (d *Decoder) Delete() { - C.mpg123_delete(d.handle) -} - -// returns a string containing the most recent error message corresponding to -// an mpg123 decoder instance -func (d *Decoder) strerror() string { - return C.GoString(C.mpg123_strerror(d.handle)) -} - -//////////////////////// -// OUTPUT FORMAT CODE // -//////////////////////// - -// FormatNone disables all decoder output formats (used to specifying supported formats) -func (d *Decoder) FormatNone() { - C.mpg123_format_none(d.handle) -} - -// FromatAll enables all decoder output formats (this is the default setting) -func (d *Decoder) FormatAll() { - C.mpg123_format_all(d.handle) -} - -// GetFormat returns current output format -func (d *Decoder) GetFormat() (rate int64, channels int, encoding int) { - var cRate C.long - var cChans, cEnc C.int - C.mpg123_getformat(d.handle, &cRate, &cChans, &cEnc) - return int64(cRate), int(cChans), int(cEnc) -} - -// Format sets the audio output format for decoder -func (d *Decoder) Format(rate int64, channels int, encodings int) { - C.mpg123_format(d.handle, C.long(rate), C.int(channels), C.int(encodings)) -} - -///////////////////////////// -// INPUT AND DECODING CODE // -///////////////////////////// - -// Open initializes a decoder for an mp3 file using a filename -func (d *Decoder) Open(file string) error { - cfile := C.CString(file) - defer C.free(unsafe.Pointer(cfile)) - err := C.mpg123_open(d.handle, cfile) - if err != C.MPG123_OK { - return fmt.Errorf("error opening %s: %s", file, d.strerror()) - } - return nil -} - -// OpenFile binds to an fd from an open *os.File for decoding -func (d *Decoder) OpenFile(f *os.File) error { - err := C.mpg123_open_fd(d.handle, C.int(f.Fd())) - if err != C.MPG123_OK { - return fmt.Errorf("error attaching file: %s", d.strerror()) - } - return nil -} - -// OpenFeed prepares a decoder for direct feeding via Feed(..) -func (d *Decoder) OpenFeed() error { - err := C.mpg123_open_feed(d.handle) - if err != C.MPG123_OK { - return fmt.Errorf("mpg123 error: %s", d.strerror()) - } - return nil -} - -// Close closes an input file if one was opened by mpg123 -func (d *Decoder) Close() error { - err := C.mpg123_close(d.handle) - if err != C.MPG123_OK { - return fmt.Errorf("mpg123 error: %s", d.strerror()) - } - return nil -} - -// Read decodes data and into buf and returns number of bytes decoded. -func (d *Decoder) Read(buf []byte) (int, error) { - var done C.size_t - err := C.do_mpg123_read(d.handle, (unsafe.Pointer)(&buf[0]), C.size_t(len(buf)), &done) - if err == C.MPG123_DONE { - return int(done), EOF - } - if err != C.MPG123_OK { - return int(done), fmt.Errorf("mpg123 error: %s", d.strerror()) - } - return int(done), nil -} - -// Feed provides data bytes into the decoder -func (d *Decoder) Feed(buf []byte) error { - err := C.mpg123_feed(d.handle, (*C.uchar)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))) - if err != C.MPG123_OK { - return fmt.Errorf("mpg123 error: %s", d.strerror()) - } - return nil -}