Skip to content

Commit

Permalink
#1723 work in progress - adds playback controls and playback of selec…
Browse files Browse the repository at this point in the history
…ted call.
  • Loading branch information
Dennis Sheirer committed Dec 23, 2023
1 parent 0cf77ba commit db58dbd
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.audio.call;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Button;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.HBox;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import jiconfont.icons.font_awesome.FontAwesome;
import jiconfont.javafx.IconNode;

/**
* Audio playback controller.
*/
public class AudioPlaybackControlView extends HBox
{
private static final int ICON_SIZE = 16;
private ObjectProperty<MediaPlayer> mMediaPlayer = new SimpleObjectProperty<>();
private Button mForwardButton;
private Button mBackwardButton;
private Button mRestartButton;
private ToggleButton mAutoRepeatButton;
private ToggleGroup mPlaybackGroup;
private ToggleButton mPlayButton;
private ToggleButton mPauseButton;
private ToggleButton mStopButton;

/**
* Constructs an instance
*/
public AudioPlaybackControlView()
{
setSpacing(2);
getChildren().addAll(getStopButton(), getPlayButton(), getPauseButton(), getRestartButton(),
getBackwardButton(), getForwardButton(), getAutoRepeatButton());
mediaPlayerProperty().addListener((o, oldV, newV) -> updateControls());
}

/**
* Update the controls when the media player changes
*/
private void updateControls()
{
boolean disable = mediaPlayerProperty().get() == null;
getStopButton().setDisable(disable);
getPlayButton().setDisable(disable);
getPauseButton().setDisable(disable);
getForwardButton().setDisable(disable);
getBackwardButton().setDisable(disable);
getRestartButton().setDisable(disable);
getAutoRepeatButton().setDisable(disable);
}

/**
* Media player property that can be bound to a media player controller.
*/
public ObjectProperty<MediaPlayer> mediaPlayerProperty()
{
return mMediaPlayer;
}

/**
* Clears the media player for this view.
*/
public void clearMediaPlayer()
{
mMediaPlayer.set(null);
}

private ToggleGroup getPlaybackGroup()
{
if(mPlaybackGroup == null)
{
mPlaybackGroup = new ToggleGroup();
}

return mPlaybackGroup;
}

/**
* Play button
*/
private ToggleButton getPlayButton()
{
if(mPlayButton == null)
{
mPlayButton = new ToggleButton();
mPlayButton.setToggleGroup(getPlaybackGroup());
mPlayButton.setTooltip(new Tooltip("Play Audio"));
mPlayButton.setDisable(true);
IconNode iconNode = new IconNode(FontAwesome.PLAY);
iconNode.setIconSize(ICON_SIZE);
iconNode.setFill(Color.BLACK);
mPlayButton.setGraphic(iconNode);
mPlayButton.onActionProperty().set(event -> {
MediaPlayer mediaPlayer = mediaPlayerProperty().get();
if(mediaPlayer != null)
{
mediaPlayer.play();
}
});
}

return mPlayButton;
}

/**
* Pause button
*/
private ToggleButton getPauseButton()
{
if(mPauseButton == null)
{
mPauseButton = new ToggleButton();
mPlayButton.setToggleGroup(getPlaybackGroup());
mPauseButton.setTooltip(new Tooltip("Pause Audio Playback"));
mPauseButton.setDisable(true);
IconNode iconNode = new IconNode(FontAwesome.PAUSE);
iconNode.setIconSize(ICON_SIZE);
iconNode.setFill(Color.BLACK);
mPauseButton.setGraphic(iconNode);
mPauseButton.onActionProperty().set(event -> {
MediaPlayer mediaPlayer = mediaPlayerProperty().get();

if(mediaPlayer != null)
{
mediaPlayer.pause();
}
});
}

return mPauseButton;
}

/**
* Stop button
*/
private ToggleButton getStopButton()
{
if(mStopButton == null)
{
mStopButton = new ToggleButton();
mStopButton.setToggleGroup(getPlaybackGroup());
mStopButton.setTooltip(new Tooltip("Stop Audio Playback"));
mStopButton.setDisable(true);
IconNode iconNode = new IconNode(FontAwesome.STOP);
iconNode.setIconSize(ICON_SIZE);
iconNode.setFill(Color.BLACK);
mStopButton.setGraphic(iconNode);
mStopButton.onActionProperty().set(event -> {
MediaPlayer mediaPlayer = mediaPlayerProperty().get();
if(mediaPlayer != null)
{
mediaPlayer.stop();
}
});
}

return mStopButton;
}

/**
* Restart audio playback button
*/
private Button getRestartButton()
{
if(mRestartButton == null)
{
mRestartButton = new Button();
mRestartButton.setTooltip(new Tooltip("Restart Audio Playback"));
mRestartButton.setDisable(true);
IconNode iconNode = new IconNode(FontAwesome.FAST_BACKWARD);
iconNode.setIconSize(ICON_SIZE);
iconNode.setFill(Color.BLACK);
mRestartButton.setGraphic(iconNode);
mRestartButton.onActionProperty().set(event -> {
MediaPlayer mediaPlayer = mediaPlayerProperty().get();
if(mediaPlayer != null)
{
Toggle selected = getPlaybackGroup().getSelectedToggle();
if(getPlayButton().equals(selected))
{
mediaPlayer.stop();
mediaPlayer.play();
}
else if(getStopButton().equals(selected))
{
mediaPlayer.play();
}
else if(getPauseButton().equals(selected))
{
mediaPlayer.stop();
mediaPlayer.play();
}
}
});
}

return mRestartButton;
}

/**
* Rewind button
*/
private Button getBackwardButton()
{
if(mBackwardButton == null)
{
mBackwardButton = new Button();
mBackwardButton.setTooltip(new Tooltip("Rewind Audio Playback 3 Seconds"));
mBackwardButton.setDisable(true);
IconNode iconNode = new IconNode(FontAwesome.BACKWARD);
iconNode.setIconSize(ICON_SIZE);
iconNode.setFill(Color.BLACK);
mBackwardButton.setGraphic(iconNode);
}

return mBackwardButton;
}

/**
* Fast Forward button
*/
private Button getForwardButton()
{
if(mForwardButton == null)
{
mForwardButton = new Button();
mForwardButton.setTooltip(new Tooltip("Fast Forward Audio Playback 3 Seconds"));
mForwardButton.setDisable(true);
IconNode iconNode = new IconNode(FontAwesome.FORWARD);
iconNode.setIconSize(ICON_SIZE);
iconNode.setFill(Color.BLACK);
mForwardButton.setGraphic(iconNode);
}

return mForwardButton;
}

private ToggleButton getAutoRepeatButton()
{
if(mAutoRepeatButton == null)
{
mAutoRepeatButton = new ToggleButton();
mAutoRepeatButton.setSelected(true);
mAutoRepeatButton.setTooltip(new Tooltip("Auto-repeat audio playback toggle button."));
mAutoRepeatButton.setDisable(true);
IconNode iconNode = new IconNode(FontAwesome.REPEAT);
iconNode.setIconSize(ICON_SIZE);
iconNode.setFill(Color.BLACK);
mAutoRepeatButton.setGraphic(iconNode);
}

return mAutoRepeatButton;
}
}
60 changes: 51 additions & 9 deletions src/main/java/io/github/dsheirer/audio/call/CallView.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,15 @@
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Separator;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
Expand Down Expand Up @@ -92,6 +95,8 @@ public class CallView extends VBox implements IPageRequestListener
private Sort mSort = DEFAULT_SORT;
private ComboBox<SearchColumn> mSearchColumnComboBox;
private CheckBox mSearchExactCheckBox;
private AudioPlaybackControlView mAudioPlaybackControlView;
private Button mAutoModeButton;

