Skip to content

Commit 88d8633

Browse files
DSheirerdenny
andauthored
#2234 Streaming Talkgroup Aliasing Feature (#2249)
Co-authored-by: denny <[email protected]>
1 parent 3bf3de8 commit 88d8633

File tree

10 files changed

+390
-183
lines changed

10 files changed

+390
-183
lines changed

src/main/java/io/github/dsheirer/alias/Alias.java

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2025 Dennis Sheirer
24
*
3-
* * ******************************************************************************
4-
* * Copyright (C) 2014-2020 Dennis Sheirer
5-
* *
6-
* * This program is free software: you can redistribute it and/or modify
7-
* * it under the terms of the GNU General Public License as published by
8-
* * the Free Software Foundation, either version 3 of the License, or
9-
* * (at your option) any later version.
10-
* *
11-
* * This program is distributed in the hope that it will be useful,
12-
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
13-
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-
* * GNU General Public License for more details.
15-
* *
16-
* * You should have received a copy of the GNU General Public License
17-
* * along with this program. If not, see <http://www.gnu.org/licenses/>
18-
* * *****************************************************************************
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
199
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
2014
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
2118
*/
2219
package io.github.dsheirer.alias;
2320

@@ -30,13 +27,22 @@
3027
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
3128
import io.github.dsheirer.alias.id.priority.Priority;
3229
import io.github.dsheirer.alias.id.record.Record;
30+
import io.github.dsheirer.alias.id.talkgroup.StreamAsTalkgroup;
31+
import java.awt.Color;
32+
import java.util.ArrayList;
33+
import java.util.Iterator;
34+
import java.util.List;
35+
import java.util.Set;
36+
import java.util.TreeSet;
3337
import javafx.beans.Observable;
3438
import javafx.beans.binding.Bindings;
3539
import javafx.beans.binding.BooleanBinding;
3640
import javafx.beans.property.BooleanProperty;
3741
import javafx.beans.property.IntegerProperty;
42+
import javafx.beans.property.ObjectProperty;
3843
import javafx.beans.property.SimpleBooleanProperty;
3944
import javafx.beans.property.SimpleIntegerProperty;
45+
import javafx.beans.property.SimpleObjectProperty;
4046
import javafx.beans.property.SimpleStringProperty;
4147
import javafx.beans.property.StringProperty;
4248
import javafx.collections.FXCollections;
@@ -46,13 +52,6 @@
4652
import org.slf4j.Logger;
4753
import org.slf4j.LoggerFactory;
4854

49-
import java.awt.Color;
50-
import java.util.ArrayList;
51-
import java.util.Iterator;
52-
import java.util.List;
53-
import java.util.Set;
54-
import java.util.TreeSet;
55-
5655
/**
5756
* Alias provides an aliasing (e.g. name, color, etc) container that is linked to multiple alias identifiers and
5857
* provides a corresponding set of actions related to the alias.
@@ -74,6 +73,7 @@ public class Alias
7473
private StringProperty mName = new SimpleStringProperty();
7574
private ObservableList<AliasID> mAliasIDs = FXCollections.observableArrayList();
7675
private ObservableList<AliasAction> mAliasActions = FXCollections.observableArrayList();
76+
private ObjectProperty<StreamAsTalkgroup> mStreamTalkgroupAlias = new SimpleObjectProperty<>();
7777

7878
/**
7979
* Constructs an instance and sets the specified name.
@@ -180,6 +180,12 @@ public IntegerProperty colorProperty()
180180
return mColor;
181181
}
182182

183+
@JsonIgnore
184+
public ObjectProperty streamTalkgroupAliasProperty()
185+
{
186+
return mStreamTalkgroupAlias;
187+
}
188+
183189
/**
184190
* Icon name property
185191
*/
@@ -229,6 +235,24 @@ public void setName(String name)
229235
mName.set(name);
230236
}
231237

238+
/**
239+
* Alias name
240+
*/
241+
@JacksonXmlProperty(isAttribute = true, localName = "stream_talkgroup_alias")
242+
public StreamAsTalkgroup getStreamTalkgroupAlias()
243+
{
244+
return mStreamTalkgroupAlias.get();
245+
}
246+
247+
/**
248+
* Sets the stream as talkgroup value that will be used in the TO field for streamed audio calls.
249+
* @param streamTalkgroupAlias with a talkgroup value.
250+
*/
251+
public void setStreamTalkgroupAlias(StreamAsTalkgroup streamTalkgroupAlias)
252+
{
253+
mStreamTalkgroupAlias.set(streamTalkgroupAlias);
254+
}
255+
232256
/**
233257
* Alias list name for the alias list that this alias belongs to
234258
*/
@@ -710,6 +734,7 @@ public static Callback<Alias,Observable[]> extractor()
710734
{
711735
return (Alias a) -> new Observable[] {a.recordableProperty(), a.streamableProperty(), a.colorProperty(),
712736
a.aliasListNameProperty(), a.groupProperty(), a.iconNameProperty(), a.nameProperty(), a.aliasIds(),
713-
a.aliasActions(), a.nonAudioIdentifierCountProperty(), a.overlapProperty()};
737+
a.aliasActions(), a.nonAudioIdentifierCountProperty(), a.overlapProperty(), a.priorityProperty(),
738+
a.streamTalkgroupAliasProperty()};
714739
}
715740
}

