From 187466b6bf6f0921e21f6094effe7358b7763b56 Mon Sep 17 00:00:00 2001 From: Luke Berndt Date: Sat, 17 Oct 2026 15:34:32 -0400 Subject: [PATCH] Systems with sites (SDK 0.4.0) Trunk Recorder Pro's systems now have sites: a call heard on several is one call, its JSON saying the site it was kept from. The events doc says so: site / site_name in the examples, call.start's id matching call_num only for a call heard on one site, a call's audio from a copy that had no call.start, status as an entry per site. Settings and uploading say a system's sites share its settings, and how to give a site its own. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- docs/events.md | 28 +++++++++++++++++++++------- docs/settings.md | 6 +++++- docs/uploading.md | 3 ++- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cddefa2..e2cd8cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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 2af800a..46de272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ authors = ["Your Name "] publish = false [dependencies] -trunk-recorder-plugin = "0.3.0" +trunk-recorder-plugin = "0.4.0" # The settings form is drawn from your config structs' JSON Schema. Keep the # major version the SDK uses (1). schemars = "1" diff --git a/docs/events.md b/docs/events.md index 108504f..510d889 100644 --- a/docs/events.md +++ b/docs/events.md @@ -28,7 +28,7 @@ uploaders and archivers. "path": "county/2026/9/30/101-1790771550_857587500", "system": 0, "call": { - "call_num": 412, "short_name": "county", "talkgroup": 101, + "call_num": 412, "short_name": "county", "site": "county", "talkgroup": 101, "talkgroup_tag": "Fire Dispatch", "talkgroup_description": "", "talkgroup_group": "Fire", "talkgroup_group_tag": "Fire Dispatch", "freq": 857587500, "start_time": 1790771550, "stop_time": 1790771554, "call_length": 4, "emergency": 0, "encrypted": 0, "priority": 0, "phase2_tdma": 0, "tdma_slot": 0, "audio_type": "digital", @@ -64,6 +64,12 @@ uploaders and archivers. Only recorded calls conclude. Calls the recorder skipped (encrypted, no free recorder, an unknown talkgroup when those aren't recorded) have no files. +A system can have several sites, each a control channel the recorder follows. +A call heard on more than one is one call, saved once from the site that heard +it best: `short_name` is the system, and **`site`** is the site the call was +kept from (a system of one site: its short name; none for a conventional +channel's call). + ## `call.start` and `call.end` A call started, or ended. Unlike `call.concluded`, these cover calls that @@ -73,7 +79,7 @@ it was recorded, come later in `call.concluded`. ```json { "type": "call.start", - "id": 412, "system": 0, "short_name": "county", + "id": 412, "system": 0, "short_name": "county", "site": "county", "talkgroup": 101, "talkgroup_tag": "Fire Dispatch", "freq_hz": 857587500, "tdma_slot": null, "analog": false, "encrypted": false, "emergency": false, @@ -85,7 +91,10 @@ it was recorded, come later in `call.concluded`. ``` - **`id`** is unique while the recorder runs. It's the same number as - `call_num` in the concluded call. + `call_num` in the concluded call, except for a call heard on several sites: + it starts and ends once, as its first site's copy (`site`), and the copy + that concludes may be another site's, with another number. Match those by + system, talkgroup and time if you need to. - **`recording`**: `false` means the call isn't recorded, and **`reason`** says why: `encrypted`, `unknown_tg` (not in the talkgroup list, and unknown talkgroups aren't recorded), `no_recorder` (all in use) or `no_source` (no @@ -99,7 +108,7 @@ it was recorded, come later in `call.concluded`. A radio did something on the control channel. ```json -{ "type": "unit", "system": 0, "short_name": "county", "kind": "affiliation", "unit": 1116707, "talkgroup": 101, "time": 1790771551.4 } +{ "type": "unit", "system": 0, "short_name": "county", "site": "county", "kind": "affiliation", "unit": 1116707, "talkgroup": 101, "time": 1790771551.4 } ``` `kind` is one of: @@ -128,19 +137,24 @@ little-endian, base64-encoded. `chunk.samples()` decodes it. Chunks of one call come in order. Chunks of different calls are interleaved. Use `call_id` to tell them apart, and `call.start` / `call.end` (subscribe to -them too) to know when a call's audio begins and ends. +them too) to know when a call's audio begins and ends. A call heard on several +sites plays from whichever site's copy has it at the moment, so a chunk can +carry the `call_id` of a copy that had no `call.start`: it is the call of the +same system and talkgroup that did. This topic is busy. Hand the audio to your own thread straight away. ## `status` -Every system's state, every 5 seconds. +Every system's state, every 5 seconds: an entry for each site, so a system of +several sites has several, with the same `index` and `short_name` and its own +`site_name`. ```json { "type": "status", "time": 1790771560.0, "systems": [ - { "index": 0, "short_name": "county", "control_channel_hz": 851012500, "decode_rate": 38.5, "active_calls": 3, "recording": 2 } + { "index": 0, "short_name": "county", "site_name": "county", "control_channel_hz": 851012500, "decode_rate": 38.5, "active_calls": 3, "recording": 2 } ] } ``` diff --git a/docs/settings.md b/docs/settings.md index 26323a9..0edc406 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -9,7 +9,11 @@ There are two kinds of settings: - **`Config`**: settings for the plugin as a whole, like a server URL. - **`SystemConfig`**: settings the form repeats for each system being recorded, like an API key per system. Many services give each system its own - key, so uploaders need this. + key, so uploaders need this. A system's sites share them; for a service that + knows a site as a system of its own, add a list of sites with what differs + (the [Broadcastify](https://github.com/TrunkRecorder/trunk-plugin-broadcastify) + and [OpenMHz](https://github.com/TrunkRecorder/trunk-plugin-openmhz) plugins' + **Sites of their own**) and pick by the call's `site`. Use `NoConfig` for either if you don't need it. diff --git a/docs/uploading.md b/docs/uploading.md index 3863e89..75385eb 100644 --- a/docs/uploading.md +++ b/docs/uploading.md @@ -12,7 +12,8 @@ complete example, about 250 lines with its tests. Read it alongside. ## 1. Settings Services usually give each system its own key, so the key goes in -`SystemConfig`. The server goes in `Config`, with the real service as the +`SystemConfig` (a system's sites share it; see [Settings](settings.md) for a +site a service knows on its own). The server goes in `Config`, with the real service as the default: ```rust