Compare commits

...
Sign in to create a new pull request.

57 commits

Author SHA1 Message Date
5211b70669 sessions dynamically removed 2024-02-07 16:56:23 +01:00
0dd016bb16 add session 2024-02-07 16:56:23 +01:00
574c6f039e temp commit 2024-02-07 16:56:23 +01:00
064c16d9e7 session volume/mute polling 2024-02-07 16:56:23 +01:00
cb9446cb42 temp commit 2024-02-07 16:56:07 +01:00
6d88697811 session baby steps 2024-02-07 16:56:07 +01:00
6f8455c63d mic back/cont & plug/unplug done; devicead/rem to go 2024-02-07 16:56:06 +01:00
44ccde6ac8 almost captured, only to hotplug. such is life... 2024-02-07 16:56:06 +01:00
f92df42995 uuh... peak? 2024-02-07 16:56:06 +01:00
6d2f981d35 fixed stack corruption after refactor? 2024-02-07 16:56:06 +01:00
14fae226bc wip: heap corruption (3rd item main volume) 2024-02-07 16:56:06 +01:00
60e3178e9a fixed xekboxes 2024-02-07 16:56:06 +01:00
6744a64fce wip remove epw now working, xekboxs still funky 2024-02-07 16:56:06 +01:00
a15037c5f2 wip chex still buggy + customEvent 2024-02-07 16:56:06 +01:00
04da76c021 enable/disable/add/remove groundwork done 2024-02-07 16:56:06 +01:00
a6a052f348 endpoint add/remove foundational work 2024-02-07 16:56:06 +01:00
fc63875851 defaults working as expected. bruh 2024-02-07 16:55:45 +01:00
f620a0575d wip: setenabled crash to fix 2024-02-07 16:55:45 +01:00
1a4692533d wip: default callback 2024-02-07 16:55:44 +01:00
24110624fb various fixes 2024-02-07 16:55:44 +01:00
e278280c4b phantom header and default role recollection 2024-02-07 16:55:44 +01:00
5c8c1509c8 poc prevent duplicate instances 2024-02-07 16:55:44 +01:00
5a9d2f7099 implemented tray icon 2024-02-07 16:55:44 +01:00
1fcf6c3722 fixed memory leak 2024-02-07 16:55:44 +01:00
e1dd3dc532 stoopid pointer 2024-02-07 16:55:44 +01:00
8c1cea2da9 polling data source vector'd and moved to eph 2024-02-07 16:55:44 +01:00
8e9de6a771 rounding factor and sndvol trick note: ready to move on 2024-02-07 16:55:44 +01:00
1a9f141087 code cleanup, ready to debug 2024-02-07 16:55:44 +01:00
b15e5d6df7 fixed back->front channel bar desync 2024-02-07 16:55:44 +01:00
1797b39b30 full functionality restored, slight cleanup 2024-02-07 16:55:44 +01:00
d1f0bcaf26 back to front now works without hangs? 2024-02-07 16:55:44 +01:00
966cf91a23 more code cleanup; changed define for channel enum 2024-02-07 16:55:43 +01:00
729f01a189 code cleanup; channels callback coalesced again 2024-02-07 16:55:43 +01:00
9b1c251a3c Correctly update channel sliders 2024-02-07 16:55:43 +01:00
5bb37eb9fd Remove frontend header from contclasses 2024-02-07 16:55:43 +01:00
81f6cb32c8 changed invoke instances with call-to-mem-fun macro 2024-02-07 16:55:43 +01:00
60aff9891f added pdb generation, fixed unintended back call 2024-02-07 16:55:43 +01:00
33330419a9 broken: fixed event toggling order 2024-02-07 16:55:43 +01:00
e30ed58c08 broken: play dj outside, get it stuck 2024-02-07 16:55:43 +01:00
7fb67cff3f forgot todo 2024-02-07 16:55:43 +01:00
4d9bae4c87 wip channel callback 2024-02-07 16:55:43 +01:00
cb81b49367 channels added to front programmatically 2024-02-07 16:55:43 +01:00
679ad34f84 main slider cbk, detected minor l_dcpp bug 2024-02-07 16:55:43 +01:00
a251b4cb6b fixed overload funcs and connect() 2024-02-07 16:55:43 +01:00
167331944c first callback implemented; overload not working 2024-02-07 16:55:43 +01:00
a565190e6f reverted failed attempt, fixed callback release 2024-02-07 16:55:42 +01:00
c8d64481e8 guid sent and validated for mute 2024-02-07 16:55:42 +01:00
44461afdc4 template and fixed guid obtaining 2024-02-07 16:55:42 +01:00
4e10385a3b Refactored program structure 2024-02-07 16:55:42 +01:00
bc82ec72ed wip partial refactor 2024-02-07 16:55:42 +01:00
ad34a38f38 updated build files 2024-02-07 16:55:42 +01:00
cf1829bd78 Declare EndpointWidget before using it 2024-02-07 16:55:42 +01:00
f84ddaef6c failed attempt at redrawing 2024-02-07 16:55:42 +01:00
e42c2dd6c9 mute city boton momento 2024-02-07 16:55:42 +01:00
eaa935fb39 barritas de canal que funcionan weeeee 2024-02-07 16:55:42 +01:00
b006896ccb debug.h y endpointwidget 2024-02-07 16:55:42 +01:00
826373aee4 no copies objetos, anda 2024-02-07 16:55:30 +01:00
21 changed files with 2850 additions and 188 deletions

5
assets.qrc Normal file
View file

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>assets/notificationAreaIcon.png</file>
</qresource>
</RCC>

BIN
assets/SoundVolumeView.exe Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View file

@ -1,2 +1,4 @@
qmake -o build\Makefile .\qtest.pro
mingw32-make.exe -C .\build -f Makefile.Release
copy /Y /B .\assets\SoundVolumeView.exe .\build\debug
copy /Y /B .\assets\SoundVolumeView.exe .\build\release
mingw32-make.exe -C .\build -f Makefile

View file

@ -1,8 +1,16 @@
CONFIG += debug console
QT += widgets
QMAKE_CXXFLAGS += --target=x86_64-w64-mingw32 -g -gcodeview
QMAKE_LFLAGS += --target=x86_64-w64-mingw32 -g -Wl,-pdb= -v
LIBS += -LC:/capybara/libclang/x86_64-w64-mingw32/lib -lWinmm -lodbc32 -lodbccp32 -luuid -loleaut32 -lole32 -lshell32 -ladvapi32 -lcomdlg32 -lwinspool -lgdi32 -luser32 -lkernel32
#"kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" -luuid -loleaut32 -lole32 -lshell32 -ladvapi32 -lcomdlg32 -lwinspool -lgdi32 -luser32 -lkernel32
DEFINES += DEBUG QT_LOGGING_TO_CONSOLE=1 WIN32_LEAN_AND_MEAN
CONFIG += debug
QT += widgets network
INCLUDEPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
DESTPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
VPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp contclasses.cpp
HEADERS += qtclasses.h backlasses.h contclasses.h global.h
SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp backsessionclasses.cpp contclasses.cpp contsessionclasses.cpp
HEADERS += qtclasses.h backlasses.h backsessionclasses.h contclasses.h contsessionclasses.h global.h debug.h backfuncs.h ipolicyconfig.h msinclude.h
RESOURCES = assets.qrc
#DESTDIR += "build"

32
src/back/backfuncs.h Normal file
View file

@ -0,0 +1,32 @@
GUID inline NGuidToGUID(NGuid guid) {
GUID msGuid = GUID();
msGuid.Data1 = guid.data1;
msGuid.Data2 = guid.data2;
msGuid.Data3 = guid.data3;
for (int i = 0; i < 8; i++){
msGuid.Data4[i] = guid.data4[i];
//log_debugcpp("MSGUID DATA4 BYTE " << i << ": ");
//log_debugcpp(print_as_binary(8, uint32_t, msGuid.Data4[i]));
}
//log_debugcpp("MSGUID DATA1: " << msGuid.Data1);
//log_debugcpp("MSGUID DATA2: " << msGuid.Data2);
//log_debugcpp("MSGUID DATA3: " << msGuid.Data3);
return msGuid;
}
NGuid inline GUIDToNGuid(LPGUID msGuid){
NGuid guid = NGuid();
guid.data1 = msGuid->Data1;
guid.data2 = msGuid->Data2;
guid.data3 = msGuid->Data3;
for (int i = 0; i < 8; i++){
guid.data4[i] = msGuid->Data4[i];
//log_debugcpp("GUID DATA4 BYTE " << i << ": ");
//log_debugcpp(print_as_binary(8, uint32_t, guid.data4[i]));
}
//log_debugcpp("GUID DATA1: " << guid.data1);
//log_debugcpp("GUID DATA2: " << guid.data2);
//log_debugcpp("GUID DATA3: " << guid.data3);
return guid;
}

View file

