fix: update MediaItems after network change

This commit is contained in:
pca006132 2025-11-02 16:37:01 +08:00
parent 9930537486
commit 4b7f60bb8c
4 changed files with 137 additions and 2 deletions

View file

@ -5,18 +5,20 @@ import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.TaskStackBuilder
import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.media3.common.*
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.DefaultLoadControl
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.MediaSource
import androidx.media3.exoplayer.source.TrackGroupArray
import androidx.media3.exoplayer.trackselection.TrackSelectionArray
import androidx.media3.session.*
import androidx.media3.session.MediaSession.ControllerInfo
import com.cappielloantonio.tempo.R
@ -43,6 +45,7 @@ class MediaService : MediaLibraryService() {
private lateinit var mediaLibrarySession: MediaLibrarySession
private lateinit var shuffleCommands: List<CommandButton>
private lateinit var repeatCommands: List<CommandButton>
private lateinit var networkCallback: CustomNetworkCallback
lateinit var equalizerManager: EqualizerManager
private var customLayout = ImmutableList.of<CommandButton>()
@ -81,6 +84,38 @@ class MediaService : MediaLibraryService() {
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
}
fun updateMediaItems() {
Log.d("MediaService", "update items");
val n = player.mediaItemCount
val k = player.currentMediaItemIndex
val current = player.currentPosition
val items = (0 .. n-1).map{i -> MappingUtil.mapMediaItem(player.getMediaItemAt(i))}
player.clearMediaItems()
player.setMediaItems(items, k, current)
}
inner class CustomNetworkCallback : ConnectivityManager.NetworkCallback() {
var wasWifi = false
init {
val manager = getSystemService(ConnectivityManager::class.java)
val network = manager.activeNetwork
val capabilities = manager.getNetworkCapabilities(network)
if (capabilities != null)
wasWifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
}
override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) {
val isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
if (isWifi != wasWifi) {
wasWifi = isWifi
widgetUpdateHandler.post(Runnable {
updateMediaItems()
})
}
}
}
override fun onCreate() {
super.onCreate()
@ -90,6 +125,7 @@ class MediaService : MediaLibraryService() {
restorePlayerFromQueue()
initializePlayerListener()
initializeEqualizerManager()
initializeNetworkListener()
setPlayer(player)
}
@ -99,6 +135,7 @@ class MediaService : MediaLibraryService() {
}
override fun onDestroy() {
releaseNetworkCallback()
equalizerManager.release()
stopWidgetUpdates()
releasePlayer()
@ -275,6 +312,12 @@ class MediaService : MediaLibraryService() {
}
}
private fun initializeNetworkListener() {
networkCallback = CustomNetworkCallback()
getSystemService(ConnectivityManager::class.java).registerDefaultNetworkCallback(networkCallback)
updateMediaItems()
}
private fun restorePlayerFromQueue() {
if (player.mediaItemCount > 0) return
@ -398,6 +441,10 @@ class MediaService : MediaLibraryService() {
mediaLibrarySession.release()
}
private fun releaseNetworkCallback() {
getSystemService(ConnectivityManager::class.java).unregisterNetworkCallback(networkCallback)
}
@SuppressLint("PrivateResource")
private fun getShuffleCommandButton(sessionCommand: SessionCommand): CommandButton {
val isOn = sessionCommand.customAction == CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON

View file

@ -115,6 +115,22 @@ public class MappingUtil {
.build();
}
public static MediaItem mapMediaItem(MediaItem old) {
Uri uri = old.requestMetadata.mediaUri == null ? null : MusicUtil.updateStreamUri(old.requestMetadata.mediaUri);
return new MediaItem.Builder()
.setMediaId(old.mediaId)
.setMediaMetadata(old.mediaMetadata)
.setRequestMetadata(
new MediaItem.RequestMetadata.Builder()
.setMediaUri(uri)
.setExtras(old.requestMetadata.extras)
.build()
)
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
.setUri(uri)
.build();
}
public static List<MediaItem> mapDownloads(List<Child> items) {
ArrayList<MediaItem> downloads = new ArrayList<>();

View file

@ -21,11 +21,16 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class MusicUtil {
private static final String TAG = "MusicUtil";
private static final Pattern BITRATE_PATTERN = Pattern.compile("&maxBitRate=\\d+");
private static final Pattern FORMAT_PATTERN = Pattern.compile("&format=\\w+");
public static Uri getStreamUri(String id) {
Map<String, String> params = App.getSubsonicClientInstance(false).getParams();
@ -61,6 +66,24 @@ public class MusicUtil {
return Uri.parse(uri.toString());
}
public static Uri updateStreamUri(Uri uri) {
String s = uri.toString();
Matcher m1 = BITRATE_PATTERN.matcher(s);
s = m1.replaceAll("");
Matcher m2 = FORMAT_PATTERN.matcher(s);
s = m2.replaceAll("");
s = s.replace("&estimateContentLength=true", "");
if (!Preferences.isServerPrioritized())
s += "&maxBitRate=" + getBitratePreference();
if (!Preferences.isServerPrioritized())
s += "&format=" + getTranscodingFormatPreference();
if (Preferences.askForEstimateContentLength())
s += "&estimateContentLength=true";
return Uri.parse(s);
}
public static Uri getDownloadUri(String id) {
StringBuilder uri = new StringBuilder();

View file

@ -4,10 +4,14 @@ import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.TaskStackBuilder
import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Binder
import android.os.IBinder
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.media3.cast.CastPlayer
import androidx.media3.cast.SessionAvailabilityListener
@ -43,6 +47,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
private lateinit var castPlayer: CastPlayer
private lateinit var mediaLibrarySession: MediaLibrarySession
private lateinit var librarySessionCallback: MediaLibrarySessionCallback
private lateinit var networkCallback: CustomNetworkCallback
lateinit var equalizerManager: EqualizerManager
inner class LocalBinder : Binder() {
@ -69,6 +74,38 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
}
}
fun updateMediaItems() {
Log.d("MediaService", "update items");
val n = player.mediaItemCount
val k = player.currentMediaItemIndex
val current = player.currentPosition
val items = (0 .. n-1).map{i -> MappingUtil.mapMediaItem(player.getMediaItemAt(i))}
player.clearMediaItems()
player.setMediaItems(items, k, current)
}
inner class CustomNetworkCallback : ConnectivityManager.NetworkCallback() {
var wasWifi = false
init {
val manager = getSystemService(ConnectivityManager::class.java)
val network = manager.activeNetwork
val capabilities = manager.getNetworkCapabilities(network)
if (capabilities != null)
wasWifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
}
override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) {
val isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
if (isWifi != wasWifi) {
wasWifi = isWifi
widgetUpdateHandler.post(Runnable {
updateMediaItems()
})
}
}
}
override fun onCreate() {
super.onCreate()
@ -79,6 +116,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
initializePlayerListener()
initializeCastPlayer()
initializeEqualizerManager()
initializeNetworkListener()
setPlayer(
null,
@ -99,6 +137,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
}
override fun onDestroy() {
releaseNetworkCallback()
equalizerManager.release()
stopWidgetUpdates()
releasePlayer()
@ -178,6 +217,12 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
.build()
}
private fun initializeNetworkListener() {
networkCallback = CustomNetworkCallback()
getSystemService(ConnectivityManager::class.java).registerDefaultNetworkCallback(networkCallback)
updateMediaItems()
}
private fun restorePlayerFromQueue() {
if (player.mediaItemCount > 0) return
@ -374,6 +419,10 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
automotiveRepository.deleteMetadata()
}
private fun releaseNetworkCallback() {
getSystemService(ConnectivityManager::class.java).unregisterNetworkCallback(networkCallback)
}
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
override fun onCastSessionAvailable() {