-
-
Notifications
You must be signed in to change notification settings - Fork 115
[WIP] Initial multiple queues support #865
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
base: beta
Are you sure you want to change the base?
Changes from all commits
471afcd
4f39f96
60e3b6f
3ed4ed8
73bfe3f
048130e
8b2ff7f
d917eee
c6ae8cb
33caec9
9e9001a
aa7d9a0
fe511a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| /* | ||
|
Check warning on line 1 in app/src/main/java/org/akanework/gramophone/logic/GramophoneExtensions.kt
|
||
| * Copyright (C) 2024 Akane Foundation | ||
| * | ||
| * Gramophone is free software: you can redistribute it and/or modify | ||
|
|
@@ -59,12 +59,14 @@ | |
| import androidx.core.view.children | ||
| import androidx.core.view.updateLayoutParams | ||
| import androidx.core.view.updateMargins | ||
| import androidx.media3.common.BundleListRetriever | ||
| import androidx.media3.common.C | ||
| import androidx.media3.common.Format | ||
| import androidx.media3.common.MediaItem | ||
| import androidx.media3.common.Player | ||
| import androidx.media3.common.Tracks | ||
| import androidx.media3.common.util.Log | ||
| import androidx.media3.exoplayer.source.ShuffleOrder | ||
| import androidx.media3.session.MediaController | ||
| import androidx.media3.session.SessionCommand | ||
| import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat | ||
|
|
@@ -75,6 +77,13 @@ | |
| import org.akanework.gramophone.R | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_GET_AUDIO_FORMAT | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_GET_LYRICS | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QB_DEL | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QB_GET_INACTIVE_LIST | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QB_GET_QUEUE_FOR_UI | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QB_LOAD_QUEUE | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QB_PIN_QUEUE | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QB_REORDER | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QB_UNPIN_QUEUE | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_QUERY_TIMER | ||
| import org.akanework.gramophone.logic.GramophonePlaybackService.Companion.SERVICE_SET_TIMER | ||
| import org.akanework.gramophone.logic.utils.AfFormatInfo | ||
|
|
@@ -337,6 +346,149 @@ | |
| ) | ||
| } | ||
|
|
||
| fun MediaController.getInactiveQueues(): List<MultiQueueObject> = | ||
| sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_GET_INACTIVE_LIST, Bundle.EMPTY), | ||
| Bundle.EMPTY | ||
| ).get().extras.run { | ||
| val binder = getBinder("allQueues")!! | ||
| BundleListRetriever.getList(binder).map { | ||
| MultiQueueObject.fromBundle(it) | ||
| } | ||
| } | ||
|
|
||
| fun MediaController.getQueue(index: Int = C.INDEX_UNSET): MultiQueueObject? = | ||
| sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_GET_QUEUE_FOR_UI, Bundle.EMPTY).apply { | ||
| customExtras.putInt("index", index) | ||
| }, Bundle.EMPTY | ||
| ).get().extras.run { | ||
| val binder = getBinder("allQueues")!! | ||
| BundleListRetriever.getList(binder).map { | ||
| MultiQueueObject.fromBundle(it) | ||
| }.firstOrNull() | ||
| } | ||
|
|
||
|
|
||
| fun shuffledItems( | ||
| items: List<MediaItem>, | ||
| order: ShuffleOrder | ||
| ): List<MediaItem> { | ||
| val result = mutableListOf<MediaItem>() | ||
|
|
||
| var i = order.firstIndex | ||
| while (i != C.INDEX_UNSET) { | ||
| result.add(items[i]) | ||
| i = order.getNextIndex(i) | ||
| } | ||
|
|
||
| return result | ||
| } | ||
|
|
||
| fun shuffledIndices(order: ShuffleOrder): MutableList<Int> { | ||
| val result = mutableListOf<Int>() | ||
|
|
||
| var i = order.firstIndex | ||
| while (i != C.INDEX_UNSET) { | ||
| result.add(i) | ||
| i = order.getNextIndex(i) | ||
| } | ||
|
|
||
| return result | ||
| } | ||
|
|
||
| fun MediaController.getQueueForUi(index: Int = -1): Pair<MutableList<Int>, MultiQueueObject>? { | ||
| if (index == -1) { | ||
| return null | ||
| } | ||
| return sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_GET_QUEUE_FOR_UI, Bundle.EMPTY).apply { | ||
| customExtras.putInt("index", index) | ||
| }, Bundle.EMPTY | ||
| ).get().extras.run { | ||
| val binder = getBinder("allQueues")!! | ||
| BundleListRetriever.getList(binder).map { | ||
| val mq = MultiQueueObject.fromBundle(it) | ||
| val indexes: MutableList<Int> = if (mq.shuffleOrder == null) { | ||
| (0 until mq.getSize()).toMutableList() | ||
| } else { | ||
| getIntArray("shuffleIndexes")!!.toMutableList() | ||
| } | ||
|
|
||
| Pair(indexes, mq) | ||
| }.firstOrNull() | ||
| } | ||
| } | ||
|
|
||
| fun MediaController.loadQueue(index: Int) { | ||
| sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_LOAD_QUEUE, Bundle.EMPTY).apply { | ||
| customExtras.putInt("index", index) | ||
| }, Bundle.EMPTY | ||
| ) | ||
| } | ||
|
|
||
| fun MediaController.pinQueue(index: Int) { | ||
| sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_PIN_QUEUE, Bundle.EMPTY).apply { | ||
| customExtras.putInt("index", index) | ||
| }, Bundle.EMPTY | ||
| ) | ||
| } | ||
|
|
||
|
|
||
| fun MediaController.unQueue(index: Int) { | ||
| sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_UNPIN_QUEUE, Bundle.EMPTY).apply { | ||
| customExtras.putInt("index", index) | ||
| }, Bundle.EMPTY | ||
| ) | ||
| } | ||
|
|
||
|
|
||
| fun MediaController.deleteQueue(index: Int): Boolean = | ||
| sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_DEL, Bundle.EMPTY).apply { | ||
| customExtras.putInt("index", index) | ||
| }, Bundle.EMPTY | ||
| ).get().extras.run { | ||
| if (containsKey("status")) | ||
| getBoolean("status") | ||
| else throw IllegalArgumentException("expected status to be set") | ||
| } | ||
|
|
||
| fun MediaController.reorderQueue(from: Int, to: Int): Boolean = | ||
| sendCustomCommand( | ||
| SessionCommand(SERVICE_QB_REORDER, Bundle.EMPTY).apply { | ||
| customExtras.putInt("from", from) | ||
| customExtras.putInt("to", to) | ||
| }, Bundle.EMPTY | ||
| ).get().extras.run { | ||
| if (containsKey("status")) | ||
| getBoolean("status") | ||
| else throw IllegalArgumentException("expected status to be set") | ||
| } | ||
|
|
||
| /* | ||
| // TODO: shuffle and repeat mode | ||
| fun MediaController.playQueue( | ||
| title: String?, | ||
| mediaList: List<MediaItem>, | ||
| mediaItemIndex: Int, | ||
| isOriginal: Boolean | ||
| ) { | ||
| sendCustomCommand( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. commented out much?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. qb doesn't own the current queue. Yes, a full queue was added into qb via addqueue, but all that data (with the exception of the title) remains untouched and isnt actually used anywhere. All the old data is overwritten anyways with the latest from the player when setmediaitems is called again, so there is no spaghetti required. I see how that commitQueue nonsense is redundant, so I'll change that. I'll null out the info in addQueue to prevent that info from creeping in in the future, and also call super. Now (fe511a1) it works like this for when setmediaitems is called: handleSetMediaItems -> addqueue adds skeleton queue to qb, -> commitqueue facilitates the active/inactive swap within qb (without its own setmediaitems) -> super.handleSetMediaItems And then for user initiated queue swaps: commitqueue facilitates the active/inactive swap within qb (with realSetMediaItems) -> super.handleSetMediaItems. You cant call setmediaitems again |
||
| SessionCommand(SERVICE_QB_ENQUEUE, Bundle.EMPTY).apply { | ||
| customExtras.putString("title", title) | ||
| customExtras.putInt("mediaItemIndex", mediaItemIndex) | ||
| customExtras.putBoolean("isOriginal", isOriginal) | ||
| val binder = BundleListRetriever(mediaList.map { it.toBundleIncludeLocalConfiguration() }) | ||
| customExtras.putBinder("mediaList", binder) | ||
| }, Bundle.EMPTY | ||
| ) | ||
| } | ||
| */ | ||
|
|
||
| fun Tracks.getFirstSelectedTrackFormatByType(type: @C.TrackType Int): Format? { | ||
| for (i in groups) { | ||
| if (i.type == type) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are doing this at the wrong level, Android AUto for example will just not call your SERVICE_QB_ENQUEUE, it will keep doing setMediaItems(). Instead a player wrapper should give old queue to queueboard before executing setMediaItems()