@ -1,40 +1,563 @@
#include <backlasses.h>
#include <backfuncs.h>
Endpoint::Endpoint(IMMDevice* ep){
EndpointNewSessionCallback::EndpointNewSessionCallback(EndpointHandler* eph){
this->eph = eph;
}
ULONG EndpointNewSessionCallback::AddRef(){
return InterlockedIncrement(&ref);
}
ULONG EndpointNewSessionCallback::Release(){
ULONG tempRef = InterlockedDecrement(&ref);
if (tempRef == 0) {
delete this;
}
return tempRef;
}
HRESULT EndpointNewSessionCallback::QueryInterface(REFIID riid, VOID **ppvInterface) {
if (IID_IUnknown == riid)
{
AddRef();
*ppvInterface = (IUnknown*)this;
}
else if (__uuidof(IAudioSessionNotification) == riid)
{
AddRef();
*ppvInterface = (IMMNotificationClient*)this;
}
else
{
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
HRESULT EndpointNewSessionCallback::OnSessionCreated(IAudioSessionControl *NewSession) {
if (eph->getFlow() == Flows::FLOW_CAPTURE) return S_OK;
HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
IAudioSessionControl2* sessionControl;
//ISimmpleAudioVolume* sessionVolume;
if (FAILED(NewSession->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl))) { log_wdebugcpp(L"no nueva sesion......"); };
if (sessionControl) {
sessionControl->AddRef();
//sessionControl->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&sessionVolume);
Session* newSession = new Session(this->eph->getEndpoint(), sessionControl);
eph->addSessionSendFront(newSession);
}
if (result == S_OK)
CoUninitialize();
return S_OK;
}
EndpointVolumeCallback::EndpointVolumeCallback(Endpoint* ep){
this->ep = ep;
}
ULONG EndpointVolumeCallback::AddRef(){
return InterlockedIncrement(&ref);
}
ULONG EndpointVolumeCallback::Release(){
ULONG tempRef = InterlockedDecrement(&ref);
if (tempRef == 0) {
delete this;
}
return tempRef;
}
HRESULT EndpointVolumeCallback::QueryInterface(REFIID riid, VOID **ppvInterface) {
if (IID_IUnknown == riid)
{
AddRef();
*ppvInterface = (IUnknown*)this;
}
else if (__uuidof(IAudioEndpointVolumeCallback) == riid)
{
AddRef();
*ppvInterface = (IAudioEndpointVolumeCallback*)this;
}
else
{
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
HRESULT EndpointVolumeCallback::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) {
if (pNotify == NULL) return E_INVALIDARG;
//delete osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller;
//osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.freeData4();
//Could've made a function or = override to hide this within Nguid, but back in cont = bad.
osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data1 \
= pNotify->guidEventContext.Data1;
osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data2 \
= pNotify->guidEventContext.Data2;
osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data3 \
= pNotify->guidEventContext.Data3;
for(int i = 0; i < 8 /* Data4 size */; i++){
osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data4[i] = pNotify->guidEventContext.Data4[i];
}
//memcpy(&osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller, &pNotify->guidEventContext,sizeof(NGuid) );
Flows flow = this->ep->getFlow();
EndpointHandler* eph = nullptr;
if (flow & Flows::FLOW_PLAYBACK) {
eph = osh->getPlaybackEndpointHandlers().at(this->ep->getIndex());
} else {
eph = osh->getCaptureEndpointHandlers().at(this->ep->getIndex());
}
eph->getCallbackInfo()->muted = pNotify->bMuted;
eph->getCallbackInfo()->mainVolume = pNotify->fMasterVolume;
eph->getCallbackInfo()->channels = pNotify->nChannels;
UINT j = 0;
//todo: do while here caused stack corruption; sus
while(j < pNotify->nChannels) {
if (flow & Flows::FLOW_PLAYBACK)
eph->getCallbackInfo()->channelVolumes[j] = pNotify->afChannelVolumes[j];
else
eph->getCallbackInfo()->channelVolumes[j] = pNotify->afChannelVolumes[j];
j++;
}
return S_OK;
}
/*
* EndpointSituationCallback::EndpointSituationCallback(IMMDeviceEnumerator *deviceEnumerator, std::vector<Endpoint*> playbackDevices){
* this->deviceEnumerator = deviceEnumerator;
* this->playbackDevices = playbackDevices;
* }
*
*/
//todo: not on construct since it expects them to already exist; smells like refactor!
void EndpointSituationCallback::fill(IMMDeviceEnumerator *deviceEnumerator, std::vector<Endpoint*> playbackDevices, std::vector<Endpoint*> captureDevices){
this->deviceEnumerator = deviceEnumerator;
this->playbackDevices = playbackDevices;
this->captureDevices = captureDevices;
}
ULONG EndpointSituationCallback::AddRef(){
return InterlockedIncrement(&ref);
}
ULONG EndpointSituationCallback::Release(){
ULONG tempRef = InterlockedDecrement(&ref);
if (tempRef == 0) {
delete this;
}
return tempRef;
}
HRESULT EndpointSituationCallback::QueryInterface(REFIID riid, VOID **ppvInterface) {
if (IID_IUnknown == riid)
{
AddRef();
*ppvInterface = (IUnknown*)this;
}
else if (__uuidof(IMMNotificationClient) == riid)
{
AddRef();
*ppvInterface = (IMMNotificationClient*)this;
}
else
{
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
HRESULT EndpointSituationCallback::OnDefaultDeviceChanged(EDataFlow flow, ERole role,LPCWSTR pwstrDeviceId) {
if (flow == EDataFlow::eCapture) return E_INVALIDARG;
Roles nRole;
switch (role) {
case ERole::eConsole:
nRole = Roles::ROLE_CONSOLE;
break;
case ERole::eMultimedia:
nRole = Roles::ROLE_MULTIMEDIA;
break;
case ERole::eCommunications:
nRole = Roles::ROLE_COMMUNICATIONS;
break;
}
std::wstring wstringEndpointId = pwstrDeviceId;
log_wdebugcpp(L"we got za defol 4 " + wstringEndpointId);
osh->changeFrontDefaultsCallback(nRole, wstringEndpointId);
return S_OK;
}
HRESULT EndpointSituationCallback::OnDeviceAdded(LPCWSTR pwstrDeviceId) {
log_wdebugcpp(L"ayo we eventing za adin " + std::wstring(pwstrDeviceId));
return S_OK;
};
HRESULT EndpointSituationCallback::OnDeviceRemoved(LPCWSTR pwstrDeviceId) {
log_wdebugcpp(L"ayo we eventing za rmovin " + std::wstring(pwstrDeviceId));
return S_OK;
}
HRESULT EndpointSituationCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) {
std::wstring endpointId = std::wstring(pwstrDeviceId);
switch (dwNewState){
case DEVICE_STATE_ACTIVE:
osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_ACTIVE);
break;
case DEVICE_STATE_DISABLED:
osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_DISABLED);
break;
case DEVICE_STATE_NOTPRESENT:
osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_NOTPRESENT);
break;
case DEVICE_STATE_UNPLUGGED:
osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_UNPLUGGED);
break;
}
return S_OK;
}
HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) {
/*
* log_debugcpp(" -->Changed device property " +
* key.fmtid.Data1 + key.fmtid.Data2 + key.fmtid.Data3 + "\n" +
* key.fmtid.Data4[0]+ key.fmtid.Data4[1]+ "\n"+
* key.fmtid.Data4[2]+ key.fmtid.Data4[3] + "\n"+
* key.fmtid.Data4[4]+ key.fmtid.Data4[5] + "\n"+
* key.fmtid.Data4[6]+ key.fmtid.Data4[7]+ "\n"+
* " pid " + key.pid);
*/
return S_OK;
}
Endpoint::Endpoint(IMMDevice* ep, uint64_t idx){
this->endpoint = ep;
if(FAILED(endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&endpointVolume))) { log_debugcpp("si"); };
//Obtaining friendly name: IPropertyStore creates PROPVARIANT per field
// hr = endpointPtr->GetId(&endpointID);
this->idx = idx;
/*
* It can't multiflag, it's that stupid. MS momento.
* Only shows most relevant flag according to MS, i.e. 0110 sends 0010
*/
//todo: preguntitas owindows dword no es uint32_t even tho mingw mingas
if(FAILED(endpoint->GetState(&this->endpointState))) {exit(-1);};
if(this->endpointState == EndpointState::ENDPOINT_ACTIVE) {
activateEndpointVolume();
}
reloadEndpointChannels();
/* todo: check header
* if(FAILED(endpoint->Activate(__uuidof(IAudioMeterInformation),
* CLSCTX_ALL, NULL, (void**)&endpointPeakMeter))) { log_debugcpp("peakbros..."); }
*/
//todo:: atexit into exit Gather ID
LPWSTR tempString = nullptr;
if (FAILED(endpoint->GetId(&tempString))) {exit(-1);};
endpointId = std::wstring(tempString);
log_wdebugcpp(endpointId);
CoTaskMemFree(tempString);
endpoint->OpenPropertyStore(STGM_READ, &properties);
PROPVARIANT pv;
properties->GetValue(PKEY_Device_FriendlyName , &pv);
friendlyName = pv.pwszVal;
if (pv.pwszVal == nullptr)
friendlyName = L"Unnamed Not Present Endpoint";
else
friendlyName = std::wstring(pv.pwszVal);
this->setFlow();
if (this->flow == Flows::FLOW_PLAYBACK) {
activateEndpointSessions();
}
}
LPWSTR Endpoint::getName(){
/*
* Endpoint::Endpoint(IMMDevice* endpoint) : Endpoint(endpoint, 0) {};
*/
void Endpoint::activateEndpointSessions() {
//sessionManager;
if (FAILED(endpoint->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**) &sessionManager))) { log_wdebugcpp(L"sesionbros..."); return; }
IAudioSessionEnumerator* sessionEnumerator = nullptr;
if (FAILED(sessionManager->GetSessionEnumerator(&sessionEnumerator))) { log_wdebugcpp(L"sesEnumeratorBros..."); return; }
int sessionCount;
sessionEnumerator->GetCount(&sessionCount);
for (int i = 0; i < sessionCount; i++) {
IAudioSessionControl* sessionControlTmp;
sessionEnumerator->GetSession(i, (IAudioSessionControl**)&sessionControlTmp);
//todo:: asegurar lo del dynamic_cast
IAudioSessionControl2* sessionControl;
sessionControlTmp->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl);
sessionControl->AddRef();
sessionControlTmp->Release();
Session* session = new Session(this, sessionControl, (size_t)i);
endpointSessions.push_back(session);
}
sessionEnumerator->Release();
}
void Endpoint::addSession(Session* session) {
session->setIndex(this->getSessionCount());
endpointSessions.push_back(session);
}
void Endpoint::activateEndpointVolume() {
//bool extraThread = false;
/*
* Forgive me, for MS has sinned, and now I must too.
*/
if (this->endpointVolume == nullptr){
HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&this->endpointVolume);
//if (endpointVolume == nullptr) { //why they returning 0 after dealing with the error jfc CO_E_NOTINITIALIZED) {
//CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
//extraThread = true;
//goto initialized;
//}
//log_debugcpp(std::string("no endpointVolume (IAudioEndpointVolume)"));
if (result == S_OK)
CoUninitialize();
}
}
void Endpoint::reloadEndpointChannels() {
if (this->endpointState == DEVICE_STATE_ACTIVE) {
if (FAILED(endpointVolume->GetChannelCount(&channelCount))) {log_debugcpp("get channel count fail");};/* */
}
}
void Endpoint::setIndex(uint64_t idx){
this->idx = idx;
}
uint64_t Endpoint::getIndex(){
return idx;
}
std::wstring Endpoint::getName(){
return friendlyName;
}
float Endpoint::getVolume(){
std::wstring Endpoint::getId(){
return endpointId;
}
float Endpoint::getVolume(int channel){
float volume;
if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { log_debugcpp("si");}
if (channel == AudioChannel::CHANNEL_MAIN) {
if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { /* log_debugcpp("si") */;}
} else {
if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */}
}
return volume;
}
void Endpoint::setVolume(float volume) {
if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, NULL))) { log_debugcpp("si"); };
uint32_t Endpoint::getChannelCount(){
return (uint32_t)channelCount;
}
//Endpoint::~Endpoint(){
// free(friendlyName);
// properties->Release();
// endpointVolume->Release();
// endpoint->Release();
//}
bool Endpoint::getMute(){
BOOL mut;
if(FAILED(endpointVolume->GetMute(&mut))) { /* TIP: Below */ }
bool mute = (bool)mut;
return mute;
}
void Overseer::initCOMLibrary(){
if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { log_debugcpp("si"); };
void Endpoint::setState(uint8_t state){
this->endpointState = state;
if(state == EndpointState::ENDPOINT_ACTIVE) {
this->activateEndpointVolume();
this->reloadEndpointChannels();
}
}
size_t Endpoint::getState(){
return this->endpointState;
}
void Endpoint::setVolume(NGuid guid, int channel, float volume) {
//TIP: There used to be log messages here. Now, it's a ghost town.
GUID tempMsGuid = NGuidToGUID(guid);
if (channel == AudioChannel::CHANNEL_MAIN) {
if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, &tempMsGuid))) {};
} else {
if(FAILED(endpointVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) {};
}
}
void Endpoint::setMute(NGuid guid, bool muted) {
GUID tempMsGuid = NGuidToGUID(guid);
if(FAILED(endpointVolume->SetMute(muted, &tempMsGuid))) { log_wdebugcpp(std::wstring(L"EndpointVolume null?")); };
}
void Endpoint::setVolumeCallback(EndpointVolumeCallback *epc){
if(endpointVolume == nullptr) {
this->activateEndpointVolume();
}
endpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc);
}
void Endpoint::removeVolumeCallback(EndpointVolumeCallback *epc){
endpointVolume->UnregisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc);
}
Roles Endpoint::getRoles(){
return this->endpointRoles;
}
void Endpoint::setRoles(Roles role){
//otro exe momento
STARTUPINFOEXW startupConfig;
PROCESS_INFORMATION processInfo;
SecureZeroMemory(&startupConfig, sizeof(STARTUPINFOEXW));
SecureZeroMemory(&startupConfig.StartupInfo, sizeof(STARTUPINFOW));
startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW);
SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
std::wstring command = L"SoundVolumeView.exe /SetDefault " + endpointId + L" ";
std::wstring troublePair = L"0";
switch (role) {
case Roles::ROLE_ALL:
/*
* console or multimedia, one sends both, at least for now;
* either cos of ms or dis guy;
* no choice but to treat them as one for now.
* command += L"all"; and nothing else would've been nice...
*/
troublePair = command + troublePair;
if(CreateProcessW(
NULL,
(wchar_t*)troublePair.c_str(),
NULL,
NULL,
false,
CREATE_UNICODE_ENVIRONMENT,
NULL,
NULL,
(LPSTARTUPINFOW)&startupConfig,
&processInfo
) == true) {
WaitForSingleObject(processInfo.hProcess, INFINITE );
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
command += L"2";
break;
case Roles::ROLE_CONSOLE:
command += std::to_wstring(0);
break;
case Roles::ROLE_MULTIMEDIA:
command += std::to_wstring(1);
break;
case Roles::ROLE_COMMUNICATIONS:
command += std::to_wstring(2);
break;
}
if(CreateProcessW(
NULL,
(wchar_t*)command.c_str(),
NULL,
NULL,
false,
CREATE_UNICODE_ENVIRONMENT,
NULL,
NULL,
(LPSTARTUPINFOW)&startupConfig,
&processInfo
) == true) {
WaitForSingleObject(processInfo.hProcess, INFINITE );
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
}
void Endpoint::assignRoles(Roles role){
Roles roles = (Roles)(endpointRoles | role);
this->endpointRoles = roles;
}
void Endpoint::removeRoles(Roles role){
Roles roles = (Roles)(endpointRoles ^ role);
this->endpointRoles = roles;
}
void Endpoint::setFlow() {
IMMEndpoint* flowGetter;
//this should be as simple as writing IID_IMMEndpoint, but it just won't find the macro, so I copied it. Sad.
GUID manual;
manual.Data1 = 0x1be09788;
manual.Data2 = 0x6894;
manual.Data3 = 0x4089;
manual.Data4[0] = 0x85;
manual.Data4[1] = 0x86;
manual.Data4[2] = 0x9a;
manual.Data4[3] = 0x2a;
manual.Data4[4] = 0x6c;
manual.Data4[5] = 0x26;
manual.Data4[6] = 0x5a;
manual.Data4[7] = 0xc5;
if(FAILED(this->endpoint->QueryInterface((const _GUID)manual, (void**)&flowGetter)))
{ log_debugcpp("no flow..."); }
EDataFlow MSflow;
HRESULT vafllar = flowGetter->GetDataFlow(&MSflow);
this->flow = (MSflow == EDataFlow::eRender ? Flows::FLOW_PLAYBACK : Flows::FLOW_CAPTURE);
flowGetter->Release();
}
Flows Endpoint::getFlow() {
return this->flow;
}
/* sessions */
std::vector<Session*> Endpoint::getSessions() {
return endpointSessions;
}
size_t Endpoint::getSessionCount() {
return endpointSessions.size();
}
void Endpoint::registerNewSessionNotification(EndpointNewSessionCallback* ensc){
sessionManager->RegisterSessionNotification(ensc);
}
void Endpoint::unregisterNewSessionNotification(EndpointNewSessionCallback* ensc){
sessionManager->UnregisterSessionNotification(ensc);
}
Endpoint::~Endpoint(){
log_wdebugcpp(L"murio endpoint-san uwu");
properties->Release();
endpointVolume->Release();
endpoint->Release();
sessionManager->Release();
}
void Overseer::initCOMLibrary() {
OutputDebugStringW(L"EPWidget creation\n");
if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) {
log_debugcpp("si"); };
//Retrieving endpoint enumerator
@ -44,58 +567,148 @@ void Overseer::initCOMLibrary(){
(void**)&deviceEnumerator)) )
{ log_debugcpp("si"); };
GUID tempGuid;
if(FAILED(CoCreateGuid(&tempGuid))) { log_debugcpp("Failed to obtain GUID: " ); };
//todo: wtf? why is it working? floats are ptrs...
this->guid = GUIDToNGuid(&tempGuid);
//if(FAILED(CoCreateInstance(__uuidof(CPolicyConfigClient),
// NULL, CLSCTX_ALL, __uuidof(IPolicyConfig10), (LPVOID *)&policyConfig))) {exit(-1);}
//TODO: Release lpguid?
//TODO: Uninitialize COM
}
void Overseer::reloadEndpoints() {
void Overseer::reloadEndpoints(Flows flow) {
IMMDeviceCollection *deviceCollection;
unsigned int numEndpoints;
EDataFlow MSflow = (flow == Flows::FLOW_PLAYBACK ? EDataFlow::eRender : EDataFlow::eCapture);
// | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED
if(FAILED(deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection) ))
// NOTPRESENT shows a lot of garbage, unnamed devices.
if(FAILED(deviceEnumerator->EnumAudioEndpoints(MSflow, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED, &deviceCollection) ))
{ log_debugcpp("si"); };
/*
* Counting them
*/
if(FAILED(deviceCollection->GetCount(&numEndpoints))) { log_debugcpp("si");};
if(numEndpoints == 0) { log_debugcpp("si"); };
//Counting them
if(FAILED(deviceCollection->GetCount(&numPlaybackEndpoints))) { log_debugcpp("si");};
if(numPlaybackEndpoints == 0) { log_debugcpp("si"); };
//Retrieving actual endpoints and storing them on their own class
for (unsigned int i = 0; i < numPlaybackEndpoints; i++){
/*
* Retrieving actual endpoints and storing them on their own class
*/
IMMDevice *temp;
for (unsigned int i = 0; i < numEndpoints; i++){
if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); };
Endpoint *endpoint = new Endpoint(temp);
Endpoint *endpoint = new Endpoint(temp, i);
if (flow == Flows::FLOW_PLAYBACK)
this->playbackDevices.push_back(endpoint);
//TODO: le porblemx std::cout << "ola" << std::endl;
else
this->captureDevices.push_back(endpoint);
//TODO: le porblemx std::cout + "ola" + std::endl;
}
deviceCollection->Release();
/*
* Discerning default endpoints per role
* order: console, multimedia, communications
*/
for(int i = 0; i < ERole_enum_count; i++){
ERole val;
switch(i) {
case 0:
val = eConsole;
break;
case 1:
val = eMultimedia;
break;
case 2:
val = eCommunications;
break;
}
deviceEnumerator->GetDefaultAudioEndpoint(MSflow, val, &temp);
LPWSTR id = nullptr;
if (flow == Flows::FLOW_PLAYBACK) {
for (unsigned int j = 0; j < numEndpoints; j++) {
std::wstring eptId = playbackDevices.at(j)->getId();
temp->GetId(&id);
int comparison = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, eptId.c_str(), -987, id, -987, NULL, NULL, 0);
if (comparison - 2 == 0) {
log_wdebugcpp(L"ola defaul playback de "
+ std::to_wstring(i) + L" es " + id);
playbackDevices.at(j)->assignRoles((Roles)(1 << i));
}
}
} else {
for (unsigned int j = 0; j < numEndpoints; j++){
std::wstring eptId = captureDevices.at(j)->getId();
temp->GetId(&id);
int comparison = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, eptId.c_str(), -987, id, -987, NULL, NULL, 0);
if (comparison - 2 == 0) {
log_wdebugcpp(L"ola defaul capture de "
+ std::to_wstring(i) + L" es " + id);
captureDevices.at(j)->assignRoles((Roles)(1 << i));
}
}
}
}
}
Overseer::Overseer(){
Endpoint* Overseer::addEndpoint(std::wstring endpointId, /* out */Flows* flow = nullptr) {
IMMDevice* newep;
if(FAILED(deviceEnumerator->GetDevice((LPCWSTR)endpointId.c_str(), &newep)))
log_debugcpp("ay caramba con la hot metida.");
Endpoint *endpoint = new Endpoint(newep);
Flows getFlow = endpoint->getFlow();
if (getFlow == Flows::FLOW_PLAYBACK) {
endpoint->setIndex(osh->getPlaybackEndpointsCount());
this->playbackDevices.push_back(endpoint);
} else {
endpoint->setIndex(osh->getCaptureEndpointsCount());
this->captureDevices.push_back(endpoint);
}
if (flow != nullptr) *flow = getFlow;
return endpoint;
}
Overseer::Overseer() { //: epsc(deviceEnumerator, playbackDevices){
//Initializing COM library
log_debugcpp("Initializing Overseer");
initCOMLibrary();
//Obtaining playback endpoint collection on this point in time
reloadEndpoints();
reloadEndpoints(Flows::FLOW_PLAYBACK);
//reloadEndpoints(Flows::FLOW_CAPTURE);
//Registering for endpoint information callback
this->epsc.fill(deviceEnumerator, playbackDevices, captureDevices);
if(FAILED(deviceEnumerator->RegisterEndpointNotificationCallback(((IMMNotificationClient*)&epsc)))) { log_debugcpp("when no enchufas......"); }
}
//Overseer::int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint){
//if (FAILED(deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &endpointPtr)))
// return 1;
//return 0;
//}
//int Overseer::getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
NGuid Overseer::getGuid() {
return guid;
}
std::vector<Endpoint*> Overseer::getPlaybackEndpoints() {
return playbackDevices;
}
//Overseer::~Overseer(){
// deviceEnumerator->Release();
// for(unsigned long long i = 0; i < playbackDevices.size(); i++){
//delete(playbackDevices.at(i));
//}
//}
std::vector<Endpoint*> Overseer::getCaptureEndpoints() {
return captureDevices;
}
Overseer::~Overseer(){
log_debugcpp("cum");
deviceEnumerator->Release();
for(unsigned long long i = 0; i < playbackDevices.size(); i++){
delete(playbackDevices.at(i));
}
}
//int Overseer::getCaptureEndpoints(std::vector<Endpoint*> *captureEndpoints);

View file

@ -1,38 +1,105 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include "msinclude.h"
#include "backsessionclasses.h"
#include "global.h"
#include <vector>
#include <iostream>
#include "contclasses.h"
#include <Windows.h>
#include <mmdeviceapi.h>
#include <combaseapi.h>
#include <initguid.h>
#include <functiondiscoverykeys_devpkey.h>
#include <endpointvolume.h>
#include <audiopolicy.h>
#include <audioclient.h>
//#include <comdef.h>
//#include <comip.h>
#include <Winerror.h>
class EndpointVolumeCallback;
class Session;
class Endpoint {
public:
Endpoint(IMMDevice* endpoint);
void setVolume(float volume);
float getVolume();
LPWSTR getName();
//~Endpoint();
Endpoint(IMMDevice* endpoint, uint64_t idx);
//todo: how to forward declare delegate constructors?
Endpoint(IMMDevice* endpoint) : Endpoint(endpoint, 0) {};
void reloadEndpointChannels();
uint64_t getIndex();
void setIndex(uint64_t idx);
void setVolume(NGuid guid, int channel, float volume);
uint32_t getChannelCount();
float getVolume(int channel);
void setMute(NGuid guid, bool muted);
bool getMute();
void setState(uint8_t state);
size_t getState();
Roles getRoles();
void setRoles(Roles role);
void assignRoles(Roles role);
void removeRoles(Roles role);
void setFlow();
Flows getFlow();
std::wstring getId();
std::wstring getName();
void setVolumeCallback(EndpointVolumeCallback *epc);
void removeVolumeCallback(EndpointVolumeCallback *epc);
/* sessions */
std::vector<Session*> getSessions();
size_t getSessionCount();
void addSession(Session* session);
void registerNewSessionNotification(EndpointNewSessionCallback* ensc);
void unregisterNewSessionNotification(EndpointNewSessionCallback* ensc);
~Endpoint();
private:
void inline activateEndpointVolume();
void inline activateEndpointSessions();
std::vector<Session*> endpointSessions;
uint32_t channelCount = 0;
IMMDevice* endpoint;
IAudioEndpointVolume *endpointVolume ;
IAudioSessionManager2 *sessionManager;
Flows flow;
IAudioEndpointVolume *endpointVolume = nullptr;
IPropertyStore *properties;
LPWSTR friendlyName;
// LPWSTR endpointID = NULL;
std::wstring friendlyName;
std::wstring endpointId;
unsigned long endpointState;
Roles endpointRoles = (Roles)0;
uint64_t idx;
/* Not implemented in llvm-mingw. Sad!
* IAudioMeterInformation *endpointPeakMeter = nullptr;
*/
};
class EndpointVolumeCallback : public IAudioEndpointVolumeCallback {
public:
EndpointVolumeCallback(Endpoint* ep);
ULONG AddRef();
ULONG Release();
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
HRESULT OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA update);
//~EndpointVolumeCallback();
private:
ULONG ref = 1;
Endpoint* ep;
};
class EndpointSituationCallback : public IMMNotificationClient {
public:
//EndpointSituationCallback(IMMDeviceEnumerator *deviceEnumerator, std::vector<Endpoint*> playbackDevices);
ULONG AddRef();
ULONG Release();
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
HRESULT OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId);
HRESULT OnDeviceAdded(LPCWSTR pwstrDeviceId);
HRESULT OnDeviceRemoved(LPCWSTR pwstrDeviceId);
HRESULT OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState);
HRESULT OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key);
void fill(IMMDeviceEnumerator *deviceEnumerator, std::vector<Endpoint*> playbackDevices, std::vector<Endpoint*> captureDevices);
private:
ULONG ref = 1;
IMMDeviceEnumerator *deviceEnumerator;
std::vector<Endpoint*> playbackDevices;
std::vector<Endpoint*> captureDevices;
};
class Overseer {
@ -40,21 +107,44 @@ class Overseer {
public:
Overseer();
std::vector<Endpoint*> getPlaybackEndpoints();
void reloadEndpoints();
std::vector<Endpoint*> getCaptureEndpoints();
void reloadEndpoints(Flows flow);
Endpoint* addEndpoint(std::wstring endpointId, /* out */ Flows* flow);
NGuid getGuid();
//void setEndpointStatusCallback();
//void setEndpointStatusCallback();
//~Overseer();
//int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint);
//int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
//int getCaptureEndpoints(std::vector<Endpoint*> *captureEndpoints);
//IMMDeviceEnumerator** setOrigin();
//~Overseer();
~Overseer();
private:
unsigned int numPlaybackEndpoints;
NGuid guid;
IMMDeviceEnumerator *deviceEnumerator;
EndpointSituationCallback epsc;
//IPolicyConfig *policyConfig;
std::vector<Endpoint*> playbackDevices;
std::vector<Endpoint*> captureDevices;
void initCOMLibrary();
//IMMDeviceCollection *deviceCollection;
//int numCaptureEndpoints;
//std::vector<Endpoint*> *captureDevices;
};
class EndpointNewSessionCallback : public IAudioSessionNotification {
public:
EndpointNewSessionCallback(EndpointHandler *eph);
ULONG AddRef();
ULONG Release();
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
HRESULT OnSessionCreated(IAudioSessionControl *NewSession);
private:
ULONG ref = 1;
EndpointHandler *eph;
};

View file

@ -0,0 +1,282 @@
#include "backsessionclasses.h"
#include "backfuncs.h"
SessionStateCallback::SessionStateCallback(SessionHandler *sh) {
this->sh = sh;
}
ULONG SessionStateCallback::AddRef() {
return InterlockedIncrement(&ref);
}
ULONG SessionStateCallback::Release() {
ULONG tempRef = InterlockedDecrement(&ref);
if (tempRef == 0) {
delete this;
}
return tempRef;
}
HRESULT SessionStateCallback::QueryInterface(REFIID riid, VOID **ppvInterface) {
if (IID_IUnknown == riid)
{
AddRef();
*ppvInterface = (IUnknown*)this;
}
else if (__uuidof(IAudioSessionNotification) == riid)
{
AddRef();
*ppvInterface = (IMMNotificationClient*)this;
}
else
{
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
HRESULT SessionStateCallback::OnDisplayNameChanged(LPCWSTR NewDisplayName, LPCGUID EventContext) {
return S_OK;
}
HRESULT SessionStateCallback::OnIconPathChanged(LPCWSTR NewIconPath, LPCGUID EventContex) {
return S_OK;
}
HRESULT SessionStateCallback::OnSimpleVolumeChanged(float NewVolume, BOOL NewMute, LPCGUID EventContext) {
sh->getVolumeInfo()->muted = NewMute;
sh->getVolumeInfo()->mainVolume = NewVolume;
sh->getVolumeInfo()->caller = GUIDToNGuid((LPGUID)EventContext);
/*
* if (NewMute)
* {
* printf("MUTE\n");
* }
* else
* {
* printf("Volume = %d percent\n",
* (UINT32)(100*NewVolume + 0.5));
* }
*/
return S_OK;
}
HRESULT SessionStateCallback::OnChannelVolumeChanged(DWORD ChannelCount, float NewChannelVolumeArray[], DWORD ChangedChannel, LPCGUID EventContext) {
return S_OK;
}
HRESULT SessionStateCallback::OnGroupingParamChanged(LPCGUID NewGroupingParam, LPCGUID EventContext) {
return S_OK;
}
HRESULT SessionStateCallback::OnStateChanged(AudioSessionState NewState) {
SessionState newState;// = sh->getState();
switch (NewState) {
case AudioSessionStateActive:
newState = SessionState::ACTIVE;
break;
case AudioSessionStateInactive:
newState = SessionState::INACTIVE;
break;
case AudioSessionStateExpired:
newState = SessionState::EXPIRED;
break;
}
sh->reviseSessionShowing(newState);
return S_OK;
}
HRESULT SessionStateCallback::OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason) {
sh->setState(SessionState::DISCONNECTED);
sh->reviseSessionShowing(SessionState::DISCONNECTED);
return S_OK;
}
Session::Session(Endpoint* ep, IAudioSessionControl2* sessionControl, size_t idx) {
this->ep = ep;
this->sessionControl = sessionControl;
this->idx = idx;
AudioSessionState msState;
sessionControl->GetState(&msState);
switch (msState) {
case AudioSessionState::AudioSessionStateActive:
this->sessionState = SessionState::ACTIVE;
break;
case AudioSessionState::AudioSessionStateInactive:
this->sessionState = SessionState::INACTIVE;
break;
case AudioSessionState::AudioSessionStateExpired:
this->sessionState = SessionState::EXPIRED;
break;
}
sessionControl->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&sessionVolume);
DWORD pid;
sessionControl->GetProcessId(&pid);
if (sessionControl->IsSystemSoundsSession() == S_OK)
this->sessionName = std::wstring(LSTRING_SYSTEM_SOUNDS);
else {
LPWSTR sessionDisplayName;
this->sessionControl->GetDisplayName(&sessionDisplayName);
if (!wcscmp(sessionDisplayName, L""))
this->sessionName = this->fetchProcessName(pid);
else
this->sessionName = std::wstring(sessionDisplayName);
CoTaskMemFree(sessionDisplayName);
}
}
float Session::getVolume(int channel){
float volume;
if (channel == AudioChannel::CHANNEL_MAIN) {
if(FAILED(sessionVolume->GetMasterVolume(&volume))) { /* log_debugcpp("si") */;}
} else {
return 0.0;
//if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */}
}
return volume;
}
/*
* uint32_t Endpoint::getChannelCount(){
* return (uint32_t)channelCount;
* }
*/
std::wstring Session::getName() {
return sessionName;
}
bool Session::getMute() {
BOOL mut;
if(FAILED(sessionVolume->GetMute(&mut))) { /* TIP: Below */ }
bool mute = (bool)mut;
return mute;
}
void Session::setVolume(NGuid guid, int channel, float volume) {
//TIP: There used to be log messages here. Now, it's a ghost town.
GUID tempMsGuid = NGuidToGUID(guid);
if (channel == AudioChannel::CHANNEL_MAIN) {
if(FAILED(sessionVolume->SetMasterVolume(volume, &tempMsGuid))) {};
} else {
//if(FAILED(sessionVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) {};
}
}
void Session::setIndex(size_t idx) {
this->idx = idx;
}
void Session::setMute(NGuid guid, bool muted) {
GUID tempMsGuid = NGuidToGUID(guid);
if(FAILED(sessionVolume->SetMute(muted, &tempMsGuid))) { log_wdebugcpp(std::wstring(L"SessionVolume null?")); };
}
std::wstring Session::fetchProcessName(DWORD pid) {
/*
* https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
* https://stackoverflow.com/questions/11843368/how-to-get-process-description
*/
/* Executable path retrieval */
std::wstring exePath = L"";
HANDLE processList = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (processList == INVALID_HANDLE_VALUE) {
log_wdebugcpp(L"aye no procname.");
return exePath;
}
MODULEENTRY32W me32w;
me32w.dwSize = sizeof(MODULEENTRY32W);
if(Module32FirstW(processList, &me32w)) {
do {
if (me32w.th32ProcessID == pid) {
exePath = std::wstring(me32w.szExePath);
break;
/*
* However, if the calling process is a 32-bit process, you must call the
* QueryFullProcessImageName function to retrieve the full path of the
* executable file for a 64-bit process.
*/
}
} while(Module32NextW(processList, &me32w));
}
CloseHandle(processList);
/* File description retrieval */
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *translationArray;
DWORD filler;
DWORD fileVersionInfoSize = GetFileVersionInfoSizeW(exePath.c_str(), &filler);
if (!fileVersionInfoSize) return exePath;
void* fileVersionInfo = malloc(fileVersionInfoSize);
if(!GetFileVersionInfoW(exePath.c_str(),0,fileVersionInfoSize, fileVersionInfo))
return exePath;
UINT translationArrayLen = 0;
if (!VerQueryValueW(fileVersionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayLen))
return exePath;
bool match = false;
for (UINT i = 0; i < (translationArrayLen / sizeof(LANGANDCODEPAGE)); i++) {
wchar_t fileDescriptionKey[256];
LANGID defaultUILanguage = GetUserDefaultUILanguage();
if (defaultUILanguage != translationArray[i].wLanguage)
continue;
match = true;
wchar_t* fileDescription = NULL;
UINT fileDescriptionSize = 0;
swprintf(fileDescriptionKey, L"\\StringFileInfo\\%04x%04x\\FileDescription",
translationArray[i].wLanguage, translationArray[i].wCodePage);
if (VerQueryValueW(fileVersionInfo, fileDescriptionKey, (LPVOID*)&fileDescription, &fileDescriptionSize)) {
exePath = std::wstring(fileDescription);
}
}
if (!match && 1 <= (translationArrayLen / sizeof(LANGANDCODEPAGE))) {
wchar_t fileDescriptionKey[256];
wchar_t* fileDescription = NULL;
UINT fileDescriptionSize = 0;
swprintf(fileDescriptionKey, L"\\StringFileInfo\\%04x%04x\\FileDescription",
translationArray[0].wLanguage, translationArray[0].wCodePage);
if (VerQueryValueW(fileVersionInfo, fileDescriptionKey, (LPVOID*)&fileDescription, &fileDescriptionSize)) {
exePath = std::wstring(fileDescription);
}
}
free(fileVersionInfo);
return exePath;
}
//todo: conflicting names. change callback name
void Session::setState(SessionState state) {
sessionState = state;
}
SessionState Session::getState() {
return sessionState;
}
void Session::setStateCallback(SessionStateCallback *ssc){
sessionControl->RegisterAudioSessionNotification((IAudioSessionEvents*) ssc);
}
void Session::removeStateCallback(SessionStateCallback *ssc){
sessionControl->UnregisterAudioSessionNotification((IAudioSessionEvents*) ssc);
}
Session::~Session() {
sessionControl->Release();
sessionVolume->Release();
}

View file

@ -0,0 +1,57 @@
#pragma once
#include "msinclude.h"
#include "global.h"
#include "contclasses.h"
class Endpoint;
class SessionStateCallback : public IAudioSessionEvents {
public:
SessionStateCallback(SessionHandler *sh);
ULONG AddRef();
ULONG Release();
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
HRESULT OnSessionCreated(IAudioSessionControl *NewSession);
HRESULT OnChannelVolumeChanged(DWORD ChannelCount, float NewChannelVolumeArray[], DWORD ChangedChannel, LPCGUID EventContext);
HRESULT OnDisplayNameChanged(LPCWSTR NewDisplayName, LPCGUID EventContext);
HRESULT OnGroupingParamChanged( LPCGUID NewGroupingParam, LPCGUID EventContext);
HRESULT OnIconPathChanged(LPCWSTR NewIconPath, LPCGUID EventContext);
HRESULT OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason);
HRESULT OnSimpleVolumeChanged(float NewVolume, BOOL NewMute, LPCGUID EventContext);
HRESULT OnStateChanged(AudioSessionState NewState);
private:
ULONG ref = 1;
SessionHandler *sh;
};
class Session {
public:
Session(Endpoint* ep, IAudioSessionControl2* sessionControl, size_t idx);
Session(Endpoint* ep, IAudioSessionControl2* sessionControl) : Session(ep, sessionControl, SIZE_MAX) {};
void setVolume(NGuid guid, int channel, float volume);
float getVolume(int channel);
void setMute(NGuid guid, bool muted);
bool getMute();
SessionState getState();
void setState(SessionState state);
void setIndex(size_t idx);
std::wstring getName();
void setStateCallback(SessionStateCallback *ssc);
void removeStateCallback(SessionStateCallback *ssc);
~Session();
//uint32_t getChannelCount();
private:
std::wstring fetchProcessName(DWORD pid);
std::wstring sessionName;
SessionState sessionState;
Endpoint* ep;
IAudioSessionControl2* sessionControl = nullptr;
ISimpleAudioVolume* sessionVolume = nullptr;
size_t idx;
};

