Skip to content

Commit

Permalink
Revert PR #689 due to Windows audio problems.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmiw committed Apr 13, 2024
1 parent 7b24817 commit 6160f7b
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 96 deletions.
74 changes: 8 additions & 66 deletions src/audio/PortAudioEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
//=========================================================================

#include <sstream>
#include <iomanip>
#include <mutex>
#include <condition_variable>

#include <wx/string.h>
#include "portaudio.h"
#include "PortAudioDevice.h"
Expand Down Expand Up @@ -65,66 +61,17 @@ void PortAudioEngine::start()
}
else
{
if (cachePopulationThread_.joinable())
{
cachePopulationThread_.join();
}

std::mutex theadStartMtx;
std::condition_variable threadStartCV;
std::unique_lock<std::mutex> threadStartLock(theadStartMtx);

cachePopulationThread_ = std::thread([&]() {
std::unique_lock<std::recursive_mutex> lock(deviceCacheMutex_);

{
std::unique_lock<std::mutex> 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<AudioDeviceSpecification> PortAudioEngine::getAudioDeviceList(AudioDirection direction)
{
std::unique_lock<std::recursive_mutex> lock(deviceCacheMutex_);
return deviceListCache_[direction];
}

std::vector<int> PortAudioEngine::getSupportedSampleRates(wxString deviceName, AudioDirection direction)
{
std::unique_lock<std::recursive_mutex> lock(deviceCacheMutex_);

auto key = std::pair<wxString, AudioDirection>(deviceName, direction);
if (sampleRateList_.count(key) == 0)
{
sampleRateList_[key] = getSupportedSampleRates_(deviceName, direction);
}
return sampleRateList_[key];
}

std::vector<AudioDeviceSpecification> PortAudioEngine::getAudioDeviceList_(AudioDirection direction)
{
int numDevices = Pa_GetDeviceCount();
std::vector<AudioDeviceSpecification> result;
Expand Down Expand Up @@ -155,15 +102,11 @@ std::vector<AudioDeviceSpecification> 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") ||
Expand All @@ -185,7 +128,7 @@ std::vector<AudioDeviceSpecification> PortAudioEngine::getAudioDeviceList_(Audio
direction == AUDIO_ENGINE_OUT ? &streamParameters : NULL,
deviceInfo->defaultSampleRate);

if (err != paFormatIsSupported)
if (err == paFormatIsSupported)
{
break;
}
Expand All @@ -200,7 +143,8 @@ std::vector<AudioDeviceSpecification> 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);
Expand All @@ -210,14 +154,14 @@ std::vector<AudioDeviceSpecification> PortAudioEngine::getAudioDeviceList_(Audio
return result;
}

std::vector<int> PortAudioEngine::getSupportedSampleRates_(wxString deviceName, AudioDirection direction)
std::vector<int> PortAudioEngine::getSupportedSampleRates(wxString deviceName, AudioDirection direction)
{
std::vector<int> result;
auto devInfo = getAudioDeviceList(direction);

for (auto& device : devInfo)
{
if (device.name.IsSameAs(deviceName))
if (device.name.Find(deviceName) == 0)
{
PaStreamParameters streamParameters;

Expand All @@ -241,9 +185,7 @@ std::vector<int> PortAudioEngine::getSupportedSampleRates_(wxString deviceName,
}

rateIndex++;
}

break;
}
}
}

Expand Down
12 changes: 0 additions & 12 deletions src/audio/PortAudioEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
#ifndef PORT_AUDIO_ENGINE_H
#define PORT_AUDIO_ENGINE_H

#include <map>
#include <thread>
#include <mutex>
#include "IAudioEngine.h"

class PortAudioEngine : public IAudioEngine
Expand All @@ -43,15 +40,6 @@ class PortAudioEngine : public IAudioEngine

private:
bool initialized_;

// Device cache and associated management.
std::map<AudioDirection, std::vector<AudioDeviceSpecification> > deviceListCache_;
std::map<std::pair<wxString, AudioDirection>, std::vector<int> > sampleRateList_;
std::recursive_mutex deviceCacheMutex_;
std::thread cachePopulationThread_;

std::vector<AudioDeviceSpecification> getAudioDeviceList_(AudioDirection direction);
std::vector<int> getSupportedSampleRates_(wxString deviceName, AudioDirection direction);
};

#endif // PORT_AUDIO_ENGINE_H
23 changes: 22 additions & 1 deletion src/gui/dialogs/dlg_audiooptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}


Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -1043,6 +1057,7 @@ void AudioOptsDialog::plotDeviceOutputForAFewSecs(wxString devName, PlotScalar *
}

device->stop();

codec2_fifo_destroy(callbackFifo);
}
break;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
12 changes: 10 additions & 2 deletions src/gui/dialogs/dlg_easy_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,9 @@ void EasySetupDialog::OnTest(wxCommandEvent& event)
{
txTestAudioDevice_->stop();
txTestAudioDevice_ = nullptr;

auto audioEngine = AudioEngineFactory::GetAudioEngine();
audioEngine->stop();
}

if (hamlibTestObject_ != nullptr && hamlibTestObject_->isConnected())
Expand Down Expand Up @@ -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)
Expand All @@ -893,6 +898,8 @@ void EasySetupDialog::OnTest(wxCommandEvent& event)
serialPortTestObject_->disconnect();
serialPortTestObject_ = nullptr;
}

audioEngine->stop();
return;
}

Expand Down Expand Up @@ -1129,9 +1136,8 @@ void EasySetupDialog::updateAudioDevices_()
std::map<wxString, SoundDeviceData*> 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);

Expand Down Expand Up @@ -1379,6 +1385,8 @@ void EasySetupDialog::updateAudioDevices_()
m_analogDevicePlayback->SetSelection(index);
}
}

audioEngine->stop();
}

bool EasySetupDialog::canTestRadioSettings_()
Expand Down
54 changes: 39 additions & 15 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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)
Expand Down Expand Up @@ -2491,7 +2496,11 @@ void MainFrame::startRxStream()
rxOutSoundDevice.reset();
}

m_RxRunning = false;
m_RxRunning = false;

engine->stop();
engine->setOnEngineError(nullptr, nullptr);

return;
}
else
Expand Down Expand Up @@ -2598,6 +2607,10 @@ void MainFrame::startRxStream()
}

m_RxRunning = false;

engine->stop();
engine->setOnEngineError(nullptr, nullptr);

return;
}
else
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -3159,6 +3180,9 @@ bool MainFrame::validateSoundCardSetup()
canRun = false;
}

engine->stop();
engine->setOnEngineError(nullptr, nullptr);

return canRun;
}

Expand Down

0 comments on commit 6160f7b

Please sign in to comment.