src/main/java/io/github/dsheirer/alias/id/AliasID.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2025 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -42,6 +42,7 @@
4242
import io.github.dsheirer.alias.id.status.UnitStatusID;
4343
import io.github.dsheirer.alias.id.status.UserStatusID;
4444
import io.github.dsheirer.alias.id.talkgroup.P25FullyQualifiedTalkgroup;
45+
import io.github.dsheirer.alias.id.talkgroup.StreamAsTalkgroup;
4546
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
4647
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
4748
import io.github.dsheirer.alias.id.tone.TonesID;
@@ -70,6 +71,7 @@
7071
@JsonSubTypes.Type(value = RadioRange.class, name = "radioRange"),
7172
@JsonSubTypes.Type(value = Record.class, name = "record"),
7273
@JsonSubTypes.Type(value = SiteID.class, name = "siteID"),
74+
@JsonSubTypes.Type(value = StreamAsTalkgroup.class, name = "streamAsTalkgroup"),
7375
@JsonSubTypes.Type(value = Talkgroup.class, name = "talkgroup"),
7476
@JsonSubTypes.Type(value = TalkgroupRange.class, name = "talkgroupRange"),
7577
@JsonSubTypes.Type(value = TonesID.class, name = "tones"),
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2025 Dennis Sheirer
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
18+
*/
19+
20+
package io.github.dsheirer.alias.id.talkgroup;
21+
22+
import io.github.dsheirer.protocol.Protocol;
23+
24+
/**
25+
* Streaming talkgroup alias. For streamed audio metadata, this value is used to replace the decoded talkgroup or TO
26+
* value with an alias value when there are talkgroup collisions resulting from streaming multiple channels to the
27+
* same stream. This is common in P25 conventional repeater setups where each radio channel is using talkgroup 1.
28+
*/
29+
public class StreamAsTalkgroup extends Talkgroup
30+
{
31+
public StreamAsTalkgroup(int talkgroup)
32+
{
33+
super(Protocol.UNKNOWN, talkgroup);
34+
}
35+
36+
public StreamAsTalkgroup()
37+
{
38+
//No arg JAXB constructor
39+
}
40+
}

src/main/java/io/github/dsheirer/audio/broadcast/broadcastify/BroadcastifyCallBroadcaster.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2025 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,8 @@
2020
package io.github.dsheirer.audio.broadcast.broadcastify;
2121

2222
import com.google.common.net.HttpHeaders;
23+
import io.github.dsheirer.alias.Alias;
24+
import io.github.dsheirer.alias.AliasList;
2325
import io.github.dsheirer.alias.AliasModel;
2426
import io.github.dsheirer.audio.broadcast.AbstractAudioBroadcaster;
2527
import io.github.dsheirer.audio.broadcast.AudioRecording;
@@ -32,6 +34,7 @@
3234
import io.github.dsheirer.identifier.Identifier;
3335
import io.github.dsheirer.identifier.IdentifierClass;
3436
import io.github.dsheirer.identifier.Role;
37+
import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier;
3538
import io.github.dsheirer.identifier.configuration.ConfigurationLongIdentifier;
3639
import io.github.dsheirer.identifier.patch.PatchGroup;
3740
import io.github.dsheirer.identifier.patch.PatchGroupIdentifier;
@@ -45,6 +48,7 @@
4548
import java.net.http.HttpRequest;
4649
import java.net.http.HttpResponse;
4750
import java.time.Duration;
51+
import java.util.List;
4852
import java.util.Queue;
4953
import java.util.concurrent.CompletionException;
5054
import java.util.concurrent.LinkedTransferQueue;
@@ -76,6 +80,7 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
7680
.build();
7781
private long mLastConnectionAttempt;
7882
private long mConnectionAttemptInterval = 5000; //Every 5 seconds
83+
final private AliasModel mAliasModel;
7984

