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.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.TaskStackBuilder import android.app.TaskStackBuilder
import android.content.Intent import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Binder import android.os.Binder
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log
import androidx.media3.common.* import androidx.media3.common.*
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.DefaultLoadControl import androidx.media3.exoplayer.DefaultLoadControl
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.MediaSource 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.*
import androidx.media3.session.MediaSession.ControllerInfo import androidx.media3.session.MediaSession.ControllerInfo
import com.cappielloantonio.tempo.R import com.cappielloantonio.tempo.R
@ -43,6 +45,7 @@ class MediaService : MediaLibraryService() {
private lateinit var mediaLibrarySession: MediaLibrarySession private lateinit var mediaLibrarySession: MediaLibrarySession
private lateinit var shuffleCommands: List<CommandButton> private lateinit var shuffleCommands: List<CommandButton>
private lateinit var repeatCommands: List<CommandButton> private lateinit var repeatCommands: List<CommandButton>
private lateinit var networkCallback: CustomNetworkCallback
lateinit var equalizerManager: EqualizerManager lateinit var equalizerManager: EqualizerManager
private var customLayout = ImmutableList.of<CommandButton>() private var customLayout = ImmutableList.of<CommandButton>()
@ -81,6 +84,38 @@ class MediaService : MediaLibraryService() {
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER" 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() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -90,6 +125,7 @@ class MediaService : MediaLibraryService() {
restorePlayerFromQueue() restorePlayerFromQueue()
initializePlayerListener() initializePlayerListener()
initializeEqualizerManager() initializeEqualizerManager()
initializeNetworkListener()
setPlayer(player) setPlayer(player)
} }
@ -99,6 +135,7 @@ class MediaService : MediaLibraryService() {
} }
override fun onDestroy() { override fun onDestroy() {
releaseNetworkCallback()
equalizerManager.release() equalizerManager.release()
stopWidgetUpdates() stopWidgetUpdates()
releasePlayer() releasePlayer()
@ -275,6 +312,12 @@ class MediaService : MediaLibraryService() {
} }
} }
private fun initializeNetworkListener() {
networkCallback = CustomNetworkCallback()
getSystemService(ConnectivityManager::class.java).registerDefaultNetworkCallback(networkCallback)
updateMediaItems()
}
private fun restorePlayerFromQueue() { private fun restorePlayerFromQueue() {
if (player.mediaItemCount > 0) return if (player.mediaItemCount > 0) return
@ -398,6 +441,10 @@ class MediaService : MediaLibraryService() {
mediaLibrarySession.release() mediaLibrarySession.release()
} }
private fun releaseNetworkCallback() {
getSystemService(ConnectivityManager::class.java).unregisterNetworkCallback(networkCallback)
}
@SuppressLint("PrivateResource") @SuppressLint("PrivateResource")
private fun getShuffleCommandButton(sessionCommand: SessionCommand): CommandButton { private fun getShuffleCommandButton(sessionCommand: SessionCommand): CommandButton {
val isOn = sessionCommand.customAction == CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON val isOn = sessionCommand.customAction == CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON

View file

@ -115,6 +115,22 @@ public class MappingUtil {
.build(); .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) { public static List<MediaItem> mapDownloads(List<Child> items) {
ArrayList<MediaItem> downloads = new ArrayList<>(); ArrayList<MediaItem> downloads = new ArrayList<>();

View file

@ -21,11 +21,16 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class MusicUtil { public class MusicUtil {
private static final String TAG = "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) { public static Uri getStreamUri(String id) {
Map<String, String> params = App.getSubsonicClientInstance(false).getParams(); Map<String, String> params = App.getSubsonicClientInstance(false).getParams();
@ -61,6 +66,24 @@ public class MusicUtil {
return Uri.parse(uri.toString()); 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) { public static Uri getDownloadUri(String id) {
StringBuilder uri = new StringBuilder(); 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.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.TaskStackBuilder import android.app.TaskStackBuilder
import android.content.Intent import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Binder import android.os.Binder
import android.os.IBinder import android.os.IBinder
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.media3.cast.CastPlayer import androidx.media3.cast.CastPlayer
import androidx.media3.cast.SessionAvailabilityListener import androidx.media3.cast.SessionAvailabilityListener
@ -43,6 +47,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
private lateinit var castPlayer: CastPlayer private lateinit var castPlayer: CastPlayer
private lateinit var mediaLibrarySession: MediaLibrarySession private lateinit var mediaLibrarySession: MediaLibrarySession
private lateinit var librarySessionCallback: MediaLibrarySessionCallback private lateinit var librarySessionCallback: MediaLibrarySessionCallback
private lateinit var networkCallback: CustomNetworkCallback
lateinit var equalizerManager: EqualizerManager lateinit var equalizerManager: EqualizerManager
inner class LocalBinder : Binder() { 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() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -79,6 +116,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
initializePlayerListener() initializePlayerListener()
initializeCastPlayer() initializeCastPlayer()
initializeEqualizerManager() initializeEqualizerManager()
initializeNetworkListener()
setPlayer( setPlayer(
null, null,
@ -99,6 +137,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
} }
override fun onDestroy() { override fun onDestroy() {
releaseNetworkCallback()
equalizerManager.release() equalizerManager.release()
stopWidgetUpdates() stopWidgetUpdates()
releasePlayer() releasePlayer()
@ -178,6 +217,12 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
.build() .build()
} }
private fun initializeNetworkListener() {
networkCallback = CustomNetworkCallback()
getSystemService(ConnectivityManager::class.java).registerDefaultNetworkCallback(networkCallback)
updateMediaItems()
}
private fun restorePlayerFromQueue() { private fun restorePlayerFromQueue() {
if (player.mediaItemCount > 0) return if (player.mediaItemCount > 0) return
@ -374,6 +419,10 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
automotiveRepository.deleteMetadata() automotiveRepository.deleteMetadata()
} }
private fun releaseNetworkCallback() {
getSystemService(ConnectivityManager::class.java).unregisterNetworkCallback(networkCallback)
}
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false) private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
override fun onCastSessionAvailable() { override fun onCastSessionAvailable() {