diff --git a/src/audio/PortAudioEngine.cpp b/src/audio/PortAudioEngine.cpp index 81aff5c4a..1193331c2 100644 --- a/src/audio/PortAudioEngine.cpp +++ b/src/audio/PortAudioEngine.cpp @@ -21,10 +21,6 @@ //========================================================================= #include -#include -#include -#include - #include #include "portaudio.h" #include "PortAudioDevice.h" @@ -65,66 +61,17 @@ void PortAudioEngine::start() } else { - if (cachePopulationThread_.joinable()) - { - cachePopulationThread_.join(); - } - - std::mutex theadStartMtx; - std::condition_variable threadStartCV; - std::unique_lock threadStartLock(theadStartMtx); - - cachePopulationThread_ = std::thread([&]() { - std::unique_lock lock(deviceCacheMutex_); - - { - std::unique_lock innerThreadStartLock(theadStartMtx); - threadStartCV.notify_one(); - } - - deviceListCache_[AUDIO_ENGINE_IN] = getAudioDeviceList_(AUDIO_ENGINE_IN); - deviceListCache_[AUDIO_ENGINE_OUT] = getAudioDeviceList_(AUDIO_ENGINE_OUT); - }); - - threadStartCV.wait(threadStartLock); - initialized_ = true; } } void PortAudioEngine::stop() { - if (cachePopulationThread_.joinable()) - { - cachePopulationThread_.join(); - } - Pa_Terminate(); - initialized_ = false; - deviceListCache_.clear(); - sampleRateList_.clear(); } std::vector PortAudioEngine::getAudioDeviceList(AudioDirection direction) -{ - std::unique_lock lock(deviceCacheMutex_); - return deviceListCache_[direction]; -} - -std::vector PortAudioEngine::getSupportedSampleRates(wxString deviceName, AudioDirection direction) -{ - std::unique_lock lock(deviceCacheMutex_); - - auto key = std::pair(deviceName, direction); - if (sampleRateList_.count(key) == 0) - { - sampleRateList_[key] = getSupportedSampleRates_(deviceName, direction); - } - return sampleRateList_[key]; -} - -std::vector PortAudioEngine::getAudioDeviceList_(AudioDirection direction) { int numDevices = Pa_GetDeviceCount(); std::vector result; @@ -155,15 +102,11 @@ std::vector PortAudioEngine::getAudioDeviceList_(Audio // on Windows. PaStreamParameters streamParameters; streamParameters.device = index; + streamParameters.channelCount = 1; streamParameters.sampleFormat = paInt16; streamParameters.suggestedLatency = Pa_GetDeviceInfo(index)->defaultHighInputLatency; streamParameters.hostApiSpecificStreamInfo = NULL; - streamParameters.channelCount = 1; - - // On Linux, the below logic causes the device lookup process to take MUCH - // longer than it does on other platforms, mainly because of the special devices - // it provides to PortAudio. For these, we're just going to assume the minimum - // valid channels is 1. + int maxChannels = direction == AUDIO_ENGINE_IN ? deviceInfo->maxInputChannels : deviceInfo->maxOutputChannels; bool isDeviceWithKnownMinimum = !strcmp(deviceInfo->name, "sysdefault") || @@ -185,7 +128,7 @@ std::vector PortAudioEngine::getAudioDeviceList_(Audio direction == AUDIO_ENGINE_OUT ? &streamParameters : NULL, deviceInfo->defaultSampleRate); - if (err != paFormatIsSupported) + if (err == paFormatIsSupported) { break; } @@ -200,7 +143,8 @@ std::vector PortAudioEngine::getAudioDeviceList_(Audio device.name = wxString::FromUTF8(deviceInfo->name); device.apiName = hostApiName; device.minChannels = streamParameters.channelCount; - device.maxChannels = maxChannels; + device.maxChannels = + direction == AUDIO_ENGINE_IN ? deviceInfo->maxInputChannels : deviceInfo->maxOutputChannels; device.defaultSampleRate = deviceInfo->defaultSampleRate; result.push_back(device); @@ -210,14 +154,14 @@ std::vector PortAudioEngine::getAudioDeviceList_(Audio return result; } -std::vector PortAudioEngine::getSupportedSampleRates_(wxString deviceName, AudioDirection direction) +std::vector PortAudioEngine::getSupportedSampleRates(wxString deviceName, AudioDirection direction) { std::vector result; auto devInfo = getAudioDeviceList(direction); for (auto& device : devInfo) { - if (device.name.IsSameAs(deviceName)) + if (device.name.Find(deviceName) == 0) { PaStreamParameters streamParameters; @@ -241,9 +185,7 @@ std::vector PortAudioEngine::getSupportedSampleRates_(wxString deviceName, } rateIndex++; - } - - break; + } } } diff --git a/src/audio/PortAudioEngine.h b/src/audio/PortAudioEngine.h index a1ad9b2a9..fde82319e 100644 --- a/src/audio/PortAudioEngine.h +++ b/src/audio/PortAudioEngine.h @@ -23,9 +23,6 @@ #ifndef PORT_AUDIO_ENGINE_H #define PORT_AUDIO_ENGINE_H -#include -#include -#include #include "IAudioEngine.h" class PortAudioEngine : public IAudioEngine @@ -43,15 +40,6 @@ class PortAudioEngine : public IAudioEngine private: bool initialized_; - - // Device cache and associated management. - std::map > deviceListCache_; - std::map, std::vector > sampleRateList_; - std::recursive_mutex deviceCacheMutex_; - std::thread cachePopulationThread_; - - std::vector getAudioDeviceList_(AudioDirection direction); - std::vector getSupportedSampleRates_(wxString deviceName, AudioDirection direction); }; #endif // PORT_AUDIO_ENGINE_H \ No newline at end of file diff --git a/src/gui/dialogs/dlg_audiooptions.cpp b/src/gui/dialogs/dlg_audiooptions.cpp index 207ed67ff..785ad0605 100644 --- a/src/gui/dialogs/dlg_audiooptions.cpp +++ b/src/gui/dialogs/dlg_audiooptions.cpp @@ -50,6 +50,18 @@ extern wxConfigBase *pConfig; void AudioOptsDialog::audioEngineInit(void) { m_isPaInitialized = true; + + auto engine = AudioEngineFactory::GetAudioEngine(); + engine->setOnEngineError([this](IAudioEngine&, std::string error, void*) + { + CallAfter([&]() { + wxMessageBox(wxT("Sound engine failed to initialize"), wxT("Error"), wxOK); + }); + + m_isPaInitialized = false; + }, nullptr); + + engine->start(); } @@ -344,6 +356,8 @@ AudioOptsDialog::~AudioOptsDialog() wxGetApp().appConfiguration.audioConfigWindowWidth = sz.GetWidth(); wxGetApp().appConfiguration.audioConfigWindowHeight = sz.GetHeight(); + AudioEngineFactory::GetAudioEngine()->stop(); + // Disconnect Events this->Disconnect(wxEVT_HIBERNATE, wxActivateEventHandler(AudioOptsDialog::OnHibernate)); this->Disconnect(wxEVT_ICONIZE, wxIconizeEventHandler(AudioOptsDialog::OnIconize)); @@ -624,7 +638,7 @@ int AudioOptsDialog::buildListOfSupportedSampleRates(wxComboBox *cbSampleRate, w cbSampleRate->Clear(); for (auto& dev : deviceList) { - if (dev.name.IsSameAs(devName)) + if (dev.name.Find(devName) == 0) { auto supportedSampleRates = engine->getSupportedSampleRates( @@ -1043,6 +1057,7 @@ void AudioOptsDialog::plotDeviceOutputForAFewSecs(wxString devName, PlotScalar * } device->stop(); + codec2_fifo_destroy(callbackFifo); } break; @@ -1134,6 +1149,9 @@ void AudioOptsDialog::OnCancelAudioParameters(wxCommandEvent& event) { if(m_isPaInitialized) { + auto engine = AudioEngineFactory::GetAudioEngine(); + engine->stop(); + engine->setOnEngineError(nullptr, nullptr); m_isPaInitialized = false; } EndModal(wxCANCEL); @@ -1152,6 +1170,9 @@ void AudioOptsDialog::OnOkAudioParameters(wxCommandEvent& event) if (status == 0) { if(m_isPaInitialized) { + auto engine = AudioEngineFactory::GetAudioEngine(); + engine->stop(); + engine->setOnEngineError(nullptr, nullptr); m_isPaInitialized = false; } EndModal(wxOK); diff --git a/src/gui/dialogs/dlg_easy_setup.cpp b/src/gui/dialogs/dlg_easy_setup.cpp index 427c9c1b0..1a484b191 100644 --- a/src/gui/dialogs/dlg_easy_setup.cpp +++ b/src/gui/dialogs/dlg_easy_setup.cpp @@ -736,6 +736,9 @@ void EasySetupDialog::OnTest(wxCommandEvent& event) { txTestAudioDevice_->stop(); txTestAudioDevice_ = nullptr; + + auto audioEngine = AudioEngineFactory::GetAudioEngine(); + audioEngine->stop(); } if (hamlibTestObject_ != nullptr && hamlibTestObject_->isConnected()) @@ -873,6 +876,8 @@ void EasySetupDialog::OnTest(wxCommandEvent& event) if (radioOutDeviceName != "none") { auto audioEngine = AudioEngineFactory::GetAudioEngine(); + audioEngine->start(); + txTestAudioDevice_ = audioEngine->getAudioDevice(radioOutDeviceName, IAudioEngine::AUDIO_ENGINE_OUT, radioOutSampleRate, 1); if (txTestAudioDevice_ == nullptr) @@ -893,6 +898,8 @@ void EasySetupDialog::OnTest(wxCommandEvent& event) serialPortTestObject_->disconnect(); serialPortTestObject_ = nullptr; } + + audioEngine->stop(); return; } @@ -1129,9 +1136,8 @@ void EasySetupDialog::updateAudioDevices_() std::map finalAnalogTxDeviceList; auto audioEngine = AudioEngineFactory::GetAudioEngine(); - audioEngine->stop(); audioEngine->start(); - + auto inputDevices = audioEngine->getAudioDeviceList(IAudioEngine::AUDIO_ENGINE_IN); auto outputDevices = audioEngine->getAudioDeviceList(IAudioEngine::AUDIO_ENGINE_OUT); @@ -1379,6 +1385,8 @@ void EasySetupDialog::updateAudioDevices_() m_analogDevicePlayback->SetSelection(index); } } + + audioEngine->stop(); } bool EasySetupDialog::canTestRadioSettings_() diff --git a/src/main.cpp b/src/main.cpp index 3748687ee..3aff83485 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -634,17 +634,6 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent, wxID_ANY, _("FreeDV ") pthread_setname_np(pthread_self(), "FreeDV GUI"); #endif // defined(__linux__) - // Begin loading of audio device cache. - auto engine = AudioEngineFactory::GetAudioEngine(); - engine->setOnEngineError([&](IAudioEngine&, std::string error, void* state) { - executeOnUiThreadAndWait_([&, error]() { - wxMessageBox(wxString::Format( - "Error encountered while initializing the audio engine: %s.", - error), wxT("Error"), wxOK, this); - }); - }, nullptr); - engine->start(); - m_reporterDialog = nullptr; m_filterDialog = nullptr; @@ -2407,6 +2396,10 @@ void MainFrame::stopRxStream() m_newSpkOutFilter = true; deleteEQFilters(g_rxUserdata); delete g_rxUserdata; + + auto engine = AudioEngineFactory::GetAudioEngine(); + engine->stop(); + engine->setOnEngineError(nullptr, nullptr); } } @@ -2428,16 +2421,28 @@ void MainFrame::startRxStream() if (g_verbose) fprintf(stderr, "startRxStream .....\n"); if(!m_RxRunning) { m_RxRunning = true; - - auto engine = AudioEngineFactory::GetAudioEngine(); + auto engine = AudioEngineFactory::GetAudioEngine(); + engine->setOnEngineError([&](IAudioEngine&, std::string error, void* state) { + executeOnUiThreadAndWait_([&, error]() { + wxMessageBox(wxString::Format( + "Error encountered while initializing the audio engine: %s.", + error), wxT("Error"), wxOK, this); + }); + }, nullptr); + engine->start(); + if (g_nSoundCards == 0) { executeOnUiThreadAndWait_([&]() { wxMessageBox(wxT("No Sound Cards configured, use Tools - Audio Config to configure"), wxT("Error"), wxOK); }); - m_RxRunning = false; + m_RxRunning = false; + + engine->stop(); + engine->setOnEngineError(nullptr, nullptr); + return; } else if (g_nSoundCards == 1) @@ -2491,7 +2496,11 @@ void MainFrame::startRxStream() rxOutSoundDevice.reset(); } - m_RxRunning = false; + m_RxRunning = false; + + engine->stop(); + engine->setOnEngineError(nullptr, nullptr); + return; } else @@ -2598,6 +2607,10 @@ void MainFrame::startRxStream() } m_RxRunning = false; + + engine->stop(); + engine->setOnEngineError(nullptr, nullptr); + return; } else @@ -3015,6 +3028,14 @@ bool MainFrame::validateSoundCardSetup() // Translate device names to IDs auto engine = AudioEngineFactory::GetAudioEngine(); + engine->setOnEngineError([&](IAudioEngine&, std::string error, void* state) { + CallAfter([&]() { + wxMessageBox(wxString::Format( + "Error encountered while initializing the audio engine: %s.", + error), wxT("Error"), wxOK, this); + }); + }, nullptr); + engine->start(); auto defaultInputDevice = engine->getDefaultAudioDevice(IAudioEngine::AUDIO_ENGINE_IN); auto defaultOutputDevice = engine->getDefaultAudioDevice(IAudioEngine::AUDIO_ENGINE_OUT); @@ -3159,6 +3180,9 @@ bool MainFrame::validateSoundCardSetup() canRun = false; } + engine->stop(); + engine->setOnEngineError(nullptr, nullptr); + return canRun; }