diff --git a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java index d1fe0705848e2..6f3756eef9990 100644 --- a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java +++ b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java @@ -18,6 +18,8 @@ import java.util.HashSet; import java.util.Locale; import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider; import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader; @@ -52,17 +54,21 @@ public class PulseAudioAudioSink implements AudioSink { private static final HashSet> SUPPORTED_STREAMS = new HashSet<>(); private PulseaudioHandler pulseaudioHandler; + private ScheduledExecutorService scheduler; private @Nullable Socket clientSocket; + private boolean isIdle = true; + static { SUPPORTED_FORMATS.add(AudioFormat.WAV); SUPPORTED_FORMATS.add(AudioFormat.MP3); SUPPORTED_STREAMS.add(FixedLengthAudioStream.class); } - public PulseAudioAudioSink(PulseaudioHandler pulseaudioHandler) { + public PulseAudioAudioSink(PulseaudioHandler pulseaudioHandler, ScheduledExecutorService scheduler) { this.pulseaudioHandler = pulseaudioHandler; + this.scheduler = scheduler; } @Override @@ -120,11 +126,14 @@ public void connectIfNeeded() throws IOException, InterruptedException { * Disconnect the socket to pulseaudio simple protocol */ public void disconnect() { - if (clientSocket != null) { + if (clientSocket != null && isIdle) { + logger.debug("Disconnecting"); try { clientSocket.close(); } catch (IOException e) { } + } else { + logger.debug("Stream still running or socket not open"); } } @@ -153,6 +162,7 @@ public void process(@Nullable AudioStream audioStream) connectIfNeeded(); if (audioInputStream != null && clientSocket != null) { // send raw audio to the socket and to pulse audio + isIdle = false; audioInputStream.transferTo(clientSocket.getOutputStream()); break; } @@ -178,9 +188,16 @@ public void process(@Nullable AudioStream audioStream) audioInputStream.close(); } audioStream.close(); + scheduleDisconnect(); } catch (IOException e) { } } + isIdle = true; + } + + public void scheduleDisconnect() { + logger.debug("Scheduling disconnect"); + scheduler.schedule(this::disconnect, pulseaudioHandler.getIdleTimeout(), TimeUnit.MILLISECONDS); } @Override diff --git a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseaudioBindingConstants.java b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseaudioBindingConstants.java index 9c8f4f8521927..1a6a895426249 100644 --- a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseaudioBindingConstants.java +++ b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseaudioBindingConstants.java @@ -53,6 +53,7 @@ public class PulseaudioBindingConstants { public static final String DEVICE_PARAMETER_NAME = "name"; public static final String DEVICE_PARAMETER_AUDIO_SINK_ACTIVATION = "activateSimpleProtocolSink"; public static final String DEVICE_PARAMETER_AUDIO_SINK_PORT = "simpleProtocolSinkPort"; + public static final String DEVICE_PARAMETER_AUDIO_SINK_IDLE_TIMEOUT = "simpleProtocolSinkIdleTimeout"; public static final String MODULE_SIMPLE_PROTOCOL_TCP_NAME = "module-simple-protocol-tcp"; public static final int MODULE_SIMPLE_PROTOCOL_TCP_DEFAULT_PORT = 4711; diff --git a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/handler/PulseaudioHandler.java b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/handler/PulseaudioHandler.java index 88690998ac819..41011f5d25497 100644 --- a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/handler/PulseaudioHandler.java +++ b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/handler/PulseaudioHandler.java @@ -118,7 +118,7 @@ private void audioSinkSetup() { public void run() { // Register the sink as an audio sink in openhab logger.trace("Registering an audio sink for pulse audio sink thing {}", thing.getUID()); - PulseAudioAudioSink audioSink = new PulseAudioAudioSink(thisHandler); + PulseAudioAudioSink audioSink = new PulseAudioAudioSink(thisHandler, scheduler); setAudioSink(audioSink); try { audioSink.connectIfNeeded(); @@ -128,6 +128,8 @@ public void run() { } catch (InterruptedException i) { logger.info("Interrupted during sink audio connection: {}", i.getMessage()); return; + } finally { + audioSink.scheduleDisconnect(); } @SuppressWarnings("unchecked") ServiceRegistration reg = (ServiceRegistration) bundleContext @@ -367,6 +369,11 @@ public int getSimpleTcpPort() throws InterruptedException { .orElse(simpleTcpPortPref); } + public int getIdleTimeout() { + return ((BigDecimal) getThing().getConfiguration() + .get(PulseaudioBindingConstants.DEVICE_PARAMETER_AUDIO_SINK_IDLE_TIMEOUT)).intValue(); + } + @Override public void onDeviceRemoved(PulseaudioBridgeHandler bridge, AbstractAudioDeviceConfig device) { if (device.getPaName().equals(name)) { diff --git a/bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/thing/sink.xml b/bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/thing/sink.xml index 9f98aca6ace7f..e96dbdfc8cbaf 100644 --- a/bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/thing/sink.xml +++ b/bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/thing/sink.xml @@ -33,6 +33,13 @@ Default Port to allocate for use by module-simple-protocol-tcp on the pulseaudio server 4711 + + + Timeout in ms after which the connection will be closed when no stream is running. This ensures that + your speaker is not on all the time and the pulseaudio sink can go to idle mode. + + 30000 +