2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.pulseaudio.internal;
15 import java.io.IOException;
16 import java.net.Socket;
17 import java.util.Locale;
18 import java.util.concurrent.ScheduledExecutorService;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.pulseaudio.internal.handler.PulseaudioHandler;
25 import org.openhab.core.library.types.PercentType;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * A connection to a pulseaudio Simple TCP Protocol
32 * @author Gwendal Roulleau - Initial contribution
33 * @author Miguel Álvarez - Refactor some code from PulseAudioAudioSink here
37 public abstract class PulseaudioSimpleProtocolStream {
39 private final Logger logger = LoggerFactory.getLogger(PulseaudioSimpleProtocolStream.class);
41 protected PulseaudioHandler pulseaudioHandler;
42 protected ScheduledExecutorService scheduler;
44 protected @Nullable Socket clientSocket;
46 private boolean isIdle = true;
48 private @Nullable ScheduledFuture<?> scheduledDisconnection;
50 public PulseaudioSimpleProtocolStream(PulseaudioHandler pulseaudioHandler, ScheduledExecutorService scheduler) {
51 this.pulseaudioHandler = pulseaudioHandler;
52 this.scheduler = scheduler;
56 * Connect to pulseaudio with the simple protocol
59 * @throws InterruptedException when interrupted during the loading module wait
61 public void connectIfNeeded() throws IOException, InterruptedException {
62 Socket clientSocketLocal = clientSocket;
63 if (clientSocketLocal == null || !clientSocketLocal.isConnected() || clientSocketLocal.isClosed()) {
64 logger.debug("Simple TCP Stream connecting");
65 String host = pulseaudioHandler.getHost();
66 int port = pulseaudioHandler.getSimpleTcpPortAndLoadModuleIfNecessary();
67 var clientSocketFinal = new Socket(host, port);
68 clientSocketFinal.setSoTimeout(pulseaudioHandler.getBasicProtocolSOTimeout());
69 clientSocket = clientSocketFinal;
74 * Disconnect the socket to pulseaudio simple protocol
76 public void disconnect() {
77 final Socket clientSocketLocal = clientSocket;
78 if (clientSocketLocal != null && isIdle) {
79 logger.debug("Simple TCP Stream disconnecting");
81 clientSocketLocal.close();
82 } catch (IOException ignored) {
85 logger.debug("Stream still running or socket not open");
89 public void scheduleDisconnect() {
90 var scheduledDisconnectionFinal = scheduledDisconnection;
91 if (scheduledDisconnectionFinal != null) {
92 scheduledDisconnectionFinal.cancel(true);
94 int idleTimeout = pulseaudioHandler.getIdleTimeout();
95 if (idleTimeout > -1) {
96 logger.debug("Scheduling disconnect");
97 scheduledDisconnection = scheduler.schedule(this::disconnect, idleTimeout, TimeUnit.MILLISECONDS);
101 public PercentType getVolume() {
102 return new PercentType(pulseaudioHandler.getLastVolume());
105 public void setVolume(PercentType volume) {
106 pulseaudioHandler.setVolume(volume.intValue());
109 public String getId() {
110 return pulseaudioHandler.getThing().getUID().toString();
113 public String getLabel(@Nullable Locale locale) {
114 var label = pulseaudioHandler.getThing().getLabel();
115 return label != null ? label : pulseaudioHandler.getThing().getUID().getId();
118 public void setIdle(boolean idle) {