diff --git a/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/ApiConsumerHandler.java b/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/ApiConsumerHandler.java index 7e85dec9b87..8a9ad3713f4 100644 --- a/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/ApiConsumerHandler.java +++ b/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/ApiConsumerHandler.java @@ -87,40 +87,62 @@ public abstract class ApiConsumerHandler extends BaseThingHandler implements Api Map 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 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 getManager(Class 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 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(); } diff --git a/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/HostHandler.java b/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/HostHandler.java index 5b24399d6be..eacac76df48 100644 --- a/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/HostHandler.java +++ b/bundles/org.openhab.binding.freeboxos/src/main/java/org/openhab/binding/freeboxos/internal/handler/HostHandler.java @@ -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() {