diff --git a/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt b/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt
index 57fda35aa40a79821363ed7ba3bf0067ad9ab14c..cbfe36f28918148633843d3a846fc53ed3435f3a 100644
--- a/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt
+++ b/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt
@@ -839,13 +839,9 @@ fun Route.setupRouting(appContext: Context, scope: CoroutineScope) {
                 call.respond(HttpStatusCode.Forbidden)
                 return@get
             }
-            val networkShares = RemoteAccessServer.getInstance(appContext).networkSharesLiveData.getList()
-            val list = ArrayList<RemoteAccessServer.PlayQueueItem>(networkShares.size)
-            networkShares.forEachIndexed { index, mediaLibraryItem ->
-                list.add(RemoteAccessServer.PlayQueueItem(3000L + index, mediaLibraryItem.title, " ", 0, mediaLibraryItem.artworkMrl
-                        ?: "", false, "", (mediaLibraryItem as MediaWrapper).uri.toString(), true, favorite = mediaLibraryItem.isFavorite))
-            }
-            call.respondJson(convertToJson(list))
+            RemoteAccessServer.getInstance(appContext).launchNetworkDiscovery()
+            //No response are the result are asynchronous and sent back using websockets / long polling
+            call.respondJson("")
         }
         get("/stream-list") {
             verifyLogin(settings)
diff --git a/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessServer.kt b/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessServer.kt
index b52bd29aa204a32a152385d47cbdadab702d5eb8..f79545101914f409c5b32c2e457a7f7dbb3d8586 100644
--- a/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessServer.kt
+++ b/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessServer.kt
@@ -29,6 +29,9 @@ import android.content.Context
 import android.content.SharedPreferences
 import android.media.AudioManager
 import android.net.Uri
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.Process
 import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
@@ -77,6 +80,8 @@ import kotlinx.coroutines.CoroutineExceptionHandler
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onCompletion
 import kotlinx.coroutines.flow.onEach
@@ -93,31 +98,31 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
 import org.slf4j.LoggerFactory
 import org.videolan.libvlc.MediaPlayer
 import org.videolan.libvlc.interfaces.IMedia
+import org.videolan.libvlc.util.MediaBrowser
+import org.videolan.medialibrary.MLServiceLocator
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
 import org.videolan.medialibrary.media.MediaLibraryItem
+import org.videolan.resources.VLCInstance
 import org.videolan.tools.AppScope
 import org.videolan.tools.KEYSTORE_PASSWORD
 import org.videolan.tools.KEY_REMOTE_ACCESS_LAST_STATE_STOPPED
-import org.videolan.tools.NetworkMonitor
 import org.videolan.tools.REMOTE_ACCESS_NETWORK_BROWSER_CONTENT
 import org.videolan.tools.Settings
 import org.videolan.tools.SingletonHolder
-import org.videolan.tools.livedata.LiveDataset
 import org.videolan.tools.putSingle
 import org.videolan.vlc.PlaybackService
 import org.videolan.vlc.PlaybackService.Companion.playerSleepTime
 import org.videolan.vlc.gui.DialogActivity
 import org.videolan.vlc.media.PlaylistManager
-import org.videolan.vlc.providers.NetworkProvider
+import org.videolan.vlc.remoteaccessserver.ssl.SecretGenerator
+import org.videolan.vlc.remoteaccessserver.websockets.RemoteAccessWebSockets
+import org.videolan.vlc.remoteaccessserver.websockets.RemoteAccessWebSockets.setupWebSockets
 import org.videolan.vlc.util.FileUtils
 import org.videolan.vlc.util.isSchemeSMB
 import org.videolan.vlc.viewmodels.CallBackDelegate
 import org.videolan.vlc.viewmodels.ICallBackHandler
 import org.videolan.vlc.viewmodels.browser.IPathOperationDelegate
 import org.videolan.vlc.viewmodels.browser.PathOperationDelegate
-import org.videolan.vlc.remoteaccessserver.ssl.SecretGenerator
-import org.videolan.vlc.remoteaccessserver.websockets.RemoteAccessWebSockets
-import org.videolan.vlc.remoteaccessserver.websockets.RemoteAccessWebSockets.setupWebSockets
 import java.io.File
 import java.math.BigInteger
 import java.net.InetAddress
@@ -133,6 +138,7 @@ import java.time.Duration
 import java.util.Calendar
 import java.util.Collections
 import java.util.Locale
+import java.util.concurrent.atomic.AtomicBoolean
 
 
 private const val TAG = "VLC/HttpSharingServer"
@@ -144,7 +150,8 @@ class RemoteAccessServer(private val context: Context) : PlaybackService.Callbac
     private var settings: SharedPreferences
     private lateinit var engine: NettyApplicationEngine
     var service: PlaybackService? = null
-    val networkSharesLiveData = LiveDataset<MediaLibraryItem>()
+    private val networkSharesResult = ArrayList<MediaLibraryItem>()
+    private val networkDiscoveryRunning = AtomicBoolean(false)
 
 
     private val _serverStatus = MutableLiveData(ServerStatus.NOT_INIT)
@@ -164,6 +171,12 @@ class RemoteAccessServer(private val context: Context) : PlaybackService.Callbac
         }
     }
 
