diff --git a/test/001_highsnr_stdio_audio/test_rx.py b/test/001_highsnr_stdio_audio/test_rx.py index 20d24a5b..afcd2cf6 100644 --- a/test/001_highsnr_stdio_audio/test_rx.py +++ b/test/001_highsnr_stdio_audio/test_rx.py @@ -22,8 +22,8 @@ import codec2 #--------------------------------------------GET PARAMETER INPUTS parser = argparse.ArgumentParser(description='Simons TEST TNC') -parser.add_argument('--bursts', dest="N_BURSTS", default=0, type=int) -parser.add_argument('--framesperburst', dest="N_FRAMES_PER_BURST", default=0, type=int) +parser.add_argument('--bursts', dest="N_BURSTS", default=1, type=int) +parser.add_argument('--framesperburst', dest="N_FRAMES_PER_BURST", default=1, type=int) parser.add_argument('--mode', dest="FREEDV_MODE", type=str, choices=['datac0', 'datac1', 'datac3']) parser.add_argument('--audiodev', dest="AUDIO_INPUT_DEVICE", default=-1, type=int, help="audio device number to use, use -2 to automatically select a loopback device") @@ -49,7 +49,7 @@ TIMEOUT = args.TIMEOUT # AUDIO PARAMETERS AUDIO_FRAMES_PER_BUFFER = 2048 # seems to be best if >=1024 MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000 -AUDIO_SAMPLE_RATE_RX = 48000 +AUDIO_SAMPLE_RATE_RX = 8000 assert (AUDIO_SAMPLE_RATE_RX % MODEM_SAMPLE_RATE) == 0 # check if we want to use an audio device then do an pyaudio init @@ -104,13 +104,14 @@ receive = True audio_buffer = bytes() nbytes = 0 BUF_SIZE = 160 +ratecv_state = None while receive and time.time() < timeout: if AUDIO_INPUT_DEVICE != -1: data_in = stream_rx.read(AUDIO_FRAMES_PER_BUFFER, exception_on_overflow = False) - data_in = audioop.ratecv(data_in,2,1,AUDIO_SAMPLE_RATE_RX, MODEM_SAMPLE_RATE, None) - audio_buffer += data_in[0] + #data_in, ratecv_state = audioop.ratecv(data_in,2,1,AUDIO_SAMPLE_RATE_RX, MODEM_SAMPLE_RATE, ratecv_state) + audio_buffer += data_in else: @@ -118,32 +119,30 @@ while receive and time.time() < timeout: nin = codec2.api.freedv_nin(freedv) * 2 - rx_status = codec2.api.freedv_get_rx_status(freedv) - if DEBUGGING_MODE: - state = codec2.api.rx_sync_flags_to_text[rx_status] - print(f"NIN: {nin} STATE: {state} BUFFER: {len(audio_buffer)}", file=sys.stderr) - #decode as soon as we filled the audio buffer if len(audio_buffer) >= (nin): nbytes = codec2.api.freedv_rawdatarx(freedv, bytes_out, audio_buffer[:nin]) # demodulate audio audio_buffer = audio_buffer[nin:] + rx_status = codec2.api.freedv_get_rx_status(freedv) + if rx_status & codec2.api.FREEDV_RX_BIT_ERRORS: + rx_errors = rx_errors + 1 + if DEBUGGING_MODE: + state = codec2.api.rx_sync_flags_to_text[rx_status] + print(f"NIN: {nin} RX_STATUS: {state} BUFFER: {len(audio_buffer)}", file=sys.stderr) - total_n_bytes = total_n_bytes + nbytes + total_n_bytes = total_n_bytes + nbytes - if nbytes == bytes_per_frame: - rx_total_frames = rx_total_frames + 1 - rx_frames = rx_frames + 1 + if nbytes == bytes_per_frame: + rx_total_frames = rx_total_frames + 1 + rx_frames = rx_frames + 1 if rx_frames == N_FRAMES_PER_BURST: rx_frames = 0 rx_bursts = rx_bursts + 1 - - if rx_status & codec2.api.FREEDV_RX_BIT_ERRORS: - rx_errors = rx_errors + 1 - - if rx_bursts == N_BURSTS: - receive = False + + if rx_bursts == N_BURSTS: + receive = False print(f"RECEIVED BURSTS: {rx_bursts} RECEIVED FRAMES: {rx_total_frames} RX_ERRORS: {rx_errors}", file=sys.stderr) diff --git a/test/001_highsnr_stdio_audio/test_tx.py b/test/001_highsnr_stdio_audio/test_tx.py index 1d1c0a68..e30c015e 100644 --- a/test/001_highsnr_stdio_audio/test_tx.py +++ b/test/001_highsnr_stdio_audio/test_tx.py @@ -17,9 +17,10 @@ import codec2 # GET PARAMETER INPUTS parser = argparse.ArgumentParser(description='Simons TEST TNC') -parser.add_argument('--bursts', dest="N_BURSTS", default=0, type=int) -parser.add_argument('--framesperburst', dest="N_FRAMES_PER_BURST", default=0, type=int) -parser.add_argument('--delay', dest="DELAY_BETWEEN_BURSTS", default=0, type=int) +parser.add_argument('--bursts', dest="N_BURSTS", default=1, type=int) +parser.add_argument('--framesperburst', dest="N_FRAMES_PER_BURST", default=1, type=int) +parser.add_argument('--delay', dest="DELAY_BETWEEN_BURSTS", default=500, type=int, + help="delay between bursts in ms") parser.add_argument('--mode', dest="FREEDV_MODE", type=str, choices=['datac0', 'datac1', 'datac3']) parser.add_argument('--audiodev', dest="AUDIO_OUTPUT_DEVICE", default=-1, type=int, help="audio output device number to use, use -2 to automatically select a loopback device") @@ -44,7 +45,7 @@ MODE = codec2.FREEDV_MODE[args.FREEDV_MODE].value # AUDIO PARAMETERS AUDIO_FRAMES_PER_BUFFER = 2048 MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000 -AUDIO_SAMPLE_RATE_TX = 48000 +AUDIO_SAMPLE_RATE_TX = 8000 assert (AUDIO_SAMPLE_RATE_TX % MODEM_SAMPLE_RATE) == 0 # check if we want to use an audio device then do an pyaudio init @@ -136,7 +137,7 @@ for i in range(1,N_BURSTS+1): txbuffer += bytes(mod_out_postamble) # append a delay between bursts as audio silence - samples_delay = int(MODEM_SAMPLE_RATE*DELAY_BETWEEN_BURSTS) + samples_delay = int(MODEM_SAMPLE_RATE*DELAY_BETWEEN_BURSTS*2) mod_out_silence = create_string_buffer(samples_delay) txbuffer += bytes(mod_out_silence) print(f"samples_delay: {samples_delay} DELAY_BETWEEN_BURSTS: {DELAY_BETWEEN_BURSTS}", file=sys.stderr) @@ -145,8 +146,8 @@ for i in range(1,N_BURSTS+1): if AUDIO_OUTPUT_DEVICE != -1: # sample rate conversion from 8000Hz to 48000Hz - audio = audioop.ratecv(txbuffer,2,1,MODEM_SAMPLE_RATE, AUDIO_SAMPLE_RATE_TX, None) - stream_tx.write(audio[0]) + #audio = audioop.ratecv(txbuffer,2,1,MODEM_SAMPLE_RATE, AUDIO_SAMPLE_RATE_TX, None) + stream_tx.write(txbuffer) else: # print data to terminal for piping the output to other programs diff --git a/test/001_highsnr_stdio_audio/test_virtual1.sh b/test/001_highsnr_stdio_audio/test_virtual1.sh index 60cb149e..00e09b84 100755 --- a/test/001_highsnr_stdio_audio/test_virtual1.sh +++ b/test/001_highsnr_stdio_audio/test_virtual1.sh @@ -1,6 +1,6 @@ #!/bin/bash -x -# Run a test using the virtual sound cards, but sound I/O performed by aplay/arecord, and -# we pipe to Python utilities +# Run a test using the virtual sound cards, sound I/O performed by aplay/arecord at +# Fs=8000 Hz, and we pipe to Python utilities function check_alsa_loopback { lsmod | grep snd_aloop >> /dev/null diff --git a/test/001_highsnr_stdio_audio/test_virtual1a.sh b/test/001_highsnr_stdio_audio/test_virtual1a.sh new file mode 100755 index 00000000..fdcff59d --- /dev/null +++ b/test/001_highsnr_stdio_audio/test_virtual1a.sh @@ -0,0 +1,31 @@ +#!/bin/bash -x +# Run a test using the virtual sound cards, tx sound I/O performed by aplay +# and arecord at Fs=48000Hz, we pipe to Python utilities + +function check_alsa_loopback { + lsmod | grep snd_aloop >> /dev/null + if [ $? -eq 1 ]; then + echo "ALSA loopback device not present. Please install with:" + echo + echo " sudo modprobe snd-aloop index=1,2 enable=1,1 pcm_substreams=1,1 id=CHAT1,CHAT2" + exit 1 + fi +} + +check_alsa_loopback + +RX_LOG=$(mktemp) +MAX_RUN_TIME=2600 + +# make sure all child processes are killed when we exit +trap 'jobs -p | xargs -r kill' EXIT + +arecord -r 48000 --device="plughw:CARD=CHAT1,DEV=0" -f S16_LE -d $MAX_RUN_TIME | \ + sox -t .s16 -r 48000 -c 1 - -t .s16 -r 8000 -c 1 - | \ + python3 test_rx.py --mode datac0 --frames 2 --bursts 5 --debug & +rx_pid=$! +sleep 1 +python3 test_tx.py --mode datac0 --frames 2 --bursts 5 --delay 500 | \ + sox -t .s16 -r 8000 -c 1 - -t .s16 -r 48000 -c 1 - | \ + aplay -r 48000 --device="plughw:CARD=CHAT1,DEV=1" -f S16_LE +wait ${rx_pid} diff --git a/test/001_highsnr_stdio_audio/test_virtual1b.sh b/test/001_highsnr_stdio_audio/test_virtual1b.sh new file mode 100755 index 00000000..100f037e --- /dev/null +++ b/test/001_highsnr_stdio_audio/test_virtual1b.sh @@ -0,0 +1,29 @@ +#!/bin/bash -x +# Run a test using the virtual sound cards, tx sound I/O performed by Python, +# rx using arecord, Fs=48000Hz + +function check_alsa_loopback { + lsmod | grep snd_aloop >> /dev/null + if [ $? -eq 1 ]; then + echo "ALSA loopback device not present. Please install with:" + echo + echo " sudo modprobe snd-aloop index=1,2 enable=1,1 pcm_substreams=1,1 id=CHAT1,CHAT2" + exit 1 + fi +} + +check_alsa_loopback + +RX_LOG=$(mktemp) +MAX_RUN_TIME=2600 + +# make sure all child processes are killed when we exit +trap 'jobs -p | xargs -r kill' EXIT + +arecord -r 48000 --device="plughw:CARD=CHAT1,DEV=0" -f S16_LE -d $MAX_RUN_TIME | \ + sox -t .s16 -r 48000 -c 1 - -t .s16 -r 8000 -c 1 - | \ + python3 test_rx.py --mode datac0 --frames 2 --bursts 5 --debug & +rx_pid=$! +sleep 1 +python3 test_tx.py --mode datac0 --frames 2 --bursts 5 --delay 500 --audiodev -2 +wait ${rx_pid} diff --git a/test/001_highsnr_stdio_audio/test_virtual1c.sh b/test/001_highsnr_stdio_audio/test_virtual1c.sh new file mode 100755 index 00000000..f20bb79f --- /dev/null +++ b/test/001_highsnr_stdio_audio/test_virtual1c.sh @@ -0,0 +1,29 @@ +#!/bin/bash -x +# Run a test using the virtual sound cards, tx sound I/O performed by aplay, +# rx sound I/O by Python, Fs=48000Hz. + +function check_alsa_loopback { + lsmod | grep snd_aloop >> /dev/null + if [ $? -eq 1 ]; then + echo "ALSA loopback device not present. Please install with:" + echo + echo " sudo modprobe snd-aloop index=1,2 enable=1,1 pcm_substreams=1,1 id=CHAT1,CHAT2" + exit 1 + fi +} + +check_alsa_loopback + +RX_LOG=$(mktemp) +MAX_RUN_TIME=2600 + +# make sure all child processes are killed when we exit +trap 'jobs -p | xargs -r kill' EXIT + +python3 test_rx.py --mode datac0 --frames 2 --bursts 5 --debug --audiodev -2 & +rx_pid=$! +sleep 1 +python3 test_tx.py --mode datac0 --frames 2 --bursts 5 --delay 500 | \ + sox -t .s16 -r 8000 -c 1 - -t .s16 -r 48000 -c 1 - | \ + aplay -r 48000 --device="plughw:CARD=CHAT1,DEV=1" -f S16_LE +wait ${rx_pid} diff --git a/test/001_highsnr_stdio_audio/test_virtual2.sh b/test/001_highsnr_stdio_audio/test_virtual2.sh index 504ae54a..c94f3f8a 100755 --- a/test/001_highsnr_stdio_audio/test_virtual2.sh +++ b/test/001_highsnr_stdio_audio/test_virtual2.sh @@ -1,5 +1,5 @@ #!/bin/bash -x -# Run a test using the virtual sound cards +# Run a test using the virtual sound cards, Python audio I/O function check_alsa_loopback { lsmod | grep snd_aloop >> /dev/null