Skip to content

Commit

Permalink
make android auto work
Browse files Browse the repository at this point in the history
  • Loading branch information
brahmkshatriya committed Jan 7, 2025
1 parent e0a9425 commit 6b7cbe9
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class ExtensionOpenerActivity : Activity() {
if (result && installAsApk) {
context.createLinksDialog(file, links)
}
supportFragmentManager.clearFragmentResultListener(EXTENSION_INSTALLER)
it.resume(result)
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/dev/brahmkshatriya/echo/PlayerService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class PlayerService : MediaLibraryService() {
@Inject
lateinit var currentServers: MutableStateFlow<Map<String, Streamable.Media.Server>>

private val scope = CoroutineScope(Dispatchers.Main)
private val scope = CoroutineScope(Dispatchers.IO)

@OptIn(UnstableApi::class)
private fun createExoplayer(extListFlow: MutableStateFlow<List<MusicExtension>?>) = run {
Expand Down
366 changes: 214 additions & 152 deletions app/src/main/java/dev/brahmkshatriya/echo/playback/AndroidAutoCallback.kt

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package dev.brahmkshatriya.echo.playback

import android.content.SharedPreferences
import android.os.Bundle
import androidx.annotation.OptIn
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.common.MimeTypes
import androidx.media3.common.ThumbRating
import androidx.media3.common.util.UnstableApi
import dev.brahmkshatriya.echo.common.models.EchoMediaItem
import dev.brahmkshatriya.echo.common.models.EchoMediaItem.Companion.toMediaItem
import dev.brahmkshatriya.echo.common.models.Streamable
Expand Down Expand Up @@ -39,7 +41,8 @@ object MediaItemUtils {
settings: SharedPreferences?, mediaItem: MediaItem, track: Track
): MediaItem = with(mediaItem) {
val item = buildUpon()
val metadata = track.toMetaData(mediaMetadata.extras!!, extensionId, context, true, settings)
val metadata =
track.toMetaData(mediaMetadata.extras!!, extensionId, context, true, settings)
item.setMediaMetadata(metadata)
return item.build()
}
Expand Down Expand Up @@ -137,7 +140,7 @@ object MediaItemUtils {
item.build()
}


@OptIn(UnstableApi::class)
private fun Track.toMetaData(
bundle: Bundle,
extensionId: String = bundle.getString("clientId")!!,
Expand All @@ -153,8 +156,9 @@ object MediaItemUtils {
.setAlbumArtist(album?.artists?.joinToString(", ") { it.name })
.setArtist(toMediaItem().subtitleWithE)
.setArtworkUri(cover?.toJson()?.toUri())
.setUserRating(ThumbRating(isLiked))
.setIsBrowsable(false)
.setUserRating(
if (isLiked) ThumbRating(true) else ThumbRating()
)
.setExtras(bundle.apply {
putSerialized("track", this@toMetaData)
putString("extensionId", extensionId)
Expand All @@ -167,7 +171,9 @@ object MediaItemUtils {
)
})
.setSubtitle(bundle.indexes())
.setMediaType(MediaMetadata.MEDIA_TYPE_MUSIC)
.setIsPlayable(true)
.setIsBrowsable(false)
.build()

private fun Bundle.indexes() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import androidx.media3.session.SessionResult
import androidx.media3.session.SessionResult.RESULT_SUCCESS
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.SettableFuture
import dev.brahmkshatriya.echo.R
import dev.brahmkshatriya.echo.common.MusicExtension
import dev.brahmkshatriya.echo.common.clients.SearchFeedClient
Expand All @@ -30,12 +29,14 @@ import dev.brahmkshatriya.echo.common.clients.TrackLikeClient
import dev.brahmkshatriya.echo.common.models.EchoMediaItem
import dev.brahmkshatriya.echo.common.models.EchoMediaItem.Companion.toMediaItem
import dev.brahmkshatriya.echo.common.models.Shelf
import dev.brahmkshatriya.echo.common.models.Track
import dev.brahmkshatriya.echo.extensions.getExtension
import dev.brahmkshatriya.echo.playback.MediaItemUtils.extensionId
import dev.brahmkshatriya.echo.playback.MediaItemUtils.track
import dev.brahmkshatriya.echo.playback.listeners.Radio
import dev.brahmkshatriya.echo.ui.exception.ExceptionFragment.Companion.toExceptionDetails
import dev.brahmkshatriya.echo.utils.future
import dev.brahmkshatriya.echo.utils.getFromCache
import dev.brahmkshatriya.echo.utils.getSerialized
import dev.brahmkshatriya.echo.utils.putSerialized
import dev.brahmkshatriya.echo.viewmodels.ExtensionViewModel.Companion.noClient
Expand Down Expand Up @@ -87,7 +88,7 @@ class PlayerCallback(
println("Custom Command: ${customCommand.customAction}")
when (customCommand) {
likeCommand -> onSetRating(session, controller, ThumbRating(true))
unlikeCommand -> onSetRating(session, controller, ThumbRating(false))
unlikeCommand -> onSetRating(session, controller, ThumbRating())
repeatOffCommand -> setRepeat(player, Player.REPEAT_MODE_OFF)
repeatOneCommand -> setRepeat(player, Player.REPEAT_MODE_ONE)
repeatCommand -> setRepeat(player, Player.REPEAT_MODE_ALL)
Expand Down Expand Up @@ -135,9 +136,11 @@ class PlayerCallback(
val mediaItem = MediaItemUtils.build(
settings, loaded.tracks[0], loaded.clientId, loaded.radio.toMediaItem()
)
player.setMediaItem(mediaItem)
player.prepare()
player.playWhenReady = true
withContext(Dispatchers.Main) {
player.setMediaItem(mediaItem)
player.prepare()
player.playWhenReady = true
}
SessionResult(RESULT_SUCCESS)
}

Expand All @@ -147,16 +150,15 @@ class PlayerCallback(
return if (rating !is ThumbRating) super.onSetRating(session, controller, rating)
else scope.future {
val errorIO = SessionResult(SessionError.ERROR_IO)
val item = session.player.currentMediaItem ?: return@future errorIO
val item = withContext(Dispatchers.Main) { session.player.currentMediaItem }
?: return@future errorIO
extensionList.first { it != null }
val extension = extensionList.getExtension(item.extensionId) ?: return@future errorIO
val client = extension.instance.value.getOrNull() ?: return@future errorIO
if (client !is TrackLikeClient) return@future errorIO
val track = item.track
withContext(Dispatchers.IO) {
runCatching {
client.likeTrack(track, rating.isThumbsUp)
}
runCatching {
client.likeTrack(track, rating.isThumbsUp)
}.getOrElse {
return@future SessionResult(
SessionError.ERROR_UNKNOWN,
Expand All @@ -169,7 +171,9 @@ class PlayerCallback(
mediaMetadata.buildUpon().setUserRating(ThumbRating(liked)).build()
)
}.build()
session.player.replaceMediaItem(session.player.currentMediaItemIndex, newItem)
withContext(Dispatchers.Main) {
session.player.replaceMediaItem(session.player.currentMediaItemIndex, newItem)
}
SessionResult(RESULT_SUCCESS, bundleOf("liked" to liked))
}
}
Expand All @@ -178,10 +182,7 @@ class PlayerCallback(
mediaSession: MediaSession,
controller: MediaSession.ControllerInfo
): ListenableFuture<MediaItemsWithStartPosition> {
val settable = SettableFuture.create<MediaItemsWithStartPosition>()
val resumptionPlaylist = ResumptionUtils.recoverPlaylist(context)
settable.set(resumptionPlaylist)
return settable
return Futures.immediateFuture(ResumptionUtils.recoverPlaylist(context))
}

override fun onSetMediaItems(
Expand Down Expand Up @@ -210,12 +211,8 @@ class PlayerCallback(
): ListenableFuture<MutableList<MediaItem>> {

//Look at the first item's search query, if it's null, return the super method
val query =
mediaItems.firstOrNull()?.requestMetadata?.searchQuery ?: return super.onAddMediaItems(
mediaSession,
controller,
mediaItems
)
val query = mediaItems.firstOrNull()?.requestMetadata?.searchQuery
?: return super.onAddMediaItems(mediaSession, controller, mediaItems)

fun default(reason: Context.() -> String): ListenableFuture<MutableList<MediaItem>> {
toast(reason.invoke(context))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ class PlayerEventListener(
private var last: Pair<String, Throwable>? = null
override fun onPlayerError(error: PlaybackException) {
val cause = error.cause?.cause ?: error.cause ?: error
scope.launch {
val exception = if (cause is StreamableLoadingException) cause.cause
else PlayerException(cause.toExceptionDetails(context), player.currentMediaItem)
throwableFlow.emit(exception)
}

val exception = if (cause is StreamableLoadingException) cause.cause
else PlayerException(cause.toExceptionDetails(context), player.currentMediaItem)
scope.launch { throwableFlow.emit(exception) }

if (cause !is StreamableLoadingException) return
if (cause.cause !is AppException.Other) return

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ class Radio(

else -> {
suspend fun <T> tryIO(block: suspend () -> T): T? =
withContext(Dispatchers.IO) {
extension.run(throwableFlow) { block() }
}
extension.run(throwableFlow) { block() }

val radio = tryIO {
when (item) {
Expand All @@ -93,17 +91,11 @@ class Radio(

if (radio != null) {
val tracks = tryIO { client.loadTracks(radio).loadFirst() }
val state = if (!tracks.isNullOrEmpty()) State.Loaded(
clientId,
radio,
tracks,
play
)
val state = if (!tracks.isNullOrEmpty())
State.Loaded(clientId, radio, tracks, play)
else {
messageFlow.emit(
SnackBar.Message(
context.getString(R.string.radio_empty)
)
SnackBar.Message(context.getString(R.string.radio_empty))
)
null
}
Expand All @@ -115,16 +107,17 @@ class Radio(
}
}

private fun play(loaded: State.Loaded, play: Int): Boolean {
val track = loaded.tracks.getOrNull(play) ?: return false
val item = MediaItemUtils.build(
settings, track, loaded.clientId, loaded.radio.toMediaItem()
)
player.addMediaItem(item)
player.prepare()
player.playWhenReady = true
return true
}
private suspend fun play(loaded: State.Loaded, play: Int): Boolean =
withContext(Dispatchers.Main) {
val track = loaded.tracks.getOrNull(play) ?: return@withContext false
val item = MediaItemUtils.build(
settings, track, loaded.clientId, loaded.radio.toMediaItem()
)
player.addMediaItem(item)
player.prepare()
player.playWhenReady = true
true
}

private fun loadPlaylist() {
val mediaItem = player.currentMediaItem ?: return
Expand Down Expand Up @@ -159,7 +152,7 @@ class Radio(
loadPlaylist()
}

is State.Loaded -> {
is State.Loaded -> scope.launch {
val toBePlayed = state.played + 1
if (toBePlayed == state.tracks.size) loadPlaylist()
if (play(state, toBePlayed)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class TrackingListener(
val extension = extensionList.getExtension(details?.extensionId)
val trackers = trackerList.value?.filter { it.metadata.enabled } ?: emptyList()

scope.launch(Dispatchers.IO) {
scope.launch {
extension?.get<TrackerClient, Unit>(throwableFlow) {
block(extension, details)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ class EditPlaylistFragment : Fragment() {
override fun onItemClicked(position: Int) {}

override fun onItemClosedClicked(position: Int) {
if (position == -1) return
viewModel.edit(Remove(position))
}
})
Expand Down

0 comments on commit 6b7cbe9

Please sign in to comment.