mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-15 01:57:39 -05:00
#30 - changes audio broadcaster to send full/complete MP3 frames instead of partial frames in order to reduce remote server disconnnects due to MP3 frame sync loss on remote server.
This commit is contained in:
@@ -265,7 +265,7 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
{
|
{
|
||||||
if(mBroadcastState != state)
|
if(mBroadcastState != state)
|
||||||
{
|
{
|
||||||
mLog.info("[" + getStreamName() + "] changing state to: " + state);
|
mLog.info("[" + getStreamName() + "] state: " + state);
|
||||||
mBroadcastState = state;
|
mBroadcastState = state;
|
||||||
|
|
||||||
broadcast(new BroadcastEvent(this, BroadcastEvent.Event.BROADCASTER_STATE_CHANGE));
|
broadcast(new BroadcastEvent(this, BroadcastEvent.Event.BROADCASTER_STATE_CHANGE));
|
||||||
@@ -332,8 +332,9 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
{
|
{
|
||||||
private AtomicBoolean mProcessing = new AtomicBoolean();
|
private AtomicBoolean mProcessing = new AtomicBoolean();
|
||||||
private ByteArrayInputStream mInputStream;
|
private ByteArrayInputStream mInputStream;
|
||||||
private int mAverageBytesPerInterval;
|
|
||||||
private long mFinalSilencePadding = 0;
|
private long mFinalSilencePadding = 0;
|
||||||
|
private int mBytesStreamedActual = 0;
|
||||||
|
private int mBytesStreamedRequired = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
@@ -353,13 +354,20 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
|
|
||||||
if(mInputStream != null)
|
if(mInputStream != null)
|
||||||
{
|
{
|
||||||
int length = Math.min(mAverageBytesPerInterval, mInputStream.available());
|
//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 = Math.min(bytesToStream, mInputStream.available());
|
||||||
|
|
||||||
byte[] audio = new byte[length];
|
byte[] audio = new byte[length];
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mInputStream.read(audio);
|
mBytesStreamedActual += mInputStream.read(audio);
|
||||||
|
|
||||||
broadcastAudio(audio);
|
broadcastAudio(audio);
|
||||||
}
|
}
|
||||||
@@ -382,6 +390,9 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
*/
|
*/
|
||||||
private void nextRecording()
|
private void nextRecording()
|
||||||
{
|
{
|
||||||
|
mBytesStreamedActual = 0;
|
||||||
|
mBytesStreamedRequired = 0;
|
||||||
|
|
||||||
boolean metadataUpdateRequired = false;
|
boolean metadataUpdateRequired = false;
|
||||||
|
|
||||||
if(mInputStream != null)
|
if(mInputStream != null)
|
||||||
@@ -408,15 +419,13 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
{
|
{
|
||||||
mInputStream = new ByteArrayInputStream(audio);
|
mInputStream = new ByteArrayInputStream(audio);
|
||||||
|
|
||||||
double intervals = (double)recording.getRecordingLength() / (double)PROCESSOR_RUN_INTERVAL_MS;
|
mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS -
|
||||||
|
(recording.getRecordingLength() % PROCESSOR_RUN_INTERVAL_MS);
|
||||||
|
|
||||||
mAverageBytesPerInterval = (int)((double)mInputStream.available() / intervals);
|
while(mFinalSilencePadding >= PROCESSOR_RUN_INTERVAL_MS)
|
||||||
|
{
|
||||||
int wholeIntervals = (int)Math.floor(intervals) + 1;
|
mFinalSilencePadding -= PROCESSOR_RUN_INTERVAL_MS;
|
||||||
|
}
|
||||||
//Silence padding to transmit at the end to keep stream length at multiples of run interval
|
|
||||||
mFinalSilencePadding = (wholeIntervals * PROCESSOR_RUN_INTERVAL_MS) -
|
|
||||||
recording.getRecordingLength();
|
|
||||||
|
|
||||||
if(connected())
|
if(connected())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -248,7 +248,6 @@ public class ShoutcastV1AudioBroadcaster extends ShoutcastAudioBroadcaster
|
|||||||
@Override
|
@Override
|
||||||
public void messageReceived(IoSession session, Object object) throws Exception
|
public void messageReceived(IoSession session, Object object) throws Exception
|
||||||
{
|
{
|
||||||
mLog.debug("Message Received:" + object.toString());
|
|
||||||
if(object instanceof String)
|
if(object instanceof String)
|
||||||
{
|
{
|
||||||
String message = (String)object;
|
String message = (String)object;
|
||||||
|
|||||||
@@ -57,18 +57,27 @@ public class MP3SilenceGenerator implements ISilenceGenerator
|
|||||||
{
|
{
|
||||||
mLog.debug("Starting ...");
|
mLog.debug("Starting ...");
|
||||||
|
|
||||||
MP3SilenceGenerator generator = new MP3SilenceGenerator();
|
// MP3SilenceGenerator generator = new MP3SilenceGenerator();
|
||||||
|
//
|
||||||
|
// int sampleCount = 0;
|
||||||
|
//
|
||||||
|
// int block = 1;
|
||||||
|
//
|
||||||
|
// for(long x = 0; x < 5000; x ++)
|
||||||
|
// {
|
||||||
|
// byte[] silence = generator.generate(block);
|
||||||
|
//
|
||||||
|
// sampleCount += block;
|
||||||
|
//
|
||||||
|
// if(silence.length > 0)
|
||||||
|
// {
|
||||||
|
// mLog.debug("Silence:" + x + " Count:" + sampleCount + " Length:" + silence.length);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
int sampleCount = 0;
|
for(int x = 1; x <= 288; x++)
|
||||||
|
|
||||||
int block = 1;
|
|
||||||
|
|
||||||
for(long x = 0; x < 500; x ++)
|
|
||||||
{
|
{
|
||||||
byte[] silence = generator.generate(block);
|
mLog.debug(x + ": " + (x / 144));
|
||||||
|
|
||||||
sampleCount += block;
|
|
||||||
mLog.debug("Silence:" + x + " Count:" + sampleCount + " Length:" + silence.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mLog.debug("Finished");
|
mLog.debug("Finished");
|
||||||
|
|||||||
Reference in New Issue
Block a user