Auxio
Auxio copied to clipboard
Service independence (Starting playback without opening app)
Describe the feature you want to implement:
While Auxio have Intents, they are limited and don't work unless Auxio is already running in the background. My knowledge of programming is limited, but it appears the latter is caused by the type of intent.
Is your feature request related to a problem? Please describe:
I'm trying to control music playback through Auxio, namely I'm a user of Tasker and sometime between Android 7 and Android 12 it became unreliable to start music playback by just simulating a Media Button press. Intents appear to be the only solution left, and sadly the ones Auxio have are of the broadcast type.
Do other music players handle this? If so, how?
PowerApp actually does have it, they are of the Service type and I'm able to start them even after a reboot, and it has a long list of possible intents that I'm aware of:
- Play/Pause
- Pause
- Resume
- Stop
- Next
- Previous
- Start Fast Forward
- Stop Fast Forward
- Start Fast Rewind
- Stop Fast Rewind
- Toggle Repeat
- Toggle Shuffle
Why do you think this will improve everyone's usage of Auxio?
While not useful to the majority of Auxio users, it will be incredibly helpful to the ones that are also Tasker users, and because it isn't a request for a Tasker Plug-in, it has could help users of that can send Intents.
Due Diligence:
- [x] I have read the Contribution Guidelines.
- [x] I have read the Accepted Additions and Requests document.
- [x] I have checked for this feature in the FAQ.
This is not possible.
To make my app work in modern android, I am effectively forbidden from having any means of interaction that does not require you to open the app first.
Android 8 made foreground services (Which includes Auxio's music playback) MUCH harder to initialize. I have 5 seconds to initialize everything or the app will crash. Factoring in music loading and the restoration of the playback state, I simply cannot fit it into that window.
The options I have to work around it are:
- Create a dummy notification that allows me to initialize immediately, but then I run into issues with rate-limiting and display coherency. It would cause more issues than it solves.
- Perpetually trap my app in "API 2X hell" like Phonograph so I can skirt the restrictions within the compatibility sandbox. This is obviously terrible.
- Include proprietary GPM garbage like Poweramp to work around the restrictions, because the true intent of these changes is not to reduce battery drain or increase security but really so google can peddle FireBase and Google Cloud. This is free software, so that is an instantaneous pass.
Even then, I also have to deal with Android 12's insane restriction on launching foreground services when the app is backgrounded. If I were to add these intents, it could open up a footgun where someone on Android 12 tries to fire an intent while Auxio is backgrounded, and then gets confused why the app crashes. It just isn't practical.
The days of being able to do neat things without interaction on Android are over. I do not want my app to be an awful, buggy mess, so I require you to open Auxio before doing anything. If this means I have to annoy a vanishingly small minority of Tasker users, so be it.
Besides, the MediaController API is really what one should be using to control playback, not Intent instances. Auxio does support a variety of actions with that API, save queue editing and browsing the music library (I'm working on that). The Tasker developers should really add support for that instead of trying to salvage a dying API.
Hey if you don't mind just a side note, so I don't have to open another issue for something that can be easily answered:
What about Static Shortcuts? Auxio has a Dynamic one that doesn't show up both in Tasker and Kustom, and other non-launcher apps that can initiate shortcuts. I've managed to in a really dumb roundabout way trigger the Dynamic one with Tasker, but it would be far easier and more flexible if it was possible for you to implement a couple Static ones(or even just one). Again, this would also benefit Kustom users, and others.
I also think Tasker is already using the MediaController API, as we can get Media information and interact as if it was media buttons as I stated. But even if I'm wrong, the google documentation mentions its only for ongoing media session, I don't think it is possible to start a media session from nowhere without initializing the app first.
What about Static Shortcuts? Auxio has a Dynamic one that doesn't show up both in Tasker and Kustom, and other non-launcher apps that can initiate shortcuts. I've managed to in a really dumb roundabout way trigger the Dynamic one with Tasker, but it would be far easier and more flexible if it was possible for you to implement a couple Static ones(or even just one). Again, this would also benefit Kustom users, and others.
I use dynamic shortcuts so that shotcuts in debug builds don't redirect to release builds or just not work at all. Maybe I can do some cursed hack where the release shortcut is static and the debug shortcut is dynamic.
I also think Tasker is already using the MediaController API, as we can get Media information and interact as if it was media buttons as I stated. But even if I'm wrong, the google documentation mentions its only for ongoing media session, I don't think it is possible to start a media session from nowhere without initializing the app first.
Yeah, I already know. I brought it up since controlling it through MediaController would not unexpectedly initialize the app, which was impossible as I stated prior.
Okay, let me clarify that this might not be entirely impossible. It's just impossible with the current system and not something that I actively want to say I have planned.
Over time I tend to warm up to features as I think on and off about them and eventually develop a system that will solve the problem sensibly. If I'm confident that the odds have shifted and the addition is a net benefit with the new approach, I create a new issue with my proposal and signal that it's actively planned and not just something I'm thinking about.
For example, I dismissed using my own metadata extractor/caching mechanism (i.e Ignore MediaStore tags) until I found a sensible way to implement it (Using ExoPlayer instead of JAudioTagger and caching raw tags instead of the entire music library), and then I was comfortable implementing it in the app.
For this one, I may revisit it if I find a coherent way to initialize everything that does not negatively affect the app experience as a whole.
Thank for your consideration, but just to clarify: are you talking about intents or static shortcuts?
Intents. The static shortcuts thing I need to do more research on but should be slightly more possible.
Okay, turns out your feature request might be required for #37 because the MediaBrowserService lifecycle is absurd. I haven't looked into it very much though.
So it's going to get open again?
I will not lie, I don't totally understand the technical implications or even why it is required for Android Auto, but hey, it is still an improvement
Maybe. The documentation is extremely vague, but it implies that Android Auto can start the playback service at any time, including when the app is completely dead. This is the same avenue that you want with your intents, except I might be forced to implement it.
I never even looked at Android Auto, but thinking about it, it doesn't make sense to have to manually open a Music Player while in a car.
Best case would be to test and see if a Google app can auto start with Android Auto.... except last I checked, Google doesn't make any music player anymore
Youtube Music exists. I'm going to add the media browser boilerplate and see what happens in an emulator.
Assuming that I need to handle this case, I think I have a route to implementing it. Basically, I would need to unify the two services in Auxio (music loading and playback) into a single service that can load and play music which resolves the issues with foreground time limits and app initialization in general. Albeit, I'd want to do it in such a way that the code for music loading and music playback remain separated, as it's easier to maintain in that way.
The implementation details are hard and annoying and blocked by countless things however, so this is still low-priority.
If you don't mind me asking, why is Auxio so aggressive with music loading? I don't think I've ever seen an app being so aggressive and upfront about checking for changes to the library.
- It reloads it every time you start the app, even if it was seconds since the last time it checked it
- It doesn't happen in the background, meaning it stops the user from using the app.
- "Ignore MediaStore Tags" takes significant time to reload (which is fine), but because of the above points it isn't really a viable option.
A few reasons, I guess:
- I used to use Music Player GO, and so a bunch of Auxio's architecture is derived from that app. MPGO is similarly aggressive with loading.
- Being aggressive with loading ensures a more sensible music experience at the cost of lost time at the start. I've seen how background loading mechanisms work in other apps (Read: Vanilla) and they are buggy garbage that usually renders the library similarly unusable until it's done loading. I'd rather be upfront that "Yeah, I'm is unusable until I can index your 10000-song library, sorry" rather than be implicitly unstable until the loading is done.
Note that the next version will have a much faster music loader where "Ignore MediaStore tags" is on by default, as I am now caching song metadata for later use. There will likely always be some overhead though.
Eeeh, I'm going to have to look at the next version first to give it some thought and see what really changed in terms of the user experience, because I'm not sure about the implications of caching song metadata without seeing it in action.
But I don't really get why it isn't doing like VLC by doing a big scan on boot and on the background, an option to manually refresh the library on the 3-dot menu would also help. The probability of the user changing the music library (specially if they are using a whitelist of folders) and not remembering it by doing a manual re-scan is rather low. Furthermore, you could mitigate the number of auto-refreshes by comparing when was the last time it was done, as it redo it even if you closed and reopened the app in less than 5 secs, but I'm assuming this will be taken care of with the caching.
The caching implementation is mostly to circumvent the time sink within "Ignore MediaStore tags", that being the quite slow file opening/metadata extracting process. It works something like this:
- Query the media database for every song on the device.
- For each song, check with the cache if it has extracted metadata for that song that can be used. This is used by comparing the timestamps of the song from the media database and the timestamps in the cache.
- If we can use the cached metadata (the timestamps are the same, so the song has not changed), we are done.
- Otherwise, we run the slower metadata extraction routine and save that song to the cache.
So, if you don't change your library, loads should go from taking ~15 seconds for a 1k song library to only 1 second or lower. If you only change part of your library, then it should still be quite fast, with a bit more time being needed to scan the new music.
But I don't really get why it isn't doing like VLC by doing a big scan on boot and on the background
AFAIK, newer android versions will not allow me to wake my app on boot anymore unless the user disables battery optimizations. I really want the app to work out of the box without having to make the user fiddle with hidden android settings, so I can't implement this.
The probability of the user changing the music library (specially if they are using a whitelist of folders) and not remembering it by doing a manual re-scan is rather low.
Not really sure what you mean by this.
Furthermore, you could mitigate the number of auto-refreshes by comparing when was the last time it was done, as it redo it even if you closed and reopened the app in less than 5 secs, but I'm assuming this will be taken care of with the caching.
That's basically the cache mechanism, albeit done on a song-by-song basis so it still takes a non-trivial amount of time. Even if I did some clever tracking of when loads occur, you also have to consider that I still have to load the cache as well, hence why I said there will always be some overhead.
The caching implementation is mostly to circumvent the time sink within "Ignore MediaStore tags", that being the quite slow file opening/metadata extracting process. It works something like this:
1. Query the media database for every song on the device. 2. For each song, check with the cache if it has extracted metadata for that song that can be used. This is used by comparing the timestamps of the song from the media database and the timestamps in the cache. 3. If we can use the cached metadata (the timestamps are the same, so the song has not changed), we are done. 4. Otherwise, we run the slower metadata extraction routine and save that song to the cache.So, if you don't change your library, loads should go from taking ~15 seconds for a 1k song library to only 1 second or lower. If you only change part of your library, then it should still be quite fast, with a bit more time being needed to scan the new music.
Yeah, the caching part seems fair. However, if it is really 1 second or lower, you might want to consider "hiding" it behind a fake app loading screen that takes half to one second to complete and the rest of the loading is shown as usual. This way, the app will appear faster than it actually is.
But I don't really get why it isn't doing like VLC by doing a big scan on boot and on the background
AFAIK, newer android versions will not allow me to wake my app on boot anymore unless the user disables battery optimizations. I really want the app to work out of the box without having to make the user fiddle with hidden android settings, so I can't implement this.
Alright, so I'm on Android 12, but there are 2 things which might minimize your concerns:
- Tasker can show a system floating dialog that directly asks you whether you want to disable battery optimizations.
- Kustom apps show a floating dialog that concisely tells the user how to disable battery optimization, and it takes the user directly to the android setting screen, so it's not hidden.
- Both apps somehow can know if the battery optimization was disabled or not, re-enabling it makes those apps ask again for the user to disable it.
The third point is important, because you can use it as a means to fall back to the previous method. Or make the on boot an option in the settings that only nags the user when they open the app for the first time.
The probability of the user changing the music library (specially if they are using a whitelist of folders) and not remembering it by doing a manual re-scan is rather low.
Not really sure what you mean by this.
AFAIK Auxio works in two "modes":
- Whitelist: only look for things on specific folders
- Blacklist: Look for things everywhere, except specific folders.
If the user is using the "Whitelist" method, they are more likely to be aware of changes they made to those folders, meaning they are capable of manually triggering a re-scan, if there was an option on the 3-dot menu AND scan only happened on boot.
Basically, "Whitelist-users" would be fine if scan only happened on boot.
Yeah, the caching part seems fair. However, if it is really 1 second or lower, you might want to consider "hiding" it behind a fake app loading screen that takes half to one second to complete and the rest of the loading is shown as usual. This way, the app will appear faster than it actually is.
Let me clarify that it's 1 second or so for an "average" library (1000 songs), larger libraries will slow the loading process down more. Because of this, I may as well keep the loading UI as-is.
Alright, so I'm on Android 12, but there are 2 things which might minimize your concerns:
But that's the thing: I don't want to have to make an annoying onboarding flow just to disable battery optimizations. I want my app to work without much fiddling by the user. No matter how obvious I make the dialog, no matter how much I nag the user, some user will inevitably ignore it and then make an issue complaining that the app is crashing. "Make something dumb-user-proof and the universe will make a dumber user."
Besides, disabling the optimizations is the "easy way out" that will only likely get harder and harder in future versions.
Let me clarify that it's 1 second or so for an "average" library (1000 songs), larger libraries will slow the loading process down more. Because of this, I may as well keep the loading UI as-is.
I know, that's not what I mean.
Assuming:
- Cached loading will take between 0.5 to 1 second to load a library with 1000 songs
- You know with certainty that the vast majority of users don't keep more than 1000 songs on their devices.
You can then make a fake full screen splash screen on top of the loading dialog. It is dismissed if:
- The cached loading has finished OR
- It started loading things that are not in cache OR
- One second has passed
In this case, most users wouldn't even know Auxio is loading the library. The ones that have bigger libraries will have Auxio open into a loading dialog that is already in the halfway point, meaning that for them, it will also appear like Auxio is faster than it actually is.
Granted this adds complexity, and I'm not even 100% into the idea, but eeh, I needed to explain a little since Loading Screens are really annoying for end users, specially ones that appears every time you cold start the app and don't allow you to interact with the app while it is loading.
Besides, disabling the optimizations is the "easy way out" that will only likely get harder and harder in future versions.
I understand your point, and can't really deny them, however, I'm not 100% sure about this point in specific. Android 13 added a convenient way to check for active apps in the notification drawer, this seems to point to me that Google is considering backtracking a bit on the battery limitations as long as they find an easy way to communicate it to the user
I know, that's not what I mean ...
I see. Doing that is actually not recommended by google anymore. The splash screen is only intended for basic app initialization. Otherwise for loading I should use placeholders or indicators, like I currently am. If I were to shove in my own splash to hide loading, that would just create needless jank that I don't want.
Besides, disabling the optimizations is the "easy way out" that will only likely get harder and harder in future versions.
The FGS is merely another way to cripple apps under the guide of "battery protection". You now have the free ability to completely kill an app (not just the service, the WHOLE APP) if it has an active foreground service, making services even harder to manage. I don't even have the leeway to save the playback state or reset the widget when it's pressed, my app is just killed. Of course, the real reason behind most service limitations is to railroad apps into proprietary GCM/firebase garbage, so the FGS is a logical step in that to make typical monitoring or data sync services even less usable.
Okay, I'm going to re-open this. I realized that if I unify my two services, that more or less resolves the issues of background starts and the foreground time limit. It's hard, but doable, and it will actually enable #37. I think I'll try to do it alongside #257 in a more general refactor of the service lifecycle.
Actually, may not necessarily need to unify the music loading and playback services. Seems like the type of work the music loading service is doing will be deprecated in future versions. To futureproof it, I'll have to use the new "work manager" system. No clue how much easier or harder this becomes.
A bit of off-topic, but since this conversation started because of it, could you consider adding a Tasker Plugin?
The Tasker dev made a video explaining how to do it: https://www.youtube.com/watch?v=48IVJgDtu6Y
And the documentation seems... relatively easy enough
I can, but it's still blocked by this issue since Auxio physically cannot work correctly with Tasker without this change.
Don't the shortcut implies that Auxio already has the means to work if an app manually calls it?
As I said a while ago, what prevents me from using Auxio in Tasker is because it uses dynamic shortcuts, even then, I managed to use a truly cursed method (a hell to set-up and configure) to make Trigger the Shuffle Dynamic Shortcut and it worked.
Not quite. The shortcut opens the app's activity, which then delivers commands to the services. What I'm talking about is the ability to cut the app activity out, and simply deliver the command to the service directly. Auxio doesn't really support this right now.
Oh, also scrapping the "work manager" thing I brought up earlier. Turns out it's too OEM-dependent and once again runs into the same foreground start limitation insanity as prior. Just going to lie and tell the system that the unified service is solely for "media playback" when in reality it's doing playback and loading.
Would it be possible to just open a dialog or something and immediately close it?
Too janky of a solution for something that can be solved in other ways.
I mean, everytime we open Auxio, it opens a dialog about updating the library anyway.
Even if you found a perfect solution that can start playback from cold boot, it would still need to load the music library, no? By that point you would need to create a notification or a dialog anyway
Oh, that's what you mean. Yes, I would have to show a notification. The issue is that the service performing playback and the service loading music are separate right now. Arguably, I could make the playback service show a fake notification to work around the limitation as it waits for music to load, but that's honestly too bug-prone when I can also just merge the two services and avoid such.
Regarding our discussion from awhile back, #384 is actually likely going to make it that Auxio will actually stop indicating that it's loading music front-and-center in some cases. It's still in flux however which cases Auxio will no longer indicate it, however. Once I pin it down I'll share the specifics.