-
Notifications
You must be signed in to change notification settings - Fork 540
Blocked UI when using large playlists #81
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
Comments
Maybe related to #57 |
Thanks for reporting! As you discovered this is a known issue. The time isn't spend with networking I think but with bundling/unbundling the As a first step I'd recommend to only send I think you will run into similar problems with We will try to improve this at some point and we acknowledge that this is slow currently when adding 100+ items. I wonder, as a last thing, if this is a regression and how the performance for these operations was with |
Thanks for the reply and the implementation tipps to work around the performance problem @marcbaechinger! We are planning to implement the workaround, however, I am not exactly sure if I understand correctly how to implement it. Let's say we have 500 playlist items. The user clicks on the first item in the recycler view and then scrolls all to the bottom of the list to plays the last playlist item. Do we have to add the 9 batches (450 items) after the Thanks for your time and also thanks for the information about the first beta release, really looking forward to it. PS: As far as I can tell, the legacy implementation works super smooth with the same big playlist we are currently having "trouble" with. |
Yeah, you are right. I played around with such use cases some more yesterday and can confirm your findings. My comment above was more about the addition of 500 media items to the playlist at once. But I see and agree to your point that this happens not only when adding items but also when selecting another current media item. This triggers sending over a new On a Pixel 6 I can see the lagging UI in some cases, but in some cases it is very smooth also. I see that the phone unbundles So, probably my comment above was a bit a shot from the hip. Sorry for that. I'm currently profiling this a bit to see where the time is actually spent. Will comment here once I found something useful. (thanks for the confirming it is smooth with the legacy implementation) |
No worries and thanks for your support! I will also let you know if we find out anything more. |
This problem does exist, it's been bothering me for two days, I set 1500 mediaItems, when I seekToPreviousItem, the |
Hi All, We have reduced the time required to bundle and unbundle These updates have already been published to the |
Hi, Rohit. I confirm that the issue is still present in the stable version. |
@MaximillianLeonov Could you provide further details regarding your situation that would assist us in replicating the problem on our end? For instance, could you inform us about the number of items present in the playlist initially and the delay you're encountering while attempting to play or scroll through the playlist? |
You can find the repository for reproducing the issue here. I encountered this problem with 500-1000 songs. Although the issue is less noticeable in this repository with only 500-1000 songs, so I set 10,000 songs to make the problem more clearly visible. Screen_recording_20230413_095243.webm |
@MaximillianLeonov, To clarify our optimisations, we have reduced the time it takes to bundle and unbundle playlists, ensuring that the user interface (UI) remains responsive during common use cases, typically a few hundred to thousand items. However, the latency still depends on the length of the playlist and the capabilities of the phone being used. I conducted a test on a Pixel 4A by playing a playlist containing 1000 items, and it performed smoothly without any issues. Even for larger playlists with 10,000 items, the lag was significantly reduced, and the UI did not freeze. However, if you continue to increase the playlist size to 100,000 items, it can still cause the UI to freeze. On a more advanced phone, such as the Pixel 6 Pro, the experience is smooth even when dealing with playlists of 10,000 items. Can you please share the device you're using to experience the lag with 500-1000 songs? |
Regarding the devices I experienced lag on, they are the Samsung Galaxy A23 and Xiaomi Redmi Note 8. In addition, I have noticed that the UI freezes specifically when the |
@MaximillianLeonov,
Although I did not have access to the mentioned devices for testing, I tested the demo session app on a Samsung Galaxy A51 and Xiaomi Redmi Note 9 Pro. During the testing, I did not observe any freezing of the UI or noticeable delays when the playlist contained ~1000 items. However, when the playlist size was increased to 10000 items, substantial UI lags were encountered. |
Since I was rewriting a large portion of my old media playing app to reduce laggy UI and ANR's, I have not been too thrilled to discover that Media3 introduces some new problems when using large playlists. I'm wondering if there was a way for the library to detect if the MediaController(s) is in-process and avoid the binder calls if that is the case? That would completely eliminate the lag I believe. Something like how there was a |
@svenoaks Local binder calls should not be a bottleneck at all because they automatically avoid the inter-process communication protocol (=what I think you mean by binder calls) and instead call the receiving method directly. That is, the data being sent is not going through any process or threading jumps and doesn't need to be marshalled and unmarshalled to/from a shared memory space (see first bullet point in this guide: https://developer.android.com/guide/components/aidl) |
@tonihei Thanks for the clarification. Since I'm using |
@rohitjoins probably knows this a bit better, but if my understanding is correct, the blocking happens on the reading side (=the |
@marcbaechinger @rohitjoins @tonihei Hi! I hope this gets your attention. Context: Original MediaPlayer performance: I did some tests using 10000 items and putting aside the time it takes to initially prepare the data and player (usually 0-10 seconds), the player itself was superfast. No UI lags (obviously because all potentially time-consuming operations were done on a background thread), No delays, nada. Media3 performance: Initially, I thought this issue was an edge case, and not many people have that many media items but looking at the reports from Google Play and on GitHub, the number of users with large playlists turned out to be common enough to warrant a proper solution.
@marcbaechinger this really helped reduce UI lags, however, I'm still getting ANRs with large playlists (only when the media controller is involved). I do not know how things work internally but why can't we move this media controller work to a background thread? The existing
This bundling/unbundling process is still slow and it blocks the main thread enough to cause a crash or ANR. Doing this on the main thread is a bad idea/design.
@rohitjoins even after applying the @marcbaechinger's media ID hack (let's call it), the player is slow enough to not be usable and this has nothing to do with overloaded main thread. How to reproduce:
It takes like 30-60 seconds before the player resumes playing again. The observed delay is directly proportional to the number of media items. There's a significant delay even with 5000 media items. I believe this is the same issue as #592 (comment) and #402 I tried playing around with the To summarise:
thanks! |
Thanks for the thorough reply - that's useful to hear and we definitely know that large playlists continue to be problematic. Let me summarize some of things we've done, discussed and are planning to do. There are two main data flows to look at:
Note that all these steps need to handle the large number of items somehow and to improve the performance, there are two options: optimize the operation or avoid the operation as much as possible. What we've done so far
What we are planning to do next
For later releases:
What we are not planning to do
Some comments on your concrete proposals from the comment above:
This sounds strange, but may be related to a huge backlog of work generated by these actions. We'll have a look at this case to see if there is something else going on.
ANRs can be caused by any of the steps mentioned above if they run within one main thread iteration. We'll submit some improvements, and you can also check in your app code that it is as efficient as possible and not handling too many items at once if it can be avoided. The code in MediaController in particular is not the slow part (and also not blocking). And as explained above, we are also not planning to consider any further background threads because we don't see a case where they would help further.
The delay is likely not ExoPlayer related, but in the session/controller communication as said above. We'll check your reproduction steps though, just in case there is some additional problem here.
This comparison is not really useful because this setup neither has a player that supports playlists nor a session that knows and shares all the items. So it's fast by removing all the functionality and avoiding all the work. |
@tonihei thanks for the much-needed clarifications! Blocked UI when using large playlists (pretty much resolved)
Only setting the I did some tests with ~10000 items and after calling Could you please provide some guidance on how to send incremental updates using a media controller? I'm curious, does sending incremental updates help ExoPlayer prepare faster too or is it just for fast MediaController=>MediaSession communication? Unresponsive/slow player
When this happens MediaSession => MediaController updates are delayed as well. The Not sure if it's relevant but I was looking at the memory profiler to reduce memory usage and I noticed that when I do next or previous multiple times, the memory usage spikes up and even leads to an OOM if I keep doing it: My current workaround is to throttle the A "paging" Player wrapper (deserves to be highlighted)
That is a great idea. If implemented, I think it will solve most if not all of these problems (other optimizations are nice too). |
This makes the media controller more responsive, see androidx/media#81
Yes, simply calling it multiple times in a loop likely makes no big difference I'd say. You'd need to wait with a timed delay or for the callback as you suggested. This isn't super easy to achieve of course and only helps with setting new items from your code (data flow 1 in my post above). It doesn't help with data flow 2 (sending updates to controllers) as this needs to be solved inside our library.
Should also help with the player preparation (see "paging" player idea that relies on a similar pattern)
Probably caused by the pending tasks kept in memory. This should resolve itself by reducing overall delays (as we then don't keep a long lists of pending tasks anymore). |
OK, thanks for the help. Just in case you guys need it, I'm attaching two large CPU traces (compressed) below to demonstrate the main thread getting blocked by the media controller's Since Github doesn't allow large files, here's a Google Drive link: https://drive.google.com/file/d/1XUdtA5usxPSkhW5HFZZQec-3L5zdvQMd/view?usp=sharing For anyone interested in the 'slow next/previous' workaround, click to expand /**
* This is here so the player can quickly seek next/previous without doing too much work.
* It probably won't be needed once https://github.com/androidx/media/issues/81 is resolved.
*/
private fun seekWithDelay() {
seekJob?.cancel()
seekJob = scope.launch {
delay(timeMillis = 400)
val seekCount = seekToNextCount - seekToPreviousCount
if (seekCount != 0) {
seekByCount(seekCount)
}
}
}
private fun seekByCount(seekCount: Int) {
runOnPlayerThread {
if (currentMediaItem == null) {
return@runOnPlayerThread
}
val currentIndex = currentMediaItemIndex
val seekIndex = if (shuffleModeEnabled) {
val shuffledIndex = shuffledMediaItemsIndices.indexOf(currentIndex)
val seekIndex = rotateIndex(shuffledIndex +
6D40
seekCount)
shuffledMediaItemsIndices.getOrNull(seekIndex) ?: return@runOnPlayerThread
} else {
rotateIndex(currentIndex + seekCount)
}
seekTo(seekIndex, 0)
seekToNextCount = 0
seekToPreviousCount = 0
}
}
private fun rotateIndex(index: Int): Int {
val count = mediaItemCount
return (index % count + count) % count
} |
I am commenting here because large playlists are still a major concern using 1.1.1 or 1.2.0-rc01. I have rolled out to 5% of my user base with no compensation (besides only setting the mediaId for MediaItems) for the fact that media3 library is still badly lagged with large playlists and have already received a few negative reviews mentioning it. I can reproduce all of the things mentioned in this issue, probably the lagging prev/next buttons are the worst, as there can be a huge backlog of events that can take minutes to play out, but even some kind of debouncing of them would not fix all that lagging and blocking of the main thread with large playlists. (Edit: most of the next/prev lag was due to app code) For now the only solution for me seems to be limit the size of the playing queue to 1000 items or so unless the user specifically adds more. I hope that that the "paging" player idea can be implemented quickly on the library side as this seems like the only real good solution. |
I ending up implementing a solution where my SimpleBasePlayer implementation only ever sets a playlist size of up to 10 items, and my app handles most manipulation of the actual playlist internally, overrides like handleSetMediaItems are no-ops now. The only flaw I noticed with this setup in my case was a small flickering of the track title when the SimpleBasePlayer predicated state does not line up with the actual result state, a rare occurrence. As mentioned in the previous edit, the real major lags with prev/next buttons was caused by app code. However, with the large playlists set on the player many mediaController events caused noticeable jank, even where the playlist did not change. With the limiting of the playlist that the player to 10, all the jank has been removed. |
Thanks for sharing! The pending improvements I mentioned above should result in a similar behavior out of the box so that no special workaround is required on app side. |
Sorry for the necroposting, I'm just curious, was this paging player ever implemented? |
Likely no since the issue is still open. Back then I had an idea to do an in-app version of the paging player until this is fixed. I never got around to it but, I might try it soon-ish. |
@marcbaechinger i added playlist around 600 items and UI lags for few seconds this is my code section may be i'm doing something wrong or its Media3 Api Debug Version : Delay 5sec
MediaItemMapper
|
Issue
We are experiencing UI lags when using big playlists containing podcast urls. Specifically, we are using a
MediaController
where we usesetMediaItems
to pass around 600MediaItem
s. The Items are presented in aRecyclerView
where users can select the desired item. After selecting an item by click, we callMediaController#seekToDefaultPosition
. This call clearly freezes the UI and also makes everything unresponsive for a few milliseconds. We have not checked if the problems also occurs with big playlists of local audio files.Reproduce
We successfully reproduced the issue in your session demo project by slightly modifying the following line
media/demos/session/src/main/java/androidx/media3/demo/session/PlayableFolderActivity.kt
Line 161 in 72a4fb0
with
As you can imagine, this code change only provokes a large playlist.
First select any audio file in the album, artist or genre folder. For example: Artist Folder -> The Kyoto Connection -> click on Intro - The Way ..
You should see the UI lag when you try to scroll in the list immediately after clicking an item in the bottom list view in the
PlayerActivity
.We also found out that switching between two
MediaItem
s which have been played before does not produces any lags. So maybe the UI issues are related to ongoing network calls.For us, the UI lags are visible on the following phones, however, the bug is "better" visible on the Samsung S9:
media3 Version: 1.0.0-alpha03
Please let us know if you have any further questions or if there is anything we can do to support you in finding the cause.
Thanks for building media3!
Julian
The text was updated successfully, but these errors were encountered: