mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
#1506 Resolves multiple performance issues: tuner freezing after a period of run time, buffer overflows, degraded audio playback. (#1513)
-Reduces message and event histories per channel from 500 to 200. -Resolves issue of tuner freezing due to cancelled USB transfer buffers not being resubmitted. -Reworks the audio playback system to remove in-progress call preemption and remove thread locks which can cause glitchy behavior during audio playback. -Updates audio outputs to also use single thread pool for processing audio segments. -Updates MBECallSequenceConverter to batch convert MBE to WAV audio. -Unifies recording filename prefixes across baseband, mbe and binary recordings. -Resolves issue with registering heartbeat manager to dispatcher. -Uses single-thread thread pools for Dispatcher to support batch & process to overcome context switching consistency issue in Windows. Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* 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
|
||||
@@ -24,10 +24,9 @@ import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.preference.playback.PlaybackPreference;
|
||||
import io.github.dsheirer.source.mixer.MixerChannelConfiguration;
|
||||
import io.github.dsheirer.source.mixer.MixerManager;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Orientation;
|
||||
@@ -49,9 +48,6 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
|
||||
/**
|
||||
@@ -60,20 +56,16 @@ import java.nio.ShortBuffer;
|
||||
public class PlaybackPreferenceEditor extends HBox
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(PlaybackPreferenceEditor.class);
|
||||
private PlaybackPreference mPlaybackPreference;
|
||||
private final PlaybackPreference mPlaybackPreference;
|
||||
private GridPane mEditorPane;
|
||||
private ComboBox<MixerChannelConfiguration> mMixerComboBox;
|
||||
private Button mMixerTestButton;
|
||||
private ToggleSwitch mUseAudioSegmentStartToneSwitch;
|
||||
private Button mTestStartToneButton;
|
||||
private ToggleSwitch mUseAudioSegmentPreemptToneSwitch;
|
||||
private Button mTestPreemptToneButton;
|
||||
private ToggleSwitch mUseAudioSegmentDropToneSwitch;
|
||||
private Button mTestDropToneButton;
|
||||
private ComboBox<ToneFrequency> mStartToneFrequencyComboBox;
|
||||
private ComboBox<ToneVolume> mStartToneVolumeComboBox;
|
||||
private ComboBox<ToneFrequency> mPreemptToneFrequencyComboBox;
|
||||
private ComboBox<ToneVolume> mPreemptToneVolumeComboBox;
|
||||
private ComboBox<ToneFrequency> mDropToneFrequencyComboBox;
|
||||
private ComboBox<ToneVolume> mDropToneVolumeComboBox;
|
||||
|
||||
@@ -114,18 +106,6 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
mEditorPane.add(getStartToneVolumeComboBox(), 4, row);
|
||||
mEditorPane.add(getTestStartToneButton(), 5, row);
|
||||
|
||||
mEditorPane.add(getUseAudioSegmentPreemptToneSwitch(), 0, ++row);
|
||||
mEditorPane.add(new Label("Priority Preempt Tone"), 1, row, 3, 1);
|
||||
Label preemptFrequencyLabel = new Label("Frequency:");
|
||||
GridPane.setHalignment(preemptFrequencyLabel, HPos.RIGHT);
|
||||
mEditorPane.add(preemptFrequencyLabel, 1, ++row);
|
||||
mEditorPane.add(getPreemptToneFrequencyComboBox(), 2, row);
|
||||
Label preemptVolumeLabel = new Label("Volume:");
|
||||
GridPane.setHalignment(preemptVolumeLabel, HPos.RIGHT);
|
||||
mEditorPane.add(preemptVolumeLabel, 3, row);
|
||||
mEditorPane.add(getPreemptToneVolumeComboBox(), 4, row);
|
||||
mEditorPane.add(getTestPreemptToneButton(), 5, row);
|
||||
|
||||
mEditorPane.add(getUseAudioSegmentDropToneSwitch(), 0, ++row);
|
||||
mEditorPane.add(new Label("Drop Tone - Do Not Monitor"), 1, row, 3, 1);
|
||||
Label dropFrequencyLabel = new Label("Frequency:");
|
||||
@@ -177,52 +157,21 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
mUseAudioSegmentStartToneSwitch = new ToggleSwitch();
|
||||
mUseAudioSegmentStartToneSwitch.setAlignment(Pos.BASELINE_RIGHT);
|
||||
mUseAudioSegmentStartToneSwitch.setSelected(mPlaybackPreference.getUseAudioSegmentStartTone());
|
||||
mUseAudioSegmentStartToneSwitch.selectedProperty().addListener(new ChangeListener<Boolean>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue)
|
||||
{
|
||||
mPlaybackPreference.setUseAudioSegmentStartTone(newValue);
|
||||
}
|
||||
});
|
||||
mUseAudioSegmentStartToneSwitch.selectedProperty().addListener((observable, oldValue, newValue) ->
|
||||
mPlaybackPreference.setUseAudioSegmentStartTone(newValue));
|
||||
}
|
||||
|
||||
return mUseAudioSegmentStartToneSwitch;
|
||||
}
|
||||
|
||||
private ToggleSwitch getUseAudioSegmentPreemptToneSwitch()
|
||||
{
|
||||
if(mUseAudioSegmentPreemptToneSwitch == null)
|
||||
{
|
||||
mUseAudioSegmentPreemptToneSwitch = new ToggleSwitch();
|
||||
mUseAudioSegmentPreemptToneSwitch.setSelected(mPlaybackPreference.getUseAudioSegmentPreemptTone());
|
||||
mUseAudioSegmentPreemptToneSwitch.selectedProperty().addListener(new ChangeListener<Boolean>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue)
|
||||
{
|
||||
mPlaybackPreference.setUseAudioSegmentPreemptTone(newValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mUseAudioSegmentPreemptToneSwitch;
|
||||
}
|
||||
|
||||
private ToggleSwitch getUseAudioSegmentDropToneSwitch()
|
||||
{
|
||||
if(mUseAudioSegmentDropToneSwitch == null)
|
||||
{
|
||||
mUseAudioSegmentDropToneSwitch = new ToggleSwitch();
|
||||
mUseAudioSegmentDropToneSwitch.setSelected(mPlaybackPreference.getUseAudioSegmentDropTone());
|
||||
mUseAudioSegmentDropToneSwitch.selectedProperty().addListener(new ChangeListener<Boolean>()
|
||||
{
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue)
|
||||
{
|
||||
mPlaybackPreference.setUseAudioSegmentDropTone(newValue);
|
||||
}
|
||||
});
|
||||
mUseAudioSegmentDropToneSwitch.selectedProperty().addListener((observable, oldValue, newValue) ->
|
||||
mPlaybackPreference.setUseAudioSegmentDropTone(newValue));
|
||||
}
|
||||
|
||||
return mUseAudioSegmentDropToneSwitch;
|
||||
@@ -236,14 +185,7 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
IconNode iconNode = new IconNode(FontAwesome.PLAY);
|
||||
iconNode.setFill(Color.CORNFLOWERBLUE);
|
||||
mTestStartToneButton.setGraphic(iconNode);
|
||||
mTestStartToneButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
play(mPlaybackPreference.getStartTone());
|
||||
}
|
||||
});
|
||||
mTestStartToneButton.setOnAction(event -> play(mPlaybackPreference.getStartTone()));
|
||||
|
||||
mTestStartToneButton.disableProperty().bind(getUseAudioSegmentStartToneSwitch().selectedProperty().not());
|
||||
}
|
||||
@@ -251,29 +193,6 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
return mTestStartToneButton;
|
||||
}
|
||||
|
||||
public Button getTestPreemptToneButton()
|
||||
{
|
||||
if(mTestPreemptToneButton == null)
|
||||
{
|
||||
mTestPreemptToneButton = new Button("Test");
|
||||
IconNode iconNode = new IconNode(FontAwesome.PLAY);
|
||||
iconNode.setFill(Color.CORNFLOWERBLUE);
|
||||
mTestPreemptToneButton.setGraphic(iconNode);
|
||||
mTestPreemptToneButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
play(mPlaybackPreference.getPreemptTone());
|
||||
}
|
||||
});
|
||||
|
||||
mTestPreemptToneButton.disableProperty().bind(getUseAudioSegmentPreemptToneSwitch().selectedProperty().not());
|
||||
}
|
||||
|
||||
return mTestPreemptToneButton;
|
||||
}
|
||||
|
||||
public Button getTestDropToneButton()
|
||||
{
|
||||
if(mTestDropToneButton == null)
|
||||
@@ -282,14 +201,7 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
IconNode iconNode = new IconNode(FontAwesome.PLAY);
|
||||
iconNode.setFill(Color.CORNFLOWERBLUE);
|
||||
mTestDropToneButton.setGraphic(iconNode);
|
||||
mTestDropToneButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
play(mPlaybackPreference.getDropTone());
|
||||
}
|
||||
});
|
||||
mTestDropToneButton.setOnAction(event -> play(mPlaybackPreference.getDropTone()));
|
||||
|
||||
mTestDropToneButton.disableProperty().bind(getUseAudioSegmentDropToneSwitch().selectedProperty().not());
|
||||
}
|
||||
@@ -357,36 +269,6 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
return mStartToneVolumeComboBox;
|
||||
}
|
||||
|
||||
public ComboBox<ToneFrequency> getPreemptToneFrequencyComboBox()
|
||||
{
|
||||
if(mPreemptToneFrequencyComboBox == null)
|
||||
{
|
||||
mPreemptToneFrequencyComboBox = new ComboBox<>();
|
||||
mPreemptToneFrequencyComboBox.getItems().addAll(ToneFrequency.values());
|
||||
mPreemptToneFrequencyComboBox.getSelectionModel().select(mPlaybackPreference.getPreemptToneFrequency());
|
||||
mPreemptToneFrequencyComboBox.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldValue, newValue) -> mPlaybackPreference.setPreemptToneFrequency(newValue));
|
||||
mPreemptToneFrequencyComboBox.disableProperty().bind(getUseAudioSegmentPreemptToneSwitch().selectedProperty().not());
|
||||
}
|
||||
|
||||
return mPreemptToneFrequencyComboBox;
|
||||
}
|
||||
|
||||
public ComboBox<ToneVolume> getPreemptToneVolumeComboBox()
|
||||
{
|
||||
if(mPreemptToneVolumeComboBox == null)
|
||||
{
|
||||
mPreemptToneVolumeComboBox = new ComboBox<>();
|
||||
mPreemptToneVolumeComboBox.getItems().addAll(ToneVolume.values());
|
||||
mPreemptToneVolumeComboBox.getSelectionModel().select(mPlaybackPreference.getPreemptToneVolume());
|
||||
mPreemptToneVolumeComboBox.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldValue, newValue) -> mPlaybackPreference.setPreemptToneVolume(newValue));
|
||||
mPreemptToneVolumeComboBox.disableProperty().bind(getUseAudioSegmentPreemptToneSwitch().selectedProperty().not());
|
||||
}
|
||||
|
||||
return mPreemptToneVolumeComboBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the audio buffer over the default mono playback device
|
||||
* @param audioSamples with 8 kHz mono PCM samples
|
||||
|
||||
Reference in New Issue
Block a user