mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ba9953d33 | ||
|
|
bb2199ee84 | ||
|
|
4efec4e4ef | ||
|
|
12cf9aa80f | ||
|
|
e5a42dbb11 | ||
|
|
67eaeadc03 |
@@ -1,4 +1,4 @@
|
||||
project(dsd-fme)
|
||||
project(dsd-fme-lite)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
@@ -38,24 +38,24 @@ list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c")
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||
ADD_EXECUTABLE(dsd-fme-lite ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme-lite ${LIBS})
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS dsd-fme-lite DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# man page
|
||||
find_program(HELP2MAN_FOUND help2man)
|
||||
if (HELP2MAN_FOUND)
|
||||
add_custom_command(TARGET dsd-fme POST_BUILD
|
||||
add_custom_command(TARGET dsd-fme-lite POST_BUILD
|
||||
COMMAND help2man
|
||||
ARGS -n "Digital Speech Decoder"
|
||||
--version-string=${GIT_TAG}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1
|
||||
--no-info
|
||||
$<TARGET_FILE:dsd-fme>
|
||||
$<TARGET_FILE:dsd-fme-lite>
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
|
||||
12
README.md
12
README.md
@@ -1,8 +1,11 @@
|
||||
## Notice
|
||||
|
||||
This branch is for modifications to make a Windows 32-bit binary to be precompiled, please DO NOT use this branch if you are a Linux User, or copy any contents out of here to modify your existing setup!
|
||||
|
||||
# Digital Speech Decoder - Florida Man Edition
|
||||
|
||||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25") along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, etc, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users, so please understand that this version may not compile or run correctly in other environments.
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
||||
|
||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu and others for the many hours of wav samples submitted by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. Thank you everybody.
|
||||
|
||||
@@ -16,11 +19,11 @@ Click image below for video of current DMR/P25 trunking capabilities.
|
||||
|
||||
## Information
|
||||
|
||||
See the example folder for information on cloning, installing, example usage, and trunking features.
|
||||
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/main/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/main/examples/trunking.sh "trunking examples").
|
||||
|
||||
## Notice
|
||||
|
||||
The pulseaudio branch will hearby be for legacy use as the promotion of this version to main branch will obsolete that branch. Any pre-compiled windows versions found in the release link will be considered legacy as well, and do not feature trunking support and have older handling for some other modes. Users are free to use those, but keep in mind the use case syntax may and will be different between versions. Furthermore, any wiki articles made for windows users may contain outdated information for building the pulseaudio branch, please adjust any information found in those accordingly.
|
||||
The pulseaudio branch has been deleted in favor of the new main branch which also uses Pulse Audio. Users moving to the main branch should review the help file and example usage files for changes in syntax. Users can download the last pulse audio branch version from the release link if they prefer the older version. Any pre-compiled windows versions found in the release link will be considered legacy as well, and do not feature trunking support and have older handling for some other modes. Users are free to use those, but keep in mind the use case syntax may and will be different between versions. Furthermore, any wiki articles with 'auto intstall scripts' made for windows users may contain outdated information for building the deleted pulseaudio branch, please adjust any information found in those accordingly.
|
||||
|
||||
## License
|
||||
Copyright (C) 2010 DSD Author
|
||||
@@ -37,5 +40,4 @@ GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||
echo This will clone, build, and install DSD-FME only.
|
||||
echo If you need dependencies installed, please run download-and-install.sh instead.
|
||||
echo
|
||||
|
||||
read -p "Press enter to continue"
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
@@ -1,67 +0,0 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||
echo MBELib is considered a requirement on this build.
|
||||
echo You must view this notice prior to continuing.
|
||||
echo The Patent Notice can be found at the site below.
|
||||
echo https://github.com/lwvmobile/mbelib#readme
|
||||
echo Please confirm that you have viewed the patent notice by entering y below.
|
||||
echo
|
||||
echo y/N
|
||||
read ANSWER
|
||||
Y='y'
|
||||
if [[ $Y == $ANSWER ]]; then
|
||||
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev
|
||||
|
||||
echo ITPP Manual Build and Install has been temporarily removed from this script due to issues with older versions of Ubuntu.
|
||||
echo Please check to see that libitpp-dev has successfully been downloaded and installed from the repo.
|
||||
read -p "Press enter to continue"
|
||||
|
||||
#wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
||||
#tar xjf itpp*
|
||||
#if you can't cd into this folder, double check folder name first
|
||||
#cd itpp-4.3.1
|
||||
#mkdir build
|
||||
#cd build
|
||||
#cmake ..
|
||||
#make -j `nproc`
|
||||
#sudo make install
|
||||
#sudo ldconfig
|
||||
#cd ..
|
||||
#cd ..
|
||||
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
else
|
||||
echo
|
||||
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
|
||||
fi
|
||||
|
||||
|
||||
|
||||
BIN
dsd-fme.png
BIN
dsd-fme.png
Binary file not shown.
|
Before Width: | Height: | Size: 706 KiB |
BIN
dsd-fme2.png
BIN
dsd-fme2.png
Binary file not shown.
|
Before Width: | Height: | Size: 315 KiB |
BIN
dsd-fme3.png
BIN
dsd-fme3.png
Binary file not shown.
|
Before Width: | Height: | Size: 692 KiB |
@@ -1,3 +1,7 @@
|
||||
## Notice
|
||||
|
||||
These examples will need to be modified to run on the 'lite' branch, or any precompiled Windows binaries released. (i.e. dsd-fme to dsd-fme-lite.exe, -i pulse -o pulse, etc)
|
||||
|
||||
### Example Usage and Notes!
|
||||
|
||||
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25 (1 and 2) . To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
|
||||
@@ -108,7 +112,7 @@ Trunking Note1: All samples above can also be run with the RTL input method and
|
||||
|
||||
Trunking Note2: CQPSK Phase 1 and Phase 2 Systems are subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
|
||||
|
||||
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but using channel 0 as the control channel will hardset that frequency to the control channel. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus channel numbering (as best as I can figure it) into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the Cd (channel decimal) values from the log, and not the C+ (dsdplus) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
|
||||
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but setting a fake channel number (i.e. 999) first with the CC frequency will result in finding the CC faster on startup if desired. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus channel numbering (as best as I can figure it, but they seem consistent) into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the Cd (channel decimal) values from the log, and not the C+ (dsdplus) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
|
||||
|
||||
```
|
||||
Talkgroup Voice Channel Grant (TV_GRANT) - Logical
|
||||
@@ -138,18 +142,21 @@ z - toggle console payloads
|
||||
a - toggle call alert beep
|
||||
4 - force dmr privacy key assertion over fid and svc bits
|
||||
i - toggle signal inversion on types that can't auto detect (dmr, dpmr)
|
||||
m - toggle c4fm/cqpsk 10/4 (everything but phase 2 signal)
|
||||
M - toggle c4fm/cqpsk 8/3 (phase 2 tdma control channel)
|
||||
t - toggle trunking (needs either rtl input, or rigctl setup at CLI)
|
||||
m - toggle c4fm/qpsk 10/4 (everything but phase 2 signal)
|
||||
M - toggle c4fm/qpsk 8/3 (phase 2 tdma control channel)
|
||||
R - start capturing symbol capture bin (date/time name file)
|
||||
r - stop capturing symbol capture bin
|
||||
spacebar - replay last symbol capture bin (captures must be stopped first)
|
||||
s - stop playing symbol capture bin or wav input file
|
||||
P - start per call decoded wav files
|
||||
p - stop per call decoded wav files
|
||||
t - toggle trunking (needs either rtl input, or rigctl connection)
|
||||
1 - Lockout Tuning/Playback of TG in Slot 1 or Conventional (Current Session Only)
|
||||
2 - Lockout Tuning/Playback of TG in Slot 2 (Current Session Only)
|
||||
0 - Toggle Audio Smoothing - May produce crackling if enabled on RTL/TCP or wav/bin files
|
||||
w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode
|
||||
g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25)
|
||||
u - Toggle Trunking Tuning to Private Calls (DMR T3, P25)
|
||||
d - Toggle Trunking Tuning to Data Calls (DMR T3)
|
||||
|
||||
```
|
||||
@@ -1,3 +1,7 @@
|
||||
## Notice
|
||||
|
||||
These should not be followed for the 'lite' branch
|
||||
|
||||
## How to clone and build this branch
|
||||
|
||||
### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer:
|
||||
@@ -71,6 +75,9 @@ cd ..
|
||||
cd ..
|
||||
```
|
||||
|
||||
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
|
||||
`sudo cp libmbe* /usr/lib`
|
||||
|
||||
Finish by running these steps to clone and build DSD-FME.
|
||||
|
||||
```
|
||||
|
||||
@@ -47,11 +47,14 @@
|
||||
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
//OSS support
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
#include <pulse/simple.h> //PULSE AUDIO
|
||||
#include <pulse/error.h> //PULSE AUDIO
|
||||
|
||||
#define SAMPLE_RATE_IN 48000 //48000
|
||||
#define SAMPLE_RATE_OUT 8000 //8000,
|
||||
#define SAMPLE_RATE_OUT 48000 //8000,
|
||||
|
||||
#ifdef USE_RTLSDR
|
||||
#include <rtl-sdr.h>
|
||||
@@ -190,6 +193,7 @@ typedef struct
|
||||
int audio_in_type;
|
||||
char audio_out_dev[1024];
|
||||
int audio_out_fd;
|
||||
int audio_out_fdR; //right channel audio for OSS hack
|
||||
SNDFILE *audio_out_file;
|
||||
SF_INFO *audio_out_file_info;
|
||||
|
||||
@@ -339,12 +343,18 @@ typedef struct
|
||||
//Trunking - Use Group List as Allow List
|
||||
uint8_t trunk_use_allow_list;
|
||||
|
||||
//Trunking - Tune Group Calls
|
||||
uint8_t trunk_tune_group_calls;
|
||||
|
||||
//Trunking - Tune Private Calls
|
||||
uint8_t trunk_tune_private_calls;
|
||||
|
||||
//Trunking - Tune Data Calls...why?
|
||||
//Trunking - Tune Data Calls
|
||||
uint8_t trunk_tune_data_calls;
|
||||
|
||||
//OSS audio - slot preference
|
||||
uint8_t slot_preference;
|
||||
|
||||
} dsd_opts;
|
||||
|
||||
typedef struct
|
||||
@@ -506,7 +516,6 @@ typedef struct
|
||||
char slot2light[8];
|
||||
int directmode;
|
||||
|
||||
char dmr_branding[99];
|
||||
int dmr_stereo_payload[144]; //load up 144 dibit buffer for every single DMR TDMA frame
|
||||
uint8_t data_header_blocks[2]; //collect number of blocks to follow from data header per slot
|
||||
uint8_t data_header_padding[2]; //collect number of padding octets in last block per slot
|
||||
@@ -634,8 +643,9 @@ typedef struct
|
||||
//dmr late entry mi
|
||||
uint64_t late_entry_mi_fragment[2][7][3];
|
||||
|
||||
//char dmr_branding[25]; //may need higher value?
|
||||
char dmr_branding_sub[25];
|
||||
//dmr manufacturer branding and sub_branding (i.e., Motorola and Con+)
|
||||
char dmr_branding[99];
|
||||
char dmr_branding_sub[99];
|
||||
|
||||
//Remus DMR End Call Alert Beep
|
||||
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
||||
|
||||
16
rebuild.sh
16
rebuild.sh
@@ -1,16 +0,0 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition
|
||||
echo Automatic Git Pull and Rebuild
|
||||
echo
|
||||
sleep 1
|
||||
##Open your clone folder##
|
||||
git pull
|
||||
sleep 2
|
||||
##cd into your build folder##
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
@@ -81,7 +81,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
//end collecting data header info
|
||||
|
||||
fprintf (stderr, "%s ", KMAG);
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
|
||||
if (state->data_header_sap[slot] == 0x4 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
|
||||
15
src/dmr_bs.c
15
src/dmr_bs.c
@@ -347,9 +347,22 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
// if ( opts->audio_in_type == 5 && internalslot == 0 && state->dmrburstR != 16 ) //(OSS shim)
|
||||
// {
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
// }
|
||||
// if ( opts->audio_in_type == 5 && internalslot == 1 && state->dmrburstL != 16 ) //(OSS shim)
|
||||
// {
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
// }
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
292
src/dmr_csbk.c
292
src/dmr_csbk.c
@@ -37,14 +37,23 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
csbk_pf = ( (cs_pdu[1] & 0x80) >> 7);
|
||||
csbk = ((cs_pdu[0] & 0x3F) << 8) | cs_pdu[1]; //opcode and fid combo set
|
||||
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
if (csbk_fid != 0) state->dmr_mfid = csbk_fid;
|
||||
//update time to prevent random 'Control Channel Signal Lost' hopping
|
||||
//in the middle of voice call on current Control Channel (con+ and t3)
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
|
||||
//TIII standard with fid of 0 - (opcodes in decimal)
|
||||
if (0 == 0) //some non-standard fid values (0x58 - tait, 0x68 - hytera, 0x10-motcapmax) also use a good chunk of these
|
||||
if (csbk_pf == 1) //check the protect flag, don't run if set
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "\n Protected Control Signalling Block(s)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (csbk_pf == 0) //okay to run
|
||||
{
|
||||
|
||||
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
if (csbk_fid != 0) state->dmr_mfid = csbk_fid;
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
//7.1.1.1.1 Channel Grant CSBK/MBC PDU
|
||||
@@ -138,18 +147,31 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
(stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
}
|
||||
|
||||
//Skip tuning private calls if private calls are disabled
|
||||
if (opts->trunk_tune_private_calls == 0 && csbk_o != 49) goto SKIPCALL;
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0 && csbk_o == 49) goto SKIPCALL;
|
||||
|
||||
//Allow tuning of data calls if user wishes by flipping the csbk_o to a group voice call
|
||||
if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54)
|
||||
{
|
||||
if (opts->trunk_tune_data_calls == 1) csbk_o = 49;
|
||||
}
|
||||
|
||||
//Skip tuning private calls if private calls are disabled
|
||||
if (opts->trunk_tune_private_calls == 0 && csbk_o != 49) goto SKIPCALL;
|
||||
|
||||
//if not a data channel grant (only tuning to voice channel grants)
|
||||
if (csbk_o == 48 || csbk_o == 49 || csbk_o == 50 || csbk_o == 53) //48, 49, 50 are voice grants, 51 and 52 are data grants, 53 Duplex Private Voice, 54 Duplex Private Data
|
||||
{
|
||||
//TIII tuner fix if voice assignment occurs to the control channel itself,
|
||||
//then it may not want to resume tuning due to no framesync loss after call ends
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
opts->p25_is_tuned = 0;
|
||||
//zero out vc frequencies
|
||||
state->p25_vc_freq[0] = 0;
|
||||
state->p25_vc_freq[1] = 0;
|
||||
}
|
||||
|
||||
//shim in here for ncurses freq display when not trunking (playback, not live)
|
||||
if (opts->p25_trunk == 0 && freq != 0)
|
||||
{
|
||||
@@ -463,17 +485,19 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
n = 10;
|
||||
}
|
||||
|
||||
//disabled until this can be sorted/fleshed out by type, going to use aloha only for now
|
||||
|
||||
//honestly can't say that this is accurate, just a guess
|
||||
uint8_t is_capmax = 0; //capmax(mot) flag
|
||||
if (csbk_fid == 0x10)
|
||||
{
|
||||
n = 0;
|
||||
is_capmax = 1;
|
||||
opts->dmr_dmrla_is_set = 1;
|
||||
opts->dmr_dmrla_n = 0;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "CapMax ");
|
||||
}
|
||||
// uint8_t is_capmax = 0; //capmax(mot) flag
|
||||
// if (csbk_fid == 0x10)
|
||||
// {
|
||||
// n = 0;
|
||||
// is_capmax = 1;
|
||||
// opts->dmr_dmrla_is_set = 1;
|
||||
// opts->dmr_dmrla_n = 0;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "CapMax ");
|
||||
// }
|
||||
|
||||
if (opts->dmr_dmrla_is_set == 1) n = opts->dmr_dmrla_n;
|
||||
|
||||
@@ -497,52 +521,124 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
uint32_t parms2 = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
lpchannum = parms2 & 0xFFF; //7.2.19.7, for DSDPlus, this value is (lpchannum << 1) + 1;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
if (n != 0) fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d Cat: %s Cd: %d C+: %d", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
else fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d Cat: %s Cd: %d C+: %d", model_str, net, site, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
if (is_capmax) fprintf (stderr, " Capacity Max");
|
||||
//disabled until this can be sorted/fleshed out by type, going to use aloha only for now
|
||||
|
||||
//add string for ncurses terminal display, if not adjacent site info
|
||||
if (a_type != 6 && n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1);
|
||||
if (a_type != 6 && n == 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
|
||||
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
|
||||
//sprintf(state->dmr_branding_sub, "%s", "");
|
||||
// if (a_type == 2 || a_type == 7)
|
||||
// {
|
||||
// fprintf (stderr, "\n");
|
||||
// if (n != 0) fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d Cat: %s Cd: %d C+: %d", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
// else fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d Cat: %s Cd: %d C+: %d", model_str, net, site, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
// if (is_capmax) fprintf (stderr, " Capacity Max");
|
||||
|
||||
// //add string for ncurses terminal display, if not adjacent site info
|
||||
// if (a_type != 6 && n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1);
|
||||
// if (a_type != 6 && n == 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
// }
|
||||
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
|
||||
//fprintf (stderr, "\n SYSCODE: %016b", syscode);
|
||||
//fprintf (stderr, "\n SYSCODE: %04X", syscode);
|
||||
|
||||
}
|
||||
|
||||
if (csbk == 28)
|
||||
if (csbk_o == 28)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_AHOY (TODO)");
|
||||
fprintf (stderr, " C_AHOY (TODO) ");
|
||||
}
|
||||
|
||||
if (csbk == 42)
|
||||
if (csbk_o == 42)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " P_MAINT (TODO)");
|
||||
fprintf (stderr, " P_MAINT (TODO) ");
|
||||
}
|
||||
|
||||
if (csbk == 30)
|
||||
if (csbk_o == 30)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_ACKVIT (TODO)");
|
||||
fprintf (stderr, " C_ACKVIT (TODO) ");
|
||||
}
|
||||
|
||||
if (csbk == 31)
|
||||
if (csbk_o == 31)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_RAND (TODO)");
|
||||
fprintf (stderr, " C_RAND (TODO) ");
|
||||
}
|
||||
|
||||
//tier 2 csbks
|
||||
if (csbk_o == 4)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Unit to Unit Voice Service Request (UU_V_Req) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
}
|
||||
|
||||
if (csbk_o == 5)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Unit to Unit Voice Service Answer Response (UU_Ans_Req) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 7)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Channel Timing CSBK (CT_CSBK) ");
|
||||
}
|
||||
|
||||
if (csbk_o == 38)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Negative Acknowledgement Response (NACK_Rsp) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 56)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " BS Outbound Activation (BS_Dwn_Act) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
}
|
||||
|
||||
if (csbk_o == 61)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Preamble CSBK - ");
|
||||
uint8_t content = cs_pdu_bits[16];
|
||||
uint8_t gi = cs_pdu_bits[17];
|
||||
uint8_t res = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[18], 6);
|
||||
uint8_t blocks = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24], 8);
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
|
||||
if (gi == 0) fprintf (stderr, "Individual ");
|
||||
else fprintf (stderr, "Group ");
|
||||
|
||||
if (content == 0) fprintf (stderr, "CSBK - ");
|
||||
else fprintf (stderr, "Data - ");
|
||||
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
}
|
||||
//end tier 2 csbks
|
||||
|
||||
}
|
||||
|
||||
//Capacity+ Section
|
||||
@@ -618,6 +714,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
|
||||
|
||||
//don't tune if currently a vc on the current channel
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
@@ -670,15 +769,13 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
}
|
||||
|
||||
}
|
||||
SKIPCAP: ; //do nothing
|
||||
}
|
||||
|
||||
//Connect+ Section
|
||||
if (csbk_fid == 0x06)
|
||||
{
|
||||
|
||||
//maintain this to allow users to hardset the cc freq as map[0]; otherwise, set from rigctl or rtl freq
|
||||
// if (state->p25_cc_freq == 0 && state->trunk_chan_map[0] != 0) state->p25_cc_freq = state->trunk_chan_map[0];
|
||||
|
||||
if (csbk_o == 0x01)
|
||||
{
|
||||
//initial line break
|
||||
@@ -713,6 +810,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCON;
|
||||
|
||||
//if using rigctl we can set an unknown or updated cc frequency
|
||||
//by polling rigctl for the current frequency
|
||||
if (opts->use_rigctl == 1 && opts->p25_is_tuned == 0) //&& state->p25_cc_freq == 0
|
||||
@@ -752,7 +852,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
}
|
||||
|
||||
//don't tune if currently a vc on the control channel
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
if ( (opts->trunk_tune_group_calls == 1) && (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
|
||||
if (state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0) )
|
||||
@@ -784,72 +884,70 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
}
|
||||
}
|
||||
|
||||
SKIPCON: ; //do nothing
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 0x06)
|
||||
//upon further examination, opcodes 6 and C (12) do not appear to be a channel grants or tlcs,
|
||||
//it is present in Connect+, but its purpose isn't entirely clear
|
||||
//DSDPlus only regards it as a 'CSBK [LB=1 CSBKO=6 (?) FID=06 v1=115213 v2=10488576 v3=0]
|
||||
//unsure of what the v1 v2 v3 fields specify
|
||||
// if (csbk_o == 0x06 || csbk_o == 0x0C)
|
||||
if (csbk_o != 0x01 && csbk_o != 0x03)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 ) ;
|
||||
uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 );
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Data Channel Grant\n");
|
||||
fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
|
||||
uint32_t v1 = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t v2 = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint32_t v3 = ( (cs_pdu[7] << 16) + (cs_pdu[8] << 8) + cs_pdu[9] );
|
||||
|
||||
// debug print
|
||||
// initial line break
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " Connect Plus CSBK 0x%X\n", csbk_o);
|
||||
// fprintf (stderr, " v1(%d), v2(%d), v3(%d)",v1, v2, v3);
|
||||
// state->dmr_mfid = 0x06;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
if (csbk_o == 0x0C)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 );
|
||||
uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 );
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Terminate Channel Grant\n");
|
||||
fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
//the validity of these last three csbk opcodes cannot be confirmed
|
||||
//I recall making these based on observation and speculation long ago,
|
||||
//but cannot verify the accuracy of them now, so they will remain disabled
|
||||
//they offer no particular interest to trunking/listening
|
||||
|
||||
if (csbk_o == 0x11)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Registration Request");
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
// if (csbk_o == 0x11)
|
||||
// {
|
||||
// //initial line break
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " Connect Plus Registration Request");
|
||||
// state->dmr_mfid = 0x06;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
// }
|
||||
|
||||
if (csbk_o == 0x12)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Registration Response");
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
// if (csbk_o == 0x12)
|
||||
// {
|
||||
// //initial line break
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " Connect Plus Registration Response");
|
||||
// state->dmr_mfid = 0x06;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
// }
|
||||
|
||||
if (csbk_o == 0x18)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Talkgroup Affiliation");
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
// if (csbk_o == 0x18)
|
||||
// {
|
||||
// //initial line break
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " Connect Plus Talkgroup Affiliation");
|
||||
// state->dmr_mfid = 0x06;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
// }
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
|
||||
@@ -319,8 +319,8 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
//con+ voice channels can have extremely long idle periods without properly tearing down
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->is_con_plus == 1)
|
||||
{
|
||||
//at 3 seconds, the CC was sending back to the VC even without voice present, increased to 5
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 5) )
|
||||
//bug fixed that caused hopping from CC to VC; decreased to 2 seconds.
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
if (opts->use_rigctl == 1) //rigctl tuning
|
||||
{
|
||||
|
||||
@@ -71,7 +71,19 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
{
|
||||
is_gps = 1;
|
||||
if (fid == 0) dmr_embedded_gps(opts, state, lc_bits); //issues with fid 0x10 and flco 0x08
|
||||
|
||||
//NOTE: fid 0x10 and flco 0x08 produces a lot of 'zero' lat or lon values, I don't believe this is embedded gps
|
||||
//this has been observed to happen often on CapMax systems, so I believe it could be some CapMax 'thing'
|
||||
//Unknown Link Control - FLCO=0x08 FID=0x10 SVC=0xC1 or FLCO=0x08 FID=0x10 SVC=0xC0 <-- have the enc bit set on svc, but these calls aren't enc?
|
||||
//is this an encrypted embedded link control?
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " Slot %d Unknown EMB LC - FLCO=0x%02X FID=0x%02X SVC=0x%02X ", slot+1, flco, fid, so);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//will want to continue to observe for different flco and fid combinations to find out their meaning
|
||||
@@ -549,24 +561,20 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
|
||||
if (slco == 0x2) //C_SYS_Parms
|
||||
{
|
||||
if (n != 0) fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Reg Req: %d - CSC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg, csc);
|
||||
else fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - CSC: %d ", model_str, net, site, reg, csc);
|
||||
if (n != 0) fprintf (stderr, " SLC_C_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Reg Req: %d - CSC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg, csc);
|
||||
else fprintf (stderr, " SLC_C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - Capacity Max ", model_str, net, site, reg);
|
||||
|
||||
//add string for ncurses terminal display
|
||||
if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
|
||||
else sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
|
||||
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
|
||||
|
||||
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
|
||||
{
|
||||
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||
}
|
||||
|
||||
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
|
||||
//sprintf(state->dmr_branding_sub, "%s", "");
|
||||
|
||||
//debug print
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
||||
//fprintf (stderr, "\n SYSCODE: %014b", syscode);
|
||||
@@ -575,15 +583,13 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
}
|
||||
else if (slco == 0x3) //P_SYS_Parms
|
||||
{
|
||||
fprintf (stderr, " P_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Comp CC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg);
|
||||
if (n != 0) fprintf (stderr, " SLC_P_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Comp CC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg);
|
||||
else fprintf (stderr, " SLC_P_SYS_PARMS - %s - Net ID: %d Site ID: %d - Capacity Max", model_str, net, site);
|
||||
|
||||
//add string for ncurses terminal display
|
||||
if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
|
||||
else sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
|
||||
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
|
||||
//sprintf(state->dmr_branding_sub, "%s", "");
|
||||
|
||||
//debug print
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
||||
//fprintf (stderr, "\n SYSCODE: %014b", syscode);
|
||||
|
||||
@@ -444,17 +444,18 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (state->audio_out_idx > opts->delay)
|
||||
{
|
||||
// output synthesized speech to sound card
|
||||
if(opts->audio_out_type == 2)
|
||||
{
|
||||
//go F yourself PA
|
||||
}
|
||||
else
|
||||
if (opts->audio_out_type == 5) //OSS
|
||||
{
|
||||
//Test just sending it straight on since I think I've figured out the STDIN and RTL for Stereo
|
||||
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works.
|
||||
//OSS
|
||||
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
||||
state->audio_out_idx = 0;
|
||||
}
|
||||
else if (opts->audio_out_type == 0)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL);
|
||||
state->audio_out_idx = 0;
|
||||
}
|
||||
else state->audio_out_idx = 0; //failsafe for audio_out == 0
|
||||
|
||||
|
||||
}
|
||||
@@ -478,15 +479,18 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
||||
if (state->audio_out_idxR > opts->delay)
|
||||
{
|
||||
// output synthesized speech to sound card
|
||||
if(opts->audio_out_type == 2)
|
||||
{
|
||||
//go F yourself PA
|
||||
}
|
||||
else
|
||||
if (opts->audio_out_type == 5) //OSS
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works.
|
||||
//OSS
|
||||
result = write (opts->audio_out_fdR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2));
|
||||
state->audio_out_idxR = 0;
|
||||
}
|
||||
else if (opts->audio_out_type == 0)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL);
|
||||
state->audio_out_idxR = 0;
|
||||
}
|
||||
else state->audio_out_idxR = 0; //failsafe for audio_out == 0
|
||||
|
||||
}
|
||||
|
||||
@@ -558,6 +562,7 @@ openAudioInDevice (dsd_opts * opts)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strncmp(opts->audio_in_dev, "tcp", 3) == 0)
|
||||
{
|
||||
opts->audio_in_type = 8;
|
||||
@@ -567,13 +572,13 @@ openAudioInDevice (dsd_opts * opts)
|
||||
opts->audio_in_file_info->seekable=0;
|
||||
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||
|
||||
if(opts->tcp_file_in == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strncmp(opts->audio_in_dev, "udp", 3) == 0)
|
||||
{
|
||||
opts->audio_in_type = 6;
|
||||
@@ -598,6 +603,10 @@ openAudioInDevice (dsd_opts * opts)
|
||||
{
|
||||
opts->audio_in_type = 0;
|
||||
}
|
||||
else if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
opts->audio_in_type = 5;
|
||||
}
|
||||
else if (strncmp(extension, ".bin", 3) == 0)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
@@ -645,9 +654,11 @@ openAudioInDevice (dsd_opts * opts)
|
||||
|
||||
}
|
||||
//open pulse audio if no bin or wav
|
||||
else
|
||||
else //seems this condition is never met
|
||||
{
|
||||
opts->audio_in_type = 0; //not sure if this works or needs to openPulse here
|
||||
//opts->audio_in_type = 5; //not sure if this works or needs to openPulse here
|
||||
fprintf(stderr, "Error, couldn't open input file.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (opts->split == 1)
|
||||
|
||||
291
src/dsd_main.c
291
src/dsd_main.c
@@ -52,7 +52,7 @@ char * FM_banner[9] = {
|
||||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗",
|
||||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝",
|
||||
" "
|
||||
" Lite Edition v2.0.0-6-gc44e039 Windows 32-bit RC1 "
|
||||
};
|
||||
|
||||
int
|
||||
@@ -125,6 +125,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
//zero out vc frequencies?
|
||||
state->p25_vc_freq[0] = 0;
|
||||
state->p25_vc_freq[1] = 0;
|
||||
|
||||
state->is_con_plus = 0; //flag off
|
||||
}
|
||||
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
@@ -350,11 +352,12 @@ initOpts (dsd_opts * opts)
|
||||
opts->p25status = 0;
|
||||
opts->p25tg = 0;
|
||||
opts->scoperate = 15;
|
||||
sprintf (opts->audio_in_dev, "pulse");
|
||||
sprintf (opts->audio_in_dev, "/dev/dsp");
|
||||
opts->audio_in_fd = -1;
|
||||
|
||||
sprintf (opts->audio_out_dev, "pulse");
|
||||
sprintf (opts->audio_out_dev, "/dev/dsp");
|
||||
opts->audio_out_fd = -1;
|
||||
opts->audio_out_fdR = -1;
|
||||
|
||||
opts->split = 0;
|
||||
opts->playoffset = 0;
|
||||
@@ -442,10 +445,10 @@ initOpts (dsd_opts * opts)
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->dmr_mono = 0;
|
||||
opts->dmr_stereo = 1;
|
||||
opts->aggressive_framesync = 1; //more aggressive to combat wonk wonk voice decoding
|
||||
//see if initializing these values causes issues elsewhere, if so, then disable.
|
||||
opts->audio_in_type = 0; //this was never initialized, causes issues on rPI 64 (bullseye) if not initialized
|
||||
opts->audio_out_type = 0; //this was never initialized, causes issues on rPI 64 (bullseye) if not initialized
|
||||
opts->aggressive_framesync = 1;
|
||||
|
||||
opts->audio_in_type = 5;
|
||||
opts->audio_out_type = 5;
|
||||
|
||||
opts->lrrp_file_output = 0;
|
||||
|
||||
@@ -492,12 +495,21 @@ initOpts (dsd_opts * opts)
|
||||
//Trunking - Use Group List as Allow List
|
||||
opts->trunk_use_allow_list = 0; //disabled by default
|
||||
|
||||
//Trunking - Tune Group Calls
|
||||
opts->trunk_tune_group_calls = 1; //enabled by default
|
||||
|
||||
//Trunking - Tune Private Calls
|
||||
opts->trunk_tune_private_calls = 1; //enabled by default
|
||||
|
||||
//Trunking - Tune Data Calls
|
||||
opts->trunk_tune_data_calls = 0; //disabled by default
|
||||
|
||||
//OSS audio - Slot Preference
|
||||
//slot preference is used during OSS audio playback to
|
||||
//prefer one tdma voice slot over another when both are playing back
|
||||
//this is a fix to cygwin stuttering when both slots have voice
|
||||
opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
||||
|
||||
} //initopts
|
||||
|
||||
void
|
||||
@@ -723,7 +735,7 @@ initState (dsd_state * state)
|
||||
state->p25_cc_is_tdma = 2; //init on 2, TSBK NET_STS will set 0, TDMA NET_STS will set 1. //used to determine if we need to change symbol rate when cc hunting
|
||||
|
||||
//experimental symbol file capture read throttle
|
||||
state->symbol_throttle = 0; //throttle speed
|
||||
state->symbol_throttle = 100; //throttle speed
|
||||
state->use_throttle = 0; //only use throttle if set to 1
|
||||
|
||||
state->p2_scramble_offset = 0;
|
||||
@@ -829,28 +841,18 @@ usage ()
|
||||
{
|
||||
|
||||
printf ("\n");
|
||||
printf ("Usage: dsd-fme [options] Decoder/Trunking Mode\n");
|
||||
printf (" or: dsd-fme [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" or: dsd-fme -h Show help\n");
|
||||
printf ("Usage: dsd-fme-lite [options] Decoder/Trunking Mode\n");
|
||||
printf (" or: dsd-fme-lite [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" or: dsd-fme-lite -h Show help\n");
|
||||
printf ("\n");
|
||||
printf ("Display Options:\n");
|
||||
printf (" -N Use NCurses Terminal\n");
|
||||
printf (" dsd-fme -N 2> log.ans \n");
|
||||
printf (" dsd-fme-lite -N 2> log.ans \n");
|
||||
printf (" -Z Log MBE/PDU Payloads to console\n");
|
||||
// printf (" -e Show Frame Info and errorbars (default)\n");
|
||||
// printf (" -pe Show P25 encryption sync bits\n");
|
||||
// printf (" -pl Show P25 link control bits\n");
|
||||
// printf (" -ps Show P25 status bits and low speed data\n");
|
||||
// printf (" -pt Show P25 talkgroup info\n");
|
||||
// printf (" -q Don't show Frame Info/errorbars\n");
|
||||
//printf (" -s Datascope (disables other display options)\n");
|
||||
//printf (" -t Show symbol timing during sync\n");
|
||||
// printf (" -v <num> Frame information Verbosity\n");
|
||||
// printf (" -z <num> Frame rate for datascope\n");
|
||||
printf ("\n");
|
||||
printf ("Input/Output options:\n");
|
||||
printf (" -i <device> Audio input device (default is pulse audio)\n");
|
||||
printf (" - for piped stdin\n");
|
||||
printf (" -i <device> Audio input device (default is /dev/dsp)\n");
|
||||
printf (" pulse for pulse audio \n");
|
||||
printf (" rtl:dev:freq:gain:ppm:bw:sq:udp for rtl dongle (see below)\n");
|
||||
printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\n");
|
||||
printf (" tcp:192.168.7.5:7355 for custom address and port \n");
|
||||
@@ -858,8 +860,11 @@ usage ()
|
||||
printf (" filename.wav for 48K/1 wav files (SDR++, GQRX)\n");
|
||||
printf (" filename.wav -s 96000 for 96K/1 wav files (DSDPlus)\n");
|
||||
printf (" (Use single quotes '/directory/audio file.wav' when directories/spaces are present)\n");
|
||||
printf (" -s <rate> Sample Rate of wav input files (usually 48000 or 96000) Mono only!\n");
|
||||
printf (" -o <device> Audio output device (default is pulse audio)(null for no audio output)\n");
|
||||
// printf (" (Windows - '\directory\audio file.wav' backslash, not forward slash)\n");
|
||||
printf (" -s <rate> Sample Rate of wav input files (48000 or 96000) Mono only!\n");
|
||||
printf (" -o <device> Audio output device (default is /dev/dsp)\n");
|
||||
printf (" null for no audio output\n");
|
||||
printf (" pulse for pulse audio \n");
|
||||
printf (" -d <dir> Create mbe data files, use this directory\n");
|
||||
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
|
||||
@@ -871,8 +876,10 @@ usage ()
|
||||
printf (" (Warning! Might be annoying.)\n");
|
||||
printf (" -L <file> Specify Filename for LRRP Data Output.\n");
|
||||
printf (" -c <file> Output symbol capture to .bin file\n");
|
||||
printf (" -n Throttle Symbol Capture Bin Input\n");
|
||||
printf (" (useful when reading files still being written to by OP25)");
|
||||
printf (" -q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice\n");
|
||||
printf (" -V Enable Audio Smoothing on Upsampled 48k/1 or 24k/2 Audio (Capital V)\n");
|
||||
printf (" (Audio Smoothing is now disabled on all upsampled output by default -- fix crackle/buzz bug)\n");
|
||||
printf (" -z Set TDMA Voice Slot Preference when using OSS audio output (prevent lag and stuttering)\n");
|
||||
printf ("\n");
|
||||
printf ("RTL-SDR options:\n");
|
||||
printf (" WARNING! Old CLI Switch Handling has been depreciated in favor of rtl:<parms>\n");
|
||||
@@ -883,17 +890,11 @@ usage ()
|
||||
printf (" ppm <num> RTL-SDR PPM Error (default = 0)\n");
|
||||
printf (" bw <num> RTL-SDR VFO Bandwidth kHz (default = 12)(6, 8, 12, 24) \n");
|
||||
printf (" sq <num> RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)\n");
|
||||
// printf (" -V <num> RTL-SDR Sample Gain Multiplier (default = 1)\n");
|
||||
printf (" udp <num> RTL-SDR UDP Remote Port (default = 6020)\n");
|
||||
printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf (" Example: dsd-fme-lite -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf ("\n");
|
||||
// printf ("Scanner control options:\n");
|
||||
// printf (" -B <num> Serial port baud rate (default=115200)\n");
|
||||
// printf (" -C <device> Serial port for scanner control (default=/dev/ttyUSB0)\n");
|
||||
// printf (" -R <num> Resume scan after <num> TDULC frames or any PDU or TSDU\n");
|
||||
// printf ("\n");
|
||||
printf ("Decoder options:\n");
|
||||
printf (" -fa Legacy Auto Detection (old methods default)\n");
|
||||
printf (" -fa Legacy Auto Detection 8k/1 (old methods default)\n");
|
||||
printf (" -ft XDMA P25 and DMR BS/MS frame types (new default)\n");
|
||||
printf (" -fs DMR Stereo BS and MS Simplex only\n");
|
||||
printf (" -f1 Decode only P25 Phase 1\n");
|
||||
@@ -905,7 +906,6 @@ usage ()
|
||||
printf (" -fp Decode only EDACS/ProVoice*\n");
|
||||
printf (" -fm Decode only dPMR*\n");
|
||||
printf (" -l Disable DMR and NXDN input filtering\n");
|
||||
// printf (" -pu Unmute Encrypted P25\n");
|
||||
printf (" -u <num> Unvoiced speech quality (default=3)\n");
|
||||
printf (" -xx Expect non-inverted X2-TDMA signal\n");
|
||||
printf (" -xr Expect inverted DMR signal\n");
|
||||
@@ -932,7 +932,7 @@ usage ()
|
||||
printf (" -m2 Use P25p2 6000 sps CQPSK modulation optimizations\n");
|
||||
//printf (" (4 Level, not 8 Level LSM) (this is honestly unknown since I can't verify what local systems are using)\n");
|
||||
printf (" -F Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n");
|
||||
printf (" Use this feature to allow MAC_SIGNAL even if bad CRC errors.\n");
|
||||
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
|
||||
printf (" -F Relax DMR CACH/Burst FEC Pass/Fail - Passive Frame Sync\n");
|
||||
printf (" Use if skipping occurs, but may cause wonky audio due to loss of good sync\n");
|
||||
|
||||
@@ -949,23 +949,26 @@ usage ()
|
||||
printf (" \n");
|
||||
printf (" -4 Force Privacy Key over FID and SVC bits \n");
|
||||
printf ("\n");
|
||||
printf (" New and Experimental Functions and Features---------------------------------------------------\n");
|
||||
printf (" Trunking Options:\n");
|
||||
printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n");
|
||||
printf (" (See channel_map.csv for example)\n");
|
||||
printf (" -G <file> Import Group List Allow/Block and Label from csv file.\n");
|
||||
printf (" (See group.csv for example)\n");
|
||||
printf (" -T Enable Trunking Features (NXDN/P25/EDACS/DMR) with RIGCTL/TCP or RTL Input\n");
|
||||
printf (" -W Use Imported Group List as a Trunking Allow/White List -- Only Tune with Mode A\n");
|
||||
printf (" -p Don't Tune to Private Calls (DMR TIII and P25)\n");
|
||||
printf (" -p Disable Tune to Private Calls (DMR TIII and P25)\n");
|
||||
printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+ and P25)\n");
|
||||
printf (" (NOTE: NXDN and EDACS, simply disable trunking if desired) \n");
|
||||
printf (" -e Enable Tune to Data Calls (DMR TIII)\n");
|
||||
printf (" (NOTE: DMR Con+ and P25 Data Channels Not Enabled (no handling) \n");
|
||||
printf (" (NOTE: P25 Data Channels Not Enabled (no handling) \n");
|
||||
printf (" -U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)\n");
|
||||
printf (" -B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)\n");
|
||||
printf (" P25 - 7000; NXDN48 - 4000; DMR - 7000; EDACS/PV - 12500; May vary based on system stregnth, etc.\n");
|
||||
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 4000; DMR - 7000; EDACS/PV - 12500;\n");
|
||||
printf (" May vary based on system stregnth, etc.\n");
|
||||
printf (" -t <secs> Set Trunking VC/sync loss hangtime in seconds. (default = 1 second)\n");
|
||||
printf (" -q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice\n");
|
||||
printf (" -V Enable Audio Smoothing on Upsampled Audio (XDMA and DMR Stereo 24k/2 output) (Capital V)\n");
|
||||
printf (" (Audio Smoothing is now disabled on all upsampled output by default -- fix crackle/buzz bug)\n");
|
||||
printf ("\n");
|
||||
printf (" Trunking Example TCP: dsd-fme-lite -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf (" Trunking Example RTL: dsd-fme-lite -fs -i rtl:0:450M:26:-2:8:0:6020 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf ("\n");
|
||||
exit (0);
|
||||
}
|
||||
@@ -1166,8 +1169,9 @@ main (int argc, char **argv)
|
||||
}
|
||||
//fprintf (stderr,"%s", KNRM); //change back to normal
|
||||
|
||||
fprintf (stderr, "Github Build Version: %s \n", GIT_TAG);
|
||||
fprintf (stderr,"MBElib version %s\n", versionstr);
|
||||
// git_tag not working in 32-bit cygwin? or issue with copy and paste, even with the .git folder?
|
||||
// fprintf (stderr, "Github Build Version: %s \n", GIT_TAG);
|
||||
// fprintf (stderr,"MBElib version %s\n", versionstr);
|
||||
|
||||
initOpts (&opts);
|
||||
initState (&state);
|
||||
@@ -1177,7 +1181,7 @@ main (int argc, char **argv)
|
||||
exitflag = 0;
|
||||
// signal (SIGINT, sigfun);
|
||||
|
||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:Y:K:H:X:NQWrlZTF01:2:345:6:7:89:")) != -1)
|
||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:Y:K:H:X:NQWrlZTF01:2:345:6:7:89:E")) != -1)
|
||||
{
|
||||
opterr = 0;
|
||||
switch (c)
|
||||
@@ -1195,6 +1199,13 @@ main (int argc, char **argv)
|
||||
|
||||
//Disabled the Serial Port Dev and Baud Rate, etc, If somebody uses that function, sorry...
|
||||
|
||||
case 'z':
|
||||
sscanf (optarg, "%d", &opts.slot_preference);
|
||||
opts.slot_preference--; //user inputs 1 or 2, internally we want 0 and 1
|
||||
if (opts.slot_preference > 1) opts.slot_preference = 1;
|
||||
fprintf (stderr, "TDMA (DMR and P2) Slot Voice Preference is Slot %d. \n", opts.slot_preference+1);
|
||||
break;
|
||||
|
||||
//Enable Audio Smoothing for Upsampled Audio
|
||||
case '0':
|
||||
case 'V':
|
||||
@@ -1207,6 +1218,12 @@ main (int argc, char **argv)
|
||||
fprintf (stderr, "Using Group List as Allow/White List. \n");
|
||||
break;
|
||||
|
||||
//Trunking - Tune Group Calls
|
||||
case 'E':
|
||||
opts.trunk_tune_group_calls = 0; //disable
|
||||
fprintf (stderr, "Disable Tuning to Group Calls. \n");
|
||||
break;
|
||||
|
||||
//Trunking - Tune Private Calls
|
||||
case 'p':
|
||||
opts.trunk_tune_private_calls = 0; //disable
|
||||
@@ -1561,7 +1578,7 @@ main (int argc, char **argv)
|
||||
opts.frame_dpmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
opts.frame_ysf = 0;
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_rate_out = 8000; //doesn't matter for /dev/dsp anyways
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 1;
|
||||
@@ -1764,11 +1781,11 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
opts.dmr_mono = 0;
|
||||
// opts.setmod_bw = 7000;
|
||||
opts.setmod_bw = 7000;
|
||||
opts.pulse_digi_rate_out = 24000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
sprintf (opts.output_name, "DMR Stereo");
|
||||
|
||||
fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
|
||||
}
|
||||
else if (optarg[0] == 't')
|
||||
@@ -1931,7 +1948,7 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 1;
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 1;
|
||||
opts.setmod_bw = 12500;
|
||||
opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling only QPSK modulation optimizations.\n");
|
||||
}
|
||||
else if (optarg[0] == '2')
|
||||
@@ -1942,7 +1959,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 1;
|
||||
state.samplesPerSymbol = 8;
|
||||
state.symbolCenter = 3;
|
||||
opts.setmod_bw = 12500;
|
||||
opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling 6000 sps P25p2 CQPSK.\n");
|
||||
}
|
||||
break;
|
||||
@@ -2056,12 +2073,14 @@ main (int argc, char **argv)
|
||||
{
|
||||
opts.audio_in_type = 8;
|
||||
state.audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing
|
||||
fprintf (stderr, "TCP Connection Success!\n");
|
||||
// openAudioInDevice(&opts); //do this to see if it makes it work correctly
|
||||
}
|
||||
else
|
||||
{
|
||||
opts.audio_in_type = 0;
|
||||
opts.audio_in_type = 5;
|
||||
fprintf (stderr, "TCP Connection Failure - Using Pulse Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2143,61 +2162,137 @@ main (int argc, char **argv)
|
||||
|
||||
if (rtl_ok == 0) //not set, means rtl support isn't compiled/available
|
||||
{
|
||||
fprintf (stderr, "RTL Support not enabled/compiled, falling back to Pulse Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
opts.audio_in_type = 0;
|
||||
fprintf (stderr, "RTL Support not enabled/compiled, falling back to OSS /dev/dsp Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
opts.audio_in_type = 5;
|
||||
}
|
||||
}
|
||||
|
||||
//still need to work out why I can't use this
|
||||
//issues with samples received, may be using UDP DGRAMS incorrectly, incorrect procedure?
|
||||
//doesn't work correctly, so just going to reroute to /dev/dsp instead
|
||||
if((strncmp(opts.audio_in_dev, "udp", 3) == 0)) //udp socket input from SDR++, GQRX, and others
|
||||
{
|
||||
//also still needs err handling
|
||||
opts.udp_sockfd = UDPBind(opts.udp_hostname, opts.udp_portno);
|
||||
opts.audio_in_type = 6;
|
||||
fprintf (stderr, "UDP Input not working, falling back to OSS /dev/dsp Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
opts.audio_in_type = 5;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_in_type = 0;
|
||||
}
|
||||
int fmt;
|
||||
int speed = 48000;
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_in_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
fprintf (stderr, "OSS Input %s.\n", opts.audio_in_dev);
|
||||
opts.audio_in_fd = open (opts.audio_in_dev, O_RDWR);
|
||||
if (opts.audio_in_fd == -1)
|
||||
{
|
||||
fprintf (stderr, "Error, couldn't open %s\n", opts.audio_in_dev);
|
||||
opts.audio_out = 0;
|
||||
}
|
||||
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl reset error \n");
|
||||
}
|
||||
fmt = speed;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl speed error \n");
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl stereo error \n");
|
||||
}
|
||||
fmt = AFMT_S16_LE;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl setfmt error \n");
|
||||
}
|
||||
|
||||
opts.audio_in_type = 5; //5 will become OSS input type
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
fprintf (stderr, "OSS Output %s.\n", opts.audio_out_dev);
|
||||
opts.audio_out_fd = open (opts.audio_out_dev, O_RDWR); //O_WRONLY
|
||||
opts.audio_out_fdR = open (opts.audio_out_dev, O_RDWR);
|
||||
if (opts.audio_out_fd == -1)
|
||||
{
|
||||
fprintf (stderr, "Error, couldn't open #1 %s\n", opts.audio_out_dev);
|
||||
opts.audio_out = 0;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (opts.audio_out_fdR == -1)
|
||||
{
|
||||
fprintf (stderr, "Error, couldn't open #2 %s\n", opts.audio_out_dev);
|
||||
opts.audio_out = 0;
|
||||
exit(1);
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl reset error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl reset error \n");
|
||||
}
|
||||
fmt = speed;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl speed error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl speed error \n");
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl stereo error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl stereo error \n");
|
||||
}
|
||||
fmt = AFMT_S16_LE;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl setfmt error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl setfmt error \n");
|
||||
}
|
||||
|
||||
opts.audio_out_type = 5; //5 will become OSS output type
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "pulse", 5) == 0))
|
||||
@@ -2231,6 +2326,7 @@ main (int argc, char **argv)
|
||||
openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
|
||||
{
|
||||
opts.split = 1;
|
||||
@@ -2265,13 +2361,14 @@ main (int argc, char **argv)
|
||||
{
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
openPulseOutput(&opts); //need to open it up for output
|
||||
// openPulseOutput(&opts); //need to open it up for output?
|
||||
openAudioInDevice (&opts); //needs to be tested, not sure if required
|
||||
playMbeFiles (&opts, &state, argc, argv);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
liveScanner (&opts, &state);
|
||||
liveScanner (&opts, &state);
|
||||
}
|
||||
|
||||
cleanupAndExit (&opts, &state);
|
||||
|
||||
@@ -126,6 +126,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
unsigned long long int k;
|
||||
int x;
|
||||
|
||||
int preempt = 0; //TDMA dual voice slot preemption(when using OSS output)
|
||||
|
||||
|
||||
for (i = 0; i < 88; i++)
|
||||
{
|
||||
@@ -522,6 +524,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
//end reverse mute test
|
||||
|
||||
//OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other
|
||||
if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstR == 16)
|
||||
{
|
||||
opts->audio_out = 0;
|
||||
preempt = 1;
|
||||
if (opts->payload == 0) fprintf (stderr, " *MUTED*");
|
||||
}
|
||||
|
||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
||||
{
|
||||
state->debug_audio_errors += state->errs2;
|
||||
@@ -578,6 +588,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
//end reverse mute test
|
||||
|
||||
//OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other
|
||||
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstL == 16)
|
||||
{
|
||||
opts->audio_out = 0;
|
||||
preempt = 1;
|
||||
if (opts->payload == 0) fprintf (stderr, " *MUTED*");
|
||||
}
|
||||
|
||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
||||
{
|
||||
state->debug_audio_errorsR += state->errs2R;
|
||||
@@ -632,6 +650,12 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
|
||||
if (preempt == 1)
|
||||
{
|
||||
opts->audio_out = 1;
|
||||
preempt = 0;
|
||||
}
|
||||
|
||||
//reset audio out flag for next repitition
|
||||
if (strcmp(mode, "B") == 0) opts->audio_out = 1;
|
||||
//restore flag for null output type
|
||||
|
||||
@@ -125,7 +125,7 @@ char * DMRBusrtTypes[32] = {
|
||||
"R-S ERR ",
|
||||
"CRC ERR ",
|
||||
"NULL ",
|
||||
"Voice ",
|
||||
"Voice ",
|
||||
" ",
|
||||
"INIT ",
|
||||
"INIT ",
|
||||
@@ -150,9 +150,10 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
|
||||
FILE *beep;
|
||||
char wav_name[1024] = {0};
|
||||
|
||||
if (opts->pulse_digi_rate_out == 8000) strncpy(wav_name, "/usr/share/tone8.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 48000) strncpy(wav_name, "/usr/share/tone48.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 24000) strncpy(wav_name, "/usr/share/tone24.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 8000) strncpy(wav_name, "tone8.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 48000) strncpy(wav_name, "tone48.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 24000) strncpy(wav_name, "tone24.wav", 1023);
|
||||
if (opts->audio_out_type == 5) strncpy(wav_name, "tone48.wav", 1023);
|
||||
wav_name[1023] = '\0';
|
||||
struct stat stat_buf;
|
||||
if (stat(wav_name, &stat_buf) == 0)
|
||||
@@ -174,17 +175,20 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
|
||||
//only beep on R if dmr_stereo is active and slot 2, else beep on L
|
||||
if (type == 0 && opts->dmr_stereo == 1 && opts->audio_out == 1)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 0) pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 5) write (opts->audio_out_fd, buf, sizeof(buf));
|
||||
//fprintf (stderr, "BEEP 0 24\n");
|
||||
}
|
||||
if (type == 1 && opts->dmr_stereo == 1 && opts->audio_out == 1)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_outR, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 0) pa_simple_write(opts->pulse_digi_dev_outR, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 5) write (opts->audio_out_fd, buf, sizeof(buf));
|
||||
//fprintf (stderr, "BEEP 1 24\n");
|
||||
}
|
||||
if (opts->dmr_stereo == 0 && opts->audio_out == 1)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 0) pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 5) write (opts->audio_out_fd, buf, sizeof(buf));
|
||||
//fprintf (stderr, "BEEP 0 8\n");
|
||||
}
|
||||
|
||||
@@ -199,7 +203,7 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
|
||||
}
|
||||
|
||||
char * getDateN(void) {
|
||||
char datename[99]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
||||
char datename[80]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
@@ -410,7 +414,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->audio_in_type == 5) //close UDP input SF file so we don't buffer audio while not decoding
|
||||
{
|
||||
sf_close(opts->udp_file_in); //disable for testing
|
||||
// sf_close(opts->udp_file_in); //disable for testing
|
||||
}
|
||||
|
||||
state->payload_keyid = 0;
|
||||
@@ -1160,7 +1164,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
opts->dmr_mono = 0;
|
||||
opts->dmr_stereo = 0; //this value is the end user option
|
||||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||||
opts->pulse_digi_rate_out = 48000;
|
||||
opts->pulse_digi_rate_out = 8000;
|
||||
opts->pulse_digi_out_channels = 1;
|
||||
opts->frame_dstar = 1;
|
||||
opts->frame_x2tdma = 1;
|
||||
@@ -1663,7 +1667,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->audio_in_type == 5) //re-open UDP input 'file'
|
||||
{
|
||||
opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||
// opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||
}
|
||||
|
||||
//update sync time on cc sync so we don't immediately go CC hunting when exiting the menu
|
||||
@@ -2057,7 +2061,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->ncurses_compact == 1)
|
||||
{
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
printw ("| Digital Speech Decoder: Florida Man Edition %s \n", GIT_TAG);
|
||||
printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-6-gc44e039 RC1");
|
||||
}
|
||||
if (opts->ncurses_compact == 0)
|
||||
{
|
||||
@@ -2067,8 +2071,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw("%s", FM_bannerN[i]);
|
||||
if (i == 1) printw (" ESC to Menu");
|
||||
if (i == 2) printw (" 'q' to Quit ");
|
||||
if (i == 5) printw (" MBElib %s", versionstr);
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
if (i == 4) printw (" MBElib %s", versionstr);
|
||||
if (i == 5) printw (" %s ", "Win32 RC1"); //printw (" %s \n", GIT_TAG);
|
||||
if (i == 6) printw (" %s \n", "v2.0.0-6-gc44e039"); //printw (" %s \n", GIT_TAG);
|
||||
else printw ("\n");
|
||||
}
|
||||
attroff(COLOR_PAIR(6)); //6
|
||||
@@ -2080,6 +2085,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
printw ("| Pulse Audio Input: [%2i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels);
|
||||
}
|
||||
if (opts->audio_in_type == 5)
|
||||
{
|
||||
printw ("| OSS Audio Input: [%2i] kHz [1] Channel\n", SAMPLE_RATE_IN);
|
||||
}
|
||||
if (opts->audio_in_type == 4)
|
||||
{
|
||||
printw ("| Direct Symbol Bin Input: %s \n", opts->audio_in_dev);
|
||||
@@ -2114,6 +2123,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
||||
printw (" \n");
|
||||
}
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
printw ("| OSS Audio Output: [%2i] kHz [1] Channel", SAMPLE_RATE_IN);
|
||||
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
||||
printw (" \n");
|
||||
}
|
||||
if (opts->monitor_input_audio == 1)
|
||||
{
|
||||
printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected\n");
|
||||
@@ -2145,11 +2160,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) )
|
||||
{
|
||||
printw ("| Trunk Tracking Active (P25/EDACS/NXDN/DMR)");
|
||||
if (opts->trunk_use_allow_list == 1)
|
||||
{
|
||||
printw (" - White List Mode\n");
|
||||
}
|
||||
printw ("| Trunk Tracking Active -");
|
||||
if (opts->trunk_tune_group_calls == 0) attron(COLOR_PAIR(2));
|
||||
printw (" Group(g)");
|
||||
attron(COLOR_PAIR(4));
|
||||
if (opts->trunk_tune_private_calls == 0) attron(COLOR_PAIR(2));
|
||||
printw (" Private(u)");
|
||||
attron(COLOR_PAIR(4));
|
||||
if (opts->trunk_tune_data_calls == 0) attron(COLOR_PAIR(2));
|
||||
printw (" Data(d)");
|
||||
attron(COLOR_PAIR(4));
|
||||
printw (" Calls");
|
||||
if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n");
|
||||
else printw (" - Black List Mode\n");
|
||||
}
|
||||
if (opts->reverse_mute == 1)
|
||||
@@ -2326,19 +2348,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (lls > 1 && lls < 30)
|
||||
{
|
||||
printw ("DMR BS - DCC: [%02i] ", dcc);
|
||||
printw ("%s %s", state->dmr_branding, state->dmr_branding_sub);
|
||||
// printw ("%s %s", state->dmr_branding, state->dmr_branding_sub);
|
||||
printw ("%s ", state->dmr_branding);
|
||||
printw ("%s", state->dmr_branding_sub);
|
||||
printw ("%s", state->dmr_site_parms); //site id, net id, etc
|
||||
if (state->dmr_rest_channel > 0)
|
||||
{
|
||||
printw ("Rest Channel: [%02d] ", state->dmr_rest_channel);
|
||||
if (state->trunk_chan_map[state->dmr_rest_channel] != 0)
|
||||
{
|
||||
printw ("%.06lf Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000);
|
||||
printw ("Freq: [%.06lf] Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000);
|
||||
}
|
||||
}
|
||||
else if (state->p25_cc_freq != 0)
|
||||
{
|
||||
printw ("%.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||||
printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2397,6 +2421,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//This is the new one
|
||||
printw ("%s | ", state->call_string[0]);
|
||||
printw ("%s ", DMRBusrtTypes[state->dmrburstL]);
|
||||
if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstR == 16 && state->dmrburstL == 16) printw ("*M*");
|
||||
printw ("\n");
|
||||
|
||||
printw ("| V XTRA | "); //10 spaces
|
||||
@@ -2592,6 +2617,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//THIS IS THE NEW ONE
|
||||
printw ("%s | ", state->call_string[1]);
|
||||
printw ("%s ", DMRBusrtTypes[state->dmrburstR]);
|
||||
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstR == 16 && state->dmrburstL == 16) printw ("*M*");
|
||||
printw ("\n");
|
||||
|
||||
printw ("| V XTRA | "); //10 spaces
|
||||
@@ -3193,6 +3219,24 @@ if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mo
|
||||
else opts->trunk_use_allow_list = 1;
|
||||
}
|
||||
|
||||
if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls
|
||||
{
|
||||
if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0;
|
||||
else opts->trunk_tune_private_calls = 1;
|
||||
}
|
||||
|
||||
if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls
|
||||
{
|
||||
if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0;
|
||||
else opts->trunk_tune_data_calls = 1;
|
||||
}
|
||||
|
||||
if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls
|
||||
{
|
||||
if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0;
|
||||
else opts->trunk_tune_group_calls = 1;
|
||||
}
|
||||
|
||||
//anything with an entry box will need the inputs and outputs stopped first
|
||||
//so probably just write a function to handle c input, and when c = certain values
|
||||
//needing an entry box, then stop all of those
|
||||
|
||||
@@ -82,35 +82,24 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
}
|
||||
|
||||
// Read the new sample from the input
|
||||
if(opts->audio_in_type == 0) // && state->menuopen == 0 still not quite working
|
||||
if(opts->audio_in_type == 0) //pulse audio
|
||||
{
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
//look into how processAudio handles playback, not sure if latency issues, or garbage sample values crash pulse when written
|
||||
// if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767)
|
||||
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample != 0)
|
||||
{
|
||||
state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here?
|
||||
pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL);
|
||||
}
|
||||
//playback is wrong, depends on samples_per_symbol, maybe make a buffer and store first?
|
||||
//making buffer might also fix raw audio monitoring as well
|
||||
if (opts->wav_out_file_raw[0] != 0) //if set for recording sample raw files
|
||||
{
|
||||
//writeRawSample (opts, state, sample);
|
||||
}
|
||||
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
}
|
||||
|
||||
else if (opts->audio_in_type == 5) //OSS
|
||||
{
|
||||
read (opts->audio_in_fd, &sample, 2);
|
||||
}
|
||||
|
||||
//stdin only, wav files moving to new number
|
||||
else if (opts->audio_in_type == 1)
|
||||
else if (opts->audio_in_type == 1) //won't work in windows, needs posix pipe (mintty)
|
||||
{
|
||||
result = sf_read_short(opts->audio_in_file, &sample, 1);
|
||||
if(result == 0)
|
||||
{
|
||||
//cleanupAndExit (opts, state);
|
||||
sf_close(opts->audio_in_file);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //send zero sample
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
}
|
||||
//wav files, same but using seperate value so we can still manipulate ncurses menu
|
||||
@@ -122,10 +111,15 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
|
||||
sf_close(opts->audio_in_file);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //send zero sample
|
||||
|
||||
fprintf (stderr, "\n\nEnd of .wav file.\n");
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else cleanupAndExit(opts, state);
|
||||
}
|
||||
}
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -147,24 +141,28 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
if(result == 0) {
|
||||
sf_close(opts->tcp_file_in);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //zero sample on bad result, keep the ball rolling
|
||||
|
||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else cleanupAndExit(opts, state);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//UDP Socket input...not working correct. Reads samples, but no sync
|
||||
else if (opts->audio_in_type == 6)
|
||||
{
|
||||
// else if (opts->audio_in_type == 6)
|
||||
// {
|
||||
//I think this doesn't get the entire dgram when we run sf_read_short on the udp dgram
|
||||
result = sf_read_short(opts->udp_file_in, &sample, 1);
|
||||
// result = sf_read_short(opts->udp_file_in, &sample, 1);
|
||||
// if (sample != 0)
|
||||
// fprintf (stderr, "Result = %d Sample = %d \n", result, sample);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// }
|
||||
|
||||
if (opts->use_cosine_filter)
|
||||
{
|
||||
@@ -383,6 +381,12 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
}
|
||||
#endif
|
||||
|
||||
//test throttle on wav input files
|
||||
if (opts->audio_in_type == 2)
|
||||
{
|
||||
if (state->use_throttle == 1) usleep(.003); //very environment specific, tuning to cygwin
|
||||
}
|
||||
|
||||
//read op25/fme symbol bin files
|
||||
if (opts->audio_in_type == 4)
|
||||
{
|
||||
@@ -399,14 +403,23 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
useconds_t stime = state->symbol_throttle;
|
||||
if (state->use_throttle == 1)
|
||||
{
|
||||
usleep(stime);
|
||||
// usleep(stime);
|
||||
usleep(.003); //very environment specific, tuning to cygwin
|
||||
}
|
||||
//fprintf(stderr, "%d", state->symbolc);
|
||||
if( feof(opts->symbolfile) )
|
||||
{
|
||||
opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
||||
// opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
||||
fclose(opts->symbolfile);
|
||||
openPulseInput(opts);
|
||||
fprintf (stderr, "\n\nEnd of .bin file\n");
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else cleanupAndExit(opts, state);
|
||||
}
|
||||
|
||||
//assign symbol/dibit values based on modulation type
|
||||
|
||||
@@ -480,7 +480,8 @@ decode_bch()
|
||||
}
|
||||
}
|
||||
|
||||
long int messagepp = 0x0;
|
||||
//bugfix on 32-bit cygwin, probably overflowed here
|
||||
unsigned long long int messagepp = 0x0;
|
||||
|
||||
//very simplified version, just to encode, get frame and compare
|
||||
unsigned long long int edacs_bch (unsigned long long int message)
|
||||
|
||||
@@ -47,12 +47,13 @@ char * getTimeE(void) //get pretty hh:mm:ss timestamp
|
||||
|
||||
void edacs(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
unsigned long long fr_1 = 0xFFFFFFFFFF; //40-bit frames
|
||||
unsigned long long fr_2 = 0; //each is a 40 bit frame that repeats 3 times
|
||||
unsigned long long fr_3 = 0; //two messages per frame
|
||||
unsigned long long fr_4 = 0xFFFFFFFFFF;
|
||||
unsigned long long fr_5 = 0;
|
||||
unsigned long long fr_6 = 0;
|
||||
//changed to ulli here for 32-bit cygwin (not sure if was an issue, but playing it safe)
|
||||
unsigned long long int fr_1 = 0xFFFFFFFFFF; //40-bit frames
|
||||
unsigned long long int fr_2 = 0; //each is a 40 bit frame that repeats 3 times
|
||||
unsigned long long int fr_3 = 0; //two messages per frame
|
||||
unsigned long long int fr_4 = 0xFFFFFFFFFF;
|
||||
unsigned long long int fr_5 = 0;
|
||||
unsigned long long int fr_6 = 0;
|
||||
|
||||
//BCH stuff
|
||||
unsigned long long int fr_1m = 0xFFFFFFF; //28-bit 7X message portion to pass to bch handler
|
||||
|
||||
@@ -474,6 +474,10 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
//set to 16 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 16;
|
||||
else state->dmrburstR = 16;
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
@@ -625,6 +629,10 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
//set to 16 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 16;
|
||||
else state->dmrburstR = 16;
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
|
||||
|
||||
@@ -105,6 +105,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -170,6 +173,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -233,6 +239,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//monstrocity below should get us evaluating and tuning groups...hopefully, will be first come first served though, no priority
|
||||
//see how many loops we need to run on when to tune if first group is blocked
|
||||
int loop = 1;
|
||||
@@ -343,6 +352,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -460,7 +472,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
SKIPCALL: ; //do nothing
|
||||
}
|
||||
|
||||
//Group Voice Channel Grant Update Multiple - Explicit
|
||||
@@ -486,6 +497,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq1t = process_channel_to_freq (opts, state, channelt2);
|
||||
freq1r = process_channel_to_freq (opts, state, channelr2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 1;
|
||||
if (channelt2 == channelt2) loop = 1;
|
||||
else loop = 2;
|
||||
@@ -590,6 +604,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 3 [%04X] Group 3 [%d][%04X]", channel3, group3, group3);
|
||||
freq3 = process_channel_to_freq (opts, state, channel3);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 3;
|
||||
|
||||
long int tunable_freq = 0;
|
||||
@@ -693,6 +710,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 1;
|
||||
if (channel1 == channel2) loop = 1;
|
||||
else loop = 2;
|
||||
@@ -805,6 +825,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -1315,6 +1338,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
}
|
||||
|
||||
SKIPCALL: ; //do nothing
|
||||
|
||||
if ( (len_b + len_c) < 24 && len_c != 0)
|
||||
{
|
||||
len_a = len_b;
|
||||
|
||||
BIN
tone24.wav
BIN
tone24.wav
Binary file not shown.
BIN
tone48.wav
BIN
tone48.wav
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
pacmd load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||
pacmd load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user