I have started testing another instance at one of my other monitoring sites and the weak signal P25 decode performance is out of this world. One problem I have noticed so far is that the duplicate call suppression doesn't seem to be working. With both Duplicate Call Detection and Duplicate Call Suppression during streaming selected, I am still getting duplicate calls in my Rdio-Scanner feed.
Disregard the potential duplicate call issue. ChatGPT and Codex was able to discover that I had a slight difference in system name when I added a new site. The improvement in decoding weak control channels allowed me to add some new sites that I previously could not monitor.
One area of possible improvement is how SDRTrunk selects between duplicate calls. It has never been clear to me how SDRTrunk selects which file to send to rdio-scanner, so I asked ChatGPT and Codex to look into the issue. This is what they came up with:
This investigation found that SDRTrunk VCE does not deliberately choose the strongest or best-quality copy when duplicate calls are detected. It also does not consistently choose the first call received.
The selection occurs in `AudioCallCoordinator.updateDuplicateState()`. The process is approximately:
1. Active calls are retrieved from a Java `HashMap`.
2. The calls are examined in the map’s current iteration order.
3. The first matching call that has not already been marked duplicate is retained.
4. Later matching calls are marked as duplicates.
5. Once a call has been marked duplicate, it is not reconsidered as the retained call.
Because a Java `HashMap` does not guarantee insertion order, the effective winner is based on an unspecified internal iteration order. That order may be influenced by keys, hash values, resizing, and the other entries currently in the map. It may appear stable in some situations, but it is not a defined or meaningful selection policy.
The retained call is not selected based on:
* Signal strength or SNR
* Decode quality or error rate
* Audio completeness
* Call duration
* Earliest channel grant
* Earliest audio arrival
* Preferred tuner
* Preferred receiver site
* Frequency error
* First call completion
The practical consequence is that a weaker, incomplete, or lower-quality copy can suppress a cleaner duplicate. The selected receiver or site may also vary between otherwise similar calls.
This appears to be a design issue rather than merely a configuration problem:
> Duplicate-call suppression selects the surviving call according to `HashMap` iteration order in AudioCallCoordinator.updateDuplicateState()`. The result is not based on arrival order, configured priority, or audio quality and is not guaranteed to remain stable. Once a candidate is marked duplicate, it cannot later become the retained call.
A minimum improvement would be to make selection deterministic by using an explicit comparator, for example:
1. Earliest coordinator registration time
2. Earliest call start time
3. Stable call identifier as a final tie-breaker
That would not necessarily select the best audio, but it would make the result predictable and testable.
A better long-term approach would keep all duplicate candidates eligible until sufficient information is available and then select the best candidate using available quality measures, such as:
* Valid decoded-message count
* Decode-error count
* Audio sample count
* Missing or invalid frame count
* Signal or SNR measurements
* Completeness of the beginning and end of the call
Where reliable quality measurements are unavailable, another practical option would be a user-configurable receiver, site, or channel priority, with earliest registration used as the fallback.
A useful regression test would create several matching calls in different insertion orders and verify that the same intended candidate is retained each time. Under the current implementation, changing map population or call identifiers could change which audio is streamed even though the user’s configuration remains unchanged.