mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Resolves issue with audio playback state becoming disconnected with
AudioManager connection class monitoring of the playback state. Adds a line listener to monitor when the line is started/stopped and responds accordingly. Removes squelch control from mono and stereo audio playback components which was a holdover -- squelch state is now managed within the audio component for each processing chain.
This commit is contained in:
@@ -182,7 +182,8 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
|
||||
for( AudioOutputConnection connection: mAudioOutputConnections )
|
||||
{
|
||||
if( connection.isConnected() && connection.isInactive() )
|
||||
if( connection.isInactive() &&
|
||||
mChannelConnectionMap.containsKey( connection.getSource() ) )
|
||||
{
|
||||
mChannelConnectionMap.remove( connection.getSource() );
|
||||
connection.disconnect();
|
||||
@@ -424,7 +425,7 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio output connection manages a connection between a soure and an audio
|
||||
* Audio output connection manages a connection between a source and an audio
|
||||
* output and maintains current state information about the audio activity
|
||||
* received form the source.
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package audio.output;
|
||||
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.sound.sampled.FloatControl;
|
||||
import javax.sound.sampled.LineListener;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -11,18 +11,15 @@ import org.slf4j.LoggerFactory;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import audio.AudioEvent;
|
||||
import audio.AudioEvent.Type;
|
||||
import audio.AudioPacket;
|
||||
import audio.metadata.AudioMetadata;
|
||||
import controller.ThreadPoolManager;
|
||||
|
||||
public abstract class AudioOutput implements Listener<AudioPacket>
|
||||
public abstract class AudioOutput implements Listener<AudioPacket>, LineListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( AudioOutput.class );
|
||||
|
||||
private AtomicBoolean mSquelched = new AtomicBoolean( false );
|
||||
private Listener<AudioMetadata> mAudioMetadataListener;
|
||||
|
||||
protected Broadcaster<AudioEvent> mAudioEventBroadcaster = new Broadcaster<>();
|
||||
protected LinkedTransferQueue<AudioPacket> mBuffer = new LinkedTransferQueue<>();
|
||||
protected ThreadPoolManager mThreadPoolManager;
|
||||
@@ -74,19 +71,6 @@ public abstract class AudioOutput implements Listener<AudioPacket>
|
||||
mAudioEventBroadcaster.broadcast( audioEvent );
|
||||
}
|
||||
|
||||
public void setSquelched( boolean squelched )
|
||||
{
|
||||
mSquelched.set( squelched );
|
||||
|
||||
broadcast( new AudioEvent( squelched ? Type.AUDIO_SQUELCHED :
|
||||
Type.AUDIO_UNSQUELCHED, getChannelName() ) );
|
||||
}
|
||||
|
||||
public boolean isSquelched()
|
||||
{
|
||||
return mSquelched.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a single listener to receive audio start and audio stop events
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.sound.sampled.BooleanControl;
|
||||
import javax.sound.sampled.Control;
|
||||
import javax.sound.sampled.FloatControl;
|
||||
import javax.sound.sampled.LineEvent;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
@@ -50,11 +51,9 @@ public class MonoAudioOutput extends AudioOutput
|
||||
private SourceDataLine mOutput;
|
||||
private FloatControl mGainControl;
|
||||
private BooleanControl mMuteControl;
|
||||
|
||||
private AudioEvent mAudioStartEvent;
|
||||
private AudioEvent mAudioStopEvent;
|
||||
private AudioEvent mAudioContinuationEvent;
|
||||
|
||||
private ScheduledFuture<?> mProcessorTask;
|
||||
|
||||
public MonoAudioOutput( ThreadPoolManager threadPoolManager, Mixer mixer )
|
||||
@@ -76,6 +75,7 @@ public class MonoAudioOutput extends AudioOutput
|
||||
if( mOutput != null )
|
||||
{
|
||||
mOutput.open( AudioFormats.PCM_SIGNED_48KHZ_16BITS_MONO, BUFFER_SIZE );
|
||||
mOutput.addLineListener( this );
|
||||
mCanProcessAudio = true;
|
||||
}
|
||||
}
|
||||
@@ -162,17 +162,13 @@ public class MonoAudioOutput extends AudioOutput
|
||||
|
||||
if( packets.size() > 0 )
|
||||
{
|
||||
broadcast( mAudioContinuationEvent );
|
||||
|
||||
for( AudioPacket packet: packets )
|
||||
{
|
||||
broadcast( mAudioContinuationEvent );
|
||||
|
||||
if( mCanProcessAudio )
|
||||
{
|
||||
if( isSquelched() )
|
||||
{
|
||||
checkStop();
|
||||
}
|
||||
else if( packet.getType() == Type.AUDIO )
|
||||
if( packet.getType() == Type.AUDIO )
|
||||
{
|
||||
float[] samples = packet.getAudioBuffer().getSamples();
|
||||
|
||||
@@ -216,24 +212,20 @@ public class MonoAudioOutput extends AudioOutput
|
||||
|
||||
private void checkStart()
|
||||
{
|
||||
if( mCanProcessAudio && !isSquelched() &&
|
||||
if( mCanProcessAudio &&
|
||||
!mOutput.isRunning() && mOutput.available() <= START_THRESHOLD )
|
||||
{
|
||||
mOutput.start();
|
||||
|
||||
mAudioEventBroadcaster.broadcast( mAudioStartEvent );
|
||||
}
|
||||
}
|
||||
|
||||
private void checkStop()
|
||||
{
|
||||
if( mCanProcessAudio && mOutput.isRunning() &&
|
||||
( mOutput.available() >= STOP_THRESHOLD || isSquelched() ) )
|
||||
mOutput.available() >= STOP_THRESHOLD )
|
||||
{
|
||||
mOutput.drain();
|
||||
mOutput.stop();
|
||||
|
||||
mAudioEventBroadcaster.broadcast( mAudioStopEvent );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,4 +264,19 @@ public class MonoAudioOutput extends AudioOutput
|
||||
{
|
||||
return mGainControl != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update( LineEvent event )
|
||||
{
|
||||
LineEvent.Type type = event.getType();
|
||||
|
||||
if( type == LineEvent.Type.START )
|
||||
{
|
||||
mAudioEventBroadcaster.broadcast( mAudioStartEvent );
|
||||
}
|
||||
else if( type == LineEvent.Type.STOP )
|
||||
{
|
||||
mAudioEventBroadcaster.broadcast( mAudioStopEvent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.sound.sampled.BooleanControl;
|
||||
import javax.sound.sampled.Control;
|
||||
import javax.sound.sampled.FloatControl;
|
||||
import javax.sound.sampled.LineEvent;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
@@ -40,9 +41,9 @@ public class StereoAudioOutput extends AudioOutput
|
||||
private final static int BUFFER_SIZE = 96000;
|
||||
|
||||
/* The queue processor will run every 20 milliseconds checking for inbound
|
||||
* audio and automatically starting or stopping audio playback. We set the
|
||||
* audio and automatically start or stop 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 */
|
||||
* being full and the stop threshold when 20 ms away from being empty */
|
||||
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;
|
||||
@@ -50,13 +51,10 @@ public class StereoAudioOutput extends AudioOutput
|
||||
private SourceDataLine mOutput;
|
||||
private FloatControl mGainControl;
|
||||
private BooleanControl mMuteControl;
|
||||
|
||||
private AudioEvent mAudioStartEvent;
|
||||
private AudioEvent mAudioStopEvent;
|
||||
private AudioEvent mAudioContinuationEvent;
|
||||
|
||||
private MixerChannel mMixerChannel;
|
||||
|
||||
private ScheduledFuture<?> mProcessorTask;
|
||||
|
||||
public StereoAudioOutput( ThreadPoolManager threadPoolManager,
|
||||
@@ -83,6 +81,7 @@ public class StereoAudioOutput extends AudioOutput
|
||||
if( mOutput != null )
|
||||
{
|
||||
mOutput.open( AudioFormats.PCM_SIGNED_48KHZ_16BITS_STEREO, BUFFER_SIZE );
|
||||
mOutput.addLineListener( this );
|
||||
mCanProcessAudio = true;
|
||||
}
|
||||
}
|
||||
@@ -202,17 +201,14 @@ public class StereoAudioOutput extends AudioOutput
|
||||
|
||||
if( packets.size() > 0 )
|
||||
{
|
||||
broadcast( mAudioContinuationEvent );
|
||||
|
||||
for( AudioPacket packet: packets )
|
||||
{
|
||||
broadcast( mAudioContinuationEvent );
|
||||
|
||||
if( mCanProcessAudio )
|
||||
{
|
||||
if( isSquelched() )
|
||||
{
|
||||
checkStop();
|
||||
}
|
||||
else if( packet.getType() == Type.AUDIO )
|
||||
if( packet.getType() == Type.AUDIO )
|
||||
{
|
||||
ByteBuffer buffer = convert(
|
||||
packet.getAudioBuffer().getSamples() );
|
||||
@@ -245,24 +241,20 @@ public class StereoAudioOutput extends AudioOutput
|
||||
|
||||
private void checkStart()
|
||||
{
|
||||
if( mCanProcessAudio && !isSquelched() &&
|
||||
if( mCanProcessAudio &&
|
||||
!mOutput.isRunning() && mOutput.available() <= START_THRESHOLD )
|
||||
{
|
||||
mOutput.start();
|
||||
|
||||
mAudioEventBroadcaster.broadcast( mAudioStartEvent );
|
||||
}
|
||||
}
|
||||
|
||||
private void checkStop()
|
||||
{
|
||||
if( mCanProcessAudio && mOutput.isRunning() &&
|
||||
( mOutput.available() >= STOP_THRESHOLD || isSquelched() ) )
|
||||
mOutput.available() >= STOP_THRESHOLD )
|
||||
{
|
||||
mOutput.drain();
|
||||
mOutput.stop();
|
||||
|
||||
mAudioEventBroadcaster.broadcast( mAudioStopEvent );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,4 +293,20 @@ public class StereoAudioOutput extends AudioOutput
|
||||
{
|
||||
return mGainControl != null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update( LineEvent event )
|
||||
{
|
||||
LineEvent.Type type = event.getType();
|
||||
|
||||
if( type == LineEvent.Type.START )
|
||||
{
|
||||
mAudioEventBroadcaster.broadcast( mAudioStartEvent );
|
||||
}
|
||||
else if( type == LineEvent.Type.STOP )
|
||||
{
|
||||
mAudioEventBroadcaster.broadcast( mAudioStopEvent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user