]> git.basschouten.com Git - openhab-addons.git/commitdiff
[pulseaudio] Add "idle timeout" to Pulseaudio audio sink (#10731)
authorDbzman <dev@dbzman-online.eu>
Sat, 5 Jun 2021 09:29:59 +0000 (11:29 +0200)
committerGitHub <noreply@github.com>
Sat, 5 Jun 2021 09:29:59 +0000 (11:29 +0200)
* Add "idle timeout" to pulseaudio audio sink to allow the sink to disconnect after being idle

Signed-off-by: Timo Litzius <dev@dbzman-online.eu>
bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java
bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseaudioBindingConstants.java
bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/handler/PulseaudioHandler.java
bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/thing/sink.xml

index d1fe0705848e238fc5faeffd8ba0db499672821d..6f3756eef9990046fa28fb764056aa3501d2a200 100644 (file)
@@ -18,6 +18,8 @@ import java.net.Socket;
 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<Class<? extends AudioStream>> 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 class PulseAudioAudioSink implements AudioSink {
      * 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 class PulseAudioAudioSink implements AudioSink {
                     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 class PulseAudioAudioSink implements AudioSink {
                     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
index 9c8f4f8521927df1e96e6e28836c48c5efce3e00..1a6a8954262499b36131eba189b25b3711bbf691 100644 (file)
@@ -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;
index 88690998ac819c164be260c95a2021a7b089493e..41011f5d254970044e89fe66ccf29d1043f54d63 100644 (file)
@@ -118,7 +118,7 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
             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 class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
                 } catch (InterruptedException i) {
                     logger.info("Interrupted during sink audio connection: {}", i.getMessage());
                     return;
+                } finally {
+                    audioSink.scheduleDisconnect();
                 }
                 @SuppressWarnings("unchecked")
                 ServiceRegistration<AudioSink> reg = (ServiceRegistration<AudioSink>) bundleContext
@@ -367,6 +369,11 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
                 .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)) {
index 9f98aca6ace7fcdc85ef51cd90a1ccc926b9537d..e96dbdfc8cbaf1bc92e4497f64b442a54629f5ea 100644 (file)
                                <description>Default Port to allocate for use by module-simple-protocol-tcp on the pulseaudio server</description>
                                <default>4711</default>
                        </parameter>
+                       <parameter name="simpleProtocolSinkIdleTimeout" type="integer" required="false">
+                               <label>Idle Timeout</label>
+                               <description>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.
+                               </description>
+                               <default>30000</default>
+                       </parameter>
                </config-description>
        </thing-type>