mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-09 15:17:24 -05:00
[WIP] Updates AudioPackets to be ReusableAudioPackets.
This commit is contained in:
@@ -24,6 +24,7 @@ import io.github.dsheirer.audio.output.StereoAudioOutput;
|
||||
import io.github.dsheirer.properties.SystemProperties;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.source.mixer.MixerChannel;
|
||||
import io.github.dsheirer.source.mixer.MixerChannelConfiguration;
|
||||
import io.github.dsheirer.source.mixer.MixerManager;
|
||||
@@ -43,7 +44,7 @@ import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
public class AudioManager implements Listener<ReusableAudioPacket>, IAudioController
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(AudioManager.class);
|
||||
|
||||
@@ -58,7 +59,7 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
public static final AudioEvent CONFIGURATION_CHANGE_COMPLETE =
|
||||
new AudioEvent(AudioEvent.Type.AUDIO_CONFIGURATION_CHANGE_COMPLETE, null);
|
||||
|
||||
private LinkedTransferQueue<AudioPacket> mAudioPacketQueue = new LinkedTransferQueue<>();
|
||||
private LinkedTransferQueue<ReusableAudioPacket> mAudioPacketQueue = new LinkedTransferQueue<>();
|
||||
private Map<Integer,AudioOutputConnection> mChannelConnectionMap = new HashMap<>();
|
||||
private List<AudioOutputConnection> mAudioOutputConnections = new ArrayList<>();
|
||||
private AudioOutputConnection mLowestPriorityConnection;
|
||||
@@ -170,7 +171,7 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
* Primary ingest point for audio produced by all decoding channels, for distribution to audio playback devices.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void receive(AudioPacket packet)
|
||||
public synchronized void receive(ReusableAudioPacket packet)
|
||||
{
|
||||
mAudioPacketQueue.add(packet);
|
||||
}
|
||||
@@ -362,7 +363,7 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
* @param audioPacket from a decoding channel source
|
||||
* @return an audio output connection or null
|
||||
*/
|
||||
private AudioOutputConnection getConnection(AudioPacket audioPacket)
|
||||
private AudioOutputConnection getConnection(ReusableAudioPacket audioPacket)
|
||||
{
|
||||
int channelMetadataID = audioPacket.getMetadata().getMetadataID();
|
||||
|
||||
@@ -410,6 +411,8 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
|
||||
public class AudioPacketProcessor implements Runnable
|
||||
{
|
||||
private List<ReusableAudioPacket> mPackets = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
@@ -419,14 +422,12 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
|
||||
if(mAudioPacketQueue != null)
|
||||
{
|
||||
List<AudioPacket> packets = new ArrayList<AudioPacket>();
|
||||
mAudioPacketQueue.drainTo(mPackets);
|
||||
|
||||
mAudioPacketQueue.drainTo(packets);
|
||||
|
||||
for(AudioPacket packet : packets)
|
||||
for(ReusableAudioPacket packet : mPackets)
|
||||
{
|
||||
/* Don't process any packet's marked as do not monitor */
|
||||
if(!packet.getMetadata().isDoNotMonitor() && packet.getType() == AudioPacket.Type.AUDIO)
|
||||
if(!packet.getMetadata().isDoNotMonitor() && packet.getType() == ReusableAudioPacket.Type.AUDIO)
|
||||
{
|
||||
AudioOutputConnection connection = getConnection(packet);
|
||||
|
||||
@@ -434,13 +435,29 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
{
|
||||
connection.receive(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet.decrementUserCount();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
packet.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
mPackets.clear();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Encountered error while processing audio packets", e);
|
||||
|
||||
while(mPackets.size() > 0)
|
||||
{
|
||||
ReusableAudioPacket audioPacket = mPackets.remove(0);
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,7 +480,7 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
|
||||
mAudioOutput = audioOutput;
|
||||
}
|
||||
|
||||
public void receive(AudioPacket packet)
|
||||
public void receive(ReusableAudioPacket packet)
|
||||
{
|
||||
if(packet.hasMetadata() && packet.getMetadata().getMetadataID() == mChannelMetadataID)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@ import io.github.dsheirer.dsp.filter.fir.remez.RemezFIRFilterDesigner;
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -41,6 +43,7 @@ public class AudioModule extends Module implements IAudioPacketProvider, IReusab
|
||||
ISquelchStateListener, Listener<ReusableBuffer>
|
||||
{
|
||||
protected static final Logger mLog = LoggerFactory.getLogger(AudioModule.class);
|
||||
private ReusableAudioPacketQueue mAudioPacketQueue = new ReusableAudioPacketQueue("AudioModule");
|
||||
|
||||
private static float[] sHighPassFilterCoefficients;
|
||||
|
||||
@@ -73,11 +76,12 @@ public class AudioModule extends Module implements IAudioPacketProvider, IReusab
|
||||
private RealFIRFilter2 mHighPassFilter = new RealFIRFilter2(sHighPassFilterCoefficients);
|
||||
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
|
||||
private SquelchState mSquelchState = SquelchState.SQUELCH;
|
||||
private Listener<AudioPacket> mAudioPacketListener;
|
||||
private Listener<ReusableAudioPacket> mAudioPacketListener;
|
||||
private Metadata mMetadata;
|
||||
|
||||
/**
|
||||
* Creates an Audio Module.
|
||||
*
|
||||
* @param metadata to use for audio packets produced by this audio module.
|
||||
*/
|
||||
public AudioModule(Metadata metadata)
|
||||
@@ -109,12 +113,15 @@ public class AudioModule extends Module implements IAudioPacketProvider, IReusab
|
||||
/* Issue an end-audio packet in case a recorder is still rolling */
|
||||
if(mAudioPacketListener != null)
|
||||
{
|
||||
mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
|
||||
ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer();
|
||||
endAudioPacket.setMetadata(mMetadata.copyOf());
|
||||
endAudioPacket.incrementUserCount();
|
||||
mAudioPacketListener.receive(endAudioPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAudioPacketListener(Listener<AudioPacket> listener)
|
||||
public void setAudioPacketListener(Listener<ReusableAudioPacket> listener)
|
||||
{
|
||||
mAudioPacketListener = listener;
|
||||
}
|
||||
@@ -137,8 +144,14 @@ public class AudioModule extends Module implements IAudioPacketProvider, IReusab
|
||||
if(mAudioPacketListener != null && mSquelchState == SquelchState.UNSQUELCH)
|
||||
{
|
||||
ReusableBuffer highPassFiltered = mHighPassFilter.filter(reusableBuffer);
|
||||
AudioPacket packet = new AudioPacket(highPassFiltered.getSamplesCopy(), mMetadata.copyOf());
|
||||
mAudioPacketListener.receive(packet);
|
||||
|
||||
ReusableAudioPacket audioPacket = mAudioPacketQueue.getBuffer(highPassFiltered.getSampleCount());
|
||||
audioPacket.loadAudioFrom(highPassFiltered);
|
||||
audioPacket.setMetadata(mMetadata.copyOf());
|
||||
audioPacket.incrementUserCount();
|
||||
|
||||
mAudioPacketListener.receive(audioPacket);
|
||||
|
||||
highPassFiltered.decrementUserCount();
|
||||
}
|
||||
else
|
||||
@@ -164,7 +177,9 @@ public class AudioModule extends Module implements IAudioPacketProvider, IReusab
|
||||
{
|
||||
if(state == SquelchState.SQUELCH && mAudioPacketListener != null)
|
||||
{
|
||||
mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
|
||||
ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer();
|
||||
endAudioPacket.setMetadata(mMetadata.copyOf());
|
||||
mAudioPacketListener.receive(endAudioPacket);
|
||||
}
|
||||
|
||||
mSquelchState = state;
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.audio;
|
||||
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
|
||||
public class AudioPacket
|
||||
{
|
||||
private Type mType;
|
||||
private RealBuffer mAudioData;
|
||||
private Metadata mMetadata;
|
||||
|
||||
public AudioPacket(Type type, Metadata metadata)
|
||||
{
|
||||
mType = type;
|
||||
mMetadata = metadata;
|
||||
}
|
||||
|
||||
public AudioPacket(float[] audio, Metadata metadata)
|
||||
{
|
||||
this(Type.AUDIO, metadata);
|
||||
|
||||
mAudioData = new RealBuffer(audio);
|
||||
}
|
||||
|
||||
public boolean hasMetadata()
|
||||
{
|
||||
return mMetadata != null;
|
||||
}
|
||||
|
||||
public Metadata getMetadata()
|
||||
{
|
||||
return mMetadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Metadata metadata)
|
||||
{
|
||||
mMetadata = metadata;
|
||||
}
|
||||
|
||||
public Type getType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
public RealBuffer getAudioBuffer()
|
||||
{
|
||||
return mAudioData;
|
||||
}
|
||||
|
||||
public boolean hasAudioBuffer()
|
||||
{
|
||||
return mAudioData != null;
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
AUDIO,
|
||||
END;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package io.github.dsheirer.audio;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class AudioPacketRateCounter implements Listener<AudioPacket>
|
||||
{
|
||||
private final static Logger mLog =
|
||||
LoggerFactory.getLogger( AudioPacketRateCounter.class );
|
||||
|
||||
private Listener<AudioPacket> mListener;
|
||||
private long mCount;
|
||||
private long mStartTime = -1;
|
||||
|
||||
private String mName;
|
||||
|
||||
public AudioPacketRateCounter()
|
||||
{
|
||||
mName = "UNNAMED";
|
||||
}
|
||||
|
||||
public AudioPacketRateCounter( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( AudioPacket packet )
|
||||
{
|
||||
if( mStartTime == -1 )
|
||||
{
|
||||
mStartTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
mCount += packet.getAudioBuffer().getSamples().length;
|
||||
|
||||
long elapsed = System.currentTimeMillis() - mStartTime;
|
||||
|
||||
if( elapsed != 0 )
|
||||
{
|
||||
mLog.debug( "[" + mName + "] Audio Rate: " + ( mCount / elapsed ) + " kHz" );
|
||||
}
|
||||
|
||||
if( mListener != null )
|
||||
{
|
||||
mListener.receive( packet );
|
||||
}
|
||||
}
|
||||
|
||||
public void setListener( Listener<AudioPacket> listener )
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.audio;
|
||||
|
||||
import io.github.dsheirer.sample.ConversionUtils;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -34,17 +32,18 @@ public class AudioUtils
|
||||
/**
|
||||
* Converts the audio packets into a byte array of 16-bit, little-endian audio samples
|
||||
*/
|
||||
public static byte[] convertTo16BitSamples(List<AudioPacket> audioPackets)
|
||||
public static byte[] convertTo16BitSamples(List<ReusableAudioPacket> audioPackets)
|
||||
{
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
for(AudioPacket packet: audioPackets)
|
||||
for(ReusableAudioPacket audioPacket: audioPackets)
|
||||
{
|
||||
//Converting from 32-bit floats to signed 16-bit samples
|
||||
ByteBuffer buffer = ConversionUtils.convertToSigned16BitSamples(packet.getAudioBuffer().getSamples());
|
||||
ByteBuffer buffer = ConversionUtils.convertToSigned16BitSamples(audioPacket.getAudioSamples());
|
||||
stream.write(buffer.array());
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package io.github.dsheirer.audio;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
|
||||
public interface IAudioPacketListener
|
||||
{
|
||||
public Listener<AudioPacket> getAudioPacketListener();
|
||||
public Listener<ReusableAudioPacket> getAudioPacketListener();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package io.github.dsheirer.audio;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
|
||||
public interface IAudioPacketProvider
|
||||
{
|
||||
public void setAudioPacketListener( Listener<AudioPacket> listener );
|
||||
public void setAudioPacketListener( Listener<ReusableAudioPacket> listener );
|
||||
public void removeAudioPacketListener();
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
package io.github.dsheirer.audio.broadcast;
|
||||
|
||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
import io.github.dsheirer.icon.IconManager;
|
||||
import io.github.dsheirer.properties.SystemProperties;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -46,7 +46,7 @@ import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BroadcastModel extends AbstractTableModel implements Listener<AudioPacket>
|
||||
public class BroadcastModel extends AbstractTableModel implements Listener<ReusableAudioPacket>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(BroadcastModel.class);
|
||||
|
||||
@@ -276,7 +276,7 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(AudioPacket audioPacket)
|
||||
public void receive(ReusableAudioPacket audioPacket)
|
||||
{
|
||||
if(audioPacket.hasMetadata() && audioPacket.getMetadata().isStreamable())
|
||||
{
|
||||
@@ -284,11 +284,14 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
||||
{
|
||||
if(mBroadcasterMap.containsKey(channel.getChannelName()))
|
||||
{
|
||||
audioPacket.incrementUserCount();
|
||||
mStreamManager.receive(audioPacket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.audio.broadcast;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.record.AudioRecorder;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import io.github.dsheirer.util.TimeStamp;
|
||||
import org.slf4j.Logger;
|
||||
@@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class StreamManager implements Listener<AudioPacket>
|
||||
public class StreamManager implements Listener<ReusableAudioPacket>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(StreamManager.class);
|
||||
private static final long MAXIMUM_RECORDER_LIFESPAN_MILLIS = 30000; //30 seconds
|
||||
@@ -115,7 +115,7 @@ public class StreamManager implements Listener<AudioPacket>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(AudioPacket audioPacket)
|
||||
public void receive(ReusableAudioPacket audioPacket)
|
||||
{
|
||||
if(mRunning.get() && audioPacket.hasMetadata())
|
||||
{
|
||||
@@ -123,9 +123,9 @@ public class StreamManager implements Listener<AudioPacket>
|
||||
{
|
||||
int channelMetadataID = audioPacket.getMetadata().getMetadataID();
|
||||
|
||||
AudioPacket.Type type = audioPacket.getType();
|
||||
ReusableAudioPacket.Type type = audioPacket.getType();
|
||||
|
||||
if(type == AudioPacket.Type.AUDIO)
|
||||
if(type == ReusableAudioPacket.Type.AUDIO)
|
||||
{
|
||||
if(mStreamRecorders.containsKey(channelMetadataID))
|
||||
{
|
||||
@@ -133,6 +133,7 @@ public class StreamManager implements Listener<AudioPacket>
|
||||
|
||||
if(recorder != null)
|
||||
{
|
||||
audioPacket.incrementUserCount();
|
||||
recorder.receive(audioPacket);
|
||||
}
|
||||
}
|
||||
@@ -141,11 +142,12 @@ public class StreamManager implements Listener<AudioPacket>
|
||||
AudioRecorder recorder = BroadcastFactory.getAudioRecorder(getTemporaryRecordingPath(),
|
||||
mBroadcastFormat);
|
||||
recorder.start();
|
||||
audioPacket.incrementUserCount();
|
||||
recorder.receive(audioPacket);
|
||||
mStreamRecorders.put(channelMetadataID, recorder);
|
||||
}
|
||||
}
|
||||
else if(type == AudioPacket.Type.END)
|
||||
else if(type == ReusableAudioPacket.Type.END)
|
||||
{
|
||||
removeRecorder(channelMetadataID);
|
||||
}
|
||||
@@ -155,6 +157,8 @@ public class StreamManager implements Listener<AudioPacket>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.audio.convert;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,7 +27,7 @@ public interface IAudioConverter
|
||||
/**
|
||||
* Converts the PCM audio packets to converted audio format. May produce partial audio frame data.
|
||||
*/
|
||||
public byte[] convert(List<AudioPacket> audioPackets);
|
||||
public byte[] convert(List<ReusableAudioPacket> audioPackets);
|
||||
|
||||
/**
|
||||
* Finalizes audio conversion by fully converting any partial frames left in the buffer and returning the
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
package io.github.dsheirer.audio.convert;
|
||||
|
||||
import io.github.dsheirer.audio.AudioFormats;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.audio.AudioUtils;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import net.sourceforge.lame.lowlevel.LameEncoder;
|
||||
import net.sourceforge.lame.mp3.Lame;
|
||||
import net.sourceforge.lame.mp3.MPEGMode;
|
||||
@@ -54,7 +54,7 @@ public class MP3AudioConverter implements IAudioConverter
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] convert(List<AudioPacket> audioPackets)
|
||||
public byte[] convert(List<ReusableAudioPacket> audioPackets)
|
||||
{
|
||||
mMP3Stream.reset();
|
||||
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.audio.convert;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.record.mp3.MP3Recorder;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -33,6 +34,7 @@ public class MP3SilenceGenerator implements ISilenceGenerator
|
||||
|
||||
private MP3AudioConverter mGenerator = new MP3AudioConverter(MP3Recorder.MP3_BIT_RATE, MP3Recorder.CONSTANT_BIT_RATE);
|
||||
private byte[] mPreviousPartialFrameData;
|
||||
private ReusableAudioPacketQueue mAudioPacketQueue = new ReusableAudioPacketQueue("MP3 Silence Generator");
|
||||
|
||||
/**
|
||||
* Generates MP3 audio silence frames
|
||||
@@ -44,9 +46,11 @@ public class MP3SilenceGenerator implements ISilenceGenerator
|
||||
public byte[] generate(long duration)
|
||||
{
|
||||
int length = (int)(duration * 8); //8000 Hz sample rate
|
||||
float[] silence = new float[length];
|
||||
AudioPacket silencePacket = new AudioPacket(silence, null);
|
||||
List<AudioPacket> silencePackets = new ArrayList<>();
|
||||
ReusableAudioPacket silencePacket = mAudioPacketQueue.getBuffer(length);
|
||||
Arrays.fill(silencePacket.getAudioSamples(), 0.0f);
|
||||
silencePacket.incrementUserCount();
|
||||
|
||||
List<ReusableAudioPacket> silencePackets = new ArrayList<>();
|
||||
silencePackets.add(silencePacket);
|
||||
|
||||
byte[] frameData = mGenerator.convert(silencePackets);
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
package io.github.dsheirer.audio.output;
|
||||
|
||||
import io.github.dsheirer.audio.AudioEvent;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.source.mixer.MixerChannel;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
@@ -46,11 +46,11 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public abstract class AudioOutput implements Listener<AudioPacket>, LineListener
|
||||
public abstract class AudioOutput implements Listener<ReusableAudioPacket>, LineListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(AudioOutput.class);
|
||||
|
||||
private LinkedTransferQueue<AudioPacket> mBuffer = new LinkedTransferQueue<>();
|
||||
private LinkedTransferQueue<ReusableAudioPacket> mBuffer = new LinkedTransferQueue<>();
|
||||
private int mBufferStartThreshold;
|
||||
private int mBufferStopThreshold;
|
||||
|
||||
@@ -190,7 +190,7 @@ public abstract class AudioOutput implements Listener<AudioPacket>, LineListener
|
||||
* Converts the audio packet data into a byte buffer format appropriate for
|
||||
* the underlying source data line.
|
||||
*/
|
||||
protected abstract ByteBuffer convert(AudioPacket packet);
|
||||
protected abstract ByteBuffer convert(ReusableAudioPacket packet);
|
||||
|
||||
/**
|
||||
* Audio output channel name
|
||||
@@ -271,7 +271,7 @@ public abstract class AudioOutput implements Listener<AudioPacket>, LineListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(AudioPacket packet)
|
||||
public void receive(ReusableAudioPacket packet)
|
||||
{
|
||||
if(mCanProcessAudio)
|
||||
{
|
||||
@@ -281,11 +281,17 @@ public abstract class AudioOutput implements Listener<AudioPacket>, LineListener
|
||||
|
||||
mBuffer.add(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
public class BufferProcessor implements Runnable
|
||||
{
|
||||
private AtomicBoolean mProcessing = new AtomicBoolean();
|
||||
private List<ReusableAudioPacket> mAudioPackets = new ArrayList<ReusableAudioPacket>();
|
||||
|
||||
|
||||
public BufferProcessor()
|
||||
{
|
||||
@@ -300,13 +306,11 @@ public abstract class AudioOutput implements Listener<AudioPacket>, LineListener
|
||||
* processor can run at any given time */
|
||||
if(mProcessing.compareAndSet(false, true))
|
||||
{
|
||||
List<AudioPacket> packets = new ArrayList<AudioPacket>();
|
||||
mBuffer.drainTo(mAudioPackets);
|
||||
|
||||
mBuffer.drainTo(packets);
|
||||
|
||||
for(AudioPacket packet : packets)
|
||||
for(ReusableAudioPacket packet : mAudioPackets)
|
||||
{
|
||||
if(packet.getType() == AudioPacket.Type.AUDIO)
|
||||
if(packet.getType() == ReusableAudioPacket.Type.AUDIO)
|
||||
{
|
||||
broadcast(packet.getMetadata());
|
||||
|
||||
@@ -338,8 +342,14 @@ public abstract class AudioOutput implements Listener<AudioPacket>, LineListener
|
||||
|
||||
updateTimestamp();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
mAudioPackets.clear();
|
||||
|
||||
checkStop();
|
||||
|
||||
mProcessing.set(false);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
package io.github.dsheirer.audio.output;
|
||||
|
||||
import io.github.dsheirer.audio.AudioFormats;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.source.mixer.MixerChannel;
|
||||
|
||||
import javax.sound.sampled.Mixer;
|
||||
@@ -43,14 +43,16 @@ public class MonoAudioOutput extends AudioOutput
|
||||
/**
|
||||
* Converts the audio packet data into mono audio frames.
|
||||
*/
|
||||
protected ByteBuffer convert(AudioPacket packet)
|
||||
protected ByteBuffer convert(ReusableAudioPacket packet)
|
||||
{
|
||||
if(packet.hasAudioBuffer())
|
||||
ByteBuffer buffer = null;
|
||||
|
||||
if(packet.hasAudioSamples())
|
||||
{
|
||||
float[] samples = packet.getAudioBuffer().getSamples();
|
||||
float[] samples = packet.getAudioSamples();
|
||||
|
||||
/* Little-endian byte buffer */
|
||||
ByteBuffer buffer = ByteBuffer.allocate(samples.length * 2).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer = ByteBuffer.allocate(samples.length * 2).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
ShortBuffer shortBuffer = buffer.asShortBuffer();
|
||||
|
||||
@@ -58,10 +60,10 @@ public class MonoAudioOutput extends AudioOutput
|
||||
{
|
||||
shortBuffer.put((short) (sample * Short.MAX_VALUE));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return null;
|
||||
packet.decrementUserCount();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
package io.github.dsheirer.audio.output;
|
||||
|
||||
import io.github.dsheirer.audio.AudioFormats;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.source.mixer.MixerChannel;
|
||||
|
||||
import javax.sound.sampled.Mixer;
|
||||
@@ -45,15 +45,16 @@ public class StereoAudioOutput extends AudioOutput
|
||||
* channel containing the audio and the other channel containing zero
|
||||
* valued (silent) samples.
|
||||
*/
|
||||
protected ByteBuffer convert(AudioPacket packet)
|
||||
protected ByteBuffer convert(ReusableAudioPacket packet)
|
||||
{
|
||||
if(packet.hasAudioBuffer())
|
||||
ByteBuffer buffer = null;
|
||||
|
||||
if(packet.hasAudioSamples())
|
||||
{
|
||||
float[] samples = packet.getAudioBuffer().getSamples();
|
||||
float[] samples = packet.getAudioSamples();
|
||||
|
||||
/* Little-endian byte buffer */
|
||||
ByteBuffer buffer = ByteBuffer.allocate(samples.length * 4)
|
||||
.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer = ByteBuffer.allocate(samples.length * 4).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
ShortBuffer shortBuffer = buffer.asShortBuffer();
|
||||
|
||||
@@ -73,10 +74,10 @@ public class StereoAudioOutput extends AudioOutput
|
||||
shortBuffer.put((short) (sample * Short.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return null;
|
||||
packet.decrementUserCount();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package io.github.dsheirer.controller.channel;
|
||||
|
||||
import io.github.dsheirer.alias.AliasModel;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.channel.metadata.Attribute;
|
||||
import io.github.dsheirer.channel.metadata.AttributeChangeRequest;
|
||||
import io.github.dsheirer.channel.metadata.ChannelMetadataModel;
|
||||
@@ -35,6 +34,7 @@ import io.github.dsheirer.module.log.EventLogManager;
|
||||
import io.github.dsheirer.record.RecorderManager;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.SourceManager;
|
||||
@@ -54,7 +54,7 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
|
||||
private Map<Integer,ProcessingChain> mProcessingChains = new HashMap<>();
|
||||
|
||||
private List<Listener<AudioPacket>> mAudioPacketListeners = new CopyOnWriteArrayList<>();
|
||||
private List<Listener<ReusableAudioPacket>> mAudioPacketListeners = new CopyOnWriteArrayList<>();
|
||||
private List<Listener<Message>> mMessageListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private ChannelModel mChannelModel;
|
||||
@@ -232,7 +232,7 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
processingChain = new ProcessingChain(channel.getChannelType());
|
||||
|
||||
/* Register global listeners */
|
||||
for(Listener<AudioPacket> listener : mAudioPacketListeners)
|
||||
for(Listener<ReusableAudioPacket> listener : mAudioPacketListeners)
|
||||
{
|
||||
processingChain.addAudioPacketListener(listener);
|
||||
}
|
||||
@@ -367,7 +367,7 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
* Adds a message listener that will be added to all channels to receive
|
||||
* any messages.
|
||||
*/
|
||||
public void addAudioPacketListener(Listener<AudioPacket> listener)
|
||||
public void addAudioPacketListener(Listener<ReusableAudioPacket> listener)
|
||||
{
|
||||
mAudioPacketListeners.add(listener);
|
||||
}
|
||||
@@ -375,7 +375,7 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
/**
|
||||
* Removes a message listener.
|
||||
*/
|
||||
public void removeAudioPacketListener(Listener<AudioPacket> listener)
|
||||
public void removeAudioPacketListener(Listener<ReusableAudioPacket> listener)
|
||||
{
|
||||
mAudioPacketListeners.remove(listener);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.audio.IAudioPacketListener;
|
||||
import io.github.dsheirer.audio.IAudioPacketProvider;
|
||||
import io.github.dsheirer.audio.squelch.ISquelchStateListener;
|
||||
@@ -52,6 +51,7 @@ import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.IReusableBufferListener;
|
||||
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
|
||||
import io.github.dsheirer.sample.buffer.IReusableComplexBufferListener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
@@ -99,7 +99,7 @@ public class ProcessingChain implements IChannelEventListener
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ProcessingChain.class);
|
||||
|
||||
private Broadcaster<AttributeChangeRequest> mAttributeChangeRequestBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<AudioPacket> mAudioPacketBroadcaster = new Broadcaster<>();
|
||||
private ReusableBufferBroadcaster<ReusableAudioPacket> mAudioPacketBroadcaster = new ReusableBufferBroadcaster<>();
|
||||
private Broadcaster<CallEvent> mCallEventBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<ChannelEvent> mChannelEventBroadcaster = new Broadcaster<>();
|
||||
private ReusableBufferBroadcaster<ReusableComplexBuffer> mComplexBufferBroadcaster = new ReusableBufferBroadcaster();
|
||||
@@ -724,12 +724,12 @@ public class ProcessingChain implements IChannelEventListener
|
||||
/**
|
||||
* Adds the listener to receive audio packets from all modules.
|
||||
*/
|
||||
public void addAudioPacketListener(Listener<AudioPacket> listener)
|
||||
public void addAudioPacketListener(Listener<ReusableAudioPacket> listener)
|
||||
{
|
||||
mAudioPacketBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
public void removeAudioPacketListener(Listener<AudioPacket> listener)
|
||||
public void removeAudioPacketListener(Listener<ReusableAudioPacket> listener)
|
||||
{
|
||||
mAudioPacketBroadcaster.removeListener(listener);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.github.dsheirer.module.decode.p25.audio;
|
||||
|
||||
import io.github.dsheirer.audio.AudioFormats;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.audio.IAudioPacketProvider;
|
||||
import io.github.dsheirer.audio.squelch.ISquelchStateListener;
|
||||
import io.github.dsheirer.audio.squelch.SquelchState;
|
||||
@@ -15,6 +14,8 @@ import io.github.dsheirer.module.decode.p25.message.ldu.LDU1Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDU2Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.ldu.LDUMessage;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacketQueue;
|
||||
import jmbe.iface.AudioConversionLibrary;
|
||||
import jmbe.iface.AudioConverter;
|
||||
import org.slf4j.Logger;
|
||||
@@ -33,11 +34,12 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
private boolean mEncryptedCallStateEstablished = false;
|
||||
|
||||
private AudioConverter mAudioConverter;
|
||||
private Listener<AudioPacket> mAudioPacketListener;
|
||||
private Listener<ReusableAudioPacket> mAudioPacketListener;
|
||||
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
|
||||
private NonClippingGain mGain = new NonClippingGain(5.0f, 0.95f);
|
||||
private Metadata mMetadata;
|
||||
private LDU1Message mCachedLDU1Message = null;
|
||||
private ReusableAudioPacketQueue mAudioPacketQueue = new ReusableAudioPacketQueue("P25AudioModule");
|
||||
|
||||
public P25AudioModule(Metadata metadata)
|
||||
{
|
||||
@@ -142,7 +144,12 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
|
||||
audio = mGain.apply(audio);
|
||||
|
||||
mAudioPacketListener.receive(new AudioPacket(audio, mMetadata.copyOf()));
|
||||
ReusableAudioPacket audioPacket = mAudioPacketQueue.getBuffer(audio.length);
|
||||
audioPacket.setMetadata(mMetadata.copyOf());
|
||||
audioPacket.loadAudioFrom(audio);
|
||||
audioPacket.incrementUserCount();
|
||||
|
||||
mAudioPacketListener.receive(audioPacket);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -230,7 +237,7 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAudioPacketListener(Listener<AudioPacket> listener)
|
||||
public void setAudioPacketListener(Listener<ReusableAudioPacket> listener)
|
||||
{
|
||||
mAudioPacketListener = listener;
|
||||
}
|
||||
@@ -255,7 +262,10 @@ public class P25AudioModule extends Module implements Listener<Message>, IAudioP
|
||||
{
|
||||
if(mAudioPacketListener != null)
|
||||
{
|
||||
mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
|
||||
ReusableAudioPacket endAudioPacket = mAudioPacketQueue.getEndAudioBuffer();
|
||||
endAudioPacket.setMetadata(mMetadata.copyOf());
|
||||
endAudioPacket.incrementUserCount();
|
||||
mAudioPacketListener.receive(endAudioPacket);
|
||||
}
|
||||
|
||||
mEncryptedCallStateEstablished = false;
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.record;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.audio.IAudioPacketListener;
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -38,12 +38,12 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public abstract class AudioRecorder extends Module implements Listener<AudioPacket>, IAudioPacketListener
|
||||
public abstract class AudioRecorder extends Module implements Listener<ReusableAudioPacket>, IAudioPacketListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(AudioRecorder.class);
|
||||
|
||||
private LinkedBlockingQueue<AudioPacket> mAudioPacketQueue = new LinkedBlockingQueue<>(500);
|
||||
private List<AudioPacket> mPacketsToProcess = new ArrayList<>();
|
||||
private LinkedBlockingQueue<ReusableAudioPacket> mAudioPacketQueue = new LinkedBlockingQueue<>(500);
|
||||
private List<ReusableAudioPacket> mPacketsToProcess = new ArrayList<>();
|
||||
|
||||
private FileOutputStream mFileOutputStream;
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
@@ -108,12 +108,12 @@ public abstract class AudioRecorder extends Module implements Listener<AudioPack
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the IAudioPacketListener interface and simply redirects to the Listener<AudioPacket> interface.
|
||||
* Implements the IAudioPacketListener interface and simply redirects to the Listener<ReusableAudioPacket> interface.
|
||||
* This is necessary since you can't have multiple methods with the same erasure (ie Listener<xxx>) in the
|
||||
* parent module class.
|
||||
*/
|
||||
@Override
|
||||
public Listener<AudioPacket> getAudioPacketListener()
|
||||
public Listener<ReusableAudioPacket> getAudioPacketListener()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public abstract class AudioRecorder extends Module implements Listener<AudioPack
|
||||
* Processes the audio packet and captures the latest Metadata for the recording for easy access.
|
||||
*/
|
||||
@Override
|
||||
public void receive(AudioPacket audioPacket)
|
||||
public void receive(ReusableAudioPacket audioPacket)
|
||||
{
|
||||
if(mRunning.get())
|
||||
{
|
||||
@@ -140,8 +140,13 @@ public abstract class AudioRecorder extends Module implements Listener<AudioPack
|
||||
{
|
||||
mLog.error("recorder buffer overflow - stopping recorder [" + getPath().toString() + "]");
|
||||
stop();
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,7 +194,7 @@ public abstract class AudioRecorder extends Module implements Listener<AudioPack
|
||||
/**
|
||||
* Records the list of audio packets in the sub-class specific audio format.
|
||||
*/
|
||||
protected abstract void record(List<AudioPacket> audioPackets) throws IOException;
|
||||
protected abstract void record(List<ReusableAudioPacket> audioPackets) throws IOException;
|
||||
|
||||
/**
|
||||
* Starts this recorder as a scheduled thread running under the executor argument
|
||||
@@ -234,12 +239,14 @@ public abstract class AudioRecorder extends Module implements Listener<AudioPack
|
||||
{
|
||||
record(mPacketsToProcess);
|
||||
|
||||
for(AudioPacket packet : mPacketsToProcess)
|
||||
for(ReusableAudioPacket packet : mPacketsToProcess)
|
||||
{
|
||||
if(packet.getType() == AudioPacket.Type.AUDIO)
|
||||
if(packet.getType() == ReusableAudioPacket.Type.AUDIO)
|
||||
{
|
||||
mSampleCount += packet.getAudioBuffer().getSamples().length;
|
||||
mSampleCount += packet.getAudioSamples().length;
|
||||
}
|
||||
|
||||
packet.decrementUserCount();
|
||||
}
|
||||
}
|
||||
catch(IOException ioe)
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
*/
|
||||
package io.github.dsheirer.record;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
import io.github.dsheirer.properties.SystemProperties;
|
||||
import io.github.dsheirer.record.wave.AudioPacketWaveRecorder;
|
||||
import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.sample.real.IOverflowListener;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
@@ -37,7 +37,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RecorderManager implements Listener<AudioPacket>
|
||||
public class RecorderManager implements Listener<ReusableAudioPacket>
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(RecorderManager.class);
|
||||
|
||||
@@ -45,7 +45,8 @@ public class RecorderManager implements Listener<AudioPacket>
|
||||
public static final long IDLE_RECORDER_REMOVAL_THRESHOLD = 6000; //6 seconds
|
||||
|
||||
private Map<String,AudioPacketWaveRecorder> mRecorders = new HashMap<>();
|
||||
private OverflowableTransferQueue<AudioPacket> mAudioPacketQueue = new OverflowableTransferQueue<>(1000, 100);
|
||||
private OverflowableTransferQueue<ReusableAudioPacket> mAudioPacketQueue = new OverflowableTransferQueue<>(1000, 100);
|
||||
private List<ReusableAudioPacket> mAudioPackets = new ArrayList<>();
|
||||
private ScheduledFuture<?> mBufferProcessorFuture;
|
||||
|
||||
private boolean mCanStartNewRecorders = true;
|
||||
@@ -96,12 +97,16 @@ public class RecorderManager implements Listener<AudioPacket>
|
||||
* @param audioPacket to process
|
||||
*/
|
||||
@Override
|
||||
public void receive(AudioPacket audioPacket)
|
||||
public void receive(ReusableAudioPacket audioPacket)
|
||||
{
|
||||
if(audioPacket.hasMetadata() && audioPacket.getMetadata().isRecordable())
|
||||
{
|
||||
mAudioPacketQueue.offer(audioPacket);
|
||||
}
|
||||
else
|
||||
{
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,13 +114,11 @@ public class RecorderManager implements Listener<AudioPacket>
|
||||
*/
|
||||
private void processBuffers()
|
||||
{
|
||||
List<AudioPacket> audioPackets = new ArrayList<>();
|
||||
mAudioPacketQueue.drainTo(mAudioPackets, 50);
|
||||
|
||||
mAudioPacketQueue.drainTo(audioPackets, 50);
|
||||
|
||||
while(!audioPackets.isEmpty())
|
||||
while(!mAudioPackets.isEmpty())
|
||||
{
|
||||
for(AudioPacket audioPacket : audioPackets)
|
||||
for(ReusableAudioPacket audioPacket : mAudioPackets)
|
||||
{
|
||||
String identifier = audioPacket.getMetadata().getUniqueIdentifier();
|
||||
|
||||
@@ -123,17 +126,18 @@ public class RecorderManager implements Listener<AudioPacket>
|
||||
{
|
||||
AudioPacketWaveRecorder recorder = mRecorders.get(identifier);
|
||||
|
||||
if(audioPacket.getType() == AudioPacket.Type.AUDIO)
|
||||
if(audioPacket.getType() == ReusableAudioPacket.Type.AUDIO)
|
||||
{
|
||||
audioPacket.incrementUserCount();
|
||||
recorder.receive(audioPacket);
|
||||
}
|
||||
else if(audioPacket.getType() == AudioPacket.Type.END)
|
||||
else if(audioPacket.getType() == ReusableAudioPacket.Type.END)
|
||||
{
|
||||
AudioPacketWaveRecorder finished = mRecorders.remove(identifier);
|
||||
finished.stop();
|
||||
}
|
||||
}
|
||||
else if(audioPacket.getType() == AudioPacket.Type.AUDIO)
|
||||
else if(audioPacket.getType() == ReusableAudioPacket.Type.AUDIO)
|
||||
{
|
||||
if(mCanStartNewRecorders)
|
||||
{
|
||||
@@ -147,6 +151,7 @@ public class RecorderManager implements Listener<AudioPacket>
|
||||
|
||||
recorder.start();
|
||||
|
||||
audioPacket.incrementUserCount();
|
||||
recorder.receive(audioPacket);
|
||||
mRecorders.put(identifier, recorder);
|
||||
}
|
||||
@@ -164,10 +169,12 @@ public class RecorderManager implements Listener<AudioPacket>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
|
||||
audioPackets.clear();
|
||||
mAudioPacketQueue.drainTo(audioPackets, 50);
|
||||
mAudioPackets.clear();
|
||||
mAudioPacketQueue.drainTo(mAudioPackets, 50);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +201,7 @@ public class RecorderManager implements Listener<AudioPacket>
|
||||
/**
|
||||
* Constructs a file name and path for an audio recording
|
||||
*/
|
||||
private String getFilePrefix(AudioPacket packet)
|
||||
private String getFilePrefix(ReusableAudioPacket packet)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.record.mp3;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.audio.convert.MP3AudioConverter;
|
||||
import io.github.dsheirer.record.AudioRecorder;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -55,7 +55,7 @@ public class MP3Recorder extends AudioRecorder
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void record(List<AudioPacket> audioPackets) throws IOException
|
||||
protected void record(List<ReusableAudioPacket> audioPackets) throws IOException
|
||||
{
|
||||
OutputStream outputStream = getOutputStream();
|
||||
|
||||
@@ -92,7 +92,7 @@ public class MP3Recorder extends AudioRecorder
|
||||
* writes the ID3 tags to the output stream.
|
||||
* @param audioPackets
|
||||
*/
|
||||
private void processMetadata(List<AudioPacket> audioPackets)
|
||||
private void processMetadata(List<ReusableAudioPacket> audioPackets)
|
||||
{
|
||||
//TODO: detect metadata changes and write out ID3 tags to the MP3 stream
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.record.wave;
|
||||
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.audio.IAudioPacketListener;
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class AudioPacketMonoWaveReader extends MonoWaveReader implements Listener<RealBuffer>
|
||||
{
|
||||
private Metadata mMetadata = new Metadata();
|
||||
|
||||
private IAudioPacketListener mListener;
|
||||
|
||||
/**
|
||||
* Reads wav files and converts the contents to AudioPackets.
|
||||
*
|
||||
* @param path of file to read containing 8kHz, 16-bit signed litte endian PCM audio
|
||||
* @param realTime causes the read() method to read and dispatch audio packets in real time. Note: when using
|
||||
* real time playback, the thread calling the read() method will sleep as needed to effect real-time playback,
|
||||
* therefore you should invoke read() on a separate thread if this will impact the calling thread.
|
||||
* @throws IOException on any file IO errors
|
||||
*/
|
||||
public AudioPacketMonoWaveReader(Path path, boolean realTime) throws IOException
|
||||
{
|
||||
super(path, realTime);
|
||||
setListener(this);
|
||||
}
|
||||
|
||||
public void setMetadata(Metadata metadata)
|
||||
{
|
||||
mMetadata = metadata;
|
||||
}
|
||||
|
||||
public void setListener(IAudioPacketListener listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(RealBuffer realBuffer)
|
||||
{
|
||||
if(mListener != null)
|
||||
{
|
||||
mListener.getAudioPacketListener().receive(new AudioPacket(realBuffer.getSamples(), mMetadata));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,12 @@
|
||||
package io.github.dsheirer.record.wave;
|
||||
|
||||
import io.github.dsheirer.audio.AudioFormats;
|
||||
import io.github.dsheirer.audio.AudioPacket;
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.sample.ConversionUtils;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.OverflowableReusableBufferTransferQueue;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import io.github.dsheirer.util.TimeStamp;
|
||||
import org.slf4j.Logger;
|
||||
@@ -31,7 +32,6 @@ import javax.sound.sampled.AudioFormat;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -39,7 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
/**
|
||||
* WAVE audio recorder module for recording audio buffers to a wave file
|
||||
*/
|
||||
public class AudioPacketWaveRecorder extends Module implements Listener<AudioPacket>
|
||||
public class AudioPacketWaveRecorder extends Module implements Listener<ReusableAudioPacket>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(AudioPacketWaveRecorder.class);
|
||||
|
||||
@@ -48,9 +48,10 @@ public class AudioPacketWaveRecorder extends Module implements Listener<AudioPac
|
||||
private Path mFile;
|
||||
private AudioFormat mAudioFormat;
|
||||
|
||||
private OverflowableReusableBufferTransferQueue<ReusableAudioPacket> mTransferQueue =
|
||||
new OverflowableReusableBufferTransferQueue<>(500, 100);
|
||||
private BufferProcessor mBufferProcessor;
|
||||
private ScheduledFuture<?> mProcessorHandle;
|
||||
private LinkedBlockingQueue<AudioPacket> mAudioPackets = new LinkedBlockingQueue<>(500);
|
||||
private Metadata mMetadata;
|
||||
private long mLastBufferReceived;
|
||||
|
||||
@@ -153,20 +154,17 @@ public class AudioPacketWaveRecorder extends Module implements Listener<AudioPac
|
||||
* Primary input method for receiving audio packets to enqueue for later writing to the wav file.
|
||||
*/
|
||||
@Override
|
||||
public void receive(AudioPacket audioPacket)
|
||||
public void receive(ReusableAudioPacket audioPacket)
|
||||
{
|
||||
if(mRunning.get())
|
||||
{
|
||||
boolean success = mAudioPackets.offer(audioPacket);
|
||||
|
||||
if(!success)
|
||||
{
|
||||
mLog.error("recorder buffer overflow - purging [" + mFile.toFile().getAbsolutePath() + "]");
|
||||
mAudioPackets.clear();
|
||||
}
|
||||
|
||||
mTransferQueue.offer(audioPacket);
|
||||
mLastBufferReceived = System.currentTimeMillis();
|
||||
}
|
||||
else
|
||||
{
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,17 +186,23 @@ public class AudioPacketWaveRecorder extends Module implements Listener<AudioPac
|
||||
*/
|
||||
private void write() throws IOException
|
||||
{
|
||||
AudioPacket audioPacket = mAudioPackets.poll();
|
||||
ReusableAudioPacket audioPacket = mTransferQueue.poll();
|
||||
|
||||
while(audioPacket != null && audioPacket.getType() == AudioPacket.Type.AUDIO)
|
||||
while(audioPacket != null && audioPacket.getType() == ReusableAudioPacket.Type.AUDIO)
|
||||
{
|
||||
if(audioPacket.hasMetadata())
|
||||
{
|
||||
mMetadata = audioPacket.getMetadata();
|
||||
}
|
||||
|
||||
mWriter.writeData(ConversionUtils.convertToSigned16BitSamples(audioPacket.getAudioBuffer()));
|
||||
audioPacket = mAudioPackets.poll();
|
||||
mWriter.writeData(ConversionUtils.convertToSigned16BitSamples(audioPacket.getAudioSamples()));
|
||||
audioPacket.decrementUserCount();
|
||||
audioPacket = mTransferQueue.poll();
|
||||
}
|
||||
|
||||
if(audioPacket != null)
|
||||
{
|
||||
audioPacket.decrementUserCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +220,7 @@ public class AudioPacketWaveRecorder extends Module implements Listener<AudioPac
|
||||
catch(IOException ioe)
|
||||
{
|
||||
/* Stop this module if/when we get an IO exception */
|
||||
mAudioPackets.clear();
|
||||
mTransferQueue.clear();
|
||||
stop();
|
||||
|
||||
mLog.error("IO Exception while trying to write to the wave writer", ioe);
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.sample.buffer;
|
||||
|
||||
import io.github.dsheirer.channel.metadata.Metadata;
|
||||
|
||||
/**
|
||||
* Reusable audio packet that carries audio sample data, associated metadata and a type to indicate if this
|
||||
* packet contains audio data or is an end-audio packet.
|
||||
*/
|
||||
public class ReusableAudioPacket extends AbstractReusableBuffer
|
||||
{
|
||||
private Type mType = Type.AUDIO;
|
||||
private Metadata mMetadata;
|
||||
private float[] mAudioSamples;
|
||||
|
||||
/**
|
||||
* Constructs a reusable audio packet. This constructor is package private and should only be used by
|
||||
* a reusable audio packet queue.
|
||||
*
|
||||
* @param bufferDisposedListener to be notified when all users have released the packet
|
||||
* @param length of the sample buffer
|
||||
*/
|
||||
ReusableAudioPacket(IReusableBufferDisposedListener bufferDisposedListener, int length)
|
||||
{
|
||||
super(bufferDisposedListener);
|
||||
resize(length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this packet has associated metadata
|
||||
*/
|
||||
public boolean hasMetadata()
|
||||
{
|
||||
return mMetadata != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associated audio metadata
|
||||
*/
|
||||
public Metadata getMetadata()
|
||||
{
|
||||
return mMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the metadata associated with this audio packet.
|
||||
*/
|
||||
public void setMetadata(Metadata metadata)
|
||||
{
|
||||
mMetadata = metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the type of audio packet
|
||||
*/
|
||||
public Type getType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of audio packet.
|
||||
*
|
||||
* This method is package private and is used by the reusable audio packet queue.
|
||||
*/
|
||||
void setType(Type type)
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* PCM 8 kHz audio samples
|
||||
*/
|
||||
public float[] getAudioSamples()
|
||||
{
|
||||
return mAudioSamples;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this audio packet contains audio samples.
|
||||
*/
|
||||
public boolean hasAudioSamples()
|
||||
{
|
||||
return mType != null && mType == Type.AUDIO && mAudioSamples != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the internal audio sample buffer.
|
||||
*/
|
||||
public void resize(int length)
|
||||
{
|
||||
if(mAudioSamples == null || mAudioSamples.length != length)
|
||||
{
|
||||
mAudioSamples = new float[length];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a copy of the float sample data from the reusable buffer into this audio packet, resizing the
|
||||
* internal audio sample buffer as necessary.
|
||||
*
|
||||
* @param reusableBuffer to load audio sample data from
|
||||
*/
|
||||
public void loadAudioFrom(ReusableBuffer reusableBuffer)
|
||||
{
|
||||
if(reusableBuffer.getSamples().length != mAudioSamples.length)
|
||||
{
|
||||
resize(reusableBuffer.getSamples().length);
|
||||
}
|
||||
|
||||
System.arraycopy(reusableBuffer.getSamples(), 0, mAudioSamples, 0, reusableBuffer.getSamples().length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the audio sample array into this buffer.
|
||||
*
|
||||
* Note: this method is used for compatibility with legacy audio converters that have not been updated to
|
||||
* use reusable audio packets and is therefore deprecated and will be removed once converters (ie JMBE) have
|
||||
* been updated.
|
||||
*
|
||||
* @param audio to load
|
||||
*/
|
||||
@Deprecated
|
||||
public void loadAudioFrom(float[] audio)
|
||||
{
|
||||
mAudioSamples = audio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio Packet Type
|
||||
*/
|
||||
public enum Type
|
||||
{
|
||||
AUDIO,
|
||||
END;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.sample.buffer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Queue for creating and reusing/managing reusable audio packets.
|
||||
*/
|
||||
public class ReusableAudioPacketQueue extends AbstractReusableBufferQueue<ReusableAudioPacket>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ReusableAudioPacketQueue.class);
|
||||
|
||||
public ReusableAudioPacketQueue(String debugName)
|
||||
{
|
||||
super(debugName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a reusable buffer from an internal recycling queue, or creates a new buffer if there are currently no
|
||||
* buffers available for reuse.
|
||||
*
|
||||
* @param size of the samples that will be loaded into the buffer
|
||||
* @return a reusable buffer
|
||||
*/
|
||||
public ReusableAudioPacket getBuffer(int size)
|
||||
{
|
||||
ReusableAudioPacket buffer = getRecycledBuffer();
|
||||
|
||||
if(buffer == null)
|
||||
{
|
||||
buffer = new ReusableAudioPacket(this, size);
|
||||
incrementBufferCount();
|
||||
|
||||
buffer.setDebugName("Owner:" + getDebugName());
|
||||
mLog.debug("Buffer Created - Count:" + getBufferCount() + (getDebugName() != null ? " [" + getDebugName() + "]" : ""));
|
||||
}
|
||||
|
||||
buffer.setType(ReusableAudioPacket.Type.AUDIO);
|
||||
buffer.resize(size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public ReusableAudioPacket getEndAudioBuffer()
|
||||
{
|
||||
ReusableAudioPacket buffer = getRecycledBuffer();
|
||||
|
||||
if(buffer == null)
|
||||
{
|
||||
buffer = new ReusableAudioPacket(this, 0);
|
||||
incrementBufferCount();
|
||||
|
||||
buffer.setDebugName("Owner:" + getDebugName());
|
||||
mLog.debug("Buffer Created - Count:" + getBufferCount() + (getDebugName() != null ? " [" + getDebugName() + "]" : ""));
|
||||
}
|
||||
|
||||
buffer.setType(ReusableAudioPacket.Type.END);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import io.github.dsheirer.sample.Listener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ReusableBufferBroadcaster<T extends ReusableBuffer> extends Broadcaster<T>
|
||||
public class ReusableBufferBroadcaster<T extends AbstractReusableBuffer> extends Broadcaster<T>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ReusableBufferBroadcaster.class);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user