Merge branch 'v2.0-dev' into ms-log-library

ms-log-library
Mooneer Salem 2024-11-23 08:09:15 -08:00
commit fb000c043c
20 changed files with 1151 additions and 33 deletions

View File

@ -15,33 +15,64 @@ jobs:
# well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install packages
shell: bash
run: |
sudo apt-get update
sudo apt-get install codespell libpulse-dev libspeexdsp-dev libsamplerate0-dev sox git libwxgtk3.0-gtk3-dev portaudio19-dev libhamlib-dev libasound2-dev libao-dev libgsm1-dev libsndfile-dev python3-numpy
sudo apt-get upgrade -y
sudo apt-get install codespell libpulse-dev libspeexdsp-dev libsamplerate0-dev sox git libwxgtk3.2-dev portaudio19-dev libhamlib-dev libasound2-dev libao-dev libgsm1-dev libsndfile-dev xvfb pipewire pulseaudio-utils pipewire-pulse wireplumber metacity dbus-x11 at-spi2-core rtkit
- name: Spellcheck codebase
shell: bash
run: codespell --ignore-words-list=radae,rade,inout,nin,ontop,parm,tthe,ue `find src -name '*.c*' -o -name '*.h' -o -name '*.mm'`
run: codespell --ignore-words-list=caf,radae,rade,inout,nin,ontop,parm,tthe,ue `find src -name '*.c*' -o -name '*.h' -o -name '*.mm'`
- name: Install Python required modules
shell: bash
working-directory: ${{github.workspace}}
run: |
python3 -m venv rade-venv
. ./rade-venv/bin/activate
pip3 install torch torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install matplotlib
- name: Build freedv-gui using PortAudio
shell: bash
working-directory: ${{github.workspace}}
run: UT_ENABLE=1 ./build_linux.sh portaudio
run: |
. ./rade-venv/bin/activate
UT_ENABLE=1 ./build_linux.sh portaudio
- name: Build freedv-gui using PulseAudio
shell: bash
working-directory: ${{github.workspace}}
run: UT_ENABLE=1 ./build_linux.sh pulseaudio
run: |
. ./rade-venv/bin/activate
UT_ENABLE=1 ./build_linux.sh pulseaudio
- name: Execute unit tests
shell: bash
working-directory: ${{github.workspace}}/build_linux
run: make test
run: |
sudo systemctl enable rtkit-daemon
sudo systemctl start rtkit-daemon
Xvfb :99 -screen 0 1024x768x16 &
sleep 5
export DISPLAY=:99.0
export XDG_RUNTIME_DIR=/run/user/$(id -u)
mkdir -p $XDG_RUNTIME_DIR
chmod 700 $XDG_RUNTIME_DIR
eval "$(dbus-launch --sh-syntax --exit-with-x11)"
pipewire &
pipewire-pulse &
wireplumber &
metacity --sm-disable --replace &
sleep 5
ln -s ${{github.workspace}}/build_linux/rade_src/model19_check3 model19_check3
. ../rade-venv/bin/activate
PYTHONPATH=${{github.workspace}}/build_linux/rade_src:$PYTHONPATH ctest -V

View File

@ -18,20 +18,31 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install packages
shell: bash
working-directory: ${{github.workspace}}
run: brew install automake libtool numpy
run: brew install automake libtool numpy sox
- name: Install virtual audio devices
shell: bash
working-directory: ${{github.workspace}}
run: ./build_macos_sound_drivers.sh
- name: Build freedv-gui
shell: bash
working-directory: ${{github.workspace}}
run: UT_ENABLE=1 ./build_osx.sh
- name: Workaround macOS permission issues
run: |
sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/opt/off/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
- name: Execute unit tests
shell: bash
working-directory: ${{github.workspace}}/build_osx
run: make test
run: |
FREEDV_COMPUTER_TO_RADIO_DEVICE="BlackHoleRadio 2ch" FREEDV_RADIO_TO_COMPUTER_DEVICE="BlackHoleRadio 2ch 2" FREEDV_COMPUTER_TO_SPEAKER_DEVICE="BlackHole1 2ch" FREEDV_MICROPHONE_TO_COMPUTER_DEVICE="BlackHole2 2ch" ctest -V

View File

@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install WINE
run: |
@ -48,6 +48,7 @@ jobs:
export WINEPREFIX=`pwd`/wine-env
wget https://www.python.org/ftp/python/3.12.7/python-3.12.7-amd64.exe
Xvfb :99 -screen 0 1024x768x16 &
sleep 10
export DISPLAY=:99.0
wine ./python-3.12.7-amd64.exe /quiet /log c:\\python.log InstallAllUsers=1 Include_doc=0 Include_tcltk=0 || :
cat $WINEPREFIX/drive_c/python.log
@ -76,3 +77,105 @@ jobs:
run: |
export PATH=${{github.workspace}}/llvm-mingw-20230320-ucrt-ubuntu-18.04-x86_64/bin:$PATH
make -j6 package
- name: Rename installer
shell: bash
working-directory: ${{github.workspace}}/build_windows
run: |
mv FreeDV*.exe FreeDV.exe
- name: Stash for next step
uses: actions/upload-artifact@v4
with:
name: FreeDVSetupProgram
path: ${{github.workspace}}/build_windows/FreeDV.exe
test:
runs-on: windows-latest
needs: build
env:
RADIO_TO_COMPUTER_DEVICE: "CABLE Output (VB-Audio Virtual Cable)"
COMPUTER_TO_RADIO_DEVICE: "Speakers (VB-Audio Virtual Cable)"
MICROPHONE_TO_COMPUTER_DEVICE: "Line 1 (Virtual Audio Cable)"
COMPUTER_TO_SPEAKER_DEVICE: "Line 1 (Virtual Audio Cable)"
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: FreeDVSetupProgram
path: ${{github.workspace}}
- uses: ilammy/msvc-dev-cmd@v1
- name: Install FreeDV on hard drive
shell: pwsh
run: |
.\FreeDV.exe /S /D=${{github.workspace}}\FreeDV-Install-Location | Out-Null
- name: Copy test script to install folder
shell: pwsh
run: |
Copy-Item -Path ${{github.workspace}}/test/TestFreeDVFullDuplex.ps1 -Destination ${{github.workspace}}\FreeDV-Install-Location\bin
Copy-Item -Path ${{github.workspace}}/test/freedv-ctest-fullduplex.conf.tmpl -Destination ${{github.workspace}}\FreeDV-Install-Location\bin
- name: Install VB-Cable ("Radio" sound device)
uses: LABSN/sound-ci-helpers@v1
- run: 'Invoke-WebRequest https://software.muzychenko.net/trials/vac464.zip -OutFile vac464.zip'
- run: 'Expand-Archive -Path vac464.zip -DestinationPath vac464'
- run: 'Import-Certificate -FilePath ${{github.workspace}}\test\vac464.cer -CertStoreLocation Cert:\LocalMachine\root'
- run: 'Import-Certificate -FilePath ${{github.workspace}}\test\vac464.cer -CertStoreLocation Cert:\LocalMachine\TrustedPublisher'
- name: Install driver
shell: pwsh
run: |
.\vac464\setup64.exe -s -k 30570681-0a8b-46e5-8cb2-d835f43af0c5 | Out-Null
Start-Sleep -Seconds 10
# For convenience, make sure we fail fast if for whatever reason the install gets blocked on some GUI prompt.
timeout-minutes: 5
- name: Grant FreeDV access to the microphone
run: |
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone" -Name Value -Value Allow
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone" -Name Value -Value Allow
New-Item -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone\" -Name "NonPackaged" -Force
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone\NonPackaged" -Name Value -Value Allow
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\" -Name "AppPrivacy" -Force
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy" -Name LetAppsAccessMicrophone -Value 0
- name: Start Windows Audio Service
run: |
net start audiosrv
- name: List audio devices
shell: pwsh
run: |
Get-CimInstance win32_sounddevice
- name: Test RADE
shell: pwsh
working-directory: ${{github.workspace}}\FreeDV-Install-Location\bin
run: |
.\TestFreeDVFullDuplex.ps1 -RadioToComputerDevice "${{env.RADIO_TO_COMPUTER_DEVICE}}" -ComputerToRadioDevice "${{env.COMPUTER_TO_RADIO_DEVICE}}" -MicrophoneToComputerDevice "${{env.MICROPHONE_TO_COMPUTER_DEVICE}}" -ComputerToSpeakerDevice "${{env.COMPUTER_TO_SPEAKER_DEVICE}}" -ModeToTest RADE -NumberOfRuns 1
timeout-minutes: 5
- name: Test 700D
shell: pwsh
working-directory: ${{github.workspace}}\FreeDV-Install-Location\bin
run: |
.\TestFreeDVFullDuplex.ps1 -RadioToComputerDevice "${{env.RADIO_TO_COMPUTER_DEVICE}}" -ComputerToRadioDevice "${{env.COMPUTER_TO_RADIO_DEVICE}}" -MicrophoneToComputerDevice "${{env.MICROPHONE_TO_COMPUTER_DEVICE}}" -ComputerToSpeakerDevice "${{env.COMPUTER_TO_SPEAKER_DEVICE}}" -ModeToTest 700D -NumberOfRuns 1
timeout-minutes: 5
- name: Test 700E
shell: pwsh
working-directory: ${{github.workspace}}\FreeDV-Install-Location\bin
run: |
.\TestFreeDVFullDuplex.ps1 -RadioToComputerDevice "${{env.RADIO_TO_COMPUTER_DEVICE}}" -ComputerToRadioDevice "${{env.COMPUTER_TO_RADIO_DEVICE}}" -MicrophoneToComputerDevice "${{env.MICROPHONE_TO_COMPUTER_DEVICE}}" -ComputerToSpeakerDevice "${{env.COMPUTER_TO_SPEAKER_DEVICE}}" -ModeToTest 700E -NumberOfRuns 1
timeout-minutes: 5
- name: Test 1600
shell: pwsh
working-directory: ${{github.workspace}}\FreeDV-Install-Location\bin
run: |
.\TestFreeDVFullDuplex.ps1 -RadioToComputerDevice "${{env.RADIO_TO_COMPUTER_DEVICE}}" -ComputerToRadioDevice "${{env.COMPUTER_TO_RADIO_DEVICE}}" -MicrophoneToComputerDevice "${{env.MICROPHONE_TO_COMPUTER_DEVICE}}" -ComputerToSpeakerDevice "${{env.COMPUTER_TO_SPEAKER_DEVICE}}" -ModeToTest 1600 -NumberOfRuns 1
timeout-minutes: 5

