mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 17:17:29 -05:00
#1194 Resolves issue with audio stream bit rate scheduling that was causing stream disconnects for data rate under flows. (#1195)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -42,7 +42,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
|
|||||||
private final static Logger mLog = LoggerFactory.getLogger(AudioStreamingBroadcaster.class);
|
private final static Logger mLog = LoggerFactory.getLogger(AudioStreamingBroadcaster.class);
|
||||||
|
|
||||||
public static final int PROCESSOR_RUN_INTERVAL_MS = 1000;
|
public static final int PROCESSOR_RUN_INTERVAL_MS = 1000;
|
||||||
private ScheduledFuture mRecordingQueueProcessorFuture;
|
private ScheduledFuture<?> mRecordingQueueProcessorFuture;
|
||||||
|
|
||||||
private RecordingQueueProcessor mRecordingQueueProcessor = new RecordingQueueProcessor();
|
private RecordingQueueProcessor mRecordingQueueProcessor = new RecordingQueueProcessor();
|
||||||
private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>();
|
private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>();
|
||||||
@@ -205,7 +205,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
|
|||||||
|
|
||||||
super.setBroadcastState(state);
|
super.setBroadcastState(state);
|
||||||
|
|
||||||
if(mBroadcastState.get() instanceof BroadcastState && ((BroadcastState)mBroadcastState.get()).isErrorState())
|
if(mBroadcastState.get() != null && mBroadcastState.get().isErrorState())
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
@@ -266,8 +266,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
|
|||||||
private AtomicBoolean mProcessing = new AtomicBoolean();
|
private AtomicBoolean mProcessing = new AtomicBoolean();
|
||||||
private ByteArrayInputStream mInputStream;
|
private ByteArrayInputStream mInputStream;
|
||||||
private long mFinalSilencePadding = 0;
|
private long mFinalSilencePadding = 0;
|
||||||
private int mBytesStreamedActual = 0;
|
private int mBytesToStreamPerInterval = 0;
|
||||||
private int mBytesStreamedRequired = 0;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
@@ -278,7 +277,27 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
|
|||||||
{
|
{
|
||||||
if(mInputStream == null || mInputStream.available() <= 0)
|
if(mInputStream == null || mInputStream.available() <= 0)
|
||||||
{
|
{
|
||||||
if(mFinalSilencePadding > 0)
|
nextRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mInputStream != null)
|
||||||
|
{
|
||||||
|
int length = FastMath.min(mBytesToStreamPerInterval, mInputStream.available());
|
||||||
|
|
||||||
|
byte[] audio = new byte[length];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int read = mInputStream.read(audio);
|
||||||
|
broadcastAudio(audio);
|
||||||
|
}
|
||||||
|
catch(IOException ioe)
|
||||||
|
{
|
||||||
|
mLog.error("Error reading from in-memory audio recording input stream", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
//If this is the final frame fragment then append silence padding to fill the final interval segment
|
||||||
|
if(length < mBytesToStreamPerInterval && mFinalSilencePadding > 0)
|
||||||
{
|
{
|
||||||
List<byte[]> finalSilence = mSilenceGenerator.generate(mFinalSilencePadding);
|
List<byte[]> finalSilence = mSilenceGenerator.generate(mFinalSilencePadding);
|
||||||
|
|
||||||
@@ -289,33 +308,6 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
|
|||||||
|
|
||||||
mFinalSilencePadding = 0;
|
mFinalSilencePadding = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mInputStream != null)
|
|
||||||
{
|
|
||||||
//We need to stream at 13.888 fps (144 byte frame) to achieve 2000 Bps or 16 kbps
|
|
||||||
mBytesStreamedRequired += 2000; //2000 bytes per second for 16 kbps data rate
|
|
||||||
int bytesToStream = mBytesStreamedRequired - mBytesStreamedActual;
|
|
||||||
|
|
||||||
//Trim length to whole-frame intervals (144 byte frame)
|
|
||||||
bytesToStream -= (bytesToStream % 144);
|
|
||||||
|
|
||||||
int length = FastMath.min(bytesToStream, mInputStream.available());
|
|
||||||
|
|
||||||
byte[] audio = new byte[length];
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mBytesStreamedActual += mInputStream.read(audio);
|
|
||||||
|
|
||||||
broadcastAudio(audio);
|
|
||||||
}
|
|
||||||
catch(IOException ioe)
|
|
||||||
{
|
|
||||||
mLog.error("Error reading from in-memory audio recording input stream", ioe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -340,9 +332,6 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
private void nextRecording()
|
private void nextRecording()
|
||||||
{
|
{
|
||||||
mBytesStreamedActual = 0;
|
|
||||||
mBytesStreamedRequired = 0;
|
|
||||||
|
|
||||||
boolean metadataUpdateRequired = false;
|
boolean metadataUpdateRequired = false;
|
||||||
|
|
||||||
if(mInputStream != null)
|
if(mInputStream != null)
|
||||||
@@ -381,8 +370,12 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
|
|||||||
{
|
{
|
||||||
byte[] audio = Files.readAllBytes(nextRecording.getPath());
|
byte[] audio = Files.readAllBytes(nextRecording.getPath());
|
||||||
|
|
||||||
if(audio != null && audio.length > 0)
|
if(audio.length > 0)
|
||||||
{
|
{
|
||||||
|
//Calculate how many bytes we'll send with each processor run interval
|
||||||
|
double intervals = (double)nextRecording.getRecordingLength() / (double)PROCESSOR_RUN_INTERVAL_MS;
|
||||||
|
mBytesToStreamPerInterval = (int)((double)audio.length / intervals);
|
||||||
|
|
||||||
mInputStream = new ByteArrayInputStream(audio);
|
mInputStream = new ByteArrayInputStream(audio);
|
||||||
|
|
||||||
mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS -
|
mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS -
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ public enum MP3Setting
|
|||||||
CBR_16(false, 16, "CBR - Constant Bit Rate 16 kbps (default)"),
|
CBR_16(false, 16, "CBR - Constant Bit Rate 16 kbps (default)"),
|
||||||
CBR_32(false, 32, "CBR - Constant Bit Rate 32 kbps"),
|
CBR_32(false, 32, "CBR - Constant Bit Rate 32 kbps"),
|
||||||
ABR_56(true, 56, "ABR - Average Bit Rate 56 kbps"),
|
ABR_56(true, 56, "ABR - Average Bit Rate 56 kbps"),
|
||||||
VBR_5(true, Lame.QUALITY_MIDDLE, "VBR - Middle Quality (5)"),
|
VBR_5(true, Lame.QUALITY_MIDDLE, "VBR - Variable Bit Rate - Better Quality"),
|
||||||
VBR_7(true, Lame.QUALITY_LOW, "VBR - Low Quality (7)");
|
VBR_7(true, Lame.QUALITY_LOW, "VBR - Variable Bit Rate - Good Quality");
|
||||||
|
|
||||||
private boolean mVariableBitRate;
|
private boolean mVariableBitRate;
|
||||||
private int mSetting;
|
private int mSetting;
|
||||||
|
|||||||
Reference in New Issue
Block a user