From bc430b255f36a0cb2d9cb15467deeacb760d3b8e Mon Sep 17 00:00:00 2001 From: Denny Date: Tue, 3 Jan 2017 09:27:17 -0500 Subject: [PATCH] #30 - changes internal MP3 temporary recording stream management so that the broadcast model manages the recordings and sends the completed recordings to the broadcasters to avoid 2 or more streams recording MP3 files for the same audio call. Note: there is a bug where temporary recordings are not being consistently deleted that I'm still working on. --- src/audio/broadcast/AudioBroadcaster.java | 87 ++++-------- ...udioRecording.java => AudioRecording.java} | 33 ++++- src/audio/broadcast/BroadcastModel.java | 125 +++++++++++++++--- src/audio/broadcast/StreamManager.java | 23 ++-- src/record/AudioRecorder.java | 6 +- 5 files changed, 184 insertions(+), 90 deletions(-) rename src/audio/broadcast/{StreamableAudioRecording.java => AudioRecording.java} (70%) diff --git a/src/audio/broadcast/AudioBroadcaster.java b/src/audio/broadcast/AudioBroadcaster.java index be544ae1..cda9f47e 100644 --- a/src/audio/broadcast/AudioBroadcaster.java +++ b/src/audio/broadcast/AudioBroadcaster.java @@ -36,7 +36,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -public abstract class AudioBroadcaster implements IAudioPacketListener +public abstract class AudioBroadcaster implements Listener { private final static Logger mLog = LoggerFactory.getLogger( AudioBroadcaster.class ); @@ -46,14 +46,13 @@ public abstract class AudioBroadcaster implements IAudioPacketListener private ScheduledFuture mScheduledTask; private RecordingQueueProcessor mRecordingQueueProcessor = new RecordingQueueProcessor(); - private LinkedTransferQueue mAudioRecordingQueue = new LinkedTransferQueue<>(); + private LinkedTransferQueue mAudioRecordingQueue = new LinkedTransferQueue<>(); private ISilenceGenerator mSilenceGenerator; private Listener mBroadcastEventListener; private BroadcastState mBroadcastState = BroadcastState.READY; - private StreamManager mStreamManager; private int mStreamedAudioCount = 0; private BroadcastConfiguration mBroadcastConfiguration; private long mDelay; @@ -85,11 +84,7 @@ public abstract class AudioBroadcaster implements IAudioPacketListener mThreadPoolManager = threadPoolManager; mBroadcastConfiguration = broadcastConfiguration; mDelay = mBroadcastConfiguration.getDelay(); - mSilenceGenerator = BroadcastFactory.getSilenceGenerator(broadcastConfiguration.getBroadcastFormat()); - - mStreamManager = new StreamManager(threadPoolManager, this, - SystemProperties.getInstance().getApplicationFolder(BroadcastModel.TEMPORARY_STREAM_DIRECTORY)); } protected ThreadPoolManager getThreadPoolManager() @@ -133,8 +128,6 @@ public abstract class AudioBroadcaster implements IAudioPacketListener { if(mStreaming.compareAndSet(false, true)) { - mStreamManager.start(); - if(mScheduledTask == null) { if(mThreadPoolManager != null) @@ -153,8 +146,6 @@ public abstract class AudioBroadcaster implements IAudioPacketListener { if(mStreaming.compareAndSet(true, false)) { - mStreamManager.stop(); - if(mThreadPoolManager != null && mScheduledTask != null) { mThreadPoolManager.cancel(mScheduledTask); @@ -201,7 +192,7 @@ public abstract class AudioBroadcaster implements IAudioPacketListener * * @param recording to queue for broadcasting */ - public void receive(StreamableAudioRecording recording) + public void receive(AudioRecording recording) { if(connected()) { @@ -210,24 +201,6 @@ public abstract class AudioBroadcaster implements IAudioPacketListener } } - /** - * Cleanup method to remove a temporary recording file from disk. - * - * @param recording to remove - */ - private void removeRecording(StreamableAudioRecording recording) - { - try - { - Files.delete(recording.getPath()); - } - catch(IOException ioe) - { - mLog.error("Stream [" + getBroadcastConfiguration().getName() + "] - error deleting temporary internet " + - "recording file: " + recording.getPath().toString() + " - " + ioe.getMessage()); - } - } - /** * Broadcast configuration used by this broadcaster */ @@ -236,15 +209,6 @@ public abstract class AudioBroadcaster implements IAudioPacketListener return mBroadcastConfiguration; } - /** - * IAudioPacketListener interface method to gain access to the internal stream manager for enqueuing audio packets. - */ - @Override - public Listener getAudioPacketListener() - { - return mStreamManager; - } - /** * Registers the listener to receive broadcast events/state changes */ @@ -291,11 +255,11 @@ public abstract class AudioBroadcaster implements IAudioPacketListener if(!connected()) { - StreamableAudioRecording recording = mAudioRecordingQueue.poll(); + //Remove all pending audio recordings + AudioRecording recording = mAudioRecordingQueue.poll(); while(recording != null) { - removeRecording(recording); recording = mAudioRecordingQueue.poll(); } } @@ -426,37 +390,38 @@ public abstract class AudioBroadcaster implements IAudioPacketListener mInputStream = null; - StreamableAudioRecording nextRecording = mAudioRecordingQueue.peek(); + AudioRecording nextRecording = mAudioRecordingQueue.peek(); if(nextRecording != null && nextRecording.getStartTime() + mDelay <= System.currentTimeMillis()) { - StreamableAudioRecording recording = mAudioRecordingQueue.poll(); + AudioRecording recording = mAudioRecordingQueue.poll(); try { - byte[] audio = Files.readAllBytes(recording.getPath()); - - if(audio != null && audio.length > 0) + if(Files.exists(recording.getPath())) { - mInputStream = new ByteArrayInputStream(audio); + byte[] audio = Files.readAllBytes(recording.getPath()); - mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS - - (recording.getRecordingLength() % PROCESSOR_RUN_INTERVAL_MS); - - while(mFinalSilencePadding >= PROCESSOR_RUN_INTERVAL_MS) + if(audio != null && audio.length > 0) { - mFinalSilencePadding -= PROCESSOR_RUN_INTERVAL_MS; - } + mInputStream = new ByteArrayInputStream(audio); - if(connected()) - { - broadcastMetadata(recording.getAudioMetadata()); - } + mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS - + (recording.getRecordingLength() % PROCESSOR_RUN_INTERVAL_MS); - metadataUpdateRequired = false; + while(mFinalSilencePadding >= PROCESSOR_RUN_INTERVAL_MS) + { + mFinalSilencePadding -= PROCESSOR_RUN_INTERVAL_MS; + } + + if(connected()) + { + broadcastMetadata(recording.getAudioMetadata()); + } + + metadataUpdateRequired = false; + } } - - removeRecording(recording); } catch(IOException ioe) { @@ -467,6 +432,8 @@ public abstract class AudioBroadcaster implements IAudioPacketListener metadataUpdateRequired = false; } + recording.removePendingReplay(); + broadcast(new BroadcastEvent(AudioBroadcaster.this, BroadcastEvent.Event.BROADCASTER_QUEUE_CHANGE)); } diff --git a/src/audio/broadcast/StreamableAudioRecording.java b/src/audio/broadcast/AudioRecording.java similarity index 70% rename from src/audio/broadcast/StreamableAudioRecording.java rename to src/audio/broadcast/AudioRecording.java index 507a9a5e..a8538035 100644 --- a/src/audio/broadcast/StreamableAudioRecording.java +++ b/src/audio/broadcast/AudioRecording.java @@ -21,13 +21,15 @@ package audio.broadcast; import audio.metadata.AudioMetadata; import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicInteger; -public class StreamableAudioRecording implements Comparable +public class AudioRecording implements Comparable { private Path mPath; private AudioMetadata mAudioMetadata; private long mStartTime; private long mRecordingLength; + private AtomicInteger mPendingReplayCount = new AtomicInteger(); /** * Audio recording that is ready to be streamed @@ -36,7 +38,7 @@ public class StreamableAudioRecording implements Comparable mBroadcastConfigurations = new CopyOnWriteArrayList<>(); + private List mRecordingQueue = new CopyOnWriteArrayList<>(); private Map mBroadcastConfigurationMap = new HashMap<>(); private Map mBroadcasterMap = new HashMap<>(); private ThreadPoolManager mThreadPoolManager; private SettingsManager mSettingsManager; - + private StreamManager mStreamManager; private Broadcaster mBroadcastEventBroadcaster = new Broadcaster<>(); /** @@ -75,6 +78,13 @@ public class BroadcastModel extends AbstractTableModel implements Listener