View File

@ -719,3 +719,17 @@ elseif(UNIX AND NOT APPLE)
include(CPack)
endif(WIN32)
if(UNITTEST)
# The below tests are currently Linux-only due to a dependency on
# PulseAudio/pipewire.
macro(DefineAudioTest utName)
add_test(NAME fullduplex_${utName} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test/test_zeros.sh txrx ${utName})
set_tests_properties(fullduplex_${utName} PROPERTIES PASS_REGULAR_EXPRESSION "Got 1 sync changes")
endmacro()
DefineAudioTest(RADE)
DefineAudioTest(700D)
DefineAudioTest(700E)
DefineAudioTest(1600)
endif(UNITTEST)

View File

@ -0,0 +1,51 @@
#!/bin/bash
git clone https://github.com/tmiw/BlackHole.git
cd BlackHole
bundleID=audio.existential.BlackHoleRadio
driverName=BlackHoleRadio
xcodebuild \
-project BlackHole.xcodeproj \
-configuration Release \
-target BlackHole \
CONFIGURATION_BUILD_DIR=build \
PRODUCT_BUNDLE_IDENTIFIER=$bundleID \
GCC_PREPROCESSOR_DEFINITIONS="$GCC_PREPROCESSOR_DEFINITIONS \
kNumber_Of_Channels='2' \
kPlugIn_BundleID='\"$bundleID\"' \
kDriver_Name='\"$driverName\"' \
kDevice2_IsHidden=false \
kDevice2_HasInput=true \
kDevice2_HasOutput=true" \
MACOSX_DEPLOYMENT_TARGET=10.13
sudo mv build/BlackHole.driver /Library/Audio/Plug-Ins/HAL/$driverName.driver
for i in {1..2}; do
git reset --hard
rm -rf build
export bundleID=audio.existential.BlackHole$i
export driverName=BlackHole$i
xcodebuild \
-project BlackHole.xcodeproj \
-configuration Release \
-target BlackHole \
CONFIGURATION_BUILD_DIR=build \
PRODUCT_BUNDLE_IDENTIFIER=$bundleID \
GCC_PREPROCESSOR_DEFINITIONS="$GCC_PREPROCESSOR_DEFINITIONS \
kNumber_Of_Channels='2' \
kPlugIn_BundleID='\"$bundleID\"' \
kDriver_Name='\"$driverName\"' \
kDevice2_IsHidden=false \
kDevice2_HasInput=true \
kDevice2_HasOutput=true" \
MACOSX_DEPLOYMENT_TARGET=10.13
sudo mv build/BlackHole.driver /Library/Audio/Plug-Ins/HAL/$driverName.driver
done
sudo killall -9 coreaudiod

View File

