Skip to content

Commit

Permalink
audio: skip seeking only when the error is ErrUnsupported
Browse files Browse the repository at this point in the history
Updates #3193
  • Loading branch information
hajimehoshi committed Feb 11, 2025
1 parent e33b9cf commit 6cc5ed1
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 10 deletions.
3 changes: 2 additions & 1 deletion audio/internal/convert/float32.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package convert

import (
"errors"
"fmt"
"io"
"math"
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion audio/internal/convert/resampling.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package convert

import (
"errors"
"fmt"
"io"
"math"
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions audio/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package audio

import (
"errors"
"io"
"runtime"
"sync"
Expand Down Expand Up @@ -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
Expand Down
20 changes: 15 additions & 5 deletions audio/vorbis/float32.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package vorbis

import (
"errors"
"fmt"
"io"
"math"

Expand All @@ -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) {
Expand Down Expand Up @@ -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

Expand Down
15 changes: 12 additions & 3 deletions audio/vorbis/vorbis.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package vorbis

import (
"errors"
"fmt"
"io"

Expand Down Expand Up @@ -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)
Expand All @@ -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
}
Expand All @@ -104,6 +106,7 @@ func DecodeF32(src io.Reader) (*Stream, error) {

type i16Stream struct {
posInBytes int64
seekable bool
vorbisReader *oggvorbis.Reader
i16Reader io.Reader
}
Expand All @@ -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:
Expand Down Expand Up @@ -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
}
Expand Down

0 comments on commit 6cc5ed1

Please sign in to comment.