From 0a7f6dc602a2a45fdc130130292f25c202c9fb2b Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 20 May 2025 00:02:55 +0000 Subject: [PATCH 1/2] Fixed dead links, updated to match main repo --- docs/CONFIGURE.md | 154 ++++++++++++++++++++++++--------- docs/DEBUG.md | 6 +- docs/FAQ.md | 2 +- docs/Install/INSTALL-DOCKER.md | 11 +-- docs/Install/INSTALL-LINUX.md | 4 +- docs/Install/INSTALL-PI.md | 72 +++++++++++++-- docs/Plugins.md | 106 ++++++++++++++++------- docs/SQUELCH.MD | 99 +++++++++++++++++++++ docs/intro.md | 60 ++++++++++--- 9 files changed, 409 insertions(+), 105 deletions(-) create mode 100644 docs/SQUELCH.MD diff --git a/docs/CONFIGURE.md b/docs/CONFIGURE.md index e080958..5110d8a 100644 --- a/docs/CONFIGURE.md +++ b/docs/CONFIGURE.md @@ -9,7 +9,7 @@ It takes a little bit of work to correctly configure Trunk Recorder, but once yo ## Research -Before you can start entering values, you will need to do a little research about the radio system you are trying to capture and the correct parameters for receiving it. [Radio Reference](http://www.radioreference.com/apps/db/?coid=1) is a great place to learn about a radio system. Search for your location and then select the system you are trying to record. Take note of the frequencies that the system uses. You will want to make sure you can cover the range of frequencies used with one or more SDRs. Also look at the System Type, which tells you if it is a Trunked system and what type it is. For Trunked systems, you will need to write down the control channels, and alternate control channels. +Before you can start entering values, you will need to do a little research about the radio system you are trying to capture and the correct parameters for receiving it. [Radio Reference](http://www.radioreference.com/apps/db/?coid=1) is a great place to learn about a radio system. Search for your location and then select the system you are trying to record. Take note of the frequencies that the system uses. You will want to make sure you can cover the range of frequencies used with one or more SDRs. Also look at the System Type, which tells you if it is a Trunked system and what type it is. For Trunked systems, you will need to take note of the control channels, and alternate control channels. ### Frequency @@ -31,7 +31,14 @@ The amount of tuning error is -14500Hz, so that would go under **error:** for th **NOTE:** In some instances, an alternative is to use `ppm` correction rather than the `error` configuration option. -Alternatively, you can use these tools here: https://webby.site/sdr/ or http://garvas.org/trunk-recorder/ to obtain RTL-SDR dongle/array configurations. +### Helpful Tools +Center Frequency Calculators: +- http://alertapi.alertpage.net/sdr - Paste the frequencies from Radio Reference into this website and it will automatically calculate what center frequency you should use and how many dongles you will need. We recommend a sample rate value around 2.4 MHz for an RTL-SDR, as most can be pushed that high without stability issues. +- https://tr.icarey.net/sdr_calc - Similar in functionality to the one above, but will also generate the sources section of your Trunk-Recorder configuration file as well. + +Configuration File: +- https://github.com/AlertPageSDR/tr_configurator - If you have a Radio Reference Premium account, you can use this tool to automatically generate a config.json based on the RR data for a given system (or systems) +- https://github.com/TrunkRecorder/trunk-recorder-configs - example configurations for different systems ### Gain @@ -106,7 +113,7 @@ Here is a map of the different sections of the *config.json* file: There is a list of available Plugins [here](./Plugins.md). -### Global Configs +## Global Configs | Key | Required | Default Value | Type | Description | @@ -125,6 +132,7 @@ There is a list of available Plugins [here](./Plugins.md). | consoleLog | | true | **true** / **false** | Send logging output to the console | | logFile | | false | **true** / **false** | Send logging output to a file | | logDir | | logs/ | string | Where the output logs should be put | +| logColor | | "console" (*or* "none" if `NO_COLOR` env set) | **"all"**, **"console"**, **"logfile"**, **"none"** | Control the output of ANSI color in the console or logfiles. The presence of the [`NO_COLOR` env variable](https://no-color.org) will modify the default if set (`export NO_COLOR=1`). | | frequencyFormat | | "exp" | **"exp" "mhz"** or **"hz"** | the display format for frequencies to display in the console and log file. | | controlWarnRate | | 10 | number | Log the control channel decode rate when it falls bellow this threshold. The value of *-1* will always log the decode rate. | | controlRetuneLimit | | 0 | number | Number of times to attempt to retune to a different control channel when there's no signal. *0* means unlimited attemps. The counter is reset when a signal is found. Should be at least equal to the number of channels defined in order for all to be attempted. | @@ -138,21 +146,24 @@ There is a list of available Plugins [here](./Plugins.md). | audioStreaming | | false | **true** / **false** | Whether or not to enable the audio streaming callbacks for plugins. | | newCallFromUpdate | | true | **true** / **false** | Allow for UPDATE trunking messages to start a new Call, in addition to GRANT messages. This may result in more Calls with no transmisions, and use more Recorders. The flipside is that it may catch parts of a Call that would have otherwise been missed. Turn this off if you are running out of Recorders. | | softVocoder | | false | **true** / **false** | Use the Software Decode vocoder from OP25 for Phase 1 audio. Give it a try if you are hearing weird tones in your audio. Whether it makes your audio sound better or worse is a matter of preference. | +| recordUUVCalls | | true | **true** / **false** | *P25 only* Record Unit to Unit Voice calls. | +## Source Object -#### Source Object +### USRP or OSMOSDR Sources | Key | Required | Default Value | Type | Description | | :--------------- | :------: | :-----------: | --------------------------- | ------------------------------------------------------------ | +| driver | ✓ | | **"usrp"**, **"osmosdr"** | The GNURadio block you wish to use for the SDR. | +| device | | | **string**
See the [osmosdr page](http://sdr.osmocom.org/trac/wiki/GrOsmoSDR) for supported devices and parameters. | Osmosdr device name and possibly serial number or index of the device.
You only need to do add this key if there are more than one osmosdr devices being used.
Example: `bladerf=00001` for BladeRF with serial 00001 or `rtl=00923838` for RTL-SDR with serial 00923838, just `airspy` for an airspy.
It seems that when you have 5 or more RTLSDRs on one system you need to decrease the buffer size. I think it has something to do with the driver. Try adding buflen: `"device": "rtl=serial_num,buflen=65536"`, there should be no space between the comma and `buflen`. | | center | ✓ | | number | The center frequency in Hz to tune the SDR to | | rate | ✓ | | number | The sampling rate to set the SDR to, in samples / second | | error | | 0 | number | The tuning error for the SDR, in Hz. This is the difference between the target value and the actual value. So if you wanted to recv 856MHz but you had to tune your SDR to 855MHz (when set to 0ppm) to actually receive it, you would set this to -1000000. You should also probably get a new SDR if it is off by this much. | | gain | ✓ | | number | The RF gain setting for the SDR. Use a program like GQRX to find a good value. | | digitalRecorders | | | number | The number of Digital Recorders to have attached to this source. This is essentially the number of simultaneous calls you can record at the same time in the frequency range that this Source will be tuned to. It is limited by the CPU power of the machine. Some experimentation might be needed to find the appropriate number. *This is only required for Trunk systems. Channels in Conventional systems have dedicated recorders and do not need to be included here.* | | analogRecorders | | | number | The number of Analog Recorder to have attached to this source. The same as Digital Recorders except for Analog Voice channels. *This is only required for Trunk systems. Channels in Conventional systems have dedicated recorders and do not need to be included here.* | -| driver | ✓ | | **"usrp"** or **"osmosdr"** | The GNURadio block you wish to use for the SDR. | -| device | | | **string**
See the [osmosdr page](http://sdr.osmocom.org/trac/wiki/GrOsmoSDR) for supported devices and parameters. | Osmosdr device name and possibly serial number or index of the device.
You only need to do add this key if there are more than one osmosdr devices being used.
Example: `bladerf=00001` for BladeRF with serial 00001 or `rtl=00923838` for RTL-SDR with serial 00923838, just `airspy` for an airspy.
It seems that when you have 5 or more RTLSDRs on one system you need to decrease the buffer size. I think it has something to do with the driver. Try adding buflen: `"device": "rtl=serial_num,buflen=65536"`, there should be no space between the comma and `buflen`. | +| signalDetectorThreshold | | | number | If set, a static threshold will be used for the Signal Detector on all conventional recorder. Otherwise, the threshold value for the noise floor will be automatically be determined. Only set this is you are having problems. The value is in dB, but is generally higher than the Squelch value because the power is measured differently | | ppm | | 0 | number | The tuning error for the SDR in ppm (parts per million), as an alternative to `error` above. Use a program like GQRX to find an accurate value. | | agc | | false | **true** / **false** | Whether or not to enable the SDR's automatic gain control (if supported). This is false by default. It is not recommended to set this as it often yields worse performance compared to a manual gain setting. | | gainSettings | | | { "stageName": value} | Set the gain for any stage. The value for this setting should be passed as an object, where the key specifies the name of the gain stage and the value is the amount of gain, as an int. For example:
````"gainSettings": { "IF": 10, "BB": 11},```` | @@ -165,13 +176,42 @@ There is a list of available Plugins [here](./Plugins.md). | antenna | | | string, e.g.: **"TX/RX"** | *usrp only* selects which antenna jack to use | | enabled | | true | **true** / **false** | control whether a configured source is enabled or disabled | +*** +### SigMF Sources + +| Key | Required | Default Value | Type | Description | +| :--------------- | :------: | :-----------: | --------------------------- | ------------------------------------------------------------ | +| driver | ✓ | | **"sigmffile"**| Specify that you wish to use a SigMF based source block | +| sigmfMeta | ✓ | | string | Path and filenme for the SigMF metadata File | +| sigmfData | ✓ | | string | Path and filenme for the SigMF data File | +| repeat | | false | **true** / **false** | whether to repeat playback of the IQ file when it reaches the end | +| digitalRecorders | | | number | The number of Digital Recorders to have attached to this source. This is essentially the number of simultaneous calls you can record at the same time in the frequency range that this Source will be tuned to. It is limited by the CPU power of the machine. Some experimentation might be needed to find the appropriate number. *This is only required for Trunk systems. Channels in Conventional systems have dedicated recorders and do not need to be included here.* | +| analogRecorders | | | number | The number of Analog Recorder to have attached to this source. The same as Digital Recorders except for Analog Voice channels. *This is only required for Trunk systems. Channels in Conventional systems have dedicated recorders and do not need to be included here.* | +| enabled | | true | **true** / **false** | control whether a configured source is enabled or disabled | + +*** + +### IQ File Sources + +| Key | Required | Default Value | Type | Description | +| :--------------- | :------: | :-----------: | --------------------------- | ------------------------------------------------------------ | +| driver | ✓ | | **"iqfile"**| Specify that you wish to use an IQ File based source block | +| iqfile | ✓ | | string | Path and filenme for the IQ File | +| repeat | | false | **true** / **false** | whether to repeat playback of the IQ file when it reaches the end | +| center | ✓ | | number | The center frequency in Hz to tune the SDR to | +| rate | ✓ | | number | The sampling rate to set the SDR to, in samples / second | +| digitalRecorders | | | number | The number of Digital Recorders to have attached to this source. This is essentially the number of simultaneous calls you can record at the same time in the frequency range that this Source will be tuned to. It is limited by the CPU power of the machine. Some experimentation might be needed to find the appropriate number. *This is only required for Trunk systems. Channels in Conventional systems have dedicated recorders and do not need to be included here.* | +| analogRecorders | | | number | The number of Analog Recorder to have attached to this source. The same as Digital Recorders except for Analog Voice channels. *This is only required for Trunk systems. Channels in Conventional systems have dedicated recorders and do not need to be included here.* | +| enabled | | true | **true** / **false** | control whether a configured source is enabled or disabled | + -#### System Object + +## System Object | Key | Required | Default Value | Type | Description | | ---------------------- | :------: | -------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------ | | shortName | ✓ | | string | This is a nickname for the system. It is used to help name and organize the recordings from this system. It should be 4-6 letters with no spaces. | -| type | ✓ | | **"smartnet"**, **"p25"**, **"conventional"**, **"conventionalDMR"** or **"conventionalP25"** | The type of radio system. | +| type | ✓ | | **"smartnet"**, **"p25"**, **"conventional"**, **"conventionalDMR"** or **"conventionalP25"**, **"conventionalSIGMF"** | The type of radio system. | | control_channels | ✓ | | array of numbers;
[496537500, 496437500] | *For trunked systems* The control channel frequencies for the system, in Hz. The frequencies will automatically be cycled through if the system moves to an alternate channel. | | channels | ✓ | | array of numbers;
[166725000, 166925000, 167075000, 166850000] | *For conventional systems* The channel frequencies, in Hz, used for the system. The channels get assigned a virtual talkgroup number based upon their position in the array. Squelch levels need to be specified for the Source(s) being used. | | channelFile | ✓ | | string | *For conventional systems* The filename for a CSV file that provides information about the conventional channels. The format for the file is described below. Squelch levels need to be specified for the Source(s) being used. *Use channels or channelFile, not both*. | @@ -179,6 +219,7 @@ There is a list of available Plugins [here](./Plugins.md). | squelch | | -160 | number | Squelch in DB, this needs to be set for all conventional systems. The squelch setting is also used for analog talkgroups in a SmartNet system. I generally use -60 for my rtl-sdr. The closer the squelch is to 0, the stronger the signal has to be to unmute it. | | talkgroupsFile | | | string | The filename for a CSV file that provides information about the talkgroups. It determines whether a talkgroup is analog or digital, and what priority it should have. This file should be located in the same directory as the trunk-recorder executable. | | apiKey | | | string | *if uploadServer is set* System-specific API key for uploading calls to OpenMHz.com. See the Config tab for your system in OpenMHz to find what the value should be. | +| openmhzSystemId | | `shortName` | string | *if uploadServer is set* By default, the plugin will upload calls to the `shortName` OpenMHz system. Setting this value will allow uploads to any specific OpenMHz system with its valid API key. This is useful in a multi-site setup where multiple trunk-recorder systems may be aggregating calls to the same OpenMHz feed. | | broadcastifyApiKey | | | string | *if broadcastifyCallsServer is set* System-specific API key for Broadcastify Calls | | broadcastifySystemId | | | number | *if broadcastifyCallsServer is set* System ID for Broadcastify Calls
(this is an integer, and different from the RadioReference system ID) | | uploadScript | | | string | The filename of a script that is called after each recording has finished. Checkout *encode-upload.sh.sample* as an example. Should probably start with `./` ( or `../`). | @@ -192,7 +233,6 @@ There is a list of available Plugins [here](./Plugins.md). | digitalLevels | | 1 | number (1-16) | The amount of amplification that will be applied to the digital audio. | | unitTagsFile | | | string | The filename of a CSV file that provides information about the unit tags. The format for the file is described below. | | recordUnknown | | true | **true** / **false** | Record talkgroups if they are not listed in the Talkgroups File. | -| recordUUVCalls | | true | **true** / **false** | *P25 only* Record Unit to Unit Voice calls. | | hideEncrypted | | false | **true** / **false** | Hide encrypted talkgroups log entries | | hideUnknownTalkgroups | | false | **true** / **false** | Hide unknown talkgroups log entries | | minDuration | | 0
(which is disabled) | number | The minimum call duration in seconds (decimals allowed), calls below this number will have recordings deleted and will not be uploaded. | @@ -204,13 +244,17 @@ There is a list of available Plugins [here](./Plugins.md). | bandplanHigh | | | number | *SmartNet, 400_custom only* The highest channel in the system, specified in Hz. | | bandplanSpacing | | | number | *SmartNet, 400_custom only* The channel spacing, specified in Hz. Typically this is *25000*. | | bandplanOffset | | | number | *SmartNet, 400_custom only* The offset used to calculate frequencies. | +| customFrequencyTableFile| | | string | *P25 only* The filename for a CSV file that provides information about the P25 custom frequency tables. The format for the file is described below. | | decodeMDC | | false | **true** / **false** | *Conventional systems only* enable the MDC-1200 signaling decoder. | | decodeFSync | | false | **true** / **false** | *Conventional systems only* enable the Fleet Sync signaling decoder. | | decodeStar | | false | **true** / **false** | *Conventional systems only* enable the Star signaling decoder. | | decodeTPS | | false | **true** / **false** | *Conventional systems only* enable the Motorola Tactical Public Safety (aka FDNY Fireground) signaling decoder. | +| deemphasisTau | | 0.000750 | number | *Conventional systems only* configure the de-emphasis time constant. 750µs for NFM (default), 75µs for WFM North America, 50µs for WFM most other regions. | | enabled | | true | **true** / **false** | control whether a configured system is enabled or disabled | -#### System Object - Experimental Options +*** + +### System Object - Experimental Options | Key | Required | Default Value | Type | Description | | ---------------------- | :------: | --------------| ---------------------| --------------------------------------------------------------------------------- | @@ -220,11 +264,9 @@ There is a list of available Plugins [here](./Plugins.md). When enabled, Multi-Site mode attempts to avoid recording duplicate calls by detecting simulcasted transmissions for the same talkgroup across multiple sites at the same time. -For P25, Trunk Recorder will match calls that have the same WACN and same talkgroup number but a different NAC. For SmartNet, Trunk Recorder will match calls that have the same multiSiteSystemName and same talkgroup number but different multiSiteSystemNumber. +For P25, Trunk Recorder will match calls that have the same WACN and talkgroup number but a different RFSS/SiteID. For SmartNet, Trunk Recorder will match calls that have the same multiSiteSystemName and same talkgroup number but different multiSiteSystemNumber. -By default, Trunk Recorder will record the call from the first site to receive the grant and ignore the duplicate grants from the other related sites. If you want to specify the preferred site for a given talkgroup number you can specify the preferred NAC (in decimal format) in the [talkgroupsFile](#talkgroupsFile). - -Note: While multiSiteSystemName and multiSiteSystemNumber are normally used for SmartNet systems, these settings may also be used to override the default de-duplication logic for P25 systems where the mutliSite feature may not be correctly detecting duplicates. An example would be when two or more sites within a P25 system are using the same NAC and WACN. In such a deployment as a workaround, for each related system object, set multiSiteSystemName to a shared value and multiSiteSystemNumber to a unique value: +By default, Trunk Recorder will record the call from the first site to receive the grant and ignore the duplicate grants from the other related sites. If you want to specify the preferred site for a given talkgroup number you can add a preferred NAC (in decimal format), RFSS/SiteID (`RRRRssss`, e.g. `00010026`), or multiSiteSystemNumber to the [talkgroupsFile](#talkgroupsFile). ``` { @@ -249,7 +291,7 @@ Note: While multiSiteSystemName and multiSiteSystemNumber are normally used for } ``` -#### Plugin Object +## Plugin Object | Key | Required | Default Value | Type | Description | | ------- | :------: | ------------- | -------------------- | ------------------------------------------------------------ | @@ -299,13 +341,13 @@ This plugin makes it easy to connect Trunk Recorder with [Rdio Scanner](https:// **Name:** simplestream **Library:** libsimplestream.so -This plugin streams uncompressed audio (16 bit Int, 8 kHz, mono) to UDP or TCP ports in real time as it is being recorded by trunk-recorder. It can be configured to stream audio from all talkgroups and systems being recorded or only specified talkgroups and systems. TGID information can be prepended to the audio data to allow the receiving program to take action based on the TGID. Audio from different Systems should be streamed to different UDP/TCP ports to prevent crosstalk and interleaved audio from talkgroups with the same TGID on different systems. +This plugin streams uncompressed audio (16 bit Int, 8 or 16 kHz, mono) to UDP or TCP ports in real time as it is being recorded by trunk-recorder. It can be configured to stream audio from all talkgroups and systems being recorded or only specified talkgroups and systems. TGID information can be prepended to the audio data to allow the receiving program to take action based on the TGID. Audio from different Systems should be streamed to different UDP/TCP ports to prevent crosstalk and interleaved audio from talkgroups with the same TGID on different systems. This plugin does not, by itself, stream audio to any online services. Because it sends uncompressed PCM audio, it is not bandwidth efficient and is intended mostly to send audio to other programs running on the same computer as trunk-recorder or to other computers on the LAN. The programs receiving PCM audio from this plugin may play it on speakers, compress it and stream it to an online service, etc. **NOTE 1: In order for this plugin to work, the audioStreaming option in the Global Configs section (see above) must be set to true.** -**NOTE 2: trunk-recorder passes analog audio to this plugin at 16 kHz sample rate and digital audio at 8 kHz sample rate. Since the audio data being streamed doesn't contain the sample rate, analog and digital audio should be configured to be sent to different ports to receivers that are matched to the same sample rate.** +**NOTE 2: trunk-recorder passes analog audio to this plugin at 16 kHz sample rate and digital audio at 8 kHz sample rate. JSON metadata (if enabled) will contain the sample rate of the audio being sent.** | Key | Required | Default Value | Type | Description | | ------- | :------: | ------------- | ------ | ------------------------------------------------------------ | @@ -318,8 +360,11 @@ This plugin does not, by itself, stream audio to any online services. Because i | address | ✓ | | string | IP address to send this audio stream to. Use "127.0.0.1" to send to the same computer that trunk-recorder is running on. | | port | ✓ | | number | UDP or TCP port that this stream will send audio to. | | TGID | ✓ | | number | Audio from this Talkgroup ID will be sent on this stream. Set to 0 to stream all recorded talkgroups. | -| sendTGID | | false | **true** / **false** | When set to true, the TGID will be prepended in long integer format (4 bytes, little endian) to the audio data each time a packet is sent. | -| shortName | | | string | shortName of the System that audio should be streamed for. This should match the shortName of a system that is defined in the main section of the config file. When omitted, all Systems will be streamed to the address and port configured. If TGIDs from Systems overlap, each system must be sent to a different port to prevent interleaved audio for talkgroups from different Systems with the same TGID. +| sendJSON | | false | **true** / **false** | When set to true, JSON metadata will be prepended to the audio data each time a packet is sent. JSON fields are talkgroup, patched_talkgroups, src, src_tag, freq, audio_sample_rate, short_name, event (set to "audio"). The length of the JSON metadata is prepended to the metadata in long integer format (4 bytes, little endian). If this is set to **true**, the sendTGID field will be ignored. | +| sendCallStart | | false | **true** / **false** | Only used if sendJSON is set to **true**. When set to true, a JSON message will be sent at the start of each call that includes the following JSON fields: talkgroup, talkgroup_tag, patched_talkgroups, patched_talkgroup_tags, src, src_tag, freq, short_name, event (set to "call_start"). The length of the JSON metadata is prepended to the metadata in long integer format (4 bytes, little endian). +| sendCallEnd | | false | **true** / **false** | Only used if sendJSON is set to **true**. When set to true, a JSON message will be sent at the end of each call that includes the following JSON fields: talkgroup, patched_talkgroups, freq, short_name, event (set to "call_end"). The length of the JSON metadata is prepended to the metadata in long integer format (4 bytes, little endian). +| sendTGID | | false | **true** / **false** | Deprecated. Recommend using sendJSON for metadata instead. If sendJSON is set to true, this setting will be ignored. When set to true, the TGID will be prepended in long integer format (4 bytes, little endian) to the audio data each time a packet is sent. | +| shortName | | | string | shortName of the System that audio should be streamed for. This should match the shortName of a system that is defined in the main section of the config file. When omitted, all Systems will be streamed to the address and port configured. If TGIDs from Systems overlap, JSON metadata should be used to prevent interleaved audio for talkgroups from different Systems with the same TGID. | useTCP | | false | **true** / **false** | When set to true, TCP will be used instead of UDP. ###### Plugin Object Example #1: @@ -332,7 +377,7 @@ This example will stream audio from talkgroup 58914 on system "CountyTrunked" to "TGID":58914, "address":"127.0.0.1", "port":9123, - "sendTGID":false, + "sendJSON":false, "shortName":"CountyTrunked"} } ``` @@ -347,19 +392,19 @@ This example will stream audio from talkgroup 58914 from System CountyTrunked to "TGID":58914, "address":"127.0.0.1", "port":9123, - "sendTGID":false, + "sendJSON":false, "shortName":"CountyTrunked"}, {"TGID":58916, "address":"127.0.0.1", "port":9124, - "sendTGID":false, + "sendJSON":false, "shortName":"StateTrunked"} ]} } ``` ###### Plugin Object Example #3: -This example will stream audio from talkgroups 58914 and 58916 from all Systems to the local machine on the same UDP port 9123. It will prepend the TGID to the audio data in each UDP packet so that the receiving program can differentiate the two audio streams (the receiver may decide to only play one depending on priority, mix the two streams, play one left and one right, etc.) +This example will stream audio from talkgroups 58914 and 58916 from all Systems to the local machine on the same UDP port 9123. It will prepend the TGID and other JSON metadata to the audio data in each UDP packet so that the receiving program can differentiate the two audio streams (the receiver may decide to only play one depending on priority, mix the two streams, play one left and one right, etc.) ```yaml { "name":"simplestream", @@ -368,16 +413,16 @@ This example will stream audio from talkgroups 58914 and 58916 from all Systems "TGID":58914, "address":"127.0.0.1", "port":9123, - "sendTGID":true}, + "sendJSON":true}, {"TGID":58916, "address":"127.0.0.1", "port":9123, - "sendTGID":true} + "sendJSON":true} ]} } ``` ###### Plugin Object Example #4: -This example will stream audio from all talkgroups being recorded on System CountyTrunked to the local machine on UDP port 9123. It will prepend the TGID to the audio data in each UDP packet so that the receiving program can decide which ones to play or otherwise handle) +This example will stream audio from all talkgroups being recorded on System CountyTrunked to the local machine on UDP port 9123. It will prepend the TGID and other JSON metadata to the audio data in each UDP packet so that the receiving program can decide which ones to play or otherwise handle) ```yaml { "name":"simplestream", @@ -386,7 +431,7 @@ This example will stream audio from all talkgroups being recorded on System Coun "TGID":0, "address":"127.0.0.1", "port":9123, - "sendTGID":true, + "sendJSON":true, "shortName":"CountyTrunked"} } ``` @@ -406,11 +451,14 @@ The matching simplestream config to send audio from talkgroup 58918 to TCP port "TGID":58918, "address":"127.0.0.1", "port":9125, - "sendTGID":false, + "sendJSON":false, "shortName":"CountyTrunked", "useTCP":true} } ``` +#### Example - Sending Audio to FFMPEG for compression +Here's an FFMPEG command that takes PCM audio from simplestream via UDP, cleans it up, and outputs ogg/opus to stdout. Note that this will only work if sendTGID and sendJSON are both set to false and only a single talkgroup is fed to ffmpeg over the UDP port, as ffmpeg cannot interpret any metadata. +`ffmpeg -loglevel warning -f s16le -ar 16000 -ac 1 -i udp://localhost:9125 -af:a adeclick -f:a ogg -c:a libopus -frame_duration:a 20 -vbr:a on -b:a 48000 -application:a voip pipe:1` ## talkgroupsFile @@ -434,7 +482,7 @@ The columns are: | Category | | The category for the Talkgroup | | Tag | | The Service Tag for the Talkgroup | | Priority | | The priority field specifies the number of recorders the system must have available to record a new call for the talkgroup. For example, a priority of 1, the highest means as long as at least a single recorder is available, the system will record the new call. If the priority is 2, the system would at least 2 free recorders to record the new call, and so on. If there is no priority set for a talkgroup entry, a prioity of 1 is assumed.
Talkgroups assigned a priority of -1 will never be recorded, regardless of the number of available recorders. | -| Preferred NAC | | In Multi-Site mode, the preferred NAC for a specific talk group is used to specify the site you prefer the talk group to be recorded from.| +| Preferred NAC | | In Multi-Site mode, the preferred NAC (`nnnn`, e.g. `1234`), RFSS/SiteID (`RRRRssss`, e.g. `00010023`), or multiSiteSystemNumber to record a specific talkgroup.| | Comment | | Use this field to capture comments about a talkgroup. It will be ignored by Trunk Recorder. | Here are the column headers and some sample data: @@ -447,29 +495,28 @@ Here are the column headers and some sample data: ## channelFile -This file allows for you to specify additional information about conventional channels. A recorder is started for each line in the file and set the to frequency specified. The type of recorder is based on the type of System. A **Conventional** system would have Analog Recorders, while **ConventionalP25** or **ConventionalDMR** would have digital recorders. - -*Tone based squelch is currently not supported.* - +This file allows for you to specify additional information about conventional channels. A recorder is started for each line in the file and set the to frequency specified. The type of recorder is based on the type of System. A **conventional** system would have Analog Recorders, while **conventionalP25** or **conventionalDMR** would have digital recorders. **conventionalSIGMF** is a conventional system with SIGMF Recorders. | Column Name | Required | Value | |-------------|----------|-------| | TG Number | ✔️ | The Talkgroup Number formatted as a decimal number. This has to be the first column | -| Frequency | ✔️ | The frequency in Hz for the channel | -| Tone | ✔️ | The Tone for the talkgroup. This value is not used. *Tone based squelch is currently not supported.* | +| Frequency | ✔️ | The frequency in MHz or Hz for the channel (decimal point must be used for MHz) | +| Tone | | The CTCSS Tone for the talkgroup. | | Alpha Tag | | A 16 character description that is intended as a shortened display on radio displays | +| Description | | A longer description of the talkgroup | | Category | | The category for the Talkgroup | | Tag | | The Service Tag for the Talkgroup | | Comment | | Use this field to capture comments about a talkgroup. It will be ignored by Trunk Recorder. | | Enable | | Set to 'false' if you do not want this talkgroup/channel to created | +| Signal Detector | | Set to `false` if you do not want to use the Signal Detector for this channel. The Signal Detector scans a source's bandwidth and only enables a channel if a signal over a threshold is detected. If it not used, the channel will always be enabled and the Squelch will be running which uses more CPU. Default is `true`| +| Squelch | | Value in dB to use for the Squelch for this channel. If this is not set then the System Squelch value will be used instead. | +A **Header Row** is required for the file, with a header provided for each of the columns that will be used. The columns can be in any order. For the Optional columns, if they are left blank for some of the rows, the default value will be used instead. -The **Enable** Column is optional and defaults to *True*. It only needs to be added to rows that you do not want to have recorded. For those rows, set **Enable** to *False*. - -| TG Number | Frequency | Tone | Alpha Tag | Description | Tag | Category | Enable (*optional*) | -| --------- | --------- | -------- | ------------- | ---------------------- | ------ | ------ | ------------------- | -| 300 | 462275000 | 94.8 | Town A Police | Town A Police Dispatch | Police | Town A | | -| 325 | 462275000 | 151.4 | Town B DPW | Town B Trash Dispatch | DPW | Town B | False | +| TG Number | Frequency | Tone | Alpha Tag | Description | Tag | Category | Enable | Signal Detector | Squelch | +| --------- | --------- | -------- | ------------- | ---------------------- | ------ | ------ | ------------------- | ---- | ---- | +| 300 | 462275000 | 94.8 | Town A Police | Town A Police Dispatch | Police | Town A | | false | | +| 325 | 462275000 | 151.4 | Town B DPW | Town B Trash Dispatch | DPW | Town B | false | | -50 | ## unitTagsFile @@ -485,3 +532,28 @@ In the second row of the example below, the first capture group `([0-9]{2})` bec | 911000 | Dispatch | | 1[1245]10([0-9]{2})[127] | Engine $1 | | /^1[78]3(1[0-9]{2})/ | Ambulance $1 | + +## customFrequencyTableFile + +This file allows for you to specify custom P25 frequency table information. + +**It is highly recommended to only use this file when the system control channel is not accurately broadcasting frequency table information. In most cases, this file should not be needed.** + +| Column Name | Required | Value | +|-------------|----------|-------| +| TABLEID | ✔️ | The frequency table ID. This ID uses One-Based numbering to match the RadioReference format. | +| TYPE | ✔️ | The type of frequency table. This should be either **TDMA** or **FDMA**. | +| BASE | ✔️ | The base frequency defined in MHz. (Example: 851.00625)| +| SPACING | ✔️ | The channel spacing defined in KHz. (Example 6.25) | +| OFFSET | ✔️ | The transmit offset defined in MHz. (Example -45) | + +A **Header Row** is required for the file and the headers must match the column names above. Column headers are case sensitive and must be provided in uppercase. + +**RadioReference Subscribers** please note that if you copy this information directly from RadioReference, you will need to update the column headers. + +| TABLEID | TYPE | BASE | SPACING | OFFSET | +|---------|------|-----------|---------|--------| +| 1 | FDMA | 851.00625 | 6.25 | -45 | +| 2 | FDMA | 762.00625 | 6.25 | +30 | +| 3 | TDMA | 851.01250 | 12.5 | -45 | +| 4 | TDMA | 762.00625 | 12.5 | +30 | \ No newline at end of file diff --git a/docs/DEBUG.md b/docs/DEBUG.md index baecd10..2c15e3c 100644 --- a/docs/DEBUG.md +++ b/docs/DEBUG.md @@ -26,7 +26,7 @@ make gdb trunk-recorder core ``` -6. *gdb* is a powerful debugging platform. However, all we need is a trace of the crash. After *gdb* has finished loading, type in `bt full` to get a trace. Copy all of the output from *gdb* into a new [GitHub Issue](https://github.com/robotastic/trunk-recorder/issues/new), along with as much information as possible on what maybe casuing the crash. +6. *gdb* is a powerful debugging platform. However, all we need is a trace of the crash. After *gdb* has finished loading, type in `bt full` to get a trace. Copy all of the output from *gdb* into a new [GitHub Issue](https://github.com/TrunkRecorder/trunk-recorder/issues/new), along with as much information as possible on what maybe casuing the crash. # How to Capture an IQ Sample @@ -67,7 +67,7 @@ Use the settings from the source you are interested in from your config.json fil you would use: `rtl_sdr -f 855700000 -s 2048000 -g 39 -d 41 debug.iq` -The file that rtl_sdr generates is in a compact format... which is great but it can't easily be opened by other program. There is a good write-up on it from here (from 2014!). Luckily, some wrote a small program to convert it into a more standard format (complex IQ). I have included it in the /utils folder: [rtlsdr-to-iq.c](https://github.com/robotastic/trunk-recorder/blob/master/utils/rtlsdr-to-iq.c). Compile the program and then copy it to the directory with your recordings and run it against them. Note - the conversion will cause the filesize to increase 4x, so make sure you have enough space. +The file that rtl_sdr generates is in a compact format... which is great but it can't easily be opened by other program. There is a good write-up on it from here (from 2014!). Luckily, some wrote a small program to convert it into a more standard format (complex IQ). I have included it in the /utils folder: [rtlsdr-to-iq.c](https://github.com/TrunkRecorder/trunk-recorder/blob/master/utils/rtlsdr-to-iq.c). Compile the program and then copy it to the directory with your recordings and run it against them. Note - the conversion will cause the filesize to increase 4x, so make sure you have enough space. ## Playback in GQRX @@ -81,4 +81,4 @@ You are then going to need a device string with the correct options. Update this ## Playing an IQ File as a Source in Trunk Recorder -Check out the [config-iq-file.json](https://github.com/robotastic/trunk-recorder/blob/master/examples/config-iq-file.json) config as an example of how to playback an IQ file as a Source. You will probably need to have the `repeat` parameter turned on, unless you have a really long file. \ No newline at end of file +Check out the [config-iq-file.json](https://github.com/TrunkRecorder/trunk-recorder/blob/master/examples/config-iq-file.json) config as an example of how to playback an IQ file as a Source. You will probably need to have the `repeat` parameter turned on, unless you have a really long file. \ No newline at end of file diff --git a/docs/FAQ.md b/docs/FAQ.md index 2be6131..099e324 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -46,5 +46,5 @@ Once **gdb** loads up, use the *backtrace* command to review the execution histo `backtrace` -Now you can create a [GitHub Issue](https://github.com/robotastic/trunk-recorder/issues), including the info from **gdb**, along with your config.json and as much info as possible on how to recreate the crash. +Now you can create a [GitHub Issue](https://github.com/TrunkRecorder/trunk-recorder/issues), including the info from **gdb**, along with your config.json and as much info as possible on how to recreate the crash. diff --git a/docs/Install/INSTALL-DOCKER.md b/docs/Install/INSTALL-DOCKER.md index 7b41f9b..1d0529f 100644 --- a/docs/Install/INSTALL-DOCKER.md +++ b/docs/Install/INSTALL-DOCKER.md @@ -6,13 +6,12 @@ sidebar_position: 2 # Docker If you are not going to be modifying the source code, **a [Docker](https://www.docker.com/) based install is the easiest way to get started.** Images are published frequently to [Docker Hub](https://hub.docker.com/r/robotastic/trunk-recorder). The images have GNURadio 3.8 and all other required dependencies built into it, so it should be ready to go and be a much faster solution than compiling. Images have been built for amd64 (amd64 is used by all modern Intel and AMD CPUs) and most popular flavors of ARM. -To get started, create a directory and place your **config.json** file there and a **talkgroup.csv** file if you are using one. Refer to [Configuring Trunk Recorder](CONFIGURE.md) for instructions on how to create these files. +To get started, create a directory and place your **config.json** file there and a **talkgroup.csv** file if you are using one. Refer to [Configuring Trunk Recorder](../CONFIGURE.md) for instructions on how to create these files. ```bash docker run -it \ - --privileged -e TZ=$(cat /etc/timezone) --user "$(id -u):$(id -g)" \ + --device "/dev/bus/usb:/dev/bus/usb:rwm" -e TZ=$(cat /etc/timezone) --user "$(id -u):$(id -g)" \ -v $(pwd):/app \ - -v /dev/bus/usb:/dev/bus/usb \ -v /var/run/dbus:/var/run/dbus \ -v /var/run/avahi-daemon/socket:/var/run/avahi-daemon/socket \ robotastic/trunk-recorder:latest @@ -21,15 +20,14 @@ docker run -it \ To use it as part of a [Docker Compose](https://docs.docker.com/compose/) file: ```yaml -version: '3' services: recorder: image: robotastic/trunk-recorder:latest container_name: trunk-recorder restart: always - privileged: true + devices: + - "/dev/bus/usb:/dev/bus/usb:rwm" volumes: - - /dev/bus/usb:/dev/bus/usb - /var/run/dbus:/var/run/dbus - /var/run/avahi-daemon/socket:/var/run/avahi-daemon/socket - ./:/app @@ -56,4 +54,3 @@ Currently, Docker image builds are triggered by the following events: * After every push to the `master` branch the `edge` tag is built and pushed to Docker Hub. * Every day at 10 AM UTC the `nightly` tag is built and pushed to Docker Hub. * When a new [release](https://github.com/robotastic/trunk-recorder/releases) happens the `` and `latest` tags are built and pushed to Docker Hub. - diff --git a/docs/Install/INSTALL-LINUX.md b/docs/Install/INSTALL-LINUX.md index 433b1bc..94f0e17 100644 --- a/docs/Install/INSTALL-LINUX.md +++ b/docs/Install/INSTALL-LINUX.md @@ -213,7 +213,7 @@ Now restart to make sure these drivers are not loaded. ## Configuring Trunk Recorder -The next step is to [configure Trunk Recorder](CONFIGURE.md) for the system you are trying to capture. +The next step is to [configure Trunk Recorder](../CONFIGURE.md) for the system you are trying to capture. ## Running trunk recorder. @@ -224,4 +224,4 @@ From your build directory (e.g. `trunk-build`) you can now run ### Runtime options -Trunk Recorder will look for a *config.json* file in the same directory as it is being run in. You can point it to a different config file by using the *--config* argument on the command line, for example: `./trunk-recorder --config=examples/config-wmata-rtl.json`. +Trunk Recorder will look for a *config.json* file in the same directory as it is being run in. You can point it to a different config file by using the *--config* argument on the command line, for example: `./trunk-recorder --config=examples/config-wmata-rtl.json`. \ No newline at end of file diff --git a/docs/Install/INSTALL-PI.md b/docs/Install/INSTALL-PI.md index 12c036f..6ab14e0 100644 --- a/docs/Install/INSTALL-PI.md +++ b/docs/Install/INSTALL-PI.md @@ -10,7 +10,7 @@ Smaller radio systems can be covered using a Raspberry Pi. If you are interested ## RaspberryOS (aka Raspbian) ### Setup Raspbian -This is a [good guide](https://desertbot.io/blog/headless-raspberry-pi-4-ssh-wifi-setup) on how to setup a Raspberry Pi in headless mode. This means that you do not have to attach a monitor, keyboard or mouse to it to get it working. The steps below are pulled from this guide. +This is a [good guide](https://www.tomshardware.com/reviews/raspberry-pi-headless-setup-how-to,6028.html) on how to setup a Raspberry Pi in headless mode. This means that you do not have to attach a monitor, keyboard or mouse to it to get it working. The steps below are pulled from this guide. #### Download and burn the image @@ -21,7 +21,7 @@ The first step is to put the Raspberry Pi OS onto a MicroSD card. You will need #### Setup for headless boot -After the OS has been written to MicroSD card, we need to change a few files so that the Pi can get on Wifi and also allow for SSH connections. See the [guide](https://desertbot.io/blog/headless-raspberry-pi-4-ssh-wifi-setup) for how to do it using Windows. +After the OS has been written to MicroSD card, we need to change a few files so that the Pi can get on Wifi and also allow for SSH connections. See the [guide](https://www.tomshardware.com/reviews/raspberry-pi-headless-setup-how-to,6028.html) for how to do it using Windows. - **On a Mac** `touch /Volumes/boot/ssh` - Next, add the WiFi info @@ -66,13 +66,13 @@ deb https://www.deb-multimedia.org bookworm main non-free ``` - Download the keys for the apt source and install them: ```bash -wget https://www.deb-multimedia.org/pool/main/d/deb-multimedia-keyring/deb-multimedia-keyring_2016.8.1_all.deb -sudo dpkg -i deb-multimedia-keyring_2016.8.1_all.deb +wget https://www.deb-multimedia.org/pool/main/d/deb-multimedia-keyring/deb-multimedia-keyring_2024.9.1_all.deb +sudo dpkg -i deb-multimedia-keyring_2024.9.1_all.deb ``` - You can verify the package integrity with: ```bash -sha256sum deb-multimedia-keyring_2016.8.1_all.deb -9faa6f6cba80aeb69c9bac139b74a3d61596d4486e2458c2c65efe9e21ff3c7d deb-multimedia-keyring_2016.8.1_all.deb +sha256sum deb-multimedia-keyring_2024.9.1_all.deb +9faa6f6cba80aeb69c9bac139b74a3d61596d4486e2458c2c65efe9e21ff3c7d deb-multimedia-keyring_2024.9.1_all.deb ``` - Update the OS: ``` @@ -84,7 +84,13 @@ sudo apt upgrade sudo apt -y install libssl-dev openssl curl git fdkaac sox libcurl3-gnutls libcurl4 libcurl4-openssl-dev gnuradio gnuradio-dev gr-osmosdr libhackrf-dev libuhd-dev cmake make build-essential libboost-all-dev libusb-1.0-0-dev libsndfile1-dev ``` -Configure RTL-SDRs to load correctly: +- Remove xtra-dkms. +DKMS is not needed on the Raspberry Pi platform, and just causes issues. The above command actually returns an error on Raspberry Pi OS. So we remove that module from our build so we do not get errors from subsaquent `apt` calls. +```bash +sudo apt remove xtrx-dkms +``` + +## Configure RTL-SDRs to load correctly: ```bash sudo wget https://raw.githubusercontent.com/osmocom/rtl-sdr/master/rtl-sdr.rules ~/rtl-sdr.rules @@ -97,7 +103,55 @@ You will need to restart for the rules to take effect. Logging out and logging b sudo shutdown -r now ``` -Now go [Build](#build-trunk-recorder) Trunk Recorder! +## Configuring the UHD for Ettus SDRs + +If you haven't setup UHD yet there are a few extra steps you need to take: + +Install the UHD drivers: + +```bash +sudo apt-get install libuhd-dev uhd-host +``` + +Download the firmware images. The location of the downloader is different than the error message: + +```bash +dpkg -L uhd-host | grep "downloader" +``` +The run the downloader at the location identified, it should be something like this: + +```bash +sudo python3 /usr/libexec/uhd/utils/uhd_images_downloader.py +``` + +Setup the udev rules so any user can access the USB, as documented [here](https://files.ettus.com/manual/page_transport.html#transport_usb_udev): + +```bash +cd /usr/libexec/uhd/utils/ +sudo cp uhd-usrp.rules /etc/udev/rules.d/ +sudo udevadm control --reload-rules +sudo udevadm trigger +``` + +## Building Trunk Recorder + +In order to keep your copy of the Trunk Recorder source code free of build artifacts created by the build process, it is suggested to create a separate "out-of-tree" build directory. We will use `trunk-build` as our build directory. We by default do this in our home directory (`~` - Is a shortcut back to home.). + +**Note:** Depending on the ammount of RAM in your Raspberry Pi, it may be best to run `make -j1` (2GB), `make -j3` (4GB), and `make -j4` (8GB) in order to ensure that you do not run out of RAM, at the cost of making the compile process take longer. If you ran out of RAM the compile process will fail competely, so it can be an acceptable tradeoff. + +```bash +cd ~ +mkdir trunk-build +git clone https://github.com/robotastic/trunk-recorder.git +cd trunk-build +cmake ../trunk-recorder +make -j1 +sudo make install +``` + +## Configuring Trunk Recorder + +The next step is to [configure Trunk Recorder](../CONFIGURE.md) for the system you are trying to capture. *** # Ubuntu 22.04 Server (64-bit support!) @@ -163,4 +217,4 @@ From your build directory (e.g. `trunk-build`) you can now run ### Runtime options -Trunk Recorder will look for a *config.json* file in the same directory as it is being run in. You can point it to a different config file by using the *--config* argument on the command line, for example: `./trunk-recorder --config=examples/config-wmata-rtl.json`. +Trunk Recorder will look for a *config.json* file in the same directory as it is being run in. You can point it to a different config file by using the *--config* argument on the command line, for example: `./trunk-recorder --config=examples/config-wmata-rtl.json`. \ No newline at end of file diff --git a/docs/Plugins.md b/docs/Plugins.md index e2b8aaa..9d72ae3 100644 --- a/docs/Plugins.md +++ b/docs/Plugins.md @@ -21,12 +21,12 @@ The [Built-in Plugins](#built-in-plugins) are compiled and installed when you se #### Plugin Object -| Key | Required | Default Value | Type | Description | -| ------- | :------: | ------------- | -------------------- | ------------------------------------------------------------ | -| library | ✓ | | string | the name of the library that contains the plugin. | +| Key | Required | Default Value | Type | Description | +| ------- | :------: | ------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| library | ✓ | | string | the name of the library that contains the plugin. | | name | ✓ | | string | the name of the plugin. This name is used to find the `_plugin_new` method that creates a new instance of the plugin. | -| enabled | | true | **true** / **false** | control whether a configured plugin is enabled or disabled | -| | | | | *Additional elements can be added, they will be passed into the `parse_config` method of the plugin.* | +| enabled | | true | **true** / **false** | control whether a configured plugin is enabled or disabled | +| | | | | *Additional elements can be added, they will be passed into the `parse_config` method of the plugin.* | ## Built-in Plugins @@ -38,18 +38,18 @@ The [Built-in Plugins](#built-in-plugins) are compiled and installed when you se This plugin makes it easy to connect Trunk Recorder with [Rdio Scanner](https://github.com/chuot/rdio-scanner). It uploads recordings and the information about them. The following additional settings are required: -| Key | Required | Default Value | Type | Description | -| ------- | :------: | ------------- | ------ | ------------------------------------------------------------ | -| server | ✓ | | string | The URL for uploading to Rdio Scanner. The default is an empty string. It should be the same URL as the one you are using to access Rdio Scanner. | +| Key | Required | Default Value | Type | Description | +| ------- | :------: | ------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| server | ✓ | | string | The URL for uploading to Rdio Scanner. The default is an empty string. It should be the same URL as the one you are using to access Rdio Scanner. | | systems | ✓ | | array | This is an array of objects, where each is a system that should be passed to Rdio Scanner. More information about what should be in each object is in the following table. | *Rdio Scanner System Object:* -| Key | Required | Default Value | Type | Description | -| --------- | :------: | ------------- | ------ | ------------------------------------------------------------ | -| systemId | ✓ | | number | System ID for Rdio Scanner. | +| Key | Required | Default Value | Type | Description | +| --------- | :------: | ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| systemId | ✓ | | number | System ID for Rdio Scanner. | | apiKey | ✓ | | string | System-specific API key for uploading calls to Rdio Scanner. See the ApiKey section in the Rdio Scanner administrative dashboard for the value it should be. | -| shortName | ✓ | | string | This should match the shortName of a system that is defined in the main section of the config file. | +| shortName | ✓ | | string | This should match the shortName of a system that is defined in the main section of the config file. | @@ -80,20 +80,20 @@ This plugin does not, by itself, stream audio to any online services. Because i **NOTE 2: trunk-recorder passes analog audio to this plugin at 16 kHz sample rate and digital audio at 8 kHz sample rate. Since the audio data being streamed doesn't contain the sample rate, analog and digital audio should be configured to be sent to different ports to receivers that are matched to the same sample rate.** -| Key | Required | Default Value | Type | Description | -| ------- | :------: | ------------- | ------ | ------------------------------------------------------------ | -| streams | ✓ | | array | This is an array of objects, where each is an audio stream that will be sent to a specific IP address and UDP port. More information about what should be in each object is in the following table. | +| Key | Required | Default Value | Type | Description | +| ------- | :------: | ------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| streams | ✓ | | array | This is an array of objects, where each is an audio stream that will be sent to a specific IP address and UDP port. More information about what should be in each object is in the following table. | *Audio Stream Object:* -| Key | Required | Default Value | Type | Description | -| --------- | :------: | ------------- | -------------------- | ------------------------------------------------------------ | -| address | ✓ | | string | IP address to send this audio stream to. Use "127.0.0.1" to send to the same computer that trunk-recorder is running on. | -| port | ✓ | | number | UDP or TCP port that this stream will send audio to. | -| TGID | ✓ | | number | Audio from this Talkgroup ID will be sent on this stream. Set to 0 to stream all recorded talkgroups. | -| sendTGID | | false | **true** / **false** | When set to true, the TGID will be prepended in long integer format (4 bytes, little endian) to the audio data each time a packet is sent. | -| shortName | | | string | shortName of the System that audio should be streamed for. This should match the shortName of a system that is defined in the main section of the config file. When omitted, all Systems will be streamed to the address and port configured. If TGIDs from Systems overlap, each system must be sent to a different port to prevent interleaved audio for talkgroups from different Systems with the same TGID. -| useTCP | | false | **true** / **false** | When set to true, TCP will be used instead of UDP. +| Key | Required | Default Value | Type | Description | +| --------- | :------: | ------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| address | ✓ | | string | IP address to send this audio stream to. Use "127.0.0.1" to send to the same computer that trunk-recorder is running on. | +| port | ✓ | | number | UDP or TCP port that this stream will send audio to. | +| TGID | ✓ | | number | Audio from this Talkgroup ID will be sent on this stream. Set to 0 to stream all recorded talkgroups. | +| sendTGID | | false | **true** / **false** | When set to true, the TGID will be prepended in long integer format (4 bytes, little endian) to the audio data each time a packet is sent. | +| shortName | | | string | shortName of the System that audio should be streamed for. This should match the shortName of a system that is defined in the main section of the config file. When omitted, all Systems will be streamed to the address and port configured. If TGIDs from Systems overlap, each system must be sent to a different port to prevent interleaved audio for talkgroups from different Systems with the same TGID. | +| useTCP | | false | **true** / **false** | When set to true, TCP will be used instead of UDP. | ###### Plugin Object Example #1: This example will stream audio from talkgroup 58914 on system "CountyTrunked" to the local machine on UDP port 9123. @@ -185,11 +185,59 @@ The matching simplestream config to send audio from talkgroup 58918 to TCP port } ``` +## Community Plugins +Community plugins can extend the features of Trunk Recorder and allow customized workflows or analysis. +> As new plugins are developed, authors are encouraged to add to the below tables by submitting a PR to this document. + +#### External Plugins +Plugins that are built out-of-tree and installed seperately from Trunk Recorder: +| Plugin Name / Link | Description | +| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| [MQTT Status](https://github.com/taclane/trunk-recorder-mqtt-status) | Publishes the current status of a Trunk Recorder instance over MQTT | +| [MQTT Statistics](https://github.com/robotastic/trunk-recorder-mqtt-statistics) | Publishes statistics about a Trunk Recorder instance over MQTT | +| [Decode rates logger](https://github.com/rosecitytransit/trunk-recorder-decode-rate) | Logs trunking control channel decode rates to a CSV file, and includes a PHP file that outputs an SVG graph | +| [Daily call log and live Web page](https://github.com/rosecitytransit/trunk-recorder-daily-log) | Creates a daily log of calls (instead of just individual JSON files) and includes an updating PHP Web page w/audio player | +| [Prometheus exporter](https://github.com/USA-RedDragon/trunk-recorder-prometheus) | Publishes statistics to a metrics endpoint via HTTP | + +#### user_plugins +Plugins that are ready to clone into `/user_plugins` for automatic building and installation: +| Plugin Name / Link | Description | +| ---------------------------------------------------------------------- | ----------------------------------- | +| [Placeholder](https://github.com/tr_plugin_developer/my-tr-plugin.git) | Not a real plugin, but it could be. | + +## Automatic Building and Development +As an alternative to developing out-of-tree, or within `/plugins`, user plugins may be staged into a subdirectory of `/user_plugins` to automatically compile as if they were a built-in plugin. Minor changes may be required for exsting user plugins to benefit from automatic building, but this should simplify the process of development and installation, and ensure plugins remain up-to-date with any changes to Trunk Recorder. + +#### Example +1. Clone the plugin repository +```bash +cd /user_plugins +git clone https://github.com/tr_plugin_developer/my-tr-plugin.git +``` +  or add it as a submodule. +```bash +cd /user_plugins +git submodule add https://github.com/tr_plugin_developer/my-tr-plugin.git +``` +2. Review plugin requrements, and ensure all dependencies have been met. -## Community Plugins -* [MQTT Status](https://github.com/robotastic/trunk-recorder-mqtt-status): Publishes the current status of a Trunk Recorder instance over MQTT -* [MQTT Statistics](https://github.com/robotastic/trunk-recorder-mqtt-statistics): Publishes statistics about a Trunk Recorder instance over MQTT -* [Decode rates logger](https://github.com/rosecitytransit/trunk-recorder-decode-rate): Logs trunking control channel decode rates to a CSV file, and includes a PHP file that outputs an SVG graph -* [Daily call log and live Web page](https://github.com/rosecitytransit/trunk-recorder-daily-log): Creates a daily log of calls (instead of just individual JSON files) and includes an updating PHP Web page w/audio player -* [Prometheus exporter](https://github.com/USA-RedDragon/trunk-recorder-prometheus): Publishes statistics to a metrics endpoint via HTTP \ No newline at end of file +3. Return to your 'build' directory, and resume from the `cmake` step: e.g. +```bash +cd trunk-build +cmake ../trunk-recorder +``` +  Note that the plugin is displayed near the end of the cmake output: +``` +-- Added user plugin: my-tr-plugin +``` + +4. Contine to build and install Trunk Recorder with included plugins: +```bash +make +sudo make install +``` +  Return to the `cmake` step as you add or remove user plugins. + +### Development Quick-Start +Any of the built-in plugins in `/plugins` can be directly copied to `/user_plugins` as a template for development. The `rdio_scanner` plugin is a good example of a curl-based uploader, and `stat_socket` shows how many of the internal Trunk Recorder methods can be accessed for live updates or offline analysis. Ensure that instances of the previous plugin name are changed in `CMakeFile.txt` to avoid any conflicts with built-in plugins. \ No newline at end of file diff --git a/docs/SQUELCH.MD b/docs/SQUELCH.MD new file mode 100644 index 0000000..c873066 --- /dev/null +++ b/docs/SQUELCH.MD @@ -0,0 +1,99 @@ +# Adjusting Squelch for Conventional Systems + +```mermaid +flowchart TD + subgraph subgraph_5wys65oxs["Conventional Recorder"] + node_9tex2m50c["Squelch"] + end + A("SDR Source") --> B("Signal Detector") & C("Recorder Selector") + B -. Turn On Recorder .- C + C --> subgraph_5wys65oxs + B -.- nk["Automatic Signal Detection Threshold"] + style nk stroke-width:2px,stroke-dasharray: 2 +``` + +Conventional Systems can use up a lot of CPU. Prior to v5.0, conventional recorders are always "on" waiting for a signal to break squelch. With v5.0 you now have a Signal Detector per source. Its job is to look over the bandwidth for that source and perform an FFT. For each FFT bin that is over a power threshold, it will look for a **Conventional Recorder** that has similar frequencies. If there is a match, it will Enable the recorder in the Souce's Recorder Selector. The Recorder Selector is just a way to determine if a Recorder should receive samples from the Source. In your logs, look for something like `[ 0 ] AnalogC Enabled - Freq: 855.737500 MHz Detected Signal: -63dBM (Threshold: -69dBM)` if you see that, it means that the **Signal Detector** has turned on a conventional recorder. + +The **Signal Detector** automatically tries to find a power threshold to separate signal from noise. It is not perfect. If you are seeing a recorder not turn on when there is a signal, that could be because the Signal Detector threshold is not being set correctly. Or, if the Recorder is always being enabled by the Signal Detector, even when there is not a transmission, that is also a sign that is not automatically being set correctly. You can manually set the Signal Detector Threshold in the `config.json` file. Just to make things more confusing, the power levels used in the Signal Detector are slightly different than the values used for the Squelch. + +Each Conventional Recorder also has a Squelch setting. Once a Conventional Recorder has been enabled and is receiving samples from the source, it will use a Squelch block and only process samples above a certain power level. This prevent noise from being recorded. The Squelch value needs to be hand tuned, and can be set for the entire Conventional System, or per channel. + + +## Configuring a Conventional System + +- Use a visual signal analyzer program, like GQRX to explore the signal you are trying to capture + - Adjust the gain settings so that you have strong signals without adding a lot of noise. Copy these gain settings into the `config.json` file. + - Note the Db value for the noise floor. You should set the squelch value to be in between the noise floor value and the the signal peak values. + - In the `config.json` file you can specify the squelch value for the whole system, or do it channel by channel, or a mix: + - **System Wide Squelch** + - `config.json` + ```json + { + "systems": [ + { + "type": "conventional", + "squelch": -50 + } + } + ``` + - **Channel Specific Squelch** + - `config.json` + ```json + { + "systems": [ + { + "type": "conventional", + "channelFile": "channels.csv", + } + } + ``` + - `channels.csv` + | TG Number | Frequency | Squelch | + | --------- | --------- | -------- | + | 300 | 462275000 | -50 | + + ```csv + TG Number, Frequency, Squelch + 300, 462275000, -50 + ``` + - **Hybrid Squelch** + - `config.json` + ```json + { + "systems": [ + { + "type": "conventional", + "channelFile": "channels.csv", + "squelch": -50 + } + } + ``` + - `channels.csv` + | TG Number | Frequency | Squelch | + | --------- | --------- | -------- | + | 300 | 462275000 | -70 | + | 301 | 462300000 | | + + ```csv + TG Number, Frequency, Squelch + 300, 462275000, -70 + 301, 462300000, + ``` + +## Debugging a Conventional System + +- ### The Channels for a System are never being recorded + - Try setting the squelch value to something very low, like -100. This should cause the Recorder to always be on and recording. When you quit trunk-recorder you should have a long file, possibly of static. If you, it is possible that the Signal Detector is not working correctly. +- ### Signal Detector is not working correctly + - IF you are not seeing a line like: `[ 0 ] AnalogC Enabled - Freq: 855.737500 MHz Detected Signal: -63dBM (Threshold: -69dBM)` and you know there is a transmission on that frequency, it is a sign the the threshold for the Signal Detector is not being set correctly. To test this out, manually set the signal detector threshold in the `sources: [{}]` section of the config.json file. + + ```json + "sources": [ + { + "center": 851734375, + "rate": 2000000, + "driver": "osmosdr", + "signalDetectorThreshold": -100 + }] + ``` + This will effectively leave all of the recorders enabled all the time... which is not the most efficient. If this does work, then try to find a value for the `signalDetectorThreshold` that works reliably. RF power is measured differently between the Signal Detector and the Squelch block. You may need to use a value roughly 10 dB higher for the Signal Detector. Ideally, you only want the Signal Detector to enable a recorder when a there is a transmission that would trigger the squelch block in the Recorder. \ No newline at end of file diff --git a/docs/intro.md b/docs/intro.md index 506d21a..c856b88 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,37 +1,50 @@ +![Trunk Recorder](./docs/media/trunk-recorder-header.png) --- -sidebar_label: 'Introduction' -sidebar_position: 1 ---- -# All About Trunk Recorder +[![Discord](./docs/media/discord.jpg)](https://discord.gg/btJAhESnks)    + ## Sponsors **Do you find Trunk Recorder and OpenMHz useful?** Become a [Sponsor](https://github.com/sponsors/robotastic) to help support continued development and operation! Thank you to everyone who has contributed! +## 🎉 V5.0 Our Best Release Yet!! +Thanks to everyone who contributed, tested and helped collect cored dumps! + ## Overview Need help? Got something working? Share it! -[Discord Server](https://discord.gg/btJAhESnks) - and don't forget the [Wiki](https://github.com/robotastic/trunk-recorder/wiki) -Trunk Recorder is able to record the calls on trunked and conventional radio systems. It uses 1 or more Software Defined Radios (SDRs) to do this. The SDRs capture large swathes of RF and then use software to process what was received. [GNU Radio](https://gnuradio.org/) is used to do this processing because it provides lots of convenient RF blocks that can be pieced together to allow for complex RF processing. The libraries from the amazing [OP25](http://op25.osmocom.org/trac/wiki) project are used for a lot of the P25 functionality. Multiple radio systems can be recorded at the same time. +- [Discord Server](https://discord.gg/btJAhESnks) + +- [Documentation](https://trunkrecorder.com/docs/intro) + +- ... and don't forget the [Wiki](https://github.com/robotastic/trunk-recorder/wiki) + +![screenshot](./docs/media/screenshot.jpg) + +Trunk Recorder is able to record calls on trunked and conventional radio systems. It uses 1 or more Software Defined Radios (SDRs) to do this. The SDRs capture large swathes of RF and then use software to process what was received. [GNU Radio](https://gnuradio.org/) is used to do this processing because it provides lots of convenient RF blocks that can be pieced together to allow for complex RF processing. The libraries from the amazing [OP25](https://osmocom.org/projects/op25/wiki) project are used for a lot of the P25 functionality. Multiple radio systems can be recorded at the same time. Trunk Recorder currently supports the following: - Trunked P25 & SmartNet Systems - - Conventional P25 & analog systems, where each group has a dedicated RF channel + - Conventional P25, DMR & analog systems, where each talkgroup has a dedicated RF channel - P25 Phase 1, P25 Phase 2 & Analog voice channels -Supported platforms: +### Supported platforms -**Ubuntu** (18.04, 20.04, 21.04, 22.04, 23.04); **Raspberry Pi** (Raspberry OS/Raspbian & Ubuntu 21.04, 22.04); **Arch Linux** (2021.09.20); **Debian** (9.x); **macOS** +- **Ubuntu** +- **Raspberry Pi** (Raspberry OS/Raspbian & Ubuntu) +- **Arch Linux** +- **Debian** +- **macOS** GNU Radio 3.7 - 3.10 -...and SDRs: +### SDRs -RTL-SDR dongles; HackRF; Ettus USRP B200, B210, B205; BladeRF; Airspy +RTL-SDR dongles; HackRF; Ettus USRP B200, B210, B205; BladeRF; Airspy; SDRplay ## Install @@ -51,11 +64,32 @@ RTL-SDR dongles; HackRF; Ettus USRP B200, B210, B205; BladeRF; Airspy ## Setup * [Configuring a system](docs/CONFIGURE.md) +* [Uploading to OpenMHz](./docs/OpenMHz.md) * [FAQ](docs/FAQ.md) + +### Playback & Sharing +By default, Trunk Recorder just dumps a lot of recorded files into a directory. Here are a couple of options to make it easier to browse through recordings and share them on the Internet. +* [OpenMHz](https://github.com/robotastic/trunk-recorder/wiki/Uploading-to-OpenMHz): This is my free hosted platform for sharing recordings +* [Trunk Player](https://github.com/ScanOC/trunk-player): A great Python based server, if you want to you want to run your own +* [Rdio Scanner](https://github.com/chuot/rdio-scanner): Provide a good looking, scanner style interface for listening to Trunk Recorder +* Broadcastify Calls (API): see Radio Reference [forum thread](https://forums.radioreference.com/threads/405236/) and [wiki page](https://wiki.radioreference.com/index.php/Broadcastify-Calls-Trunk-Recorder) +* [Broadcastify via Liquidsoap](https://github.com/robotastic/trunk-recorder/wiki/Streaming-online-to-Broadcastify-with-Liquid-Soap) +* [audioplayer.php](https://github.com/robotastic/trunk-recorder/wiki/Using-audioplayer.php) +* [rosecitytransit's Live Web page](https://github.com/rosecitytransit/trunk-recorder-daily-log) + +### Plugins + +* [MQTT Status](https://github.com/taclane/trunk-recorder-mqtt-status): Publishes the current status of a Trunk Recorder instance over MQTT +* [MQTT Statistics](https://github.com/robotastic/trunk-recorder-mqtt-statistics): Publishes statistics about a Trunk Recorder instance over MQTT +* [Decode rates logger](https://github.com/rosecitytransit/trunk-recorder-decode-rate): Logs trunking control channel decode rates to a CSV file, and includes a PHP file that outputs an SVG graph +* [Daily call log and live Web page](https://github.com/rosecitytransit/trunk-recorder-daily-log): Creates a daily log of calls (instead of just individual JSON files) and includes an updating PHP Web page w/audio player +* [Prometheus exporter](https://github.com/USA-RedDragon/trunk-recorder-prometheus): Publishes statistics to a metrics endpoint via HTTP + ### Troubleshooting -If are having trouble, check out the [FAQ](./FAQ.md) and/or ask a question on the [Discord Server](https://discord.gg/btJAhESnks) +If are having trouble, check out the [FAQ](docs/FAQ.md) and/or ask a question on the [Discord Server](https://discord.gg/btJAhESnks) + ## How Trunking Works For those not familiar, trunking systems allow a large number of user groups to share a limited number of radio frequencies by temporarily, dynamically assigning radio frequencies to talkgroups (channels) on-demand. It is understood that most user groups actually use the radio very sporadically and don't need a dedicated frequency. @@ -64,4 +98,4 @@ Most trunking system types (such as SmartNet and P25) set aside one of the radio In order to follow all of the transmissions, Trunk Recorder constantly listens to and decodes the control channel. When a frequency is granted to a talkgroup, Trunk Recorder creates a monitoring process which decodes the portion of the radio spectrum for that frequency from the SDR that is already pulling it in. -No message is transmitted on the control channel when a conversation on a talkgroup is over. The monitoring process keeps track of transmissions and if there has been no activity for a specified period, it ends the recording. +No message is transmitted on the control channel when a conversation on a talkgroup is over. The monitoring process keeps track of transmissions and if there has been no activity for a specified period, it ends the recording. \ No newline at end of file From ab0d77212d2098023833c82898c3589cfe09d291 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 3 Jun 2025 15:56:14 -0400 Subject: [PATCH 2/2] Updated MacOS install --- docs/Install/INSTALL-MAC.md | 41 +++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/docs/Install/INSTALL-MAC.md b/docs/Install/INSTALL-MAC.md index 875bf4c..c3132e8 100644 --- a/docs/Install/INSTALL-MAC.md +++ b/docs/Install/INSTALL-MAC.md @@ -6,18 +6,19 @@ sidebar_position: 4 There are two main "package managers" used on MacOS: [Homebrew](#using-homebrew) and [MacPorts](#using-macports). Trunk-recorder can be installed with dependencies from one or the other ## Using Homebrew -Tested on macOS Ventura 13.2 with the following packages: +Tested on macOS Sequoia 15.5 with the following packages: -- homebrew 3.6.21 -- cmake 3.25.2 -- gnuradio 3.10.5.1 -- uhd 4.4.0.0 -- pkgconfig 0.29.2 +- homebrew 4.5.3 +- cmake 4.0.2 +- gnuradio 3.10.12.0_1 +- uhd 4.8.0.0_1 +- pkgconfig 2.4.3 - cppunit 1.15.1 -- openssl 3.0.7 -- fdk-aac-encoder 1.0.3 -- sox 14.4.2 -- pybind11 2.10.3 +- openssl 3.5.0 +- fdk-aac-encoder 2.0.3 +- sox 14.4.2_6 +- pybind11 2.13.6_1 +- six 1.17.0 #### Install Homebrew See [the Brew homepage](https://brew.sh) for more information. @@ -25,9 +26,19 @@ See [the Brew homepage](https://brew.sh) for more information. /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" ``` +#### Installing using the Trunk Recorder Tap + +Trunk Recorder can be installed easily by adding the repository to homebrew. More information can be found on [this github repo](https://github.com/TrunkRecorder/homebrew-install). Install can be done easily with the following commands. +``` +brew tap trunkrecorder/install +brew install trunk-recorder +``` + +If you prefer to install packages individually or without adding the repository, it can be done using the instructions below. + #### Install GNURadio and other dependencies ```bash -brew install gnuradio uhd cmake pkgconfig cppunit openssl fdk-aac-encoder sox pybind11 +brew install gnuradio uhd cmake pkgconfig cppunit openssl fdk-aac-encoder sox pybind11 six ``` #### Install the OsmoSDR Package for GNURadio See the gr-osmosdr [homepage](https://osmocom.org/projects/gr-osmosdr/wiki/GrOsmoSDR) for more information. @@ -71,7 +82,7 @@ sudo port selfupdate #### Install GNU Radio -The preferred method for [installing GNU Radio](http://gnuradio.org/redmine/projects/gnuradio/wiki/InstallingGR) on macOS is: +The preferred method for [installing GNU Radio](https://wiki.gnuradio.org/index.php?title=MacInstall) on macOS is: ```bash sudo port install gnuradio uhd gr-osmosdr @@ -111,7 +122,7 @@ sudo make install #### Building Trunk Recorder ```bash mkdir trunk-recorder && cd trunk-recorder -git clone https://github.com/robotastic/trunk-recorder.git source +git clone https://github.com/TrunkRecorder/trunk-recorder.git source mkdir build && cd build cmake ../source -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl make -j @@ -120,11 +131,11 @@ sudo make install ## Configuring Trunk Recorder -The next step is to [configure Trunk Recorder](CONFIGURE.md) for the system you are trying to capture. +The next step is to [configure Trunk Recorder](../CONFIGURE.md) for the system you are trying to capture. ## Running trunk recorder. -If all goes well you should now have the executable named `trunk-recorder`, and created the `config.json` configuration file as described in the [Wiki](https://github.com/robotastic/trunk-recorder/wiki/Configuring-a-System) and [README](https://github.com/robotastic/trunk-recorder/blob/master/README.md#configure). +If all goes well you should now have the executable named `trunk-recorder`, and created the `config.json` configuration file as described in the [Wiki](https://github.com/TrunkRecorder/trunk-recorder/wiki/Configuring-a-System) and [Configuring Trunk Recorder](https://github.com/TrunkRecorder/trunk-recorder/blob/master/docs/CONFIGURE.md). From your build directory (e.g. `trunk-build`) you can now run `./trunk-recorder`