192
src/back/ipolicyconfig.h Normal file
View file

@ -0,0 +1,192 @@
// ----------------------------------------------------------------------------
// PolicyConfig.h
// Undocumented COM-interface IPolicyConfig.
// Use for set default audio render endpoint
// @author EreTIk
// ----------------------------------------------------------------------------
#pragma once
interface DECLSPEC_UUID("CA286FC3-91FD-42C3-8E9B-CAAFA66242E3")
IPolicyConfig10;
interface DECLSPEC_UUID("00000000-0000-0000-C000-000000000046")
IPolicyConfig10_1;
interface DECLSPEC_UUID("F8679F50-850A-41CF-9C72-430F290290C8")
IPolicyConfig7;
/* interface DECLSPEC_UUID("568B9108-44BF-40B4-9006-86AFE5B5A620") */
/* IPolicyConfigVista; */
interface DECLSPEC_UUID("f8679f50-850a-41cf-9c72-430f290290c8")
IPolicyConfig;
class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9")
CPolicyConfigClient;
// ----------------------------------------------------------------------------
// class CPolicyConfigClient
// {870af99c-171d-4f9e-af0d-e63df40c2bc9}
//
// interface IPolicyConfig
// {f8679f50-850a-41cf-9c72-430f290290c8}
//
// Query interface:
// CComPtr<IPolicyConfig> PolicyConfig;
// PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigClient));
//
// @compatible: Windows 7 and Later
// ----------------------------------------------------------------------------
interface IPolicyConfig : public IUnknown
{
public:
virtual HRESULT GetMixFormat(
PCWSTR,
WAVEFORMATEX **
);
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
PCWSTR,
INT,
WAVEFORMATEX **
);
virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
PCWSTR
);
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
PCWSTR,
WAVEFORMATEX *,
WAVEFORMATEX *
);
virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
PCWSTR,
INT,
PINT64,
PINT64
);
virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
PCWSTR,
PINT64
);
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
PCWSTR,
struct DeviceShareMode *
);
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
PCWSTR,
struct DeviceShareMode *
);
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
PCWSTR,
const PROPERTYKEY &,
PROPVARIANT *
);
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
PCWSTR,
const PROPERTYKEY &,
PROPVARIANT *
);
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
PCWSTR wszDeviceId,
ERole eRole
);
virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
PCWSTR,
INT
);
};
/* interface DECLSPEC_UUID("568b9108-44bf-40b4-9006-86afe5b5a620") */
/* IPolicyConfigVista; */
/* class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862") */
/* CPolicyConfigVistaClient; */
/* // ---------------------------------------------------------------------------- */
/* // class CPolicyConfigVistaClient */
/* // {294935CE-F637-4E7C-A41B-AB255460B862} */
/* // */
/* // interface IPolicyConfigVista */
/* // {568b9108-44bf-40b4-9006-86afe5b5a620} */
/* // */
/* // Query interface: */
/* // CComPtr<IPolicyConfigVista> PolicyConfig; */
/* // PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigVistaClient)); */
/* // */
/* // @compatible: Windows Vista and Later */
/* // ---------------------------------------------------------------------------- */
/* interface IPolicyConfigVista : public IUnknown */
/* { */
/* public: */
/* virtual HRESULT GetMixFormat( */
/* PCWSTR, */
/* WAVEFORMATEX ** */
/* ); // not available on Windows 7, use method from IPolicyConfig */
/* virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat( */
/* PCWSTR, */
/* INT, */
/* WAVEFORMATEX ** */
/* ); */
/* virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat( */
/* PCWSTR, */
/* WAVEFORMATEX *, */
/* WAVEFORMATEX * */
/* ); */
/* virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod( */
/* PCWSTR, */
/* INT, */
/* PINT64, */
/* PINT64 */
/* ); // not available on Windows 7, use method from IPolicyConfig */
/* virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod( */
/* PCWSTR, */
/* PINT64 */
/* ); // not available on Windows 7, use method from IPolicyConfig */
/* virtual HRESULT STDMETHODCALLTYPE GetShareMode( */
/* PCWSTR, */
/* struct DeviceShareMode * */
/* ); // not available on Windows 7, use method from IPolicyConfig */
/* virtual HRESULT STDMETHODCALLTYPE SetShareMode( */
/* PCWSTR, */
/* struct DeviceShareMode * */
/* ); // not available on Windows 7, use method from IPolicyConfig */
/* virtual HRESULT STDMETHODCALLTYPE GetPropertyValue( */
/* PCWSTR, */
/* const PROPERTYKEY &, */
/* PROPVARIANT * */
/* ); */
/* virtual HRESULT STDMETHODCALLTYPE SetPropertyValue( */
/* PCWSTR, */
/* const PROPERTYKEY &, */
/* PROPVARIANT * */
/* ); */
/* virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint( */
/* __in PCWSTR wszDeviceId, */
/* __in ERole eRole */
/* ); */
/* virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility( */
/* PCWSTR, */
/* INT */
/* ); // not available on Windows 7, use method from IPolicyConfig */
/* }; */

