Adds support to AM and FM decoders to record all audio produced by the
decoder.
This commit is contained in:
Denny Sheirer
2019-01-20 15:14:56 +00:00
committed by GitHub
parent 25d387f3cf
commit 4e92a6e350
7 changed files with 236 additions and 119 deletions

View File

@@ -1,7 +1,7 @@
/* /*
* ****************************************************************************** * ******************************************************************************
* sdrtrunk * sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer * Copyright (C) 2014-2019 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -71,8 +71,14 @@ public class AudioMetadataProcessor
if(aliasList != null) if(aliasList != null)
{ {
audioPacket.addBroadcastChannels(aliasList.getBroadcastChannels(audioPacket.getIdentifierCollection())); audioPacket.addBroadcastChannels(aliasList.getBroadcastChannels(audioPacket.getIdentifierCollection()));
audioPacket.setRecordable(aliasList.isRecordable(audioPacket.getIdentifierCollection()));
audioPacket.setMonitoringPriority(aliasList.getAudioPlaybackPriority(audioPacket.getIdentifierCollection())); audioPacket.setMonitoringPriority(aliasList.getAudioPlaybackPriority(audioPacket.getIdentifierCollection()));
//If the audio packet is already marked recordable, leave it alone, otherwise attempt to determine
//if we should record the audio packet from the aliased identifiers
if(!audioPacket.isRecordable())
{
audioPacket.setRecordable(aliasList.isRecordable(audioPacket.getIdentifierCollection()));
}
} }
} }
} }

View File

@@ -1,18 +1,22 @@
/******************************************************************************* /*
* sdr-trunk * ******************************************************************************
* Copyright (C) 2014-2018 Dennis Sheirer * sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software: you can redistribute it and/or modify
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any * it under the terms of the GNU General Public License as published by
* later version. * 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 * This program is distributed in the hope that it will be useful,
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * 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. * You should have received a copy of the GNU General Public License
* If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.audio; package io.github.dsheirer.audio;
import io.github.dsheirer.audio.squelch.SquelchState; import io.github.dsheirer.audio.squelch.SquelchState;
@@ -72,6 +76,7 @@ public class AudioModule extends AbstractAudioModule implements IReusableBufferL
private RealFIRFilter2 mHighPassFilter = new RealFIRFilter2(sHighPassFilterCoefficients); private RealFIRFilter2 mHighPassFilter = new RealFIRFilter2(sHighPassFilterCoefficients);
private SquelchStateListener mSquelchStateListener = new SquelchStateListener(); private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
private SquelchState mSquelchState = SquelchState.SQUELCH; private SquelchState mSquelchState = SquelchState.SQUELCH;
private boolean mRecordAudioOverride;
/** /**
* Creates an Audio Module. * Creates an Audio Module.
@@ -87,6 +92,16 @@ public class AudioModule extends AbstractAudioModule implements IReusableBufferL
mSquelchStateListener = null; mSquelchStateListener = null;
} }
/**
* Sets all audio packets as recordable when the argument is true. Otherwise, defers to the aliased identifiers
* from the identifier collection to determine whether to record the audio or not.
* @param recordAudio set to true to mark all audio as recordable.
*/
public void setRecordAudio(boolean recordAudio)
{
mRecordAudioOverride = recordAudio;
}
@Override @Override
public void reset() public void reset()
{ {
@@ -109,6 +124,11 @@ public class AudioModule extends AbstractAudioModule implements IReusableBufferL
endAudioPacket.resetAttributes(); endAudioPacket.resetAttributes();
endAudioPacket.setAudioChannelId(getAudioChannelId()); endAudioPacket.setAudioChannelId(getAudioChannelId());
endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); endAudioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
if(mRecordAudioOverride)
{
endAudioPacket.setRecordable(true);
}
endAudioPacket.incrementUserCount(); endAudioPacket.incrementUserCount();
getAudioPacketListener().receive(endAudioPacket); getAudioPacketListener().receive(endAudioPacket);
} }
@@ -132,6 +152,10 @@ public class AudioModule extends AbstractAudioModule implements IReusableBufferL
audioPacket.resetAttributes(); audioPacket.resetAttributes();
audioPacket.setAudioChannelId(getAudioChannelId()); audioPacket.setAudioChannelId(getAudioChannelId());
audioPacket.loadAudioFrom(highPassFiltered); audioPacket.loadAudioFrom(highPassFiltered);
if(mRecordAudioOverride)
{
audioPacket.setRecordable(true);
}
audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf()); audioPacket.setIdentifierCollection(getIdentifierCollection().copyOf());
getAudioPacketListener().receive(audioPacket); getAudioPacketListener().receive(audioPacket);

