diff --git a/audio/internal/convert/float32.go b/audio/internal/convert/float32.go index c41897c0b..08ff57350 100644 --- a/audio/internal/convert/float32.go +++ b/audio/internal/convert/float32.go @@ -15,6 +15,7 @@ package convert import ( + "errors" "fmt" "io" "math" @@ -83,7 +84,7 @@ func (r *float32BytesReader) Read(buf []byte) (int, error) { func (r *float32BytesReader) Seek(offset int64, whence int) (int64, error) { s, ok := r.r.(io.Seeker) if !ok { - return 0, fmt.Errorf("float32: the source must be io.Seeker when seeking but not") + return 0, fmt.Errorf("float32: the source must be io.Seeker when seeking but not: %w", errors.ErrUnsupported) } r.i16Buf = r.i16Buf[:0] r.eof = false diff --git a/audio/internal/convert/resampling.go b/audio/internal/convert/resampling.go index c52a6ac03..ba96c02cb 100644 --- a/audio/internal/convert/resampling.go +++ b/audio/internal/convert/resampling.go @@ -15,6 +15,7 @@ package convert import ( + "errors" "fmt" "io" "math" @@ -307,7 +308,7 @@ func (r *Resampling) Read(b []byte) (int, error) { func (r *Resampling) Seek(offset int64, whence int) (int64, error) { if _, ok := r.source.(io.Seeker); !ok { - return 0, fmt.Errorf("convert: source must be io.Seeker") + return 0, fmt.Errorf("convert: source must be io.Seeker: %w", errors.ErrUnsupported) } r.eof = false diff --git a/audio/player.go b/audio/player.go index 37ab868f6..d9fcce4bc 100644 --- a/audio/player.go +++ b/audio/player.go @@ -15,6 +15,7 @@ package audio import ( + "errors" "io" "runtime" "sync" @@ -408,6 +409,9 @@ func newTimeStream(r io.Reader, seekable bool, sampleRate int, bitDepthInBytes i // Get the current position of the source. pos, err := s.r.(io.Seeker).Seek(0, io.SeekCurrent) if err != nil { + if !errors.Is(err, errors.ErrUnsupported) { + return nil, err + } // Ignore the error, as the undelrying source might not support Seek (#3192). // This happens when vorbis.Decode* is used, as vorbis.Stream is io.Seeker whichever the underlying source is. pos = 0 diff --git a/audio/vorbis/float32.go b/audio/vorbis/float32.go index 05a98425f..0ac5b847c 100644 --- a/audio/vorbis/float32.go +++ b/audio/vorbis/float32.go @@ -15,6 +15,8 @@ package vorbis import ( + "errors" + "fmt" "io" "math" @@ -23,14 +25,18 @@ import ( var _ io.ReadSeeker = (*float32BytesReadSeeker)(nil) -func newFloat32BytesReadSeeker(r *oggvorbis.Reader) *float32BytesReadSeeker { - return &float32BytesReadSeeker{r: r} +func newFloat32BytesReadSeeker(r *oggvorbis.Reader, seekable bool) *float32BytesReadSeeker { + return &float32BytesReadSeeker{ + r: r, + seekable: seekable, + } } type float32BytesReadSeeker struct { - r *oggvorbis.Reader - fbuf []float32 - pos int64 + r *oggvorbis.Reader + seekable bool + fbuf []float32 + pos int64 } func (r *float32BytesReadSeeker) Read(buf []byte) (int, error) { @@ -62,6 +68,10 @@ func (r *float32BytesReadSeeker) Read(buf []byte) (int, error) { } func (r *float32BytesReadSeeker) Seek(offset int64, whence int) (int64, error) { + if !r.seekable { + return 0, fmt.Errorf("vorbis: the source must be io.Seeker but not: %w", errors.ErrUnsupported) + } + sampleSize := int64(r.r.Channels()) * 4 offset = offset / sampleSize * sampleSize diff --git a/audio/vorbis/vorbis.go b/audio/vorbis/vorbis.go index 077fbb703..6248262ad 100644 --- a/audio/vorbis/vorbis.go +++ b/audio/vorbis/vorbis.go @@ -16,6 +16,7 @@ package vorbis import ( + "errors" "fmt" "io" @@ -78,7 +79,8 @@ func DecodeF32(src io.Reader) (*Stream, error) { return nil, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", r.Channels()) } - var s io.ReadSeeker = newFloat32BytesReadSeeker(r) + _, seekable := src.(io.Seeker) + var s io.ReadSeeker = newFloat32BytesReadSeeker(r, seekable) length := r.Length() * int64(r.Channels()) * bitDepthInBytesFloat32 if r.Channels() == 1 { s = convert.NewStereoF32(s, true) @@ -91,7 +93,7 @@ func DecodeF32(src io.Reader) (*Stream, error) { sampleRate: r.SampleRate(), } // Read some data for performance (#297). - if _, ok := src.(io.Seeker); ok { + if seekable { if _, err := stream.Read(make([]byte, 65536)); err != nil && err != io.EOF { return nil, err } @@ -104,6 +106,7 @@ func DecodeF32(src io.Reader) (*Stream, error) { type i16Stream struct { posInBytes int64 + seekable bool vorbisReader *oggvorbis.Reader i16Reader io.Reader } @@ -128,6 +131,10 @@ retry: } func (s *i16Stream) Seek(offset int64, whence int) (int64, error) { + if !s.seekable { + return 0, fmt.Errorf("vorbis: the source must be io.Seeker but not: %w", errors.ErrUnsupported) + } + next := int64(0) switch whence { case io.SeekStart: @@ -162,12 +169,14 @@ func decodeI16(in io.Reader) (*i16Stream, error) { return nil, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", r.Channels()) } + _, seekable := in.(io.Seeker) s := &i16Stream{ + seekable: seekable, posInBytes: 0, vorbisReader: r, } // Read some data for performance (#297). - if _, ok := in.(io.Seeker); ok { + if seekable { if _, err := s.Read(make([]byte, 65536)); err != nil && err != io.EOF { return nil, err }