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 package convert
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -83,7 +84,7 @@ func (r *float32BytesReader) Read(buf []byte) (int, error) {
func (r *float32BytesReader) Seek(offset int64, whence int) (int64, error) { func (r *float32BytesReader) Seek(offset int64, whence int) (int64, error) {
s, ok := r.r.(io.Seeker) s, ok := r.r.(io.Seeker)
if !ok { 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.i16Buf = r.i16Buf[:0]
r.eof = false r.eof = false

View File

@ -15,6 +15,7 @@
package convert package convert
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -307,7 +308,7 @@ func (r *Resampling) Read(b []byte) (int, error) {
func (r *Resampling) Seek(offset int64, whence int) (int64, error) { func (r *Resampling) Seek(offset int64, whence int) (int64, error) {
if _, ok := r.source.(io.Seeker); !ok { 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 r.eof = false

View File

@ -15,6 +15,7 @@
package audio package audio
import ( import (
"errors"
"io" "io"
"runtime" "runtime"
"sync" "sync"
@ -408,6 +409,9 @@ func newTimeStream(r io.Reader, seekable bool, sampleRate int, bitDepthInBytes i
// Get the current position of the source. // Get the current position of the source.
pos, err := s.r.(io.Seeker).Seek(0, io.SeekCurrent) pos, err := s.r.(io.Seeker).Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
if !errors.Is(err, errors.ErrUnsupported) {
return nil, err
}
// Ignore the error, as the undelrying source might not support Seek (#3192). // 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. // This happens when vorbis.Decode* is used, as vorbis.Stream is io.Seeker whichever the underlying source is.
pos = 0 pos = 0

View File

@ -15,6 +15,8 @@
package vorbis package vorbis
import ( import (
"errors"
"fmt"
"io" "io"
"math" "math"
@ -23,14 +25,18 @@ import (
var _ io.ReadSeeker = (*float32BytesReadSeeker)(nil) var _ io.ReadSeeker = (*float32BytesReadSeeker)(nil)
func newFloat32BytesReadSeeker(r *oggvorbis.Reader) *float32BytesReadSeeker { func newFloat32BytesReadSeeker(r *oggvorbis.Reader, seekable bool) *float32BytesReadSeeker {
return &float32BytesReadSeeker{r: r} return &float32BytesReadSeeker{
r: r,
seekable: seekable,
}
} }
type float32BytesReadSeeker struct { type float32BytesReadSeeker struct {
r *oggvorbis.Reader r *oggvorbis.Reader
fbuf []float32 seekable bool
pos int64 fbuf []float32
pos int64
} }
func (r *float32BytesReadSeeker) Read(buf []byte) (int, error) { 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) { 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 sampleSize := int64(r.r.Channels()) * 4
offset = offset / sampleSize * sampleSize offset = offset / sampleSize * sampleSize

View File

@ -16,6 +16,7 @@
package vorbis package vorbis
import ( import (
"errors"
"fmt" "fmt"
"io" "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()) 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 length := r.Length() * int64(r.Channels()) * bitDepthInBytesFloat32
if r.Channels() == 1 { if r.Channels() == 1 {
s = convert.NewStereoF32(s, true) s = convert.NewStereoF32(s, true)
@ -91,7 +93,7 @@ func DecodeF32(src io.Reader) (*Stream, error) {
sampleRate: r.SampleRate(), sampleRate: r.SampleRate(),
} }
// Read some data for performance (#297). // 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 { if _, err := stream.Read(make([]byte, 65536)); err != nil && err != io.EOF {
return nil, err return nil, err
} }
@ -104,6 +106,7 @@ func DecodeF32(src io.Reader) (*Stream, error) {
type i16Stream struct { type i16Stream struct {
posInBytes int64 posInBytes int64
seekable bool
vorbisReader *oggvorbis.Reader vorbisReader *oggvorbis.Reader
i16Reader io.Reader i16Reader io.Reader
} }
@ -128,6 +131,10 @@ retry:
} }
func (s *i16Stream) Seek(offset int64, whence int) (int64, error) { 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) next := int64(0)
switch whence { switch whence {
case io.SeekStart: 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()) return nil, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", r.Channels())
} }
_, seekable := in.(io.Seeker)
s := &i16Stream{ s := &i16Stream{
seekable: seekable,
posInBytes: 0, posInBytes: 0,
vorbisReader: r, vorbisReader: r,
} }
// Read some data for performance (#297). // 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 { if _, err := s.Read(make([]byte, 65536)); err != nil && err != io.EOF {
return nil, err return nil, err
} }