Skip to content

Commit

Permalink
🐛 Fix reader slow than decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
tosone committed Aug 1, 2023
1 parent d22286f commit 2b0fd3d
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 6 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ on:
jobs:
builder:
name: builder
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
matrix:
go: ["1.16", "1.15"]
go: ["1.20", "1.19", "1.18", "1.17", "1.16", "1.15"]
steps:
- name: Checkout branch
uses: actions/checkout@v2
Expand Down
23 changes: 19 additions & 4 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type Decoder struct {
Channels int
Kbps int
Layer int

originalEof bool // if the original reader is EOF, set this to true
}

// BufferSize Decoded data buffer size.
Expand Down Expand Up @@ -80,9 +82,11 @@ func NewDecoder(reader io.Reader) (dec *Decoder, err error) {
dec.data = append(dec.data, data[:n]...)
dec.readerLocker.Unlock()
if err == io.EOF {
dec.originalEof = true
break
}
if err != nil {
dec.originalEof = true
break
}
}
Expand Down Expand Up @@ -152,12 +156,23 @@ func (dec *Decoder) Started() (channel chan bool) {

// Read read the raw stream
func (dec *Decoder) Read(data []byte) (n int, err error) {
for {
select {
case <-dec.context.Done(): // if the decoder is stopped, then here should return EOF
err = io.EOF
return
default:
}
if len(dec.data) == 0 && len(dec.decodedData) == 0 && dec.originalEof {
err = io.EOF
return
} else if len(dec.decodedData) > 0 {
break
}
<-time.After(WaitForDataDuration)
}
dec.decoderLocker.Lock()
defer dec.decoderLocker.Unlock()
if len(dec.decodedData) == 0 {
err = io.EOF
return
}
n = copy(data, dec.decodedData[:])
dec.decodedData = dec.decodedData[n:]
return
Expand Down
60 changes: 60 additions & 0 deletions decode_issue18_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package minimp3

import (
"bytes"
"io"
"os"
"testing"
"time"
)

// TestIssue18DelayPutData ...
func TestIssue18DelayPutData(t *testing.T) {
reader, writer := io.Pipe()
dec, err := NewDecoder(reader)
if err != nil {
t.Errorf("NewDecoder failed: %v", err)
}
go func() {
time.Sleep(3 * time.Second)
file, err := os.ReadFile("test.mp3")

Check failure on line 20 in decode_issue18_test.go

View workflow job for this annotation

GitHub Actions / builder (1.15)

undefined: os.ReadFile
if err != nil {
t.Errorf("open file failed: %v", err)
}
_, err = io.Copy(writer, bytes.NewReader(file))
if err != nil {
t.Errorf("copy mp3 data to pipe failed: %v", err)
}
writer.Close() // nolint: errcheck
}()
// seems like the 'dec.Started' is unnecessary here
data, err := io.ReadAll(dec)

Check failure on line 31 in decode_issue18_test.go

View workflow job for this annotation

GitHub Actions / builder (1.15)

undefined: io.ReadAll
if err != nil {
t.Errorf("read the whole decoded data failed: %v", err)
}
if len(data) != 44928 {
t.Errorf("decode mp3 file failed, real is 44928, but got %d", len(data))
}
}

// TestIssue18GracefulExit ...
func TestIssue18GracefulExit(t *testing.T) {
reader, writer := io.Pipe()
dec, err := NewDecoder(reader)
if err != nil {
t.Errorf("NewDecoder failed: %v", err)
}
go func() {
time.Sleep(3 * time.Second)
writer.Close() // nolint: errcheck
}()
// seems like the 'dec.Started' is necessary here
// if the Decoder input reader is closed, then the Decoder.Read will be returned
data, err := io.ReadAll(dec)

Check failure on line 53 in decode_issue18_test.go

View workflow job for this annotation

GitHub Actions / builder (1.15)

undefined: io.ReadAll
if err != nil {
t.Errorf("read the whole decoded data failed: %v", err)
}
if len(data) != 0 {
t.Errorf("graceful exit read something data")
}
}

0 comments on commit 2b0fd3d

Please sign in to comment.