poll merge squash

This commit is contained in:
Hane 2024-02-07 17:20:59 +01:00
commit 40bee90610
21 changed files with 2753 additions and 261 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 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,17 @@
CONFIG += debug console QMAKE_CXXFLAGS += --target=x86_64-w64-mingw32 -g -gcodeview
QT += widgets 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" INCLUDEPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
DESTPATH += "$$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" 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 debug.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" #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,83 +1,562 @@
#include <backlasses.h> #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; this->endpoint = ep;
if(FAILED(endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&endpointVolume))) { log_debugcpp("si"); }; this->idx = idx;
//Obtaining friendly name: IPropertyStore creates PROPVARIANT per field
// hr = endpointPtr->GetId(&endpointID); /*
* 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); endpoint->OpenPropertyStore(STGM_READ, &properties);
PROPVARIANT pv; PROPVARIANT pv;
properties->GetValue(PKEY_Device_FriendlyName , &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; return friendlyName;
} }
std::wstring Endpoint::getId(){
return endpointId;
}
float Endpoint::getVolume(int channel){ float Endpoint::getVolume(int channel){
float volume; float volume;
if (channel == ENDPOINT_MASTER_VOLUME) { if (channel == AudioChannel::CHANNEL_MAIN) {
if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { log_debugcpp("si");} if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { /* log_debugcpp("si") */;}
} else { } else {
if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { log_debugcpp("si");} if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */}
} }
return volume; return volume;
} }
uint32_t Endpoint::getChannelCount(){
return (uint32_t)channelCount;
}
bool Endpoint::getMute(){ bool Endpoint::getMute(){
BOOL mut; BOOL mut;
if(FAILED(endpointVolume->GetMute(&mut))) { log_debugcpp("si"); } if(FAILED(endpointVolume->GetMute(&mut))) { /* TIP: Below */ }
log_debugcpp("back BOOL is " << mut);
bool mute = (bool)mut; bool mute = (bool)mut;
log_debugcpp("translate to bool " << mute);
return mute; return mute;
} }
/* void Endpoint::setState(uint8_t state){
* float Endpoint::getLeftChannelVolume(){ this->endpointState = state;
* float volume; if(state == EndpointState::ENDPOINT_ACTIVE) {
* if(FAILED(endpointVolume-> GetChannelVolumeLevelScalar(0, &volume)) { log_debugcpp("si"); } ); this->activateEndpointVolume();
* return volume; this->reloadEndpointChannels();
* }
*
* float Endpoint::getRightChannelVolume(){
* float volume;
* if(FAILED(endpointVolume-> GetChannelVolumeLevelScalar(1, &volume)) { log_debugcpp("si");}
* return volume;
* }
*/
void Endpoint::setVolume(int channel, float volume) {
if (channel == ENDPOINT_MASTER_VOLUME) {
if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, NULL))) { log_debugcpp("si"); };
} else {
if(FAILED(endpointVolume->SetChannelVolumeLevelScalar(channel, volume, NULL))) { log_debugcpp("si"); };
} }
} }
void Endpoint::setMute() { size_t Endpoint::getState(){
log_debugcpp("bool mute arrives as " << mut); return this->endpointState;
BOOL mut;
if(FAILED(endpointVolume->GetMute(&mut))) { log_debugcpp("si"); }
log_debugcpp("translate to BOOL as " << mute);
if(FAILED(endpointVolume->SetMute((mut == false ? 1 : 0), NULL))) { log_debugcpp("si"); };
} }
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(){ Endpoint::~Endpoint(){
log_debugcpp("cum"); log_wdebugcpp(L"murio endpoint-san uwu");
free(friendlyName);
properties->Release(); properties->Release();
endpointVolume->Release(); endpointVolume->Release();
endpoint->Release(); endpoint->Release();
sessionManager->Release();
} }
void Overseer::initCOMLibrary() {
void Overseer::initCOMLibrary(){ OutputDebugStringW(L"EPWidget creation\n");
if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { log_debugcpp("si"); }; if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) {
log_debugcpp("si"); };
//Retrieving endpoint enumerator //Retrieving endpoint enumerator
@ -87,52 +566,141 @@ void Overseer::initCOMLibrary(){
(void**)&deviceEnumerator)) ) (void**)&deviceEnumerator)) )
{ log_debugcpp("si"); }; { 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; IMMDeviceCollection *deviceCollection;
unsigned int numEndpoints;
EDataFlow MSflow = (flow == Flows::FLOW_PLAYBACK ? EDataFlow::eRender : EDataFlow::eCapture);
// | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED // | 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"); }; { 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");}; * Retrieving actual endpoints and storing them on their own class
if(numPlaybackEndpoints == 0) { log_debugcpp("si"); }; */
IMMDevice *temp;
for (unsigned int i = 0; i < numEndpoints; i++){
//Retrieving actual endpoints and storing them on their own class
for (unsigned int i = 0; i < numPlaybackEndpoints; i++){
IMMDevice *temp;
if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); }; if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); };
Endpoint *endpoint = new Endpoint(temp); Endpoint *endpoint = new Endpoint(temp, i);
this->playbackDevices.push_back(endpoint);
//TODO: le porblemx std::cout << "ola" << std::endl; if (flow == Flows::FLOW_PLAYBACK)
this->playbackDevices.push_back(endpoint);
else
this->captureDevices.push_back(endpoint);
//TODO: le porblemx std::cout + "ola" + std::endl;
} }
deviceCollection->Release(); 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 //Initializing COM library
log_debugcpp("Initializing Overseer");
initCOMLibrary(); initCOMLibrary();
//Obtaining playback endpoint collection on this point in time //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){ NGuid Overseer::getGuid() {
//if (FAILED(deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &endpointPtr))) return guid;
// return 1; }
//return 0;
//}
//int Overseer::getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
std::vector<Endpoint*> Overseer::getPlaybackEndpoints() { std::vector<Endpoint*> Overseer::getPlaybackEndpoints() {
return playbackDevices; return playbackDevices;
} }
std::vector<Endpoint*> Overseer::getCaptureEndpoints() {
return captureDevices;
}
Overseer::~Overseer(){ Overseer::~Overseer(){
log_debugcpp("cum"); log_debugcpp("cum");
deviceEnumerator->Release(); deviceEnumerator->Release();

View file

@ -1,43 +1,105 @@
#pragma once #pragma once
#define WIN32_LEAN_AND_MEAN
#include "debug.h" #include "msinclude.h"
#include "backsessionclasses.h"
#include "global.h" #include "global.h"
#include <vector> #include "contclasses.h"
#include <iostream>
#include <Windows.h> class EndpointVolumeCallback;
#include <mmdeviceapi.h> class Session;
#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 Endpoint { class Endpoint {
public: public:
Endpoint(IMMDevice* endpoint); Endpoint(IMMDevice* endpoint, uint64_t idx);
void setVolume(int channel, float volume); //todo: how to forward declare delegate constructors?
/* float getLeftChannelVolume(); */ Endpoint(IMMDevice* endpoint) : Endpoint(endpoint, 0) {};
/* float getRightChannelVolume(); */ 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); float getVolume(int channel);
void setMute(); void setMute(NGuid guid, bool muted);
bool getMute(); bool getMute();
LPWSTR getName(); 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(); ~Endpoint();
private: private:
void inline activateEndpointVolume();
void inline activateEndpointSessions();
std::vector<Session*> endpointSessions;
uint32_t channelCount = 0;
IMMDevice* endpoint; IMMDevice* endpoint;
IAudioEndpointVolume *endpointVolume ; IAudioSessionManager2 *sessionManager;
Flows flow;
IAudioEndpointVolume *endpointVolume = nullptr;
IPropertyStore *properties; IPropertyStore *properties;
LPWSTR friendlyName; std::wstring friendlyName;
// LPWSTR endpointID = NULL; 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 { class Overseer {
@ -45,7 +107,14 @@ class Overseer {
public: public:
Overseer(); Overseer();
std::vector<Endpoint*> getPlaybackEndpoints(); 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(); //~Overseer();
//int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint); //int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint);
//int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint); //int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
@ -54,12 +123,28 @@ class Overseer {
~Overseer(); ~Overseer();
private: private:
unsigned int numPlaybackEndpoints; NGuid guid;
IMMDeviceEnumerator *deviceEnumerator; IMMDeviceEnumerator *deviceEnumerator;
EndpointSituationCallback epsc;
//IPolicyConfig *policyConfig;
std::vector<Endpoint*> playbackDevices; std::vector<Endpoint*> playbackDevices;
std::vector<Endpoint*> captureDevices;
void initCOMLibrary(); void initCOMLibrary();
//IMMDeviceCollection *deviceCollection; //IMMDeviceCollection *deviceCollection;
//int numCaptureEndpoints; //int numCaptureEndpoints;
//std::vector<Endpoint*> *captureDevices; //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,50 +1,337 @@
#include "backlasses.h"
#include "contclasses.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) { epc = new EndpointVolumeCallback(ep);
this->ept = ept; ensc = new EndpointNewSessionCallback(this);
eptName = QString::fromStdWString(ept->getName()); 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 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;
}
void EndpointHandler::setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx){
ephfv.visibility = state;
ephfv.frontIdx = frontIdx;
}
uint64_t EndpointHandler::getFrontVisibilityIndex(){
return ephfv.frontIdx;
}
EndpointState EndpointHandler::getFrontVisibilityState(){
return ephfv.visibility;
}
Flows EndpointHandler::getFlow(){
return ep->getFlow();
}
/* 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;
}
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 * -1 for master volume
*/ */
void EndpointHandler::setValue(int channel, int value){ void EndpointHandler::setVolume(NGuid guid, int channel, int value){
if (channel == ENDPOINT_MASTER_VOLUME) if (channel == AudioChannel::CHANNEL_MAIN)
ept->setVolume(channel, (float)value / 100); ep->setVolume(guid, channel, (float)value / 100);
else ept->setVolume(channel, (float)value / 100); else ep->setVolume(guid, channel, (float)value / 100);
} }
void EndpointHandler::setMute(){ void EndpointHandler::setMute(NGuid guid, bool muted){
//Qt momento, de ahi el param? ep->setMute(guid, muted);
log_debugcpp("kinda handling the muting tbh");
ept->setMute();
} }
QString EndpointHandler::getName(){ std::wstring EndpointHandler::getName(){
return eptName; return ep->getName();
}
std::wstring EndpointHandler::getId(){
return ep->getId();
} }
float EndpointHandler::getVolume(int channel){ float EndpointHandler::getVolume(int channel){
return ept->getVolume(channel); return ep->getVolume(channel);
} }
bool EndpointHandler::getMute(){ bool EndpointHandler::getMute(){
return ept->getMute(); return ep->getMute();
} }
Overseer* OverseerHandler::getOverseer(){ size_t EndpointHandler::getState(){
return &os; return ep->getState();
} }
OverseerHandler::OverseerHandler(QObject *parent) : QObject(parent) { 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);
}
}
} }
std::vector<EndpointHandler*>* OverseerHandler::getEndpointHandlers(){ void EndpointHandler::setState(uint8_t state){
return endpointHandlers; ep->setState(state);
this->setBackEndpointVolumeCallbackInfoContent(state);
} }
void OverseerHandler::setEndpointHandlers(std::vector<EndpointHandler*> *ephs){ void EndpointHandler::setState(uint8_t state, uint64_t index){
this->endpointHandlers = ephs; 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,48 +1,138 @@
#pragma once #pragma once
#include <QObject>
#include "backlasses.h"
#include "global.h"
#include "contsessionclasses.h"
//#define invoke_mem_fn(object,ptrToMember) ((object).*(ptrToMember))
//#define pinvoke_mem_fn(object,ptrToMember) ((object)->*(ptrToMember))
class EndpointHandler : public QObject { class EndpointWidget;
Q_OBJECT 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 EndpointHandler {
public: public:
EndpointHandler(Endpoint *ept, QObject *parent = nullptr); EndpointHandler(uint64_t idx, Flows flow);
QString getName(); 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); float getVolume(int channel);
bool getMute(); 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: private:
Endpoint *ept; std::vector<Session*> getSessions();
QString eptName;
//QSlider *slidy;
public slots:
void setValue(int channel, int value);
void setMute();
//signals:
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 {
class OverseerHandler : public QObject {
Q_OBJECT
public: public:
OverseerHandler(QObject *parent = nullptr); OverseerHandler();
void setEndpointHandlers(std::vector<EndpointHandler*> *ephs); void setChangeFrontDefaultsFunction(std::function<void(Roles, std::wstring)> changeFrontDefaults);
std::vector<EndpointHandler*>* getEndpointHandlers(); void changeFrontDefaultsCallback(Roles role, std::wstring endpointId);
static Overseer* getOverseer();
//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: private:
static Overseer os; Overseer *os;
std::vector<EndpointHandler*> *endpointHandlers; std::vector<EndpointHandler*> playbackEndpointHandlers;
//QSlider *slidy; std::vector<EndpointHandler*> captureEndpointHandlers;
std::function<void(Roles, std::wstring /* endpointid */)> changeFrontDefaults;
//public slots: std::function<void(uint64_t /* epw id */)> removeEndpointWidget;
//void setValue(int value); 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;
};

View file

@ -2,9 +2,46 @@
#if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG) #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 { \ #define log_debugcpp(str) do { \
std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \ std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
} while (0) } 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 #else
#define log_debugcpp(str) #define log_debugcpp(str)
#define log_wdebugcpp(str)
#define print_as_binary(len, type, info)
#endif #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,14 +1,80 @@
#pragma once #pragma once
//TODO enum capullo #include <vector>
#define ENDPOINT_MASTER_VOLUME -1 #include <iostream>
#define ENDPOINT_LEFT_CHANNEL_VOLUME 0 #include <string>
#define ENDPOINT_RIGHT_CHANNEL_VOLUME 1 #include <bitset>
#include <climits>
#include <locale>
#include "debug.h"
//TODO: Use tr();? QTranslator
#define STRING_MUTE "Mute" #define STRING_MUTE "Mute"
#define STRING_UNMUTE "Unmute" #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 //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; class OverseerHandler;
extern OverseerHandler *osh; extern OverseerHandler *osh;

View file

@ -1,114 +1,584 @@
#include "qtclasses.h" #include "qtclasses.h"
template <typename T>
CustomWidgetEvent<T>::CustomWidgetEvent(QEvent::Type type, T payload) : QEvent(type){
this->payload = payload;
}
EndpointWidget::EndpointWidget(EndpointHandler* eph, QWidget *parent) : QWidget(parent){ void ExtendedCheckBox::customEvent(QEvent* ev) {
this->eph = eph; QEvent::Type tipo = ev->type();
layout = new QGridLayout(); if (ev->type() == (QEvent::Type)CustomQEvent::EndpointDefaultChange) {
this->setLayout(layout); //todo: still prone to bugs; whack-a-mole to come
log_debugcpp("olaW"); ev->setAccepted(true);
if (parent == nullptr) { log_debugcpp("owo?"); } 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);
}
muteButton = new QPushButton(); SessionWidget::SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent) : QWidget(parent){
mainLabel = new QLabel(eph->getName()); //todo: based on qgridlayout, name+mute should be its own widget, same with channels
leftChannelLabel = new QLabel("88"); this->idx = idx;
rightChannelLabel = new QLabel("77"); this->sh = sh;
mainSlider = new QSlider(Qt::Horizontal);
leftChannelSlider = new QSlider(Qt::Horizontal);
rightChannelSlider = new QSlider(Qt::Horizontal);
muteButton->setStyleSheet("background-color: #A3C1DA; color: red"); 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->setFocusPolicy(Qt::StrongFocus);
mainSlider->setTickPosition(QSlider::TicksBothSides); mainSlider->setTickPosition(QSlider::TicksBothSides);
mainSlider->setTickInterval(5); mainSlider->setTickInterval(5);
mainSlider->setSingleStep(1); mainSlider->setSingleStep(1);
mainSlider->setRange(0,100); mainSlider->setRange(0,100);
leftChannelSlider->setTickInterval(5);
leftChannelSlider->setSingleStep(1);
leftChannelSlider->setRange(0,100);
rightChannelSlider->setTickInterval(5);
rightChannelSlider->setSingleStep(1);
rightChannelSlider->setRange(0,100);
muteButton->setText(eph->getMute() ? STRING_UNMUTE : STRING_MUTE); muteButton->setCheckState((sh->getMute() == false ? Qt::Unchecked : Qt::Checked));
float volume = eph->getVolume(ENDPOINT_MASTER_VOLUME) * 100; muteButton->setText(sh->getMute() ? STRING_UNMUTE : STRING_MUTE);
float volume = sh->getVolume(AudioChannel::CHANNEL_MAIN) * 100;
mainSlider->setValue((int)volume); mainSlider->setValue((int)volume);
volume = eph->getVolume(ENDPOINT_LEFT_CHANNEL_VOLUME) * 100; log_debugcpp("SESSION SET WITH VOLUME " + std::to_string(volume));
leftChannelSlider->setValue((int)volume);
leftChannelLabel->setText(QString::number(volume));
volume = eph->getVolume(ENDPOINT_RIGHT_CHANNEL_VOLUME) * 100;
rightChannelSlider->setValue((int)volume);
rightChannelLabel->setText(QString::number(volume));
log_debugcpp("ENDPOINT SET WITH VOLUME " << volume);
mainMuteLayout = new QGridLayout(); //tip: would need to be new widget with layout in it
layout->addLayout(mainMuteLayout, 0, 0); //mainMuteLayout = new QGridLayout();
mainMuteLayout->addWidget(mainLabel, 0, 0); layout->addWidget(mainLabel, 0, 0, Qt::AlignLeft | Qt::AlignBottom);
mainMuteLayout->addWidget(muteButton, 0, 1); layout->addWidget(muteButton, 0, 1, Qt::AlignLeft | Qt::AlignBottom);
layout->addWidget(mainSlider, 0, 1); layout->addWidget(mainSlider, 0, 2, 1, 2);
layout->addWidget(leftChannelSlider, 1, 0);
layout->addWidget(leftChannelLabel, 2, 0); //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?
layout->addWidget(rightChannelSlider, 1, 1); connect<void(QSlider::*)(int), void(SessionWidget::*)(int)>(mainSlider, &QSlider::valueChanged, this,&SessionWidget::updateMainVolume);
layout->addWidget(rightChannelLabel, 2, 1); connect<void(QCheckBox::*)(int), void(SessionWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&SessionWidget::updateMute));
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 3, 0);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 3, 1);
/* /*
* connect(mainSlider, &QSlider::valueChanged, eph, &EndpointHandler::setValue); * Session Volume Polling
*/ */
connect(mainSlider, &QSlider::valueChanged, [this](int newValue){this->eph->setValue(ENDPOINT_MASTER_VOLUME, newValue); }); volumePoller = new QTimer();
connect(leftChannelSlider, &QSlider::valueChanged, [this](int newValue){ this->eph->setValue(ENDPOINT_LEFT_CHANNEL_VOLUME, newValue); this->leftChannelLabel->setText(QString::number(newValue)); }); connect(volumePoller, &QTimer::timeout, [this, sh](){
connect(rightChannelSlider, &QSlider::valueChanged, [this](int newValue){ this->eph->setValue(ENDPOINT_RIGHT_CHANNEL_VOLUME, newValue); this->rightChannelLabel->setText(QString::number(newValue)); }); //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.
connect(muteButton, &QPushButton::clicked, [this](bool clicked){ log_debugcpp("cliqui" << clicked << "cloqui"); this->eph->setMute(); this->muteButton->setText(this->eph->getMute() ? STRING_UNMUTE : STRING_MUTE); }); //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"); 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;
}
MainWindow::MainWindow(std::vector<EndpointHandler*> *ephs, QWidget *parent) : QMainWindow(parent) { void EndpointWidget::removeSessionWidget(CustomWidgetEvent<SessionHandler*>* ev){
// setWindowState(Qt::WindowFullScreen); uint64_t i = ev->payload->getFrontIndex();
// setCentralWidget(centralWidget); this->sessionWidgets.at(i)->setParent(nullptr);
widget = new QWidget(); this->layout->removeWidget(sessionWidgets.at(i));
layout = new QGridLayout(); delete sessionWidgets.at(i);
sessionWidgets.at(i) = nullptr;
ev->payload->setFrontIndex(INT_MAX);
//this->sessionWidgetsUpdateTimer->start();
return;
}
widget->setLayout(layout); void EndpointWidget::customEvent(QEvent* ev) {
setCentralWidget(widget); if (ev->type() == (QEvent::Type)CustomQEvent::SessionWidgetCreated) {
//layout->addWidget(pintas, 0, 0); ev->setAccepted(true);
this->addSessionWidget((CustomWidgetEvent<SessionHandler*>*) ev);
setWindowTitle("slidea resbala nu c"); } else if (ev->type() == (QEvent::Type)CustomQEvent::SessionWidgetObsolete) {
ev->setAccepted(true);
/*s this->removeSessionWidget((CustomWidgetEvent<SessionHandler*>*) ev);
* setEndpointHandlers(ephs);
*/
unsigned int i = 0;
for (; i < ephs->size(); i++) {
log_debugcpp("EPWidget creation");
EndpointWidget *epw = new EndpointWidget(ephs->at(i), widget);
ews.push_back(epw);
layout->addWidget(epw, i, 0);
} }
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), i, 0); 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::setEndpointHandlers(std::vector<EndpointHandler*> *ephs){ * void EndpointWidget::updateVolume(uint32_t channel, float newValue){
* this->ephs = ephs; * //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 MainWindow::setPlotButton() { * void EndpointWidget::updateFrontIndex(uint64_t index){
* button = new QPushButton("push"), * this->idx = index;
* button->setCheckable(true); * }
* connect(button, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))) */
* QHBoxLayout *plotsLayout = new QHBoxLayout;
* plotsLayout->setSpacing(10); void EndpointWidget::setIndex(uint64_t idx){
* plotsLayout->addWidget(funPlot); this->idx = idx;
* QHBoxLayout *buttonsLayout = new QHBoxLayout ; this->eph->setFrontVisibilityInfo(EndpointState::ENDPOINT_ACTIVE, this->idx);
* buttonsLayout->addWidget(button); }
* QVBoxLayout *widgetLayout = new QVBoxLayout;
* widgetLayout->addLayout(plotsLayout); uint64_t EndpointWidget::getIndex(){
* widgetLayout->addLayout(buttonsLayout); return idx;
* setLayout(widgetLayout); }
* ...
*/ 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,42 +1,164 @@
#pragma once #pragma once
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#include <vector>
#include <QMainWindow> #include <QMainWindow>
#include <QApplication> #include <QApplication>
#include <QCloseEvent>
#include <QIcon>
#include <QSystemTrayIcon>
#include <QMenu>
//#include <QMessageBox>
#include <QLabel> #include <QLabel>
#include <QSlider> #include <QSlider>
#include <QGridLayout> #include <QGridLayout>
#include <QPushButton> #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" #include "contclasses.h"
//#include <Q> //class EndpointHandler;
//#include <QWidgets>
/*
* 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
};
class EndpointWidget : public QWidget { template <typename T>
Q_OBJECT class CustomWidgetEvent : public QEvent {
public: public:
EndpointWidget(EndpointHandler* eph, QWidget *parent = nullptr); 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 populateEndpointWidget(EndpointHandler *eph);
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs); //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: private:
EndpointHandler* eph; int row;
QPushButton *muteButton = nullptr; QCheckBox *muteButton = nullptr;
QLabel *mainLabel = nullptr, *leftChannelLabel = nullptr, *rightChannelLabel = nullptr; QLabel *mainLabel = nullptr, *leftChannelLabel = nullptr, *rightChannelLabel = nullptr;
QSlider *mainSlider = nullptr; QSlider *mainSlider = nullptr;
QSlider *leftChannelSlider = nullptr; std::vector<QSlider*> channelSliders;
QSlider *rightChannelSlider = nullptr; std::vector<QLabel*> channelLabels;
QGridLayout *layout = nullptr; QGridLayout *layout = nullptr;
QGridLayout *mainMuteLayout = 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<EndpointHandler*> *ephs;
//std::vector<QSlider> *sliders; //std::vector<QSlider> *sliders;
//public slots:
// void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
//signals: //signals:
//void valueChanged(int value); //void valueChanged(int value);
@ -48,7 +170,19 @@ class MainWindow : public QMainWindow {
//QWidget *centralWidget; //QWidget *centralWidget;
public: public:
MainWindow(std::vector<EndpointHandler*> *ephs, QWidget *parent = nullptr); 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); //void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
private: private:
@ -56,8 +190,12 @@ private:
std::vector<EndpointWidget*> ews; std::vector<EndpointWidget*> ews;
QWidget *widget; QWidget *widget;
QGridLayout *layout; QGridLayout *layout;
//QLabel *pintas;
QSystemTrayIcon *trayIcon;
QMenu *trayIconMenu;
QAction *trayIconMenuQuit;
QTimer *ewsUpdateTimer;
static constexpr uint64_t ewsUpdateTimerFrequency = 500;
//public slots: //public slots:
// void setEndpointHandlers(std::vector<EndpointHandler*> *ephs); // void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);

View file

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