Open smkhalsa opened 3 years ago
@ryanheise
Hi @mz5210 Please write your comments in English, thank you.
@ryanheise I tested 502 pieces of music, adding them to the playlist in bulk, it worked fine, no stuck, maybe you should incorporate this change into master
Hi @ryanheise, Any chance to update feature/treadmill?
Just updated.
@ryanheise works fine!
First impressions on feature/treadmill
- my weird issue with gapless sometimes being broken is fixed! I'll use it on my own device for a bit to see how stable it is :)
@ryanheise Would this already address a scenario where audio media needs to be loaded from an HTTP URL which becomes available after making an additional request ?
Something like below:
Items loaded in the playlist is
When actually playing a music, the item from the above list is HTTP requested, which returns an MP3 audio file to play.
If feature/treadmill doesn't address this, what approach would you recommend ?
Thanks in advance.
so I can load 2000 audio now directly to the player without any freezing issue ?
@LouisAldorio Try it and let me know how it goes. The treadmill branch has been put out there to be tested in order to receive feedback.
Branch feature/treadmill right ? , tomorrow I will try it let you know , but just to confirm I am not using the wrong branch , feature/treadmill right , sir ryan
but just to confirm I am not using the wrong branch , feature/treadmill right
Well, if you find any other treadmill branch, please let me know about it!
everything works well, 917 tracks, added and instantly played lol. that was fast
Even though mine instantly started playing, it took about 30 seconds to add 1000 tracks in the newest version of feature/treadmill on iOS with all the flags enabled. I see a huge improvement, but it is still not satisfactory for shuffle mode to work properly when starting the app.
@hunterwilhelm Can you just clarify, so it started playing BEFORE it added the tracks? In which case, what precisely do you mean by adding the tracks? Do you mean the time it took to appear in the UI?
@ryanheise Here is how I have it in the code right now.
.add
instead of .addAll
because .addAll
is still freezing the UI.Right now I am making my own implementation of the dynamically loading so it works on iOS. I am loading the tracks into the playlist one by one when needed. But if the user starts in the middle of the playlist, they need to go backward. So, I am going to have to write a complicated function to map the indices of the queues (shuffled and chronological) to the playlist indices (for precaching purposes) and vice versa.
In the case of .addAll
or passing all children into the constructor, there are several points in the code that cause the slowdown. The treadmill
branch addresses only one of them, which is to prevent the native player on iOS from trying to load the entire playlist all at once. But there are still 2 other bottlenecks. One is passing a large playlist over the flutter method channel all at once, and the other is purely on the dart side when processing long lists. Dart is not multi-threaded, so any time we do a for loop over a long list, that is potentially going to lock up the UI.
If you do have a very long playlist, yes, you do have to just avoid passing very long lists into ConcatenatingAudioSource
and instead use it more dynamically so that you maintain your own Dart list containing your entire playlist, but you use ConcatenatingAudioSource
to only ever contain the next 3 items to play. When you reach the end of the current track, you remove it from the front and add a new track onto the back so that you always have 3 items queued up for gapless playback.
The long term future direction of the plugin should be to shift the internal implementation somewhat in this direction. There are complications to that, so there is no short term quick fix, apart from using ConcatenatingAudioSource
within your app in a more dynamic way as described above.
@ryanheise Is there any example code available that I may refer that follows your suggested approach to fill ConcatenatingAudioSource dynamically by 3 items only? Thanks in advance!
@ryanheise thanks for that quick response! That makes sense. Someday I'll be knowledgeable enough on the topic to be able to assist with the amazing work you do!
@jagpreetsethi Once I finish my implemention of what Ryan is talking about, I'll post it here. It will include shuffling.
Hi @ryanheise
I've been trying to include the just_audio package in my Flutter project using its Git repository as the source. However, I've been encountering an issue when specifying the Git reference in the pubspec.yaml file.
Here's how I'm adding the package to my pubspec.yaml file:
just_audio:
git:
url: https://github.com/ryanheise/just_audio.git
ref: feature/treadmill
However, every time I attempt to fetch the package, I get an error indicating that the pubspec.yaml file cannot be found in the specified Git reference:
Could not find a file named "pubspec.yaml" in https://github.com/ryanheise/just_audio.git 02f74512e51c40ba68fe4c898d570c0c4ae906d5.
The reference I'm using is: feature/treadmill, and I've verified that it exists in the repository: https://github.com/ryanheise/just_audio/tree/feature/treadmill.
I've tried cleaning the cache, updating Flutter packages, and even cloning the repository locally to test, but the issue persists.
Is there something I might be missing or any suggestions you can provide to help me resolve this? I greatly appreciate your assistance in this matter.
Thank you!
It's because just_audio isn't in the root directory of this repo, it's in the just_audio
subdirectory, so you need to specify that with path: just_audio
. So:
just_audio:
git:
url: https://github.com/ryanheise/just_audio.git
ref: feature/treadmill
path: just_audio
For me this feature/treadmill
works good. I would ask you to merge it. Thank you for the nice package and your support.
@jagpreetsethi I implemented what @ryanheise was suggesting. However, I wasn't able to figure out shuffling while preloading without having any visual glitches or refreshes when switching between shuffle mode and non-shuffle mode. So I left it out. If anyone can modify it to add it, I would be very grateful.
@ryanheise Is there a way to disable preloading/pre-caching entirely for ConcatenatingAudioSource
? I don't see an option to turn it off on iOS.
No, that is in fact why you are working around it by only adding a limited number of items to the playlist. You need to have at least the current and the next item in the playlist in order to get gapless playback. If you want to get more sophisticated, you could listen to the current position, and when it reaches 15-20 seconds before reaching the end of the track, that's when you can add the next item to the playlist, so that it then starts buffering it just in time.
No, that is in fact why you are working around it by only adding a limited number of items to the playlist. You need to have at least the current and the next item in the playlist in order to get gapless playback. If you want to get more sophisticated, you could listen to the current position, and when it reaches 15-20 seconds before reaching the end of the track, that's when you can add the next item to the playlist, so that it then starts buffering it just in time.
Would it be a problem if I don't remove the previous item and just keep adding for as much as I want?
If you keep adding without ever removing, you will eventually end up with a very large list that could again slow down communication between Dart and iOS.
Can you please update branch(feature/treadmill
)?
What specifically would you like me to update about it?
Dear @ryanheise, Firstly, congratulations on this fantastic package. I've encountered an issue – I've created an MP3 podcast playlist with no spaces at the beginning of the files, yet there's a disruptive effect during transitions. Is it possible to add a very brief gap at each episode change, or is there a way to smooth out the transitions?
Hi @burhanaksendir , this issue concerns slow loading of long playlists on iOS only. I would like to maintain separate issues for separate issues, so I'll mark both of our comments as off topic.
@ryanheise Is there any reason, known issue to not merge feature/treadmill branch? First impression, it works just fine for me. I am planning to publish it to our production if there is no known issue. Btw Is this branch changes affecting Android too?
I think one more thing I would like to do is make this behaviour sensitive to the useLazyPreparation
parameter, or even add a separate parameter to specifically control the iOS/macOS specific behaviour. In this case, perhaps the parameter would control the size of the treadmill. I welcome any feedback on this.
or even add a separate parameter to specifically control the iOS/macOS specific behaviour. In this case, perhaps the parameter would control the size of the treadmill. I welcome any feedback on this.
The only reason to want to specify the size of the treadmill is for short queue items where items are so short that having two items on the treadmill is not enough of a buffer to ensure that we will not hit the end of the buffer and stall playback. However, I think a boolean option such as useLazyPreparation
might suffice after all. Apps that are using "really" short items where this is a consideration probably aren't the intended use case for lazy loading anyway, and they have two options:
ConcatenatingAudioSource
.So unless there are any objections, I may just tie this to useLazyPreparation
with a treadmill size of 2.
Update: I have made substantial changes to the feature/treadmill
branch in order to support the useLazyPreparation
option, along with a couple of other bug fixes/enhancements.
Please let me know if this update breaks anything in your apps before I officially merge it into the next release.
Update: I have made substantial changes to the
feature/treadmill
branch in order to support theuseLazyPreparation
option, along with a couple of other bug fixes/enhancements.Please let me know if this update breaks anything in your apps before I officially merge it into the next release.
Working great, I am using it to load 114 files with large files such as 2 hours length with no issues
Update: I have made substantial changes to the
feature/treadmill
branch in order to support theuseLazyPreparation
option, along with a couple of other bug fixes/enhancements.Please let me know if this update breaks anything in your apps before I officially merge it into the next release.
Works awesome with 1000+ ConcatenatingAudioSources in playlist.
Thanks for the testing results @MohammadElKhatib and @bekchan .
Have either of you had any experience with how this interacts with shuffle mode, loop modes, or edge cases such as where there are only 1 or 0 items in the playlist?
Thanks for the testing results @MohammadElKhatib and @bekchan .
Have either of you had any experience with how this interacts with shuffle mode, loop modes, or edge cases such as where there are only 1 or 0 items in the playlist?
Well I believe it is working so well as I mentioned previously, first it did not work well but maybe it was caching the default branch and once I cleared cache and re-run the application, it is working awesome
I am using it for Quran application where there is multiple reciters so basically 114 files with around 15 reciters and what i am doing is loading all the files and replace it once changing the reciters also I am listening to the sound progress updates in order to highlight text in parallel with sound.
thanks for your efforts waiting the merge with main branch :-)
Thanks, @MohammadElKhatib . Are you using either/both of shuffle and loop modes, or is that not a pertinent feature in your app?
Thanks, @MohammadElKhatib . Are you using either/both of shuffle and loop modes, or is that not a pertinent feature in your app?
I used the loop options but I faced one issue I am not sure if this is the default behavior, what happened is that I used a button to toggle the loop and repeat. I have 3 options repeat one, repeat all and no repeat basically repeat one is repeating the current sound normally, repeat all is going through all the files and repeat from first index after reaching the last index while the no repeat is keep going forward till the last sound and stop there.
while what I wanted is to only play one sound and stop so I am not sure if this is a bug or default behavior or I am missing something here.
Note: I am also using background service and syncing text and progress alltogether.
below screenshot of my app
while what I wanted is to only play one sound and stop so I am not sure if this is a bug or default behavior or I am missing something here.
If you have a ConcatenatingAudioSource
, it is the normal behaviour to auto-advance to the next child after completing the current one. There is another feature request to make that configurable, but until then you could listen to the PositionDiscontinuity
event type and when it is autoAdvance
, you can handle that event by pausing. The playlist example contains some code that shows how to listen for this event, since it uses it to show a toast whenever auto-advancing. Since this is a workaround until the aforementioned feature is implemented, it is not going to be perfect, though, because the time between when you receive the event and when you invoke pause()
and wait for it to actually pause won't be zero, and so there is a chance that if the next audio doesn't have any silent padding at the start, you might hear a few milliseconds of the next audio before it pauses.
while what I wanted is to only play one sound and stop so I am not sure if this is a bug or default behavior or I am missing something here.
If you have a
ConcatenatingAudioSource
, it is the normal behaviour to auto-advance to the next child after completing the current one. There is another feature request to make that configurable, but until then you could listen to thePositionDiscontinuity
event type and when it isautoAdvance
, you can handle that event by pausing. The playlist example contains some code that shows how to listen for this event, since it uses it to show a toast whenever auto-advancing. Since this is a workaround until the aforementioned feature is implemented, it is not going to be perfect, though, because the time between when you receive the event and when you invokepause()
and wait for it to actually pause won't be zero, and so there is a chance that if the next audio doesn't have any silent padding at the start, you might hear a few milliseconds of the next audio before it pauses.
Honestly, the current situation is acceptable in my app, I will keep following your updates.
Thanks again for your great work.
Have either of you had any experience with how this interacts with shuffle mode, loop modes, or edge cases such as where there are only 1 or 0 items in the playlist?
Shuffle and loop modes works great. Also tested reorderable playlist with +1000 audio, still good. Thank you for this great package.
I have just merged and published the feature/treadmill
branch. Thank you very much to those who helped to test it. This issue will remain open since there are 2 other sources of lag that can be introduced by long lists. One is that the Dart iterators don't yield, which may be an issue on very long lists, and the other is (or was?) possibly the lag from passing a huge message over the method channels all at once. I have to test whether this is still an issue. But of course in the meantime, apps can work around this by creating an empty ConcatenatingAudioSource
and incrementally building it up rather than initialising it all in one go.
Which API doesn't behave as documented, and how does it misbehave?
Creating a ConcatenatingAudioSource with lots (~1000) of children takes a very long time (>20 seconds).
In my application, users can have playlists with an arbitrary number of items.
Minimal reproduction project
To Reproduce (i.e. user steps, not code)
Error messages
Expected behavior
I'd expect to be able to set the audio source and start playing the first source within a couple seconds, even with a large number of sources (since only the initial few sources are actually being fetched).
Screenshots
Desktop (please complete the following information):
Smartphone (please complete the following information):
Flutter SDK version
Additional context
NOTE added by @ryanheise :
Adding a large number of children is problematic at multiple levels due to the single-threaded model. For now, there are three approaches to workaround this issue:
ConcatenatingAudioSource
with zero children, and then add the children in a loop that yields every now and then to let other coroutines execute on the same thread. This can be done for example by periodically callingawait Future.delayed(Duration.zero);
.ConcatenatingAudioSource
with an initial sublist of children small enough to load without issue, and then write your own application logic to lazily add more children as needed (just-in-time). If you want to create the illusion that the list of children is complete from the beginning, you will need to write your UI around some other more complete list of metadata, separate fromConcatenatingAudioSource
's own internal list of items.feature/treadmill
(now merged) that implements the logic of (2) above but on the iOS native side (Android already has this implemented on the native side whenuseLazyPreparation
istrue
). This will stop iOS from trying to load every item in the playlist, and instead only load items that are nearer to the front of the queue. If you test this branch, please share below whether you found it stable enough to release.