+    private val browserHandler by lazy {
+        val handlerThread = HandlerThread("vlc-provider-remote-access", Process.THREAD_PRIORITY_DEFAULT + Process.THREAD_PRIORITY_LESS_FAVORABLE)
+        handlerThread.start()
+        Handler(handlerThread.looper)
+    }
+
     /**
      * Observes the need to login (for the browser) and display a warning on the website
      */
@@ -221,19 +234,83 @@ class RemoteAccessServer(private val context: Context) : PlaybackService.Callbac
             engine = generateServer()
             engine.start()
         }
+    }
+
+    /**
+     * Launch a network discovery. It directly uses a dedicated [MediaBrowser] and doesn't instantiate a Provider
+     * It only launches once. It has a timeout. I sends the result back using websockets
+     *
+     */
+    fun launchNetworkDiscovery() = scope.launch(Dispatchers.IO) {
+        if (!settings.getBoolean(REMOTE_ACCESS_NETWORK_BROWSER_CONTENT, false)) {
+            Log.i(TAG, "Preventing the network monitor to be collected as the network browsing is disabled")
+            return@launch
+        }
+        if (networkDiscoveryRunning.getAndSet(true)) {
+            //Already running only send current results
+            if (BuildConfig.DEBUG) Log.w(TAG, "Already running")
+            sendNetworkShares()
+            return@launch
+        }
+        val job = launch {
+            var finished = false
+            networkSharesResult.clear()
+            val mediaBrowser = MediaBrowser(VLCInstance.getInstance(context), object : MediaBrowser.EventListener {
+                override fun onMediaAdded(index: Int, media: IMedia?) {
+                    try {
+                        MLServiceLocator.getAbstractMediaWrapper(media)
+                    } catch (e: Exception) {
+                        Log.e(TAG, "Unable to generate the media wrapper. It usually happen when the IMedia fields have some encoding issues", e)
+                        null
+                    }?.let {
+                        scope.launch(Dispatchers.Main) {
+                            networkSharesResult.add(it)
+                            sendNetworkShares()
+                        }
+                    }
+                    media?.release()
+                }
+
+                override fun onMediaRemoved(index: Int, media: IMedia?) {}
 
-        withContext(Dispatchers.Main) {
-            if (!settings.getBoolean(REMOTE_ACCESS_NETWORK_BROWSER_CONTENT, false)) {
-                Log.i(TAG, "Preventing the network monitor to be collected as the network browsing is disabled")
-                return@withContext
+                override fun onBrowseEnd() {
+                    if (BuildConfig.DEBUG) Log.i(TAG, "Discovery is finished")
+                    finished = true
+                }
+
+            }, browserHandler)
+            try {
+                mediaBrowser.discoverNetworkShares()
+                while (!finished) {
+                    delay(1000)
+                }
+            } finally {
+                if (BuildConfig.DEBUG) Log.i(TAG, "Discovery job releasing everything")
+                mediaBrowser.changeEventListener(null)
+                mediaBrowser.release()
+                sendNetworkShares()
             }
-            //keep track of the network shares as they are highly asynchronous
-            val provider = NetworkProvider(context, networkSharesLiveData, null)
-            NetworkMonitor.getInstance(context).connectionFlow.onEach {
-                if (it.connected) provider.refresh()
-                else networkSharesLiveData.clear()
-            }.launchIn(AppScope)
         }
+        // The discovery job is 30s max
+        delay(30000L)
+        if (BuildConfig.DEBUG) Log.i(TAG, "Discovery job timer exhausted")
+        job.cancelAndJoin()
+        if (BuildConfig.DEBUG) Log.i(TAG, "Discovery job quit")
+        networkDiscoveryRunning.set(false)
+    }
+
+    private suspend fun sendNetworkShares() {
+        if (BuildConfig.DEBUG) Log.i(TAG, "Sending network shares: ${networkSharesResult.size}")
+        val list = ArrayList<PlayQueueItem>(networkSharesResult.size)
+        networkSharesResult.forEachIndexed { index, mediaLibraryItem ->
+            list.add(
+                PlayQueueItem(
+                    3000L + index, mediaLibraryItem.title, " ", 0, mediaLibraryItem.artworkMrl
+                        ?: "", false, "", (mediaLibraryItem as MediaWrapper).uri.toString(), true, favorite = mediaLibraryItem.isFavorite
+                )
+            )
+        }
+        RemoteAccessWebSockets.sendToAll(NetworkShares(list))
     }
 
     /**
@@ -789,7 +866,7 @@ class RemoteAccessServer(private val context: Context) : PlaybackService.Callbac
         val list: MutableList<Pair<String, String>> = mutableListOf()
         if (isOtg) list.add(Pair(otgDevice, "root"))
         if (uri.scheme.isSchemeSMB()) {
-            networkSharesLiveData.getList().forEach {
+            networkSharesResult.forEach {
                 (it as? MediaWrapper)?.let { share ->
                     if (share.uri.scheme == uri.scheme && share.uri.authority == uri.authority) {
                         list.add(Pair(share.title, Uri.Builder().scheme(uri.scheme).encodedAuthority(uri.authority).build().toString()))
@@ -836,6 +913,7 @@ class RemoteAccessServer(private val context: Context) : PlaybackService.Callbac
     data class MLRefreshNeeded(val refreshNeeded: Boolean = true) : WSMessage(WSMessageType.ML_REFRESH_NEEDED)
     data class BrowserDescription(val path: String, val description: String) : WSMessage(WSMessageType.BROWSER_DESCRIPTION)
     data class PlaybackControlForbidden(val forbidden: Boolean = true): WSMessage(WSMessageType.PLAYBACK_CONTROL_FORBIDDEN)
+    data class NetworkShares(val shares: List<PlayQueueItem>): WSMessage(WSMessageType.NETWORK_SHARES)
     data class SearchResults(val albums: List<PlayQueueItem>, val artists: List<PlayQueueItem>, val genres: List<PlayQueueItem>, val playlists: List<PlayQueueItem>, val videos: List<PlayQueueItem>, val tracks: List<PlayQueueItem>)
     data class BreadcrumbItem(val title: String, val path: String)
     data class BrowsingResult(val content: List<PlayQueueItem>, val breadcrumb: List<BreadcrumbItem>)
@@ -882,6 +960,8 @@ class RemoteAccessServer(private val context: Context) : PlaybackService.Callbac
         @Json(name = "browser-description")
         BROWSER_DESCRIPTION,
         @Json(name = "playback-control-forbidden")
-        PLAYBACK_CONTROL_FORBIDDEN
+        PLAYBACK_CONTROL_FORBIDDEN,
+        @Json(name = "network-shares")
+        NETWORK_SHARES
     }
 }
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index e0dae3f9233d3c9fe139499f1675b8e249ec306b..86efff9a624bd7e62bedc0886e41bdfa581a4b52 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,7 +42,7 @@ ext {
     versionCode = 3060300
     versionName = project.hasProperty('forceVlc4') && project.getProperty('forceVlc4') ? '4.0.0-preview - ' + versionCode : '3.6.3'
     vlcMajorVersion = project.hasProperty('forceVlc4') && project.getProperty('forceVlc4') ? 4 : 3
-    remoteAccessVersion = '0.2.0'
+    remoteAccessVersion = '0.3.0'
     libvlcVersion = vlcMajorVersion == 3 ? '3.6.0' :'4.0.0-eap18'
     medialibraryVersion = vlcMajorVersion == 3 ? '0.13.13-rc15' : '0.13.13-vlc4-rc15'
     minSdkVersion = 17
diff --git a/buildsystem/compile-remoteaccess.sh b/buildsystem/compile-remoteaccess.sh
index cb09402a45e998799d0fb036a2d52d7ccbdc8b52..884380615f0eeed3deda50c78b59fff974624f36 100755
--- a/buildsystem/compile-remoteaccess.sh
+++ b/buildsystem/compile-remoteaccess.sh
@@ -57,7 +57,7 @@ done
 ##############################
   diagnostic "Setting up the Remote Access project"
 
-  REMOTE_ACCESS_TESTED_HASH=543dcf36610e6944c85cbf355b4b934b8ae451d3
+  REMOTE_ACCESS_TESTED_HASH=4c400ef0dbac2ba23606af4bf0d11e3f05807eb7
   REMOTE_ACCESS_REPOSITORY=https://code.videolan.org/videolan/remoteaccess
 
   : ${VLC_REMOTE_ACCESS_PATH:="$(pwd -P)/application/remote-access-client/remoteaccess"}