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;
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
* 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");
}
}
connectIfNeeded();
if (audioInputStream != null && clientSocket != null) {
// send raw audio to the socket and to pulse audio
+ isIdle = false;
audioInputStream.transferTo(clientSocket.getOutputStream());
break;
}
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
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();
} catch (InterruptedException i) {
logger.info("Interrupted during sink audio connection: {}", i.getMessage());
return;
+ } finally {
+ audioSink.scheduleDisconnect();
}
@SuppressWarnings("unchecked")
ServiceRegistration<AudioSink> reg = (ServiceRegistration<AudioSink>) bundleContext
.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)) {
<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>