/**
* Constructs an instance
Expand All @@ -116,13 +121,19 @@ public CallView()
public void postConstruct()
{
HBox controlBox = new HBox();
controlBox.setPadding(new Insets(2, 15, 2, 15));
HBox.setHgrow(getPagingBox(), Priority.ALWAYS);
controlBox.getChildren().addAll(getSearchBox(), getPagingBox());
controlBox.setSpacing(10);
controlBox.setPadding(new Insets(5, 5, 5, 5));
getAudioPlaybackControlView().setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(getSearchBox(), Priority.ALWAYS);
getSearchBox().setAlignment(Pos.CENTER_RIGHT);

Separator separator = new Separator(Orientation.VERTICAL);
controlBox.getChildren().addAll(getAudioPlaybackControlView(), separator, getAutoModeButton(), getSearchBox());

VBox.setVgrow(getCallTableView(), Priority.ALWAYS);
getChildren().addAll(controlBox, getCallTableView());
getChildren().addAll(controlBox, getCallTableView(), getPagingBox());

getPagingController().setPadding(new Insets(5, 5, 5, 5));
getPagingController().update(1, 20);

//Register for call event notifications
Expand Down Expand Up @@ -272,6 +283,33 @@ private int getPageSize()
return getPageSizeComboBox().getValue();
}

/**
* Sets playback mode to auto
*/
private Button getAutoModeButton()
{
if(mAutoModeButton == null)
{
mAutoModeButton = new Button("Auto-Playback");
mAutoModeButton.setDisable(true);
}

return mAutoModeButton;
}

/**
* Audio playback control view.
*/
private AudioPlaybackControlView getAudioPlaybackControlView()
{
if(mAudioPlaybackControlView == null)
{
mAudioPlaybackControlView = new AudioPlaybackControlView();
}

return mAudioPlaybackControlView;
}

/**
* Calls label to display the number of calls in the database.
*/
Expand Down Expand Up @@ -347,10 +385,10 @@ private HBox getPagingBox()
if(mPagingBox == null)
{
mPagingBox = new HBox();
mPagingBox.setAlignment(Pos.CENTER_RIGHT);
mPagingBox.setAlignment(Pos.CENTER_LEFT);
mPagingBox.setSpacing(3);
Label pageSizeLabel = new Label("Page Size:");
getPagingController().setPadding(new Insets(2, 0, 6, 20));
// getPagingController().setPadding(new Insets(2, 0, 6, 20));
pageSizeLabel.setPadding(new Insets(0, 2, 0, 10));
getCallsCountLabel().setPadding(new Insets(0, 0, 0, 10));
mPagingBox.getChildren().addAll(getPagingController(), pageSizeLabel, getPageSizeComboBox(), getCallsCountLabel());
Expand Down Expand Up @@ -489,13 +527,17 @@ private TableView<Call> getCallTableView()
fromIdColumn, fromAliasColumn, protocolColumn, frequencyColumn, systemColumn, siteColumn, channelColumn,
duplicateColumn, recordColumn, streamColumn, monitorColumn);
mCallTableView.setPlaceholder(getPlaceholderProgressIndicator());
mCallTableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null)
mCallTableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, selectedCall) -> {
if(selectedCall != null)
{
mAudioPlaybackController.getPrimaryController().play(newValue, false);
mAudioPlaybackController.getPrimaryController().play(selectedCall, false);
}
});
getPlaceholderProgressIndicator().setVisible(true);

//Bind the playback control view to the primary audio channel playback controller
getAudioPlaybackControlView().mediaPlayerProperty()
.bind(mAudioPlaybackController.getPrimaryController().mediaPlayerProperty());
}

return mCallTableView;
Expand Down
Loading

0 comments on commit db58dbd

Please sign in to comment.