-
Notifications
You must be signed in to change notification settings - Fork 135
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
Seek
after Reset
might not work as expected
#172
Comments
I agree with your comments in the old issue, things will not be safe if you seek while Oto is playing and that is fine. What is not expected though is that it is not safe to seek even when the player is paused and has all its buffers cleared. //Assume a paused player
player.Pause()
//This is NOT safe because 'rseeker' is being used by player
player.Reset()
rseeker.Seek()
//The following is safe to do ONCE. But after that we don't know when we can do it again :)
//So this is 'safe'
rseeker.Seek()
player.Reset()
//This is NOT safe because the second seek will collide with the first reset
rseeker.Seek()
player.Reset()
rseeker.Seek()
player.Reset() Because of the behavior I mentioned earlier we can't provide users with an API that (for example) controls audio position safely, because they will only be able to call it one time haha. Some things we can do:
I prefer the second one (and I think its easy to implement? One mutex?), but I am worried about there being large latency before Oto stops pre-reading. All sound control APIs will have large latency each time they want to seek or do some simple processing. So to fix the latency problem, along with point 2 I believe it would be good to be able to control how much pre-read is done. Perhaps a function similar to Hope this is a good summary of everything. |
Another possibility is to let a player implement |
So the player will handle synchronization internally right? That sounds nice. Just make sure that the player handles seek calls as soon as possible. We don't want it to finish all reads first (e.g. to fill a buffer), that will be too much latency. For the implementation, maybe something like the wrapper I made here is enough? When someone gives you a Reader/ReadSeeker wrap internally then let the player use the wrapped version. |
The player's Seek will invoke Reset internally so the seeking will happen immediately. Read will still happen, but does this cause so much latency?
You will no longer need locks as you don't have to call Read and Seek on the source stream and instead Oto will call them. |
So when I call We both do video game stuff and so am sure you know how much a millisecond is worth ;) Why I mentioned locks is because lets say pre-read will do 10 reads then stop. Without locks Oto will do reset->10 reads->seek, but if we lock we can do reset->1 read->seek->continue pre-reading. Basically as soon as seek has a chance we run it so the main app can continue its thing. Sorry if you meant something else. |
If you really care about this latency, you should adjust the buffer size by SetBufferSize. Does this make sense? |
Maybe I missed something, but when I was testing before pre-reading was not following For example, I set the buffer to a lot more than enough to read till Is this expected behavior? Edit: Wanted to ask, what's the benefit of allowing pre-read to fully finish before doing a seek? |
Oto tries to fill the buffer with the buffer size, so the amount should depend on the buffer size. |
Prereading just after Seek might not be needed but this simplifies the implementation (the reading loop can restart immediately after the player can read the source again by resetting). I'm not sure this is really a problem to you. Can we revisit this issue when you find an actual latency issue that cannot be solved even with SetBufferSize? |
That's what I expect, but its not what I see with Reset. I had the tada sound, which in total is 451584 bytes. I set the buffer to double that but still it didn't read till EOF. You can reproduce with this: //Play tada
player.Play()
for player.IsPlaying() {
time.Sleep(time.Millisecond)
}
// mp3.Length() reports 451584, so we use double that
player.(oto.BufferSizeSetter).SetBufferSize(451584 * 2)
fw.Seek(0, io.SeekStart)
player.Reset()
//Let Oto finish pre-read
time.Sleep(5*time.Second)
//Check how much was read. You will notice its a small amount, and the amount is different every run?!
pos, _ := fw.Seek(0, io.SeekCurrent)
println("Amount read:", pos) Is this correct behavior?
Definitely! |
Let me check the actual reading size later. Thanks! |
Please take a look at |
Thank you! This looks like a great start! So the only (minor) thing we have left is this: #172 (comment) Perhaps we should move this to a new issue? Something like "Pre-read loads undefined number of bytes and doesn't fill buffer"? |
Yes, please, thanks! |
#171 (comment)
Oto internally reads immediately after
Reset
, soSeek
afterReset
might be risky./CC @bloeys
The text was updated successfully, but these errors were encountered: