Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abort function for io.Copy #25

Closed
wants to merge 3 commits into from
Closed

Abort function for io.Copy #25

wants to merge 3 commits into from

Conversation

kemokemo
Copy link

@kemokemo kemokemo commented Aug 2, 2017

Hello @hajimehoshi !

I was moved by the method of playing music by combining go-mp3 and oto library with io.Copy. here
I would like to create a mechanism like jukebox using this technique and incorporate it into my game using ebiten.

So I searched for a way to interrupt music play by interrupting io.Copy and implemented.
Here is an example of an interruption sample written based on your sample.

Would you please give me comments or advice?

@hajimehoshi
Copy link
Member

hajimehoshi commented Aug 2, 2017

Hi Kemo-kemo-san!

As far as I know, there is no feasible way to suspend copying of io.Copy.

Instead, how about making a 'abortable' copy function? The (pseudo) code would be:

func AbortableCopy(w io.Writer, r io.Reader, abortCh <-chan struct{}) (int, error) {
  type readResult struct {
    buf []uint8
    err error
  }
  readCh := make(chan, readResult)
  abortReadCh := make(chan struct{})
  go func() {
    buf := make([]uint8, 4096)
  readLoop:
    for {
      n, err := r.Read(buf)
      r := ReadResult{buf[:n], nil}
      if err != nil && err != io.EOF {
        r.err = err
      }
      select {
      case readCh <- r:
      case <-abortReadCh:
        break readLoop:
      }
      if err != nil {
        break
      }
    }
    close(readCh)
  }()
  written := 0
loop:
  for {
    select {
    case buf, ok := <-readCh:
      if !ok {
        readCh = nil
        break loop
      }
      n, err := w.Write(buf)
      if err != nil {
        return err
      }
      written += n
    case <-abortCh:
      close(readAbortCh)
      return written, nil
    }
  }
  return written, nil
}

Note that I've not tested that code and there might be something wrong in that.

EDIT: Added readAbortCh to stop the reader goroutine.

@hajimehoshi
Copy link
Member

Hmm, that code has a bug: writtenBytes is not accurate when aborting. I don't think it is not hard to fix though.

@hajimehoshi
Copy link
Member

I would like to create a mechanism like jukebox using this technique and incorporate it into my game using ebiten.

Sorry I missed this comment. If you are using Ebiten, you can use Player's Pause. http://godoc.org/github.com/hajimehoshi/ebiten/audio#Player.Pause Doesn't this work?

@kemokemo
Copy link
Author

kemokemo commented Aug 3, 2017

Hi hajime-hoshi-san!

I understood that the Copy function should be able to Abort. Thank you so much for the code of AbortableCopy! And now, I am convinced that ebiten's Player is the best choice for me.
I'm sorry to have disturbed you....

I'll try to implement the jukebox in my ebiten game!

@kemokemo kemokemo closed this Aug 3, 2017
@hajimehoshi
Copy link
Member

No problem. Thank you for using Oto and Ebiten!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants