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

Add Context.SetReadBufferSize. #160

Closed
wants to merge 1 commit into from
Closed

Conversation

bigfarts
Copy link

This is useful for cases where you may need to sync visuals with audio.

The use case I have is with mGBA, where the buffer size needs to be consistent between the emulator and the system sound driver. The automatic sizing from Oto is too large and causes audio delays :(

This is useful for cases where you may need to sync visuals with audio.
@hajimehoshi
Copy link
Member

Thanks, but this kind of change requires discussions before the implementation...

@hajimehoshi
Copy link
Member

For a real-time streaming, I think it is possible by

  1. Writing not-full data when Read is called
  2. Adjusting the writing pace by seeing UnplayedBufferSize

and actually Tinne (in Ebiten Discord) created a proof of concept.

What do you think?

@bigfarts
Copy link
Author

Sorry for dropping this code like this, I just wanted a starting point to discuss around!

I'm not sure if the suggested solution works, or I'm not sure that I fully understand it.

With mGBA it works something like:

  1. Audio is produced by the emulator.
  2. The player thread consumes the audio and must play it immediately.
  3. The renderer thread is synchronized with the player thread and must display the next frame at roughly the same time the player plays.

I don't think it's possible to adjust the writing pace in this case, because the received audio has to play immediately and the buffer size is fixed. I can return the written buffer size from the io.Reader.Read method, but Oto will cause a significant delay.

@hajimehoshi
Copy link
Member

hajimehoshi commented Mar 23, 2022

I don't think it's possible to adjust the writing pace in this case, because the received audio has to play immediately and the buffer size is fixed.

The io.Reader as an audio source doesn't always have to fill the given buffer 100%. So you can pass the data that is generated in real-time pace. You can adjust the pace with UnplayedBufferSize.

So, it works, but I admit this is not an elegant solution. It is in theory possible to adjust the amount of writing with UnplayedBufferSize, but this would not be a long-term solution.

I'm OK to give a way to adjust the buffer size. My thoughts are:

  • Adjusting the buffer size for each player would be ideal rather than the global context buffer size. Do you think this works?
  • I don't want Oto to guarantee the behavior when the buffer size is adjusted. So even if glitches happen, this is the user's responsibility.
  • Does a small amount of buffers work on browsers well?

Thanks,

@bigfarts
Copy link
Author

I think that works for me -- do you have a code example for adjusting the pace wth UnplayedBufferSize actually, in case I'm missing something here?

Adjusting the buffer size at the per-player level works for me. I'm not sure what the behavior on browsers is, unfortunately.

@tinne26
Copy link

tinne26 commented Mar 23, 2022

This is reference code I used for ebiten. It's admittedly not ideal, and it's ebiten, not oto directly, but it should help you get the idea. I don't know if in oto it's possible to call UnplayedBufferSize inside Read itself. And also, notice that the ebiten version returns a duration, not the number of bytes directly.

It's possible to work without unsafe, but I had this in hand. You can go at ~16ms latency with this, which should be at least acceptable for your use-case.

Notice that this relies on ebiten's v2.3.0-alpha.5.0.20220321170451-d6596369abc4.

@hajimehoshi
Copy link
Member

I'll try to implement SetBufferSize for each player tomorrow.

@bigfarts Thank you for suggesting the prototype and explaining the situation, and @tinne26 thank you for the discussion in Discord!

@bigfarts
Copy link
Author

Thank you so much! I'll close this PR.

@bigfarts bigfarts closed this Mar 23, 2022
@hajimehoshi
Copy link
Member

@bigfarts Could you try 585752a? Unfortunately we cannot modify Player interface, but you can use type-assersion like

p := context.NewPlayer(src)
p.(oto.BufferSizeSetter).SetBufferSize(4096)

Thanks,

@bigfarts
Copy link
Author

Thanks, it works!

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.

3 participants