#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:
Denny Sheirer
2020-05-02 10:29:45 +00:00
committed by GitHub
parent cc52ae5bd7
commit 379461e649
30 changed files with 1883 additions and 522 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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());

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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:

View File

@@ -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);
});
}
}