mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
Resolves issue #23.
Adds audio output display and management options supporting mono and stereo output options. Provides audio output supporting prioritization by talkgroup and/or channel selection. Supports muting all channels, or muting individual channels and individual audio gain/volume controls.
This commit is contained in:
@@ -6,20 +6,19 @@ import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.BooleanControl;
|
||||
import javax.sound.sampled.FloatControl;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import source.mixer.MixerChannel;
|
||||
import audio.AudioEvent;
|
||||
import audio.AudioFormats;
|
||||
import audio.AudioPacket;
|
||||
@@ -27,14 +26,14 @@ import audio.AudioPacket.Type;
|
||||
import controller.NamingThreadFactory;
|
||||
|
||||
/**
|
||||
* Audio output with automatic flow control based on the availability of
|
||||
* Mono Audio output with automatic flow control based on the availability of
|
||||
* audio data packets.
|
||||
*/
|
||||
public class MonoAudioOutput extends AudioOutput
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( MonoAudioOutput.class );
|
||||
|
||||
/* Output line buffer size is set at one second of audio at 48 kHz and
|
||||
/* Output line buffer size is set at one half second of audio at 48 kHz and
|
||||
* two bytes per sample */
|
||||
private final static int BUFFER_SIZE = 48000;
|
||||
|
||||
@@ -42,40 +41,34 @@ public class MonoAudioOutput extends AudioOutput
|
||||
* audio and automatically starting or stopping audio playback. We set the
|
||||
* data line available space threshold to start when we're 20 ms away from
|
||||
* being full, and the stop threshold when 20 ms away from being empty */
|
||||
private final static int SAMPLE_SIZE_40_MS = 48000 / 25;
|
||||
private final static int SAMPLE_SIZE_40_MS = BUFFER_SIZE / 25;
|
||||
private final static int START_THRESHOLD = SAMPLE_SIZE_40_MS;
|
||||
private final static int STOP_THRESHOLD = BUFFER_SIZE - SAMPLE_SIZE_40_MS;
|
||||
|
||||
private LinkedTransferQueue<AudioPacket> mBuffer = new LinkedTransferQueue<>();
|
||||
|
||||
private ScheduledExecutorService mExecutorService;
|
||||
|
||||
private SourceDataLine mOutput;
|
||||
private FloatControl mGainControl;
|
||||
private BooleanControl mMuteControl;
|
||||
|
||||
private boolean mCanProcessAudio;
|
||||
|
||||
private long mLastBufferReceived;
|
||||
|
||||
private AudioEvent mAudioStartEvent;
|
||||
private AudioEvent mAudioStopEvent;
|
||||
|
||||
public MonoAudioOutput()
|
||||
public MonoAudioOutput( Mixer mixer )
|
||||
{
|
||||
super();
|
||||
|
||||
mAudioStartEvent = new AudioEvent( AudioEvent.Type.AUDIO_STARTED, getChannelName() );
|
||||
mAudioStopEvent = new AudioEvent( AudioEvent.Type.AUDIO_STOPPED, getChannelName() );
|
||||
|
||||
mAudioStartEvent = new AudioEvent( AudioEvent.Type.AUDIO_STARTED,
|
||||
getChannelName() );
|
||||
mAudioStopEvent = new AudioEvent( AudioEvent.Type.AUDIO_STOPPED,
|
||||
getChannelName() );
|
||||
|
||||
try
|
||||
{
|
||||
mOutput = AudioSystem.getSourceDataLine(
|
||||
AudioFormats.PCM_SIGNED_48KHZ_16BITS );
|
||||
|
||||
mOutput = (SourceDataLine)mixer.getLine(
|
||||
AudioFormats.MONO_SOURCE_DATALINE_INFO );
|
||||
|
||||
if( mOutput != null )
|
||||
{
|
||||
mOutput.open( AudioFormats.PCM_SIGNED_48KHZ_16BITS, BUFFER_SIZE );
|
||||
mOutput.open( AudioFormats.PCM_SIGNED_48KHZ_16BITS_MONO, BUFFER_SIZE );
|
||||
|
||||
mCanProcessAudio = true;
|
||||
|
||||
@@ -103,47 +96,18 @@ public class MonoAudioOutput extends AudioOutput
|
||||
@Override
|
||||
public String getChannelName()
|
||||
{
|
||||
return "Mono";
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp when most recent buffer was received
|
||||
*/
|
||||
public long getLastBufferReceived()
|
||||
{
|
||||
return mLastBufferReceived;
|
||||
return MixerChannel.MONO.getLabel();
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
super.dispose();
|
||||
|
||||
mCanProcessAudio = false;
|
||||
|
||||
mBuffer.clear();
|
||||
|
||||
if( mExecutorService != null )
|
||||
{
|
||||
mExecutorService.shutdown();
|
||||
}
|
||||
|
||||
if( mOutput != null )
|
||||
{
|
||||
mOutput.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( AudioPacket packet )
|
||||
{
|
||||
if( mCanProcessAudio )
|
||||
{
|
||||
mLastBufferReceived = System.currentTimeMillis();
|
||||
|
||||
mBuffer.add( packet );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class QueueProcessor implements Runnable
|
||||
{
|
||||
@@ -233,17 +197,27 @@ public class MonoAudioOutput extends AudioOutput
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMuted( boolean muted )
|
||||
{
|
||||
if( mMuteControl != null )
|
||||
{
|
||||
mMuteControl.setValue( muted );
|
||||
|
||||
broadcast( new AudioEvent( muted ? AudioEvent.Type.AUDIO_MUTED :
|
||||
AudioEvent.Type.AUDIO_UNMUTED, getChannelName() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanControl getMuteControl()
|
||||
public boolean isMuted()
|
||||
{
|
||||
return mMuteControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMuteControl()
|
||||
{
|
||||
return mMuteControl != null;
|
||||
if( mMuteControl != null )
|
||||
{
|
||||
return mMuteControl.getValue();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user