[pulseaudio] Add "idle timeout" to Pulseaudio audio sink ()

* 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>
This commit is contained in:
Dbzman 2021-06-05 11:29:59 +02:00 committed by GitHub
parent 6d68746b60
commit 7109475929
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 3 deletions
bundles/org.openhab.binding.pulseaudio/src/main
java/org/openhab/binding/pulseaudio/internal
resources/OH-INF/thing

@ -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

@ -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;

@ -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)) {

@ -33,6 +33,13 @@
<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>