Resolves #387 10 second/10 minute audio recording time limit.

Updated audio packet wave recorder to correctly dequeue audio packets
to ensure that the overflowable buffer queue accounting process was
working correctly.

Updated overflowable buffer queue's poll() method to correctly decrement
the queue size counter.

Resolved issue where the mutable metadata was being prematurely reset
and causing the end audio packet to be mis-identified.  This resulted
in the recording manager not stopping the recording on command with the
timeout mechanism kicking in after a brief delay.
This commit is contained in:
Denny
2018-10-08 04:58:21 -04:00
parent d95c78c0f1
commit eb79d9e037
4 changed files with 71 additions and 27 deletions

View File

@@ -114,6 +114,8 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
@Override
public void reset()
{
getMutableMetadata().resetTemporalAttributes();
broadcast(new DecoderStateEvent(this, Event.RESET, State.IDLE));
mState = State.IDLE;
@@ -401,8 +403,6 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
{
broadcast(SquelchState.SQUELCH);
getMutableMetadata().resetTemporalAttributes();
mState = State.TEARDOWN;
mMutableMetadata.receive(new AttributeChangeRequest<State>(Attribute.CHANNEL_STATE, mState));

View File

@@ -1,20 +1,22 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
/*
* ******************************************************************************
* sdrtrunk
* 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.record.config;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@@ -24,32 +26,64 @@ import io.github.dsheirer.record.RecorderType;
import java.util.ArrayList;
import java.util.List;
/**
* Contains the types of recordings specified for a channel
*/
public class RecordConfiguration extends Configuration
{
/**
* Recording types requested for this configuration
*/
private List<RecorderType> mRecorders = new ArrayList<>();
/**
* Constructs a recording configuration instance
*/
public RecordConfiguration()
{
//Empty constructor required for deserialization
}
/**
* List of recorder types specified in this configuration
*/
@JacksonXmlProperty(isAttribute = false, localName = "recorder")
public List<RecorderType> getRecorders()
{
return mRecorders;
}
/**
* Sets the (complete) list of recorder types for this configuration, erasing any existing recording types.
*/
public void setRecorders(List<RecorderType> recorders)
{
mRecorders = recorders;
}
/**
* Adds the recorder type to the configuration
*/
public void addRecorder(RecorderType recorder)
{
mRecorders.add(recorder);
}
/**
* Clears all recorder types from this configuration
*/
public void clearRecorders()
{
mRecorders.clear();
}
/**
* Indicates if this configuration has the specified recorder type
* @param recorderType to check
* @return true if this configuration contains the specified recorder type
*/
public boolean contains(RecorderType recorderType)
{
return mRecorders.contains(recorderType);
}
}

View File

@@ -32,6 +32,8 @@ import javax.sound.sampled.AudioFormat;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -54,6 +56,7 @@ public class AudioPacketWaveRecorder extends Module implements Listener<Reusable
private ScheduledFuture<?> mProcessorHandle;
private Metadata mMetadata;
private long mLastBufferReceived;
private List<ReusableAudioPacket> mAudioPacketsToProcess = new ArrayList<>();
private AtomicBoolean mRunning = new AtomicBoolean();
@@ -186,24 +189,24 @@ public class AudioPacketWaveRecorder extends Module implements Listener<Reusable
*/
private void write() throws IOException
{
ReusableAudioPacket audioPacket = mTransferQueue.poll();
mTransferQueue.drainTo(mAudioPacketsToProcess);
while(audioPacket != null && audioPacket.getType() == ReusableAudioPacket.Type.AUDIO)
for(ReusableAudioPacket audioPacket: mAudioPacketsToProcess)
{
if(audioPacket.hasMetadata())
if(audioPacket.getType() == ReusableAudioPacket.Type.AUDIO)
{
mMetadata = audioPacket.getMetadata();
if(audioPacket.hasMetadata())
{
mMetadata = audioPacket.getMetadata();
}
mWriter.writeData(ConversionUtils.convertToSigned16BitSamples(audioPacket.getAudioSamples()));
}
mWriter.writeData(ConversionUtils.convertToSigned16BitSamples(audioPacket.getAudioSamples()));
audioPacket.decrementUserCount();
audioPacket = mTransferQueue.poll();
}
if(audioPacket != null)
{
audioPacket.decrementUserCount();
}
mAudioPacketsToProcess.clear();
}
/**

View File

@@ -101,7 +101,14 @@ public class OverflowableTransferQueue<E>
*/
public E poll()
{
return mQueue.poll();
E element = mQueue.poll();
if(element != null)
{
mCounter.decrementAndGet();
}
return element;
}
/**