mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
Resolves #680 Audio Do Not Monitor is not working. Adds audio segment drop tone to indicate that an audio playback is dropped because the do not monitor setting was applied after the audio segment started. (#681)
Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
@@ -161,7 +161,7 @@ public class AudioSegment implements Listener<IdentifierUpdateNotification>
|
||||
*/
|
||||
public boolean isDoNotMonitor()
|
||||
{
|
||||
return mMonitorPriority.get() == Priority.DO_NOT_MONITOR;
|
||||
return mMonitorPriority.get() <= Priority.DO_NOT_MONITOR;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,6 +85,8 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
private IntegerProperty mAudioPriority = new SimpleIntegerProperty(Priority.DEFAULT_PRIORITY);
|
||||
private ByteBuffer mAudioSegmentStartTone;
|
||||
private ByteBuffer mAudioSegmentPreemptTone;
|
||||
private ByteBuffer mAudioSegmentDropTone;
|
||||
private boolean mRunning = false;
|
||||
|
||||
/**
|
||||
* Single audio channel playback with automatic starting and stopping of the
|
||||
@@ -147,9 +149,9 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
mixer.getMixerInfo().getName() + " | " + getChannelName() + "]");
|
||||
}
|
||||
|
||||
//Run the queue processor task every 250 milliseconds or 4 times a second
|
||||
//Run the queue processor task every 100 milliseconds or 10 times a second
|
||||
mProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioSegmentProcessor(),
|
||||
0, 250, TimeUnit.MILLISECONDS);
|
||||
0, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
mAudioStartEvent = new AudioEvent(AudioEvent.Type.AUDIO_STARTED, getChannelName());
|
||||
@@ -255,12 +257,13 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates audio segment start and preempt tone insertion clips
|
||||
* Updates audio segment start, drop and preempt tone insertion clips
|
||||
*/
|
||||
private void updateToneInsertionAudioClips()
|
||||
{
|
||||
mAudioSegmentStartTone = null;
|
||||
mAudioSegmentPreemptTone = null;
|
||||
mAudioSegmentDropTone = null;
|
||||
|
||||
float[] start = mUserPreferences.getPlaybackPreference().getStartTone();
|
||||
|
||||
@@ -275,6 +278,13 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
{
|
||||
mAudioSegmentPreemptTone = convert(preempt);
|
||||
}
|
||||
|
||||
float[] drop = mUserPreferences.getPlaybackPreference().getDropTone();
|
||||
|
||||
if(drop != null)
|
||||
{
|
||||
mAudioSegmentDropTone = convert(drop);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,6 +320,15 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
return mAudioSegmentPreemptTone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a tone indicating that the current audio segment playback has been dropped because the audio segment
|
||||
* has been flagged as Do Not Monitor after playback has started.
|
||||
*/
|
||||
private ByteBuffer getAudioSegmentDropTone()
|
||||
{
|
||||
return mAudioSegmentDropTone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the audio buffer data to the source data line. If the data line is not currently playing, write as
|
||||
* much of the buffer to the data line as will fit, start the dataline, and then finish writing the residual
|
||||
@@ -362,8 +381,18 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
|
||||
try
|
||||
{
|
||||
//Remove an assigned audio segment that's subsequently flagged as do not monitor before playback
|
||||
if(mNextAudioSegment.isDoNotMonitor())
|
||||
{
|
||||
mNextAudioSegment = null;
|
||||
|
||||
if(mCurrentAudioSegment == null)
|
||||
{
|
||||
mEmptyProperty.set(true);
|
||||
}
|
||||
}
|
||||
//For linked audio segments, allow the linked segment to complete first before assigning the next
|
||||
if(mNextAudioSegment.isLinked())
|
||||
else if(mNextAudioSegment.isLinked())
|
||||
{
|
||||
if(mCurrentAudioSegment == null)
|
||||
{
|
||||
@@ -427,10 +456,15 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
|
||||
if(mCurrentAudioSegment != null)
|
||||
{
|
||||
//Check for completed audio segment
|
||||
if(mCurrentAudioSegment.completeProperty().get() &&
|
||||
mCurrentBufferIndex >= mCurrentAudioSegment.getAudioBufferCount())
|
||||
//Check for completed audio segment or a segment flagged as Do Not Monitor
|
||||
if(mCurrentAudioSegment.isDoNotMonitor() || (mCurrentAudioSegment.completeProperty().get() &&
|
||||
mCurrentBufferIndex >= mCurrentAudioSegment.getAudioBufferCount()))
|
||||
{
|
||||
if(mCurrentAudioSegment.isDoNotMonitor())
|
||||
{
|
||||
playAudio(getAudioSegmentDropTone());
|
||||
}
|
||||
|
||||
dispose(mCurrentAudioSegment);
|
||||
mCurrentAudioSegment = null;
|
||||
|
||||
@@ -455,7 +489,8 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
//while processing, exit the loop so that we can evaluate the next for higher priority preempt. If the next
|
||||
//segment is a linked segment, ignore it so that we can close out the current segment.
|
||||
while((mNextAudioSegment == null || mNextAudioSegment.isLinked()) &&
|
||||
mCurrentBufferIndex < mCurrentAudioSegment.getAudioBufferCount())
|
||||
mCurrentBufferIndex < mCurrentAudioSegment.getAudioBufferCount() &&
|
||||
!mCurrentAudioSegment.isDoNotMonitor())
|
||||
{
|
||||
float[] audioBuffer = mCurrentAudioSegment.getAudioBuffers().get(mCurrentBufferIndex++);
|
||||
|
||||
@@ -595,6 +630,7 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
if(mCanProcessAudio && !mOutput.isRunning() && mOutput.available() <= mBufferStartThreshold)
|
||||
{
|
||||
mOutput.start();
|
||||
mRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,11 +642,26 @@ public abstract class AudioOutput implements LineListener, Listener<IdentifierUp
|
||||
*/
|
||||
private void checkStop()
|
||||
{
|
||||
if(mCanProcessAudio && mOutput.isRunning() && mOutput.available() >= mBufferStopThreshold)
|
||||
if(mRunning)
|
||||
{
|
||||
mOutput.drain();
|
||||
mOutput.stop();
|
||||
broadcast(null);
|
||||
//If the output buffer falls below the threshold then drain the output and stop playback
|
||||
if(mOutput.isRunning() && mOutput.available() >= mBufferStopThreshold)
|
||||
{
|
||||
mOutput.drain();
|
||||
mOutput.stop();
|
||||
mRunning = false;
|
||||
}
|
||||
//If output playback stopped on its own because the buffer emptied, then cleanup
|
||||
else if(!mOutput.isRunning())
|
||||
{
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
//If we stopped audio playback, broadcast a null identifier to clear the gui panel
|
||||
if(!mRunning)
|
||||
{
|
||||
broadcast(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ public class AudioPlaybackManager implements Listener<AudioSegment>, IAudioContr
|
||||
private MixerChannelConfiguration mMixerChannelConfiguration;
|
||||
private List<AudioOutput> mAudioOutputs = new ArrayList<>();
|
||||
private List<AudioSegment> mAudioSegments = new ArrayList<>();
|
||||
private List<AudioSegment> mPendingAudioSegments = new ArrayList<>();
|
||||
private LinkedTransferQueue<AudioSegment> mNewAudioSegmentQueue = new LinkedTransferQueue<>();
|
||||
|
||||
/**
|
||||
@@ -109,9 +110,50 @@ public class AudioPlaybackManager implements Listener<AudioSegment>, IAudioContr
|
||||
*/
|
||||
private void processAudioSegments()
|
||||
{
|
||||
//Transfer new audio segments out of the concurrent queue and into the managed segments list.
|
||||
mNewAudioSegmentQueue.drainTo(mAudioSegments);
|
||||
//Process new audio segments queue. If segment has audio, queue it for replay, otherwise place in pending queue
|
||||
AudioSegment newSegment = mNewAudioSegmentQueue.poll();
|
||||
|
||||
while(newSegment != null)
|
||||
{
|
||||
if(newSegment.hasAudio())
|
||||
{
|
||||
mAudioSegments.add(newSegment);
|
||||
}
|
||||
else
|
||||
{
|
||||
mPendingAudioSegments.add(newSegment);
|
||||
}
|
||||
|
||||
newSegment = mNewAudioSegmentQueue.poll();
|
||||
}
|
||||
|
||||
//Transfer pending audio segments that now have audio or that completed without ever having audio
|
||||
if(!mPendingAudioSegments.isEmpty())
|
||||
{
|
||||
Iterator<AudioSegment> it = mPendingAudioSegments.iterator();
|
||||
|
||||
AudioSegment audioSegment;
|
||||
|
||||
while(it.hasNext())
|
||||
{
|
||||
audioSegment = it.next();
|
||||
|
||||
if(audioSegment.hasAudio())
|
||||
{
|
||||
//Queue it up for replay
|
||||
it.remove();
|
||||
mAudioSegments.add(audioSegment);
|
||||
}
|
||||
else if(audioSegment.completeProperty().get())
|
||||
{
|
||||
//Rare situation: the audio segment completed but never had audio ... dispose it
|
||||
it.remove();
|
||||
audioSegment.decrementConsumerCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Process all audio segments that have audio
|
||||
if(!mAudioSegments.isEmpty())
|
||||
{
|
||||
Iterator<AudioSegment> it = mAudioSegments.iterator();
|
||||
@@ -119,15 +161,15 @@ public class AudioPlaybackManager implements Listener<AudioSegment>, IAudioContr
|
||||
|
||||
//Remove any audio segments flagged as do not monitor. Don't remove completed segments yet, because
|
||||
//we want to give them a brief chance at playback. Automatically assign linked audio segments to the
|
||||
//current audio output for audio continutity
|
||||
//current audio output for audio continuity
|
||||
while(it.hasNext())
|
||||
{
|
||||
audioSegment = it.next();
|
||||
|
||||
if(audioSegment.isDoNotMonitor())
|
||||
{
|
||||
audioSegment.decrementConsumerCount();
|
||||
it.remove();
|
||||
audioSegment.decrementConsumerCount();
|
||||
}
|
||||
else if(audioSegment.isLinked())
|
||||
{
|
||||
@@ -135,14 +177,14 @@ public class AudioPlaybackManager implements Listener<AudioSegment>, IAudioContr
|
||||
{
|
||||
if(audioOutput.isLinkedTo(audioSegment))
|
||||
{
|
||||
audioOutput.play(audioSegment);
|
||||
it.remove();
|
||||
audioOutput.play(audioSegment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Assign audio segments to empty audio outputs
|
||||
//Sort audio segments by playback priority and assign to empty audio outputs
|
||||
if(!mAudioSegments.isEmpty())
|
||||
{
|
||||
Collections.sort(mAudioSegments, Comparator.comparingInt(o -> o.monitorPriorityProperty().get()));
|
||||
@@ -165,7 +207,6 @@ public class AudioPlaybackManager implements Listener<AudioSegment>, IAudioContr
|
||||
//Preempt ongoing audio segment playback when higher priority audio segments are available
|
||||
if(!mAudioSegments.isEmpty())
|
||||
{
|
||||
//Assign empty audio outputs first
|
||||
for(AudioOutput audioOutput: mAudioOutputs)
|
||||
{
|
||||
if(mAudioSegments.get(0).monitorPriorityProperty().get() < audioOutput.audioPriorityProperty().get())
|
||||
@@ -180,7 +221,7 @@ public class AudioPlaybackManager implements Listener<AudioSegment>, IAudioContr
|
||||
}
|
||||
}
|
||||
|
||||
//Remove any audio segments marked as completed
|
||||
//Remove any audio segments marked as complete that didn't get assigned to an output
|
||||
it = mAudioSegments.iterator(); //reset the iterator
|
||||
while(it.hasNext())
|
||||
{
|
||||
@@ -275,7 +316,7 @@ public class AudioPlaybackManager implements Listener<AudioSegment>, IAudioContr
|
||||
}
|
||||
|
||||
mProcessingTask = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioSegmentProcessor(),
|
||||
0, 250, TimeUnit.MILLISECONDS);
|
||||
0, 100, TimeUnit.MILLISECONDS);
|
||||
mControllerBroadcaster.broadcast(CONFIGURATION_CHANGE_COMPLETE);
|
||||
mMixerChannelConfiguration = entry;
|
||||
}
|
||||
|
||||
@@ -422,7 +422,6 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
|
||||
|
||||
for(Channel channel : channelsToStop)
|
||||
{
|
||||
mLog.info("Stopping channel: " + channel.toString());
|
||||
stopProcessing(channel, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +71,14 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
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;
|
||||
|
||||
public PlaybackPreferenceEditor(UserPreferences userPreferences)
|
||||
{
|
||||
@@ -100,6 +104,7 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
mEditorPane.add(getMixerTestButton(), 5, row);
|
||||
mEditorPane.add(new Separator(Orientation.HORIZONTAL), 0, ++row, 6, 1);
|
||||
mEditorPane.add(new Label("Audio Playback Insert Tones"), 0, ++row, 2, 1);
|
||||
|
||||
mEditorPane.add(getUseAudioSegmentStartToneSwitch(), 0, ++row);
|
||||
mEditorPane.add(new Label("Start Tone"), 1, row, 3, 1);
|
||||
Label startFrequencyLabel = new Label("Frequency:");
|
||||
@@ -111,6 +116,7 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
mEditorPane.add(startVolumeLabel, 3, row);
|
||||
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:");
|
||||
@@ -122,6 +128,18 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
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:");
|
||||
GridPane.setHalignment(dropFrequencyLabel, HPos.RIGHT);
|
||||
mEditorPane.add(dropFrequencyLabel, 1, ++row);
|
||||
mEditorPane.add(getDropToneFrequencyComboBox(), 2, row);
|
||||
Label dropVolumeLabel = new Label("Volume:");
|
||||
GridPane.setHalignment(dropVolumeLabel, HPos.RIGHT);
|
||||
mEditorPane.add(dropVolumeLabel, 3, row);
|
||||
mEditorPane.add(getDropToneVolumeComboBox(), 4, row);
|
||||
mEditorPane.add(getTestDropToneButton(), 5, row);
|
||||
}
|
||||
|
||||
return mEditorPane;
|
||||
@@ -194,6 +212,25 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mUseAudioSegmentDropToneSwitch;
|
||||
}
|
||||
|
||||
public Button getTestStartToneButton()
|
||||
{
|
||||
if(mTestStartToneButton == null)
|
||||
@@ -240,6 +277,59 @@ public class PlaybackPreferenceEditor extends HBox
|
||||
return mTestPreemptToneButton;
|
||||
}
|
||||
|
||||
public Button getTestDropToneButton()
|
||||
{
|
||||
if(mTestDropToneButton == null)
|
||||
{
|
||||
mTestDropToneButton = new Button("Test");
|
||||
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.disableProperty().bind(getUseAudioSegmentDropToneSwitch().selectedProperty().not());
|
||||
}
|
||||
|
||||
return mTestDropToneButton;
|
||||
}
|
||||
|
||||
public ComboBox<ToneFrequency> getDropToneFrequencyComboBox()
|
||||
{
|
||||
if(mDropToneFrequencyComboBox == null)
|
||||
{
|
||||
mDropToneFrequencyComboBox = new ComboBox<>();
|
||||
mDropToneFrequencyComboBox.getItems().addAll(ToneFrequency.values());
|
||||
mDropToneFrequencyComboBox.getSelectionModel().select(mPlaybackPreference.getDropToneFrequency());
|
||||
mDropToneFrequencyComboBox.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldValue, newValue) -> mPlaybackPreference.setDropToneFrequency(newValue));
|
||||
mDropToneFrequencyComboBox.disableProperty().bind(getUseAudioSegmentDropToneSwitch().selectedProperty().not());
|
||||
}
|
||||
|
||||
return mDropToneFrequencyComboBox;
|
||||
}
|
||||
|
||||
public ComboBox<ToneVolume> getDropToneVolumeComboBox()
|
||||
{
|
||||
if(mDropToneVolumeComboBox == null)
|
||||
{
|
||||
mDropToneVolumeComboBox = new ComboBox<>();
|
||||
mDropToneVolumeComboBox.getItems().addAll(ToneVolume.values());
|
||||
mDropToneVolumeComboBox.getSelectionModel().select(mPlaybackPreference.getDropToneVolume());
|
||||
mDropToneVolumeComboBox.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldValue, newValue) -> mPlaybackPreference.setDropToneVolume(newValue));
|
||||
mDropToneVolumeComboBox.disableProperty().bind(getUseAudioSegmentDropToneSwitch().selectedProperty().not());
|
||||
}
|
||||
|
||||
return mDropToneVolumeComboBox;
|
||||
}
|
||||
|
||||
public ComboBox<ToneFrequency> getStartToneFrequencyComboBox()
|
||||
{
|
||||
if(mStartToneFrequencyComboBox == null)
|
||||
|
||||
@@ -38,12 +38,18 @@ import java.util.prefs.Preferences;
|
||||
*/
|
||||
public class PlaybackPreference extends Preference
|
||||
{
|
||||
private static final String PREFERENCE_KEY_USE_AUDIO_SEGMENT_DROP_TONE = "audio.playback.segment.drop.tone";
|
||||
private static final String PREFERENCE_KEY_DROP_TONE_FREQUENCY = "audio.playback.segment.drop.frequency";
|
||||
private static final String PREFERENCE_KEY_DROP_TONE_VOLUME = "audio.playback.segment.drop.volume";
|
||||
|
||||
private static final String PREFERENCE_KEY_USE_AUDIO_SEGMENT_PREEMPT_TONE = "audio.playback.segment.preempt.tone";
|
||||
private static final String PREFERENCE_KEY_PREEMPT_TONE_FREQUENCY = "audio.playback.segment.preempt.frequency";
|
||||
private static final String PREFERENCE_KEY_PREEMPT_TONE_VOLUME = "audio.playback.segment.preempt.volume";
|
||||
|
||||
private static final String PREFERENCE_KEY_USE_AUDIO_SEGMENT_START_TONE = "audio.playback.segment.start.tone";
|
||||
private static final String PREFERENCE_KEY_START_TONE_FREQUENCY = "audio.playback.segment.start.frequency";
|
||||
private static final String PREFERENCE_KEY_START_TONE_VOLUME = "audio.playback.segment.start.volume";
|
||||
private static final String PREFERENCE_KEY_PREEMPT_TONE_FREQUENCY = "audio.playback.segment.preempt.frequency";
|
||||
private static final String PREFERENCE_KEY_PREEMPT_TONE_VOLUME = "audio.playback.segment.preempt.volume";
|
||||
|
||||
private static final String PREFERENCE_KEY_MIXER_CHANNEL_CONFIG = "audio.playback.mixer.channel.configuration";
|
||||
private static final int TONE_LENGTH_SAMPLES = 180;
|
||||
|
||||
@@ -51,10 +57,13 @@ public class PlaybackPreference extends Preference
|
||||
private Preferences mPreferences = Preferences.userNodeForPackage(PlaybackPreference.class);
|
||||
private Boolean mUseAudioSegmentStartTone;
|
||||
private Boolean mUseAudioSegmentPreemptTone;
|
||||
private Boolean mUseAudioSegmentDropTone;
|
||||
private ToneFrequency mStartToneFrequency;
|
||||
private ToneVolume mStartToneVolume;
|
||||
private ToneFrequency mPreemptToneFrequency;
|
||||
private ToneVolume mPreemptToneVolume;
|
||||
private ToneFrequency mDropToneFrequency;
|
||||
private ToneVolume mDropToneVolume;
|
||||
private MixerChannelConfiguration mMixerChannelConfiguration;
|
||||
|
||||
/**
|
||||
@@ -72,6 +81,29 @@ public class PlaybackPreference extends Preference
|
||||
return PreferenceType.PLAYBACK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if an audio segment drop tone should be used.
|
||||
*/
|
||||
public boolean getUseAudioSegmentDropTone()
|
||||
{
|
||||
if(mUseAudioSegmentDropTone == null)
|
||||
{
|
||||
mUseAudioSegmentDropTone = mPreferences.getBoolean(PREFERENCE_KEY_USE_AUDIO_SEGMENT_DROP_TONE, true);
|
||||
}
|
||||
|
||||
return mUseAudioSegmentDropTone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the preference for using an audio segment drop tone
|
||||
*/
|
||||
public void setUseAudioSegmentDropTone(boolean use)
|
||||
{
|
||||
mUseAudioSegmentDropTone = use;
|
||||
mPreferences.putBoolean(PREFERENCE_KEY_USE_AUDIO_SEGMENT_DROP_TONE, use);
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if an audio segment start tone should be used.
|
||||
*/
|
||||
@@ -118,6 +150,30 @@ public class PlaybackPreference extends Preference
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency for the drop tone
|
||||
*/
|
||||
public ToneFrequency getDropToneFrequency()
|
||||
{
|
||||
if(mDropToneFrequency == null)
|
||||
{
|
||||
int frequency = mPreferences.getInt(PREFERENCE_KEY_DROP_TONE_FREQUENCY, ToneFrequency.F500.getValue());
|
||||
mDropToneFrequency = ToneFrequency.fromValue(frequency);
|
||||
}
|
||||
|
||||
return mDropToneFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frequency for the drop tone
|
||||
*/
|
||||
public void setDropToneFrequency(ToneFrequency toneFrequency)
|
||||
{
|
||||
mDropToneFrequency = toneFrequency;
|
||||
mPreferences.putInt(PREFERENCE_KEY_DROP_TONE_FREQUENCY, toneFrequency.getValue());
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Frequency for the start tone
|
||||
*/
|
||||
@@ -166,6 +222,30 @@ public class PlaybackPreference extends Preference
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop tone volume
|
||||
*/
|
||||
public ToneVolume getDropToneVolume()
|
||||
{
|
||||
if(mDropToneVolume == null)
|
||||
{
|
||||
int volume = mPreferences.getInt(PREFERENCE_KEY_DROP_TONE_VOLUME, ToneVolume.V3.getValue());
|
||||
mDropToneVolume = ToneVolume.fromValue(volume);
|
||||
}
|
||||
|
||||
return mDropToneVolume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the drop tone volume
|
||||
*/
|
||||
public void setDropToneVolume(ToneVolume toneVolume)
|
||||
{
|
||||
mDropToneVolume = toneVolume;
|
||||
mPreferences.putInt(PREFERENCE_KEY_DROP_TONE_VOLUME, toneVolume.getValue());
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tone volume
|
||||
*/
|
||||
@@ -240,6 +320,19 @@ public class PlaybackPreference extends Preference
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer with samples for the audio segment drop tone
|
||||
*/
|
||||
public float[] getDropTone()
|
||||
{
|
||||
if(getUseAudioSegmentDropTone())
|
||||
{
|
||||
return ToneUtil.getTone(getDropToneFrequency(), getDropToneVolume(), TONE_LENGTH_SAMPLES);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test tone to use for testing the currently selected mixer output
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user