/ tea2adt_source / tea2adt
tea2adt
1 #!/bin/bash 2 3 # read tmp path 4 TMP_PATH=$(head -n 1 cfg/tmp_path) 5 6 # read version 7 VERSION=$(head -n 1 version) 8 9 # install dependencies? 10 INSTALL_DEPENDENCIES=$(head -n 1 cfg/install_dependencies) 11 if [ "${INSTALL_DEPENDENCIES}" == true ] ; then 12 read -p "Do you want to install dependencies(y/Y)? " -n 1 -r 13 echo # (optional) move to a new line 14 if [[ $REPLY =~ ^[Yy]$ ]] 15 then 16 echo "-------------------------------------------" 17 ${TERMINAL} ./install_dependencies.sh 18 echo "-------------------------------------------" 19 else 20 read -p "Please install dependencies by hand as described in the documentation, cfg/install_dependencies will be set to false" 21 fi 22 echo "false" > cfg/install_dependencies 23 fi 24 25 # first remove previous temporary working folder 26 if [ -d "${HOME}${TMP_PATH}" ]; then 27 rm -r "${HOME}${TMP_PATH}" 28 fi 29 30 # create new temporary working folder 31 mkdir -p "${HOME}${TMP_PATH}" 32 33 # copy files to tmp path 34 cp -r "./cfg" "${HOME}${TMP_PATH}" 35 cp -r "./state" "${HOME}${TMP_PATH}" 36 cp -r "./tmp" "${HOME}${TMP_PATH}" 37 38 # read configuration from files copied in tmp path 39 BAUD=$(head -n 1 ${HOME}${TMP_PATH}/cfg/baud) 40 SYNCBYTE=$(head -n 1 ${HOME}${TMP_PATH}/cfg/syncbyte) 41 CONFIDENCE=$(head -n 1 ${HOME}${TMP_PATH}/cfg/confidence) 42 LIMIT=$(head -n 1 ${HOME}${TMP_PATH}/cfg/limit) 43 TERMINAL=$(head -n 1 ${HOME}${TMP_PATH}/cfg/terminal) 44 PROBE_MSG=$(head -n 1 ${HOME}${TMP_PATH}/cfg/probe_msg) 45 PROBE_SLEEP=$(head -n 1 ${HOME}${TMP_PATH}/cfg/probe_sleep) 46 HALF_DUPLEX=$(head -n 1 ${HOME}${TMP_PATH}/cfg/half_duplex) 47 VOLUME_SPEAKER_LEFT=$(head -n 1 ${HOME}${TMP_PATH}/cfg/volume_speaker_left) 48 VOLUME_SPEAKER_RIGHT=$(head -n 1 ${HOME}${TMP_PATH}/cfg/volume_speaker_right) 49 VOLUME_MICROPHONE=$(head -n 1 ${HOME}${TMP_PATH}/cfg/volume_microphone) 50 TEXT_TO_SPEECH=$(head -n 1 ${HOME}${TMP_PATH}/cfg/text_to_speech) 51 SPEECH_TO_TEXT=$(head -n 1 ${HOME}${TMP_PATH}/cfg/speech_to_text) 52 INTERFACE_INDEX_TTS_OUT=$(head -n 1 ${HOME}${TMP_PATH}/cfg/interface_index_tts_out) 53 INTERFACE_INDEX_STT_IN=$(head -n 1 ${HOME}${TMP_PATH}/cfg/interface_index_stt_in) 54 INTERFACE_INDEX_MINIMODEM_OUT=$(head -n 1 ${HOME}${TMP_PATH}/cfg/interface_index_minimodem_out) 55 INTERFACE_INDEX_MINIMODEM_IN=$(head -n 1 ${HOME}${TMP_PATH}/cfg/interface_index_minimodem_in) 56 VOLUME_STT_IN=$(head -n 1 ${HOME}${TMP_PATH}/cfg/volume_stt_in) 57 VOLUME_TTS_OUT=$(head -n 1 ${HOME}${TMP_PATH}/cfg/volume_tts_out) 58 LLM_CMD=$(head -n 1 ${HOME}${TMP_PATH}/cfg/llm_cmd) 59 60 # SET_COMM_IFS 61 # WORKAROUND: for now, clear audio interfaces for communication in case they were set altough not yet supported 62 if [ "${INTERFACE_INDEX_MINIMODEM_IN}" != "" ] ; then 63 printf "INTERFACE_INDEX_MINIMODEM_IN is not supported yet. The default audio interfaces will be used instead." 64 INTERFACE_INDEX_MINIMODEM_IN= 65 fi 66 if [ "${INTERFACE_INDEX_MINIMODEM_OUT}" != "" ] ; then 67 printf "INTERFACE_INDEX_MINIMODEM_OUT is not supported yet. The default audio interfaces will be used instead." 68 INTERFACE_INDEX_MINIMODEM_OUT= 69 fi 70 71 trap ctrl_c INT 72 73 function ctrl_c() 74 { 75 # TODO: kill child/started processes before ctrl-c 76 # kill $(ps -s $$ -o pid=) 77 # pkill -P $$ 78 # restore mic volume 79 ${TERMINAL} ./restore_audio_settings.sh & 80 # TODO: brute-force kill? 81 ./killtea2adt.sh 2> /dev/null & 82 # and now ctr-c 83 trap - INT 84 kill -INT $$ 85 } 86 87 # SET_COMM_IFS 88 set_interfaces() 89 { 90 # speaker / sink (communication) 91 if [ "${INTERFACE_INDEX_MINIMODEM_OUT}" != "" ] ; then 92 # get sink-input 93 while true; do 94 SINK_INPUT=$(pacmd list-sink-inputs | awk '/index:/{idx=$2} /application.process.binary = "minimodem"/{print idx; exit}') 95 if [ -n "$SINK_INPUT" ]; then 96 break 97 fi 98 sleep 1 99 done 100 # set configured sink for this specific sink-input 101 pactl move-sink-input ${SINK_INPUT} ${INTERFACE_INDEX_MINIMODEM_OUT} 102 echo "set minimodem output with sink input ${SINK_INPUT} to interface index ${INTERFACE_INDEX_MINIMODEM_OUT}" 103 fi 104 # microphone / source (communication) 105 if [ "${INTERFACE_INDEX_MINIMODEM_IN}" != "" ] ; then 106 # get source-input 107 while true; do 108 SOURCE_OUTPUT=$(pacmd list-source-outputs | awk '/index:/{idx=$2} /application.process.binary = "minimodem"/{print idx; exit}') 109 if [ -n "$SOURCE_OUTPUT" ]; then 110 break 111 fi 112 sleep 1 113 done 114 # set configured source for this specific source-output 115 pactl move-source-output ${SOURCE_OUTPUT} ${INTERFACE_INDEX_MINIMODEM_IN} 116 echo "set minimodem input with source output ${SOURCE_OUTPUT} to interface index ${INTERFACE_INDEX_MINIMODEM_IN}" 117 fi 118 } 119 120 set_volumes() 121 { 122 # speaker 123 if [ "${INTERFACE_INDEX_MINIMODEM_OUT}" != "" ] ; then 124 if [ "${VOLUME_SPEAKER_LEFT}" != "" ] ; then 125 pactl -- set-sink-volume ${INTERFACE_INDEX_MINIMODEM_OUT} ${VOLUME_SPEAKER_LEFT} ${VOLUME_SPEAKER_RIGHT} 126 echo "setting output/speaker volume to L,R = ${VOLUME_SPEAKER_LEFT},${VOLUME_SPEAKER_RIGHT}" 127 fi 128 echo "configured output/speaker, index = " ${INTERFACE_INDEX_MINIMODEM_OUT} 129 else 130 if [ "${VOLUME_SPEAKER_LEFT}" != "" ] ; then 131 default_sink_index=$(pacmd list-sinks | grep "* index: " | grep -o '...$') 132 if [ "${default_sink_index:0:1}" == ":" ] ; then 133 default_sink_index=$(pacmd list-sinks | grep "* index: " | grep -o '..$') 134 fi 135 pactl -- set-sink-volume ${default_sink_index} ${VOLUME_SPEAKER_LEFT} ${VOLUME_SPEAKER_RIGHT} 136 echo "setting default output/speaker volume to L,R = "${VOLUME_SPEAKER_LEFT}","${VOLUME_SPEAKER_RIGHT} 137 # echo "(leave cfg/volume_speaker_left empty in order to not set input volume automtatically)" 138 fi 139 # echo default settings for communication 140 echo "default output/speaker, index = " ${default_sink_index} 141 fi 142 # mic 143 if [ "${INTERFACE_INDEX_MINIMODEM_IN}" != "" ] ; then 144 if [ "${VOLUME_MICROPHONE}" != "" ] ; then 145 pactl -- set-source-volume ${INTERFACE_INDEX_MINIMODEM_IN} ${VOLUME_MICROPHONE} 146 echo "setting input/microphone volume to "${VOLUME_MICROPHONE} 147 # echo "(leave cfg/volume_microphone empty in order to not set output volume automtatically)" 148 fi 149 echo "configured input/microphone, index = " ${INTERFACE_INDEX_MINIMODEM_IN} 150 else 151 if [ "${VOLUME_MICROPHONE}" != "" ] ; then 152 default_source_index=$(pacmd list-sources | grep "* index: " | grep -o '...$') 153 if [ "${default_source_index:0:1}" == ":" ] ; then 154 default_source_index=$(pacmd list-sources | grep "* index: " | grep -o '..$') 155 fi 156 pactl -- set-source-volume ${default_source_index} ${VOLUME_MICROPHONE} 157 echo "setting input/microphone volume to "${VOLUME_MICROPHONE} 158 # echo "(leave cfg/volume_microphone empty in order to not set output volume automtatically)" 159 fi 160 echo "default input/microphone, index = " ${default_source_index} 161 fi 162 # TTS 163 if [ "${TEXT_TO_SPEECH}" != "" ] ; then 164 if [ "${VOLUME_TTS_OUT}" != "" ] ; then 165 pactl -- set-sink-volume ${INTERFACE_INDEX_TTS_OUT} ${VOLUME_TTS_OUT} 166 echo "setting TTS output/speaker volume = "${VOLUME_TTS_OUT} 167 fi 168 fi 169 # STT 170 if [ "${SPEECH_TO_TEXT}" == true ] ; then 171 if [ "${VOLUME_STT_IN}" != "" ] ; then 172 pactl -- set-source-volume ${INTERFACE_INDEX_STT_IN} ${VOLUME_STT_IN} 173 echo "setting STT input/microphone volume = "${VOLUME_STT_IN} 174 fi 175 fi 176 # echo TTS and STT settings 177 echo "TTS command = "${TEXT_TO_SPEECH} 178 echo "TTS output/speaker, index = "${INTERFACE_INDEX_TTS_OUT} 179 echo "STT input/microphone, index = "${INTERFACE_INDEX_STT_IN} 180 } 181 182 create_fifos() 183 { 184 if [ "$1" == "-l" ] || [ "$1" == "--llm" ] || [ "$1" == "--llm-chat" ] || [ "$1" == "--llm-prompt" ] ; then 185 PIPE_LLM_OUT="${HOME}${TMP_PATH}/tmp/pipe_llm_out" 186 if [ -p ${PIPE_LLM_OUT} ] || [ -f ${PIPE_LLM_OUT} ]; then 187 rm ${PIPE_LLM_OUT} 188 fi 189 mkfifo ${PIPE_LLM_OUT} 190 elif [ "$1" == "-s" ] || [ "$1" == "--rs" ] || [ "$1" == "--remote-shell" ] || [ "$1" == "--reverse-shell" ] ; then 191 PIPE_SHELL_IN="${HOME}${TMP_PATH}/tmp/pipe_shell_in" 192 PIPE_SHELL_OUT="${HOME}${TMP_PATH}/tmp/pipe_shell_out" 193 if [ -p ${PIPE_SHELL_IN} ] || [ -f ${PIPE_SHELL_IN} ]; then 194 rm ${PIPE_SHELL_IN} 195 fi 196 if [ -p ${PIPE_SHELL_OUT} ] || [ -f ${PIPE_SHELL_OUT} ]; then 197 rm ${PIPE_SHELL_OUT} 198 fi 199 mkfifo ${PIPE_SHELL_IN} 200 mkfifo ${PIPE_SHELL_OUT} 201 elif [ "$1" == "-f" ] || [ "$1" == "--file" ] ; then 202 PIPE_FILE_IN="${HOME}${TMP_PATH}/tmp/pipe_file_in" 203 PIPE_FILE_OUT="${HOME}${TMP_PATH}/tmp/pipe_file_out" 204 if [ -p ${PIPE_FILE_IN} ] || [ -f ${PIPE_FILE_IN} ]; then 205 rm ${PIPE_FILE_IN} 206 fi 207 if [ -p ${PIPE_FILE_OUT} ] || [ -f ${PIPE_FILE_OUT} ]; then 208 rm ${PIPE_FILE_OUT} 209 fi 210 mkfifo ${PIPE_FILE_IN} 211 mkfifo ${PIPE_FILE_OUT} 212 fi 213 } 214 215 ask_password() 216 { 217 while true 218 do 219 while true 220 do 221 echo -n "password: " 222 read -ers PASSWORD1 223 echo "" 224 # 2> /dev/null shall prevent showing the password if some error occurs 225 if [ ! "${PASSWORD1}" == "" ] 2> /dev/null 226 then 227 break 228 else 229 echo "Password cannot be empty!" 230 fi 231 done 232 echo -n "confirm password: " 233 read -ers PASSWORD 234 echo "" 235 # 2> /dev/null shall prevent showing the password if some error occurs 236 [ "${PASSWORD1}" == "${PASSWORD}" ] 2> /dev/null && break 237 echo "Passwords dont match!" 238 done 239 } 240 241 # SET_COMM_IFS 242 # TODO: if we get feature # SET_COMM_IFS to work, then we need to update this function to show the correct comm. interfaces 243 # which will then be defined by INTERFACE_INDEX_MINIMODEM_IN and INTERFACE_INDEX_MINIMODEM_OUT 244 echo_audio_interfaces() 245 { 246 # list audio output interfaces 247 echo "audio output interfaces" 248 echo "-----------------------" 249 echo "$(pactl list short sinks)" 250 # list audio input interfaces 251 echo "" 252 echo "audio input interfaces" 253 echo "----------------------" 254 echo "$(pactl list short sources)" 255 # default audio output / speaker 256 default_sink_index=$(pacmd list-sinks | grep "* index: " | grep -o '...$') 257 if [ "${default_sink_index:0:1}" == ":" ] ; then 258 default_sink_index=$(pacmd list-sinks | grep "* index: " | grep -o '..$') 259 fi 260 # default audio input / mic 261 default_source_index=$(pacmd list-sources | grep "* index: " | grep -o '...$') 262 if [ "${default_source_index:0:1}" == ":" ] ; then 263 default_source_index=$(pacmd list-sources | grep "* index: " | grep -o '..$') 264 fi 265 # echo settings 266 echo "" 267 echo "audio settings for communication" 268 echo "--------------------------------" 269 echo "default output/speaker, index = " ${default_sink_index} 270 echo "default input/microphone, index = " ${default_source_index} 271 echo "" 272 echo "audio settings for TTS and STT" 273 echo "--------------------------------" 274 echo "TTS output/speaker, index = " ${INTERFACE_INDEX_TTS_OUT} 275 echo "STT input/microphone, index = " ${INTERFACE_INDEX_STT_IN} 276 echo "" 277 } 278 279 echo_help() 280 { 281 echo "usage: tea2adt [-c|-s] 282 -c, --chat 283 -l, --llm, --llm-chat, --llm-prompt 284 -s, --rs, --remote-shell, --reverse-shell (to execute a command as sudo type: echo \"<pwd>\" | sudo -k -S <cmd>) 285 -f, --file, --file-transfer 286 -p, --probe (send periodic test messages to check connectivity and adjust the volumes if required) 287 -g, --gui (only for configuration) 288 -a, --audio-settings 289 -d, --directory (show installation path) 290 -V, --version 291 -h, --help 292 -i, --image 293 294 tea2adt is a command-line utility for Chat, Remote Shell, Remote AI Prompt and File Transfer, that reads and writes encrypted data across peer-to-peer or broadcast audio connections, using minimodem and gpg. 295 It is a powerful tool that can be combined with any audio infrastructure (like PSTN, cellular network, internet, radio) to provide a secure communication channel through an audio tunnel. 296 The audio interfaces behave like data-diodes, each allowing unidirectional data transmission only, thus preventing data-leaks and malware-injection. 297 This enables an enhanced-end-to-end encryption (E-E2EE) which notably increases security and privacy, especially when the end devices are completely offline (air-gapped-system), providing an effective barrier against legal or illegal client-side-scanning! 298 Homepage: https://github.com/ClarkFieseln/tea2adt" 299 } 300 301 echo_image() 302 { 303 echo " 304 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 305 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 306 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 307 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓█░█▓▓▓▓▓▓▓▓▓▓███░▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▓█░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 308 ▓▓▓▓▓▓▓▓▓▓▓▓▓█░░█▓▓▓▓▓▓▓▓▓▓███████▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▒█░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▓▓▓▓▓▓▓▓▓ 309 ▓▓▓▓▓▓▓▓▓▓▓▓▒░░░▓█▓▓▓▓▓▓▓▓▓███████░██▓█▓▓▓▓▓▓▓▓▓█░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓█▓▓▓▓▓▓▓▓▓▓ 310 ▓▓▓▓▓▓▓▓▓▓▓▓█░░░▓███████████████████░██░░░░░░░░░█░░░░▓▓▓▓▓▓▓█▓▓▓▓█▓▓▓▓█▓▓▓▓▓▓▓▓▓ 311 ▓▓▓▓▓▓▓▓▓▓▓▓▒░░░██▓▓▓▓▓▓▓▓▓██████▒█▒▓▓█▓▓▓▓▓▓▓▓▓██░░░▓▓▓▓▓▓▓▓█▓▓█▓▓▓▓▓▓▓▓█▓▓▓▓▓▓ 312 ▓▓▓▓▓▓▓▓▓▓▓▓▓█░░█▓▓▓▓▓▓▓▓▓▓█████▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▒█░█▓▓▓▓▓▓▓▓██▓▓▓▓▓▓▓██▓▓▓▓▓▓▓ 313 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒██▓▓▓▓▓▓▓▓▓▓██▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 314 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 315 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 316 ▓▓▓▓▓▓▓▓▓▓▓▓▓░░▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓██▓▓▓▓▓▓▓▓▓▓▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 317 ▓▓▓▓▓▓▓▓▓▓▓▓▓▒░█▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▒█░██▒▓▓▓▓▓▓▓▓▓▓▓░░█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓ 318 ▓▓▓▓▓▓▓▓▓▓▓▓▓▒░░██▓▓▓▓▓▓▓▓▓█▓▓▓█░░█████▓▓▓▓▓▓▓▓▓░█░░░█▓▓▓▓▓▓▓▓██▓▓▓▓█▓█▓▓▓▓▓▓▓▓▓ 319 ▓▓▓▓▓▓▓▓▓▓▓▓▓▒░░█▒░░░░░░░░░██░░██████████████████░░░░█▓▓▓▓▓███▓█▓███▓▓█▓▓▓██▓▓▓▓ 320 ▓▓▓▓▓▓▓▓▓▓▓▓▓▒░░█▒▓▓▓▓▓▓▓▓▓█▓▓█████████▓▓▓▓▓▓▓▓▓▓▒░░░█▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓█▓█▓▓▓▓▓▓ 321 ▓▓▓▓▓▓▓▓▓▓▓▓▓▒░▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▒██████▓▓▓▓▓▓▓▓▓▓▓░░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓ 322 ▓▓▓▓▓▓▓▓▓▓▓▓▓░█▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓███▓▓▓▓▓▓▓▓▓▓▓░█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 323 ▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 324 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 325 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 326 " 327 } 328 329 echo_parameters() 330 { 331 echo "baud = $BAUD" 332 echo "half_duplex = $HALF_DUPLEX" 333 echo "syncbyte = $SYNCBYTE" 334 echo "confidence = $CONFIDENCE" 335 echo "limit = $LIMIT" 336 echo "terminal = $TERMINAL" 337 echo "volume speaker left = $VOLUME_SPEAKER_LEFT" 338 echo "volume speaker right = $VOLUME_SPEAKER_RIGHT" 339 echo "volume microphone = $VOLUME_MICROPHONE" 340 echo "text to speech = $TEXT_TO_SPEECH" 341 echo "speech to text = $SPEECH_TO_TEXT" 342 echo "volume TTS out = $VOLUME_TTS_OUT" 343 echo "volume STT in = $VOLUME_STT_IN" 344 } 345 346 echo_version() 347 { 348 echo "tea2adt ${VERSION} 349 MIT License: <https://opensource.org/license/mit>. 350 Copyright (C) 2025 Clark Fieseln 351 This is free software: you are free to change and redistribute it. 352 There is NO WARRANTY, to the extent permitted by law." 353 } 354 355 : ' 356 # SET_COMM_IFS 357 --------------------------------------------- 358 NOTE: set audio interfaces for communication: 359 --------------------------------------------- 360 in the tested solution minimodem is running in a background tmux session (or a screen session) with a pipe to cat | minimodem 361 (in that case the sink-source remains always the same, i.e. interface_index_minimodem_in/out are set once and are working as expected) 362 but in that case the communication gets very unstable due to synchronization issues in minimodem, and probably also due to buffering in pipe, cat or tmux/screen 363 alternatives using a named pipe instead of cat, or a temporary variable or file did not work as minimodem gets called several times 364 A "dynamic" solution which detects the current sink-source used by minimodem which each call was not implemented 365 because it may bring timing-problems as is the case when setting the TTS sink based on the sink-input 366 A generic solution using virtual sinks and load-module in pulse audio may also not work when the sink-input changes with each call to minimodem. 367 init_minimodem() 368 { 369 # init minimodem process in new tmux session which can then be written with tmux send-keys -t session_mmtx 370 tmux new-session -d -s session_mmtx "cat | minimodem --tx --ascii --quiet --startbits 1 --stopbits 1.0 --sync-byte ${SYNCBYTE} --volume 1.0 ${BAUD}" & 371 # alternative: 372 # screen -dmS session_mmtx bash -c "cat | minimodem --tx --ascii --quiet --startbits 1 --stopbits 1.0 --sync-byte 0x7F --volume 1.0 9600" & 373 } 374 ' 375 376 # options 377 if [ "$1" == "" ] ; then 378 echo "tea2adt: *** you must specify an option, run tea2adt -h for more information ***" 379 echo_help 380 elif [ "$1" == "-a" ] || [ "$1" == "--audio-settings" ] ; then 381 echo_audio_interfaces 382 elif [ "$1" == "-c" ] || [ "$1" == "--chat" ] ; then 383 ask_password 384 # init_minimodem 385 set_volumes 386 create_fifos "$1" 387 ${TERMINAL} ./mmtx.sh "${PASSWORD}" & 388 # wait a little bit so the transmitter can initialize the state flags 389 sleep 0.5 390 echo_parameters 391 # don't call set_interfaces here, have not yet a source-output, need yet to run rx.src 392 source rx.src | python3 mmrx.py "${PASSWORD}" $1 393 elif [ "$1" == "-f" ] || [ "$1" == "--file" ] ; then 394 ask_password 395 # init_minimodem 396 set_volumes 397 create_fifos "$1" 398 ${TERMINAL} ./mmtxfile.sh "${PASSWORD}" & 399 # wait a little bit so the transmitter can initialize the state flags 400 sleep 0.5 401 # track input files 402 ${TERMINAL} cat ${PIPE_FILE_IN} & 403 # don't call set_interfaces here, have not yet a source-output, need yet to run rx.src 404 # we don't echo_parameters in -f mode 405 source rx.src | python3 mmrx.py "${PASSWORD}" $1 406 elif [ "$1" == "-l" ] || [ "$1" == "--llm" ] || [ "$1" == "--llm-chat" ] || [ "$1" == "--llm-prompt" ] ; then 407 ask_password 408 # init_minimodem 409 set_volumes 410 create_fifos "$1" 411 if [ "${LLM_CMD}" != "" ] ; then 412 # check if ollama is used and if it is running 413 if [[ ${LLM_CMD} =~ "ollama run" ]]; then 414 while ! curl -s http://localhost:11434/api/tags > /dev/null; do 415 # sleep 1 416 echo "Error: ollama is not running!" 417 exit 418 done 419 fi 420 # create persistent session to run in background with output pipe 421 # (input is done with command 'tmux send-keys -t session_llm') 422 tmux new-session -d -s session_llm "${LLM_CMD} > ${PIPE_LLM_OUT}" & 423 # TODO: use instead 2> to not redirect errors? 424 # tmux new-session -d -s session_llm "${LLM_CMD} 2> ${PIPE_LLM_OUT}" & 425 echo "LLM model started..." 426 else 427 echo "Error: llm_cmd is not configured!" 428 exit 429 fi 430 echo_parameters 431 # don't call set_interfaces here, have not yet a source-output, need yet to run rx.src 432 source rx.src | python3 mmrx.py "${PASSWORD}" $1 433 elif [ "$1" == "-s" ] || [ "$1" == "--rs" ] || [ "$1" == "--remote-shell" ] || [ "$1" == "--reverse-shell" ] ; then 434 ask_password 435 # init_minimodem 436 set_volumes 437 create_fifos "$1" 438 # create persistent shell to run in background with input and output pipes 439 while true; do /bin/sh &> ${PIPE_SHELL_OUT}; done 0< ${PIPE_SHELL_IN} & 440 echo_parameters 441 # don't call set_interfaces here, have not yet a source-output, need yet to run rx.src 442 source rx.src | python3 mmrx.py "${PASSWORD}" $1 443 elif [ "$1" == "-p" ] || [ "$1" == "--probe" ] ; then 444 # init_minimodem 445 set_volumes 446 echo_parameters 447 ${TERMINAL} ./mmrxnopwd.sh & 448 echo "**********************************" 449 echo "*** tea2adt probe transmitter ****" 450 echo "**********************************" 451 echo "Test messages "${PROBE_MSG}" sent with a delay of "${PROBE_SLEEP}" seconds..." 452 echo "(a separate terminal is opened to receive unencrypted test messages from the communication partner)" 453 # SET_COMM_IFS 454 # set_interfaces 455 while : 456 do 457 echo "${PROBE_MSG}" | source tx.src 458 sleep ${PROBE_SLEEP} 459 done 460 elif [ "$1" == "-g" ] || [ "$1" == "--gui" ] ; then 461 python3 gui.py 462 elif [ "$1" == "-d" ] || [ "$1" == "--directory" ] ; then 463 echo $(pip show tea2adt | grep Location)"/tea2adt_source" 464 elif [ "$1" == "-V" ] || [ "$1" == "--version" ] ; then 465 echo_version 466 elif [ "$1" == "-h" ] || [ "$1" == "--help" ] ; then 467 echo_help 468 elif [ "$1" == "-i" ] || [ "$1" == "--image" ] ; then 469 echo_image 470 else 471 echo "tea2adt: invalid option" 472 fi