[Android] Fix the upnp service discover crashing when browsing while the remote access is running

Nicolas Pomepuy git at videolan.org
Fri Dec 6 11:11:58 UTC 2024


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Wed Dec  4 14:09:40 2024 +0100| [4702f6951534445c711e77774426632d4ed3bc8d] | committer: Duncan McNamara

Fix the upnp service discover crashing when browsing while the remote access is running

> https://code.videolan.org/videolan/vlc-android/commit/4702f6951534445c711e77774426632d4ed3bc8d
---

 .../org/videolan/vlc/providers/BrowserProvider.kt  | 12 +++++-
 .../org/videolan/vlc/providers/NetworkProvider.kt  | 44 ++++++++++++++++++++++
 2 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/providers/BrowserProvider.kt b/application/vlc-android/src/org/videolan/vlc/providers/BrowserProvider.kt
index bd7418cb44..5e5087660b 100644
--- a/application/vlc-android/src/org/videolan/vlc/providers/BrowserProvider.kt
+++ b/application/vlc-android/src/org/videolan/vlc/providers/BrowserProvider.kt
@@ -130,7 +130,7 @@ abstract class BrowserProvider(val context: Context, val dataset: LiveDataset<Me
                     mediabrowser?.release()
                 } catch (e: IllegalStateException) {
                 }
-                mediabrowser = null
+                cleanMediaBrowser()
             }
         }
     }
@@ -152,13 +152,21 @@ abstract class BrowserProvider(val context: Context, val dataset: LiveDataset<Me
                         mediabrowser?.release()
                     } catch (e: Exception) {
                     }
-                    mediabrowser = null
+                    cleanMediaBrowser()
                 }
                 is BrowseUrl -> action.deferred.complete(browseUrlImpl(action.url))
             }
         }
     }
 
+    /**
+     * Clean the media browser
+     *
+     */
+    open fun cleanMediaBrowser() {
+        mediabrowser = null
+    }
+
     protected open fun initBrowser() {
         if (mediabrowser == null) {
             registerCreator { MediaBrowser(VLCInstance.getInstance(context), null, browserHandler) }
diff --git a/application/vlc-android/src/org/videolan/vlc/providers/NetworkProvider.kt b/application/vlc-android/src/org/videolan/vlc/providers/NetworkProvider.kt
index 5dc5a73d1f..9562535403 100644
--- a/application/vlc-android/src/org/videolan/vlc/providers/NetworkProvider.kt
+++ b/application/vlc-android/src/org/videolan/vlc/providers/NetworkProvider.kt
@@ -24,18 +24,54 @@ import android.content.Context
 import androidx.core.net.toUri
 import androidx.lifecycle.Observer
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import org.videolan.libvlc.util.MediaBrowser
 import org.videolan.medialibrary.interfaces.Medialibrary
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
 import org.videolan.medialibrary.media.DummyItem
 import org.videolan.medialibrary.media.MediaLibraryItem
+import org.videolan.tools.AppScope
 import org.videolan.tools.NetworkMonitor
 import org.videolan.tools.livedata.LiveDataset
 import org.videolan.vlc.R
+import java.util.concurrent.atomic.AtomicBoolean
 
 class NetworkProvider(context: Context, dataset: LiveDataset<MediaLibraryItem>, url: String? = null): BrowserProvider(context, dataset, url, Medialibrary.SORT_FILENAME, false), Observer<List<MediaWrapper>> {
 
+    override fun initBrowser() {
+        if (alreadyRunning.getAndSet(true)) {
+            // Use the cached [MediaBrowser] instead of creating a new one
+            if (cachedMediaBrowser != null) {
+                mediabrowser = cachedMediaBrowser
+            } else {
+                AppScope.launch(Dispatchers.IO) {
+                    while (cachedMediaBrowser == null && alreadyRunning.get()) {
+                        delay(50)
+                    }
+                    if (alreadyRunning.get()) {
+                        mediabrowser = cachedMediaBrowser
+                    } else {
+                        super.initBrowser()
+                    }
+                }
+            }
+            return
+        }
+        super.initBrowser()
+        cachedMediaBrowser = mediabrowser
+    }
+
+    /**
+     * Also clean the cached [MediaBrowser]
+     *
+     */
+    override fun cleanMediaBrowser() {
+        super.cleanMediaBrowser()
+        cachedMediaBrowser = null
+        alreadyRunning.set(false)
+    }
 
     override suspend fun browseRootImpl() {
         dataset.clear()
@@ -101,4 +137,12 @@ class NetworkProvider(context: Context, dataset: LiveDataset<MediaLibraryItem>,
         }
         return null
     }
+
+    companion object {
+        // For network discovery, we don't want multiple [MediaBrowser] simultaneously running
+        // as it will spawn two service discovery that VLC cannot run simultaneously
+        // So we cache the [MediaBrowser] instance here and clean it when the [NetworkProvider] is cleared
+        var cachedMediaBrowser: MediaBrowser? = null
+        var alreadyRunning = AtomicBoolean(false)
+    }
 }
\ No newline at end of file



More information about the Android mailing list