diff --git a/CHANGELOG.md b/CHANGELOG.md index 06905a1..640aae2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.1.4] + +- A system's sites: Trunk Recorder Pro now has systems with several sites, and + a call heard on more than one starts and ends once, its live audio coming + from whichever site's copy has it. Audio from a copy that wasn't the one + that started now still finds its call (its patched talkgroups, radio and + frequency), also when that first copy wasn't recorded. +- Built with trunk-recorder-plugin 0.4.0. + ## [0.1.3] - A system can have streams of its own (the recorder's per-system override of the streams); they carry only its audio, and the recorder-wide streams no longer carry it. diff --git a/Cargo.lock b/Cargo.lock index 2675b56..9e338ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,7 +162,7 @@ dependencies = [ [[package]] name = "simplestream" -version = "0.1.3" +version = "0.1.4" dependencies = [ "schemars", "serde", @@ -183,9 +183,9 @@ dependencies = [ [[package]] name = "trunk-recorder-plugin" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f6a3ae3954c34ae02ca4a347777d30481ec4f6b456c6adc7bbe59e8117751e" +checksum = "587edb957af1d5bd2cd1a8a0e362419d731d95b78e3ca4181a1494d0f8831753" dependencies = [ "schemars", "serde", diff --git a/Cargo.toml b/Cargo.toml index 153991f..a703119 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simplestream" -version = "0.1.3" +version = "0.1.4" edition = "2024" description = "Streams the audio of calls as they're recorded to other programs, over UDP or TCP." license = "GPL-3.0-or-later" @@ -9,7 +9,7 @@ authors = ["Luke Berndt "] publish = false [dependencies] -trunk-recorder-plugin = "0.3.0" +trunk-recorder-plugin = "0.4.0" schemars = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/README.md b/README.md index c57ac36..e92271d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,10 @@ A list of **streams**. Each sends some of the audio to one place: Talkgroup numbers repeat between systems, so stream each system to a port of its own, or turn on JSON (which names the system). +A system can have several sites. A call heard on more than one is one call: +its audio streams once, from whichever site's copy has it at the moment, and +`short_name` is the system's. + ## Packets Each packet is one slice of audio, with, depending on the settings: diff --git a/src/main.rs b/src/main.rs index db6661e..a5db959 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,7 +115,7 @@ impl Out { struct SimpleStream { outs: Vec, - /// The calls recording now. + /// The calls going now (each once, however many sites hear it). calls: HashMap, } @@ -167,7 +167,9 @@ impl Plugin for SimpleStream { } fn call_start(&mut self, call: CallInfo) { + // (Kept even when not recorded here: another site's copy of it may be, and its audio is this call's.) if !call.recording { + self.calls.insert(call.id, call); return; } let short_name = call.short_name.clone(); @@ -194,7 +196,10 @@ impl Plugin for SimpleStream { fn audio(&mut self, chunk: AudioChunk) { let pcm = base64::decode(&chunk.pcm); - let call = self.calls.get(&chunk.call_id); + // A call heard on several sites plays from whichever copy has it: one that wasn't + // told to start is the call that was (the same system and talkgroup). + let twin = || self.calls.values().find(|c| c.short_name == chunk.short_name && c.talkgroup == chunk.talkgroup); + let call = self.calls.get(&chunk.call_id).or_else(twin); let short_name = chunk.short_name.as_str(); let talkgroups = call.map_or(vec![chunk.talkgroup], talkgroups); for o in self.outs.iter().filter(|o| o.wants_system(short_name)) { @@ -372,6 +377,19 @@ mod tests { assert_eq!(last.extra["packetsSent"], 1); } + /// A call heard on several sites is started once, by its first site's copy (here not + /// recorded); its audio can come from another site's copy, with another id: it is still the call. + #[test] + fn audio_from_another_sites_copy() { + let (s, url) = udp(); + let mut first = call(1, 101, vec![101, 202]); + first.recording = false; + testing::run::([hello(json!([{ "url": url, "TGID": 202, "sendJSON": true }])), HostMessage::CallStart(first), audio(9, 101, &[1])]); + let (a, pcm) = split(&recv(&s).unwrap()); + assert_eq!((a["talkgroup"].clone(), a["src"].clone(), a["freq"].clone()), (json!(202), json!(1234), json!(851012500u64)), "{a}"); + assert_eq!(pcm, [1, 0]); + } + #[test] fn json_and_call_events() { let (s, url) = udp();