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) {
}
}
- 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) {
@Override
public void dispose() {
stopJobs();
- ServiceRegistration<?> localReg = reg;
- if (localReg != null) {
- localReg.unregister();
- }
+ stopAudioSink();
super.dispose();
}
// 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;
@Override
protected void internalPoll() throws FreeboxException {
+ if (tryConfigureMediaSink > 0) {
+ configureMediaSink();
+ tryConfigureMediaSink--;
+ }
+
if (pushSubscribed) {
return;
}
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() {