[freeboxos] Fix start/stop audio sink (#17223)

* [freeboxos] Fix start/stop audio sink Fix #17208

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2024-08-10 11:45:55 +02:00 committed by GitHub
parent 39eca040d1
commit 0562b0a231
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 31 deletions

View 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<>());
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 {
logger.info("A password needs to be configured to enable Air Media capability.");
}
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();
}

View 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() {