From 3239e60471f71aca363293e73e74d26a1d311dfe Mon Sep 17 00:00:00 2001 From: Hane Date: Sat, 25 Jan 2025 17:27:36 +0100 Subject: [PATCH] fixed synch issues + memleak @ name fetching --- src/back/backlasses.cpp | 51 +++++++++++++++++++++++---------- src/back/backlasses.h | 15 +++++----- src/back/backsessionclasses.cpp | 15 ++++++---- src/cont/contclasses.cpp | 24 +++++++++++++--- src/cont/contclasses.h | 2 ++ src/cont/contsessionclasses.h | 8 +++--- src/qt/qtclasses.cpp | 15 +++++----- 7 files changed, 87 insertions(+), 43 deletions(-) diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index cead61f..74af6a0 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -234,6 +234,7 @@ HRESULT EndpointSituationCallback::OnDeviceRemoved(LPCWSTR pwstrDeviceId) { HRESULT EndpointSituationCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { std::wstring endpointId = std::wstring(pwstrDeviceId); + log_wdebugcpp(L"Endpoint state change for " + endpointId); EndpointState newState; switch (dwNewState) { case DEVICE_STATE_ACTIVE: @@ -249,7 +250,7 @@ HRESULT EndpointSituationCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, D newState = EndpointState::ENDPOINT_UNPLUGGED; break; } - isEpStateChanging = true; + isEpStateChanging.exchange(true); std::thread newEndpointThread(&OverseerHandler::reviseEndpointShowing, osh, endpointId, newState); newEndpointThread.detach(); @@ -258,7 +259,7 @@ HRESULT EndpointSituationCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, D } HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { - isEpStateChanging = true; + isEpStateChanging.exchange(true); std::thread propertyThread(&Overseer::updateEndpointInfo, os, std::wstring(pwstrDeviceId)); propertyThread.detach(); while(isEpStateChanging); @@ -266,7 +267,8 @@ HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, } void EndpointSituationCallback::reportFinishedStateChange() { - this->isEpStateChanging = false; + this->isEpStateChanging.exchange(false); + return; } Endpoint::Endpoint(IMMDevice* ep, IPolicyConfig7* policyConfig, uint64_t idx) { @@ -325,23 +327,29 @@ void Endpoint::activateEndpointSessions() { return; } - if (FAILED(endpoint->Activate(__uuidof(IAudioSessionManager2), - CLSCTX_ALL, NULL, (void**) &sessionManager))) { - log_debugcpp("Couldn't open session manager2, huh"); - return; + if (!sessionManager) { + if (FAILED(endpoint->Activate(__uuidof(IAudioSessionManager2), + CLSCTX_ALL, NULL, (void**) &sessionManager))) { + log_debugcpp("Couldn't open session manager2, huh"); + return; + } } + IAudioSessionEnumerator* sessionEnumerator = nullptr; - if (FAILED(sessionManager->GetSessionEnumerator(&sessionEnumerator))) { log_wdebugcpp(L"sesEnumeratorBros..."); return; } + if (FAILED(sessionManager->GetSessionEnumerator(&sessionEnumerator))) { log_wdebugcpp(L"sesEnumeratorBros..."); exit(-5); return; } endpointSessions.resize(1, nullptr); int sessionCount; sessionEnumerator->GetCount(&sessionCount); for (int i = 0; i < sessionCount; i++) { IAudioSessionControl* sessionControlTmp; - sessionEnumerator->GetSession(i, (IAudioSessionControl**)&sessionControlTmp); + if (FAILED(sessionEnumerator->GetSession(i, (IAudioSessionControl**)&sessionControlTmp))) { + exit(-6); + } IAudioSessionControl2* sessionControl; - sessionControlTmp->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl); - sessionControl->AddRef(); + if(FAILED(sessionControlTmp->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl))){ + exit(-7); + } sessionControlTmp->Release(); Session* session = new Session(this, sessionControl, (size_t)i); if (sessionControl->IsSystemSoundsSession() == S_OK) endpointSessions[0] = session; @@ -350,6 +358,13 @@ void Endpoint::activateEndpointSessions() { sessionEnumerator->Release(); } +/* + * void Endpoint::deleteSessionManager() { + * sessionManager->Release(); + * sessionManager = nullptr; + * } + */ + void Endpoint::addSession(Session* session) { session->setIndex(this->getSessionCount()); endpointSessions.push_back(session); @@ -357,9 +372,15 @@ void Endpoint::addSession(Session* session) { void Endpoint::activateEndpointVolume() { //If this EP is created after init, COM won't be initialized on the executing thread. - HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + HRESULT result = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); if (this->endpointVolume == nullptr) { - endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&this->endpointVolume); + if(FAILED(endpoint->Activate( + IID_IAudioEndpointVolume, + CLSCTX_ALL, + NULL, + (void**)&this->endpointVolume))) { + log_debugcpp("No volume, huh"); + } //todo: check header if(FAILED(endpoint->Activate(__uuidof(IAudioMeterInformation), @@ -594,8 +615,8 @@ void Overseer::createEndpoints(Flows flow) { /* * Counting them */ - if(FAILED(deviceCollection->GetCount(&numEndpoints))) { log_debugcpp("si");}; - if(numEndpoints == 0) { log_debugcpp("si"); }; + if(FAILED(deviceCollection->GetCount(&numEndpoints))) { log_debugcpp("si");}; + if(numEndpoints == 0) { log_debugcpp("si"); }; /* * Retrieving actual endpoints and storing them on their own collection diff --git a/src/back/backlasses.h b/src/back/backlasses.h index 9f79924..5acedba 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -82,6 +82,7 @@ class Endpoint { void unregisterNewSessionNotification(EndpointNewSessionCallback* ensc); void deleteSessions(); void activateEndpointSessions(); + //void deleteSessionManager(); std::mutex endpointSessionsMutex; ~Endpoint(); @@ -91,12 +92,13 @@ class Endpoint { std::vector endpointSessions; uint32_t channelCount = 0; IMMDevice *endpoint; - IAudioClient *audioClient; + IAudioEndpointVolume *endpointVolume = nullptr; + IPropertyStore *properties; + IAudioMeterInformation *endpointPeakMeter = nullptr; + //IAudioClient *audioClient; int64_t defTime, minTime; IAudioSessionManager2 *sessionManager = nullptr; Flows flow; - IAudioEndpointVolume *endpointVolume = nullptr; - IPropertyStore *properties; std::wstring friendlyName; std::wstring descriptionName; std::wstring deviceName; @@ -105,7 +107,6 @@ class Endpoint { Roles endpointRoles = (Roles)0; uint64_t idx; //Not implemented in llvm-mingw. Sad! todo: mingw patch - IAudioMeterInformation *endpointPeakMeter = nullptr; IPolicyConfig7* policyConfig; }; @@ -125,7 +126,7 @@ class EndpointVolumeCallback : public IAudioEndpointVolumeCallback { private: ULONG ref = 1; Endpoint* ep; - bool wait = false; + std::atomic wait = false; }; class EndpointSituationCallback : public IMMNotificationClient { @@ -143,7 +144,7 @@ class EndpointSituationCallback : public IMMNotificationClient { private: ULONG ref = 1; Overseer* os; - bool isEpStateChanging = false; + std::atomic isEpStateChanging = false; }; class Overseer { @@ -204,7 +205,7 @@ class EndpointNewSessionCallback : public IAudioSessionNotification { void createSessionThread(SessionThreadParams params); private: - bool wait = false; + std::atomic wait = false; ULONG ref = 1; EndpointHandler *eph; diff --git a/src/back/backsessionclasses.cpp b/src/back/backsessionclasses.cpp index 5816ac5..c9aaa85 100644 --- a/src/back/backsessionclasses.cpp +++ b/src/back/backsessionclasses.cpp @@ -39,6 +39,7 @@ HRESULT SessionStateCallback::QueryInterface(REFIID riid, VOID **ppvInterface) { HRESULT SessionStateCallback::OnDisplayNameChanged(LPCWSTR NewDisplayName, LPCGUID EventContext) { //TODO: Preguntar while(sh->getVolumeInfo()->isNameChanged == true); + sh->setName(std::wstring(NewDisplayName)); sh->getVolumeInfo()->isNameChanged = true; return S_OK; @@ -238,13 +239,15 @@ bool Session::fetchNameViaFD(std::wstring exePath, DWORD pid, std::wstring *sess void* fileVersionInfo = malloc(fileVersionInfoSize); if(!GetFileVersionInfoExW(FILE_VER_GET_LOCALISED | FILE_VER_GET_NEUTRAL, - exePath.c_str(),0,fileVersionInfoSize, fileVersionInfo)) + exePath.c_str(),0,fileVersionInfoSize, fileVersionInfo)) { return false; + } UINT translationArrayLen = 0; - if (!VerQueryValueW(fileVersionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayLen)) + if (!VerQueryValueW(fileVersionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayLen)) { + free(fileVersionInfo); return false; - + } //File descriptor parsing //TODO: https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserpreferreduilanguages /* It is possible to retrieve user languages and try to use one of those before falling back to whatever @@ -257,7 +260,6 @@ bool Session::fetchNameViaFD(std::wstring exePath, DWORD pid, std::wstring *sess int8_t syslangIdx = -1; wchar_t metadataStringKey[256]; wchar_t* metadataString = NULL; - //std::wstring name; for (UINT i = 0; i < availableLangs; i++) { LANGID defaultUILanguage = GetUserDefaultUILanguage(); if (defaultUILanguage != translationArray[i].wLanguage) @@ -340,8 +342,6 @@ bool Session::fetchNameViaMSIX(std::wstring exePath, DWORD pid, std::wstring *se if (sessionName->length() > 0) return true; else return false; - - } @@ -419,4 +419,7 @@ Session::~Session() { meterInformation->Release(); sessionControl->Release(); sessionVolume->Release(); + meterInformation = nullptr; + sessionControl = nullptr; + sessionVolume = nullptr; } diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp index 27ae4a6..d2188f0 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -28,7 +28,6 @@ EndpointHandler::EndpointHandler(uint64_t idx, Flows flow) { this->flow = flow; this->ep = (flow == Flows::FLOW_PLAYBACK ? osh->getPlaybackEndpoints().at(idx) : osh->getCaptureEndpoints().at(idx)); - epc = new EndpointVolumeCallback(ep); this->callbackInfo.caller = osh->getGuid(); //epName = ep->getName(); this->setBackEndpointVolumeCallbackInfoContent(this->getState()); @@ -115,7 +114,10 @@ void EndpointHandler::setBackEndpointVolumeCallbackInfoContent(uint8_t state) { callbackInfo.muted = this->getMute(); callbackInfo.mainVolume = this->getVolume(AudioChannel::CHANNEL_MAIN); callbackInfo.channels = this->getChannelCount(); - ep->setVolumeCallback(epc); + if (!epc) { + epc = new EndpointVolumeCallback(ep); + ep->setVolumeCallback(epc); + } callbackInfo.channelVolumes.resize(this->callbackInfo.channels); for(uint32_t i = 0; i < this->getChannelCount(); i++){ callbackInfo.channelVolumes.at(i) = this->getVolume(i); @@ -181,13 +183,13 @@ Endpoint* EndpointHandler::getEndpoint() { void EndpointHandler::addSessionSendFront(Session* session) { if(!ep->endpointSessionsMutex.try_lock()) return; + sessionHandlersMutex.lock(); this->ep->addSession(session); SessionHandler* sessionHandler = new SessionHandler(this, session, (getSessionCount() - 1)); - ep->endpointSessionsMutex.unlock(); - sessionHandlersMutex.lock(); sessionHandlers.push_back(sessionHandler); + ep->endpointSessionsMutex.unlock(); sessionHandlersMutex.unlock(); this->addSessionWidget(sessionHandler); } @@ -203,11 +205,13 @@ void EndpointHandler::removeSessionFromFront(SessionHandler* sh) { void EndpointHandler::deleteSessions() { ep->unregisterNewSessionNotification(ensc); ensc->Release(); + ensc = nullptr; for (auto sh : sessionHandlers) { delete sh; } sessionHandlers.resize(0); ep->deleteSessions(); + //ep->deleteSessionManager(); } void EndpointHandler::createSessionHandlers() { @@ -218,6 +222,9 @@ void EndpointHandler::createSessionHandlers() { sessionHandlers.push_back(sessionHandler); } } +} + +void EndpointHandler::createSessionHandlersCallback() { ensc = new EndpointNewSessionCallback(this); ep->registerNewSessionNotification(ensc); } @@ -232,6 +239,12 @@ void EndpointHandler::unlockSessionCollections() { this->ep->endpointSessionsMutex.unlock(); } +void EndpointHandler::removeVolumeCallback() { + ep->removeVolumeCallback(epc); + epc->Release(); + epc = nullptr; +} + EndpointHandler::~EndpointHandler() { ep->removeVolumeCallback(epc); ep->unregisterNewSessionNotification(ensc); @@ -411,10 +424,13 @@ void OverseerHandler::reviseEndpointShowing(std::wstring endpointId, EndpointSta if (flow == Flows::FLOW_CAPTURE) goto end; if (eph && EndpointState::ENDPOINT_ACTIVE & state) { + eph->setState(EndpointState::ENDPOINT_ACTIVE); this->addEndpointWidget(eph); } else if (eph && eph->getFrontVisibilityState() == EndpointState::ENDPOINT_ACTIVE) { + eph->removeVolumeCallback(); this->removeEndpointWidget(eph->getFrontVisibilityIndex()); } + end: handlersPlaybackMutex.unlock(); handlersCaptureMutex.unlock(); diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index 2034986..cd0e03e 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -76,9 +76,11 @@ public: void removeSessionFromFront(SessionHandler* sh); void deleteSessions(); void createSessionHandlers(); + void createSessionHandlersCallback(); std::mutex sessionHandlersMutex; void lockSessionCollections(); void unlockSessionCollections(); + void removeVolumeCallback(); ~EndpointHandler(); private: diff --git a/src/cont/contsessionclasses.h b/src/cont/contsessionclasses.h index 455bbe1..24c0ba7 100644 --- a/src/cont/contsessionclasses.h +++ b/src/cont/contsessionclasses.h @@ -9,10 +9,10 @@ class SessionStateCallback; struct SessionVolumeInfo { //SessionVolumeInfo(bool muted, float mainVolume); - bool muted; - float mainVolume; - NGuid caller; - bool isNameChanged = false; + bool muted; + float mainVolume; + NGuid caller; + std::atomic isNameChanged = false; //size_t channels; //std::vector channelVolumes; }; diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index 2e2a4b0..a5c391d 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -411,7 +411,8 @@ SessionWidget::SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent) if (sh->getVolumeInfo()->isNameChanged) { mainLabel->setText(QString::fromStdWString(sh->getName())); mainLabel->setToolTip(QString::fromStdWString(sh->getName())); - } + sh->getVolumeInfo()->isNameChanged = false; + } const float roundingFactor = 0.005; mainSlider->blockSignals(true); muteButton->blockSignals(true); @@ -538,7 +539,7 @@ EndpointWidget::EndpointWidget(EndpointHandler* eph, QWidget *parent, uint64_t i eph->createSessionHandlers(); //todo: sussy - this->eph->setState(EndpointState::ENDPOINT_ACTIVE, idx); + this->eph->setFrontVisibilityInfo(EndpointState::ENDPOINT_ACTIVE, idx); this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); widgetLayout = new QGridLayout(this); //this->setContentsMargins(0, 0, 0, 0); @@ -698,9 +699,9 @@ EndpointWidget::EndpointWidget(EndpointHandler* eph, QWidget *parent, uint64_t i }); log_debugcpp("ENDPOINT_WIDGETED"); + eph->createSessionHandlersCallback(); } - void EndpointWidget::addSessionWidget(CustomWidgetEvent* ev){ this->setUpdatesEnabled(false); uint64_t index = this->sessionWidgets.size(); @@ -779,7 +780,7 @@ void MainWindow::customEvent(QEvent* ev) { } //__attribute__((optimize("O0", "unroll-loops"))) -void MainWindow::removeEndpointWidget(CustomWidgetEvent* ev){ +void MainWindow::removeEndpointWidget(CustomWidgetEvent* ev) { uint64_t i = ev->payload; this->ews.at(i)->setParent(nullptr); this->widgetLayout->removeWidget(ews.at(i)); @@ -792,7 +793,7 @@ void MainWindow::removeEndpointWidget(CustomWidgetEvent* ev){ return; } -void MainWindow::addEndpointWidget(CustomWidgetEvent* ev){ +void MainWindow::addEndpointWidget(CustomWidgetEvent* ev) { EndpointWidget* epw = new EndpointWidget(ev->payload, containerWidget, this->ews.size()); //epw->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); epw->setParent(this); @@ -924,9 +925,9 @@ EndpointHandler* EndpointWidget::getEndpointHandler(){ * } */ -void EndpointWidget::setIndex(uint64_t idx){ +void EndpointWidget::setIndex(uint64_t idx) { this->idx = idx; - this->eph->setState(EndpointState::ENDPOINT_ACTIVE, this->idx); + this->eph->setFrontVisibilityInfo(EndpointState::ENDPOINT_ACTIVE, this->idx); } uint64_t EndpointWidget::getIndex(){