Merge branch 'v2.0-dev' into ms-log-library
commit
fb000c043c
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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 ""
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -191,7 +191,8 @@ private:
|
|||
FARGANState fargan_;
|
||||
LPCNetEncState *lpcnetEncState_;
|
||||
RADETransmitStep *radeTxStep_;
|
||||
|
||||
int sync_;
|
||||
|
||||
int preProcessRxFn_(ParallelStep* ps);
|
||||
int postProcessRxFn_(ParallelStep* ps);
|
||||
};
|
||||
|
|
196
src/main.cpp
196
src/main.cpp
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_()
|
||||
|
|
|
@ -82,9 +82,7 @@ class wxListViewComboPopup;
|
|||
/// Class TopFrame
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class TopFrame : public wxFrame
|
||||
{
|
||||
private:
|
||||
|
||||
{
|
||||
protected:
|
||||
wxPanel* m_panel;
|
||||
wxMenuBar* m_menubarMain;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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.")
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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-----
|
Loading…
Reference in New Issue