Make Broadcastify Calls scheduled test configurable (#1218)

* Broadcastify Calls periodic keep-alive to avoid showing offline status
This commit is contained in:
Doug Hoffman
2022-04-30 04:04:10 -04:00
committed by GitHub
parent 0d5d1b20e3
commit 166383e1ed
3 changed files with 100 additions and 7 deletions

View File

@@ -68,7 +68,6 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
private static final String MULTIPART_TYPE = "multipart"; private static final String MULTIPART_TYPE = "multipart";
private static final String DEFAULT_SUBTYPE = "form-data"; private static final String DEFAULT_SUBTYPE = "form-data";
private static final String MULTIPART_FORM_DATA = MULTIPART_TYPE + "/" + DEFAULT_SUBTYPE; private static final String MULTIPART_FORM_DATA = MULTIPART_TYPE + "/" + DEFAULT_SUBTYPE;
private static final long BROADCASTIFY_TEST_INTERVAL = 15l; // minutes
private ScheduledFuture<?> mBroadcastifyTestFuture; private ScheduledFuture<?> mBroadcastifyTestFuture;
private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>(); private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>();
private ScheduledFuture<?> mAudioRecordingProcessorFuture; private ScheduledFuture<?> mAudioRecordingProcessorFuture;
@@ -104,9 +103,6 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
if(response != null && response.toLowerCase().startsWith("ok")) if(response != null && response.toLowerCase().startsWith("ok"))
{ {
setBroadcastState(BroadcastState.CONNECTED); setBroadcastState(BroadcastState.CONNECTED);
// Test periodically so we don't get marked offline due to radio inactivity
mBroadcastifyTestFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new BroadcastifyCallTest(), BROADCASTIFY_TEST_INTERVAL, BROADCASTIFY_TEST_INTERVAL, TimeUnit.MINUTES);
} }
else else
{ {
@@ -114,6 +110,12 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
setBroadcastState(BroadcastState.ERROR); setBroadcastState(BroadcastState.ERROR);
} }
if(mBroadcastifyTestFuture == null && getBroadcastConfiguration().isTestEnabled())
{
// Test periodically so we don't get marked offline due to radio inactivity
mBroadcastifyTestFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new BroadcastifyCallTest(), getBroadcastConfiguration().getTestInterval(), getBroadcastConfiguration().getTestInterval(), TimeUnit.MINUTES);
}
if(mAudioRecordingProcessorFuture == null) if(mAudioRecordingProcessorFuture == null)
{ {
mAudioRecordingProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioRecordingProcessor(), mAudioRecordingProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioRecordingProcessor(),
@@ -127,10 +129,13 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
@Override @Override
public void stop() public void stop()
{ {
if(mAudioRecordingProcessorFuture != null) if(mBroadcastifyTestFuture != null)
{ {
mBroadcastifyTestFuture.cancel(true); mBroadcastifyTestFuture.cancel(true);
mBroadcastifyTestFuture = null; mBroadcastifyTestFuture = null;
}
if(mAudioRecordingProcessorFuture != null)
{
mAudioRecordingProcessorFuture.cancel(true); mAudioRecordingProcessorFuture.cancel(true);
mAudioRecordingProcessorFuture = null; mAudioRecordingProcessorFuture = null;
dispose(); dispose();
@@ -144,9 +149,13 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
public void run() public void run()
{ {
String response = testConnection(getBroadcastConfiguration()); String response = testConnection(getBroadcastConfiguration());
if(response != null && !response.toLowerCase().startsWith("ok")) if(response != null && response.toLowerCase().startsWith("ok"))
{ {
mLog.info("Broadcastify Calls test failure"); mLog.info("Broadcastify Calls keep-alive success");
}
else
{
mLog.info("Broadcastify Calls keep-alive failure");
} }
} }
} }

View File

@@ -24,7 +24,9 @@ import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
import io.github.dsheirer.audio.broadcast.BroadcastFormat; import io.github.dsheirer.audio.broadcast.BroadcastFormat;
import io.github.dsheirer.audio.broadcast.BroadcastServerType; import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
@@ -42,6 +44,8 @@ public class BroadcastifyCallConfiguration extends BroadcastConfiguration
private IntegerProperty mSystemID = new SimpleIntegerProperty(); private IntegerProperty mSystemID = new SimpleIntegerProperty();
private StringProperty mApiKey = new SimpleStringProperty(); private StringProperty mApiKey = new SimpleStringProperty();
private BooleanProperty mTestEnabled= new SimpleBooleanProperty(false);
private IntegerProperty mTestInterval = new SimpleIntegerProperty(15);
/** /**
* Constructor for faster jackson * Constructor for faster jackson
@@ -128,6 +132,34 @@ public class BroadcastifyCallConfiguration extends BroadcastConfiguration
return BroadcastServerType.BROADCASTIFY_CALL; return BroadcastServerType.BROADCASTIFY_CALL;
} }
/**
* Indicates if this instance should schedule tests after connecting
*/
@JacksonXmlProperty(isAttribute = true, localName = "test_enabled")
public boolean isTestEnabled()
{
return mTestEnabled.get();
}
public void setTestEnabled(boolean enabled)
{
mTestEnabled.set(enabled);
}
/**
* Indicates the interval at which tests should be performed while enabled
*/
@JacksonXmlProperty(isAttribute = true, localName = "test_interval")
public int getTestInterval()
{
return mTestInterval.get();
}
public void setTestInterval(int interval)
{
mTestInterval.set(interval);
}
@Override @Override
public BroadcastConfiguration copyOf() public BroadcastConfiguration copyOf()
{ {

View File

@@ -34,6 +34,7 @@ import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.controlsfx.control.ToggleSwitch;
/** /**
* Broadcastify calls API configuration editor * Broadcastify calls API configuration editor
@@ -47,6 +48,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
private TextField mApiKeyTextField; private TextField mApiKeyTextField;
private TextField mHostTextField; private TextField mHostTextField;
private GridPane mEditorPane; private GridPane mEditorPane;
private ToggleSwitch mTestEnabledToggleSwitch;
private IntegerTextField mTestIntervalTextField;
/** /**
* Constructs an instance * Constructs an instance
@@ -66,6 +69,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getApiKeyTextField().setDisable(item == null); getApiKeyTextField().setDisable(item == null);
getHostTextField().setDisable(item == null); getHostTextField().setDisable(item == null);
getMaxAgeTextField().setDisable(item == null); getMaxAgeTextField().setDisable(item == null);
getTestEnabledToggleSwitch().setDisable(item == null);
getTestIntervalTextField().setDisable(item == null);
if(item != null) if(item != null)
{ {
@@ -73,6 +78,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getApiKeyTextField().setText(item.getApiKey()); getApiKeyTextField().setText(item.getApiKey());
getHostTextField().setText(item.getHost()); getHostTextField().setText(item.getHost());
getMaxAgeTextField().set((int)(item.getMaximumRecordingAge() / 1000)); getMaxAgeTextField().set((int)(item.getMaximumRecordingAge() / 1000));
getTestEnabledToggleSwitch().setSelected(item.isTestEnabled());
getTestIntervalTextField().set(item.getTestInterval());
} }
else else
{ {
@@ -80,6 +87,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getApiKeyTextField().setText(null); getApiKeyTextField().setText(null);
getHostTextField().setText(null); getHostTextField().setText(null);
getMaxAgeTextField().set(0); getMaxAgeTextField().set(0);
getTestEnabledToggleSwitch().setSelected(false);
getTestIntervalTextField().set(15);
} }
modifiedProperty().set(false); modifiedProperty().set(false);
@@ -100,6 +109,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getItem().setHost(getHostTextField().getText()); getItem().setHost(getHostTextField().getText());
getItem().setApiKey(getApiKeyTextField().getText()); getItem().setApiKey(getApiKeyTextField().getText());
getItem().setMaximumRecordingAge(getMaxAgeTextField().get() * 1000); getItem().setMaximumRecordingAge(getMaxAgeTextField().get() * 1000);
getItem().setTestEnabled(getTestEnabledToggleSwitch().isSelected());
getItem().setTestInterval(getTestIntervalTextField().get());
} }
super.save(); super.save();
@@ -177,6 +188,22 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
GridPane.setConstraints(getMaxAgeTextField(), 1, row); GridPane.setConstraints(getMaxAgeTextField(), 1, row);
mEditorPane.getChildren().add(getMaxAgeTextField()); mEditorPane.getChildren().add(getMaxAgeTextField());
Label testEnabledLabel = new Label("Send Periodic Keep-Alive");
GridPane.setHalignment(testEnabledLabel, HPos.RIGHT);
GridPane.setConstraints(testEnabledLabel, 0, ++row);
mEditorPane.getChildren().add(testEnabledLabel);
GridPane.setConstraints(getTestEnabledToggleSwitch(), 1, row);
mEditorPane.getChildren().add(getTestEnabledToggleSwitch());
Label testIntervalLabel = new Label("Ping Interval (minutes)");
GridPane.setHalignment(testIntervalLabel, HPos.RIGHT);
GridPane.setConstraints(testIntervalLabel, 3, row);
mEditorPane.getChildren().add(testIntervalLabel);
GridPane.setConstraints(getTestIntervalTextField(), 4, row);
mEditorPane.getChildren().add(getTestIntervalTextField());
GridPane.setConstraints(getTestButton(), 1, ++row); GridPane.setConstraints(getTestButton(), 1, ++row);
mEditorPane.getChildren().add(getTestButton()); mEditorPane.getChildren().add(getTestButton());
} }
@@ -232,6 +259,31 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
return mSystemIdTextField; return mSystemIdTextField;
} }
private ToggleSwitch getTestEnabledToggleSwitch()
{
if(mTestEnabledToggleSwitch == null)
{
mTestEnabledToggleSwitch = new ToggleSwitch();
mTestEnabledToggleSwitch.setDisable(true);
mTestEnabledToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}
return mTestEnabledToggleSwitch;
}
private IntegerTextField getTestIntervalTextField()
{
if(mTestIntervalTextField == null)
{
mTestIntervalTextField = new IntegerTextField();
mTestIntervalTextField.setDisable(true);
mTestIntervalTextField.textProperty().addListener(mEditorModificationListener);
}
return mTestIntervalTextField;
}
private Button getTestButton() private Button getTestButton()
{ {
if(mTestButton == null) if(mTestButton == null)