diff --git a/.idea/dictionaries/denny.xml b/.idea/dictionaries/denny.xml
index 408050c7..24e59925 100644
--- a/.idea/dictionaries/denny.xml
+++ b/.idea/dictionaries/denny.xml
@@ -8,6 +8,7 @@
icecast
ident
polyphase
+ remez
samplerate
sdrtrunk
sheirer
diff --git a/src/alias/AliasList.java b/src/alias/AliasList.java
index cc1c4662..10c3e214 100644
--- a/src/alias/AliasList.java
+++ b/src/alias/AliasList.java
@@ -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,6 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
+ *
******************************************************************************/
package alias;
@@ -29,7 +30,6 @@ import alias.id.siteID.SiteID;
import alias.id.status.StatusID;
import alias.id.talkgroup.TalkgroupID;
import alias.id.uniqueID.UniqueID;
-import audio.metadata.MetadataType;
import module.decode.lj1200.LJ1200Message.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,16 +48,16 @@ public class AliasList implements Listener
public static final String WILDCARD = "*";
public static final String REGEX_WILDCARD = ".";
- private Map mESN = new HashMap<>();
- private Map mFleetsync = new HashMap<>();
- private Map mLoJack = new HashMap<>();
- private Map mMDC1200 = new HashMap<>();
- private Map mMobileID = new HashMap<>();
- private Map mMPT1327 = new HashMap<>();
- private Map mSiteID = new HashMap<>();
- private Map mStatus = new HashMap<>();
- private Map mTalkgroup = new HashMap<>();
- private Map mUniqueID = new HashMap<>();
+ private Map mESN = new HashMap<>();
+ private Map mFleetsync = new HashMap<>();
+ private Map mLoJack = new HashMap<>();
+ private Map mMDC1200 = new HashMap<>();
+ private Map mMobileID = new HashMap<>();
+ private Map mMPT1327 = new HashMap<>();
+ private Map mSiteID = new HashMap<>();
+ private Map mStatus = new HashMap<>();
+ private Map mTalkgroup = new HashMap<>();
+ private Map mUniqueID = new HashMap<>();
private List mESNWildcards = new ArrayList<>();
private List mMobileIDWildcards = new ArrayList<>();
@@ -85,9 +85,9 @@ public class AliasList implements Listener
*/
public void addAlias(Alias alias)
{
- if (alias != null)
+ if(alias != null)
{
- for (AliasID aliasID : alias.getId())
+ for(AliasID aliasID : alias.getId())
{
addAliasID(aliasID, alias);
}
@@ -99,18 +99,18 @@ public class AliasList implements Listener
*/
private void addAliasID(AliasID id, Alias alias)
{
- if (id.isValid())
+ if(id.isValid())
{
try
{
- switch (id.getType())
+ switch(id.getType())
{
case ESN:
- String esn = ((Esn)id).getEsn();
+ String esn = ((Esn) id).getEsn();
if(esn != null)
{
- if (esn.contains(WILDCARD))
+ if(esn.contains(WILDCARD))
{
mESNWildcards.add(new WildcardID(esn));
Collections.sort(mESNWildcards);
@@ -120,11 +120,11 @@ public class AliasList implements Listener
}
break;
case FLEETSYNC:
- String fleetsync = ((FleetsyncID)id).getIdent();
+ String fleetsync = ((FleetsyncID) id).getIdent();
if(fleetsync != null)
{
- if (fleetsync.contains(WILDCARD))
+ if(fleetsync.contains(WILDCARD))
{
mFleetsyncWildcards.add(new WildcardID(fleetsync));
Collections.sort(mFleetsyncWildcards);
@@ -137,11 +137,11 @@ public class AliasList implements Listener
mLoJack.put((LoJackFunctionAndID) id, alias);
break;
case MDC1200:
- String mdc = ((MDC1200ID)id).getIdent();
+ String mdc = ((MDC1200ID) id).getIdent();
if(mdc != null)
{
- if (mdc.contains(WILDCARD))
+ if(mdc.contains(WILDCARD))
{
mMDC1200Wildcards.add(new WildcardID(mdc));
Collections.sort(mMDC1200Wildcards);
@@ -151,11 +151,11 @@ public class AliasList implements Listener
}
break;
case MPT1327:
- String mpt = ((MPT1327ID)id).getIdent();
+ String mpt = ((MPT1327ID) id).getIdent();
if(mpt != null)
{
- if (mpt.contains(WILDCARD))
+ if(mpt.contains(WILDCARD))
{
mMPT1327Wildcards.add(new WildcardID(mpt));
Collections.sort(mMPT1327Wildcards);
@@ -165,11 +165,11 @@ public class AliasList implements Listener
}
break;
case MIN:
- String min = ((Min)id).getMin();
+ String min = ((Min) id).getMin();
if(min != null)
{
- if (min.contains(WILDCARD))
+ if(min.contains(WILDCARD))
{
mMobileIDWildcards.add(new WildcardID(min));
Collections.sort(mMobileIDWildcards);
@@ -179,14 +179,14 @@ public class AliasList implements Listener
}
break;
case LTR_NET_UID:
- mUniqueID.put(((UniqueID)id).getUid(), alias);
+ mUniqueID.put(((UniqueID) id).getUid(), alias);
break;
case SITE:
- String siteID = ((SiteID)id).getSite();
+ String siteID = ((SiteID) id).getSite();
if(siteID != null)
{
- if (siteID.contains(WILDCARD))
+ if(siteID.contains(WILDCARD))
{
mSiteWildcards.add(new WildcardID(siteID));
Collections.sort(mSiteWildcards);
@@ -199,11 +199,11 @@ public class AliasList implements Listener
mStatus.put(((StatusID) id).getStatus(), alias);
break;
case TALKGROUP:
- String tgid = ((TalkgroupID)id).getTalkgroup();
+ String tgid = ((TalkgroupID) id).getTalkgroup();
if(tgid != null)
{
- if (tgid.contains(WILDCARD))
+ if(tgid.contains(WILDCARD))
{
mTalkgroupWildcards.add(new WildcardID(tgid));
Collections.sort(mTalkgroupWildcards);
@@ -222,7 +222,7 @@ public class AliasList implements Listener
break;
}
}
- catch (Exception e)
+ catch(Exception e)
{
mLog.error("Couldn't add alias ID " + id + " for alias " + alias);
}
@@ -234,9 +234,9 @@ public class AliasList implements Listener
*/
public void removeAlias(Alias alias)
{
- if (alias != null)
+ if(alias != null)
{
- for (AliasID aliasID : alias.getId())
+ for(AliasID aliasID : alias.getId())
{
removeAliasID(aliasID, alias);
}
@@ -247,7 +247,7 @@ public class AliasList implements Listener
{
if(value != null)
{
- for(WildcardID wildcardID: wildcards)
+ for(WildcardID wildcardID : wildcards)
{
if(wildcardID.value().equals(value))
{
@@ -262,12 +262,12 @@ public class AliasList implements Listener
*/
private void removeAliasID(AliasID id, Alias alias)
{
- if (id.isValid())
+ if(id.isValid())
{
- switch (id.getType())
+ switch(id.getType())
{
case ESN:
- String esn = ((Esn)id).getEsn();
+ String esn = ((Esn) id).getEsn();
if(esn != null)
{
@@ -280,13 +280,13 @@ public class AliasList implements Listener
mESN.remove(esn);
break;
case FLEETSYNC:
- String fleetsync = ((FleetsyncID)id).getIdent();
+ String fleetsync = ((FleetsyncID) id).getIdent();
if(fleetsync != null)
{
if(fleetsync.contains(WILDCARD))
{
- removeWildcard(fleetsync,mFleetsyncWildcards);
+ removeWildcard(fleetsync, mFleetsyncWildcards);
}
mFleetsync.remove(fleetsync);
@@ -296,7 +296,7 @@ public class AliasList implements Listener
mLoJack.remove((LoJackFunctionAndID) id);
break;
case MDC1200:
- String mdc = ((MDC1200ID)id).getIdent();
+ String mdc = ((MDC1200ID) id).getIdent();
if(mdc != null)
{
@@ -309,7 +309,7 @@ public class AliasList implements Listener
}
break;
case MPT1327:
- String mpt = ((MPT1327ID)id).getIdent();
+ String mpt = ((MPT1327ID) id).getIdent();
if(mpt != null)
{
@@ -322,7 +322,7 @@ public class AliasList implements Listener
}
break;
case MIN:
- String min = ((Min)id).getMin();
+ String min = ((Min) id).getMin();
if(min != null)
{
@@ -344,7 +344,7 @@ public class AliasList implements Listener
mStatus.remove(((StatusID) id).getStatus());
break;
case TALKGROUP:
- String tgid = ((TalkgroupID)id).getTalkgroup();
+ String tgid = ((TalkgroupID) id).getTalkgroup();
if(tgid != null)
{
@@ -378,11 +378,11 @@ public class AliasList implements Listener
*/
private String getWildcardMatch(String id, List wildcards)
{
- if (id != null)
+ if(id != null)
{
- for (WildcardID wildcard : wildcards)
+ for(WildcardID wildcard : wildcards)
{
- if (wildcard.matches(id))
+ if(wildcard.matches(id))
{
return wildcard.value();
}
@@ -399,15 +399,15 @@ public class AliasList implements Listener
{
Alias alias = null;
- if (siteID != null)
+ if(siteID != null)
{
alias = mSiteID.get(siteID);
- if (alias == null)
+ if(alias == null)
{
String wildcard = getWildcardMatch(siteID, mSiteWildcards);
- if (wildcard != null)
+ if(wildcard != null)
{
alias = mSiteID.get(wildcard);
}
@@ -440,15 +440,15 @@ public class AliasList implements Listener
{
Alias alias = null;
- if (esn != null)
+ if(esn != null)
{
alias = mESN.get(esn);
- if (alias == null)
+ if(alias == null)
{
String wildcard = getWildcardMatch(esn, mESNWildcards);
- if (wildcard != null)
+ if(wildcard != null)
{
alias = mESN.get(wildcard);
}
@@ -465,15 +465,15 @@ public class AliasList implements Listener
{
Alias alias = null;
- if (ident != null)
+ if(ident != null)
{
alias = mFleetsync.get(ident);
- if (alias == null)
+ if(alias == null)
{
String wildcard = getWildcardMatch(ident, mFleetsyncWildcards);
- if (wildcard != null)
+ if(wildcard != null)
{
alias = mFleetsync.get(wildcard);
}
@@ -488,11 +488,11 @@ public class AliasList implements Listener
*/
public Alias getLoJackAlias(Function function, String id)
{
- if (id != null)
+ if(id != null)
{
- for (LoJackFunctionAndID lojack : mLoJack.keySet())
+ for(LoJackFunctionAndID lojack : mLoJack.keySet())
{
- if (lojack.matches(function, id))
+ if(lojack.matches(function, id))
{
return mLoJack.get(lojack);
}
@@ -509,15 +509,15 @@ public class AliasList implements Listener
{
Alias alias = null;
- if (ident != null)
+ if(ident != null)
{
alias = mMDC1200.get(ident);
- if (alias == null)
+ if(alias == null)
{
String wildcard = getWildcardMatch(ident, mMDC1200Wildcards);
- if (wildcard != null)
+ if(wildcard != null)
{
alias = mMDC1200.get(wildcard);
}
@@ -534,15 +534,15 @@ public class AliasList implements Listener
{
Alias alias = null;
- if (ident != null)
+ if(ident != null)
{
alias = mMPT1327.get(ident);
- if (alias == null)
+ if(alias == null)
{
String wildcard = getWildcardMatch(ident, mMPT1327Wildcards);
- if (wildcard != null)
+ if(wildcard != null)
{
alias = mMPT1327.get(wildcard);
}
@@ -559,15 +559,15 @@ public class AliasList implements Listener
{
Alias alias = null;
- if (ident != null)
+ if(ident != null)
{
alias = mMobileID.get(ident);
- if (alias == null)
+ if(alias == null)
{
String wildcard = getWildcardMatch(ident, mMobileIDWildcards);
- if (wildcard != null)
+ if(wildcard != null)
{
alias = mMobileID.get(wildcard);
}
@@ -584,15 +584,15 @@ public class AliasList implements Listener
{
Alias alias = null;
- if (tgid != null)
+ if(tgid != null)
{
alias = mTalkgroup.get(tgid);
- if (alias == null)
+ if(alias == null)
{
String wildcard = getWildcardMatch(tgid, mTalkgroupWildcards);
- if (wildcard != null)
+ if(wildcard != null)
{
alias = mTalkgroup.get(wildcard);
}
@@ -619,61 +619,6 @@ public class AliasList implements Listener
return mName;
}
- /**
- * Lookup an alias by metadata type and string value
- */
- public Alias getAlias(String value, MetadataType type)
- {
- switch (type)
- {
- case ESN:
- return getESNAlias(value);
- case FLEETSYNC:
- return getFleetsyncAlias(value);
- case MDC1200:
- return getMDC1200Alias(value);
- case MOBILE_ID:
- return getMobileIDNumberAlias(value);
- case MPT1327:
- return getMPT1327Alias(value);
- case SITE_ID:
- return getSiteID(value);
- case STATUS:
- if (value != null)
- {
- try
- {
- return getStatus(Integer.valueOf(value));
- }
- catch (Exception e)
- {
- //do nothing, we couldn't parse the int value
- }
- }
- break;
- case FROM:
- case TO:
- return getTalkgroupAlias(value);
- case UNIQUE_ID:
- if (value != null)
- {
- try
- {
- return getUniqueID(Integer.valueOf(value));
- }
- catch (Exception e)
- {
- //do nothing, we couldn't parse the int value
- }
- }
- break;
- default:
- break;
- }
-
- return null;
- }
-
/**
* Receive alias change event notifications and modify this list accordingly
*/
@@ -682,22 +627,22 @@ public class AliasList implements Listener
{
Alias alias = event.getAlias();
- switch (event.getEvent())
+ switch(event.getEvent())
{
case ADD:
- if (alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
+ if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
{
addAlias(alias);
}
break;
case CHANGE:
- if (alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
+ if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
{
addAlias(alias);
}
break;
case DELETE:
- if (alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
+ if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
{
removeAlias(alias);
}
diff --git a/src/audio/AudioChannelPanel.java b/src/audio/AudioChannelPanel.java
index 72f4a091..5532fdb7 100644
--- a/src/audio/AudioChannelPanel.java
+++ b/src/audio/AudioChannelPanel.java
@@ -19,10 +19,8 @@
package audio;
import alias.Alias;
-import audio.metadata.AudioMetadata;
-import audio.metadata.Metadata;
-import audio.metadata.MetadataType;
import audio.output.AudioOutput;
+import channel.metadata.Metadata;
import icon.IconManager;
import net.miginfocom.swing.MigLayout;
import sample.Listener;
@@ -50,12 +48,12 @@ public class AudioChannelPanel extends JPanel
private JLabel mChannelName = new JLabel(" ");
private JLabel mToLabel = new JLabel("TO:");
- private JLabel mTo = new JLabel("");
+ private JLabel mTo = new JLabel("-----");
private JLabel mToAlias = new JLabel("");
private JLabel mMutedLabel = new JLabel(" ");
private JLabel mFromLabel = new JLabel("FROM:");
- private JLabel mFrom = new JLabel("");
+ private JLabel mFrom = new JLabel("-----");
private JLabel mFromAlias = new JLabel("");
private boolean mConfigured = false;
@@ -71,7 +69,7 @@ public class AudioChannelPanel extends JPanel
if(mAudioOutput != null)
{
mAudioOutput.addAudioEventListener(this);
- mAudioOutput.setAudioMetadataListener(new AudioMetadataProcessor());
+ mAudioOutput.setMetadataListener(new AudioMetadataProcessor());
}
mLabelColor = mSettingsManager.getColorSetting(
@@ -173,11 +171,8 @@ public class AudioChannelPanel extends JPanel
*/
private void resetLabels()
{
- mFrom.setText("");
- updateAlias(mFromAlias, null);
-
- mTo.setText("");
- updateAlias(mToAlias, null);
+ updateLabel(mFromLabel, null, mFromAlias, null);
+ updateLabel(mToLabel, null, mToAlias, null);
mConfigured = false;
}
@@ -187,27 +182,25 @@ public class AudioChannelPanel extends JPanel
* does not occur on the Swing event thread -- wrap any calls to this
* method with an event thread call.
*/
- private void updateAlias(JLabel label, Alias alias)
+ private void updateLabel(JLabel valueLabel, String value, JLabel aliasLabel, Alias alias)
{
- if(alias != null)
+ if(value != null)
{
- label.setText(alias.getName());
+ valueLabel.setText(value);
- String icon = alias.getIconName();
-
- if(icon != null)
+ if(alias != null)
{
- label.setIcon(mIconManager.getIcon(icon, IconManager.DEFAULT_ICON_SIZE));
+ aliasLabel.setIcon(mIconManager.getIcon(alias.getIconName(), IconManager.DEFAULT_ICON_SIZE));
}
else
{
- label.setIcon(null);
+ aliasLabel.setIcon(null);
}
}
else
{
- label.setText("");
- label.setIcon(null);
+ valueLabel.setText("-----");
+ aliasLabel.setIcon(null);
}
}
@@ -215,45 +208,28 @@ public class AudioChannelPanel extends JPanel
/**
* Processes audio metadata to update this panel's display values
*/
- public class AudioMetadataProcessor implements Listener
+ public class AudioMetadataProcessor implements Listener
{
@Override
- public void receive(AudioMetadata audioMetadata)
+ public void receive(final Metadata metadata)
{
- if(!mConfigured || audioMetadata.isUpdated())
+ if(metadata.isUpdated() || !mConfigured)
{
- final Metadata from = audioMetadata.getMetadata(MetadataType.FROM);
-
- final Metadata to = audioMetadata.getMetadata(MetadataType.TO);
-
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
- if(from != null)
- {
- mFrom.setText(from.getValue());
- updateAlias(mFromAlias, from.getAlias());
- }
- else
- {
- mFrom.setText("-----");
- }
+ updateLabel(mFromLabel, metadata.getPrimaryAddressFrom().getIdentifier(),
+ mFromAlias, metadata.getPrimaryAddressFrom().getAlias());
- if(to != null)
- {
- mTo.setText(to.getValue());
- updateAlias(mToAlias, to.getAlias());
- }
- else
- {
- mTo.setText("-----");
- }
+ updateLabel(mToLabel, metadata.getPrimaryAddressTo().getIdentifier(),
+ mToAlias, metadata.getPrimaryAddressTo().getAlias());
+
+ mConfigured = true;
}
});
- mConfigured = true;
}
}
}
diff --git a/src/audio/AudioManager.java b/src/audio/AudioManager.java
index fbc7e7b1..6be25898 100644
--- a/src/audio/AudioManager.java
+++ b/src/audio/AudioManager.java
@@ -1,22 +1,40 @@
/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2014-2016 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
+ * 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
+ *
******************************************************************************/
package audio;
+import audio.AudioEvent.Type;
+import audio.output.AudioOutput;
+import audio.output.MonoAudioOutput;
+import audio.output.StereoAudioOutput;
+import controller.ThreadPoolManager;
+import controller.ThreadPoolManager.ThreadType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import properties.SystemProperties;
+import sample.Broadcaster;
+import sample.Listener;
+import source.mixer.MixerChannel;
+import source.mixer.MixerChannelConfiguration;
+import source.mixer.MixerManager;
+
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Mixer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -27,523 +45,495 @@ import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.Mixer;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import properties.SystemProperties;
-import sample.Broadcaster;
-import sample.Listener;
-import source.mixer.MixerChannel;
-import source.mixer.MixerChannelConfiguration;
-import source.mixer.MixerManager;
-import audio.AudioEvent.Type;
-import audio.output.AudioOutput;
-import audio.output.MonoAudioOutput;
-import audio.output.StereoAudioOutput;
-import controller.ThreadPoolManager;
-import controller.ThreadPoolManager.ThreadType;
-
public class AudioManager implements Listener, IAudioController
{
- private static final Logger mLog = LoggerFactory.getLogger( AudioManager.class );
+ private static final Logger mLog = LoggerFactory.getLogger(AudioManager.class);
- public static final int AUDIO_TIMEOUT = 1000; //1 second
-
- public static final String AUDIO_CHANNELS_PROPERTY = "audio.manager.channels";
- public static final String AUDIO_MIXER_PROPERTY = "audio.manager.mixer";
-
- public static final AudioEvent CONFIGURATION_CHANGE_STARTED =
- new AudioEvent( Type.AUDIO_CONFIGURATION_CHANGE_STARTED, null );
-
- public static final AudioEvent CONFIGURATION_CHANGE_COMPLETE =
- new AudioEvent( Type.AUDIO_CONFIGURATION_CHANGE_COMPLETE, null );
+ public static final int AUDIO_TIMEOUT = 1000; //1 second
- private LinkedTransferQueue mAudioPacketQueue = new LinkedTransferQueue<>();
- private Map mChannelConnectionMap = new HashMap<>();
- private List mAudioOutputConnections = new ArrayList<>();
- private AudioOutputConnection mLowestPriorityConnection;
- private int mAvailableConnectionCount;
+ public static final String AUDIO_CHANNELS_PROPERTY = "audio.manager.channels";
+ public static final String AUDIO_MIXER_PROPERTY = "audio.manager.mixer";
- private Map mAudioOutputMap = new HashMap<>();
-
- private Broadcaster mControllerBroadcaster = new Broadcaster<>();
-
- private ThreadPoolManager mThreadPoolManager;
- private ScheduledFuture> mProcessingTask;
- private MixerManager mMixerManager;
- private MixerChannelConfiguration mMixerChannelConfiguration;
-
+ public static final AudioEvent CONFIGURATION_CHANGE_STARTED =
+ new AudioEvent(Type.AUDIO_CONFIGURATION_CHANGE_STARTED, null);
- /**
- * Processes all audio produced by the decoding channels and routes audio
- * packets to any combination of outputs based on any alias audio routing
- * options specified by the user.
- */
- public AudioManager( ThreadPoolManager manager, MixerManager mixerManager )
- {
- mThreadPoolManager = manager;
- mMixerManager = mixerManager;
+ public static final AudioEvent CONFIGURATION_CHANGE_COMPLETE =
+ new AudioEvent(Type.AUDIO_CONFIGURATION_CHANGE_COMPLETE, null);
- loadSettings();
- }
-
- private void loadSettings()
- {
- MixerChannelConfiguration configuration = null;
-
- SystemProperties properties = SystemProperties.getInstance();
-
- Mixer defaultMixer = AudioSystem.getMixer( null );
+ private LinkedTransferQueue mAudioPacketQueue = new LinkedTransferQueue<>();
+ private Map mChannelConnectionMap = new HashMap<>();
+ private List mAudioOutputConnections = new ArrayList<>();
+ private AudioOutputConnection mLowestPriorityConnection;
+ private int mAvailableConnectionCount;
- String mixer = properties.get( AUDIO_MIXER_PROPERTY, defaultMixer.getMixerInfo().getName() );
-
- String channels = properties.get( AUDIO_CHANNELS_PROPERTY, MixerChannel.MONO.name() );
-
- MixerChannelConfiguration[] mixerConfigurations = mMixerManager.getOutputMixers();
+ private Map mAudioOutputMap = new HashMap<>();
- for( MixerChannelConfiguration mixerConfig: mixerConfigurations )
- {
- if( mixerConfig.matches( mixer, channels ) )
- {
- configuration = mixerConfig;
- }
- }
-
- if( configuration == null )
- {
- configuration = getDefaultConfiguration();
- }
+ private Broadcaster mControllerBroadcaster = new Broadcaster<>();
- try
- {
- setMixerChannelConfiguration( configuration );
- }
- catch( Exception e )
- {
- mLog.error( "Couldn't set stored audio mixer/channel configuration"
- + " - using default", e );
-
- try
- {
- setMixerChannelConfiguration( getDefaultConfiguration() );
- }
- catch( Exception e2 )
- {
- mLog.error( "Couldn't set default audio mixer/channel "
- + "configuration - no audio will be available", e2 );
- }
- }
- }
-
- private MixerChannelConfiguration getDefaultConfiguration()
- {
- /* Use the system default mixer and mono channel as default startup */
- Mixer defaultMixer = AudioSystem.getMixer( null );
-
- return new MixerChannelConfiguration( defaultMixer, MixerChannel.MONO );
- }
-
- public void dispose()
- {
- if( mThreadPoolManager != null && mProcessingTask != null )
- {
- mThreadPoolManager.cancel( mProcessingTask );
- }
-
- mAudioPacketQueue.clear();
-
- mThreadPoolManager = null;
- mProcessingTask = null;
+ private ThreadPoolManager mThreadPoolManager;
+ private ScheduledFuture> mProcessingTask;
+ private MixerManager mMixerManager;
+ private MixerChannelConfiguration mMixerChannelConfiguration;
- mChannelConnectionMap.clear();
-
- for( AudioOutputConnection connection: mAudioOutputConnections )
- {
- connection.dispose();
- }
-
- mAudioOutputConnections.clear();
- }
- @Override
- public synchronized void receive( AudioPacket packet )
- {
- mAudioPacketQueue.add( packet );
- }
-
- /**
- * Checks each audio channel assignment and disconnects any inactive connections
- */
- private void disconnectInactiveChannelAssignments()
- {
- boolean changed = false;
-
- for( AudioOutputConnection connection: mAudioOutputConnections )
- {
- if( connection.isInactive() &&
- mChannelConnectionMap.containsKey( connection.getSource() ) )
- {
- mChannelConnectionMap.remove( connection.getSource() );
- connection.disconnect();
- changed = true;
- }
- }
-
- if( changed )
- {
- updateLowestPriorityAssignment();
- }
- }
+ /**
+ * Processes all audio produced by the decoding channels and routes audio
+ * packets to any combination of outputs based on any alias audio routing
+ * options specified by the user.
+ */
+ public AudioManager(ThreadPoolManager manager, MixerManager mixerManager)
+ {
+ mThreadPoolManager = manager;
+ mMixerManager = mixerManager;
- /**
- * Identifies the lowest priority channel connection
- */
- private void updateLowestPriorityAssignment()
- {
- mLowestPriorityConnection = null;
-
- for( AudioOutputConnection connection: mAudioOutputConnections )
- {
- if( connection.isConnected() &&
- ( mLowestPriorityConnection == null ||
- mLowestPriorityConnection.getPriority() > connection.getPriority() ) )
- {
- mLowestPriorityConnection = connection;
- }
- }
- }
-
- @Override
- public void setMixerChannelConfiguration( MixerChannelConfiguration entry ) throws AudioException
- {
- if( entry != null &&
- ( entry.getMixerChannel() == MixerChannel.MONO ||
- entry.getMixerChannel() == MixerChannel.STEREO ) )
- {
- mControllerBroadcaster.broadcast( CONFIGURATION_CHANGE_STARTED );
-
- if( mThreadPoolManager != null && mProcessingTask != null )
- {
- mThreadPoolManager.cancel( mProcessingTask );
- }
-
- disposeCurrentConfiguration();
-
- switch( entry.getMixerChannel() )
- {
- case MONO:
- AudioOutput mono = new MonoAudioOutput( mThreadPoolManager,
- entry.getMixer() );
- mAudioOutputConnections.add( new AudioOutputConnection( mono ) );
- mAvailableConnectionCount++;
- mAudioOutputMap.put( mono.getChannelName(), mono );
- break;
- case STEREO:
- AudioOutput left = new StereoAudioOutput( mThreadPoolManager,
- entry.getMixer(), MixerChannel.LEFT );
- mAudioOutputConnections.add( new AudioOutputConnection( left ) );
- mAvailableConnectionCount++;
- mAudioOutputMap.put( left.getChannelName(), left );
-
- AudioOutput right = new StereoAudioOutput( mThreadPoolManager,
- entry.getMixer(), MixerChannel.RIGHT );
- mAudioOutputConnections.add( new AudioOutputConnection( right ) );
- mAvailableConnectionCount++;
- mAudioOutputMap.put( right.getChannelName(), right );
- break;
- default:
- throw new AudioException( "Unsupported mixer channel "
- + "configuration: " + entry.getMixerChannel() );
- }
+ loadSettings();
+ }
- mProcessingTask = mThreadPoolManager.scheduleFixedRate(
- ThreadType.AUDIO_PROCESSING, new AudioPacketProcessor(), 15,
- TimeUnit.MILLISECONDS );
+ private void loadSettings()
+ {
+ MixerChannelConfiguration configuration = null;
- mControllerBroadcaster.broadcast( CONFIGURATION_CHANGE_COMPLETE );
-
- SystemProperties properties = SystemProperties.getInstance();
-
- properties.set( AUDIO_MIXER_PROPERTY, entry.getMixer().getMixerInfo().getName() );
- properties.set( AUDIO_CHANNELS_PROPERTY, entry.getMixerChannel().name() );
- properties.save();
- }
- }
+ SystemProperties properties = SystemProperties.getInstance();
- /**
- * Clears all channel assignments and terminates all audio outputs in
- * preparation for complete shutdown or change to another mixer/channel
- * configuration
- */
- private void disposeCurrentConfiguration()
- {
- mChannelConnectionMap.clear();
+ Mixer defaultMixer = AudioSystem.getMixer(null);
- for( AudioOutputConnection connection : mAudioOutputConnections )
- {
- connection.dispose();
- }
-
- mAvailableConnectionCount = 0;
+ String mixer = properties.get(AUDIO_MIXER_PROPERTY, defaultMixer.getMixerInfo().getName());
- mAudioOutputConnections.clear();
-
- mAudioOutputMap.clear();
-
- mLowestPriorityConnection = null;
- }
+ String channels = properties.get(AUDIO_CHANNELS_PROPERTY, MixerChannel.MONO.name());
- @Override
- public MixerChannelConfiguration getMixerChannelConfiguration() throws AudioException
- {
- return mMixerChannelConfiguration;
- }
+ MixerChannelConfiguration[] mixerConfigurations = mMixerManager.getOutputMixers();
- @Override
- public List getAudioOutputs()
- {
- List outputs = new ArrayList<>( mAudioOutputMap.values() );
+ for(MixerChannelConfiguration mixerConfig : mixerConfigurations)
+ {
+ if(mixerConfig.matches(mixer, channels))
+ {
+ configuration = mixerConfig;
+ }
+ }
- Collections.sort( outputs, new Comparator()
- {
- @Override
- public int compare( AudioOutput first, AudioOutput second )
- {
- return first.getChannelName().compareTo( second.getChannelName() );
- }
- } );
-
- return outputs;
- }
+ if(configuration == null)
+ {
+ configuration = getDefaultConfiguration();
+ }
- @Override
- public void addControllerListener( Listener listener )
- {
- mControllerBroadcaster.addListener( listener );
- }
+ try
+ {
+ setMixerChannelConfiguration(configuration);
+ }
+ catch(Exception e)
+ {
+ mLog.error("Couldn't set stored audio mixer/channel configuration"
+ + " - using default", e);
- @Override
- public void removeControllerListener( Listener listener )
- {
- mControllerBroadcaster.removeListener( listener );
- }
-
- /**
- * Returns an audio output connection for the packet if one is
- * available, or overrides an existing lower priority connection.
- * Returns null if no connection is available for the audio packet.
- *
- * @param packet from a source
- * @return an audio output connection or null
- */
- private AudioOutputConnection getConnection( AudioPacket packet )
- {
- int source = packet.getAudioMetadata().getSource();
-
- //Use an existing connection
- if( mChannelConnectionMap.containsKey( source ) )
- {
- return mChannelConnectionMap.get( source );
- }
+ try
+ {
+ setMixerChannelConfiguration(getDefaultConfiguration());
+ }
+ catch(Exception e2)
+ {
+ mLog.error("Couldn't set default audio mixer/channel "
+ + "configuration - no audio will be available", e2);
+ }
+ }
+ }
- //Connect to and use an available connection
- if( mAvailableConnectionCount > 0 )
- {
- for( AudioOutputConnection connection: mAudioOutputConnections )
- {
- if( connection.isDisconnected() )
- {
- connection.connect( source );
- mChannelConnectionMap.put( source, connection );
- return connection;
- }
- }
- }
- //Preempt an existing connection and connect it to this higher priority source
- else //Check for a channel priority override
- {
- int priority = packet.getAudioMetadata().getPriority();
+ private MixerChannelConfiguration getDefaultConfiguration()
+ {
+ /* Use the system default mixer and mono channel as default startup */
+ Mixer defaultMixer = AudioSystem.getMixer(null);
- if( mLowestPriorityConnection != null &&
- priority < mLowestPriorityConnection.getPriority() )
- {
- AudioOutputConnection connection = mLowestPriorityConnection;
+ return new MixerChannelConfiguration(defaultMixer, MixerChannel.MONO);
+ }
- mChannelConnectionMap.remove( connection.getSource() );
-
- connection.connect( source );
-
- mChannelConnectionMap.put( source, connection );
-
- updateLowestPriorityAssignment();
-
- return connection;
- }
- }
-
- return null;
- }
-
- public class AudioPacketProcessor implements Runnable
- {
- @Override
- public void run()
- {
- try
- {
- disconnectInactiveChannelAssignments();
-
- if( mAudioPacketQueue != null )
- {
- List packets = new ArrayList();
+ public void dispose()
+ {
+ if(mThreadPoolManager != null && mProcessingTask != null)
+ {
+ mThreadPoolManager.cancel(mProcessingTask);
+ }
- mAudioPacketQueue.drainTo( packets );
-
- for( AudioPacket packet: packets )
- {
+ mAudioPacketQueue.clear();
+
+ mThreadPoolManager = null;
+ mProcessingTask = null;
+
+ mChannelConnectionMap.clear();
+
+ for(AudioOutputConnection connection : mAudioOutputConnections)
+ {
+ connection.dispose();
+ }
+
+ mAudioOutputConnections.clear();
+ }
+
+ @Override
+ public synchronized void receive(AudioPacket packet)
+ {
+ mAudioPacketQueue.add(packet);
+ }
+
+ /**
+ * Checks each audio channel assignment and disconnects any inactive connections
+ */
+ private void disconnectInactiveChannelAssignments()
+ {
+ boolean changed = false;
+
+ for(AudioOutputConnection connection : mAudioOutputConnections)
+ {
+ if(connection.isInactive() &&
+ mChannelConnectionMap.containsKey(connection.getChannelMetadataID()))
+ {
+ mChannelConnectionMap.remove(connection.getChannelMetadataID());
+ connection.disconnect();
+ changed = true;
+ }
+ }
+
+ if(changed)
+ {
+ updateLowestPriorityAssignment();
+ }
+ }
+
+ /**
+ * Identifies the lowest priority channel connection
+ */
+ private void updateLowestPriorityAssignment()
+ {
+ mLowestPriorityConnection = null;
+
+ for(AudioOutputConnection connection : mAudioOutputConnections)
+ {
+ if(connection.isConnected() &&
+ (mLowestPriorityConnection == null || mLowestPriorityConnection.getPriority() > connection.getPriority()))
+ {
+ mLowestPriorityConnection = connection;
+ }
+ }
+ }
+
+ @Override
+ public void setMixerChannelConfiguration(MixerChannelConfiguration entry) throws AudioException
+ {
+ if(entry != null &&
+ (entry.getMixerChannel() == MixerChannel.MONO || entry.getMixerChannel() == MixerChannel.STEREO))
+ {
+ mControllerBroadcaster.broadcast(CONFIGURATION_CHANGE_STARTED);
+
+ if(mThreadPoolManager != null && mProcessingTask != null)
+ {
+ mThreadPoolManager.cancel(mProcessingTask);
+ }
+
+ disposeCurrentConfiguration();
+
+ switch(entry.getMixerChannel())
+ {
+ case MONO:
+ AudioOutput mono = new MonoAudioOutput(mThreadPoolManager,
+ entry.getMixer());
+ mAudioOutputConnections.add(new AudioOutputConnection(mono));
+ mAvailableConnectionCount++;
+ mAudioOutputMap.put(mono.getChannelName(), mono);
+ break;
+ case STEREO:
+ AudioOutput left = new StereoAudioOutput(mThreadPoolManager, entry.getMixer(), MixerChannel.LEFT);
+ mAudioOutputConnections.add(new AudioOutputConnection(left));
+ mAvailableConnectionCount++;
+ mAudioOutputMap.put(left.getChannelName(), left);
+
+ AudioOutput right = new StereoAudioOutput(mThreadPoolManager, entry.getMixer(), MixerChannel.RIGHT);
+ mAudioOutputConnections.add(new AudioOutputConnection(right));
+ mAvailableConnectionCount++;
+ mAudioOutputMap.put(right.getChannelName(), right);
+ break;
+ default:
+ throw new AudioException("Unsupported mixer channel "
+ + "configuration: " + entry.getMixerChannel());
+ }
+
+ mProcessingTask = mThreadPoolManager.scheduleFixedRate(
+ ThreadType.AUDIO_PROCESSING, new AudioPacketProcessor(), 15,
+ TimeUnit.MILLISECONDS);
+
+ mControllerBroadcaster.broadcast(CONFIGURATION_CHANGE_COMPLETE);
+
+ SystemProperties properties = SystemProperties.getInstance();
+
+ properties.set(AUDIO_MIXER_PROPERTY, entry.getMixer().getMixerInfo().getName());
+ properties.set(AUDIO_CHANNELS_PROPERTY, entry.getMixerChannel().name());
+ properties.save();
+ }
+ }
+
+ /**
+ * Clears all channel assignments and terminates all audio outputs in
+ * preparation for complete shutdown or change to another mixer/channel
+ * configuration
+ */
+ private void disposeCurrentConfiguration()
+ {
+ mChannelConnectionMap.clear();
+
+ for(AudioOutputConnection connection : mAudioOutputConnections)
+ {
+ connection.dispose();
+ }
+
+ mAvailableConnectionCount = 0;
+
+ mAudioOutputConnections.clear();
+
+ mAudioOutputMap.clear();
+
+ mLowestPriorityConnection = null;
+ }
+
+ @Override
+ public MixerChannelConfiguration getMixerChannelConfiguration() throws AudioException
+ {
+ return mMixerChannelConfiguration;
+ }
+
+ @Override
+ public List getAudioOutputs()
+ {
+ List outputs = new ArrayList<>(mAudioOutputMap.values());
+
+ Collections.sort(outputs, new Comparator()
+ {
+ @Override
+ public int compare(AudioOutput first, AudioOutput second)
+ {
+ return first.getChannelName().compareTo(second.getChannelName());
+ }
+ });
+
+ return outputs;
+ }
+
+ @Override
+ public void addControllerListener(Listener listener)
+ {
+ mControllerBroadcaster.addListener(listener);
+ }
+
+ @Override
+ public void removeControllerListener(Listener listener)
+ {
+ mControllerBroadcaster.removeListener(listener);
+ }
+
+ /**
+ * Returns an audio output connection for the packet if one is
+ * available, or overrides an existing lower priority connection.
+ * Returns null if no connection is available for the audio packet.
+ *
+ * @param packet from a source
+ * @return an audio output connection or null
+ */
+ private AudioOutputConnection getConnection(AudioPacket packet)
+ {
+ int channelMetadataID = packet.getMetadata().getMetadataID();
+
+ //Use an existing connection
+ if(mChannelConnectionMap.containsKey(channelMetadataID))
+ {
+ return mChannelConnectionMap.get(channelMetadataID);
+ }
+
+ //Connect to and use an available connection
+ if(mAvailableConnectionCount > 0)
+ {
+ for(AudioOutputConnection connection : mAudioOutputConnections)
+ {
+ if(connection.isDisconnected())
+ {
+ connection.connect(channelMetadataID);
+ mChannelConnectionMap.put(channelMetadataID, connection);
+ return connection;
+ }
+ }
+ }
+ //Preempt an existing connection and connect it to this higher priority source
+ else //Check for a channel priority override
+ {
+ int priority = packet.getMetadata().getAudioPriority();
+
+ if(mLowestPriorityConnection != null &&
+ priority < mLowestPriorityConnection.getPriority())
+ {
+ AudioOutputConnection connection = mLowestPriorityConnection;
+
+ mChannelConnectionMap.remove(connection.getChannelMetadataID());
+
+ connection.connect(channelMetadataID);
+
+ mChannelConnectionMap.put(channelMetadataID, connection);
+
+ updateLowestPriorityAssignment();
+
+ return connection;
+ }
+ }
+
+ return null;
+ }
+
+ public class AudioPacketProcessor implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ disconnectInactiveChannelAssignments();
+
+ if(mAudioPacketQueue != null)
+ {
+ List packets = new ArrayList();
+
+ mAudioPacketQueue.drainTo(packets);
+
+ for(AudioPacket packet : packets)
+ {
/* Don't process any packet's marked as do not monitor */
- if( !packet.getAudioMetadata().isDoNotMonitor() &&
- packet.getType() == AudioPacket.Type.AUDIO )
- {
- AudioOutputConnection connection = getConnection( packet );
+ if(!packet.getMetadata().isDoNotMonitor() && packet.getType() == AudioPacket.Type.AUDIO)
+ {
+ AudioOutputConnection connection = getConnection(packet);
- if( connection != null )
- {
- connection.receive( packet );
- }
- }
- }
- }
- }
- catch( Exception e )
- {
- mLog.error( "Encountered error while processing audio packets", e );
- }
- }
- }
-
- /**
- * Audio output connection manages a connection between a source and an audio
- * output and maintains current state information about the audio activity
- * received form the source.
- */
- public class AudioOutputConnection
- {
- private static final int DISCONNECTED = -1;
-
- private AudioOutput mAudioOutput;
- private int mPriority = 0;
- private int mSource = DISCONNECTED;
-
- public AudioOutputConnection( AudioOutput audioOutput )
- {
- mAudioOutput = audioOutput;
- }
-
- public void receive( AudioPacket packet )
- {
- if( packet.hasAudioMetadata() &&
- packet.getAudioMetadata().getSource() == mSource )
- {
- int priority = packet.getAudioMetadata().getPriority();
+ if(connection != null)
+ {
+ connection.receive(packet);
+ }
+ }
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ mLog.error("Encountered error while processing audio packets", e);
+ }
+ }
+ }
- if( mPriority != priority )
- {
- mPriority = priority;
- updateLowestPriorityAssignment();
- }
-
- if( mAudioOutput != null )
- {
- mAudioOutput.receive( packet );
- }
- }
- else
- {
- if( packet.hasAudioMetadata() )
- {
- mLog.error( "Received audio packet from channel source [" +
- packet.getAudioMetadata().getSource() +
- "] however this assignment is currently connected "
- + "to channel source [" + mSource + "]" );
- }
- else
- {
- mLog.error( "Received audio packet with no metadata - "
- + "cannot route audio packet" );
- }
- }
- }
-
- /**
- * Terminates the audio output and prepares this connection for disposal
- */
- public void dispose()
- {
- mAudioOutput.dispose();
- mAudioOutput = null;
- }
+ /**
+ * Audio output connection manages a connection between a source and an audio
+ * output and maintains current state information about the audio activity
+ * received form the source.
+ */
+ public class AudioOutputConnection
+ {
+ private static final int DISCONNECTED = -1;
- /**
- * Indicates if this assignment is currently disconnected from a channel source
- */
- public boolean isDisconnected()
- {
- return mSource == DISCONNECTED;
- }
-
- /**
- * Indicates if this assignment is currently connected to a channel source
- */
- public boolean isConnected()
- {
- return !isDisconnected();
- }
+ private AudioOutput mAudioOutput;
+ private int mPriority = 0;
+ private int mChannelMetadataID = DISCONNECTED;
- /**
- * Connects this assignment to the indicated source so that audio
- * packets from this source can be sent to the audio output
- */
- public void connect( int source )
- {
- mSource = source;
-
- mAudioOutput.updateTimestamp();
- }
+ public AudioOutputConnection(AudioOutput audioOutput)
+ {
+ mAudioOutput = audioOutput;
+ }
- /**
- * Currently connected source or -1 if disconnected
- */
- public int getSource()
- {
- return mSource;
- }
+ public void receive(AudioPacket packet)
+ {
+ if(packet.hasMetadata() && packet.getMetadata().getMetadataID() == mChannelMetadataID)
+ {
+ int priority = packet.getMetadata().getAudioPriority();
- /**
- * Disconnects this assignment from the source and prevents any audio
- * from being routed to the audio output until another source is assigned
- */
- public void disconnect()
- {
- mSource = DISCONNECTED;
- mPriority = 0;
- }
+ if(mPriority != priority)
+ {
+ mPriority = priority;
+ updateLowestPriorityAssignment();
+ }
- /**
- * Indicates if audio output is current inactive, meaning that the
- * audio output hasn't recently processed any audio packets.
- */
- public boolean isInactive()
- {
- return ( mAudioOutput.getLastActivityTimestamp() + AUDIO_TIMEOUT ) < System.currentTimeMillis();
- }
-
- public int getPriority()
- {
- return mPriority;
- }
- }
+ if(mAudioOutput != null)
+ {
+ mAudioOutput.receive(packet);
+ }
+ }
+ else
+ {
+ if(packet.hasMetadata())
+ {
+ mLog.error("Received audio packet from channel metadata [" + packet.getMetadata().getMetadataID() +
+ "] however this assignment is currently connected to metadata [" + mChannelMetadataID + "]");
+ }
+ else
+ {
+ mLog.error("Received audio packet with no metadata - cannot route audio packet");
+ }
+ }
+ }
+
+ /**
+ * Terminates the audio output and prepares this connection for disposal
+ */
+ public void dispose()
+ {
+ mAudioOutput.dispose();
+ mAudioOutput = null;
+ }
+
+ /**
+ * Indicates if this assignment is currently disconnected from a channel source
+ */
+ public boolean isDisconnected()
+ {
+ return mChannelMetadataID == DISCONNECTED;
+ }
+
+ /**
+ * Indicates if this assignment is currently connected to a channel source
+ */
+ public boolean isConnected()
+ {
+ return !isDisconnected();
+ }
+
+ /**
+ * Connects this assignment to the indicated source so that audio
+ * packets from this source can be sent to the audio output
+ */
+ public void connect(int source)
+ {
+ mChannelMetadataID = source;
+
+ mAudioOutput.updateTimestamp();
+ }
+
+ /**
+ * Currently connected source or -1 if disconnected
+ */
+ public int getChannelMetadataID()
+ {
+ return mChannelMetadataID;
+ }
+
+ /**
+ * Disconnects this assignment from the source and prevents any audio
+ * from being routed to the audio output until another source is assigned
+ */
+ public void disconnect()
+ {
+ mChannelMetadataID = DISCONNECTED;
+ mPriority = 0;
+ }
+
+ /**
+ * Indicates if audio output is current inactive, meaning that the
+ * audio output hasn't recently processed any audio packets.
+ */
+ public boolean isInactive()
+ {
+ return (mAudioOutput.getLastActivityTimestamp() + AUDIO_TIMEOUT) < System.currentTimeMillis();
+ }
+
+ public int getPriority()
+ {
+ return mPriority;
+ }
+ }
}
diff --git a/src/audio/AudioModule.java b/src/audio/AudioModule.java
index 4a02298f..58b0be0f 100644
--- a/src/audio/AudioModule.java
+++ b/src/audio/AudioModule.java
@@ -1,29 +1,38 @@
+/*******************************************************************************
+ * 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
+ *
+ ******************************************************************************/
package audio;
-import java.util.Arrays;
-import java.util.concurrent.ScheduledExecutorService;
-
+import audio.squelch.ISquelchStateListener;
+import audio.squelch.SquelchState;
+import channel.metadata.Metadata;
import dsp.filter.design.FilterDesignException;
import dsp.filter.fir.FIRFilterSpecification;
import dsp.filter.fir.remez.RemezFIRFilterDesigner;
import dsp.filter.polyphase.PolyphaseFIRDecimatingFilter_RB;
import module.Module;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import sample.Listener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
-import audio.metadata.AudioMetadata;
-import audio.metadata.IMetadataListener;
-import audio.metadata.Metadata;
-import audio.squelch.ISquelchStateListener;
-import audio.squelch.SquelchState;
-import controller.channel.ChannelEvent;
-import controller.channel.IChannelEventListener;
-import dsp.filter.Filters;
-import dsp.filter.fir.real.RealFIRFilter_R_R;
+
+import java.util.concurrent.ScheduledExecutorService;
/**
* Provides packaging of demodulated audio sample buffers into audio packets for
@@ -33,12 +42,8 @@ import dsp.filter.fir.real.RealFIRFilter_R_R;
* Incorporates audio squelch state listener to control if audio packets are
* broadcast or ignored.
*/
-public class AudioModule extends Module implements IAudioPacketProvider,
- IChannelEventListener,
- IMetadataListener,
- IFilteredRealBufferListener,
- ISquelchStateListener,
- Listener
+public class AudioModule extends Module implements IAudioPacketProvider, IFilteredRealBufferListener,
+ ISquelchStateListener, Listener
{
protected static final Logger mLog = LoggerFactory.getLogger(AudioModule.class);
@@ -48,48 +53,41 @@ public class AudioModule extends Module implements IAudioPacketProvider,
{
//Band-pass filter to both decimate (48kHz to 8kHz) and block 0 - 300 Hz (LTR signalling).
FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder()
- .sampleRate( 48000 )
- .stopFrequency1( 150 )
- .passFrequencyBegin( 300 )
- .passFrequencyEnd( 3500 )
- .stopFrequency2( 4000 )
- .stopRipple( 0.0004 )
- .passRipple( 0.008)
- .build();
+ .sampleRate(48000)
+ .stopFrequency1(150)
+ .passFrequencyBegin(300)
+ .passFrequencyEnd(3500)
+ .stopFrequency2(4000)
+ .stopRipple(0.0004)
+ .passRipple(0.008)
+ .build();
RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification);
try
{
- if (!designer.isValid())
+ if(!designer.isValid())
{
throw new FilterDesignException("Couldn't design the audio decimation filter");
}
mDecimationCoefficients = designer.getImpulseResponse();
}
- catch (FilterDesignException e)
+ catch(FilterDesignException e)
{
mLog.debug("Error designing filter", e);
}
}
- /* Provides a unique identifier for this audio module instance to use as a
- * source identifier for all audio packets */
- private static int UNIQUE_ID = 0;
- private int mSourceID;
-
- private AudioMetadata mAudioMetadata;
- private ChannelEventListener mChannelEventListener = new ChannelEventListener();
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
private SquelchState mSquelchState = SquelchState.SQUELCH;
private Listener mAudioPacketListener;
private PolyphaseFIRDecimatingFilter_RB mAudioDecimationFilter;
+ private Metadata mMetadata;
- public AudioModule(boolean record)
+ public AudioModule(Metadata metadata)
{
- mSourceID = ++UNIQUE_ID;
- mAudioMetadata = new AudioMetadata(mSourceID, record);
+ mMetadata = metadata;
mAudioDecimationFilter = new PolyphaseFIRDecimatingFilter_RB(mDecimationCoefficients, 6, 2.0f);
mAudioDecimationFilter.setListener(new Listener()
@@ -97,9 +95,9 @@ public class AudioModule extends Module implements IAudioPacketProvider,
@Override
public void receive(RealBuffer realBuffer)
{
- if (mAudioPacketListener != null)
+ if(mAudioPacketListener != null)
{
- AudioPacket packet = new AudioPacket(realBuffer.getSamples(), mAudioMetadata.copyOf());
+ AudioPacket packet = new AudioPacket(realBuffer.getSamples(), mMetadata.copyOf());
mAudioPacketListener.receive(packet);
}
}
@@ -116,7 +114,6 @@ public class AudioModule extends Module implements IAudioPacketProvider,
@Override
public void reset()
{
- mAudioMetadata.reset();
}
@Override
@@ -128,11 +125,10 @@ public class AudioModule extends Module implements IAudioPacketProvider,
@Override
public void stop()
{
- /* Issue an end audio packet in case a recorder is still rolling */
- if (mAudioPacketListener != null)
+ /* Issue an end audio packet in case a recorder is still rolling */
+ if(mAudioPacketListener != null)
{
- mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END,
- mAudioMetadata.copyOf()));
+ mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
}
}
@@ -143,15 +139,9 @@ public class AudioModule extends Module implements IAudioPacketProvider,
@Override
public void receive(RealBuffer buffer)
{
- if (mAudioPacketListener != null && mSquelchState == SquelchState.UNSQUELCH)
+ if(mAudioPacketListener != null && mSquelchState == SquelchState.UNSQUELCH)
{
mAudioDecimationFilter.receive(buffer);
-
-// /* We make a copy of the samples, so that we don't affect any other
-// * processes that might be concurrently processing the same buffer */
-// float[] audio = Arrays.copyOf( buffer.getSamples(), buffer.getSamples().length );
-//
-// mAudioFilter.filter( audio );
}
}
@@ -161,12 +151,6 @@ public class AudioModule extends Module implements IAudioPacketProvider,
return this;
}
- @Override
- public Listener getMetadataListener()
- {
- return mAudioMetadata;
- }
-
@Override
public void setAudioPacketListener(Listener listener)
{
@@ -179,41 +163,12 @@ public class AudioModule extends Module implements IAudioPacketProvider,
mAudioPacketListener = null;
}
- @Override
- public Listener getChannelEventListener()
- {
- return mChannelEventListener;
- }
-
@Override
public Listener getSquelchStateListener()
{
return mSquelchStateListener;
}
- /**
- * Wrapper for channel event listener. Responds to channel state reset
- * events to remove/cleanup current audio metadata
- */
- public class ChannelEventListener implements Listener
- {
- @Override
- public void receive(ChannelEvent event)
- {
- switch (event.getEvent())
- {
- case NOTIFICATION_STATE_RESET:
- mAudioMetadata.reset();
- break;
- case NOTIFICATION_SELECTION_CHANGE:
- mAudioMetadata.setSelected(event.getChannel().isSelected());
- break;
- default:
- break;
- }
- }
- }
-
/**
* Wrapper for squelch state listener
*/
@@ -222,10 +177,9 @@ public class AudioModule extends Module implements IAudioPacketProvider,
@Override
public void receive(SquelchState state)
{
- if (state == SquelchState.SQUELCH && mAudioPacketListener != null)
+ if(state == SquelchState.SQUELCH && mAudioPacketListener != null)
{
- mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END,
- mAudioMetadata.copyOf()));
+ mAudioPacketListener.receive(new AudioPacket(AudioPacket.Type.END, mMetadata.copyOf()));
}
mSquelchState = state;
diff --git a/src/audio/AudioPacket.java b/src/audio/AudioPacket.java
index 2936557e..aa655975 100644
--- a/src/audio/AudioPacket.java
+++ b/src/audio/AudioPacket.java
@@ -1,77 +1,78 @@
+/*******************************************************************************
+ * 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
+ *
+ ******************************************************************************/
package audio;
+import channel.metadata.Metadata;
import sample.real.RealBuffer;
-import audio.metadata.AudioMetadata;
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2014,2016 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
- ******************************************************************************/
public class AudioPacket
{
- private Type mType;
- private RealBuffer mAudioData;
- private AudioMetadata mAudioMetadata;
-
- public AudioPacket( Type type, AudioMetadata metadata )
- {
- mType = type;
- mAudioMetadata = metadata;
- }
-
- public AudioPacket( float[] audio, AudioMetadata metadata )
- {
- this( Type.AUDIO, metadata );
+ private Type mType;
+ private RealBuffer mAudioData;
+ private Metadata mMetadata;
- mAudioData = new RealBuffer( audio );
- }
-
- public boolean hasAudioMetadata()
- {
- return mAudioMetadata != null;
- }
-
- public AudioMetadata getAudioMetadata()
- {
- return mAudioMetadata;
- }
-
- public void setMetadata( AudioMetadata metadata )
- {
- mAudioMetadata = metadata;
- }
-
- public Type getType()
- {
- return mType;
- }
-
- public RealBuffer getAudioBuffer()
- {
- return mAudioData;
- }
-
- public boolean hasAudioBuffer()
- {
- return mAudioData != null;
- }
-
- public enum Type
- {
- AUDIO,
- END;
- }
+ 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;
+ }
}
diff --git a/src/audio/broadcast/AudioBroadcaster.java b/src/audio/broadcast/AudioBroadcaster.java
index 7467a2b6..2115480b 100644
--- a/src/audio/broadcast/AudioBroadcaster.java
+++ b/src/audio/broadcast/AudioBroadcaster.java
@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
- * Copyright (C) 2014-2016 Dennis Sheirer
+ * 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
@@ -18,14 +18,11 @@
******************************************************************************/
package audio.broadcast;
-import audio.AudioPacket;
-import audio.IAudioPacketListener;
import audio.convert.ISilenceGenerator;
-import audio.metadata.AudioMetadata;
+import channel.metadata.Metadata;
import controller.ThreadPoolManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import properties.SystemProperties;
import sample.Listener;
import java.io.ByteArrayInputStream;
@@ -34,14 +31,13 @@ import java.nio.file.Files;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class AudioBroadcaster implements Listener
{
- private final static Logger mLog = LoggerFactory.getLogger( AudioBroadcaster.class );
+ private final static Logger mLog = LoggerFactory.getLogger(AudioBroadcaster.class);
public static final int PROCESSOR_RUN_INTERVAL_MS = 1000;
@@ -107,9 +103,10 @@ public abstract class AudioBroadcaster implements Listener
/**
* Broadcasts the next song's audio metadata prior to streaming the next song.
+ *
* @param metadata for the next recording that will be streamed
*/
- protected void broadcastMetadata(AudioMetadata metadata)
+ protected void broadcastMetadata(Metadata metadata)
{
IBroadcastMetadataUpdater metadataUpdater = getMetadataUpdater();
@@ -136,7 +133,7 @@ public abstract class AudioBroadcaster implements Listener
if(mThreadPoolManager != null)
{
mScheduledTask = mThreadPoolManager.scheduleFixedRate(ThreadPoolManager.ThreadType.AUDIO_PROCESSING,
- mRecordingQueueProcessor, PROCESSOR_RUN_INTERVAL_MS, TimeUnit.MILLISECONDS );
+ mRecordingQueueProcessor, PROCESSOR_RUN_INTERVAL_MS, TimeUnit.MILLISECONDS);
}
}
}
@@ -160,6 +157,7 @@ public abstract class AudioBroadcaster implements Listener
/**
* Stream name for the broadcast configuration for this broadcaster
+ *
* @return stream name or null
*/
public String getStreamName()
@@ -246,7 +244,7 @@ public abstract class AudioBroadcaster implements Listener
{
if(mBroadcastState != state)
{
- mLog.info("[" + getStreamName() + "] status: " + state);
+ mLog.info("[" + getStreamName() + "] status: " + state);
mBroadcastState = state;
broadcast(new BroadcastEvent(this, BroadcastEvent.Event.BROADCASTER_STATE_CHANGE));
@@ -386,7 +384,7 @@ public abstract class AudioBroadcaster implements Listener
{
mStreamedAudioCount++;
broadcast(new BroadcastEvent(AudioBroadcaster.this,
- BroadcastEvent.Event.BROADCASTER_STREAMED_COUNT_CHANGE));
+ BroadcastEvent.Event.BROADCASTER_STREAMED_COUNT_CHANGE));
metadataUpdateRequired = true;
}
@@ -431,7 +429,7 @@ public abstract class AudioBroadcaster implements Listener
if(connected())
{
- broadcastMetadata(nextRecording.getAudioMetadata());
+ broadcastMetadata(nextRecording.getMetadata());
}
metadataUpdateRequired = false;
diff --git a/src/audio/broadcast/AudioRecording.java b/src/audio/broadcast/AudioRecording.java
index 1d4c3f16..f80a0c66 100644
--- a/src/audio/broadcast/AudioRecording.java
+++ b/src/audio/broadcast/AudioRecording.java
@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
- * Copyright (C) 2014-2016 Dennis Sheirer
+ * 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
@@ -18,7 +18,7 @@
******************************************************************************/
package audio.broadcast;
-import audio.metadata.AudioMetadata;
+import channel.metadata.Metadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,22 +30,23 @@ public class AudioRecording implements Comparable
private final static Logger mLog = LoggerFactory.getLogger(StreamManager.class);
private Path mPath;
- private AudioMetadata mAudioMetadata;
private long mStartTime;
private long mRecordingLength;
private AtomicInteger mPendingReplayCount = new AtomicInteger();
+ private Metadata mMetadata;
/**
* Audio recording that is ready to be streamed
+ *
* @param path to the audio recording file
- * @param audioMetadata associated with the recording
+ * @param metadata associated with the recording
* @param start time of recording in milliseconds since epoch
* @param recordingLength in milliseconds
*/
- public AudioRecording(Path path, AudioMetadata audioMetadata, long start, long recordingLength)
+ public AudioRecording(Path path, Metadata metadata, long start, long recordingLength)
{
mPath = path;
- mAudioMetadata = audioMetadata;
+ mMetadata = metadata;
mStartTime = start;
mRecordingLength = recordingLength;
}
@@ -61,9 +62,9 @@ public class AudioRecording implements Comparable
/**
* Optional audio metadata for the recording.
*/
- public AudioMetadata getAudioMetadata()
+ public Metadata getMetadata()
{
- return mAudioMetadata;
+ return mMetadata;
}
/**
diff --git a/src/audio/broadcast/BroadcastModel.java b/src/audio/broadcast/BroadcastModel.java
index 911eaf39..f6e9b587 100644
--- a/src/audio/broadcast/BroadcastModel.java
+++ b/src/audio/broadcast/BroadcastModel.java
@@ -20,7 +20,7 @@ package audio.broadcast;
import alias.id.broadcast.BroadcastChannel;
import audio.AudioPacket;
-import audio.metadata.AudioMetadata;
+import channel.metadata.Metadata;
import controller.ThreadPoolManager;
import icon.IconManager;
import org.slf4j.Logger;
@@ -48,7 +48,7 @@ import java.util.regex.Pattern;
public class BroadcastModel extends AbstractTableModel implements Listener
{
- private final static Logger mLog = LoggerFactory.getLogger( BroadcastModel.class );
+ private final static Logger mLog = LoggerFactory.getLogger(BroadcastModel.class);
public static final String TEMPORARY_STREAM_DIRECTORY = "streaming";
public static final String TEMPORARY_STREAM_FILE_SUFFIX = "temporary_streaming_file_";
@@ -84,7 +84,7 @@ public class BroadcastModel extends AbstractTableModel implements Listener