26
src/back/msinclude.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#define _WIN32_WINNT 0x0A00
#include <sdkddkver.h>
//done by qt by def #define UNICODE
#include <Windows.h>
#include <processthreadsapi.h>
#include <mmdeviceapi.h>
#include <combaseapi.h>
#include <initguid.h>
#include <Propidl.h>
#include <functiondiscoverykeys_devpkey.h>
//#include <debugapi.h>
#include <endpointvolume.h>
#include <audiopolicy.h>
#include <audioclient.h>
//#include <comdef.h>
//#include <comip.h>
#include <Winerror.h>
#include <stringapiset.h>
#include "ipolicyconfig.h"
#include <Mmreg.h>
#include <tlhelp32.h>

View file

@ -1,36 +1,337 @@
#include "backlasses.h"
#include "contclasses.h"
//TODO: pragma once
Overseer OverseerHandler::os;
EndpointHandler::EndpointHandler(uint64_t idx, Flows flow) {
//std::vector<Endpoint*> endpoints = osh->getPlaybackEndpoints().at(idx);
this->idx = idx;
this->flow = flow;
this->ep = (flow == Flows::FLOW_PLAYBACK ? osh->getPlaybackEndpoints().at(idx) : osh->getCaptureEndpoints().at(idx));
EndpointHandler::EndpointHandler(Endpoint *ept, QObject *parent) : QObject(parent) {
this->ept = ept;
eptName = QString::fromStdWString(ept->getName());
epc = new EndpointVolumeCallback(ep);
ensc = new EndpointNewSessionCallback(this);
this->callbackInfo.caller = osh->getGuid();
ep->registerNewSessionNotification(ensc);
//epName = ep->getName();
this->setBackEndpointVolumeCallbackInfoContent(this->getState());
osh->pushBackEndpointHandler(this, flow);
if (this->flow == Flows::FLOW_PLAYBACK) {
for (int i = 0; i < this->getSessionCount(); i++) {
SessionHandler* sessionHandler = new SessionHandler(this, this->getSessions().at(i),i);
sessionHandlers.push_back(sessionHandler);
}
}
}
void EndpointHandler::setValue(int value){
ept->setVolume((float)value / 100);
void OverseerHandler::pushBackEndpointHandler(EndpointHandler* eph, Flows flow) {
if (eph == nullptr) return;
if (flow == Flows::FLOW_PLAYBACK)
this->playbackEndpointHandlers.push_back(eph);
else
this->captureEndpointHandlers.push_back(eph);
return;
}
QString EndpointHandler::getName(){
return eptName;
void EndpointHandler::setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx){
ephfv.visibility = state;
ephfv.frontIdx = frontIdx;
}
float EndpointHandler::getVolume(){
return ept->getVolume();
uint64_t EndpointHandler::getFrontVisibilityIndex(){
return ephfv.frontIdx;
}
Overseer OverseerHandler::getOverseer(){
return os;
EndpointState EndpointHandler::getFrontVisibilityState(){
return ephfv.visibility;
}
OverseerHandler::OverseerHandler(QObject *parent) : QObject(parent) {
Flows EndpointHandler::getFlow(){
return ep->getFlow();
}
std::vector<EndpointHandler*>* OverseerHandler::getEndpointHandlers(){
return endpointHandlers;
/* these two, currently unused. If I use them, I should feel bad.
* Endpoint* EndpointHandler::getEndpoint() {
* return this->ep;
* }
*
* EndpointVolumeCallback* EndpointHandler::getEndpointVolumeCallback() {
* return this->epc;
* }
*/
BackEndpointVolumeCallbackInfo* EndpointHandler::getCallbackInfo(){
return &this->callbackInfo;
}
void OverseerHandler::setEndpointHandlers(std::vector<EndpointHandler*> *ephs){
this->endpointHandlers = ephs;
uint32_t EndpointHandler::getChannelCount(){
return ep->getChannelCount();
}
void EndpointHandler::setIndex(uint64_t idx){
this->idx = idx;
}
uint64_t EndpointHandler::getIndex(){
return idx;
}
/*
* -1 for master volume
*/
void EndpointHandler::setVolume(NGuid guid, int channel, int value){
if (channel == AudioChannel::CHANNEL_MAIN)
ep->setVolume(guid, channel, (float)value / 100);
else ep->setVolume(guid, channel, (float)value / 100);
}
void EndpointHandler::setMute(NGuid guid, bool muted){
ep->setMute(guid, muted);
}
std::wstring EndpointHandler::getName(){
return ep->getName();
}
std::wstring EndpointHandler::getId(){
return ep->getId();
}
float EndpointHandler::getVolume(int channel){
return ep->getVolume(channel);
}
bool EndpointHandler::getMute(){
return ep->getMute();
}
size_t EndpointHandler::getState(){
return ep->getState();
}
void EndpointHandler::setBackEndpointVolumeCallbackInfoContent(uint8_t state) {
if(state == EndpointState::ENDPOINT_ACTIVE) {
callbackInfo.muted = this->getMute();
callbackInfo.mainVolume = this->getVolume(AudioChannel::CHANNEL_MAIN);
callbackInfo.channels = this->getChannelCount();
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);
}
}
}
void EndpointHandler::setState(uint8_t state){
ep->setState(state);
this->setBackEndpointVolumeCallbackInfoContent(state);
}
void EndpointHandler::setState(uint8_t state, uint64_t index){
ep->setState(state);
this->setFrontVisibilityInfo((EndpointState)state, index);
this->setBackEndpointVolumeCallbackInfoContent(state);
}
uint8_t EndpointHandler::getRoles(){
return ep->getRoles();
}
void EndpointHandler::setRoles(Roles newRole){
ep->setRoles(newRole);
}
void EndpointHandler::assignRoles(Roles newRole){
ep->assignRoles(newRole);
}
void EndpointHandler::removeRoles(Roles newRole){
ep->removeRoles(newRole);
}
void EndpointHandler::setAddSessionWidgetFunction(std::function<void(SessionHandler*)> addSessionWidget) {
this->addSessionWidget = addSessionWidget;
}
void EndpointHandler::setRemoveSessionWidgetFunction(std::function<void(SessionHandler*)> removeSessionWidget) {
this->removeSessionWidget = removeSessionWidget;
}
/* sessions */
size_t EndpointHandler::getSessionCount() {
return ep->getSessionCount();
}
std::vector<Session*> EndpointHandler::getSessions(){
return ep->getSessions();
}
std::vector<SessionHandler*> EndpointHandler::getSessionHandlers(){
return this->sessionHandlers;
}
Endpoint* EndpointHandler::getEndpoint() {
return this->ep;
}
void EndpointHandler::addSessionSendFront(Session* session) {
ep->addSession(session);
SessionHandler* sessionHandler = new SessionHandler(this, session, (getSessionCount() - 1));
sessionHandlers.push_back(sessionHandler);
this->addSessionWidget(sessionHandler);
}
void EndpointHandler::sendSessionToFront(SessionHandler* sh) {
this->addSessionWidget(sh);
}
void EndpointHandler::removeSessionFromFront(SessionHandler* sh) {
this->removeSessionWidget(sh);
}
EndpointHandler::~EndpointHandler() {
ep->removeVolumeCallback(epc);
ep->unregisterNewSessionNotification(ensc);
epc->Release();
delete ep;
}
OverseerHandler::OverseerHandler() {
this->os = new Overseer();
}
std::vector<Endpoint*> OverseerHandler::getPlaybackEndpoints() {
return this->os->getPlaybackEndpoints();
}
std::vector<Endpoint*> OverseerHandler::getCaptureEndpoints() {
return this->os->getCaptureEndpoints();
}
std::vector<EndpointHandler*> OverseerHandler::getPlaybackEndpointHandlers(){
return playbackEndpointHandlers;
}
std::vector<EndpointHandler*> OverseerHandler::getCaptureEndpointHandlers(){
return captureEndpointHandlers;
}
uint64_t OverseerHandler::getPlaybackEndpointsCount(){
return this->os->getPlaybackEndpoints().size();
}
uint64_t OverseerHandler::getCaptureEndpointsCount(){
return this->os->getCaptureEndpoints().size();
}
void OverseerHandler::reloadEndpointHandlers(){
//todo: add capture
//std::vector<EndpointHandler*>* ephs = new std::vector<EndpointHandler*>;
log_debugcpp("Playback VSize: " + std::to_string(this->getPlaybackEndpointsCount()));
for(uint64_t i = 0; i < this->getPlaybackEndpointsCount(); i++){
log_debugcpp("Creating Playback handler " + std::to_string(i));
EndpointHandler* ephexx = new EndpointHandler(i, Flows::FLOW_PLAYBACK);
//this->playbackEndpointHandlers.push_back(ephexx);
log_debugcpp("Created Playback handler " + std::to_string(i) + ", adding to vector. " + " VSize: " + std::to_string(this->playbackEndpointHandlers.size()));
}
log_debugcpp("Capture VSize: " +
std::to_string(this->getCaptureEndpointsCount()));
for(uint64_t i = 0; i < this->getCaptureEndpointsCount(); i++){
log_debugcpp("Creating Capture handler " + std::to_string(i));
/*
* if(i < (this->captureEndpointHandlers.size()) &&
* this->captureEndpointHandlers.at(i) != nullptr)
* delete captureEndpointHandlers.at(i);
*/
EndpointHandler* ephoo = new EndpointHandler(i, Flows::FLOW_CAPTURE);
//this->captureEndpointHandlers.push_back(ephoo);
log_debugcpp("Created Capture handler " + std::to_string(i) + ", adding to vector. " + " VSize: " + std::to_string(this->captureEndpointHandlers.size()));
/*
* if (i >= this->captureEndpointHandlers.size())
* captureEndpointHandlers.push_back(eph);
* else captureEndpointHandlers.at(i) = eph;
*/
}
//setEndpointHandlers(ephs);
}
EndpointHandler* OverseerHandler::addEndpoint(std::wstring endpointId, /* out */ Flows *flow = nullptr){
Flows localFlow;
Endpoint* newEp = this->os->addEndpoint(endpointId, &localFlow);
uint64_t ephIdx = (localFlow == Flows::FLOW_PLAYBACK ? this->getPlaybackEndpointsCount() : this->getCaptureEndpointsCount()) - 1;
EndpointHandler* newEph = new EndpointHandler(ephIdx, localFlow);
// std::vector<EndpointHandler*> getPlaybackEndpointHandlers();
//std::vector<EndpointHandler*> getCaptureEndpointHandlers();
if (flow != nullptr) *flow = localFlow;
return newEph;
}
NGuid OverseerHandler::getGuid() {
return this->os->getGuid();
}
void OverseerHandler::setChangeFrontDefaultsFunction(std::function<void(Roles, std::wstring)> changeFrontDefaults){
this->changeFrontDefaults = changeFrontDefaults;
}
void OverseerHandler::changeFrontDefaultsCallback(Roles role, std::wstring endpointId) {
this->changeFrontDefaults(role, endpointId);
}
void OverseerHandler::reviseEndpointShowing(std::wstring endpointId, EndpointState state) {
std::vector<EndpointHandler*> allHandlers;
allHandlers.insert(allHandlers.end(), this->captureEndpointHandlers.begin(), this->captureEndpointHandlers.end());
allHandlers.insert(allHandlers.end(), this->playbackEndpointHandlers.begin(), this->playbackEndpointHandlers.end());
EndpointHandler* eph = nullptr;
for (auto loopEph : allHandlers) {
if (loopEph->getId() == endpointId) {
eph = loopEph;
break;
}
}
//debug
Flows flow;
if (!eph) {
if (state ^ EndpointState::ENDPOINT_ACTIVE) return;
//return;
//flow = Flows::FLOW_CAPTURE;
eph = osh->addEndpoint(endpointId, &flow);
} else
flow = eph->getFlow();
//todo: mic done but disabled. Tab-kun will come...
if (flow == Flows::FLOW_CAPTURE) return;
if(eph && EndpointState::ENDPOINT_ACTIVE & state) {
this->addEndpointWidget(eph);
} else if (eph && eph->getFrontVisibilityState() == EndpointState::ENDPOINT_ACTIVE){
this->removeEndpointWidget(eph->getFrontVisibilityIndex());
}
return;
}
void OverseerHandler::setAddEndpointWidgetFunction(std::function<void(EndpointHandler*)> addEndpointWidget){
this->addEndpointWidget = addEndpointWidget;
}
void OverseerHandler::setRemoveEndpointWidgetFunction(std::function<void(uint64_t)> removeEndpointWidget){
this->removeEndpointWidget = removeEndpointWidget;
}
void OverseerHandler::setEndpointHandlers(std::vector<EndpointHandler*> ephs){
this->playbackEndpointHandlers = ephs;
}

View file

@ -1,49 +1,138 @@
#pragma once
#include <QObject>
#include "global.h"
#include "backlasses.h"
class EndpointHandler : public QObject {
Q_OBJECT
public:
EndpointHandler(Endpoint *ept, QObject *parent = nullptr);
QString getName();
float getVolume();
private:
Endpoint *ept;
QString eptName;
//QSlider *slidy;
public slots:
void setValue(int value);
//signals:
#include "contsessionclasses.h"
//#define invoke_mem_fn(object,ptrToMember) ((object).*(ptrToMember))
//#define pinvoke_mem_fn(object,ptrToMember) ((object)->*(ptrToMember))
class EndpointWidget;
class Endpoint;
class EndpointVolumeCallback;
class Overseer;
class SessionHandler;
class EndpointNewSessionCallback;
struct BackEndpointVolumeCallbackInfo {
NGuid caller;
bool muted;
float mainVolume;
size_t channels;
std::vector<float> channelVolumes;
};
class OverseerHandler : public QObject {
Q_OBJECT
class EndpointHandler {
public:
OverseerHandler(QObject *parent = nullptr);
void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
std::vector<EndpointHandler*>* getEndpointHandlers();
static Overseer getOverseer();
EndpointHandler(uint64_t idx, Flows flow);
void setBackEndpointVolumeCallbackInfoContent(uint8_t state);
//these two, currently unused. If I use them, I should feel bad.
//EndpointVolumeCallback* getEndpointVolumeCallback();
//Endpoint* getEndpoint();
//std::wstring epName;
BackEndpointVolumeCallbackInfo* getCallbackInfo();
uint32_t getChannelCount();
void setIndex(uint64_t idx);
uint64_t getIndex();
void setVolume(int channel, float volume);
std::wstring getName();
std::wstring getId();
void setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx);
uint64_t getFrontVisibilityIndex();
EndpointState getFrontVisibilityState();
Flows getFlow();
float getVolume(int channel);
bool getMute();
size_t getState();
uint8_t getRoles();
void setRoles(Roles newRole);
void assignRoles(Roles newRole);
void removeRoles(Roles newRole);
void setVolume(NGuid guid, int channel, int value);
void setMute(NGuid guid, bool muted);
void setState(uint8_t state);
void setState(uint8_t state, uint64_t idx);
/* sessions */
size_t getSessionCount();
std::vector<SessionHandler*> getSessionHandlers();
void createNewSession();
Endpoint* getEndpoint();
/*Session*/
void addSessionSendFront(Session* session);
void setAddSessionWidgetFunction(std::function<void(SessionHandler*)> addSessionWidget);
void setRemoveSessionWidgetFunction(std::function<void(SessionHandler*)> removeSessionWidget);
void sendSessionToFront(SessionHandler* sh);
void removeSessionFromFront(SessionHandler* sh);
~EndpointHandler();
private:
std::vector<Session*> getSessions();
uint64_t idx;
Endpoint *ep = nullptr;
EndpointVolumeCallback *epc = nullptr;
Flows flow;
BackEndpointVolumeCallbackInfo callbackInfo;
struct EndpointHandlerFrontVisibility {
EndpointState visibility = EndpointState::ENDPOINT_ALL;
uint64_t frontIdx = INT_MAX;
};
EndpointHandlerFrontVisibility ephfv;
EndpointNewSessionCallback* ensc;
std::vector<SessionHandler*> sessionHandlers;
std::function<void(SessionHandler*)> addSessionWidget;
std::function<void(SessionHandler*)> removeSessionWidget;
//QSlider *slidy;
};
class OverseerHandler {
public:
OverseerHandler();
void setChangeFrontDefaultsFunction(std::function<void(Roles, std::wstring)> changeFrontDefaults);
void changeFrontDefaultsCallback(Roles role, std::wstring endpointId);
//void setReviseEndpointShowingFunction(std::function<void(std::wstring, EndpointState)> reviseEndpointShowing);
void reviseEndpointShowing(std::wstring endpointId, EndpointState state);
void setRemoveEndpointWidgetFunction(std::function<void(uint64_t)> removeEndpointWidget);
void setAddEndpointWidgetFunction(std::function<void(EndpointHandler*)> addEndpointWidget);
void setEndpointHandlers(std::vector<EndpointHandler*> ephs);
std::vector<EndpointHandler*> getPlaybackEndpointHandlers();
std::vector<EndpointHandler*> getCaptureEndpointHandlers();
std::vector<Endpoint*> getPlaybackEndpoints();
std::vector<Endpoint*> getCaptureEndpoints();
void pushBackEndpointHandler(EndpointHandler* eph, Flows flow);
uint64_t getPlaybackEndpointsCount();
uint64_t getCaptureEndpointsCount();
void reloadEndpointHandlers();
EndpointHandler* addEndpoint(std::wstring endpointId, Flows *flow);
NGuid getGuid();
/*
* void setSessionVolumeCallback(std::function<void(float)> changeSessionVolume);
* void setSessionVolume(float newValue, );
*/
private:
static Overseer os;
std::vector<EndpointHandler*> *endpointHandlers;
//QSlider *slidy;
//public slots:
//void setValue(int value);
Overseer *os;
std::vector<EndpointHandler*> playbackEndpointHandlers;
std::vector<EndpointHandler*> captureEndpointHandlers;
std::function<void(Roles, std::wstring /* endpointid */)> changeFrontDefaults;
std::function<void(uint64_t /* epw id */)> removeEndpointWidget;
std::function<void(EndpointHandler*)> addEndpointWidget;
/* Session's */
std::function<void(float)> changeSessionVolume;
//std::function<void(uint64_t /* device */, uint32_t /* channel */, float /* value */)> updateFrontVolumeCallback;
//std::function<void(uint64_t /* device */, bool /* mute */)> updateFrontMuteCallback;
};

View file

@ -0,0 +1,79 @@
#include "contsessionclasses.h"
#include "backsessionclasses.h"
SessionHandler::SessionHandler(EndpointHandler* eph, Session* session, size_t idx) {
this->eph = eph;
this->idx = idx;
this->session = session;
this->svi.mainVolume = session->getVolume(AudioChannel::CHANNEL_MAIN);
this->svi.muted = session->getMute();
this->svi.caller = osh->getGuid();
ssc = new SessionStateCallback(this);
this->session->setStateCallback(ssc);
}
void SessionHandler::setVolume(NGuid guid, int channel, int value){
if (channel == AudioChannel::CHANNEL_MAIN)
session->setVolume(guid, channel, (float)value / 100);
else session->setVolume(guid, channel, (float)value / 100);
}
float SessionHandler::getVolume(int channel){
return session->getVolume(channel);
}
void SessionHandler::setMute(NGuid guid, bool muted){
session->setMute(guid, muted);
}
std::wstring SessionHandler::getName(){
return session->getName();
}
bool SessionHandler::getMute(){
return session->getMute();
}
void SessionHandler::setFrontIndex(uint64_t frontIdx) {
this->frontIdx = frontIdx;
}
uint64_t SessionHandler::getFrontIndex() {
return frontIdx;
}
SessionVolumeInfo* SessionHandler::getVolumeInfo() {
return &svi;
}
SessionState SessionHandler::getState() {
return session->getState();
}
void SessionHandler::setState(SessionState state) {
session->setState(state);
}
void SessionHandler::reviseSessionShowing(SessionState state) {
SessionState currentState = this->getState();
switch (currentState) {
case SessionState::ACTIVE:
case SessionState::INACTIVE:
if (state == SessionState::EXPIRED) {
eph->removeSessionFromFront(this);
}
break;
case SessionState::EXPIRED:
if (state == SessionState::ACTIVE || INACTIVE) {
eph->sendSessionToFront(this);
}
break;
case SessionState::DISCONNECTED:
if (frontIdx != INT_MAX)
eph->removeSessionFromFront(this);
break;
}
}

View file

@ -0,0 +1,42 @@
#pragma once
#include "global.h"
//#include "contclasses.h"
class EndpointHandler;
class Session;
class SessionStateCallback;
struct SessionVolumeInfo {
//SessionVolumeInfo(bool muted, float mainVolume);
bool muted;
float mainVolume;
NGuid caller;
//size_t channels;
//std::vector<float> channelVolumes;
};
class SessionHandler {
public:
SessionHandler(EndpointHandler* eph, Session* session, size_t idx);
void setVolume(NGuid guid, int channel, int value);
float getVolume(int channel);
void setMute(NGuid guid, bool muted);
bool getMute();
void setFrontIndex(uint64_t frontIdx);
SessionState getState();
void setState(SessionState state);
uint64_t getFrontIndex();
std::wstring getName();
void reviseSessionShowing(SessionState state);
SessionVolumeInfo* getVolumeInfo();
private:
SessionVolumeInfo svi;
EndpointHandler* eph;
Session* session;
SessionStateCallback* ssc;
size_t idx;
uint64_t frontIdx = INT_MAX;
};

47
src/debug.h Normal file
View file

@ -0,0 +1,47 @@
#pragma once
#if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG)
template<size_t Y, typename T>
std::bitset<Y> varToBitset(T info) {
std::bitset<Y> content(info);
return content;
}
#ifndef _WIN32
#define log_debugcpp(str) do { \
std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
} while (0)
#define log_wdebugcpp(str) do { \
std::wcout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
} while (0)
#else
#include <Windows.h>
#include <debugapi.h>
#define WIDE2(x) L##x
#define WIDE1(x) WIDE2(x)
#define WFILE WIDE1(__FILE__)
#define log_debugcpp(str) { \
OutputDebugStringA(std::string("[DEBUG] (" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "): " + std::string(str) + "\n").c_str()); \
} while (0)
#define log_wdebugcpp(str) do { \
OutputDebugStringW(std::wstring(L"[DEBUG] (" + std::wstring(WFILE) + L":" + std::to_wstring(__LINE__) + L"): " + std::wstring(str) +L"\n").c_str()); \
} while (0)
#endif
#define print_as_binary(len, type, info) varToBitset<len, type>(info)
#else
#define log_debugcpp(str)
#define log_wdebugcpp(str)
#define print_as_binary(len, type, info)
#endif
/* Here as a quick reference, in case smthn similar is needed again */
/* typedef void (EndpointWidget::*epwMuteFunc)(bool muted); */
/* typedef void (EndpointWidget::*epwMainVolumeFunc)(float newValue); */
/* typedef void (EndpointWidget::*epwChannelVolumeFunc)(uint32_t channel, float newValue); */
/* typedef void (EndpointWidget::*epwToggleFrontFunc)(bool active); */

View file

@ -1,4 +1,82 @@
#pragma once
#define log_debugcpp(str) do { \
std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
} while (0)
#include <vector>
#include <iostream>
#include <string>
#include <bitset>
#include <climits>
#include <locale>
#include "debug.h"
//TODO: Use tr();? QTranslator
#define STRING_MUTE "Mute"
#define STRING_UNMUTE "Unmute"
#define STRING_QUIT "Quit"
#define STRING_TITLE "Mixer Fachero"
#define STRING_ROLE_CONSOLE "Console"
#define STRING_ROLE_MULTIMEDIA "Multimedia"
#define STRING_ROLE_COMMUNICATIONS "Communications"
#define STRING_ROLE_ALL "All"
#define STRING_SYSTEM_SOUNDS "System Sounds"
#define LSTRING_SYSTEM_SOUNDS L"System Sounds"
//INIT BACK
enum AudioChannel {
CHANNEL_LEFT = (1 << 0),
CHANNEL_RIGHT = (1 << 1),
CHANNEL_MAIN = ~0,
};
enum EndpointState {
ENDPOINT_ACTIVE = (1 << 0),
ENDPOINT_DISABLED = (1 << 1),
ENDPOINT_NOTPRESENT = (1 << 2),
ENDPOINT_UNPLUGGED = (1 << 3),
ENDPOINT_ALL = 0x0F
};
enum SessionState {
ACTIVE = (1 << 0),
INACTIVE = (1 << 1),
EXPIRED = (1 << 2),
DISCONNECTED = (1 << 3),
ALL = 0x0F
};
enum Flows {
FLOW_PLAYBACK = (1 << 0),
FLOW_CAPTURE = (1 << 1),
FLOW_BOTH = (1 << 2),
};
enum Roles {
ROLE_CONSOLE = (1 << 0),
ROLE_MULTIMEDIA = (1 << 1),
ROLE_COMMUNICATIONS = (1 << 2),
ROLE_ALL = 0x07,
};
struct NGuid {
//todo: still leaking?
uint32_t data1;
uint16_t data2;
uint16_t data3;
unsigned char data4[8];
/* void freeData4(){ */
/* int i = 0; */
/* do{ */
/* if(this->data4 + i != nullptr) free(data4 + i); */
/* i++; */
/* }while (i < 8); */
/* } */
};
class OverseerHandler;
extern OverseerHandler *osh;

View file

@ -1,53 +1,584 @@
#include "qtclasses.h"
MainWindow::MainWindow(std::vector<EndpointHandler*> *ephs, QWidget *parent) : QMainWindow(parent) {
// setWindowState(Qt::WindowFullScreen);
// setCentralWidget(centralWidget);
widget = new QWidget();
layout = new QGridLayout();
widget->setLayout(layout);
setCentralWidget(widget);
//layout->addWidget(pintas, 0, 0);
setWindowTitle("slidea resbala nu c");
setEndpointHandlers(ephs);
for (unsigned int i = 0; i < this->ephs->size(); i++){
QLabel *pintas = new QLabel(ephs->at(i)->getName());
QSlider *teSlider = new QSlider(Qt::Horizontal);
teSlider->setFocusPolicy(Qt::StrongFocus);
teSlider->setTickPosition(QSlider::TicksBothSides);
teSlider->setTickInterval(5);
teSlider->setSingleStep(1);
teSlider->setRange(0,100);
float volume = ephs->at(i)->getVolume() * 100;
teSlider->setValue((int)volume);
log_debugcpp("ENDPOINT SET WITH VOLUME " << volume);
layout->addWidget(pintas, i, 0);
layout->addWidget(teSlider, i, 1);
connect(teSlider, &QSlider::valueChanged, ephs->at(i), &EndpointHandler::setValue);
}
template <typename T>
CustomWidgetEvent<T>::CustomWidgetEvent(QEvent::Type type, T payload) : QEvent(type){
this->payload = payload;
}
void MainWindow::setEndpointHandlers(std::vector<EndpointHandler*> *ephs){
this->ephs = ephs;
void ExtendedCheckBox::customEvent(QEvent* ev) {
QEvent::Type tipo = ev->type();
if (ev->type() == (QEvent::Type)CustomQEvent::EndpointDefaultChange) {
//todo: still prone to bugs; whack-a-mole to come
ev->setAccepted(true);
this->blockSignals(true);
if (this->isEnabled()) {
this->setCheckState(Qt::Checked);
this->setDisabled(true);
} else {
this->setDisabled(false);
this->setCheckState(Qt::Unchecked);
}
this->blockSignals(false);
return;
}
// Make sure the rest of events are handled
QCheckBox::customEvent(ev);
}
SessionWidget::SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent) : QWidget(parent){
//todo: based on qgridlayout, name+mute should be its own widget, same with channels
this->idx = idx;
this->sh = sh;
layout = new QGridLayout(this);
//this->setLayout(
muteButton = new QCheckBox(this);
mainLabel = new QLabel(QString::fromStdWString(sh->getName()), this);
mainSlider = new QSlider(Qt::Horizontal, this);
mainSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
mainSlider->setFocusPolicy(Qt::StrongFocus);
mainSlider->setTickPosition(QSlider::TicksBothSides);
mainSlider->setTickInterval(5);
mainSlider->setSingleStep(1);
mainSlider->setRange(0,100);
muteButton->setCheckState((sh->getMute() == false ? Qt::Unchecked : Qt::Checked));
muteButton->setText(sh->getMute() ? STRING_UNMUTE : STRING_MUTE);
float volume = sh->getVolume(AudioChannel::CHANNEL_MAIN) * 100;
mainSlider->setValue((int)volume);
log_debugcpp("SESSION SET WITH VOLUME " + std::to_string(volume));
//tip: would need to be new widget with layout in it
//mainMuteLayout = new QGridLayout();
layout->addWidget(mainLabel, 0, 0, Qt::AlignLeft | Qt::AlignBottom);
layout->addWidget(muteButton, 0, 1, Qt::AlignLeft | Qt::AlignBottom);
layout->addWidget(mainSlider, 0, 2, 1, 2);
//TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option?
connect<void(QSlider::*)(int), void(SessionWidget::*)(int)>(mainSlider, &QSlider::valueChanged, this,&SessionWidget::updateMainVolume);
connect<void(QCheckBox::*)(int), void(SessionWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&SessionWidget::updateMute));
/*
* Session Volume Polling
*/
volumePoller = new QTimer();
connect(volumePoller, &QTimer::timeout, [this, sh](){
//if (memcmp(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid)) == 0) return; CHECK IF THIS PROGRAM GENERATED THE FUNSIES IS NO LONGER IN USE FOR NOW.
//todo: global + constexpr + ratio
const float roundingFactor = 0.005;
mainSlider->blockSignals(true);
muteButton->blockSignals(true);
mainSlider->setValue((int)((sh->getVolumeInfo()->mainVolume + roundingFactor) * 100));
muteButton->setCheckState((sh->getVolumeInfo()->muted == false ? Qt::Unchecked : Qt::Checked));
muteButton->setText(sh->getVolumeInfo()->muted ? STRING_UNMUTE : STRING_MUTE);
//memcpy(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid));
//TODO: el default = objcopy frees?
//Todo: like fr pregunta
sh->getVolumeInfo()->caller = osh->getGuid();
mainSlider->blockSignals(false);
muteButton->blockSignals(false);
});
volumePoller->start(10);
}
void SessionWidget::updateMute(int checked){
bool muted = (checked == 2 ? true : false);
this->sh->setMute(osh->getGuid(), muted);
this->muteButton->setText(this->sh->getMute() ? STRING_UNMUTE : STRING_MUTE);
}
void SessionWidget::updateMainVolume(int newValue){
this->sh->setVolume(osh->getGuid(), AudioChannel::CHANNEL_MAIN, newValue);
}
SessionWidget::~SessionWidget() {
volumePoller->stop();
delete volumePoller;
}
EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *parent) : QWidget(parent){
//todo: based on qgridlayout, name+mute should be its own widget, same with channels
row = 0;
this->idx = idx;
this->eph = eph;
//todo: sussy
this->eph->setState(EndpointState::ENDPOINT_ACTIVE, idx);
layout = new QGridLayout(this);
//this->setLayout(layout);
log_debugcpp("epw main layout parent: " + std::to_string((intptr_t)(layout->parent())));
if (parent == nullptr) { log_debugcpp("ayooooo?"); }
defaultRolesCheckBoxes = {
{Roles::ROLE_ALL, new ExtendedCheckBox(this)},
{Roles::ROLE_CONSOLE, new ExtendedCheckBox(this)},
{Roles::ROLE_MULTIMEDIA, new ExtendedCheckBox(this)},
{Roles::ROLE_COMMUNICATIONS, new ExtendedCheckBox(this)}
};
/*
* Mute, main slider and label setup
*/
muteButton = new QCheckBox(this);
mainLabel = new QLabel(QString::fromStdWString(eph->getName()), this);
mainSlider = new QSlider(Qt::Horizontal, this);
if (this->eph->getState() != EndpointState::ENDPOINT_ACTIVE) {
layout->addWidget(mainLabel, row, 0);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 1, 0);
return;
}
//muteButton->setStyleSheet("background-color: #A3C1DA; color: red");
mainSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
mainSlider->setFocusPolicy(Qt::StrongFocus);
mainSlider->setTickPosition(QSlider::TicksBothSides);
mainSlider->setTickInterval(5);
mainSlider->setSingleStep(1);
mainSlider->setRange(0,100);
muteButton->setCheckState((eph->getMute() == false ? Qt::Unchecked : Qt::Checked));
muteButton->setText(eph->getMute() ? STRING_UNMUTE : STRING_MUTE);
float volume = eph->getVolume(AudioChannel::CHANNEL_MAIN) * 100;
mainSlider->setValue((int)volume);
log_debugcpp("ENDPOINT SET WITH VOLUME " + std::to_string(volume));
//tip: would need to be new widget with layout in it
//mainMuteLayout = new QGridLayout();
layout->addWidget(mainLabel, row, 0, Qt::AlignLeft | Qt::AlignBottom);
layout->addWidget(muteButton, row, 1, Qt::AlignLeft | Qt::AlignBottom);
layout->addWidget(mainSlider, row, 2, 1, 2);
row++;
//TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option?
connect<void(QSlider::*)(int), void(EndpointWidget::*)(int)>(mainSlider, &QSlider::valueChanged, this,&EndpointWidget::updateMainVolume);
connect<void(QCheckBox::*)(int), void(EndpointWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&EndpointWidget::updateMute));
/*
* Channel sliders setup
*/
uint32_t epChannelCount = eph->getChannelCount();
for(uint32_t i = 0; i < epChannelCount && epChannelCount > 1; i++){
QSlider* tmp = new QSlider(Qt::Horizontal);
QLabel* tmpLb = new QLabel("");
tmp->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
tmp->setTickInterval(5);
tmp->setSingleStep(1);
tmp->setRange(0,100);
volume = eph->getVolume(i) * 100;
tmp->setValue((int) volume);
tmpLb->setText(QString::number(volume));
this->channelSliders.push_back(tmp);
this->channelLabels.push_back(tmpLb);
layout->addWidget(tmp, row + 1, i);
layout->addWidget(tmpLb, row + 2, i);
//TODO: check if there's a need to prevent deadlocks; probably this will eventually turn into its own func
//this causes channel bar desync when back -> front. blocksignals below fix it. huh.
connect(tmp, &QSlider::valueChanged, [this, i](int newValue){
this->eph->setVolume(osh->getGuid(), i, newValue);
this->channelLabels.at(i)->setText(QString::number(newValue));
});
}
row += 3;
/*
* Role ExtendedCheckBoxes setup
*/
uint8_t assignedRoles = eph->getRoles();
defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setCheckState(assignedRoles == Roles::ROLE_ALL ? Qt::Checked : Qt::Unchecked);
//todo duditas de &
defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setDisabled(assignedRoles == Roles::ROLE_ALL ? true : false);
defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setText(STRING_ROLE_ALL);
defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setCheckState(assignedRoles & Roles::ROLE_CONSOLE ? Qt::Checked : Qt::Unchecked);
defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setDisabled(assignedRoles & Roles::ROLE_CONSOLE ? true : false);
defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setText(STRING_ROLE_CONSOLE);
defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setCheckState(assignedRoles & Roles::ROLE_MULTIMEDIA ? Qt::Checked : Qt::Unchecked);
defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setDisabled(assignedRoles & Roles::ROLE_MULTIMEDIA ? true : false);
defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setText(STRING_ROLE_MULTIMEDIA);
defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setCheckState(assignedRoles & Roles::ROLE_COMMUNICATIONS ? Qt::Checked : Qt::Unchecked);
defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setDisabled(assignedRoles & Roles::ROLE_COMMUNICATIONS ? true : false);
defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setText(STRING_ROLE_COMMUNICATIONS);
connect(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_ALL);
});
connect(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_CONSOLE);
});
connect(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_MULTIMEDIA);
});
connect(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_COMMUNICATIONS);
});
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), row, 0);
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), row, 1);
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), row, 2);
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), row, 3);
row++;
/* ----------------------------------------------------------- */
/*
* EndpointVolume Polling time
*/
timer = new QTimer();
connect(timer, &QTimer::timeout, [this, eph](){
//if (memcmp(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid)) == 0) return; CHECK IF THIS PROGRAM GENERATED THE FUNSIES IS NO LONGER IN USE FOR NOW.
//todo: global + constexpr + ratio
const float roundingFactor = 0.005;
mainSlider->blockSignals(true);
muteButton->blockSignals(true);
mainSlider->setValue((int)((eph->getCallbackInfo()->mainVolume + roundingFactor) * 100));
muteButton->setCheckState((eph->getCallbackInfo()->muted == false ? Qt::Unchecked : Qt::Checked));
muteButton->setText(eph->getCallbackInfo()->muted ? STRING_UNMUTE : STRING_MUTE);
for(uint32_t i = 0; i < eph->getCallbackInfo()->channels && eph->getChannelCount() > 1; i++){
this->channelSliders.at(i)->blockSignals(true);
this->channelSliders.at(i)->setValue((int)((eph->getCallbackInfo()->channelVolumes[i] + roundingFactor) * 100));
this->channelLabels.at(i)->setText(QString::number((int)((eph->getCallbackInfo()->channelVolumes[i] + roundingFactor) * 100)));
this->channelSliders.at(i)->blockSignals(false);
}
//memcpy(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid));
//TODO: el default = objcopy frees?
//Todo: like fr pregunta
eph->getCallbackInfo()->caller = osh->getGuid();
mainSlider->blockSignals(false);
muteButton->blockSignals(false);
});
timer->start(10);
/* First SessionWidget batch */
for (size_t i = 0; i < eph->getSessionCount(); i++) {
SessionWidget* sessionWidget = new SessionWidget(i, eph->getSessionHandlers().at(i), this);
layout->addWidget(sessionWidget, row, 4);
row++;
sessionWidgets.push_back(sessionWidget);
eph->getSessionHandlers().at(i)->setFrontIndex(i);
}
/* Add/Remove SessionWidget callback */
eph->setAddSessionWidgetFunction([this](SessionHandler* sessionHandler) {
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<SessionHandler*>((QEvent::Type)CustomQEvent::SessionWidgetCreated, sessionHandler));
});
eph->setRemoveSessionWidgetFunction([this](SessionHandler* sessionHandler) {
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<SessionHandler*>((QEvent::Type)CustomQEvent::SessionWidgetObsolete, sessionHandler));
});
//todo parent?
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 1, 0);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 4, 0);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 6, 0);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 6, 1);
log_debugcpp("ENDPOINT_WIDGETED");
}
void EndpointWidget::addSessionWidget(CustomWidgetEvent<SessionHandler*>* ev){
uint64_t index = this->sessionWidgets.size();
SessionWidget* sw = new SessionWidget(index, ev->payload, this);
ev->payload->setFrontIndex(index);
this->layout->addWidget(sw, row, 4);
row++;
sessionWidgets.push_back(sw);
return;
}
void EndpointWidget::removeSessionWidget(CustomWidgetEvent<SessionHandler*>* ev){
uint64_t i = ev->payload->getFrontIndex();
this->sessionWidgets.at(i)->setParent(nullptr);
this->layout->removeWidget(sessionWidgets.at(i));
delete sessionWidgets.at(i);
sessionWidgets.at(i) = nullptr;
ev->payload->setFrontIndex(INT_MAX);
//this->sessionWidgetsUpdateTimer->start();
return;
}
void EndpointWidget::customEvent(QEvent* ev) {
if (ev->type() == (QEvent::Type)CustomQEvent::SessionWidgetCreated) {
ev->setAccepted(true);
this->addSessionWidget((CustomWidgetEvent<SessionHandler*>*) ev);
} else if (ev->type() == (QEvent::Type)CustomQEvent::SessionWidgetObsolete) {
ev->setAccepted(true);
this->removeSessionWidget((CustomWidgetEvent<SessionHandler*>*) ev);
}
QWidget::customEvent(ev);
}
EndpointWidget::~EndpointWidget() {
timer->stop();
delete timer;
this->eph->setFrontVisibilityInfo(EndpointState::ENDPOINT_ALL, INT_MAX);
}
void MainWindow::customEvent(QEvent* ev) {
if (ev->type() == CustomQEvent::EndpointWidgetObsolete) {
ev->setAccepted(true);
this->removeEndpointWidget((CustomWidgetEvent<uint64_t>*)ev);
} else if (ev->type() == (QEvent::Type)CustomQEvent::EndpointWidgetCreated) {
ev->setAccepted(true);
this->addEndpointWidget((CustomWidgetEvent<EndpointHandler*>*)ev);
}
QMainWindow::customEvent(ev);
}
void MainWindow::removeEndpointWidget(CustomWidgetEvent<uint64_t>* ev){
uint64_t i = ev->payload;
this->ews.at(i)->setParent(nullptr);
this->layout->removeWidget(ews.at(i));
//uint64_t saisu = ews.size();
//delete ews.at(index);
delete ews.at(i);
ews.at(i) = nullptr;
this->ewsUpdateTimer->start();
return;
}
void MainWindow::addEndpointWidget(CustomWidgetEvent<EndpointHandler*>* ev){
EndpointWidget* epw = new EndpointWidget(this->ews.size(), ev->payload, widget);
this->layout->addWidget(epw);
ews.push_back(epw);
return;
}
void MainWindow::reorderEndpointWidgetCollection() {
/* Flatten */
size_t firstNullPosition = 0;
size_t ewsSize = ews.size();
bool breakSorting = false;
//todo: is all of gui really atomic by definition? im afraid of cutting through amazing add momentos, but I think I did my homework. Must check back.
for (size_t i = 0; i < ewsSize; i++) {
if (ews.at(i) == nullptr) {
for (size_t j = (i + 1); j < ewsSize; j++) {
if (ews.at(j) != nullptr) {
ews.at(i) = ews.at(j);
ews.at(i)->setIndex(i);
ews.at(j) = nullptr;
break;
}
if (j == ewsSize - 1) {
firstNullPosition = i;
breakSorting = true;
}
}
if (breakSorting) break;
}
}
ews.resize(firstNullPosition + 1);
}
void EndpointWidget::updateMute(int checked){
bool muted = (checked == 2 ? true : false);
this->eph->setMute(osh->getGuid(), muted);
this->muteButton->setText(this->eph->getMute() ? STRING_UNMUTE : STRING_MUTE);
}
void EndpointWidget::updateMainVolume(int newValue){
this->eph->setVolume(osh->getGuid(), AudioChannel::CHANNEL_MAIN, newValue);
}
/*
* void MainWindow::setPlotButton() {
* button = new QPushButton("push"),
* button->setCheckable(true);
* connect(button, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)))
* QHBoxLayout *plotsLayout = new QHBoxLayout;
* plotsLayout->setSpacing(10);
* plotsLayout->addWidget(funPlot);
* QHBoxLayout *buttonsLayout = new QHBoxLayout ;
* buttonsLayout->addWidget(button);
* QVBoxLayout *widgetLayout = new QVBoxLayout;
* widgetLayout->addLayout(plotsLayout);
* widgetLayout->addLayout(buttonsLayout);
* setLayout(widgetLayout);
* ...
* void EndpointWidget::updateVolume(uint32_t channel, float newValue){
* //this->blockSignals(true);
* int newVal = newValue * 100;
* if (channel == (uint32_t)AudioChannel::CHANNEL_MAIN) {
* //TIP: Above
* //this->mainSlider->blockSignals(true);
*
* if(this->mainSlider->value() != newVal) {
* this->mainSlider->blockSignals(true);
* this->mainSlider->setValue(newVal);
* this->mainSlider->blockSignals(false);
* }
* return;
* }
*
* for (size_t i = 0; i < sizeof(uint32_t) * 8 && i < channelSliders.size(); ++i) {
* if (((channel >> i) & 1) && this->channelSliders.at(i)->value() != newVal) {
* //this->channelSliders.at(i)->blockSignals(true);
*
* this->channelSliders.at(i)->setValue(newVal);
* this->channelLabels.at(i)->setText(QString::number((int)(newValue * 100)));
*
* //this->channelSliders.at(i)->blockSignals(false);
* }
* }
*
* //this->blockSignals(false);
* }
*/
EndpointHandler* EndpointWidget::getEndpointHandler(){
return this->eph;
}
/*
* void EndpointWidget::updateFrontIndex(uint64_t index){
* this->idx = index;
* }
*/
void EndpointWidget::setIndex(uint64_t idx){
this->idx = idx;
this->eph->setFrontVisibilityInfo(EndpointState::ENDPOINT_ACTIVE, this->idx);
}
uint64_t EndpointWidget::getIndex(){
return idx;
}
std::map<Roles, ExtendedCheckBox*> EndpointWidget::getDefaultRolesWidgets() {
return defaultRolesCheckBoxes;
}
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
// setWindowState(Qt::WindowFullScreen);
// setCentralWidget(centralWidget);
/*
* Registering needed custom events
*/
QEvent::registerEventType(CustomQEvent::EndpointWidgetObsolete);
QEvent::registerEventType(CustomQEvent::EndpointWidgetCreated);
QEvent::registerEventType(CustomQEvent::EndpointDefaultChange);
ewsUpdateTimer = new QTimer(this);
widget = new QWidget();
layout = new QGridLayout();
trayIcon = new QSystemTrayIcon();
trayIconMenu = new QMenu();
trayIconMenuQuit = new QAction(STRING_QUIT);
ewsUpdateTimer->setSingleShot(true);
ewsUpdateTimer->setInterval(ewsUpdateTimerFrequency);
connect(ewsUpdateTimer, &QTimer::timeout, this, &MainWindow::reorderEndpointWidgetCollection);
widget->setLayout(layout);
setCentralWidget(widget);
//layout->addWidget(pintas, 0, 0);
setWindowTitle(STRING_TITLE);
reloadEndpointWidgets();
/*
* Tray Icon code
*/
trayIconMenu->addSeparator();
trayIconMenu->addAction(trayIconMenuQuit);
connect(trayIconMenuQuit, &QAction::triggered, qApp, &QCoreApplication::quit);
trayIcon->setIcon(QIcon(":/assets/notificationAreaIcon.png"));
setWindowIcon(QIcon(":/assets/notificationAreaIcon.png"));
//TODO: Extend qsystemtrayicon to change mouse click?
//show before setting tooltip required; smells like bug to me!
trayIcon->show();
trayIcon->setToolTip(STRING_TITLE);
trayIcon->setContextMenu(trayIconMenu);
connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
/*
* Set of function callback definitons for EndpointSituationCallback
*/
osh->setChangeFrontDefaultsFunction([this](Roles role, std::wstring endpointId) {
for (auto epw : this->ews) {
/*
* Is this the new default endpoint?
*/
if (epw->getEndpointHandler()->getId() == endpointId) {
//not necessary to keep endpointState flags up to date right now, but updating it will allow for later config files / profiles
epw->getDefaultRolesWidgets().at(role)->blockSignals(true);
epw->getEndpointHandler()->assignRoles(role);
epw->getDefaultRolesWidgets().at(role)->blockSignals(false);
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(role), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
//epw->defaultRolesCheckBoxes.at(role)->postEnableChange();
/*
* And were you THE default?
*/
if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) {
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(Roles::ROLE_ALL), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
}
/*
* Are you the dethroned king?
*/
} else if (epw->getEndpointHandler()->getRoles() & role) {
/*
* And were you THE default up until now?
*/
if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) {
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(Roles::ROLE_ALL), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
}
epw->getDefaultRolesWidgets().at(role)->blockSignals(true);
//Same as before. ini-san will come...
epw->getEndpointHandler()->removeRoles(role);
epw->getDefaultRolesWidgets().at(role)->blockSignals(false);
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(role), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
}
}
});
osh->setRemoveEndpointWidgetFunction([this](uint64_t index) {
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<uint64_t>((QEvent::Type)CustomQEvent::EndpointWidgetObsolete, index));
});
osh->setAddEndpointWidgetFunction([this](EndpointHandler* eph) {
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<EndpointHandler*>((QEvent::Type)CustomQEvent::EndpointWidgetCreated, eph));
});
}
void MainWindow::closeEvent(QCloseEvent *event) {
if (!event->spontaneous() || !isVisible()) return;
if (trayIcon->isVisible()) {
//todo: would be nice to show this to 1st time users; ini-san will come...
//this->trayIcon->showMessage("ini file calling","tratarte como un gilipollas la primera vez", QSystemTrayIcon::Information);
hide();
event->ignore();
}
}
void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason) {
switch (reason) {
case QSystemTrayIcon::Trigger:
this->showNormal();
break;
default:
break;
}
}
void MainWindow::reloadEndpointWidgets() {
size_t i = 0;
for (size_t epwIndex = 0; i < (osh->getPlaybackEndpointHandlers().size()); i++) {
if (osh->getPlaybackEndpointHandlers().at(i)->getState() == EndpointState::ENDPOINT_ACTIVE){
log_debugcpp("EPWidget creation");
//osh->getPlaybackEndpointHandlers().at(i)->getCallbackInfo()->caller = osh->getGuid();
EndpointWidget *epw = new EndpointWidget(epwIndex, osh->getPlaybackEndpointHandlers().at(i), widget);
epwIndex++;
//alfinal estoes solopara inicializarlmao
ews.push_back(epw);
layout->addWidget(epw, i, 0);
}
}
//todo:: tas aqui tirao, no me gustas y probablemente yo a ti tampoco
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), i, 0);
}

