audio: skip seeking only when the error is ErrUnsupported

Updates #3193
This commit is contained in:
Hajime Hoshi 2025-02-12 02:14:42 +09:00
parent e33b9cf20e
commit 6cc5ed14fc
5 changed files with 35 additions and 10 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -15,6 +15,8 @@
package vorbis
import (
"errors"
"fmt"
"io"
"math"
@ -23,12 +25,16 @@ 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
seekable bool
fbuf []float32
pos int64
}
@ -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

View File

@ -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
}