View File

@@ -150,7 +150,14 @@ public class DecoderFactory
case AM: case AM:
modules.add(new AMDecoder(decodeConfig)); modules.add(new AMDecoder(decodeConfig));
modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.AM, channel.getName())); modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.AM, channel.getName()));
modules.add(new AudioModule()); AudioModule audioModuleAM = new AudioModule();
//Check if the user wants all audio recorded ..
if(((DecodeConfigAM)decodeConfig).getRecordAudio())
{
audioModuleAM.setRecordAudio(true);
}
modules.add(audioModuleAM);
if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER)
{ {
modules.add(new AMDemodulatorModule(AM_CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE)); modules.add(new AMDemodulatorModule(AM_CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE));
@@ -159,7 +166,14 @@ public class DecoderFactory
case NBFM: case NBFM:
modules.add(new NBFMDecoder(decodeConfig)); modules.add(new NBFMDecoder(decodeConfig));
modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.NBFM, channel.getName())); modules.add(new AlwaysUnsquelchedDecoderState(DecoderType.NBFM, channel.getName()));
modules.add(new AudioModule()); AudioModule audioModuleFM = new AudioModule();
//Check if the user wants all audio recorded ..
if(((DecodeConfigNBFM)decodeConfig).getRecordAudio())
{
audioModuleFM.setRecordAudio(true);
}
modules.add(audioModuleFM);
if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER)
{ {
modules.add(new FMDemodulatorModule(FM_CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE)); modules.add(new FMDemodulatorModule(FM_CHANNEL_BANDWIDTH, DEMODULATED_AUDIO_SAMPLE_RATE));

View File

@@ -1,20 +1,22 @@
/******************************************************************************* /*
* SDR Trunk * ******************************************************************************
* Copyright (C) 2014-2016 Dennis Sheirer * sdrtrunk
* * Copyright (C) 2014-2019 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 * This program is free software: you can redistribute it and/or modify
* the Free Software Foundation, either version 3 of the License, or * it under the terms of the GNU General Public License as published by
* (at your option) any later version. * 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 * This program is distributed in the hope that it will be useful,
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU General Public License for more details. * 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.module.decode.am; package io.github.dsheirer.module.decode.am;
import io.github.dsheirer.controller.channel.Channel; import io.github.dsheirer.controller.channel.Channel;
@@ -23,53 +25,74 @@ import io.github.dsheirer.gui.editor.EditorValidationException;
import io.github.dsheirer.gui.editor.ValidatingEditor; import io.github.dsheirer.gui.editor.ValidatingEditor;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
import javax.swing.*; import javax.swing.JCheckBox;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AMDecoderEditor extends ValidatingEditor<Channel> public class AMDecoderEditor extends ValidatingEditor<Channel>
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private JCheckBox mCheckBoxRecordAudio;
public AMDecoderEditor()
{
setLayout( new MigLayout( "insets 0 0 0 0", "", "" ) );
add( new JLabel( "AM Decoder" ) );
}
@Override public AMDecoderEditor()
public void validate( Editor<Channel> editor ) throws EditorValidationException {
{ setLayout(new MigLayout("insets 0 0 0 0", "", ""));
} add(new JLabel("AM Decoder"));
mCheckBoxRecordAudio = new JCheckBox("Record Audio");
mCheckBoxRecordAudio.setEnabled(false);
mCheckBoxRecordAudio.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mCheckBoxRecordAudio);
}
@Override @Override
public void setItem( Channel item ) public void validate(Editor<Channel> editor) throws EditorValidationException
{ {
super.setItem( item ); }
if( hasItem() ) @Override
{ public void setItem(Channel item)
if( getItem().getDecodeConfiguration() instanceof DecodeConfigAM ) {
{ super.setItem(item);
setModified( false );
}
else
{
setModified( true );
}
}
else
{
setModified( false );
}
}
@Override if(hasItem())
public void save() {
{ if(getItem().getDecodeConfiguration() instanceof DecodeConfigAM)
if( hasItem() && isModified() ) {
{ DecodeConfigAM config = (DecodeConfigAM)getItem().getDecodeConfiguration();
getItem().setDecodeConfiguration( new DecodeConfigAM() ); mCheckBoxRecordAudio.setSelected(config.getRecordAudio());
} mCheckBoxRecordAudio.setEnabled(true);
setModified(false);
setModified( false ); }
} else
{
setModified(true);
}
}
else
{
mCheckBoxRecordAudio.setEnabled(false);
setModified(false);
}
}
@Override
public void save()
{
if(hasItem() && isModified())
{
DecodeConfigAM config = new DecodeConfigAM();
config.setRecordAudio(mCheckBoxRecordAudio.isSelected());
getItem().setDecodeConfiguration(config);
}
setModified(false);
}
} }

View File

@@ -1,20 +1,22 @@
/******************************************************************************* /*
* SDR Trunk * ******************************************************************************
* Copyright (C) 2014 Dennis Sheirer * sdrtrunk
* * Copyright (C) 2014-2019 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 * This program is free software: you can redistribute it and/or modify
* the Free Software Foundation, either version 3 of the License, or * it under the terms of the GNU General Public License as published by
* (at your option) any later version. * 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 * This program is distributed in the hope that it will be useful,
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU General Public License for more details. * 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.module.decode.am; package io.github.dsheirer.module.decode.am;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -25,10 +27,23 @@ import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
public class DecodeConfigAM extends DecodeConfiguration public class DecodeConfigAM extends DecodeConfiguration
{ {
private boolean mRecordAudio = false;
public DecodeConfigAM() public DecodeConfigAM()
{ {
} }
@JacksonXmlProperty(isAttribute = true, localName = "recordAudio")
public boolean getRecordAudio()
{
return mRecordAudio;
}
public void setRecordAudio(boolean recordAudio)
{
mRecordAudio = recordAudio;
}
/** /**
* Source channel specification for this decoder * Source channel specification for this decoder
*/ */

View File

@@ -1,20 +1,22 @@
/******************************************************************************* /*
* SDR Trunk * ******************************************************************************
* Copyright (C) 2014 Dennis Sheirer * sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/ * *****************************************************************************
*/
package io.github.dsheirer.module.decode.nbfm; package io.github.dsheirer.module.decode.nbfm;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -26,6 +28,7 @@ import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
public class DecodeConfigNBFM extends DecodeConfiguration public class DecodeConfigNBFM extends DecodeConfiguration
{ {
private Bandwidth mBandwidth = Bandwidth.BW_12_5; private Bandwidth mBandwidth = Bandwidth.BW_12_5;
private boolean mRecordAudio = false;
public DecodeConfigNBFM() public DecodeConfigNBFM()
{ {
@@ -68,6 +71,17 @@ public class DecodeConfigNBFM extends DecodeConfiguration
mBandwidth = bandwidth; mBandwidth = bandwidth;
} }
@JacksonXmlProperty(isAttribute = true, localName = "recordAudio")
public boolean getRecordAudio()
{
return mRecordAudio;
}
public void setRecordAudio(boolean recordAudio)
{
mRecordAudio = recordAudio;
}
public enum Bandwidth public enum Bandwidth
{ {
BW_12_5("12.5 kHz"), BW_12_5("12.5 kHz"),
@@ -85,5 +99,5 @@ public class DecodeConfigNBFM extends DecodeConfiguration
{ {
return mLabel; return mLabel;
} }
}; }
} }

View File

@@ -1,18 +1,22 @@
/******************************************************************************* /*
* sdr-trunk * ******************************************************************************
* Copyright (C) 2014-2018 Dennis Sheirer * sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software: you can redistribute it and/or modify
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any * it under the terms of the GNU General Public License as published by
* later version. * 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 * This program is distributed in the hope that it will be useful,
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * 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. * You should have received a copy of the GNU General Public License
* If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.module.decode.nbfm; package io.github.dsheirer.module.decode.nbfm;
import io.github.dsheirer.controller.channel.Channel; import io.github.dsheirer.controller.channel.Channel;
@@ -23,6 +27,7 @@ import io.github.dsheirer.module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JLabel; import javax.swing.JLabel;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@@ -33,6 +38,7 @@ public class NBFMDecoderEditor extends ValidatingEditor<Channel>
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private JComboBox<DecodeConfigNBFM.Bandwidth> mComboBandwidth; private JComboBox<DecodeConfigNBFM.Bandwidth> mComboBandwidth;
private JCheckBox mCheckBoxRecordAudio;
public NBFMDecoderEditor() public NBFMDecoderEditor()
{ {
@@ -41,7 +47,7 @@ public class NBFMDecoderEditor extends ValidatingEditor<Channel>
private void init() private void init()
{ {
setLayout(new MigLayout("insets 0 0 0 0,wrap 2", "[right][grow,fill]", "")); setLayout(new MigLayout("insets 0 0 0 0,wrap 3", "[][][]", ""));
mComboBandwidth = new JComboBox<>(); mComboBandwidth = new JComboBox<>();
mComboBandwidth.setModel(new DefaultComboBoxModel<DecodeConfigNBFM.Bandwidth>( mComboBandwidth.setModel(new DefaultComboBoxModel<DecodeConfigNBFM.Bandwidth>(
@@ -58,6 +64,18 @@ public class NBFMDecoderEditor extends ValidatingEditor<Channel>
add(new JLabel("Bandwidth:")); add(new JLabel("Bandwidth:"));
add(mComboBandwidth); add(mComboBandwidth);
mCheckBoxRecordAudio = new JCheckBox("Record Audio");
mCheckBoxRecordAudio.setEnabled(false);
mCheckBoxRecordAudio.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mCheckBoxRecordAudio);
} }
@Override @Override
@@ -73,6 +91,7 @@ public class NBFMDecoderEditor extends ValidatingEditor<Channel>
{ {
DecodeConfigNBFM nbfm = new DecodeConfigNBFM(); DecodeConfigNBFM nbfm = new DecodeConfigNBFM();
nbfm.setBandwidth((DecodeConfigNBFM.Bandwidth)mComboBandwidth.getSelectedItem()); nbfm.setBandwidth((DecodeConfigNBFM.Bandwidth)mComboBandwidth.getSelectedItem());
nbfm.setRecordAudio(mCheckBoxRecordAudio.isSelected());
getItem().setDecodeConfiguration(nbfm); getItem().setDecodeConfiguration(nbfm);
} }
@@ -82,6 +101,7 @@ public class NBFMDecoderEditor extends ValidatingEditor<Channel>
private void setControlsEnabled(boolean enabled) private void setControlsEnabled(boolean enabled)
{ {
mComboBandwidth.setEnabled(enabled); mComboBandwidth.setEnabled(enabled);
mCheckBoxRecordAudio.setEnabled(enabled);
} }
@Override @Override
@@ -99,6 +119,7 @@ public class NBFMDecoderEditor extends ValidatingEditor<Channel>
{ {
DecodeConfigNBFM nbfm = (DecodeConfigNBFM)config; DecodeConfigNBFM nbfm = (DecodeConfigNBFM)config;
mComboBandwidth.setSelectedItem(nbfm.getBandwidth()); mComboBandwidth.setSelectedItem(nbfm.getBandwidth());
mCheckBoxRecordAudio.setSelected(nbfm.getRecordAudio());
setModified(false); setModified(false);
} }
else else