Skip to content

Commit

Permalink
Merge pull request #46 from NielsMasdorp/feature/update_libs
Browse files Browse the repository at this point in the history
Update dependencies
  • Loading branch information
Niels Masdorp authored Jun 29, 2023
2 parents 418f15b + 144d5f2 commit 9500be6
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 98 deletions.
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ android {
minSdkVersion 26
//noinspection OldTargetApi
targetSdkVersion 33
versionCode 194
versionName "2.3.0"
versionCode 195
versionName "2.3.1"
}
buildTypes {
release {
Expand Down Expand Up @@ -106,7 +106,7 @@ dependencies {
implementation "com.github.skydoves:landscapist-glide:$landscapist_glide_version"
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'
implementation "com.airbnb.android:lottie-compose:$lottie_version"
implementation "com.patrykandpatrick.vico:compose-m3:1.6.5"
implementation "com.patrykandpatrick.vico:compose-m3:$vico_version"

//test
testImplementation "junit:junit:$junit_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ class AndroidEqualizerManager(
}

override fun onCastingStatusChanged(isCasting: Boolean) {
if (isCasting) {
equalizerState.value = if (isCasting) {
EqualizerState.NotAvailableWhileCasting
} else {
equalizer.toState()
}
equalizerState.value = if (isCasting) {
EqualizerState.NotAvailableWhileCasting
} else {
equalizer.toState()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@ class ReplaceableForwardingPlayer(private var player: Player) : Player {
playlist.addAll(min(newIndex, playlist.size), removedItems)
}

override fun replaceMediaItem(index: Int, mediaItem: MediaItem) {
player.replaceMediaItem(index, mediaItem)
playlist.set(index, mediaItem)
}

override fun replaceMediaItems(
fromIndex: Int,
toIndex: Int,
mediaItems: MutableList<MediaItem>
) {
player.replaceMediaItems(fromIndex, toIndex, mediaItems)
mediaItems.forEachIndexed { index, mediaItem ->
playlist.set(fromIndex + index, mediaItem)
}
}

override fun removeMediaItem(index: Int) {
player.removeMediaItem(index)
playlist.removeAt(index)
Expand Down Expand Up @@ -255,13 +271,6 @@ class ReplaceableForwardingPlayer(private var player: Player) : Player {

override fun stop() = player.stop()

override fun stop(reset: Boolean) {
player.stop(reset)
if (reset) {
playlist.clear()
}
}

override fun release() {
player.release()
playlist.clear()
Expand Down Expand Up @@ -401,14 +410,30 @@ class ReplaceableForwardingPlayer(private var player: Player) : Player {
player.deviceVolume = volume
}

override fun setDeviceVolume(volume: Int, flags: Int) {
player.setDeviceVolume(volume, flags)
}

override fun increaseDeviceVolume() = player.increaseDeviceVolume()

override fun increaseDeviceVolume(flags: Int) {
player.increaseDeviceVolume(flags)
}

override fun decreaseDeviceVolume() = player.decreaseDeviceVolume()

override fun decreaseDeviceVolume(flags: Int) {
player.decreaseDeviceVolume(flags)
}

override fun setDeviceMuted(muted: Boolean) {
player.isDeviceMuted = muted
}

override fun setDeviceMuted(muted: Boolean, flags: Int) {
player.setDeviceMuted(muted, flags)
}

private inner class PlayerListener : Listener {
override fun onEvents(player: Player, events: Events) {
if (events.contains(EVENT_POSITION_DISCONTINUITY) ||
Expand Down
142 changes: 68 additions & 74 deletions app/src/main/java/com/nielsmasdorp/nederadio/playback/StreamService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.*
import androidx.media3.session.MediaConstants.*
import androidx.media3.session.MediaLibraryService.MediaLibrarySession
import androidx.media3.session.MediaSession.MediaItemsWithStartPosition
import androidx.media3.session.SessionCommand.*
import androidx.media3.session.SessionResult.RESULT_SUCCESS
import com.google.android.gms.cast.framework.CastContext
Expand All @@ -29,11 +30,10 @@ import com.nielsmasdorp.nederadio.domain.equalizer.EqualizerManager
import com.nielsmasdorp.nederadio.domain.settings.GetLastPlayedId
import com.nielsmasdorp.nederadio.domain.stream.SetActiveStream
import com.nielsmasdorp.nederadio.playback.library.StreamLibrary
import com.nielsmasdorp.nederadio.playback.library.Tree
import com.nielsmasdorp.nederadio.ui.NederadioActivity
import com.nielsmasdorp.nederadio.util.connectedDeviceName
import com.nielsmasdorp.nederadio.util.moveToFront
import com.nielsmasdorp.nederadio.util.sendCommandToController
import com.nielsmasdorp.nederadio.util.toMediaItem
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.guava.future
Expand All @@ -58,6 +58,10 @@ class StreamService :
SessionAvailabilityListener {

private val streamLibrary: StreamLibrary by inject()

private val contentTree: Flow<Tree> = streamLibrary.browsableContent
private suspend fun Flow<Tree>.await(): Tree = first()

private val setActiveStream: SetActiveStream by inject()
private val getLastPlayedId: GetLastPlayedId by inject()
private val equalizerManager: EqualizerManager by inject()
Expand Down Expand Up @@ -102,13 +106,13 @@ class StreamService :
): ListenableFuture<LibraryResult<MediaItem>> {
return serviceScope.future {
val isRecentRequest = params?.isRecent ?: false
val tree = streamLibrary.browsableContent.first()
val contentTree = contentTree.await()
val rootItem = if (!isRecentRequest) {
tree.rootNode.mediaItem
contentTree.rootNode.mediaItem
} else {
// Playback resumption
tree.recentRootNode.also {
tree.getLastPlayed(lastPlayedId = getLastPlayedId()!!).let { item ->
contentTree.recentRootNode.also {
contentTree.getLastPlayed(lastPlayedId = getLastPlayedId()!!).let { item ->
player.setMediaItem(item)
player.prepare()
}
Expand Down Expand Up @@ -138,11 +142,11 @@ class StreamService :
params: LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return serviceScope.future {
val tree = streamLibrary.browsableContent.first()
val children = if (parentId == tree.recentRootNode.mediaId) {
listOf(tree.getLastPlayed(lastPlayedId = getLastPlayedId()!!))
val contentTree = contentTree.await()
val children = if (parentId == contentTree.recentRootNode.mediaId) {
listOf(contentTree.getLastPlayed(lastPlayedId = getLastPlayedId()!!))
} else {
tree.getChildren(nodeId = parentId).toMutableList()
contentTree.getChildren(nodeId = parentId).toMutableList()
}
LibraryResult.ofItemList(children, params)
}
Expand All @@ -154,8 +158,7 @@ class StreamService :
mediaId: String
): ListenableFuture<LibraryResult<MediaItem>> {
return serviceScope.future {
val item = streamLibrary.browsableContent.first().getItem(itemId = mediaId)
LibraryResult.ofItem(item, null)
LibraryResult.ofItem(contentTree.await().getItem(itemId = mediaId), null)
}
}

Expand All @@ -166,9 +169,12 @@ class StreamService :
params: LibraryParams?
): ListenableFuture<LibraryResult<Void>> {
return serviceScope.future {
// Ignore extras since we have only top level streams without genres etc.
val results = streamLibrary.browsableContent.first().search(query = query)
mediaSession.notifySearchResultChanged(browser, query, results.size, params)
mediaSession.notifySearchResultChanged(
/* browser */ browser,
/* query */ query,
/* itemCount */ contentTree.await().search(query = query).size,
/* params */ params
)
LibraryResult.ofVoid()
}
}
Expand All @@ -182,24 +188,26 @@ class StreamService :
params: LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return serviceScope.future {
// Ignore extras since we have only top level streams without genres etc.
val results = streamLibrary.browsableContent.first().search(query = query)
val results = contentTree.await().search(query = query)
val fromIndex = max((page - 1) * pageSize, results.size - 1)
val toIndex = max(fromIndex + pageSize, results.size)
LibraryResult.ofItemList(results.subList(fromIndex, toIndex), params)
LibraryResult.ofItemList(
/* items */ results.subList(fromIndex, toIndex),
/* params */ params
)
}
}

/**
* Casting has started, switch to [CastPlayer]
* Casting has started, switch to [CastPlayer] and notify equalizer
*/
override fun onCastSessionAvailable() {
player.setPlayer(newPlayer = castPlayer)
equalizerManager.onCastingStatusChanged(isCasting = true)
}

/**
* Casting has been stopped, switch to [ExoPlayer]
* Casting has been stopped, switch to [ExoPlayer] and notify equalizer
*/
override fun onCastSessionUnavailable() {
player.setPlayer(newPlayer = localPlayer)
Expand Down Expand Up @@ -254,26 +262,7 @@ class StreamService :
session: MediaSession,
controller: MediaSession.ControllerInfo
): MediaSession.ConnectionResult {
if (controller.packageName == "com.google.android.projection.gearhead" &&
player.playbackState == STATE_IDLE
) {
// If there is a last played stream, preload the item in Android Auto
serviceScope.launch {
val lastPlayedId = getLastPlayedId()
if (lastPlayedId != null) {
val content = streamLibrary.streams.first()
content.find { it.id == lastPlayedId }?.toMediaItem()?.run {
withContext(Dispatchers.Main) {
player.setMediaItem(this@run)
player.prepare()
}
}
}
}
}

val result = super.onConnect(session, controller)

val sessionCommands = result.availableSessionCommands
.buildUpon()
.add(SessionCommand(START_TIMER_COMMAND, Bundle()))
Expand Down Expand Up @@ -315,55 +304,60 @@ class StreamService :
}
}

override fun onAddMediaItems(
override fun onSetMediaItems(
mediaSession: MediaSession,
controller: MediaSession.ControllerInfo,
mediaItems: MutableList<MediaItem>
): ListenableFuture<MutableList<MediaItem>> {
// There are a couple of issues with media3:
// Firstly when the [MediaController] in [AndroidStreamManager] adds media items this
// hook gets called. As a security measure content URI's get removed before the [MediaItem]s
// reach the [MediaSession]. We have to fill these URI's again.
//
// Also when the [MediaController] used by Android Auto selects a new track
// this method is called with only one item (the selected one), the rest of the queue
// is dropped for some reason. his is a known problem,
// See: https:/androidx/media/issues/156 and https:/androidx/media/issues/236
// To solve both these problems we check the [MediaItems]s here and replace them with the
// Known items in our repository. In the case of Android Auto we use the whole list instead
// of having a queue with a single item.
mediaItems: MutableList<MediaItem>,
startIndex: Int,
startPositionMs: Long
): ListenableFuture<MediaItemsWithStartPosition> {
return serviceScope.future {
val streams = streamLibrary
.browsableContent
.first()
val contentTree = contentTree.await()
if (mediaItems.size == 1) {
val singleItem = mediaItems[0]
if (singleItem.mediaId.isBlank() &&
singleItem.requestMetadata.searchQuery != null
) {
// User has preformed a voice search in Android Auto
streams.search(query = singleItem.requestMetadata.searchQuery)
val itemId = singleItem.mediaId
if (itemId.isBlank() && singleItem.requestMetadata.searchQuery != null) {
// Voice search -> return search results
val streams = contentTree
.search(query = singleItem.requestMetadata.searchQuery)
.toMutableList()
MediaItemsWithStartPosition(streams, startIndex, startPositionMs)
} else {
// User has selected an item in Android Auto
// It is expected behavior, but might get solved in the future
// That the rest of the queue is removed by Android Auto
// So we have to recreate the queue with the selected item in front
streams
.getAllPlayableItems()
.toMutableList()
.apply { moveToFront { it.mediaId == singleItem.mediaId } }
// Selected item in Android Auto, whole list gets dropped (bug)
// so -> recreate items with correct starting index of selected item
// see: https:/androidx/media/issues/156 and 236
val streams = contentTree.getAllPlayableItems().toMutableList()
val index = streams.indexOfFirst { it.mediaId == itemId }
MediaItemsWithStartPosition(streams, index, startPositionMs)
}
} else {
// Just use the [MediaItem] from the content library since the URI exists there
val allContent = streams.getAllPlayableItems()
mediaItems.map { mediaItem ->
allContent.find { it.mediaId == mediaItem.mediaId }!!
// normal cases -> map to content tree for usable URIs
// because they get stripped for IPC safety
val streams = contentTree.getAllPlayableItems()
val mappedStreams = mediaItems.map { mediaItem ->
streams.find { it.mediaId == mediaItem.mediaId }!!
}.toMutableList()
MediaItemsWithStartPosition(mappedStreams, startIndex, startPositionMs)
}
}
}

override fun onPlaybackResumption(
mediaSession: MediaSession,
controller: MediaSession.ControllerInfo
): ListenableFuture<MediaItemsWithStartPosition> {
return serviceScope.future {
val content = contentTree.await()
val streams = content.getAllPlayableItems()
val lastPlayedStream = content.getLastPlayed(lastPlayedId = getLastPlayedId()!!)
MediaItemsWithStartPosition(
/* mediaItems */ streams.toMutableList(),
/* startIndex */streams.indexOf(lastPlayedStream),
/* startPositionMs */ 0L
)
}
}

@SuppressLint("ObsoleteSdkInt")
private fun initialize() {
localPlayer = ExoPlayer.Builder(this)
Expand Down
17 changes: 9 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ buildscript {

//google
ext.google_cast_version = '21.3.0'
ext.material_version = '1.8.0'
ext.material_version = '1.9.0'

//kotlin
ext.kotlin_version = '1.7.10'
Expand All @@ -14,13 +14,13 @@ buildscript {
ext.kotlinx_guava_version = '1.6.4'

//androidx
ext.androidx_media_router_version = '1.3.1'
ext.androidx_media_router_version = '1.4.0'
ext.androidx_app_compat_version = '1.6.1'
ext.androidx_activity_version = '1.6.1'
ext.androidx_core_version = '1.9.0'
ext.androidx_lifecycle_version = '2.5.1'
ext.androidx_navigation_version = '2.5.3'
ext.androidx_media3_version = '1.0.1'
ext.androidx_activity_version = '1.7.2'
ext.androidx_core_version = '1.10.1'
ext.androidx_lifecycle_version = '2.6.1'
ext.androidx_navigation_version = '2.6.0'
ext.androidx_media3_version = '1.1.0-rc01'
ext.androidx_compose_version = '1.3.1'
ext.androidx_compose_material3_version = '1.0.1'

Expand All @@ -37,6 +37,7 @@ buildscript {
//misc
ext.landscapist_glide_version = '1.4.5'
ext.lottie_version = '4.2.2'
ext.vico_version = '1.6.5'

//test
ext.junit_version = "4.13.2"
Expand All @@ -56,7 +57,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.1'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
Expand Down

0 comments on commit 9500be6

Please sign in to comment.