Pato05 / just_audio_media_kit

A platform interface for just_audio which wraps media_kit
https://pub.dev/packages/just_audio_media_kit
The Unlicense
9 stars 11 forks source link

Buffer duration control? #11

Closed Chaphasilor closed 7 months ago

Chaphasilor commented 7 months ago

Is there any way to control the buffer duration with the media-kit backend? For Android there's AndroidLoadControl.minBufferDuration and AndroidLoadControl.minBufferDuration, and for iOS there's DarwinLoadControl.preferredForwardBufferDuration in just_audio.

It appears like currently the player is using the AndroidLoadControl on Windows, but that could just be a coincidence.
Either way, it seems like the buffer always stops at the end of the current track, and does not pre-fetch the next track, contrary to what happens on the mobile platforms. Setting the buffer duration to 10 minutes should always fetch the next 10 minutes of the current audio source (which is a ConcatenatingAudioSouce in this case), even if the current track is shorter than that.

Is that a limitation of media-kit?

Pato05 commented 7 months ago

No, it's not a limitation, you can edit the buffer size with the JustAudioMediaKit.bufferSize static parameter.

Please check the README: https://github.com/Pato05/just_audio_media_kit?tab=readme-ov-file#plugin-specific-configuration-settings-for-media_kits-player-instance

Pato05 commented 7 months ago

Either way, it seems like the buffer always stops at the end of the current track, and does not pre-fetch the next track

That is true. I wanted to create a proxy server to handle this, but that would be too bloat-y to include in the main plugin, so I'll probably never actually do this. However, feel free to create a new plugin for it!

Actually this might not be necessary as it seems mpv already supports this via the --prefetch-playlist option (see media_kit#200). I'll test for a possible solution in the next days, as today I may not be able to.

Chaphasilor commented 7 months ago

So there's no way to set the buffer size based on a duration somehow?

The --prefetch-playlist option actually doesn't seem to solve the issue. It expects a static queue, and only fetches the next track shortly before the current track ends. So it's more like a gapless option?

Pato05 commented 7 months ago

So there's no way to set the buffer size based on a duration somehow?

Not as far as I'm aware...

The --prefetch-playlist option actually doesn't seem to solve the issue. It expects a static queue, and only fetches the next track shortly before the current track ends. So it's more like a gapless option?

depends on the demuxer cache settings [...]. This merely opens the URL of the next playlist entry as soon the current URL is fully read. (source)

According to docs it's kinda similar to what just_audio provides in Android. Though docs also say it's highly experimental, so I may make this available under a flag that is false by default.

Also I'm not really sure how "gapless" would be different than pre-fetching the next track..

I'll implement this anyways (also cause it doesn't hurt to), though, can you try it yourself as to check whether this meets your needs?

Chaphasilor commented 7 months ago

I am a bit confused by the part about it not pre-fetching video data. It sounded like it would simply open a connection and fetch the header of the next item, instead of actually loading any media data. I guess we'll have to try it out.

Where would I need to add this option to try things out?

Pato05 commented 7 months ago

It sounded like it would simply open a connection and fetch the header of the next item, instead of actually loading any media data.

You may actually be right, that's why it says "merely", I guess...

Where would I need to add this option to try things out?

You could add it right after _player = Player(...); in mediakit_player.dart, you'd have to call _player.platform.setProperty('prefetch-playlist', 'yes'); or something along these lines.. Check here: https://github.com/media-kit/media-kit/issues/14#issuecomment-1373205132.

Pato05 commented 7 months ago

Ok, so I did some testing by using a python HTTP server (from scratch, so that I can check whenever the connection is open), and it seems that --prefetch-playlist just makes the loading a little bit less lazy by starting to load the track moments before it has to be played (see attached video)

Screencast from 2024-04-09 14-25-14.webm

I don't think increasing the demuxer buffer will actually do anything, as by default it should be about 150MB, and, well, the song doesn't even go close to that...

It's surely better to put the option to use --prefetch-playlist, as it is a little more 'gap-less' this way, though it's not what we ideally want.

Pato05 commented 7 months ago

So there's no way to set the buffer size based on a duration somehow?

I was looking at the mpv docs, and yes, you can specify a duration instead of specifying bytes, with the --cache-secs option. It may make sense to use the AndroidLoadControl.maxBufferDuration option as the value for this option, or just let it be.

If https://github.com/ryanheise/just_audio/issues/1222 gets fixed, I could export the Player instance, so that more options can be set via setProperty, thus allow more freedom on controlling the player without editing just_audio_media_kit's code..

Pato05 commented 7 months ago

While testing the new option, it seems that the actual behaviour in media_kit is slightly different (and way closer to what we want in the first place). My example app is just a tweak of the example in just_audio, where I removed the ClippingAudioSource, and basically changed the URL for the third entry to my local HTTP server.

I'll cut to the chase: it started loading the track when there were about 15 minutes left from the podcast, and it didn't only stop when it received the headers, but the entire song was downloaded way before it was required for playback!

prefetch.webm

With that said, this issue can be now closed (feel free to reopen if you find a new solution or feel like this is incomplete).

Chaphasilor commented 7 months ago

Sorry for not responding to this, I'm currently sitting on a huge stack of unread notifications and I'm spread way to thin. So thanks for all your work, and the nice write-ups.
Looks like everything ended up working out great!

I see that you've already published your changes. I'll give this a try immediately and report back!

Chaphasilor commented 7 months ago

Yeah, that seems to work well! Sometimes the buffer doesn't show up in our UI immediately, but the next track is definitely starting to play immediately.
Skipping ahead two tracks doesn't seem to work yet, but that's fine. Could be a cache size issue, although you mentioned a size of 150 MB, which should be more than enough.

Either way, I also consider this issue closed. Providing the buffer duration in seconds would be nice, but if you want to wait for ryanheise/just_audio#1222 for that, that's also fine with me!
Thanks again!

Pato05 commented 7 months ago

Either way, I also consider this issue closed. Providing the buffer duration in seconds would be nice [...]

As I said earlier, media-kit itself doesn't have a way of specifying the buffer in seconds, even though mpv does have a property --demuxer-readahead-secs which, according to docs, should do what you're asking for.

Exporting the native platform would of course mean that you can set this property yourself, thus reaching your goal. Though I would like to avoid tinkering with properties (and introducing "hacks") as much as possible and just sticking to what media-kit already provides.

Though of course, if a hack is needed for a huge deficiency (like in #3), that would be completely fine as there wouldn't be any way around it.

Chaphasilor commented 7 months ago

I'm still a but fuzzy with the relation between media-kit and mpv. I thought media-kit was a stand-alone player that doesn't use platform-specific implementations, but your comment makes me think it's just an additional wrapper around the "native" players for all platforms, that exposes a unified API?

Pato05 commented 7 months ago

I'm still a but fuzzy with the relation between media-kit and mpv. I thought media-kit was a stand-alone player that doesn't use platform-specific implementations, but your comment makes me think it's just an additional wrapper around the "native" players for all platforms, that exposes a unified API?

media-kit uses libmpv internally. There would be only two "platform implementations", being the native platform (platforms with dart:io) and the web platform (flutter web, which implements an HTML player)