mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
#757 Implements Broadcastify Calls API audio broadcaster and resolves audio streaming error introduced with #5 (#773)
Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
@@ -47,7 +47,7 @@ import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
|
||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupFormatter;
|
||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
|
||||
import io.github.dsheirer.alias.id.tone.TonesID;
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
||||
import io.github.dsheirer.audio.broadcast.ConfiguredBroadcast;
|
||||
import io.github.dsheirer.eventbus.MyEventBus;
|
||||
import io.github.dsheirer.gui.playlist.Editor;
|
||||
import io.github.dsheirer.gui.playlist.alias.action.ActionEditor;
|
||||
@@ -167,8 +167,8 @@ public class AliasItemEditor extends Editor<Alias>
|
||||
mUserPreferences = userPreferences;
|
||||
|
||||
//Listen for changes to the stream configurations and refresh the stream lists
|
||||
mPlaylistManager.getBroadcastModel().getBroadcastConfigurations()
|
||||
.addListener((ListChangeListener<BroadcastConfiguration>)c -> updateStreamViews());
|
||||
mPlaylistManager.getBroadcastModel().getConfiguredBroadcasts()
|
||||
.addListener((ListChangeListener<ConfiguredBroadcast>)c -> updateStreamViews());
|
||||
|
||||
MyEventBus.getEventBus().register(this);
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ import io.github.dsheirer.module.decode.mpt1327.identifier.MPT1327Talkgroup;
|
||||
import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25Talkgroup;
|
||||
import io.github.dsheirer.module.decode.passport.identifier.PassportTalkgroup;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.preference.identifier.talkgroup.LTRTalkgroupFormatter;
|
||||
import io.github.dsheirer.preference.identifier.talkgroup.MPT1327TalkgroupFormatter;
|
||||
import io.github.dsheirer.protocol.Protocol;
|
||||
import io.github.dsheirer.rrapi.type.Flavor;
|
||||
import io.github.dsheirer.rrapi.type.Site;
|
||||
@@ -102,6 +104,30 @@ public class RadioReferenceDecoder
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the talkgroup value to the format used by radio reference
|
||||
* @param value of the talkgroup
|
||||
* @param protocol for the talkgroup
|
||||
* @return radio reference formatted talkgroup
|
||||
*/
|
||||
public static int convertToRadioReferenceTalkgroup(int value, Protocol protocol)
|
||||
{
|
||||
switch(protocol)
|
||||
{
|
||||
case LTR:
|
||||
int area = LTRTalkgroupFormatter.getArea(value);
|
||||
int home = LTRTalkgroupFormatter.getLcn(value);
|
||||
int group = LTRTalkgroupFormatter.getTalkgroup(value);
|
||||
return (area * 100000) + (home * 1000) + group;
|
||||
case MPT1327:
|
||||
int prefix = MPT1327TalkgroupFormatter.getPrefix(value);
|
||||
int ident = MPT1327TalkgroupFormatter.getIdent(value);
|
||||
return (prefix * 10000) + ident;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a talkgroup identifier for the talkgroup using the protocol for the system
|
||||
* @param talkgroup with value
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.gui.playlist.streaming;
|
||||
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastEvent;
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
||||
import io.github.dsheirer.gui.playlist.Editor;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.controlsfx.control.ToggleSwitch;
|
||||
|
||||
/**
|
||||
* Broadcast configuration editor base class
|
||||
* @param <T> type of broadcast configuration
|
||||
*/
|
||||
public abstract class AbstractBroadcastEditor<T extends BroadcastConfiguration> extends Editor<T>
|
||||
{
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private Button mSaveButton;
|
||||
private Button mResetButton;
|
||||
private TextField mFormatField;
|
||||
private TextField mNameTextField;
|
||||
private ToggleSwitch mEnabledSwitch;
|
||||
protected EditorModificationListener mEditorModificationListener = new EditorModificationListener();
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager for access the stream manager
|
||||
*/
|
||||
public AbstractBroadcastEditor(PlaylistManager playlistManager)
|
||||
{
|
||||
mPlaylistManager = playlistManager;
|
||||
getFormatField().setText(getBroadcastServerType().toString());
|
||||
|
||||
VBox buttonBox = new VBox();
|
||||
buttonBox.setPadding(new Insets(10,10,10,10));
|
||||
buttonBox.setSpacing(10);
|
||||
buttonBox.getChildren().addAll(getSaveButton(), getResetButton());
|
||||
|
||||
HBox editorBox = new HBox();
|
||||
HBox.setHgrow(getEditorPane(), Priority.ALWAYS);
|
||||
editorBox.getChildren().addAll(getEditorPane(), buttonBox);
|
||||
getChildren().addAll(editorBox);
|
||||
}
|
||||
|
||||
protected PlaylistManager getPlaylistManager()
|
||||
{
|
||||
return mPlaylistManager;
|
||||
}
|
||||
|
||||
protected abstract GridPane getEditorPane();
|
||||
|
||||
public abstract BroadcastServerType getBroadcastServerType();
|
||||
|
||||
@Override
|
||||
public void setItem(T item)
|
||||
{
|
||||
super.setItem(item);
|
||||
|
||||
getNameTextField().setDisable(item == null);
|
||||
getEnabledSwitch().setDisable(item == null);
|
||||
|
||||
if(item != null)
|
||||
{
|
||||
getNameTextField().setText(item.getName());
|
||||
getEnabledSwitch().selectedProperty().set(item.isEnabled());
|
||||
}
|
||||
else
|
||||
{
|
||||
getNameTextField().setText(null);
|
||||
getEnabledSwitch().selectedProperty().set(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void save()
|
||||
{
|
||||
BroadcastConfiguration configuration = getItem();
|
||||
|
||||
if(configuration != null)
|
||||
{
|
||||
configuration.setEnabled(getEnabledSwitch().isSelected());
|
||||
|
||||
//Detect stream name change so that we can update any aliases that might be using the previous name
|
||||
String previousName = configuration.getName();
|
||||
String updatedName = getNameTextField().getText();
|
||||
configuration.setName(getNameTextField().getText());
|
||||
|
||||
if(previousName != null && !previousName.isEmpty() && !updatedName.contentEquals(previousName))
|
||||
{
|
||||
if(getPlaylistManager().getAliasModel().hasAliasesWithBroadcastChannel(previousName))
|
||||
{
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.getButtonTypes().clear();
|
||||
alert.getButtonTypes().addAll(ButtonType.NO, ButtonType.YES);
|
||||
alert.setTitle("Update Aliases");
|
||||
alert.setHeaderText("Rename requires updating aliases for this stream");
|
||||
alert.setContentText("Do you want to update aliases to new stream name?");
|
||||
alert.initOwner(((Node)getSaveButton()).getScene().getWindow());
|
||||
|
||||
//Workaround for JavaFX KDE on Linux bug in FX 10/11: https://bugs.openjdk.java.net/browse/JDK-8179073
|
||||
alert.setResizable(true);
|
||||
alert.onShownProperty().addListener(e -> {
|
||||
Platform.runLater(() -> alert.setResizable(false));
|
||||
});
|
||||
|
||||
alert.showAndWait().ifPresent(buttonType -> {
|
||||
if(buttonType == ButtonType.YES)
|
||||
{
|
||||
getPlaylistManager().getAliasModel().updateBroadcastChannel(previousName, updatedName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: remove this after we get rid of Swing tables so that we don't have to announce these changes.
|
||||
mPlaylistManager.getBroadcastModel().process(new BroadcastEvent(configuration,
|
||||
BroadcastEvent.Event.CONFIGURATION_CHANGE));
|
||||
}
|
||||
|
||||
modifiedProperty().set(false);
|
||||
}
|
||||
|
||||
protected Button getSaveButton()
|
||||
{
|
||||
if(mSaveButton == null)
|
||||
{
|
||||
mSaveButton = new Button("Save");
|
||||
mSaveButton.setDisable(true);
|
||||
mSaveButton.setMaxWidth(Double.MAX_VALUE);
|
||||
mSaveButton.setOnAction(event -> save());
|
||||
mSaveButton.disableProperty().bind(modifiedProperty().not());
|
||||
}
|
||||
|
||||
return mSaveButton;
|
||||
}
|
||||
|
||||
protected Button getResetButton()
|
||||
{
|
||||
if(mResetButton == null)
|
||||
{
|
||||
mResetButton = new Button("Reset");
|
||||
mResetButton.setDisable(true);
|
||||
mResetButton.setMaxWidth(Double.MAX_VALUE);
|
||||
mResetButton.setOnAction(event -> setItem(getItem()));
|
||||
mResetButton.disableProperty().bind(modifiedProperty().not());
|
||||
}
|
||||
|
||||
return mResetButton;
|
||||
}
|
||||
|
||||
protected TextField getNameTextField()
|
||||
{
|
||||
if(mNameTextField == null)
|
||||
{
|
||||
mNameTextField = new TextField();
|
||||
mNameTextField.setDisable(true);
|
||||
mNameTextField.textProperty().addListener(mEditorModificationListener);
|
||||
}
|
||||
|
||||
return mNameTextField;
|
||||
}
|
||||
|
||||
protected TextField getFormatField()
|
||||
{
|
||||
if(mFormatField == null)
|
||||
{
|
||||
mFormatField = new TextField();
|
||||
mFormatField.setDisable(true);
|
||||
}
|
||||
|
||||
return mFormatField;
|
||||
}
|
||||
|
||||
protected ToggleSwitch getEnabledSwitch()
|
||||
{
|
||||
if(mEnabledSwitch == null)
|
||||
{
|
||||
mEnabledSwitch = new ToggleSwitch();
|
||||
mEnabledSwitch.setDisable(true);
|
||||
mEnabledSwitch.selectedProperty()
|
||||
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
|
||||
}
|
||||
|
||||
return mEnabledSwitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple string change listener that sets the editor modified flag to true any time text fields are edited.
|
||||
*/
|
||||
public class EditorModificationListener implements ChangeListener<String>
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
modifiedProperty().set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,39 +23,18 @@
|
||||
package io.github.dsheirer.gui.playlist.streaming;
|
||||
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
||||
import io.github.dsheirer.gui.control.IntegerTextField;
|
||||
import io.github.dsheirer.gui.playlist.Editor;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.PasswordField;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.controlsfx.control.ToggleSwitch;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Base class for broadcast configuration editors.
|
||||
*/
|
||||
public abstract class AbstractStreamEditor<T extends BroadcastConfiguration> extends Editor<T>
|
||||
public abstract class AbstractStreamEditor<T extends BroadcastConfiguration> extends AbstractBroadcastEditor<T>
|
||||
{
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private Button mSaveButton;
|
||||
private Button mResetButton;
|
||||
private TextField mFormatField;
|
||||
private TextField mNameTextField;
|
||||
private TextField mHostTextField;
|
||||
private TextField mUnMaskedPasswordTextField;
|
||||
private PasswordField mMaskedPasswordTextField;
|
||||
@@ -63,25 +42,13 @@ public abstract class AbstractStreamEditor<T extends BroadcastConfiguration> ext
|
||||
private IntegerTextField mPortTextField;
|
||||
private IntegerTextField mDelayTextField;
|
||||
private IntegerTextField mMaxAgeTextField;
|
||||
private ToggleSwitch mEnabledSwitch;
|
||||
protected EditorModificationListener mEditorModificationListener = new EditorModificationListener();
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*/
|
||||
public AbstractStreamEditor(PlaylistManager playlistManager)
|
||||
{
|
||||
mPlaylistManager = playlistManager;
|
||||
|
||||
VBox buttonBox = new VBox();
|
||||
buttonBox.setPadding(new Insets(10,10,10,10));
|
||||
buttonBox.setSpacing(10);
|
||||
buttonBox.getChildren().addAll(getSaveButton(), getResetButton());
|
||||
|
||||
HBox editorBox = new HBox();
|
||||
HBox.setHgrow(getEditorPane(), Priority.ALWAYS);
|
||||
editorBox.getChildren().addAll(getEditorPane(), buttonBox);
|
||||
getChildren().addAll(editorBox);
|
||||
super(playlistManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,32 +56,26 @@ public abstract class AbstractStreamEditor<T extends BroadcastConfiguration> ext
|
||||
{
|
||||
super.setItem(item);
|
||||
|
||||
getNameTextField().setDisable(item == null);
|
||||
getHostTextField().setDisable(item == null);
|
||||
getPortTextField().setDisable(item == null);
|
||||
getMaskedPasswordTextField().setDisable(item == null);
|
||||
getUnMaskedPasswordTextField().setDisable(item == null);
|
||||
getEnabledSwitch().setDisable(item == null);
|
||||
getMaxAgeTextField().setDisable(item == null);
|
||||
getDelayTextField().setDisable(item == null);
|
||||
|
||||
if(item != null)
|
||||
{
|
||||
getNameTextField().setText(item.getName());
|
||||
getHostTextField().setText(item.getHost());
|
||||
getPortTextField().set(item.getPort());
|
||||
getMaskedPasswordTextField().setText(item.getPassword());
|
||||
getEnabledSwitch().setSelected(item.isEnabled());
|
||||
getMaxAgeTextField().set((int)(item.getMaximumRecordingAge() / 1000)); //Convert millis to seconds
|
||||
getDelayTextField().set((int)(item.getDelay() / 1000)); //Convert millis to seconds
|
||||
}
|
||||
else
|
||||
{
|
||||
getNameTextField().setText(null);
|
||||
getHostTextField().setText(null);
|
||||
getPortTextField().set(0);
|
||||
getMaskedPasswordTextField().setText(null);
|
||||
getEnabledSwitch().setSelected(false);
|
||||
getMaxAgeTextField().set(0);
|
||||
getDelayTextField().set(0);
|
||||
}
|
||||
@@ -130,80 +91,24 @@ public abstract class AbstractStreamEditor<T extends BroadcastConfiguration> ext
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
super.save();
|
||||
|
||||
BroadcastConfiguration configuration = getItem();
|
||||
|
||||
if(configuration != null)
|
||||
{
|
||||
configuration.setEnabled(getEnabledSwitch().isSelected());
|
||||
configuration.setHost(getHostTextField().getText());
|
||||
configuration.setPort(getPortTextField().get());
|
||||
configuration.setPassword(getMaskedPasswordTextField().getText());
|
||||
configuration.setDelay(getDelayTextField().get() * 1000); //Convert seconds to millis
|
||||
configuration.setMaximumRecordingAge(getMaxAgeTextField().get() * 1000); //Convert seconds to millis
|
||||
|
||||
//Detect stream name change so that we can update any aliases that might be using the previous name
|
||||
String previousName = configuration.getName();
|
||||
String updatedName = getNameTextField().getText();
|
||||
configuration.setName(getNameTextField().getText());
|
||||
|
||||
if(previousName != null && !previousName.isEmpty() && !updatedName.contentEquals(previousName))
|
||||
{
|
||||
if(mPlaylistManager.getAliasModel().hasAliasesWithBroadcastChannel(previousName))
|
||||
{
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.getButtonTypes().clear();
|
||||
alert.getButtonTypes().addAll(ButtonType.NO, ButtonType.YES);
|
||||
alert.setTitle("Update Aliases");
|
||||
alert.setHeaderText("Rename requires updating aliases for this stream");
|
||||
alert.setContentText("Do you want to update aliases to new stream name?");
|
||||
alert.initOwner(((Node)getSaveButton()).getScene().getWindow());
|
||||
|
||||
//Workaround for JavaFX KDE on Linux bug in FX 10/11: https://bugs.openjdk.java.net/browse/JDK-8179073
|
||||
alert.setResizable(true);
|
||||
alert.onShownProperty().addListener(e -> {
|
||||
Platform.runLater(() -> alert.setResizable(false));
|
||||
});
|
||||
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
|
||||
if(result.get() == ButtonType.YES)
|
||||
{
|
||||
mPlaylistManager.getAliasModel().updateBroadcastChannel(previousName, updatedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
modifiedProperty().set(false);
|
||||
}
|
||||
|
||||
public abstract BroadcastServerType getBroadcastServerType();
|
||||
|
||||
protected abstract GridPane getEditorPane();
|
||||
|
||||
protected TextField getFormatField()
|
||||
{
|
||||
if(mFormatField == null)
|
||||
{
|
||||
mFormatField = new TextField();
|
||||
mFormatField.setDisable(true);
|
||||
}
|
||||
|
||||
return mFormatField;
|
||||
}
|
||||
|
||||
protected TextField getNameTextField()
|
||||
{
|
||||
if(mNameTextField == null)
|
||||
{
|
||||
mNameTextField = new TextField();
|
||||
mNameTextField.setDisable(true);
|
||||
mNameTextField.textProperty().addListener(mEditorModificationListener);
|
||||
}
|
||||
|
||||
return mNameTextField;
|
||||
}
|
||||
|
||||
protected TextField getHostTextField()
|
||||
{
|
||||
if(mHostTextField == null)
|
||||
@@ -287,57 +192,4 @@ public abstract class AbstractStreamEditor<T extends BroadcastConfiguration> ext
|
||||
|
||||
return mMaxAgeTextField;
|
||||
}
|
||||
|
||||
protected ToggleSwitch getEnabledSwitch()
|
||||
{
|
||||
if(mEnabledSwitch == null)
|
||||
{
|
||||
mEnabledSwitch = new ToggleSwitch();
|
||||
mEnabledSwitch.setDisable(true);
|
||||
mEnabledSwitch.selectedProperty()
|
||||
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
|
||||
}
|
||||
|
||||
return mEnabledSwitch;
|
||||
}
|
||||
|
||||
private Button getSaveButton()
|
||||
{
|
||||
if(mSaveButton == null)
|
||||
{
|
||||
mSaveButton = new Button("Save");
|
||||
mSaveButton.setDisable(true);
|
||||
mSaveButton.setMaxWidth(Double.MAX_VALUE);
|
||||
mSaveButton.setOnAction(event -> save());
|
||||
mSaveButton.disableProperty().bind(modifiedProperty().not());
|
||||
}
|
||||
|
||||
return mSaveButton;
|
||||
}
|
||||
|
||||
private Button getResetButton()
|
||||
{
|
||||
if(mResetButton == null)
|
||||
{
|
||||
mResetButton = new Button("Reset");
|
||||
mResetButton.setDisable(true);
|
||||
mResetButton.setMaxWidth(Double.MAX_VALUE);
|
||||
mResetButton.setOnAction(event -> setItem(getItem()));
|
||||
mResetButton.disableProperty().bind(modifiedProperty().not());
|
||||
}
|
||||
|
||||
return mResetButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple string change listener that sets the editor modified flag to true any time text fields are edited.
|
||||
*/
|
||||
public class EditorModificationListener implements ChangeListener<String>
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
|
||||
{
|
||||
modifiedProperty().set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.gui.playlist.streaming;
|
||||
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyCallBroadcaster;
|
||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyCallConfiguration;
|
||||
import io.github.dsheirer.gui.control.IntegerTextField;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Broadcastify calls API configuration editor
|
||||
*/
|
||||
public class BroadcastifyCallEditor extends AbstractBroadcastEditor<BroadcastifyCallConfiguration>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(BroadcastifyCallEditor.class);
|
||||
private IntegerTextField mSystemIdTextField;
|
||||
private Button mTestButton;
|
||||
private IntegerTextField mMaxAgeTextField;
|
||||
private GridPane mEditorPane;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager for accessing the broadcast model
|
||||
*/
|
||||
public BroadcastifyCallEditor(PlaylistManager playlistManager)
|
||||
{
|
||||
super(playlistManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(BroadcastifyCallConfiguration item)
|
||||
{
|
||||
super.setItem(item);
|
||||
|
||||
getSystemIdTextField().setDisable(item == null);
|
||||
|
||||
if(item != null)
|
||||
{
|
||||
getSystemIdTextField().set(item.getSystemID());
|
||||
}
|
||||
else
|
||||
{
|
||||
getSystemIdTextField().set(0);
|
||||
}
|
||||
|
||||
modifiedProperty().set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if(getItem() != null)
|
||||
{
|
||||
int systemID = getSystemIdTextField().get() != null ? getSystemIdTextField().get() : 0;
|
||||
getItem().setSystemID(systemID);
|
||||
}
|
||||
|
||||
super.save();
|
||||
}
|
||||
|
||||
public BroadcastServerType getBroadcastServerType()
|
||||
{
|
||||
return BroadcastServerType.BROADCASTIFY_CALL;
|
||||
}
|
||||
|
||||
protected GridPane getEditorPane()
|
||||
{
|
||||
if(mEditorPane == null)
|
||||
{
|
||||
mEditorPane = new GridPane();
|
||||
mEditorPane.setPadding(new Insets(10, 5, 10,10));
|
||||
mEditorPane.setVgap(10);
|
||||
mEditorPane.setHgap(5);
|
||||
|
||||
int row = 0;
|
||||
|
||||
Label formatLabel = new Label("Format");
|
||||
GridPane.setHalignment(formatLabel, HPos.RIGHT);
|
||||
GridPane.setConstraints(formatLabel, 0, row);
|
||||
mEditorPane.getChildren().add(formatLabel);
|
||||
|
||||
GridPane.setConstraints(getFormatField(), 1, row);
|
||||
mEditorPane.getChildren().add(getFormatField());
|
||||
|
||||
Label enabledLabel = new Label("Enabled");
|
||||
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
|
||||
GridPane.setConstraints(enabledLabel, 2, row);
|
||||
mEditorPane.getChildren().add(enabledLabel);
|
||||
|
||||
GridPane.setConstraints(getEnabledSwitch(), 3, row);
|
||||
mEditorPane.getChildren().add(getEnabledSwitch());
|
||||
|
||||
Label systemLabel = new Label("Name");
|
||||
GridPane.setHalignment(systemLabel, HPos.RIGHT);
|
||||
GridPane.setConstraints(systemLabel, 0, ++row);
|
||||
mEditorPane.getChildren().add(systemLabel);
|
||||
|
||||
GridPane.setConstraints(getNameTextField(), 1, row);
|
||||
mEditorPane.getChildren().add(getNameTextField());
|
||||
|
||||
Label systemIdLabel = new Label("System ID");
|
||||
GridPane.setHalignment(systemIdLabel, HPos.RIGHT);
|
||||
GridPane.setConstraints(systemIdLabel, 0, ++row);
|
||||
mEditorPane.getChildren().add(systemIdLabel);
|
||||
|
||||
GridPane.setConstraints(getSystemIdTextField(), 1, row);
|
||||
mEditorPane.getChildren().add(getSystemIdTextField());
|
||||
|
||||
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
|
||||
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
|
||||
GridPane.setConstraints(maxAgeLabel, 0, ++row);
|
||||
mEditorPane.getChildren().add(maxAgeLabel);
|
||||
|
||||
GridPane.setConstraints(getMaxAgeTextField(), 1, row);
|
||||
mEditorPane.getChildren().add(getMaxAgeTextField());
|
||||
|
||||
GridPane.setConstraints(getTestButton(), 1, ++row);
|
||||
mEditorPane.getChildren().add(getTestButton());
|
||||
}
|
||||
|
||||
return mEditorPane;
|
||||
}
|
||||
|
||||
protected IntegerTextField getMaxAgeTextField()
|
||||
{
|
||||
if(mMaxAgeTextField == null)
|
||||
{
|
||||
mMaxAgeTextField = new IntegerTextField();
|
||||
mMaxAgeTextField.setDisable(true);
|
||||
mMaxAgeTextField.textProperty().addListener(mEditorModificationListener);
|
||||
}
|
||||
|
||||
return mMaxAgeTextField;
|
||||
}
|
||||
|
||||
private IntegerTextField getSystemIdTextField()
|
||||
{
|
||||
if(mSystemIdTextField == null)
|
||||
{
|
||||
mSystemIdTextField = new IntegerTextField();
|
||||
mSystemIdTextField.setDisable(true);
|
||||
mSystemIdTextField.textProperty().addListener(mEditorModificationListener);
|
||||
}
|
||||
|
||||
return mSystemIdTextField;
|
||||
}
|
||||
|
||||
private Button getTestButton()
|
||||
{
|
||||
if(mTestButton == null)
|
||||
{
|
||||
mTestButton = new Button("Test Connection");
|
||||
mTestButton.setOnAction(event -> {
|
||||
int systemID = getSystemIdTextField().get();
|
||||
|
||||
if(systemID < 1)
|
||||
{
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR, "Please enter a non-zero System ID",
|
||||
ButtonType.OK);
|
||||
alert.setTitle("Test Connection");
|
||||
alert.setHeaderText("A valid System ID is required");
|
||||
alert.initOwner(getTestButton().getScene().getWindow());
|
||||
alert.show();
|
||||
return;
|
||||
}
|
||||
|
||||
BroadcastifyCallConfiguration configToTest = new BroadcastifyCallConfiguration();
|
||||
configToTest.setSystemID(systemID);
|
||||
String result = BroadcastifyCallBroadcaster.testConnection(configToTest);
|
||||
|
||||
if(result == null)
|
||||
{
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Test successful.",
|
||||
ButtonType.OK);
|
||||
alert.setTitle("Test Connection");
|
||||
alert.setHeaderText("Success!");
|
||||
alert.initOwner(getTestButton().getScene().getWindow());
|
||||
alert.show();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR, "Error: " + result,
|
||||
ButtonType.OK);
|
||||
alert.setTitle("Test Connection");
|
||||
alert.setHeaderText("Test Failed.");
|
||||
alert.initOwner(getTestButton().getScene().getWindow());
|
||||
alert.show();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mTestButton;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ package io.github.dsheirer.gui.playlist.streaming;
|
||||
|
||||
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyConfiguration;
|
||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyFeedConfiguration;
|
||||
import io.github.dsheirer.gui.control.IntegerTextField;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import javafx.geometry.HPos;
|
||||
@@ -36,7 +36,7 @@ import javafx.scene.layout.GridPane;
|
||||
/**
|
||||
* Broadcastify streaming configuration editor
|
||||
*/
|
||||
public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyConfiguration>
|
||||
public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyFeedConfiguration>
|
||||
{
|
||||
private GridPane mEditorPane;
|
||||
private TextField mMountPointTextField;
|
||||
@@ -48,7 +48,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyC
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(BroadcastifyConfiguration item)
|
||||
public void setItem(BroadcastifyFeedConfiguration item)
|
||||
{
|
||||
super.setItem(item);
|
||||
|
||||
@@ -72,13 +72,13 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyC
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
super.save();
|
||||
|
||||
if(getItem() != null)
|
||||
{
|
||||
getItem().setFeedID(getFeedIdTextField().get());
|
||||
getItem().setMountPoint(getMountPointTextField().getText());
|
||||
}
|
||||
|
||||
super.save();
|
||||
}
|
||||
|
||||
public BroadcastServerType getBroadcastServerType()
|
||||
@@ -100,7 +100,6 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyC
|
||||
GridPane.setConstraints(formatLabel, 0, 0);
|
||||
mEditorPane.getChildren().add(formatLabel);
|
||||
|
||||
getFormatField().setText(getBroadcastServerType().toString());
|
||||
GridPane.setConstraints(getFormatField(), 1, 0);
|
||||
mEditorPane.getChildren().add(getFormatField());
|
||||
|
||||
|
||||
@@ -82,8 +82,6 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
super.save();
|
||||
|
||||
if(getItem() != null)
|
||||
{
|
||||
getItem().setMountPoint(getMountPointTextField().getText());
|
||||
@@ -93,7 +91,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
|
||||
getItem().setURL(getURLTextField().getText());
|
||||
}
|
||||
|
||||
modifiedProperty().set(false);
|
||||
super.save();
|
||||
}
|
||||
|
||||
protected GridPane getEditorPane()
|
||||
|
||||
@@ -82,8 +82,6 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
super.save();
|
||||
|
||||
if(getItem() != null)
|
||||
{
|
||||
getItem().setDescription(getDescriptionTextField().getText());
|
||||
@@ -91,7 +89,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
|
||||
getItem().setPublic(getPublicToggleSwitch().isSelected());
|
||||
}
|
||||
|
||||
modifiedProperty().set(false);
|
||||
super.save();
|
||||
}
|
||||
|
||||
protected GridPane getEditorPane()
|
||||
|
||||
@@ -91,8 +91,6 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
super.save();
|
||||
|
||||
if(getItem() != null)
|
||||
{
|
||||
getItem().setURL(getUrlTextField().getText());
|
||||
@@ -102,7 +100,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
|
||||
getItem().setStreamID(getStreamIdTextField().get());
|
||||
}
|
||||
|
||||
modifiedProperty().set(false);
|
||||
super.save();
|
||||
}
|
||||
|
||||
protected GridPane getEditorPane()
|
||||
|
||||
@@ -35,12 +35,14 @@ public class StreamEditorFactory
|
||||
* @param broadcastServerType to edit
|
||||
* @return editor or the default unknown editor
|
||||
*/
|
||||
public static AbstractStreamEditor getEditor(BroadcastServerType broadcastServerType, PlaylistManager playlistManager)
|
||||
public static AbstractBroadcastEditor getEditor(BroadcastServerType broadcastServerType, PlaylistManager playlistManager)
|
||||
{
|
||||
switch(broadcastServerType)
|
||||
{
|
||||
case BROADCASTIFY:
|
||||
return new BroadcastifyStreamEditor(playlistManager);
|
||||
case BROADCASTIFY_CALL:
|
||||
return new BroadcastifyCallEditor(playlistManager);
|
||||
case ICECAST_HTTP:
|
||||
return new IcecastHTTPStreamEditor(playlistManager);
|
||||
case ICECAST_TCP:
|
||||
|
||||
@@ -27,15 +27,13 @@ import io.github.dsheirer.audio.broadcast.BroadcastFactory;
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastFormat;
|
||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
||||
import io.github.dsheirer.audio.broadcast.ConfiguredBroadcast;
|
||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyConfiguration;
|
||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyFeedConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.rrapi.type.UserFeedBroadcast;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.geometry.Pos;
|
||||
@@ -64,7 +62,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -76,7 +74,7 @@ public class StreamingEditor extends SplitPane
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(StreamingEditor.class);
|
||||
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private final PlaylistManager mPlaylistManager;
|
||||
private TableView<ConfiguredBroadcast> mConfiguredBroadcastTableView;
|
||||
private MenuButton mNewButton;
|
||||
private Button mDeleteButton;
|
||||
@@ -84,13 +82,13 @@ public class StreamingEditor extends SplitPane
|
||||
private Tab mConfigurationTab;
|
||||
private Tab mAliasTab;
|
||||
private Label mRadioReferenceLoginLabel;
|
||||
private AbstractStreamEditor mCurrentEditor;
|
||||
private UnknownStreamEditor mUnknownEditor;
|
||||
private Map<BroadcastServerType, AbstractStreamEditor> mEditorMap = new HashMap();
|
||||
private List<UserFeedBroadcast> mBroadcastifyFeeds = new ArrayList<>();
|
||||
private AbstractBroadcastEditor<?> mCurrentEditor;
|
||||
private final UnknownStreamEditor mUnknownEditor;
|
||||
private Map<BroadcastServerType, AbstractBroadcastEditor<?>> mEditorMap = new EnumMap<>(BroadcastServerType.class);
|
||||
private final List<UserFeedBroadcast> mBroadcastifyFeeds = new ArrayList<>();
|
||||
private ScrollPane mEditorScrollPane;
|
||||
private StreamAliasSelectionEditor mStreamAliasSelectionEditor;
|
||||
private StreamConfigurationEditorModificationListener mStreamConfigurationEditorModificationListener =
|
||||
private final StreamConfigurationEditorModificationListener mStreamConfigurationEditorModificationListener =
|
||||
new StreamConfigurationEditorModificationListener();
|
||||
|
||||
/**
|
||||
@@ -124,7 +122,7 @@ public class StreamingEditor extends SplitPane
|
||||
getItems().addAll(editorBox, getTabPane());
|
||||
}
|
||||
|
||||
private void setEditor(AbstractStreamEditor<?> editor)
|
||||
private void setEditor(AbstractBroadcastEditor<?> editor)
|
||||
{
|
||||
if(editor != getCurrentEditor())
|
||||
{
|
||||
@@ -167,20 +165,17 @@ public class StreamingEditor extends SplitPane
|
||||
alert.setTitle("Save Changes");
|
||||
alert.setHeaderText("Streaming configuration has been modified");
|
||||
alert.setContentText("Do you want to save these changes?");
|
||||
alert.initOwner(((Node)getNewButton()).getScene().getWindow());
|
||||
alert.initOwner((getNewButton()).getScene().getWindow());
|
||||
|
||||
//Workaround for JavaFX KDE on Linux bug in FX 10/11: https://bugs.openjdk.java.net/browse/JDK-8179073
|
||||
alert.setResizable(true);
|
||||
alert.onShownProperty().addListener(e -> {
|
||||
Platform.runLater(() -> alert.setResizable(false));
|
||||
alert.onShownProperty().addListener(e -> Platform.runLater(() -> alert.setResizable(false)));
|
||||
alert.showAndWait().ifPresent(buttonType -> {
|
||||
if(buttonType == ButtonType.YES)
|
||||
{
|
||||
getCurrentEditor().save();
|
||||
}
|
||||
});
|
||||
|
||||
Optional<ButtonType> result = alert.showAndWait();
|
||||
|
||||
if(result.get() == ButtonType.YES)
|
||||
{
|
||||
getCurrentEditor().save();
|
||||
}
|
||||
}
|
||||
|
||||
getDeleteButton().setDisable(configuredBroadcast == null);
|
||||
@@ -203,7 +198,7 @@ public class StreamingEditor extends SplitPane
|
||||
|
||||
if(editorType == null || editorType != configType)
|
||||
{
|
||||
AbstractStreamEditor editor = mEditorMap.get(configType);
|
||||
AbstractBroadcastEditor editor = mEditorMap.get(configType);
|
||||
|
||||
if(editor == null)
|
||||
{
|
||||
@@ -280,7 +275,7 @@ public class StreamingEditor extends SplitPane
|
||||
return mRadioReferenceLoginLabel;
|
||||
}
|
||||
|
||||
private AbstractStreamEditor getCurrentEditor()
|
||||
private AbstractBroadcastEditor getCurrentEditor()
|
||||
{
|
||||
if(mCurrentEditor == null)
|
||||
{
|
||||
@@ -455,20 +450,15 @@ public class StreamingEditor extends SplitPane
|
||||
public CreateBroadcastifyMenuItem(UserFeedBroadcast userFeedBroadcast)
|
||||
{
|
||||
mUserFeedBroadcast = userFeedBroadcast;
|
||||
setText("Broadcastify: " + mUserFeedBroadcast.getDescription());
|
||||
setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
BroadcastConfiguration configuration = BroadcastifyConfiguration.from(mUserFeedBroadcast);
|
||||
setText("Broadcastify Feed: " + mUserFeedBroadcast.getDescription());
|
||||
setOnAction(event -> {
|
||||
BroadcastConfiguration configuration = BroadcastifyFeedConfiguration.from(mUserFeedBroadcast);
|
||||
|
||||
if(configuration != null)
|
||||
{
|
||||
ConfiguredBroadcast configuredBroadcast = mPlaylistManager.getBroadcastModel()
|
||||
.addBroadcastConfiguration(configuration);
|
||||
getConfiguredBroadcastTableView().getSelectionModel().select(configuredBroadcast);
|
||||
}
|
||||
if(configuration != null)
|
||||
{
|
||||
ConfiguredBroadcast configuredBroadcast = mPlaylistManager.getBroadcastModel()
|
||||
.addBroadcastConfiguration(configuration);
|
||||
getConfiguredBroadcastTableView().getSelectionModel().select(configuredBroadcast);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -485,16 +475,15 @@ public class StreamingEditor extends SplitPane
|
||||
{
|
||||
setText(type.toString());
|
||||
mBroadcastServerType = type;
|
||||
setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
BroadcastConfiguration config = BroadcastFactory.getConfiguration(mBroadcastServerType, BroadcastFormat.MP3);
|
||||
ConfiguredBroadcast configuredBroadcast = mPlaylistManager.getBroadcastModel()
|
||||
.addBroadcastConfiguration(config);
|
||||
getConfiguredBroadcastTableView().getSelectionModel().select(configuredBroadcast);
|
||||
}
|
||||
|
||||
//Temporary disable until we receive a production API key for broadcastify calls api
|
||||
setDisable(mBroadcastServerType == BroadcastServerType.BROADCASTIFY_CALL);
|
||||
|
||||
setOnAction(event -> {
|
||||
BroadcastConfiguration config = BroadcastFactory.getConfiguration(mBroadcastServerType, BroadcastFormat.MP3);
|
||||
ConfiguredBroadcast configuredBroadcast = mPlaylistManager.getBroadcastModel()
|
||||
.addBroadcastConfiguration(config);
|
||||
getConfiguredBroadcastTableView().getSelectionModel().select(configuredBroadcast);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user