mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
redesign of buffer management
This commit is contained in:
parent
2642ae414b
commit
b27563fe77
|
@ -74,5 +74,12 @@ add_test(NAME 001_highsnr_virtual2_P_P
|
|||
./test_virtual2.sh")
|
||||
set_tests_properties(001_highsnr_virtual2_P_P PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: 5 RECEIVED FRAMES: 10 RX_ERRORS: 0")
|
||||
|
||||
# lets Python do a multimode test
|
||||
add_test(NAME 001_highsnr_virtual3_P_P_MM
|
||||
COMMAND sh -c "export LD_LIBRARY_PATH=${CODEC2_BUILD_DIR}/src;
|
||||
PATH=$PATH:${CODEC2_BUILD_DIR}/src;
|
||||
cd ${CMAKE_CURRENT_SOURCE_DIR}/test/001_highsnr_stdio_audio;
|
||||
./test_virtual_mm.sh")
|
||||
set_tests_properties(001_highsnr_virtual3_P_P_MM PROPERTIES PASS_REGULAR_EXPRESSION "RECEIVED BURSTS: 5 RECEIVED FRAMES: 10 RX_ERRORS: 0")
|
||||
endif()
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ 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('--framesperburst', dest="N_FRAMES_PER_BURST", default=1, type=int)
|
||||
parser.add_argument('--audiodev', dest="AUDIO_INPUT_DEVICE", default=-1, type=int, help="audio device number to use")
|
||||
parser.add_argument('--debug', dest="DEBUGGING_MODE", action="store_true")
|
||||
parser.add_argument('--list', dest="LIST", action="store_true", help="list audio devices by number and exit")
|
||||
|
@ -32,14 +32,17 @@ if args.LIST:
|
|||
N_BURSTS = args.N_BURSTS
|
||||
N_FRAMES_PER_BURST = args.N_FRAMES_PER_BURST
|
||||
AUDIO_INPUT_DEVICE = args.AUDIO_INPUT_DEVICE
|
||||
DEBUGGING_MODE = args.DEBUGGING_MODE
|
||||
TIMEOUT = args.TIMEOUT
|
||||
|
||||
# AUDIO PARAMETERS
|
||||
AUDIO_FRAMES_PER_BUFFER = 2048
|
||||
AUDIO_FRAMES_PER_BUFFER = 4096
|
||||
MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000
|
||||
AUDIO_SAMPLE_RATE_RX = 48000
|
||||
assert (AUDIO_SAMPLE_RATE_RX % MODEM_SAMPLE_RATE) == 0
|
||||
|
||||
BUF_SIZE = 160
|
||||
|
||||
# SET COUNTERS
|
||||
rx_total_frames_datac0 = 0
|
||||
rx_frames_datac0 = 0
|
||||
|
@ -79,7 +82,19 @@ datac3_buffer = bytes()
|
|||
# check if we want to use an audio device then do an pyaudio init
|
||||
if AUDIO_INPUT_DEVICE != -1:
|
||||
p = pyaudio.PyAudio()
|
||||
# --------------------------------------------OPEN AUDIO CHANNEL RX
|
||||
# auto search for loopback devices
|
||||
if AUDIO_INPUT_DEVICE == -2:
|
||||
loopback_list = []
|
||||
for dev in range(0,p.get_device_count()):
|
||||
if 'Loopback: PCM' in p.get_device_info_by_index(dev)["name"]:
|
||||
loopback_list.append(dev)
|
||||
if len(loopback_list) >= 2:
|
||||
AUDIO_INPUT_DEVICE = loopback_list[0] #0 = RX 1 = TX
|
||||
print(f"loopback_list rx: {loopback_list}", file=sys.stderr)
|
||||
else:
|
||||
quit()
|
||||
|
||||
print(f"AUDIO INPUT DEVICE: {AUDIO_INPUT_DEVICE} DEVICE: {p.get_device_info_by_index(AUDIO_INPUT_DEVICE)['name']} AUDIO SAMPLE RATE: {AUDIO_SAMPLE_RATE_RX}", file=sys.stderr)
|
||||
stream_rx = p.open(format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=AUDIO_SAMPLE_RATE_RX,
|
||||
|
@ -92,29 +107,30 @@ if AUDIO_INPUT_DEVICE != -1:
|
|||
timeout = time.time() + TIMEOUT
|
||||
receive = True
|
||||
|
||||
BUF_SIZE = 160
|
||||
|
||||
while receive and time.time() < timeout:
|
||||
if AUDIO_INPUT_DEVICE != -1:
|
||||
buf_size_converted = int(BUF_SIZE*(AUDIO_SAMPLE_RATE_RX/MODEM_SAMPLE_RATE))
|
||||
data_in = stream_rx.read(buf_size_converted, exception_on_overflow=False)
|
||||
|
||||
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)
|
||||
data_in = data_in[0].rstrip(b'\x00')
|
||||
|
||||
datac0_buffer += data_in[0]
|
||||
datac1_buffer += data_in[0]
|
||||
datac3_buffer += data_in[0]
|
||||
|
||||
|
||||
else:
|
||||
data_in = sys.stdin.buffer.read(BUF_SIZE)
|
||||
|
||||
|
||||
datac0_buffer += data_in
|
||||
datac1_buffer += data_in
|
||||
datac3_buffer += data_in
|
||||
datac0_buffer += data_in
|
||||
datac1_buffer += data_in
|
||||
datac3_buffer += data_in
|
||||
|
||||
|
||||
datac0_nin = codec2.api.freedv_nin(datac0_freedv) * 2
|
||||
|
||||
if len(datac0_buffer) >= (datac0_nin):
|
||||
datac0_audio = datac0_buffer[:datac0_nin]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac0_freedv, datac0_bytes_out, datac0_buffer[:datac0_nin]) # demodulate audio
|
||||
datac0_buffer = datac0_buffer[datac0_nin:]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac0_freedv, datac0_bytes_out, datac0_audio) # demodulate audio
|
||||
if nbytes == datac0_bytes_per_frame:
|
||||
rx_total_frames_datac0 = rx_total_frames_datac0 + 1
|
||||
rx_frames_datac0 = rx_frames_datac0 + 1
|
||||
|
@ -126,9 +142,8 @@ while receive and time.time() < timeout:
|
|||
|
||||
datac1_nin = codec2.api.freedv_nin(datac1_freedv) * 2
|
||||
if len(datac1_buffer) >= (datac1_nin):
|
||||
datac1_audio = datac1_buffer[:datac1_nin]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac1_freedv, datac1_bytes_out, datac1_buffer[:datac1_nin]) # demodulate audio
|
||||
datac1_buffer = datac1_buffer[datac1_nin:]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac1_freedv, datac1_bytes_out, datac1_audio) # demodulate audio
|
||||
if nbytes == datac1_bytes_per_frame:
|
||||
rx_total_frames_datac1 = rx_total_frames_datac1 + 1
|
||||
rx_frames_datac1 = rx_frames_datac1 + 1
|
||||
|
@ -139,9 +154,8 @@ while receive and time.time() < timeout:
|
|||
|
||||
datac3_nin = codec2.api.freedv_nin(datac3_freedv) * 2
|
||||
if len(datac3_buffer) >= (datac3_nin):
|
||||
datac3_audio = datac3_buffer[:datac3_nin]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac3_freedv, datac3_bytes_out, datac3_buffer[:datac3_nin]) # demodulate audio
|
||||
datac3_buffer = datac3_buffer[datac3_nin:]
|
||||
nbytes = codec2.api.freedv_rawdatarx(datac3_freedv, datac3_bytes_out, datac3_audio) # demodulate audio
|
||||
if nbytes == datac3_bytes_per_frame:
|
||||
rx_total_frames_datac3 = rx_total_frames_datac3 + 1
|
||||
rx_frames_datac3 = rx_frames_datac3 + 1
|
||||
|
@ -151,6 +165,23 @@ while receive and time.time() < timeout:
|
|||
rx_bursts_datac3 = rx_bursts_datac3 + 1
|
||||
|
||||
|
||||
if DEBUGGING_MODE:
|
||||
sync0 = codec2.api.freedv_get_rx_status(datac0_freedv)
|
||||
sync1 = codec2.api.freedv_get_rx_status(datac1_freedv)
|
||||
sync3 = codec2.api.freedv_get_rx_status(datac3_freedv)
|
||||
|
||||
datac0_rxstatus = codec2.api.freedv_get_rx_status(datac0_freedv)
|
||||
datac0_state = codec2.api.rx_sync_flags_to_text[datac0_rxstatus]
|
||||
|
||||
datac1_rxstatus = codec2.api.freedv_get_rx_status(datac1_freedv)
|
||||
datac1_state = codec2.api.rx_sync_flags_to_text[datac1_rxstatus]
|
||||
|
||||
datac3_rxstatus = codec2.api.freedv_get_rx_status(datac3_freedv)
|
||||
datac3_state = codec2.api.rx_sync_flags_to_text[datac3_rxstatus]
|
||||
|
||||
print(f"NIN0: {datac0_nin} STATE0: {datac3_state} | NIN1: {datac1_nin} STATE1: {datac1_state} | NIN3: {datac3_nin} STATE3: {datac3_state}", file=sys.stderr)
|
||||
|
||||
|
||||
if rx_bursts_datac0 == N_BURSTS and rx_bursts_datac1 == N_BURSTS and rx_bursts_datac3 == N_BURSTS:
|
||||
receive = False
|
||||
|
||||
|
@ -159,3 +190,4 @@ if time.time() > timeout:
|
|||
print(f"TIMEOUT REACHED", file=sys.stderr)
|
||||
|
||||
print(f"DATAC0: {rx_bursts_datac0}/{rx_total_frames_datac0} DATAC1: {rx_bursts_datac1}/{rx_total_frames_datac1} DATAC3: {rx_bursts_datac3}/{rx_total_frames_datac3}", file=sys.stderr)
|
||||
|
||||
|
|
|
@ -46,8 +46,19 @@ assert (AUDIO_SAMPLE_RATE_TX % MODEM_SAMPLE_RATE) == 0
|
|||
|
||||
|
||||
if AUDIO_OUTPUT_DEVICE != -1:
|
||||
# pyaudio init
|
||||
p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
if AUDIO_OUTPUT_DEVICE == -2:
|
||||
loopback_list = []
|
||||
for dev in range(0,p.get_device_count()):
|
||||
if 'Loopback: PCM' in p.get_device_info_by_index(dev)["name"]:
|
||||
loopback_list.append(dev)
|
||||
if len(loopback_list) >= 2:
|
||||
AUDIO_OUTPUT_DEVICE = loopback_list[1] #0 = RX 1 = TX
|
||||
print(f"loopback_list tx: {loopback_list}", file=sys.stderr)
|
||||
else:
|
||||
quit()
|
||||
# pyaudio init
|
||||
stream_tx = p.open(format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=AUDIO_SAMPLE_RATE_TX,
|
||||
|
@ -134,7 +145,7 @@ for m in modes:
|
|||
|
||||
|
||||
# and at last check if we had an openend pyaudio instance and close it
|
||||
if AUDIO_OUTPUT_DEVICE != 0:
|
||||
if AUDIO_OUTPUT_DEVICE != -1:
|
||||
stream_tx.close()
|
||||
p.terminate()
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ parser.add_argument('--framesperburst', dest="N_FRAMES_PER_BURST", default=0, ty
|
|||
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")
|
||||
parser.add_argument('--debug', dest="DEBUGGING_MODE", action="store_true")
|
||||
parser.add_argument('--timeout', dest="TIMEOUT", default=10, type=int, help="Timeout (seconds) before test ends")
|
||||
parser.add_argument('--list', dest="LIST", action="store_true", help="list audio devices by number and exit")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
@ -42,10 +43,10 @@ N_FRAMES_PER_BURST = args.N_FRAMES_PER_BURST
|
|||
AUDIO_INPUT_DEVICE = args.AUDIO_INPUT_DEVICE
|
||||
MODE = codec2.FREEDV_MODE[args.FREEDV_MODE].value
|
||||
DEBUGGING_MODE = args.DEBUGGING_MODE
|
||||
|
||||
TIMEOUT = args.TIMEOUT
|
||||
|
||||
# AUDIO PARAMETERS
|
||||
AUDIO_FRAMES_PER_BUFFER = 2048
|
||||
AUDIO_FRAMES_PER_BUFFER = 2048 # seems to be best if >=1024
|
||||
MODEM_SAMPLE_RATE = codec2.api.FREEDV_FS_8000
|
||||
AUDIO_SAMPLE_RATE_RX = 48000
|
||||
assert (AUDIO_SAMPLE_RATE_RX % MODEM_SAMPLE_RATE) == 0
|
||||
|
@ -53,6 +54,19 @@ assert (AUDIO_SAMPLE_RATE_RX % MODEM_SAMPLE_RATE) == 0
|
|||
# check if we want to use an audio device then do an pyaudio init
|
||||
if AUDIO_INPUT_DEVICE != -1:
|
||||
p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
if AUDIO_INPUT_DEVICE == -2:
|
||||
loopback_list = []
|
||||
for dev in range(0,p.get_device_count()):
|
||||
if 'Loopback: PCM' in p.get_device_info_by_index(dev)["name"]:
|
||||
loopback_list.append(dev)
|
||||
if len(loopback_list) >= 2:
|
||||
AUDIO_INPUT_DEVICE = loopback_list[0] #0 = RX 1 = TX
|
||||
print(f"loopback_list rx: {loopback_list}", file=sys.stderr)
|
||||
else:
|
||||
quit()
|
||||
|
||||
print(f"AUDIO INPUT DEVICE: {AUDIO_INPUT_DEVICE} DEVICE: {p.get_device_info_by_index(AUDIO_INPUT_DEVICE)['name']} AUDIO SAMPLE RATE: {AUDIO_SAMPLE_RATE_RX}", file=sys.stderr)
|
||||
stream_rx = p.open(format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=AUDIO_SAMPLE_RATE_RX,
|
||||
|
@ -83,36 +97,37 @@ rx_total_frames = 0
|
|||
rx_frames = 0
|
||||
rx_bursts = 0
|
||||
rx_errors = 0
|
||||
timeout = time.time() + 10
|
||||
timeout = time.time() + TIMEOUT
|
||||
receive = True
|
||||
|
||||
audio_buffer = bytes()
|
||||
nbytes = 0
|
||||
BUF_SIZE = 160
|
||||
while receive and time.time() < timeout:
|
||||
|
||||
data_in = b''
|
||||
if AUDIO_INPUT_DEVICE != -1:
|
||||
|
||||
nin = codec2.api.freedv_nin(freedv)
|
||||
nin_converted = int(nin*(AUDIO_SAMPLE_RATE_RX/MODEM_SAMPLE_RATE))
|
||||
if DEBUGGING_MODE == True:
|
||||
print("nin: %5d nin_converted: %5d " % (nin,nin_converted), end='', file=sys.stderr)
|
||||
|
||||
data_in = stream_rx.read(nin_converted, exception_on_overflow = False)
|
||||
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)
|
||||
data_in = data_in[0].rstrip(b'\x00')
|
||||
audio_buffer += data_in[0]
|
||||
|
||||
else:
|
||||
nin = codec2.api.freedv_nin(freedv) * 2
|
||||
if DEBUGGING_MODE == True:
|
||||
print("nin: %5d " % (nin), end='', file=sys.stderr)
|
||||
data_in = sys.stdin.buffer.read(nin)
|
||||
|
||||
nbytes = codec2.api.freedv_rawdatarx(freedv, bytes_out, data_in) # demodulate audio
|
||||
total_n_bytes = total_n_bytes + nbytes
|
||||
audio_buffer += sys.stdin.buffer.read(BUF_SIZE)
|
||||
|
||||
nin = codec2.api.freedv_nin(freedv) * 2
|
||||
|
||||
rx_status = codec2.api.freedv_get_rx_status(freedv)
|
||||
if DEBUGGING_MODE == True:
|
||||
rx_status_string = codec2.api.rx_sync_flags_to_text[rx_status]
|
||||
print(f"rx_status: {rx_status_string}", file=sys.stderr)
|
||||
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:]
|
||||
|
||||
|
||||
total_n_bytes = total_n_bytes + nbytes
|
||||
|
||||
if nbytes == bytes_per_frame:
|
||||
rx_total_frames = rx_total_frames + 1
|
||||
|
|
|
@ -37,7 +37,6 @@ N_FRAMES_PER_BURST = args.N_FRAMES_PER_BURST
|
|||
DELAY_BETWEEN_BURSTS = args.DELAY_BETWEEN_BURSTS/1000
|
||||
AUDIO_OUTPUT_DEVICE = args.AUDIO_OUTPUT_DEVICE
|
||||
|
||||
|
||||
MODE = codec2.FREEDV_MODE[args.FREEDV_MODE].value
|
||||
|
||||
|
||||
|
@ -49,8 +48,19 @@ assert (AUDIO_SAMPLE_RATE_TX % MODEM_SAMPLE_RATE) == 0
|
|||
|
||||
# check if we want to use an audio device then do an pyaudio init
|
||||
if AUDIO_OUTPUT_DEVICE != -1:
|
||||
# pyaudio init
|
||||
p = pyaudio.PyAudio()
|
||||
# auto search for loopback devices
|
||||
if AUDIO_OUTPUT_DEVICE == -2:
|
||||
loopback_list = []
|
||||
for dev in range(0,p.get_device_count()):
|
||||
if 'Loopback: PCM' in p.get_device_info_by_index(dev)["name"]:
|
||||
loopback_list.append(dev)
|
||||
if len(loopback_list) >= 2:
|
||||
AUDIO_OUTPUT_DEVICE = loopback_list[1] #0 = RX 1 = TX
|
||||
print(f"loopback_list tx: {loopback_list}", file=sys.stderr)
|
||||
else:
|
||||
quit()
|
||||
# pyaudio init
|
||||
stream_tx = p.open(format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=AUDIO_SAMPLE_RATE_TX,
|
||||
|
@ -115,7 +125,7 @@ for i in range(1,N_BURSTS+1):
|
|||
|
||||
txbuffer += bytes(mod_out)
|
||||
|
||||
print(f"BURST: {i}/{N_BURSTS} FRAME: {n}/{N_FRAMES_PER_BURST}", file=sys.stderr)
|
||||
print(f"TX BURST: {i}/{N_BURSTS} FRAME: {n}/{N_FRAMES_PER_BURST}", file=sys.stderr)
|
||||
|
||||
# append postamble to txbuffer
|
||||
codec2.api.freedv_rawdatapostambletx(freedv, mod_out_postamble)
|
||||
|
|
|
@ -18,8 +18,8 @@ RX_LOG=$(mktemp)
|
|||
# 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 --audiodev 4 --debug &
|
||||
python3 test_rx.py --mode datac0 --frames 2 --bursts 5 --audiodev -2 --debug &
|
||||
rx_pid=$!
|
||||
sleep 1
|
||||
python3 test_tx.py --mode datac0 --frames 2 --bursts 5 --delay 500 --audiodev 5
|
||||
python3 test_tx.py --mode datac0 --frames 2 --bursts 5 --delay 500 --audiodev -2
|
||||
wait ${rx_pid}
|
||||
|
|
29
test/001_highsnr_stdio_audio/test_virtual_mm.sh
Executable file
29
test/001_highsnr_stdio_audio/test_virtual_mm.sh
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash -x
|
||||
# Run a test using the virtual sound cards
|
||||
|
||||
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)
|
||||
|
||||
# make sure all child processes are killed when we exit
|
||||
trap 'jobs -p | xargs -r kill' EXIT
|
||||
|
||||
python3 test_multimode_rx.py --timeout 30 --framesperburst 2 --bursts 1 --audiodev -2 --debug &
|
||||
rx_pid=$!
|
||||
sleep 1
|
||||
python3 test_multimode_tx.py --framesperburst 2 --bursts 1 --audiodev -2
|
||||
|
||||
#tail -f ${RX_LOG} | sed '/RECEIVED BURSTS/ q'
|
||||
|
||||
|
||||
wait ${rx_pid}
|
Loading…
Reference in a new issue