more robust chromecast discovery
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 1 Aug 2019 09:29:12 +0000 (11:29 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 1 Aug 2019 09:29:12 +0000 (11:29 +0200)
force 1.5 version of vuetify
implement periodic scan for chromecast devices to catch disconnections and group leader changes

music_assistant/modules/playerproviders/chromecast.py
music_assistant/web/index.html
music_assistant/web/pages/config.vue.js

index 1e29add3b33908d69bfd227a8b601f60b6955c4c..6e1898bbbac60be4390ac3a52e2c92a555bb5abf 100644 (file)
@@ -50,7 +50,7 @@ class ChromecastProvider(PlayerProvider):
         self._player_queue_index = {}
         self._player_queue_stream_startindex = {}
         self.supported_musicproviders = ['http']
-        self.__chromecast_discovery()
+        self.mass.event_loop.create_task(self.__chromecast_discovery())
         
     ### Provider specific implementation #####
 
@@ -388,36 +388,45 @@ class ChromecastProvider(PlayerProvider):
                     self._players[member].group_parent = str(mz._uuid)
                     self.mass.event_loop.create_task(self.mass.player.update_player(self._players[member]))
     
-    def __chromecast_discovery(self):
+    @run_periodic(300)
+    async def __chromecast_discovery(self):
         ''' background non-blocking chromecast discovery and handler '''
+        # remove any disconnected players...
+        removed_players = []
+        for player_id, cast in self._chromecasts.items():
+            if not cast.socket_client.is_connected:
+                LOGGER.info("%s is disconnected" % cast.name)
+                removed_players.append(player_id)
+        for player_id in removed_players:
+            self._chromecasts[player_id].socket_client.stop.set()
+            self._chromecasts.pop(player_id, None)
+            await self.mass.player.remove_player(player_id)
+        await asyncio.sleep(5)
+        # search for available chromecasts
         from pychromecast.discovery import start_discovery, stop_discovery
-        def internal_callback(name):
-            """Called when zeroconf has discovered a new chromecast."""
-            asyncio.run_coroutine_threadsafe(
-                    self.__chromecast_discovered(listener.services[name]), self.mass.event_loop)
-        def internal_stop(msg=None, msg_details=None):
-            """Stops discovery of new chromecasts."""
-            LOGGER.info('stopping Chromecast discovery...')
-            stop_discovery(browser)
-        listener, browser = start_discovery(internal_callback)
-        self.mass.add_event_listener(internal_stop, 'system_shutdown')
+        def discovered_callback(name):
+            """Called when zeroconf has discovered a (new) chromecast."""
+            discovery_info = listener.services[name]
+            ip_address, port, uuid, model_name, friendly_name = discovery_info
+            player_id = str(uuid)
+            if not player_id in self._chromecasts:
+                LOGGER.info("discovered chromecast: %s - %s:%s" % (friendly_name, ip_address, port))
+                asyncio.run_coroutine_threadsafe(
+                        self.__chromecast_discovered(player_id, discovery_info), self.mass.event_loop)
+        LOGGER.debug("Chromecast discovery started...")
+        listener, browser = start_discovery(discovered_callback)
+        await asyncio.sleep(15) # run discovery for 15 seconds
+        stop_discovery(browser)
+        LOGGER.debug("Chromecast discovery completed...")
     
-    async def __chromecast_discovered(self, discovery_info):
+    async def __chromecast_discovered(self, player_id, discovery_info):
         ''' callback when a (new) chromecast device is discovered '''
-        ip_address, port, uuid, model_name, friendly_name = discovery_info
-        player_id = str(uuid)
-        if player_id in self._chromecasts:
-            # cleanup old object
-            self._chromecasts[player_id].socket_client.stop.set()
-            await asyncio.sleep(1)
-            self._chromecasts.pop(player_id, None)
         from pychromecast import _get_chromecast_from_host, ChromecastConnectionError
         try:
-            chromecast = _get_chromecast_from_host(discovery_info)
+            chromecast = _get_chromecast_from_host(discovery_info, tries=2, retry_wait=5)
         except ChromecastConnectionError:
-            LOGGER.warning("Could not connect to device")
+            LOGGER.warning("Could not connect to device %s" % player_id)
             return
-        LOGGER.info("discovered chromecast: %s - %s:%s" % (friendly_name, ip_address, port))
         if not player_id in self._players:
             player = MusicPlayer()
             player.player_id = player_id
index 0584f5c4d4ccba8da07d60c11ed0b3d082043cbb..5855510547b5ebb699a65bf0910caf98bdced9f4 100755 (executable)
@@ -5,7 +5,7 @@
         <meta charset="utf-8" />
         <title>Music Assistant</title>
         <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
-        <link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
+        <link href="https://cdn.jsdelivr.net/npm/vuetify@1.5.16/dist/vuetify.min.css" rel="stylesheet">
         <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
         <link rel="icon" href="./images/icons/icon-256x256.png">
         <link rel="manifest" href="./manifest.json">
@@ -32,7 +32,7 @@
 
         <script src="https://unpkg.com/vue/dist/vue.js"></script>
         <script src="https://unpkg.com/vue-i18n/dist/vue-i18n.js"></script>
-        <script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
+        <script src="https://cdn.jsdelivr.net/npm/vuetify@1.5.16/dist/vuetify.min.js"></script>
         <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
         <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
         <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
index 3fd24a1e5cb65037a3ce25a64903059bbd437fa9..c4164db2dae1d9e99fc503e1520ae5a60cee3499 100755 (executable)
@@ -104,7 +104,7 @@ var Config = Vue.component('Config', {
             this.saveConfig();
             this.$toasted.show(this.$t('conf.conf_saved'))
           }
-        }, 1000),
+        }, 5000),
         deep: true
     }
   },