]> git.basschouten.com Git - openhab-addons.git/commitdiff
[freeboxos] Fix start/stop audio sink (#17223)
authorlolodomo <lg.hc@free.fr>
Sat, 10 Aug 2024 09:45:55 +0000 (11:45 +0200)
committerGitHub <noreply@github.com>
Sat, 10 Aug 2024 09:45:55 +0000 (11:45 +0200)
* [freeboxos] Fix start/stop audio sink Fix #17208

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/ApiConsumerHandler.java
bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/HostHandler.java

index 7e85dec9b8729045f48c08ab3acb0d44686423dd..8a9ad3713f4060575072589bdcc4201214b8b50a 100644 (file)
@@ -87,40 +87,62 @@ public abstract class ApiConsumerHandler extends BaseThingHandler implements Api
         Map<String, String> properties = editProperties();
         try {
             initializeProperties(properties);
-            checkAirMediaCapabilities(properties);
             updateProperties(properties);
         } catch (FreeboxException e) {
             logger.warn("Error getting thing {} properties: {}", thing.getUID(), e.getMessage());
         }
 
-        boolean isAudioReceiver = Boolean.parseBoolean(properties.get(MediaType.AUDIO.name()));
-        if (isAudioReceiver) {
-            configureMediaSink(bridgeHandler, properties.getOrDefault(Source.UPNP.name(), ""));
-        }
-
         startRefreshJob();
     }
 
-    private void configureMediaSink(FreeboxOsHandler bridgeHandler, String upnpName) {
+    protected void configureMediaSink() {
         try {
+            String upnpName = editProperties().getOrDefault(Source.UPNP.name(), "");
             Receiver receiver = getManager(MediaReceiverManager.class).getReceiver(upnpName);
-            if (receiver != null && reg == null) {
-                ApiConsumerConfiguration config = getConfig().as(ApiConsumerConfiguration.class);
-                String callbackURL = bridgeHandler.getCallbackURL();
-                if (!config.password.isEmpty() || !receiver.passwordProtected()) {
-                    reg = bridgeHandler.getBundleContext().registerService(
-                            AudioSink.class.getName(), new AirMediaSink(this, bridgeHandler.getAudioHTTPServer(),
-                                    callbackURL, receiver.name(), config.password, config.acceptAllMp3),
-                            new Hashtable<>());
-                } else {
-                    logger.info("A password needs to be configured to enable Air Media capability.");
-                }
+            if (receiver != null) {
+                Map<String, String> properties = editProperties();
+                receiver.capabilities().entrySet()
+                        .forEach(entry -> properties.put(entry.getKey().name(), entry.getValue().toString()));
+                updateProperties(properties);
+
+                startAudioSink(receiver);
+            } else {
+                stopAudioSink();
             }
         } catch (FreeboxException e) {
             logger.warn("Unable to retrieve Media Receivers: {}", e.getMessage());
         }
     }
 
+    private void startAudioSink(Receiver receiver) {
+        FreeboxOsHandler bridgeHandler = checkBridgeHandler();
+        // Only video and photo is supported by the API so use VIDEO capability for audio
+        Boolean isAudioReceiver = receiver.capabilities().get(MediaType.VIDEO);
+        if (reg == null && bridgeHandler != null && isAudioReceiver != null && isAudioReceiver.booleanValue()) {
+            ApiConsumerConfiguration config = getConfig().as(ApiConsumerConfiguration.class);
+            String callbackURL = bridgeHandler.getCallbackURL();
+            if (!config.password.isEmpty() || !receiver.passwordProtected()) {
+                reg = bridgeHandler.getBundleContext()
+                        .registerService(
+                                AudioSink.class.getName(), new AirMediaSink(this, bridgeHandler.getAudioHTTPServer(),
+                                        callbackURL, receiver.name(), config.password, config.acceptAllMp3),
+                                new Hashtable<>());
+                logger.debug("Audio sink registered for {}.", receiver.name());
+            } else {
+                logger.warn("A password needs to be configured to enable Air Media capability.");
+            }
+        }
+    }
+
+    private void stopAudioSink() {
+        ServiceRegistration<?> localReg = reg;
+        if (localReg != null) {
+            localReg.unregister();
+            logger.debug("Audio sink unregistered");
+            reg = null;
+        }
+    }
+
     public <T extends RestManager> T getManager(Class<T> clazz) throws FreeboxException {
         FreeboxOsHandler handler = checkBridgeHandler();
         if (handler != null) {
@@ -159,15 +181,6 @@ public abstract class ApiConsumerHandler extends BaseThingHandler implements Api
         }
     }
 
-    private void checkAirMediaCapabilities(Map<String, String> properties) throws FreeboxException {
-        String upnpName = properties.getOrDefault(Source.UPNP.name(), "");
-        Receiver receiver = getManager(MediaReceiverManager.class).getReceiver(upnpName);
-        if (receiver != null) {
-            receiver.capabilities().entrySet()
-                    .forEach(entry -> properties.put(entry.getKey().name(), entry.getValue().toString()));
-        }
-    }
-
     private @Nullable FreeboxOsHandler checkBridgeHandler() {
         Bridge bridge = getBridge();
         if (bridge != null) {
@@ -192,10 +205,7 @@ public abstract class ApiConsumerHandler extends BaseThingHandler implements Api
     @Override
     public void dispose() {
         stopJobs();
-        ServiceRegistration<?> localReg = reg;
-        if (localReg != null) {
-            localReg.unregister();
-        }
+        stopAudioSink();
         super.dispose();
     }
 
index 5b24399d6bea07e7085a7b9683d25f225fe4a9f0..eacac76df48dba2c6381fb0a098bf3f996009f8a 100644 (file)
@@ -46,6 +46,10 @@ public class HostHandler extends ApiConsumerHandler {
     // We start in pull mode and switch to push after a first update...
     protected boolean pushSubscribed = false;
 
+    protected boolean reachable;
+
+    private int tryConfigureMediaSink = 1;
+
     public HostHandler(Thing thing) {
         super(thing);
         statusDrivenByBridge = false;
@@ -78,6 +82,11 @@ public class HostHandler extends ApiConsumerHandler {
 
     @Override
     protected void internalPoll() throws FreeboxException {
+        if (tryConfigureMediaSink > 0) {
+            configureMediaSink();
+            tryConfigureMediaSink--;
+        }
+
         if (pushSubscribed) {
             return;
         }
@@ -109,6 +118,13 @@ public class HostHandler extends ApiConsumerHandler {
         updateChannelDateTimeState(CONNECTIVITY, LAST_SEEN, host.getLastSeen());
         updateChannelString(CONNECTIVITY, IP_ADDRESS, host.getIpv4());
         updateStatus(host.reachable() ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
+        // We will check and configure audio sink only when the host reachability changed
+        if (reachable != host.reachable()) {
+            reachable = host.reachable();
+            // It can take time until the Media Receiver API returns the receiver after it becomes reachable.
+            // So this will be checked during the next 2 polls.
+            tryConfigureMediaSink = 2;
+        }
     }
 
     public void wol() {