diff --git a/audio/internal/cbackend/player.go b/audio/internal/cbackend/player.go index d633402af..c1cb3387b 100644 --- a/audio/internal/cbackend/player.go +++ b/audio/internal/cbackend/player.go @@ -21,6 +21,7 @@ package cbackend import ( + "errors" "io" "runtime" "sync" @@ -250,6 +251,34 @@ func (p *playerImpl) Pause() { p.state = playerPaused } +func (p *Player) Seek(offset int64, whence int) (int64, error) { + return p.p.Seek(offset, whence) +} + +func (p *playerImpl) Seek(offset int64, whence int) (int64, error) { + p.m.Lock() + defer p.m.Unlock() + + if p.state == playerPlay { + defer p.playImpl() + } + + // Reset the internal buffer. + p.resetImpl() + + // Check if the source implements io.Seeker. + s, ok := p.src.(io.Seeker) + if !ok { + return 0, errors.New("cbackend: the source must implement io.Seeker") + } + newOffset, err := s.Seek(offset, whence) + if err != nil { + return newOffset, err + } + + return newOffset, nil +} + func (p *Player) Reset() { p.p.Reset() } diff --git a/audio/player.go b/audio/player.go index e91890c50..c201b2ca4 100644 --- a/audio/player.go +++ b/audio/player.go @@ -33,6 +33,7 @@ type player interface { UnplayedBufferSize() int Err() error SetBufferSize(bufferSize int) + io.Seeker io.Closer } @@ -267,13 +268,11 @@ func (p *playerImpl) Seek(offset time.Duration) error { return err } - if p.player.IsPlaying() { - defer func() { - p.player.Play() - }() + pos := p.stream.timeDurationToPos(offset) + if _, err := p.player.Seek(pos, io.SeekStart); err != nil { + return err } - p.player.Reset() - return p.stream.Seek(offset) + return nil } func (p *playerImpl) Err() error { @@ -338,7 +337,25 @@ func (s *timeStream) Read(buf []byte) (int, error) { return n, err } -func (s *timeStream) Seek(offset time.Duration) error { +func (s *timeStream) Seek(offset int64, whence int) (int64, error) { + s.m.Lock() + defer s.m.Unlock() + + seeker, ok := s.r.(io.Seeker) + if !ok { + // TODO: Should this return an error? + panic("audio: the source must be io.Seeker when seeking but not") + } + pos, err := seeker.Seek(offset, whence) + if err != nil { + return pos, err + } + + s.pos = pos + return pos, nil +} + +func (s *timeStream) timeDurationToPos(offset time.Duration) int64 { s.m.Lock() defer s.m.Unlock() @@ -348,17 +365,7 @@ func (s *timeStream) Seek(offset time.Duration) error { o -= o % bytesPerSample o += s.pos % bytesPerSample - seeker, ok := s.r.(io.Seeker) - if !ok { - panic("audio: the source must be io.Seeker when seeking but not") - } - pos, err := seeker.Seek(o, io.SeekStart) - if err != nil { - return err - } - - s.pos = pos - return nil + return o } func (s *timeStream) Current() int64 { diff --git a/go.mod b/go.mod index fdf76b934..3e2ae4392 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/hajimehoshi/bitmapfont/v2 v2.2.0 github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41 github.com/hajimehoshi/go-mp3 v0.3.3 - github.com/hajimehoshi/oto/v2 v2.2.0-alpha.3.0.20220627134823-65dbd988610c + github.com/hajimehoshi/oto/v2 v2.2.0-alpha.3.0.20220630171212-19c3101d3014 github.com/jakecoffman/cp v1.2.0 github.com/jezek/xgb v1.0.1 github.com/jfreymuth/oggvorbis v1.0.3 diff --git a/go.sum b/go.sum index e0976c99a..b5a1b79fe 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,8 @@ github.com/hajimehoshi/go-mp3 v0.3.3 h1:cWnfRdpye2m9ElSoVqneYRcpt/l3ijttgjMeQh+r github.com/hajimehoshi/go-mp3 v0.3.3/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/oto v0.6.1 h1:7cJz/zRQV4aJvMSSRqzN2TImoVVMpE0BCY4nrNJaDOM= github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= -github.com/hajimehoshi/oto/v2 v2.2.0-alpha.3.0.20220627134823-65dbd988610c h1:hHMvizeDtTgaLcvh78CvzVi82yrYkUJsr81vfRBeeg0= -github.com/hajimehoshi/oto/v2 v2.2.0-alpha.3.0.20220627134823-65dbd988610c/go.mod h1:9i0oYbpJ8BhVGkXDKdXKfFthX1JUNfXjeTp944W8TGM= +github.com/hajimehoshi/oto/v2 v2.2.0-alpha.3.0.20220630171212-19c3101d3014 h1:CzwUmBzSfGTCrUXwnuhEbZf3QFzr1qYolBEYE4VxvLI= +github.com/hajimehoshi/oto/v2 v2.2.0-alpha.3.0.20220630171212-19c3101d3014/go.mod h1:9i0oYbpJ8BhVGkXDKdXKfFthX1JUNfXjeTp944W8TGM= github.com/jakecoffman/cp v1.2.0 h1:ZdCFqHglNYJibiIeRvpAktJ7ZuWUnh0cnBsZNKVbY3A= github.com/jakecoffman/cp v1.2.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg= github.com/jezek/xgb v1.0.1 h1:YUGhxps0aR7J2Xplbs23OHnV1mWaxFVcOl9b+1RQkt8=