@ -13,7 +13,7 @@ ExternalProject_Add(build_rade
SOURCE_DIR rade_src
BINARY_DIR rade_build
GIT_REPOSITORY https://github.com/drowe67/radae.git
GIT_TAG dr-reset
GIT_TAG main
CMAKE_ARGS ${RADE_CMAKE_ARGS}
#CMAKE_CACHE_ARGS -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}
INSTALL_COMMAND ""

View File

@ -1,4 +1,5 @@
#set(BUILD_SHARED_LIBS OFF CACHE STRING "Disable shared libraries for portaudio")
#set(PA_ENABLE_DEBUG_OUTPUT ON CACHE STRING "Enable debug output")
include(FetchContent)
FetchContent_Declare(

View File

@ -139,6 +139,7 @@ void PulseAudioDevice::start()
outputPendingLength_ = 0;
targetOutputPendingLength_ = PULSE_FPB * getNumChannels() * 2;
outputPendingThreadActive_ = true;
#if 0
if (direction_ == IAudioEngine::AUDIO_ENGINE_OUT)
{
outputPendingThread_ = new std::thread([&]() {
@ -194,6 +195,7 @@ void PulseAudioDevice::start()
});
assert(outputPendingThread_ != nullptr);
}
#endif
}
pa_threaded_mainloop_unlock(mainloop_);
@ -262,6 +264,7 @@ void PulseAudioDevice::StreamWriteCallback_(pa_stream *s, size_t length, void *u
memset(data, 0, sizeof(data));
PulseAudioDevice* thisObj = static_cast<PulseAudioDevice*>(userdata);
#if 0
{
std::unique_lock<std::mutex> lk(thisObj->outputPendingMutex_);
if (thisObj->outputPendingLength_ >= numSamples)
@ -280,7 +283,12 @@ void PulseAudioDevice::StreamWriteCallback_(pa_stream *s, size_t length, void *u
thisObj->targetOutputPendingLength_ = std::max(thisObj->targetOutputPendingLength_, 2 * numSamples);
}
#endif
if (thisObj->onAudioDataFunction)
{
thisObj->onAudioDataFunction(*thisObj, data, numSamples / thisObj->getNumChannels(), thisObj->onAudioDataState);
}
pa_stream_write(s, &data[0], length, NULL, 0LL, PA_SEEK_RELATIVE);
}
}

View File

@ -74,7 +74,8 @@ FreeDVInterface::FreeDVInterface() :
lastSyncRxMode_(nullptr),
rade_(nullptr),
lpcnetEncState_(nullptr),
radeTxStep_(nullptr)
radeTxStep_(nullptr),
sync_(0)
{
// empty
}
@ -127,6 +128,7 @@ float FreeDVInterface::GetMinimumSNR_(int mode)
void FreeDVInterface::start(int txMode, int fifoSizeMs, bool singleRxThread, bool usingReliableText)
{
sync_ = 0;
singleRxThread_ = singleRxThread;
modemStatsList_ = new MODEM_STATS[enabledModes_.size()];
@ -428,13 +430,7 @@ void FreeDVInterface::setSync(int val)
int FreeDVInterface::getSync() const
{
// Special case for RADE.
if (currentRxMode_ == nullptr)
{
return rade_sync(rade_);
}
return freedv_get_sync(currentRxMode_);
return sync_;
}
void FreeDVInterface::setEq(int val)
@ -678,7 +674,7 @@ IPipelineStep* FreeDVInterface::createTransmitPipeline(int inputSampleRate, int
std::function<int(ParallelStep*)> modeFn =
[&](ParallelStep*) {
int index = 0;
// Special handling for RADE.
if (txMode_ >= FREEDV_MODE_RADE) return 0;
@ -881,5 +877,7 @@ skipSyncCheck:
*state->getRxStateFn() = rade_sync(rade_);
}
sync_ = *state->getRxStateFn();
return indexWithSync;
};

View File

@ -191,7 +191,8 @@ private:
FARGANState fargan_;
LPCNetEncState *lpcnetEncState_;
RADETransmitStep *radeTxStep_;
int sync_;
int preProcessRxFn_(ParallelStep* ps);
int postProcessRxFn_(ParallelStep* ps);
};

View File

@ -31,6 +31,7 @@
#include <climits>
#include <wx/cmdline.h>
#include <wx/stdpaths.h>
#include <wx/uiaction.h>
#include "version.h"
#include "main.h"
@ -51,6 +52,8 @@
#include "rade_api.h"
using namespace std::chrono_literals;
#define wxUSE_FILEDLG 1
#define wxUSE_LIBPNG 1
#define wxUSE_LIBJPEG 1
@ -185,15 +188,174 @@ FILE *ftest;
// Config file management
wxConfigBase *pConfig = NULL;
// Unit test management
wxString testName;
wxString utFreeDVMode;
// WxWidgets - initialize the application
IMPLEMENT_APP(MainApp);
void MainApp::UnitTest_()
{
// List audio devices
auto engine = AudioEngineFactory::GetAudioEngine();
engine->start();
for (auto& dev : engine->getAudioDeviceList(IAudioEngine::AUDIO_ENGINE_IN))
{
fprintf(stderr, "Input audio device: %s (ID %d, sample rate %d, valid channels: %d-%d)\n", (const char*)dev.name.ToUTF8(), dev.deviceId, dev.defaultSampleRate, dev.minChannels, dev.maxChannels);
}
for (auto& dev : engine->getAudioDeviceList(IAudioEngine::AUDIO_ENGINE_OUT))
{
fprintf(stderr, "Output audio device: %s (ID %d, sample rate %d, valid channels: %d-%d)\n", (const char*)dev.name.ToUTF8(), dev.deviceId, dev.defaultSampleRate, dev.minChannels, dev.maxChannels);
}
engine->stop();
// Bring window to the front
CallAfter([&]() {
frame->Iconize(false);
frame->SetFocus();
frame->Raise();
frame->Show(true);
});
// Wait 100ms for FreeDV to come to foreground
std::this_thread::sleep_for(100ms);
// Select FreeDV mode. Note, 2020 is deprecated so not testable here.
wxRadioButton* modeBtn = nullptr;
if (utFreeDVMode == "RADE")
{
modeBtn = frame->m_rbRADE;
}
/*else if (utFreeDVMode == "700C")
{
modeBtn = frame->m_rb700c;
}*/
else if (utFreeDVMode == "700D")
{
modeBtn = frame->m_rb700d;
}
else if (utFreeDVMode == "700E")
{
modeBtn = frame->m_rb700e;
}
/*else if (utFreeDVMode == "800XA")
{
modeBtn = frame->m_rb800xa;
}*/
else if (utFreeDVMode == "1600")
{
modeBtn = frame->m_rb1600;
}
if (modeBtn != nullptr)
{
fprintf(stderr, "Firing mode change\n");
/*sim.MouseMove(modeBtn->GetScreenPosition());
sim.MouseClick();*/
CallAfter([&]() {
modeBtn->SetValue(true);
wxCommandEvent* modeEvent = new wxCommandEvent(wxEVT_RADIOBUTTON, modeBtn->GetId());
modeEvent->SetEventObject(modeBtn);
QueueEvent(modeEvent);
});
}
// Fire event to start FreeDV
fprintf(stderr, "Firing start\n");
CallAfter([&]() {
frame->m_togBtnOnOff->SetValue(true);
wxCommandEvent* onEvent = new wxCommandEvent(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, frame->m_togBtnOnOff->GetId());
onEvent->SetEventObject(frame->m_togBtnOnOff);
frame->OnTogBtnOnOff(*onEvent);
delete onEvent;
//QueueEvent(onEvent);
});
/*sim.MouseMove(frame->m_togBtnOnOff->GetScreenPosition());
sim.MouseClick();*/
// Wait 5 seconds for FreeDV to start
std::this_thread::sleep_for(5s);
if (testName == "tx")
{
// Fire event to begin TX
//sim.MouseMove(frame->m_btnTogPTT->GetScreenPosition());
//sim.MouseClick();
fprintf(stderr, "Firing PTT\n");
CallAfter([&]() {
frame->m_btnTogPTT->SetValue(true);
wxCommandEvent* txEvent = new wxCommandEvent(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, frame->m_btnTogPTT->GetId());
txEvent->SetEventObject(frame->m_btnTogPTT);
//QueueEvent(txEvent);
frame->OnTogBtnPTT(*txEvent);
delete txEvent;
});
// Transmit for 60 seconds
std::this_thread::sleep_for(60s);
// Stop transmitting
fprintf(stderr, "Firing PTT\n");
CallAfter([&]() {
frame->m_btnTogPTT->SetValue(false);
wxCommandEvent* rxEvent = new wxCommandEvent(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, frame->m_btnTogPTT->GetId());
rxEvent->SetEventObject(frame->m_btnTogPTT);
frame->OnTogBtnPTT(*rxEvent);
delete rxEvent;
//QueueEvent(rxEvent);
});
/*sim.MouseMove(frame->m_btnTogPTT->GetScreenPosition());
sim.MouseClick();*/
// Wait 5 seconds for FreeDV to stop
std::this_thread::sleep_for(5s);
}
else
{
// Receive for 60 seconds
auto sync = 0;
for (int i = 0; i < 60*10; i++)
{
std::this_thread::sleep_for(100ms);
auto newSync = freedvInterface.getSync();
if (newSync != sync)
{
fprintf(stderr, "Sync changed from %d to %d\n", sync, newSync);
sync = newSync;
}
}
}
// Fire event to stop FreeDV
fprintf(stderr, "Firing stop\n");
CallAfter([&]() {
wxCommandEvent* offEvent = new wxCommandEvent(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, frame->m_togBtnOnOff->GetId());
offEvent->SetEventObject(frame->m_togBtnOnOff);
frame->m_togBtnOnOff->SetValue(false);
//QueueEvent(offEvent);
frame->OnTogBtnOnOff(*offEvent);
delete offEvent;
});
//sim.MouseMove(frame->m_togBtnOnOff->GetScreenPosition());
//sim.MouseClick();
// Wait 5 seconds for FreeDV to stop
std::this_thread::sleep_for(5s);
// Destroy main window to exit application. Must be done in UI thread to avoid problems.
CallAfter([&]() {
frame->Destroy();
});
}
void MainApp::OnInitCmdLine(wxCmdLineParser& parser)
{
wxApp::OnInitCmdLine(parser);
parser.AddOption("f", "config", "Use different configuration file instead of the default.");
parser.AddOption("ut", "unit_test", "Execute FreeDV in unit test mode.");
parser.AddOption("utmode", wxEmptyString, "Switch FreeDV to the given mode before UT execution.");
}
bool MainApp::OnCmdLineParsed(wxCmdLineParser& parser)
@ -219,6 +381,15 @@ bool MainApp::OnCmdLineParsed(wxCmdLineParser& parser)
}
pConfig->SetRecordDefaults();
if (parser.Found("ut", &testName))
{
fprintf(stderr, "Executing test %s\n", (const char*)testName.ToUTF8());
if (parser.Found("utmode", &utFreeDVMode))
{
fprintf(stderr, "Using mode %s for tests\n", (const char*)utFreeDVMode.ToUTF8());
}
}
return true;
}
@ -301,8 +472,15 @@ bool MainApp::OnInit()
frame->m_auiNbookCtrl->ChangeSelection(0);
frame->Layout();
frame->Show();
g_parent =frame;
g_parent = frame;
// Begin test execution
if (testName != "")
{
std::thread utThread(std::bind(&MainApp::UnitTest_, this));
utThread.detach();
}
return true;
}
@ -2789,15 +2967,15 @@ void MainFrame::startRxStream()
// loop.
int m_fifoSize_ms = wxGetApp().appConfiguration.fifoSizeMs;
int soundCard1InFifoSizeSamples = m_fifoSize_ms*wxGetApp().appConfiguration.audioConfiguration.soundCard1In.sampleRate/1000;
int soundCard1OutFifoSizeSamples = m_fifoSize_ms*wxGetApp().appConfiguration.audioConfiguration.soundCard1Out.sampleRate/1000;
int soundCard1InFifoSizeSamples = wxGetApp().appConfiguration.audioConfiguration.soundCard1In.sampleRate;
int soundCard1OutFifoSizeSamples = wxGetApp().appConfiguration.audioConfiguration.soundCard1Out.sampleRate;
g_rxUserdata->infifo1 = codec2_fifo_create(soundCard1InFifoSizeSamples);
g_rxUserdata->outfifo1 = codec2_fifo_create(soundCard1OutFifoSizeSamples);
if (txInSoundDevice && txOutSoundDevice)
{
int soundCard2InFifoSizeSamples = m_fifoSize_ms*wxGetApp().appConfiguration.audioConfiguration.soundCard2In.sampleRate/1000;
int soundCard2OutFifoSizeSamples = m_fifoSize_ms*wxGetApp().appConfiguration.audioConfiguration.soundCard2Out.sampleRate/1000;
int soundCard2InFifoSizeSamples = m_fifoSize_ms*wxGetApp().appConfiguration.audioConfiguration.soundCard2In.sampleRate / 1000;
int soundCard2OutFifoSizeSamples = m_fifoSize_ms*wxGetApp().appConfiguration.audioConfiguration.soundCard2Out.sampleRate / 1000;
g_rxUserdata->outfifo2 = codec2_fifo_create(soundCard2OutFifoSizeSamples);
g_rxUserdata->infifo2 = codec2_fifo_create(soundCard2InFifoSizeSamples);
@ -2880,15 +3058,18 @@ void MainFrame::startRxStream()
// Set sound card callbacks
auto errorCallback = [&](IAudioDevice&, std::string error, void*)
{
CallAfter([&, error]() {
fprintf(stderr, "AUDIO ERROR: %s\n", error.c_str());
/*CallAfter([&, error]() {
wxMessageBox(wxString::Format("Error encountered while processing audio: %s", error), wxT("Error"), wxOK);
});
});*/
};
rxInSoundDevice->setOnAudioData([&](IAudioDevice& dev, void* data, size_t size, void* state) {
paCallBackData* cbData = static_cast<paCallBackData*>(state);
short* audioData = static_cast<short*>(data);
short indata[size];
//fprintf(stderr, "recoded %d samples\n", size);
for (size_t i = 0; i < size; i++, audioData += dev.getNumChannels())
{
indata[i] = audioData[0];
@ -2896,6 +3077,7 @@ void MainFrame::startRxStream()
if (codec2_fifo_write(cbData->infifo1, indata, size))
{
fprintf(stderr, "RX FIFO full\n");
g_infifo1_full++;
}

View File

@ -224,6 +224,8 @@ class MainApp : public wxApp
int m_reportCounter;
protected:
private:
void UnitTest_();
};
// declare global static function wxGetApp()
@ -441,6 +443,8 @@ class MainFrame : public TopFrame
void OnSetMonitorTxAudioVol( wxCommandEvent& event );
private:
friend class MainApp; // needed for unit tests
std::shared_ptr<IAudioDevice> rxInSoundDevice;
std::shared_ptr<IAudioDevice> rxOutSoundDevice;
std::shared_ptr<IAudioDevice> txInSoundDevice;

View File

@ -20,6 +20,9 @@
//
//=========================================================================
#include <chrono>
using namespace std::chrono_literals;
// This forces us to use freedv-gui's version rather than another one.
// TBD -- may not be needed once we fully switch over to the audio pipeline.
#include "../defines.h"
@ -479,6 +482,7 @@ void* TxRxThread::Entry()
pthread_setname_np(pthread_self(), threadName);
#endif // defined(__linux__)
#if 0
{
std::unique_lock<std::mutex> lk(m_processingMutex);
if (m_processingCondVar.wait_for(lk, std::chrono::milliseconds(100)) == std::cv_status::timeout)
@ -486,9 +490,15 @@ void* TxRxThread::Entry()
log_warn("txRxThread: timeout while waiting for CV, tx = %d", m_tx);
}
}
#endif
auto currentTime = std::chrono::steady_clock::now();
if (!m_run) break;
if (m_tx) txProcessing_();
else rxProcessing_();
std::this_thread::sleep_until(currentTime + 20ms);
}
// Force pipeline to delete itself when we're done with the thread.
@ -510,8 +520,10 @@ void TxRxThread::terminateThread()
void TxRxThread::notify()
{
#if 0
std::unique_lock<std::mutex> lk(m_processingMutex);
m_processingCondVar.notify_all();
#endif
}
void TxRxThread::clearFifos_()

View File

@ -82,9 +82,7 @@ class wxListViewComboPopup;
/// Class TopFrame
///////////////////////////////////////////////////////////////////////////////
class TopFrame : public wxFrame
{
private:
{
protected:
wxPanel* m_panel;
wxMenuBar* m_menubarMain;

View File

@ -0,0 +1,138 @@
<#
.SYNOPSIS
Executes full-duplex test of FreeDV.
.DESCRIPTION
This script starts FreeDV in full-duplex mode for approximately 60 seconds using an autogenerated configuration file
that will access the audio devices passed in. After 60 seconds, FreeDV will terminate and this script will examine
the output to determine the number of times that it went into and out of sync. If it detects that FreeDV went out
of sync during the test, the test is marked as having failed.
.INPUTS
None. You can't pipe objects to this script.
.OUTPUTS
The script outputs the mode tested as well as the number of passed/failed tests to the console.
.EXAMPLE
PS> .\TestFreeDVFullDuplex.ps1 -ModeToTest RADE -RadioToComputerDevice "Microphone (USB Audio CODEC)" -ComputerToRadioDevice "Speakers (USB Audio CODEC)" -ComputerToSpeakerDevice "Speakers (Realtek High Definition Audio(SST))" -MicrophoneToComputerDevice "Microphone Array (Realtek High Definition Audio(SST))"
#>
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
# The sound device to receive RX audio from.
$RadioToComputerDevice,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
# The sound device to emit decoded audio to.
$ComputerToSpeakerDevice,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
# The sound device to receive analog audio from.
$MicrophoneToComputerDevice,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]
# The sound device to emit TX audio to.
$ComputerToRadioDevice,
[ValidateSet("RADE", "700D", "700E", "1600")]
[ValidateNotNullOrEmpty()]
[string]
# The FreeDV mode to use for testing.
$ModeToTest="RADE",
[int]
# The number of times to execute the test.
$NumberOfRuns=10)
<#
.Description
Performs the actual test with FreeDV by generating the needed configuration file, starting FreeDV and then examining the output.
#>
function Test-FreeDV {
param (
$ModeToTest,
$RadioToComputerDevice,
$ComputerToSpeakerDevice,
$MicrophoneToComputerDevice,
$ComputerToRadioDevice
)
$current_loc = Get-Location
# Generate new conf
$conf_tmpl = Get-Content "$current_loc\freedv-ctest-fullduplex.conf.tmpl"
$conf_tmpl = $conf_tmpl.Replace("@FREEDV_RADIO_TO_COMPUTER_DEVICE@", $RadioToComputerDevice)
$conf_tmpl = $conf_tmpl.Replace("@FREEDV_COMPUTER_TO_RADIO_DEVICE@", $ComputerToRadioDevice)
$conf_tmpl = $conf_tmpl.Replace("@FREEDV_MICROPHONE_TO_COMPUTER_DEVICE@", $MicrophoneToComputerDevice)
$conf_tmpl = $conf_tmpl.Replace("@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@", $ComputerToSpeakerDevice)
$tmp_file = New-TemporaryFile
$conf_tmpl | Set-Content -Path $tmp_file.FullName
# Start freedv.exe
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardError = $true
$psi.RedirectStandardOutput = $true
$psi.FileName = "$current_loc\freedv.exe"
$psi.WorkingDirectory = $current_loc
$quoted_tmp_filename = "`"" + $tmp_file.FullName + "`""
$psi.Arguments = @("/f $quoted_tmp_filename /ut txrx /utmode $ModeToTest")
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
[void]$process.Start()
# Read output from process
$err_output = $process.StandardError.ReadToEnd();
$output = $process.StandardOutput.ReadToEnd();
$process.WaitForExit()
Write-Host "$err_output"
$syncs = $err_output.Split([Environment]::NewLine) | Where { $_.Contains("Sync changed") }
if ($syncs.Count -eq 1) {
return $true
}
return $false
}
$passes = 0
$fails = 0
for (($i = 0); $i -lt $NumberOfRuns; $i++)
{
$result = Test-FreeDV `
-ModeToTest $ModeToTest `
-RadioToComputerDevice $RadioToComputerDevice `
-ComputerToSpeakerDevice $ComputerToSpeakerDevice `
-MicrophoneToComputerDevice $MicrophoneToComputerDevice `
-ComputerToRadioDevice $ComputerToRadioDevice
if ($result -eq $true)
{
$passes++
}
else
{
$fails++
}
}
Write-Host "Mode: $ModeToTest, Total Runs: $NumberOfRuns, Passed: $passes, Failures: $fails"
if ($fails -gt 0) {
throw "Test failed"
exit 1
}

View File

@ -0,0 +1,30 @@
#!/usr/bin/python3
import sys
import struct
index = 0
detected = False
detected_index = -1
first_detected_index = -1
with open(sys.argv[1], "rb") as f:
while True:
bytes_to_read = struct.calcsize("h")
buffer = f.read(bytes_to_read)
if len(buffer) != bytes_to_read:
break
if buffer[0] == 0:
if first_detected_index == -1:
first_detected_index = index
detected = True
detected_index = index
elif index == (detected_index + 1):
if (index - first_detected_index) > 1:
sys.stderr.write(f"Zero audio detected at index {index} ({index / 8000} seconds)")
sys.stderr.write(f" - lasted {(index - first_detected_index) / 8000} seconds\n")
first_detected_index = -1
index = index + 1
if detected is False:
print("No zeros found.")

View File

@ -0,0 +1,189 @@
FirstTimeUse=0
ExperimentalFeatures=0
[Audio]
soundCard1SampleRate=-1
soundCard2SampleRate=-1
soundCard1InDeviceName=@FREEDV_RADIO_TO_COMPUTER_DEVICE@
soundCard1InSampleRate=48000
soundCard1OutDeviceName=@FREEDV_COMPUTER_TO_RADIO_DEVICE@
soundCard1OutSampleRate=48000
soundCard2InDeviceName=@FREEDV_MICROPHONE_TO_COMPUTER_DEVICE@
soundCard2InSampleRate=48000
soundCard2OutDeviceName=@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@
soundCard2OutSampleRate=48000
SquelchActive=1
SquelchLevel=-4
fifoSize_ms=440
transmitLevel=0
snrSlow=0
mode=4
TxRxDelayMilliseconds=0
[Filter]
codec2LPCPostFilterGamma=50
codec2LPCPostFilterBeta=20
MicInBassFreqHz=100
MicInBassGaindB=0
MicInTrebleFreqHz=3000
MicInTrebleGaindB=0
MicInMidFreqHz=1500
MicInMidGaindB=0
MicInMidQ=100
MicInVolInDB=0
SpkOutBassFreqHz=100
SpkOutBassGaindB=0
SpkOutTrebleFreqHz=3000
SpkOutTrebleGaindB=0
SpkOutMidFreqHz=1500
SpkOutMidGaindB=0
SpkOutMidQ=100
SpkOutVolInDB=0
codec2LPCPostFilterEnable=1
codec2LPCPostFilterBassBoost=1
speexpp_enable=1
700C_EQ=1
[Filter/MicIn]
EQEnable=0
BassFreqHz=100
BassGaindB=0
TrebleFreqHz=3000
TrebleGaindB=0
MidFreqHz=1500
MidGaindB=0
MidQ=1
VolInDB=0
[Filter/SpkOut]
EQEnable=0
BassFreqHz=100
BassGaindB=0
TrebleFreqHz=3000
TrebleGaindB=0
MidFreqHz=1500
MidGaindB=0
MidQ=1
VolInDB=0
[Filter/codec2LPCPostFilter]
Gamma=50
Beta=20
[Hamlib]
UseForPTT=0
EnableFreqModeChanges=1
UseAnalogModes=0
IcomCIVHex=0
RigNameStr=ADAT www.adat.ch ADT-200A
PttType=0
SerialRate=0
SerialPort=
PttSerialPort=
RigName=0
[Rig]
UseSerialPTT=0
Port=
UseRTS=1
RTSPolarity=1
UseDTR=0
DTRPolarity=0
UseSerialPTTInput=0
PttInPort=
CTSPolarity=0
leftChannelVoxTone=0
EnableSpacebarForPTT=1
HalfDuplex=0
MultipleRx=1
SingleRxThread=0
[PSKReporter]
Enable=0
Callsign=
GridSquare=
FrequencyHzStr=0
[Data]
CallSign=
[Reporting]
Enable=0
Callsign=
GridSquare=
FrequencyAsKHz=0
FrequencyList=1.997000,3.625000,3.643000,3.693000,3.697000,3.850000,5.403500,5.366500,5.368500,7.177000,7.197000,14.236000,14.240000,18.118000,21.313000,24.933000,28.330000,28.720000,10489.640000
ManualFrequencyReporting=0
DirectionAsCardinal=0
Frequency=0
[Reporting/PSKReporter]
Enable=1
[Reporting/FreeDV]
Enable=1
Hostname=qso.freedv.org
CurrentBandFilter=0
UseMetricDistances=1
BandFilterTracksFrequency=0
ForceReceiveOnly=0
StatusText=
RecentStatusTexts=
TxRowBackgroundColor=#FC4500
TxRowForegroundColor=#000000
RxRowBackgroundColor=#379BAF
RxRowForegroundColor=#000000
MsgRowBackgroundColor=#E58BE5
MsgRowForegroundColor=#000000
[Reporting/FreeDV/BandFilterTracking]
TracksFreqBand=1
TracksExactFreq=0
[CallsignList]
UseUTCTime=0
[FreeDV2020]
Allowed=0
[MainFrame]
left=26
top=23
width=800
height=780
rxNbookCtrl=0
TabLayout=
[Windows]
[Windows/AudioConfig]
left=26
top=23
width=1148
height=732
[Windows/FreeDVReporter]
left=20
top=20
width=-1
height=-1
visible=0
currentSort=-1
currentSortDirection=1
reportingUserMsgColWidth=130
[File]
playFileToMicInPath=
recFileFromRadioPath=
recFileFromRadioSecs=60
recFileFromModulatorPath=
recFileFromModulatorSecs=60
playFileFromRadioPath=
[VoiceKeyer]
WaveFilePath=/home/mooneer/Documents
WaveFile=
RxPause=10
Repeats=5
[FreeDV700]
txClip=1
txBPF=1
[Noise]
noise_snr=2
[Debug]
console=0
verbose=0
APIverbose=0
[Waterfall]
Color=0
[Stats]
ResetTime=10
[Plot]
[Plot/Spectrum]
CurrentAveraging=0
[Monitor]
VoiceKeyerAudio=0
TransmitAudio=0
VoiceKeyerAudioVol=0
TransmitAudioVol=0
[QuickRecord]
SavePath=/home/mooneer/Documents

View File

@ -0,0 +1,189 @@
FirstTimeUse=0
ExperimentalFeatures=0
[Audio]
soundCard1SampleRate=-1
soundCard2SampleRate=-1
soundCard1InDeviceName=@FREEDV_RADIO_TO_COMPUTER_DEVICE@
soundCard1InSampleRate=48000
soundCard1OutDeviceName=@FREEDV_COMPUTER_TO_RADIO_DEVICE@
soundCard1OutSampleRate=48000
soundCard2InDeviceName=@FREEDV_MICROPHONE_TO_COMPUTER_DEVICE@
soundCard2InSampleRate=48000
soundCard2OutDeviceName=@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@
soundCard2OutSampleRate=48000
SquelchActive=1
SquelchLevel=-4
fifoSize_ms=440
transmitLevel=0
snrSlow=0
mode=257
TxRxDelayMilliseconds=0
[Filter]
codec2LPCPostFilterGamma=50
codec2LPCPostFilterBeta=20
MicInBassFreqHz=100
MicInBassGaindB=0
MicInTrebleFreqHz=3000
MicInTrebleGaindB=0
MicInMidFreqHz=1500
MicInMidGaindB=0
MicInMidQ=100
MicInVolInDB=0
SpkOutBassFreqHz=100
SpkOutBassGaindB=0
SpkOutTrebleFreqHz=3000
SpkOutTrebleGaindB=0
SpkOutMidFreqHz=1500
SpkOutMidGaindB=0
SpkOutMidQ=100
SpkOutVolInDB=0
codec2LPCPostFilterEnable=1
codec2LPCPostFilterBassBoost=1
speexpp_enable=1
700C_EQ=1
[Filter/MicIn]
EQEnable=0
BassFreqHz=100
BassGaindB=0
TrebleFreqHz=3000
TrebleGaindB=0
MidFreqHz=1500
MidGaindB=0
MidQ=1
VolInDB=0
[Filter/SpkOut]
EQEnable=0
BassFreqHz=100
BassGaindB=0
TrebleFreqHz=3000
TrebleGaindB=0
MidFreqHz=1500
MidGaindB=0
MidQ=1
VolInDB=0
[Filter/codec2LPCPostFilter]
Gamma=50
Beta=20
[Hamlib]
UseForPTT=0
EnableFreqModeChanges=1
UseAnalogModes=0
IcomCIVHex=0
RigNameStr=ADAT www.adat.ch ADT-200A
PttType=0
SerialRate=0
SerialPort=
PttSerialPort=
RigName=0
[Rig]
UseSerialPTT=0
Port=
UseRTS=1
RTSPolarity=1
UseDTR=0
DTRPolarity=0
UseSerialPTTInput=0
PttInPort=
CTSPolarity=0
leftChannelVoxTone=0
EnableSpacebarForPTT=1
HalfDuplex=1
MultipleRx=1
SingleRxThread=1
[PSKReporter]
Enable=0
Callsign=
GridSquare=
FrequencyHzStr=0
[Data]
CallSign=
[Reporting]
Enable=0
Callsign=
GridSquare=
FrequencyAsKHz=0
FrequencyList=1.9970,3.6250,3.6430,3.6930,3.6970,3.8500,5.4035,5.3665,5.3685,7.1770,7.1970,14.2360,14.2400,18.1180,21.3130,24.9330,28.3300,28.7200,10489.6400
ManualFrequencyReporting=0
DirectionAsCardinal=0
Frequency=0
[Reporting/PSKReporter]
Enable=1
[Reporting/FreeDV]
Enable=1
Hostname=qso.freedv.org
CurrentBandFilter=0
UseMetricDistances=1
BandFilterTracksFrequency=0
ForceReceiveOnly=0
StatusText=
RecentStatusTexts=
TxRowBackgroundColor=#fc4500
TxRowForegroundColor=#000000
RxRowBackgroundColor=#379baf
RxRowForegroundColor=#000000
MsgRowBackgroundColor=#E58BE5
MsgRowForegroundColor=#000000
[Reporting/FreeDV/BandFilterTracking]
TracksFreqBand=1
TracksExactFreq=0
[CallsignList]
UseUTCTime=0
[FreeDV2020]
Allowed=0
[MainFrame]
left=26
top=23
width=800
height=780
rxNbookCtrl=0
TabLayout=
[Windows]
[Windows/AudioConfig]
left=26
top=23
width=918
height=739
[Windows/FreeDVReporter]
left=20
top=20
width=-1
height=-1
visible=0
currentSort=-1
currentSortDirection=1
reportingUserMsgColWidth=130
[File]
playFileToMicInPath=
recFileFromRadioPath=
recFileFromRadioSecs=60
recFileFromModulatorPath=
recFileFromModulatorSecs=60
playFileFromRadioPath=
[VoiceKeyer]
WaveFilePath=/home/mooneer/Documents
WaveFile=voicekeyer.wav
RxPause=10
Repeats=5
[FreeDV700]
txClip=1
txBPF=1
[Noise]
noise_snr=2
[Debug]
console=0
verbose=0
APIverbose=0
[Waterfall]
Color=0
[Stats]
ResetTime=10
[Plot]
[Plot/Spectrum]
CurrentAveraging=0
[Monitor]
VoiceKeyerAudio=0
TransmitAudio=0
VoiceKeyerAudioVol=0
TransmitAudioVol=0
[QuickRecord]
SavePath=/home/mooneer/Documents

123
test/test_zeros.sh 100755
View File

@ -0,0 +1,123 @@
#!/bin/bash
FREEDV_TEST=$1
FREEDV_MODE=$2
FREEDV_RX_FILE=$3
# Determine sox driver to use for recording/playback
OPERATING_SYSTEM=`uname`
SOX_DRIVER=alsa
FREEDV_BINARY=src/freedv
if [ "$OPERATING_SYSTEM" == "Darwin" ]; then
SOX_DRIVER=coreaudio
FREEDV_BINARY=src/FreeDV.app/Contents/MacOS/freedv
fi
createVirtualAudioCable () {
CABLE_NAME=$1
pactl load-module module-null-sink sink_name=$CABLE_NAME sink_properties=device.description=$CABLE_NAME
}
FREEDV_RADIO_TO_COMPUTER_DEVICE="${FREEDV_RADIO_TO_COMPUTER_DEVICE:-FreeDV_Radio_To_Computer}"
FREEDV_COMPUTER_TO_SPEAKER_DEVICE="${FREEDV_COMPUTER_TO_SPEAKER_DEVICE:-FreeDV_Computer_To_Speaker}"
FREEDV_MICROPHONE_TO_COMPUTER_DEVICE="${FREEDV_MICROPHONE_TO_COMPUTER_DEVICE:-FreeDV_Microphone_To_Computer}"
FREEDV_COMPUTER_TO_RADIO_DEVICE="${FREEDV_COMPUTER_TO_RADIO_DEVICE:-FreeDV_Computer_To_Radio}"
# Automated script to help find audio dropouts.
# NOTE: this must be run from "build_linux". Also assumes PulseAudio/pipewire.
if [ "$OPERATING_SYSTEM" == "Linux" ]; then
DRIVER_INDEX_FREEDV_RADIO_TO_COMPUTER=$(createVirtualAudioCable FreeDV_Radio_To_Computer)
DRIVER_INDEX_FREEDV_COMPUTER_TO_SPEAKER=$(createVirtualAudioCable FreeDV_Computer_To_Speaker)
DRIVER_INDEX_FREEDV_MICROPHONE_TO_COMPUTER=$(createVirtualAudioCable FreeDV_Microphone_To_Computer)
DRIVER_INDEX_FREEDV_COMPUTER_TO_RADIO=$(createVirtualAudioCable FreeDV_Computer_To_Radio)
DRIVER_INDEX_LOOPBACK=`pactl load-module module-loopback source="FreeDV_Computer_To_Radio.monitor" sink="FreeDV_Radio_To_Computer"`
fi
# For debugging--list sink info
#pactl list sinks
# If full duplex test, use correct config file and assume "rx" mode.
FREEDV_CONF_FILE=freedv-ctest.conf
if [ "$FREEDV_TEST" == "txrx" ]; then
FREEDV_TEST=rx
FREEDV_CONF_FILE=freedv-ctest-fullduplex.conf
REC_DEVICE="$FREEDV_COMPUTER_TO_SPEAKER_DEVICE"
# Generate sine wave for input
if [ "$OPERATING_SYSTEM" == "Linux" ]; then
sox -r 48000 -n -b 16 -c 1 -t wav - synth 120 sin 1000 vol -10dB | paplay -d "$FREEDV_MICROPHONE_TO_COMPUTER_DEVICE" &
else
sox -r 48000 -n -b 16 -c 1 -t $SOX_DRIVER "$FREEDV_MICROPHONE_TO_COMPUTER_DEVICE" - synth 120 sin 1000 vol -10dB &
fi
PLAY_PID=$!
elif [ "$FREEDV_TEST" == "rx" ]; then
# Start playback if RX
if [ "$OPERATING_SYSTEM" == "Linux" ]; then
paplay -d "$FREEDV_RADIO_TO_COMPUTER_DEVICE" $FREEDV_RX_FILE &
else
sox $FREEDV_RX_FILE -t $SOX_DRIVER "$FREEDV_RADIO_TO_COMPUTER_DEVICE" &
fi
PLAY_PID=$!
REC_DEVICE="$FREEDV_COMPUTER_TO_SPEAKER_DEVICE.monitor"
else
REC_DEVICE="$FREEDV_COMPUTER_TO_RADIO_DEVICE.monitor"
fi
# Generate config file
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
if [ "$FREEDV_RADIO_TO_COMPUTER_DEVICE" == "FreeDV_Radio_To_Computer" ] && [ "$OPERATING_SYSTEM" == "Linux" ]; then
sed "s/@FREEDV_RADIO_TO_COMPUTER_DEVICE@/$FREEDV_RADIO_TO_COMPUTER_DEVICE.monitor/g" $SCRIPTPATH/$FREEDV_CONF_FILE.tmpl > $(pwd)/$FREEDV_CONF_FILE
else
sed "s/@FREEDV_RADIO_TO_COMPUTER_DEVICE@/$FREEDV_RADIO_TO_COMPUTER_DEVICE/g" $SCRIPTPATH/$FREEDV_CONF_FILE.tmpl > $(pwd)/$FREEDV_CONF_FILE
fi
sed "s/@FREEDV_COMPUTER_TO_RADIO_DEVICE@/$FREEDV_COMPUTER_TO_RADIO_DEVICE/g" $(pwd)/$FREEDV_CONF_FILE > $(pwd)/$FREEDV_CONF_FILE.tmp
mv $(pwd)/$FREEDV_CONF_FILE.tmp $(pwd)/$FREEDV_CONF_FILE
sed "s/@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@/$FREEDV_COMPUTER_TO_SPEAKER_DEVICE/g" $(pwd)/$FREEDV_CONF_FILE > $(pwd)/$FREEDV_CONF_FILE.tmp
mv $(pwd)/$FREEDV_CONF_FILE.tmp $(pwd)/$FREEDV_CONF_FILE
if [ "$FREEDV_MICROPHONE_TO_COMPUTER_DEVICE" == "FreeDV_Microphone_To_Computer" ] && [ "$OPERATING_SYSTEM" == "Linux" ]; then
sed "s/@FREEDV_MICROPHONE_TO_COMPUTER_DEVICE@/$FREEDV_MICROPHONE_TO_COMPUTER_DEVICE.monitor/g" $(pwd)/$FREEDV_CONF_FILE > $(pwd)/$FREEDV_CONF_FILE.tmp
else
sed "s/@FREEDV_MICROPHONE_TO_COMPUTER_DEVICE@/$FREEDV_MICROPHONE_TO_COMPUTER_DEVICE/g" $(pwd)/$FREEDV_CONF_FILE > $(pwd)/$FREEDV_CONF_FILE.tmp
fi
mv $(pwd)/$FREEDV_CONF_FILE.tmp $(pwd)/$FREEDV_CONF_FILE
# Start recording
if [ "$FREEDV_TEST" == "tx" ]; then
if [ "$OPERATING_SYSTEM" == "Linux" ]; then
parecord --channels=1 --rate 8000 --file-format=wav --device "$REC_DEVICE" --latency 1 test.wav &
else
sox -t $SOX_DRIVER "$REC_DEVICE" -c 1 -r 8000 -t wav test.wav &
fi
RECORD_PID=$!
fi
# Start FreeDV in test mode
$FREEDV_BINARY -f $(pwd)/$FREEDV_CONF_FILE -ut $FREEDV_TEST -utmode $FREEDV_MODE 2>&1 | tee tmp.log
FDV_PID=$!
#sleep 30
#screencapture ../screenshot.png
#wpctl status
#pw-top -b -n 5
#wait $FDV_PID
# Stop recording/playback and process data
if [ "$FREEDV_TEST" == "rx" ]; then
kill $PLAY_PID || echo "Already done playing"
NUM_RESYNCS=`grep "Sync changed" tmp.log | wc -l | xargs`
echo "Got $NUM_RESYNCS sync changes"
else
kill $RECORD_PID
sox test.wav -t raw -r 8k -c 1 -b 16 -e signed-integer test.raw silence 1 0.1 0.1% reverse silence 1 0.1 0.1% reverse
python3 $SCRIPTPATH/check-for-zeros.py test.raw
fi
# Clean up PulseAudio virtual devices
if [ "$OPERATING_SYSTEM" == "Linux" ]; then
pactl unload-module $DRIVER_INDEX_LOOPBACK
pactl unload-module $DRIVER_INDEX_FREEDV_RADIO_TO_COMPUTER
pactl unload-module $DRIVER_INDEX_FREEDV_COMPUTER_TO_SPEAKER
pactl unload-module $DRIVER_INDEX_FREEDV_COMPUTER_TO_RADIO
pactl unload-module $DRIVER_INDEX_FREEDV_MICROPHONE_TO_COMPUTER
fi

35
test/vac464.cer 100644
View File

@ -0,0 +1,35 @@
-----BEGIN CERTIFICATE-----
MIIGDDCCBPSgAwIBAgIMW5i7HVbfDAJdVbddMA0GCSqGSIb3DQEBCwUAMG4xCzAJ
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMUQwQgYDVQQDEztH
bG9iYWxTaWduIEV4dGVuZGVkIFZhbGlkYXRpb24gQ29kZVNpZ25pbmcgQ0EgLSBT
SEEyNTYgLSBHMzAeFw0yMDA1MjYxMjE4NDBaFw0yMzA4MjYxMjE4NDBaMIIBOzEd
MBsGA1UEDwwUUHJpdmF0ZSBPcmdhbml6YXRpb24xGDAWBgNVBAUTDzMxNjU0NzYw
MDEwNTU1NjETMBEGCysGAQQBgjc8AgEDEwJSVTEmMCQGCysGAQQBgjc8AgECExVO
b3Zvc2liaXJza2F5YSBvYmxhc3QxCzAJBgNVBAYTAlJVMR4wHAYDVQQIExVOb3Zv
c2liaXJza2F5YSBvYmxhc3QxFDASBgNVBAcTC05vdm9zaWJpcnNrMSswKQYDVQQK
EyJNdXp5Y2hlbmtvIEV2Z2VuaWkgVmlrdG9yb3ZpY2gsIElQMSswKQYDVQQDEyJN
dXp5Y2hlbmtvIEV2Z2VuaWkgVmlrdG9yb3ZpY2gsIElQMSYwJAYJKoZIhvcNAQkB
Fhdzb2Z0d2FyZUBtdXp5Y2hlbmtvLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMzy2+Ke77GcrnUkMh5D8SB99OrONoC3QkniNZ78H0k1t/9qdBB7
PgsGIGMXlyo3tLx5A6kWI9iczp5iWEpdZUmvTs7AV/NDPGIDbHU7dJR1gFlzc4yn
0CSYbW5GkQEnYLZutYDzfJP6WkteKdj7EHg2N1iO9AtpcyyC8k4CWRahymT8wQLO
TmhcwoIgayY1rn4Qfyx5rO4EPf4dYl3NwNItJk5IAL+QgWuSQSIHptqbxM8G1Eiu
wR0Q+Ab5v3tKktdQc7OQootJv1IX1IhLaT/AYHTxrKugiTArwzAv77fYo6HUZPZ4
a+lKt/FH/FF6wH0BZZoDtAab1NU2m15Cz8kCAwEAAaOCAdkwggHVMA4GA1UdDwEB
/wQEAwIHgDCBoAYIKwYBBQUHAQEEgZMwgZAwTgYIKwYBBQUHMAKGQmh0dHA6Ly9z
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzZXh0ZW5kY29kZXNpZ25zaGEy
ZzNvY3NwLmNydDA+BggrBgEFBQcwAYYyaHR0cDovL29jc3AyLmdsb2JhbHNpZ24u
Y29tL2dzZXh0ZW5kY29kZXNpZ25zaGEyZzMwVQYDVR0gBE4wTDBBBgkrBgEEAaAy
AQIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVw
b3NpdG9yeS8wBwYFZ4EMAQMwCQYDVR0TBAIwADBFBgNVHR8EPjA8MDqgOKA2hjRo
dHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2dzZXh0ZW5kY29kZXNpZ25zaGEyZzMu
Y3JsMCIGA1UdEQQbMBmBF3NvZnR3YXJlQG11enljaGVua28ubmV0MBMGA1UdJQQM
MAoGCCsGAQUFBwMDMB8GA1UdIwQYMBaAFNwsWCwqbzUtn3mVqEhdxG0+U7+5MB0G
A1UdDgQWBBSIENjDBY/ZwM9nURvPaBjwD0BpIDANBgkqhkiG9w0BAQsFAAOCAQEA
KAHk8s47IfKW8g/P2+Ia1koc/CkHFy4Q+R+uVC3DF3GVvNeBY9qCj8f8xUpQfkF1
mRUyIxfGCWS6sg+/CtzMY+vuSZnGb1C/2GQ5hBP/CvXXGz1W+sKASy29EU/gzzKd
j0sBVAUk+dgQ18P8cyUDnBxOGaizG/Yn10/2jzLi2eyBoxnunpzxMcgaaLUhtt/7
q7Jmor+A6FQ2xiuJlWE6TnUTR4aJH6uPswa6s6msHwNj9P7mbQfgK9P3pVmLuHBK
k9K9jkyL9KAAlNa7GBoT98a86z4x2lC/GcKOAD78M09qrfsd9+8f2II0XIXVuEuE
nabx4jlGD9IwXJ+daDrhfA==
-----END CERTIFICATE-----