[pulseaudio] Fix exception handling when connecting (#12423)
Fix bridge/thing status update Also update log levels Fix #12419 Fix #12424 Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
20f6b52e71
commit
e3ca3b01bf
@ -18,7 +18,6 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.net.NoRouteToHostException;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
@ -129,20 +128,18 @@ public class PulseaudioClient {
|
|||||||
*/
|
*/
|
||||||
private static final String MODULE_COMBINE_SINK = "module-combine-sink";
|
private static final String MODULE_COMBINE_SINK = "module-combine-sink";
|
||||||
|
|
||||||
public PulseaudioClient(String host, int port, PulseAudioBindingConfiguration configuration) throws IOException {
|
public PulseaudioClient(String host, int port, PulseAudioBindingConfiguration configuration) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
|
|
||||||
items = new ArrayList<>();
|
items = new ArrayList<>();
|
||||||
modules = new ArrayList<>();
|
modules = new ArrayList<>();
|
||||||
|
|
||||||
connect();
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return client != null ? client.isConnected() : false;
|
Socket clientSocket = client;
|
||||||
|
return clientSocket != null ? clientSocket.isConnected() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -378,9 +375,6 @@ public class PulseaudioClient {
|
|||||||
* 0 - 65536)
|
* 0 - 65536)
|
||||||
*/
|
*/
|
||||||
public void setVolume(AbstractAudioDeviceConfig item, int vol) {
|
public void setVolume(AbstractAudioDeviceConfig item, int vol) {
|
||||||
if (item == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String itemCommandName = getItemCommandName(item);
|
String itemCommandName = getItemCommandName(item);
|
||||||
if (itemCommandName == null) {
|
if (itemCommandName == null) {
|
||||||
return;
|
return;
|
||||||
@ -485,7 +479,7 @@ public class PulseaudioClient {
|
|||||||
.map(portS -> Integer.parseInt(portS));
|
.map(portS -> Integer.parseInt(portS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull Optional<@NonNull String> extractArgumentFromLine(String argumentWanted, String argumentLine) {
|
private Optional<@NonNull String> extractArgumentFromLine(String argumentWanted, String argumentLine) {
|
||||||
String argument = null;
|
String argument = null;
|
||||||
int startPortIndex = argumentLine.indexOf(argumentWanted + "=");
|
int startPortIndex = argumentLine.indexOf(argumentWanted + "=");
|
||||||
if (startPortIndex != -1) {
|
if (startPortIndex != -1) {
|
||||||
@ -525,11 +519,8 @@ public class PulseaudioClient {
|
|||||||
* @param vol the new volume percent value the {@link AbstractAudioDeviceConfig} should be changed to (possible
|
* @param vol the new volume percent value the {@link AbstractAudioDeviceConfig} should be changed to (possible
|
||||||
* values from 0 - 100)
|
* values from 0 - 100)
|
||||||
*/
|
*/
|
||||||
public void setVolumePercent(@Nullable AbstractAudioDeviceConfig item, int vol) {
|
public void setVolumePercent(AbstractAudioDeviceConfig item, int vol) {
|
||||||
int volumeToSet = vol;
|
int volumeToSet = vol;
|
||||||
if (item == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (volumeToSet <= 100) {
|
if (volumeToSet <= 100) {
|
||||||
volumeToSet = toAbsoluteVolume(volumeToSet);
|
volumeToSet = toAbsoluteVolume(volumeToSet);
|
||||||
}
|
}
|
||||||
@ -662,15 +653,16 @@ public class PulseaudioClient {
|
|||||||
|
|
||||||
private synchronized void sendRawCommand(String command) {
|
private synchronized void sendRawCommand(String command) {
|
||||||
checkConnection();
|
checkConnection();
|
||||||
if (client != null && client.isConnected()) {
|
Socket clientSocket = client;
|
||||||
|
if (clientSocket != null && clientSocket.isConnected()) {
|
||||||
try {
|
try {
|
||||||
PrintStream out = new PrintStream(client.getOutputStream(), true);
|
PrintStream out = new PrintStream(clientSocket.getOutputStream(), true);
|
||||||
logger.trace("sending command {} to pa-server {}", command, host);
|
logger.trace("sending command {} to pa-server {}", command, host);
|
||||||
out.print(command + "\r\n");
|
out.print(command + "\r\n");
|
||||||
out.close();
|
out.close();
|
||||||
client.close();
|
clientSocket.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("{}", e.getLocalizedMessage(), e);
|
logger.warn("{}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -679,12 +671,13 @@ public class PulseaudioClient {
|
|||||||
logger.trace("_sendRawRequest({})", command);
|
logger.trace("_sendRawRequest({})", command);
|
||||||
checkConnection();
|
checkConnection();
|
||||||
String result = "";
|
String result = "";
|
||||||
if (client != null && client.isConnected()) {
|
Socket clientSocket = client;
|
||||||
|
if (clientSocket != null && clientSocket.isConnected()) {
|
||||||
try {
|
try {
|
||||||
PrintStream out = new PrintStream(client.getOutputStream(), true);
|
PrintStream out = new PrintStream(clientSocket.getOutputStream(), true);
|
||||||
out.print(command + "\r\n");
|
out.print(command + "\r\n");
|
||||||
|
|
||||||
InputStream instr = client.getInputStream();
|
InputStream instr = clientSocket.getInputStream();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[] buff = new byte[1024];
|
byte[] buff = new byte[1024];
|
||||||
@ -709,42 +702,52 @@ public class PulseaudioClient {
|
|||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
logger.warn("Socket exception while sending pulseaudio command: {}", e.getMessage());
|
logger.warn("Socket exception while sending pulseaudio command: {}", e.getMessage());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Exception while reading socket: {}", e.getMessage());
|
logger.warn("Exception while reading socket: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
instr.close();
|
instr.close();
|
||||||
out.close();
|
out.close();
|
||||||
client.close();
|
clientSocket.close();
|
||||||
return result;
|
return result;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("{}", e.getLocalizedMessage(), e);
|
logger.warn("{}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkConnection() {
|
private void checkConnection() {
|
||||||
if (client == null || client.isClosed() || !client.isConnected()) {
|
try {
|
||||||
try {
|
connect();
|
||||||
connect();
|
} catch (IOException e) {
|
||||||
} catch (IOException e) {
|
logger.debug("{}", e.getMessage(), e);
|
||||||
logger.error("{}", e.getLocalizedMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to the pulseaudio server (timeout 500ms)
|
* Connects to the pulseaudio server (timeout 500ms)
|
||||||
*/
|
*/
|
||||||
private void connect() throws IOException {
|
public void connect() throws IOException {
|
||||||
try {
|
Socket clientSocket = client;
|
||||||
client = new Socket(host, port);
|
if (clientSocket == null || clientSocket.isClosed() || !clientSocket.isConnected()) {
|
||||||
client.setSoTimeout(500);
|
logger.trace("Try to connect...");
|
||||||
} catch (UnknownHostException e) {
|
try {
|
||||||
logger.error("unknown socket host {}", host);
|
client = new Socket(host, port);
|
||||||
} catch (NoRouteToHostException e) {
|
client.setSoTimeout(500);
|
||||||
logger.error("no route to host {}", host);
|
logger.trace("connected");
|
||||||
} catch (SocketException e) {
|
} catch (UnknownHostException e) {
|
||||||
logger.error("cannot connect to host {} : {}", host, e.getMessage());
|
client = null;
|
||||||
|
throw new IOException("Unknown host", e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
client = null;
|
||||||
|
throw new IOException("Invalid port", e);
|
||||||
|
} catch (SecurityException | SocketException e) {
|
||||||
|
client = null;
|
||||||
|
throw new IOException(
|
||||||
|
String.format("Cannot connect socket: %s", e.getMessage() != null ? e.getMessage() : ""), e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
client = null;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,11 +755,12 @@ public class PulseaudioClient {
|
|||||||
* Disconnects from the pulseaudio server
|
* Disconnects from the pulseaudio server
|
||||||
*/
|
*/
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (client != null) {
|
Socket clientSocket = client;
|
||||||
|
if (clientSocket != null) {
|
||||||
try {
|
try {
|
||||||
client.close();
|
clientSocket.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("{}", e.getLocalizedMessage(), e);
|
logger.debug("{}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import org.openhab.core.config.core.Configuration;
|
|||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
@ -67,11 +68,22 @@ public class PulseaudioBridgeHandler extends BaseBridgeHandler implements PulseA
|
|||||||
private HashSet<String> lastActiveDevices = new HashSet<>();
|
private HashSet<String> lastActiveDevices = new HashSet<>();
|
||||||
|
|
||||||
private ScheduledFuture<?> pollingJob;
|
private ScheduledFuture<?> pollingJob;
|
||||||
private Runnable pollingRunnable = () -> {
|
|
||||||
update();
|
|
||||||
};
|
|
||||||
|
|
||||||
private synchronized void update() {
|
private synchronized void update() {
|
||||||
|
try {
|
||||||
|
client.connect();
|
||||||
|
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
logger.debug("Established connection to Pulseaudio server on Host '{}':'{}'.", host, port);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("{}", e.getMessage(), e);
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
|
String.format("Couldn't connect to Pulsaudio server [Host '%s':'%d']: %s", host, port,
|
||||||
|
e.getMessage() != null ? e.getMessage() : ""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
client.update();
|
client.update();
|
||||||
for (AbstractAudioDeviceConfig device : client.getItems()) {
|
for (AbstractAudioDeviceConfig device : client.getItems()) {
|
||||||
if (lastActiveDevices != null && lastActiveDevices.contains(device.getPaName())) {
|
if (lastActiveDevices != null && lastActiveDevices.contains(device.getPaName())) {
|
||||||
@ -79,7 +91,7 @@ public class PulseaudioBridgeHandler extends BaseBridgeHandler implements PulseA
|
|||||||
try {
|
try {
|
||||||
deviceStatusListener.onDeviceStateChanged(getThing().getUID(), device);
|
deviceStatusListener.onDeviceStateChanged(getThing().getUID(), device);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("An exception occurred while calling the DeviceStatusListener", e);
|
logger.warn("An exception occurred while calling the DeviceStatusListener", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -88,7 +100,7 @@ public class PulseaudioBridgeHandler extends BaseBridgeHandler implements PulseA
|
|||||||
deviceStatusListener.onDeviceAdded(getThing(), device);
|
deviceStatusListener.onDeviceAdded(getThing(), device);
|
||||||
deviceStatusListener.onDeviceStateChanged(getThing().getUID(), device);
|
deviceStatusListener.onDeviceStateChanged(getThing().getUID(), device);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("An exception occurred while calling the DeviceStatusListener", e);
|
logger.warn("An exception occurred while calling the DeviceStatusListener", e);
|
||||||
}
|
}
|
||||||
lastActiveDevices.add(device.getPaName());
|
lastActiveDevices.add(device.getPaName());
|
||||||
}
|
}
|
||||||
@ -106,13 +118,7 @@ public class PulseaudioBridgeHandler extends BaseBridgeHandler implements PulseA
|
|||||||
if (command instanceof RefreshType) {
|
if (command instanceof RefreshType) {
|
||||||
client.update();
|
client.update();
|
||||||
} else {
|
} else {
|
||||||
logger.warn("received invalid command for pulseaudio bridge '{}'.", host);
|
logger.debug("received unexpected command for pulseaudio bridge '{}'.", host);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void startAutomaticRefresh() {
|
|
||||||
if (pollingJob == null || pollingJob.isCancelled()) {
|
|
||||||
pollingJob = scheduler.scheduleWithFixedDelay(pollingRunnable, 0, refreshInterval, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,26 +146,15 @@ public class PulseaudioBridgeHandler extends BaseBridgeHandler implements PulseA
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (host != null && !host.isEmpty()) {
|
if (host != null && !host.isEmpty()) {
|
||||||
Runnable connectRunnable = () -> {
|
client = new PulseaudioClient(host, port, configuration);
|
||||||
try {
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
client = new PulseaudioClient(host, port, configuration);
|
if (pollingJob == null || pollingJob.isCancelled()) {
|
||||||
if (client.isConnected()) {
|
pollingJob = scheduler.scheduleWithFixedDelay(this::update, 0, refreshInterval, TimeUnit.MILLISECONDS);
|
||||||
updateStatus(ThingStatus.ONLINE);
|
}
|
||||||
logger.info("Established connection to Pulseaudio server on Host '{}':'{}'.", host, port);
|
|
||||||
startAutomaticRefresh();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("Couldn't connect to Pulsaudio server [Host '{}':'{}']: {}", host, port,
|
|
||||||
e.getLocalizedMessage());
|
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
scheduler.schedule(connectRunnable, 0, TimeUnit.SECONDS);
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, String.format(
|
||||||
"Couldn't connect to Pulseaudio server because of missing connection parameters [Host '{}':'{}'].",
|
"Couldn't connect to Pulseaudio server because of missing connection parameters [Host '%s':'%d']",
|
||||||
host, port);
|
host, port));
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.configuration.addPulseAudioBindingConfigurationListener(this);
|
this.configuration.addPulseAudioBindingConfigurationListener(this);
|
||||||
@ -168,8 +163,10 @@ public class PulseaudioBridgeHandler extends BaseBridgeHandler implements PulseA
|
|||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
this.configuration.removePulseAudioBindingConfigurationListener(this);
|
this.configuration.removePulseAudioBindingConfigurationListener(this);
|
||||||
if (pollingJob != null) {
|
ScheduledFuture<?> job = pollingJob;
|
||||||
pollingJob.cancel(true);
|
if (job != null) {
|
||||||
|
job.cancel(true);
|
||||||
|
pollingJob = null;
|
||||||
}
|
}
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
client.disconnect();
|
client.disconnect();
|
||||||
|
|||||||
@ -50,6 +50,8 @@ import org.openhab.core.thing.Bridge;
|
|||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
|
import org.openhab.core.thing.ThingStatusInfo;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
@ -101,15 +103,13 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
Configuration config = getThing().getConfiguration();
|
Configuration config = getThing().getConfiguration();
|
||||||
name = (String) config.get(DEVICE_PARAMETER_NAME);
|
name = (String) config.get(DEVICE_PARAMETER_NAME);
|
||||||
|
|
||||||
// until we get an update put the Thing offline
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
|
||||||
deviceOnlineWatchdog();
|
deviceOnlineWatchdog();
|
||||||
|
|
||||||
// if it's a SINK thing, then maybe we have to activate the audio sink
|
// if it's a SINK thing, then maybe we have to activate the audio sink
|
||||||
if (PulseaudioBindingConstants.SINK_THING_TYPE.equals(thing.getThingTypeUID())) {
|
if (SINK_THING_TYPE.equals(thing.getThingTypeUID())) {
|
||||||
// check the property to see if we it's enabled :
|
// check the property to see if we it's enabled :
|
||||||
Boolean sinkActivated = (Boolean) thing.getConfiguration()
|
Boolean sinkActivated = (Boolean) thing.getConfiguration().get(DEVICE_PARAMETER_AUDIO_SINK_ACTIVATION);
|
||||||
.get(PulseaudioBindingConstants.DEVICE_PARAMETER_AUDIO_SINK_ACTIVATION);
|
|
||||||
if (sinkActivated != null && sinkActivated) {
|
if (sinkActivated != null && sinkActivated) {
|
||||||
audioSinkSetup();
|
audioSinkSetup();
|
||||||
}
|
}
|
||||||
@ -182,22 +182,25 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (refreshJob != null && !refreshJob.isCancelled()) {
|
ScheduledFuture<?> job = refreshJob;
|
||||||
refreshJob.cancel(true);
|
if (job != null && !job.isCancelled()) {
|
||||||
|
job.cancel(true);
|
||||||
refreshJob = null;
|
refreshJob = null;
|
||||||
}
|
}
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
PulseaudioBridgeHandler briHandler = bridgeHandler;
|
||||||
if (bridgeHandler != null) {
|
if (briHandler != null) {
|
||||||
bridgeHandler.unregisterDeviceStatusListener(this);
|
briHandler.unregisterDeviceStatusListener(this);
|
||||||
bridgeHandler = null;
|
bridgeHandler = null;
|
||||||
}
|
}
|
||||||
logger.trace("Thing {} {} disposed.", getThing().getUID(), name);
|
logger.trace("Thing {} {} disposed.", getThing().getUID(), name);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
if (audioSink != null) {
|
PulseAudioAudioSink sink = audioSink;
|
||||||
audioSink.disconnect();
|
if (sink != null) {
|
||||||
|
sink.disconnect();
|
||||||
}
|
}
|
||||||
if (audioSource != null) {
|
PulseAudioAudioSource source = audioSource;
|
||||||
audioSource.disconnect();
|
if (source != null) {
|
||||||
|
source.disconnect();
|
||||||
}
|
}
|
||||||
// Unregister the potential pulse audio sink's audio sink
|
// Unregister the potential pulse audio sink's audio sink
|
||||||
ServiceRegistration<AudioSink> sinkReg = audioSinkRegistrations.remove(getThing().getUID().toString());
|
ServiceRegistration<AudioSink> sinkReg = audioSinkRegistrations.remove(getThing().getUID().toString());
|
||||||
@ -213,20 +216,42 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
|
||||||
|
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE
|
||||||
|
&& getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE) {
|
||||||
|
// Bridge is now ONLINE, restart the refresh job to get an update of the thing status without waiting
|
||||||
|
// its next planned run
|
||||||
|
ScheduledFuture<?> job = refreshJob;
|
||||||
|
if (job != null && !job.isCancelled()) {
|
||||||
|
job.cancel(true);
|
||||||
|
refreshJob = null;
|
||||||
|
}
|
||||||
|
deviceOnlineWatchdog();
|
||||||
|
} else if (bridgeStatusInfo.getStatus() == ThingStatus.OFFLINE
|
||||||
|
|| bridgeStatusInfo.getStatus() == ThingStatus.UNKNOWN) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void deviceOnlineWatchdog() {
|
private void deviceOnlineWatchdog() {
|
||||||
Runnable runnable = () -> {
|
Runnable runnable = () -> {
|
||||||
try {
|
try {
|
||||||
PulseaudioBridgeHandler bridgeHandler = getPulseaudioBridgeHandler();
|
PulseaudioBridgeHandler bridgeHandler = getPulseaudioBridgeHandler();
|
||||||
if (bridgeHandler != null) {
|
if (bridgeHandler != null) {
|
||||||
if (bridgeHandler.getDevice(name) == null) {
|
if (bridgeHandler.getThing().getStatus() == ThingStatus.ONLINE) {
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
if (bridgeHandler.getDevice(name) == null) {
|
||||||
this.bridgeHandler = null;
|
updateStatus(ThingStatus.OFFLINE);
|
||||||
|
this.bridgeHandler = null;
|
||||||
|
} else {
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Bridge for pulseaudio device {} not found.", name);
|
logger.debug("Bridge for pulseaudio device {} not found.", name);
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
|
logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
|
||||||
@ -258,17 +283,17 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
PulseaudioBridgeHandler bridge = getPulseaudioBridgeHandler();
|
PulseaudioBridgeHandler briHandler = getPulseaudioBridgeHandler();
|
||||||
if (bridge == null) {
|
if (briHandler == null) {
|
||||||
logger.warn("pulseaudio server bridge handler not found. Cannot handle command without bridge.");
|
logger.debug("pulseaudio server bridge handler not found. Cannot handle command without bridge.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (command instanceof RefreshType) {
|
if (command instanceof RefreshType) {
|
||||||
bridge.handleCommand(channelUID, command);
|
briHandler.handleCommand(channelUID, command);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAudioDeviceConfig device = bridge.getDevice(name);
|
AbstractAudioDeviceConfig device = briHandler.getDevice(name);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
logger.warn("device {} not found", name);
|
logger.warn("device {} not found", name);
|
||||||
updateStatus(ThingStatus.OFFLINE);
|
updateStatus(ThingStatus.OFFLINE);
|
||||||
@ -279,8 +304,8 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
if (channelUID.getId().equals(VOLUME_CHANNEL)) {
|
if (channelUID.getId().equals(VOLUME_CHANNEL)) {
|
||||||
if (command instanceof IncreaseDecreaseType) {
|
if (command instanceof IncreaseDecreaseType) {
|
||||||
// refresh to get the current volume level
|
// refresh to get the current volume level
|
||||||
bridge.getClient().update();
|
briHandler.getClient().update();
|
||||||
device = bridge.getDevice(name);
|
device = briHandler.getDevice(name);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
logger.warn("missing device info, aborting");
|
logger.warn("missing device info, aborting");
|
||||||
return;
|
return;
|
||||||
@ -293,24 +318,24 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
if (command.equals(IncreaseDecreaseType.DECREASE)) {
|
if (command.equals(IncreaseDecreaseType.DECREASE)) {
|
||||||
newVolume = Math.max(0, oldVolume - 5);
|
newVolume = Math.max(0, oldVolume - 5);
|
||||||
}
|
}
|
||||||
bridge.getClient().setVolumePercent(device, newVolume);
|
briHandler.getClient().setVolumePercent(device, newVolume);
|
||||||
updateState = new PercentType(newVolume);
|
updateState = new PercentType(newVolume);
|
||||||
savedVolume = newVolume;
|
savedVolume = newVolume;
|
||||||
} else if (command instanceof PercentType) {
|
} else if (command instanceof PercentType) {
|
||||||
DecimalType volume = (DecimalType) command;
|
DecimalType volume = (DecimalType) command;
|
||||||
bridge.getClient().setVolumePercent(device, volume.intValue());
|
briHandler.getClient().setVolumePercent(device, volume.intValue());
|
||||||
updateState = (PercentType) command;
|
updateState = (PercentType) command;
|
||||||
savedVolume = volume.intValue();
|
savedVolume = volume.intValue();
|
||||||
} else if (command instanceof DecimalType) {
|
} else if (command instanceof DecimalType) {
|
||||||
// set volume
|
// set volume
|
||||||
DecimalType volume = (DecimalType) command;
|
DecimalType volume = (DecimalType) command;
|
||||||
bridge.getClient().setVolume(device, volume.intValue());
|
briHandler.getClient().setVolume(device, volume.intValue());
|
||||||
updateState = (DecimalType) command;
|
updateState = (DecimalType) command;
|
||||||
savedVolume = volume.intValue();
|
savedVolume = volume.intValue();
|
||||||
}
|
}
|
||||||
} else if (channelUID.getId().equals(MUTE_CHANNEL)) {
|
} else if (channelUID.getId().equals(MUTE_CHANNEL)) {
|
||||||
if (command instanceof OnOffType) {
|
if (command instanceof OnOffType) {
|
||||||
bridge.getClient().setMute(device, OnOffType.ON.equals(command));
|
briHandler.getClient().setMute(device, OnOffType.ON.equals(command));
|
||||||
updateState = (OnOffType) command;
|
updateState = (OnOffType) command;
|
||||||
}
|
}
|
||||||
} else if (channelUID.getId().equals(SLAVES_CHANNEL)) {
|
} else if (channelUID.getId().equals(SLAVES_CHANNEL)) {
|
||||||
@ -318,32 +343,32 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
if (command instanceof StringType) {
|
if (command instanceof StringType) {
|
||||||
List<Sink> slaves = new ArrayList<>();
|
List<Sink> slaves = new ArrayList<>();
|
||||||
for (String slaveName : command.toString().split(",")) {
|
for (String slaveName : command.toString().split(",")) {
|
||||||
Sink slave = bridge.getClient().getSink(slaveName.trim());
|
Sink slave = briHandler.getClient().getSink(slaveName.trim());
|
||||||
if (slave != null) {
|
if (slave != null) {
|
||||||
slaves.add(slave);
|
slaves.add(slave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!slaves.isEmpty()) {
|
if (!slaves.isEmpty()) {
|
||||||
bridge.getClient().setCombinedSinkSlaves(((Sink) device), slaves);
|
briHandler.getClient().setCombinedSinkSlaves(((Sink) device), slaves);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.error("{} is no combined sink", device);
|
logger.warn("{} is no combined sink", device);
|
||||||
}
|
}
|
||||||
} else if (channelUID.getId().equals(ROUTE_TO_SINK_CHANNEL)) {
|
} else if (channelUID.getId().equals(ROUTE_TO_SINK_CHANNEL)) {
|
||||||
if (device instanceof SinkInput) {
|
if (device instanceof SinkInput) {
|
||||||
Sink newSink = null;
|
Sink newSink = null;
|
||||||
if (command instanceof DecimalType) {
|
if (command instanceof DecimalType) {
|
||||||
newSink = bridge.getClient().getSink(((DecimalType) command).intValue());
|
newSink = briHandler.getClient().getSink(((DecimalType) command).intValue());
|
||||||
} else {
|
} else {
|
||||||
newSink = bridge.getClient().getSink(command.toString());
|
newSink = briHandler.getClient().getSink(command.toString());
|
||||||
}
|
}
|
||||||
if (newSink != null) {
|
if (newSink != null) {
|
||||||
logger.debug("rerouting {} to {}", device, newSink);
|
logger.debug("rerouting {} to {}", device, newSink);
|
||||||
bridge.getClient().moveSinkInput(((SinkInput) device), newSink);
|
briHandler.getClient().moveSinkInput(((SinkInput) device), newSink);
|
||||||
updateState = new StringType(newSink.getPaName());
|
updateState = new StringType(newSink.getPaName());
|
||||||
} else {
|
} else {
|
||||||
logger.error("no sink {} found", command.toString());
|
logger.warn("no sink {} found", command.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,25 +386,31 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
*/
|
*/
|
||||||
public int getLastVolume() {
|
public int getLastVolume() {
|
||||||
if (savedVolume == null) {
|
if (savedVolume == null) {
|
||||||
PulseaudioBridgeHandler bridge = getPulseaudioBridgeHandler();
|
PulseaudioBridgeHandler briHandler = getPulseaudioBridgeHandler();
|
||||||
// refresh to get the current volume level
|
if (briHandler != null) {
|
||||||
bridge.getClient().update();
|
// refresh to get the current volume level
|
||||||
AbstractAudioDeviceConfig device = bridge.getDevice(name);
|
briHandler.getClient().update();
|
||||||
if (device != null) {
|
AbstractAudioDeviceConfig device = briHandler.getDevice(name);
|
||||||
savedVolume = device.getVolume();
|
if (device != null) {
|
||||||
|
savedVolume = device.getVolume();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return savedVolume == null ? 50 : savedVolume;
|
return savedVolume == null ? 50 : savedVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVolume(int volume) {
|
public void setVolume(int volume) {
|
||||||
PulseaudioBridgeHandler bridge = getPulseaudioBridgeHandler();
|
PulseaudioBridgeHandler briHandler = getPulseaudioBridgeHandler();
|
||||||
AbstractAudioDeviceConfig device = bridge.getDevice(name);
|
if (briHandler == null) {
|
||||||
|
logger.warn("bridge is not ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AbstractAudioDeviceConfig device = briHandler.getDevice(name);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
logger.warn("missing device info, aborting");
|
logger.warn("missing device info, aborting");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bridge.getClient().setVolumePercent(device, volume);
|
briHandler.getClient().setVolumePercent(device, volume);
|
||||||
updateState(VOLUME_CHANNEL, new PercentType(volume));
|
updateState(VOLUME_CHANNEL, new PercentType(volume));
|
||||||
savedVolume = volume;
|
savedVolume = volume;
|
||||||
}
|
}
|
||||||
@ -411,7 +442,7 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
if (bridge != null) {
|
if (bridge != null) {
|
||||||
return (String) bridge.getConfiguration().get(PulseaudioBindingConstants.BRIDGE_PARAMETER_HOST);
|
return (String) bridge.getConfiguration().get(PulseaudioBindingConstants.BRIDGE_PARAMETER_HOST);
|
||||||
} else {
|
} else {
|
||||||
logger.error("A bridge must be configured for this pulseaudio thing");
|
logger.warn("A bridge must be configured for this pulseaudio thing");
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,8 +456,11 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
* @throws InterruptedException when interrupted during the loading module wait
|
* @throws InterruptedException when interrupted during the loading module wait
|
||||||
*/
|
*/
|
||||||
public int getSimpleTcpPort() throws IOException, InterruptedException {
|
public int getSimpleTcpPort() throws IOException, InterruptedException {
|
||||||
var bridgeHandler = getPulseaudioBridgeHandler();
|
var briHandler = getPulseaudioBridgeHandler();
|
||||||
AbstractAudioDeviceConfig device = bridgeHandler.getDevice(name);
|
if (briHandler == null) {
|
||||||
|
throw new IOException("bridge is not ready");
|
||||||
|
}
|
||||||
|
AbstractAudioDeviceConfig device = briHandler.getDevice(name);
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
throw new IOException("missing device info, device appears to be offline");
|
throw new IOException("missing device info, device appears to be offline");
|
||||||
}
|
}
|
||||||
@ -439,7 +473,7 @@ public class PulseaudioHandler extends BaseThingHandler implements DeviceStatusL
|
|||||||
BigDecimal simpleRate = (BigDecimal) getThing().getConfiguration().get(DEVICE_PARAMETER_AUDIO_SOURCE_RATE);
|
BigDecimal simpleRate = (BigDecimal) getThing().getConfiguration().get(DEVICE_PARAMETER_AUDIO_SOURCE_RATE);
|
||||||
BigDecimal simpleChannels = (BigDecimal) getThing().getConfiguration()
|
BigDecimal simpleChannels = (BigDecimal) getThing().getConfiguration()
|
||||||
.get(DEVICE_PARAMETER_AUDIO_SOURCE_CHANNELS);
|
.get(DEVICE_PARAMETER_AUDIO_SOURCE_CHANNELS);
|
||||||
return getPulseaudioBridgeHandler().getClient()
|
return briHandler.getClient()
|
||||||
.loadModuleSimpleProtocolTcpIfNeeded(device, simpleTcpPort, simpleFormat, simpleRate, simpleChannels)
|
.loadModuleSimpleProtocolTcpIfNeeded(device, simpleTcpPort, simpleFormat, simpleRate, simpleChannels)
|
||||||
.orElse(simpleTcpPort);
|
.orElse(simpleTcpPort);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user