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:
denny
2015-10-03 17:50:03 -04:00
parent 20f5d06104
commit 3e05a9eb03
27 changed files with 1174 additions and 458 deletions

View File

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