8085
/**
8186
* Constructs an instance of the broadcaster
@@ -86,6 +91,7 @@ public BroadcastifyCallBroadcaster(BroadcastifyCallConfiguration config, InputAu
8691
MP3Setting mp3Setting, AliasModel aliasModel)
8792
{
8893
super(config);
94+
mAliasModel = aliasModel;
8995
}
9096

9197
/**
@@ -443,10 +449,34 @@ private static String getFrom(AudioRecording audioRecording)
443449
/**
444450
* Creates a formatted string with the TO identifiers or uses a default of zero (0)
445451
*/
446-
private static String getTo(AudioRecording audioRecording)
452+
private String getTo(AudioRecording audioRecording)
447453
{
448454
Identifier identifier = audioRecording.getIdentifierCollection().getToIdentifier();
449455

456+
//Alias the TO value when the user specifies a 'Stream As Talkgroup'
457+
if(identifier != null)
458+
{
459+
AliasListConfigurationIdentifier config = audioRecording.getIdentifierCollection().getAliasListConfiguration();
460+
461+
if(config != null)
462+
{
463+
AliasList aliasList = mAliasModel.getAliasList(config.getValue());
464+
465+
if(aliasList != null)
466+
{
467+
List<Alias> aliases = aliasList.getAliases(identifier);
468+
469+
for(Alias a: aliases)
470+
{
471+
if(a.getStreamTalkgroupAlias() != null)
472+
{
473+
return String.valueOf(a.getStreamTalkgroupAlias().getValue());
474+
}
475+
}
476+
}
477+
}
478+
}
479+
450480
if(identifier instanceof PatchGroupIdentifier patchGroupIdentifier)
451481
{
452482
return format(patchGroupIdentifier);

src/main/java/io/github/dsheirer/audio/broadcast/icecast/IcecastMetadata.java

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,37 @@
11
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2025 Dennis Sheirer
24
*
3-
* * ******************************************************************************
4-
* * Copyright (C) 2014-2020 Dennis Sheirer
5-
* *
6-
* * This program is free software: you can redistribute it and/or modify
7-
* * it under the terms of the GNU General Public License as published by
8-
* * the Free Software Foundation, either version 3 of the License, or
9-
* * (at your option) any later version.
10-
* *
11-
* * This program is distributed in the hope that it will be useful,
12-
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
13-
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-
* * GNU General Public License for more details.
15-
* *
16-
* * You should have received a copy of the GNU General Public License
17-
* * along with this program. If not, see <http://www.gnu.org/licenses/>
18-
* * *****************************************************************************
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
199
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
2014
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
2118
*/
2219
package io.github.dsheirer.audio.broadcast.icecast;
2320

2421
import com.google.common.base.Joiner;
2522
import io.github.dsheirer.alias.Alias;
2623
import io.github.dsheirer.alias.AliasList;
2724
import io.github.dsheirer.alias.AliasModel;
28-
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
2925
import io.github.dsheirer.identifier.Form;
3026
import io.github.dsheirer.identifier.Identifier;
3127
import io.github.dsheirer.identifier.IdentifierClass;
3228
import io.github.dsheirer.identifier.IdentifierCollection;
3329
import io.github.dsheirer.identifier.Role;
34-
import io.github.dsheirer.properties.SystemProperties;
35-
import io.github.dsheirer.util.ThreadPool;
30+
import java.util.List;
31+
import java.util.Optional;
3632
import org.slf4j.Logger;
3733
import org.slf4j.LoggerFactory;
3834

39-
import java.io.IOException;
40-
import java.io.UnsupportedEncodingException;
41-
import java.util.List;
42-
4335
public class IcecastMetadata
4436
{
4537
private final static Logger mLog = LoggerFactory.getLogger(IcecastMetadata.class);
@@ -73,13 +65,23 @@ public static String getTitle(IdentifierCollection identifierCollection, AliasMo
7365

7466
if(to != null)
7567
{
76-
sb.append("TO:").append(to);
77-
7868
List<Alias> aliases = aliasList.getAliases(to);
7969

80-
if(aliases != null && !aliases.isEmpty())
70+
//Check for 'Stream As Talkgroup' alias and use this instead of the decoded TO value.
71+
Optional<Alias> streamAs = aliases.stream().filter(alias -> alias.getStreamTalkgroupAlias() != null).findFirst();
72+
73+
if(streamAs.isPresent())
8174
{
82-
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
75+
sb.append("TO:").append(streamAs.get().getStreamTalkgroupAlias().getValue());
76+
}
77+
else
78+
{
79+
sb.append("TO:").append(to);
80+
81+
if(!aliases.isEmpty())
82+
{
83+
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
84+
}
8385
}
8486
}
8587
else

0 commit comments

Comments
 (0)