View file

@ -1,34 +1,200 @@
#pragma once
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <vector>
#include <QMainWindow>
#include <QApplication>
#include <QCloseEvent>
#include <QIcon>
#include <QSystemTrayIcon>
#include <QMenu>
//#include <QMessageBox>
#include <QLabel>
#include <QSlider>
#include <QGridLayout>
//#include "global.h"
#include "contclasses.h"
//#include <Q>
//#include <QWidgets>
#include <QPushButton>
#include <QCheckBox>
#include <QTimer>
/*
* #else
* class QSlider;
* class QLabel;
* class QGridLayout;
* class QPushButton;
* class QWidget;
* class QMainWindow;
* #endif
*/
#include "global.h"
#include "contclasses.h"
//class EndpointHandler;
/*
* class ToggleButton : public QAbstractButton {
* Q_OBJECT
*
* public:
* ToggleButton(QWidget *parent = nullptr);
* void checkStateSet();
* bool hitButton(const QPoint &pos) const;
* void nextCheckState();
* void changeEvent(QEvent *e) override;
* bool event(QEvent *e) override;
* void focusInEvent(QFocusEvent *e) override;
* void focusOutEvent(QFocusEvent *e) override;
* void keyPressEvent(QKeyEvent *e) override;
* void keyReleaseEvent(QKeyEvent *e) override;
* void mouseMoveEvent(QMouseEvent *e) override;
* void mousePressEvent(QMouseEvent *e) override;
* void mouseReleaseEvent(QMouseEvent *e) override;
* void paintEvent(QPaintEvent *e) override = 0;
* void timerEvent(QTimerEvent *e) override;
* ToggleButton(QWidget *parent = nullptr);
* };
*/
enum CustomQEvent {
EndpointWidgetObsolete = 1001,
EndpointWidgetCreated = 1002,
EndpointDefaultChange = 1003,
SessionWidgetCreated = 1004,
SessionWidgetObsolete = 1005
};
template <typename T>
class CustomWidgetEvent : public QEvent {
public:
CustomWidgetEvent(QEvent::Type type, T payload);
T payload;
};
//Q_DECLARE_METATYPE(EndpointWidgetEvent)
class ExtendedCheckBox : public QCheckBox {
Q_OBJECT
protected:
void customEvent(QEvent* ev) override;
public:
//c++11: this inherits all parent's constructors unconditionally
using QCheckBox::QCheckBox;
//alternative being calling parent ctor directly after declaring child ctor:
//B(int x) : A(x) { }
};
class SessionWidget : public QWidget {
Q_OBJECT
public:
SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent /* = nullptr */);
~SessionWidget();
public slots:
void updateMainVolume(int newValue);
void updateMute(int checked);
private:
QLabel *mainLabel = nullptr;
QSlider *mainSlider = nullptr;
uint64_t idx;
QGridLayout *layout = nullptr;
QCheckBox *muteButton = nullptr;
SessionHandler* sh;
QTimer* volumePoller = nullptr;
};
class EndpointWidget : public QWidget {
Q_OBJECT
public:
EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *parent = nullptr);
EndpointHandler* getEndpointHandler();
std::map<Roles, ExtendedCheckBox*> getDefaultRolesWidgets();
void setIndex(uint64_t idx);
uint64_t getIndex();
void setVolume(int channel, float volume);
~EndpointWidget();
//void updateMainVolume(float newValue);
//void updateVolume(uint32_t channel, float newValue);
//void updateMute(bool muted);
//void populateEndpointWidget(EndpointHandler *eph);
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
public slots:
void updateMainVolume(int newValue);
void updateMute(int checked);
protected:
void customEvent(QEvent* ev) override;
private slots:
void addSessionWidget(CustomWidgetEvent<SessionHandler*>* ev);
void removeSessionWidget(CustomWidgetEvent<SessionHandler*>* ev);
private:
int row;
QCheckBox *muteButton = nullptr;
QLabel *mainLabel = nullptr, *leftChannelLabel = nullptr, *rightChannelLabel = nullptr;
QSlider *mainSlider = nullptr;
std::vector<QSlider*> channelSliders;
std::vector<QLabel*> channelLabels;
QGridLayout *layout = nullptr;
QGridLayout *mainMuteLayout = nullptr;
std::map<Roles, ExtendedCheckBox*> defaultRolesCheckBoxes;
EndpointHandler* eph;
size_t defaultRolesVectorSize = 4;
QTimer* timer = nullptr;
uint64_t idx;
std::vector<SessionWidget*> sessionWidgets;
//std::vector<EndpointHandler*> *ephs;
//std::vector<QSlider> *sliders;
//signals:
//void valueChanged(int value);
};
class MainWindow : public QMainWindow {
Q_OBJECT
//QWidget *centralWidget;
public:
MainWindow(std::vector<EndpointHandler*> *ephs, QWidget *parent = nullptr);
void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
MainWindow(QWidget *parent = nullptr);
void reloadEndpointWidgets();
protected:
void closeEvent(QCloseEvent *event) override;
void customEvent(QEvent* ev) override;
private slots:
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
void removeEndpointWidget(CustomWidgetEvent<uint64_t>* ev);
void addEndpointWidget(CustomWidgetEvent<EndpointHandler*>* ev);
void reorderEndpointWidgetCollection();
//TODO: destroy/empty existing EndpointWidgets
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
private:
std::vector<EndpointHandler*> *ephs;
std::vector<QSlider> *sliders;
//std::vector<EndpointHandler*> *ephs;
std::vector<EndpointWidget*> ews;
QWidget *widget;
QGridLayout *layout;
//QLabel *pintas;
QSystemTrayIcon *trayIcon;
QMenu *trayIconMenu;
QAction *trayIconMenuQuit;
QTimer *ewsUpdateTimer;
static constexpr uint64_t ewsUpdateTimerFrequency = 500;
//public slots:
// void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);

View file

@ -1,42 +1,64 @@
#include <iostream>
#include <vector>
//#include <stdio.h>
//#include <stdlib.h>
//#include <qapplicationstatic.h>
//#define QTBLESSED
#include <QApplication>
#include <QMainWindow>
#include <QLocalSocket>
#include <QLocalServer>
#include <QString>
//#include "contclasses.h"
#include "qtclasses.h"
//TODO david #include "backlasses.h"
#include "global.h"
//INIT BACK
OverseerHandler *osh = new OverseerHandler();
OverseerHandler *osh = nullptr;
QApplication* createApplication(int &argc, char *argv[])
{
return new QApplication(argc, argv);
}
bool isSingleInstanceRunning(QString appName) {
QLocalSocket socket;
socket.connectToServer(appName);
bool isOpen = socket.isOpen();
socket.close();
return isOpen;
}
QLocalServer* startSingleInstanceServer(QString appName) {
QLocalServer* server = new QLocalServer;
server->setSocketOptions(QLocalServer::WorldAccessOption);
server->listen(appName);
return server;
}
int main (int argc, char* argv[]) {
//QApplication::setStyle("windowsvista");
//INIT CONT
std::vector<Endpoint*> epts = OverseerHandler::getOverseer().getPlaybackEndpoints();
std::vector<EndpointHandler*>* ephs = new std::vector<EndpointHandler*>;
for(unsigned int i = 0; i < epts.size(); i++){
EndpointHandler *eph = new EndpointHandler(epts.at(i));
ephs->push_back(eph);
}
//Check if running
//https://stackoverflow.com/questions/48060989/qt-show-application-if-currently-running
if (!isSingleInstanceRunning("Mixer"))
startSingleInstanceServer("Mixer");
else exit(0);
osh = new OverseerHandler();
//qRegisterMetaType<EndpointWidgetEvent>();
//INIT CONT
log_debugcpp("main init");
osh->reloadEndpointHandlers();
log_debugcpp("Reloaded endpoint handlers");
osh->setEndpointHandlers(ephs);
//INIT FRONT
QScopedPointer<QApplication> app(createApplication(argc, argv));
MainWindow window = MainWindow(ephs);
MainWindow window = MainWindow();
//window.setEndpointHandlers(ephs);
QApplication::setQuitOnLastWindowClosed(false);
app->setStyle("windowsvista");
window.show();
return app->exec();
}