mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
#90 [WIP] merged metadata management for channel state, decoder states and audio metadata into a new metadata class. The new metadata class is maintained for each decoding audio channel, or in the future, a decoding TDMA channel. Audio playback, recording and streaming all use the same metadata object for the channel. The list of channel processing gui panels have been deleted and channel processing status will now reside in a table where each table row is a metadata instance from the processing channel. The channel processing manager is responsible for adding/removing the channel's metadata instance to/from the metadata table. This allows the channel processing table to be the controller for the messages, events and channel spectrum views, keyed to the selected table row metadata.
I still have to clean up the gui components and wire in the table selection listeners.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
* 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
|
||||
@@ -14,50 +14,51 @@
|
||||
*
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import alias.AliasModel;
|
||||
import audio.AudioPacket;
|
||||
import channel.metadata.Attribute;
|
||||
import channel.metadata.AttributeChangeRequest;
|
||||
import channel.metadata.ChannelMetadataModel;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ChannelEvent.Event;
|
||||
import controller.channel.map.ChannelMapModel;
|
||||
import filter.FilterSet;
|
||||
import message.Message;
|
||||
import module.Module;
|
||||
import module.ProcessingChain;
|
||||
import module.decode.DecoderFactory;
|
||||
import module.decode.event.MessageActivityModel;
|
||||
import module.log.EventLogManager;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import record.RecorderManager;
|
||||
import record.RecorderType;
|
||||
import sample.Listener;
|
||||
import source.Source;
|
||||
import source.SourceException;
|
||||
import source.SourceManager;
|
||||
import alias.AliasModel;
|
||||
import audio.AudioPacket;
|
||||
import audio.metadata.Metadata;
|
||||
import audio.metadata.MetadataType;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ChannelEvent.Event;
|
||||
import controller.channel.map.ChannelMapModel;
|
||||
import filter.FilterSet;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class ChannelProcessingManager implements ChannelEventListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelProcessingManager.class);
|
||||
|
||||
private Map<Integer, ProcessingChain> mProcessingChains = new HashMap<>();
|
||||
private Map<Integer,ProcessingChain> mProcessingChains = new HashMap<>();
|
||||
|
||||
private List<Listener<AudioPacket>> mAudioPacketListeners = new CopyOnWriteArrayList<>();
|
||||
private List<Listener<Message>> mMessageListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private ChannelModel mChannelModel;
|
||||
private ChannelMapModel mChannelMapModel;
|
||||
private ChannelMetadataModel mChannelMetadataModel = new ChannelMetadataModel();
|
||||
private AliasModel mAliasModel;
|
||||
private EventLogManager mEventLogManager;
|
||||
private RecorderManager mRecorderManager;
|
||||
@@ -78,6 +79,14 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
mSourceManager = sourceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel metadata model containing metadata for each channel or channel time-slice that is currently processing.
|
||||
*/
|
||||
public ChannelMetadataModel getChannelMetadataModel()
|
||||
{
|
||||
return mChannelMetadataModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a processing chain is constructed for the channel and that
|
||||
* the processing chain is currently processing.
|
||||
@@ -85,7 +94,7 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
private boolean isProcessing(Channel channel)
|
||||
{
|
||||
return mProcessingChains.containsKey(channel.getChannelID()) &&
|
||||
mProcessingChains.get(channel.getChannelID()).isProcessing();
|
||||
mProcessingChains.get(channel.getChannelID()).isProcessing();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,19 +111,19 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
{
|
||||
Channel channel = event.getChannel();
|
||||
|
||||
switch (event.getEvent())
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case REQUEST_ENABLE:
|
||||
if (!mProcessingChains.containsKey(channel.getChannelID()) ||
|
||||
!mProcessingChains.get(channel.getChannelID()).isProcessing())
|
||||
if(!mProcessingChains.containsKey(channel.getChannelID()) ||
|
||||
!mProcessingChains.get(channel.getChannelID()).isProcessing())
|
||||
{
|
||||
startProcessing(event);
|
||||
}
|
||||
break;
|
||||
case REQUEST_DISABLE:
|
||||
if (channel.getEnabled())
|
||||
if(channel.getEnabled())
|
||||
{
|
||||
switch (channel.getChannelType())
|
||||
switch(channel.getChannelType())
|
||||
{
|
||||
case STANDARD:
|
||||
stopProcessing(channel, true);
|
||||
@@ -129,13 +138,13 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
}
|
||||
}
|
||||
case NOTIFICATION_DELETE:
|
||||
if (channel.getEnabled())
|
||||
if(channel.getEnabled())
|
||||
{
|
||||
stopProcessing(channel, true);
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_CONFIGURATION_CHANGE:
|
||||
if (isProcessing(channel))
|
||||
if(isProcessing(channel))
|
||||
{
|
||||
stopProcessing(channel, false);
|
||||
startProcessing(event);
|
||||
@@ -153,7 +162,7 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
ProcessingChain processingChain = mProcessingChains.get(channel.getChannelID());
|
||||
|
||||
//If we're already processing, ignore the request
|
||||
if (processingChain != null && processingChain.isProcessing())
|
||||
if(processingChain != null && processingChain.isProcessing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -164,63 +173,88 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
try
|
||||
{
|
||||
source = mSourceManager.getSource(channel.getSourceConfiguration(),
|
||||
channel.getDecodeConfiguration().getDecoderType().getChannelBandwidth());
|
||||
channel.getDecodeConfiguration().getDecoderType().getChannelBandwidth());
|
||||
}
|
||||
catch (SourceException se)
|
||||
catch(SourceException se)
|
||||
{
|
||||
mLog.debug("Error obtaining source for channel [" + channel.getName() + "]", se);
|
||||
}
|
||||
|
||||
if (source == null)
|
||||
if(source == null)
|
||||
{
|
||||
channel.setEnabled(false);
|
||||
|
||||
mChannelModel.broadcast(
|
||||
new ChannelEvent(channel, Event.NOTIFICATION_ENABLE_REJECTED));
|
||||
new ChannelEvent(channel, Event.NOTIFICATION_ENABLE_REJECTED));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (processingChain == null)
|
||||
if(processingChain == null)
|
||||
{
|
||||
processingChain = new ProcessingChain(channel.getName(),
|
||||
channel.getChannelType());
|
||||
channel.getChannelType());
|
||||
|
||||
/* Register global listeners */
|
||||
for (Listener<AudioPacket> listener : mAudioPacketListeners)
|
||||
for(Listener<AudioPacket> listener : mAudioPacketListeners)
|
||||
{
|
||||
processingChain.addAudioPacketListener(listener);
|
||||
}
|
||||
|
||||
for (Listener<Message> listener : mMessageListeners)
|
||||
for(Listener<Message> listener : mMessageListeners)
|
||||
{
|
||||
processingChain.addMessageListener(listener);
|
||||
}
|
||||
|
||||
/* Processing Modules */
|
||||
List<Module> modules = DecoderFactory.getModules(mChannelModel,
|
||||
mChannelMapModel, this, mAliasModel, channel);
|
||||
List<Module> modules = DecoderFactory.getModules(mChannelModel, mChannelMapModel, this,
|
||||
mAliasModel, channel, processingChain.getChannelState().getMutableMetadata());
|
||||
processingChain.addModules(modules);
|
||||
|
||||
/* Setup message activity model with filtering */
|
||||
FilterSet<Message> messageFilter = DecoderFactory.getMessageFilters(modules);
|
||||
MessageActivityModel messageModel = new MessageActivityModel(messageFilter);
|
||||
processingChain.setMessageActivityModel(messageModel);
|
||||
|
||||
/* Inject channel metadata that will be inserted into audio packets
|
||||
* for the recorder manager and streaming */
|
||||
processingChain.broadcast(
|
||||
new Metadata(MetadataType.SYSTEM, channel.getSystem()));
|
||||
processingChain.broadcast(
|
||||
new Metadata(MetadataType.SITE_ID, channel.getSite()));
|
||||
processingChain.broadcast(
|
||||
new Metadata(MetadataType.CHANNEL_NAME, channel.getName()));
|
||||
|
||||
//Override recordable flag in metadata if user has specified audio recording
|
||||
if(channel.getRecordConfiguration() != null &&
|
||||
channel.getRecordConfiguration().getRecorders().contains(RecorderType.AUDIO))
|
||||
{
|
||||
processingChain.getChannelState().getMutableMetadata().setRecordable(true);
|
||||
}
|
||||
|
||||
//Inject channel metadata that will be inserted into audio packets for recorder manager and streaming
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if(channel.getSystem() != null)
|
||||
{
|
||||
sb.append(channel.getSystem());
|
||||
}
|
||||
|
||||
if(channel.getSite() != null)
|
||||
{
|
||||
if(sb.length() > 0)
|
||||
{
|
||||
sb.append(" - ");
|
||||
}
|
||||
|
||||
sb.append(channel.getSite());
|
||||
}
|
||||
|
||||
if(sb.length() > 0)
|
||||
{
|
||||
processingChain.getChannelState().getMutableMetadata()
|
||||
.receive(new AttributeChangeRequest<String>(Attribute.CHANNEL_CONFIGURATION_LABEL_1, sb.toString()));
|
||||
}
|
||||
|
||||
processingChain.getChannelState().getMutableMetadata()
|
||||
.receive(new AttributeChangeRequest<String>(Attribute.CHANNEL_CONFIGURATION_LABEL_2, channel.getName()));
|
||||
}
|
||||
|
||||
/* Setup event logging */
|
||||
List<Module> loggers = mEventLogManager.getLoggers(channel.getEventLogConfiguration(), channel.getName());
|
||||
|
||||
if (!loggers.isEmpty())
|
||||
if(!loggers.isEmpty())
|
||||
{
|
||||
processingChain.addModules(loggers);
|
||||
}
|
||||
@@ -228,16 +262,16 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
/* Setup recorders */
|
||||
List<RecorderType> recorders = channel.getRecordConfiguration().getRecorders();
|
||||
|
||||
if (!recorders.isEmpty())
|
||||
if(!recorders.isEmpty())
|
||||
{
|
||||
/* Add baseband recorder */
|
||||
if ((recorders.contains(RecorderType.BASEBAND) && channel.getChannelType() == ChannelType.STANDARD))
|
||||
/* Add baseband recorder */
|
||||
if((recorders.contains(RecorderType.BASEBAND) && channel.getChannelType() == ChannelType.STANDARD))
|
||||
{
|
||||
processingChain.addModule(mRecorderManager.getBasebandRecorder(channel.toString()));
|
||||
}
|
||||
|
||||
/* Add traffic channel baseband recorder */
|
||||
if (recorders.contains(RecorderType.TRAFFIC_BASEBAND) && channel.getChannelType() == ChannelType.TRAFFIC)
|
||||
if(recorders.contains(RecorderType.TRAFFIC_BASEBAND) && channel.getChannelType() == ChannelType.TRAFFIC)
|
||||
{
|
||||
processingChain.addModule(mRecorderManager.getBasebandRecorder(channel.toString()));
|
||||
}
|
||||
@@ -245,13 +279,13 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
|
||||
processingChain.setSource(source);
|
||||
|
||||
if (event instanceof TrafficChannelEvent)
|
||||
if(event instanceof TrafficChannelEvent)
|
||||
{
|
||||
TrafficChannelEvent trafficChannelEvent = (TrafficChannelEvent) event;
|
||||
|
||||
processingChain.getChannelState().configureAsTrafficChannel(
|
||||
trafficChannelEvent.getTrafficChannelManager(),
|
||||
trafficChannelEvent.getCallEvent());
|
||||
trafficChannelEvent.getTrafficChannelManager(),
|
||||
trafficChannelEvent.getCallEvent());
|
||||
}
|
||||
|
||||
processingChain.start();
|
||||
@@ -261,14 +295,14 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
mProcessingChains.put(channel.getChannelID(), processingChain);
|
||||
|
||||
mChannelModel.broadcast(
|
||||
new ChannelEvent(channel, Event.NOTIFICATION_PROCESSING_START));
|
||||
new ChannelEvent(channel, Event.NOTIFICATION_PROCESSING_START));
|
||||
}
|
||||
|
||||
private void stopProcessing(Channel channel, boolean remove)
|
||||
{
|
||||
channel.setEnabled(false);
|
||||
|
||||
if (mProcessingChains.containsKey(channel.getChannelID()))
|
||||
if(mProcessingChains.containsKey(channel.getChannelID()))
|
||||
{
|
||||
ProcessingChain processingChain = mProcessingChains.get(channel.getChannelID());
|
||||
|
||||
@@ -281,7 +315,7 @@ public class ChannelProcessingManager implements ChannelEventListener
|
||||
|
||||
mChannelModel.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_PROCESSING_STOP));
|
||||
|
||||
if (remove)
|
||||
if(remove)
|
||||
{
|
||||
mProcessingChains.remove(channel.getChannelID());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user