Compare commits
57 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5211b70669 | |||
| 0dd016bb16 | |||
| 574c6f039e | |||
| 064c16d9e7 | |||
| cb9446cb42 | |||
| 6d88697811 | |||
| 6f8455c63d | |||
| 44ccde6ac8 | |||
| f92df42995 | |||
| 6d2f981d35 | |||
| 14fae226bc | |||
| 60e3178e9a | |||
| 6744a64fce | |||
| a15037c5f2 | |||
| 04da76c021 | |||
| a6a052f348 | |||
| fc63875851 | |||
| f620a0575d | |||
| 1a4692533d | |||
| 24110624fb | |||
| e278280c4b | |||
| 5c8c1509c8 | |||
| 5a9d2f7099 | |||
| 1fcf6c3722 | |||
| e1dd3dc532 | |||
| 8c1cea2da9 | |||
| 8e9de6a771 | |||
| 1a9f141087 | |||
| b15e5d6df7 | |||
| 1797b39b30 | |||
| d1f0bcaf26 | |||
| 966cf91a23 | |||
| 729f01a189 | |||
| 9b1c251a3c | |||
| 5bb37eb9fd | |||
| 81f6cb32c8 | |||
| 60aff9891f | |||
| 33330419a9 | |||
| e30ed58c08 | |||
| 7fb67cff3f | |||
| 4d9bae4c87 | |||
| cb81b49367 | |||
| 679ad34f84 | |||
| a251b4cb6b | |||
| 167331944c | |||
| a565190e6f | |||
| c8d64481e8 | |||
| 44461afdc4 | |||
| 4e10385a3b | |||
| bc82ec72ed | |||
| ad34a38f38 | |||
| cf1829bd78 | |||
| f84ddaef6c | |||
| e42c2dd6c9 | |||
| eaa935fb39 | |||
| b006896ccb | |||
| 826373aee4 |
21 changed files with 2850 additions and 188 deletions
5
assets.qrc
Normal file
5
assets.qrc
Normal 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
BIN
assets/SoundVolumeView.exe
Normal file
Binary file not shown.
BIN
assets/notificationAreaIcon.png
Normal file
BIN
assets/notificationAreaIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
|
|
@ -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
|
||||||
|
|
|
||||||
16
qtest.pro
16
qtest.pro
|
|
@ -1,8 +1,16 @@
|
||||||
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
|
SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp backsessionclasses.cpp contclasses.cpp contsessionclasses.cpp
|
||||||
HEADERS += qtclasses.h backlasses.h contclasses.h global.h
|
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
32
src/back/backfuncs.h
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -1,40 +1,563 @@
|
||||||
#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Endpoint::getVolume(){
|
std::wstring Endpoint::getId(){
|
||||||
|
return endpointId;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Endpoint::getVolume(int channel){
|
||||||
float volume;
|
float volume;
|
||||||
if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { log_debugcpp("si");}
|
if (channel == AudioChannel::CHANNEL_MAIN) {
|
||||||
|
if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { /* log_debugcpp("si") */;}
|
||||||
|
} else {
|
||||||
|
if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */}
|
||||||
|
}
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::setVolume(float volume) {
|
uint32_t Endpoint::getChannelCount(){
|
||||||
if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, NULL))) { log_debugcpp("si"); };
|
return (uint32_t)channelCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Endpoint::~Endpoint(){
|
|
||||||
// free(friendlyName);
|
|
||||||
// properties->Release();
|
|
||||||
// endpointVolume->Release();
|
|
||||||
// endpoint->Release();
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
bool Endpoint::getMute(){
|
||||||
|
BOOL mut;
|
||||||
|
if(FAILED(endpointVolume->GetMute(&mut))) { /* TIP: Below */ }
|
||||||
|
bool mute = (bool)mut;
|
||||||
|
return mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::setState(uint8_t state){
|
||||||
|
this->endpointState = state;
|
||||||
|
if(state == EndpointState::ENDPOINT_ACTIVE) {
|
||||||
|
this->activateEndpointVolume();
|
||||||
|
this->reloadEndpointChannels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Endpoint::getState(){
|
||||||
|
return this->endpointState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::setVolume(NGuid guid, int channel, float volume) {
|
||||||
|
//TIP: There used to be log messages here. Now, it's a ghost town.
|
||||||
|
GUID tempMsGuid = NGuidToGUID(guid);
|
||||||
|
if (channel == AudioChannel::CHANNEL_MAIN) {
|
||||||
|
if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, &tempMsGuid))) {};
|
||||||
|
} else {
|
||||||
|
if(FAILED(endpointVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::setMute(NGuid guid, bool muted) {
|
||||||
|
GUID tempMsGuid = NGuidToGUID(guid);
|
||||||
|
if(FAILED(endpointVolume->SetMute(muted, &tempMsGuid))) { log_wdebugcpp(std::wstring(L"EndpointVolume null?")); };
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::setVolumeCallback(EndpointVolumeCallback *epc){
|
||||||
|
if(endpointVolume == nullptr) {
|
||||||
|
this->activateEndpointVolume();
|
||||||
|
}
|
||||||
|
endpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::removeVolumeCallback(EndpointVolumeCallback *epc){
|
||||||
|
endpointVolume->UnregisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Roles Endpoint::getRoles(){
|
||||||
|
return this->endpointRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::setRoles(Roles role){
|
||||||
|
//otro exe momento
|
||||||
|
STARTUPINFOEXW startupConfig;
|
||||||
|
PROCESS_INFORMATION processInfo;
|
||||||
|
SecureZeroMemory(&startupConfig, sizeof(STARTUPINFOEXW));
|
||||||
|
SecureZeroMemory(&startupConfig.StartupInfo, sizeof(STARTUPINFOW));
|
||||||
|
startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW);
|
||||||
|
SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
|
||||||
|
|
||||||
|
std::wstring command = L"SoundVolumeView.exe /SetDefault " + endpointId + L" ";
|
||||||
|
std::wstring troublePair = L"0";
|
||||||
|
switch (role) {
|
||||||
|
case Roles::ROLE_ALL:
|
||||||
|
/*
|
||||||
|
* console or multimedia, one sends both, at least for now;
|
||||||
|
* either cos of ms or dis guy;
|
||||||
|
* no choice but to treat them as one for now.
|
||||||
|
* command += L"all"; and nothing else would've been nice...
|
||||||
|
*/
|
||||||
|
troublePair = command + troublePair;
|
||||||
|
if(CreateProcessW(
|
||||||
|
NULL,
|
||||||
|
(wchar_t*)troublePair.c_str(),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
false,
|
||||||
|
CREATE_UNICODE_ENVIRONMENT,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
(LPSTARTUPINFOW)&startupConfig,
|
||||||
|
&processInfo
|
||||||
|
) == true) {
|
||||||
|
WaitForSingleObject(processInfo.hProcess, INFINITE );
|
||||||
|
CloseHandle(processInfo.hProcess);
|
||||||
|
CloseHandle(processInfo.hThread);
|
||||||
|
}
|
||||||
|
command += L"2";
|
||||||
|
break;
|
||||||
|
case Roles::ROLE_CONSOLE:
|
||||||
|
command += std::to_wstring(0);
|
||||||
|
break;
|
||||||
|
case Roles::ROLE_MULTIMEDIA:
|
||||||
|
command += std::to_wstring(1);
|
||||||
|
break;
|
||||||
|
case Roles::ROLE_COMMUNICATIONS:
|
||||||
|
command += std::to_wstring(2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CreateProcessW(
|
||||||
|
NULL,
|
||||||
|
(wchar_t*)command.c_str(),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
false,
|
||||||
|
CREATE_UNICODE_ENVIRONMENT,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
(LPSTARTUPINFOW)&startupConfig,
|
||||||
|
&processInfo
|
||||||
|
) == true) {
|
||||||
|
WaitForSingleObject(processInfo.hProcess, INFINITE );
|
||||||
|
CloseHandle(processInfo.hProcess);
|
||||||
|
CloseHandle(processInfo.hThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::assignRoles(Roles role){
|
||||||
|
Roles roles = (Roles)(endpointRoles | role);
|
||||||
|
this->endpointRoles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::removeRoles(Roles role){
|
||||||
|
Roles roles = (Roles)(endpointRoles ^ role);
|
||||||
|
this->endpointRoles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::setFlow() {
|
||||||
|
IMMEndpoint* flowGetter;
|
||||||
|
//this should be as simple as writing IID_IMMEndpoint, but it just won't find the macro, so I copied it. Sad.
|
||||||
|
GUID manual;
|
||||||
|
manual.Data1 = 0x1be09788;
|
||||||
|
manual.Data2 = 0x6894;
|
||||||
|
manual.Data3 = 0x4089;
|
||||||
|
manual.Data4[0] = 0x85;
|
||||||
|
manual.Data4[1] = 0x86;
|
||||||
|
manual.Data4[2] = 0x9a;
|
||||||
|
manual.Data4[3] = 0x2a;
|
||||||
|
manual.Data4[4] = 0x6c;
|
||||||
|
manual.Data4[5] = 0x26;
|
||||||
|
manual.Data4[6] = 0x5a;
|
||||||
|
manual.Data4[7] = 0xc5;
|
||||||
|
if(FAILED(this->endpoint->QueryInterface((const _GUID)manual, (void**)&flowGetter)))
|
||||||
|
{ log_debugcpp("no flow..."); }
|
||||||
|
EDataFlow MSflow;
|
||||||
|
HRESULT vafllar = flowGetter->GetDataFlow(&MSflow);
|
||||||
|
this->flow = (MSflow == EDataFlow::eRender ? Flows::FLOW_PLAYBACK : Flows::FLOW_CAPTURE);
|
||||||
|
flowGetter->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
Flows Endpoint::getFlow() {
|
||||||
|
return this->flow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sessions */
|
||||||
|
std::vector<Session*> Endpoint::getSessions() {
|
||||||
|
return endpointSessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Endpoint::getSessionCount() {
|
||||||
|
return endpointSessions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::registerNewSessionNotification(EndpointNewSessionCallback* ensc){
|
||||||
|
sessionManager->RegisterSessionNotification(ensc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::unregisterNewSessionNotification(EndpointNewSessionCallback* ensc){
|
||||||
|
sessionManager->UnregisterSessionNotification(ensc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint::~Endpoint(){
|
||||||
|
log_wdebugcpp(L"murio endpoint-san uwu");
|
||||||
|
properties->Release();
|
||||||
|
endpointVolume->Release();
|
||||||
|
endpoint->Release();
|
||||||
|
sessionManager->Release();
|
||||||
|
}
|
||||||
|
|
||||||
void Overseer::initCOMLibrary() {
|
void Overseer::initCOMLibrary() {
|
||||||
if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { log_debugcpp("si"); };
|
OutputDebugStringW(L"EPWidget creation\n");
|
||||||
|
if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) {
|
||||||
|
log_debugcpp("si"); };
|
||||||
|
|
||||||
|
|
||||||
//Retrieving endpoint enumerator
|
//Retrieving endpoint enumerator
|
||||||
|
|
@ -44,58 +567,148 @@ 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"); };
|
*/
|
||||||
|
|
||||||
|
|
||||||
//Retrieving actual endpoints and storing them on their own class
|
|
||||||
for (unsigned int i = 0; i < numPlaybackEndpoints; i++){
|
|
||||||
IMMDevice *temp;
|
IMMDevice *temp;
|
||||||
|
for (unsigned int i = 0; i < numEndpoints; i++){
|
||||||
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);
|
||||||
|
|
||||||
|
if (flow == Flows::FLOW_PLAYBACK)
|
||||||
this->playbackDevices.push_back(endpoint);
|
this->playbackDevices.push_back(endpoint);
|
||||||
//TODO: le porblemx std::cout << "ola" << std::endl;
|
else
|
||||||
|
this->captureDevices.push_back(endpoint);
|
||||||
|
//TODO: le porblemx std::cout + "ola" + std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceCollection->Release();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Overseer::~Overseer(){
|
std::vector<Endpoint*> Overseer::getCaptureEndpoints() {
|
||||||
// deviceEnumerator->Release();
|
return captureDevices;
|
||||||
// for(unsigned long long i = 0; i < playbackDevices.size(); i++){
|
}
|
||||||
//delete(playbackDevices.at(i));
|
|
||||||
//}
|
Overseer::~Overseer(){
|
||||||
//}
|
log_debugcpp("cum");
|
||||||
|
deviceEnumerator->Release();
|
||||||
|
for(unsigned long long i = 0; i < playbackDevices.size(); i++){
|
||||||
|
delete(playbackDevices.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//int Overseer::getCaptureEndpoints(std::vector<Endpoint*> *captureEndpoints);
|
//int Overseer::getCaptureEndpoints(std::vector<Endpoint*> *captureEndpoints);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,105 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
|
|
||||||
|
#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(float volume);
|
//todo: how to forward declare delegate constructors?
|
||||||
float getVolume();
|
Endpoint(IMMDevice* endpoint) : Endpoint(endpoint, 0) {};
|
||||||
LPWSTR getName();
|
void reloadEndpointChannels();
|
||||||
//~Endpoint();
|
uint64_t getIndex();
|
||||||
|
void setIndex(uint64_t idx);
|
||||||
|
void setVolume(NGuid guid, int channel, float volume);
|
||||||
|
uint32_t getChannelCount();
|
||||||
|
float getVolume(int channel);
|
||||||
|
void setMute(NGuid guid, bool muted);
|
||||||
|
bool getMute();
|
||||||
|
void setState(uint8_t state);
|
||||||
|
size_t getState();
|
||||||
|
Roles getRoles();
|
||||||
|
void setRoles(Roles role);
|
||||||
|
void assignRoles(Roles role);
|
||||||
|
void removeRoles(Roles role);
|
||||||
|
void setFlow();
|
||||||
|
Flows getFlow();
|
||||||
|
std::wstring getId();
|
||||||
|
std::wstring getName();
|
||||||
|
|
||||||
|
void setVolumeCallback(EndpointVolumeCallback *epc);
|
||||||
|
void removeVolumeCallback(EndpointVolumeCallback *epc);
|
||||||
|
|
||||||
|
/* sessions */
|
||||||
|
std::vector<Session*> getSessions();
|
||||||
|
size_t getSessionCount();
|
||||||
|
void addSession(Session* session);
|
||||||
|
void registerNewSessionNotification(EndpointNewSessionCallback* ensc);
|
||||||
|
void unregisterNewSessionNotification(EndpointNewSessionCallback* ensc);
|
||||||
|
|
||||||
|
~Endpoint();
|
||||||
|
|
||||||
private:
|
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 {
|
||||||
|
|
@ -40,21 +107,44 @@ 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);
|
||||||
//int getCaptureEndpoints(std::vector<Endpoint*> *captureEndpoints);
|
//int getCaptureEndpoints(std::vector<Endpoint*> *captureEndpoints);
|
||||||
//IMMDeviceEnumerator** setOrigin();
|
//IMMDeviceEnumerator** setOrigin();
|
||||||
//~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;
|
||||||
|
};
|
||||||
|
|
|
||||||
282
src/back/backsessionclasses.cpp
Normal file
282
src/back/backsessionclasses.cpp
Normal 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();
|
||||||
|
}
|
||||||
57
src/back/backsessionclasses.h
Normal file
57
src/back/backsessionclasses.h
Normal 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
192
src/back/ipolicyconfig.h
Normal 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
26
src/back/msinclude.h
Normal 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>
|
||||||
|
|
@ -1,36 +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 EndpointHandler::setValue(int value){
|
void OverseerHandler::pushBackEndpointHandler(EndpointHandler* eph, Flows flow) {
|
||||||
ept->setVolume((float)value / 100);
|
if (eph == nullptr) return;
|
||||||
|
if (flow == Flows::FLOW_PLAYBACK)
|
||||||
|
this->playbackEndpointHandlers.push_back(eph);
|
||||||
|
else
|
||||||
|
this->captureEndpointHandlers.push_back(eph);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EndpointHandler::getName(){
|
void EndpointHandler::setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx){
|
||||||
return eptName;
|
ephfv.visibility = state;
|
||||||
|
ephfv.frontIdx = frontIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
float EndpointHandler::getVolume(){
|
uint64_t EndpointHandler::getFrontVisibilityIndex(){
|
||||||
return ept->getVolume();
|
return ephfv.frontIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
Overseer OverseerHandler::getOverseer(){
|
EndpointState EndpointHandler::getFrontVisibilityState(){
|
||||||
return os;
|
return ephfv.visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
OverseerHandler::OverseerHandler(QObject *parent) : QObject(parent) {
|
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
|
||||||
|
*/
|
||||||
|
void EndpointHandler::setVolume(NGuid guid, int channel, int value){
|
||||||
|
if (channel == AudioChannel::CHANNEL_MAIN)
|
||||||
|
ep->setVolume(guid, channel, (float)value / 100);
|
||||||
|
else ep->setVolume(guid, channel, (float)value / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setMute(NGuid guid, bool muted){
|
||||||
|
ep->setMute(guid, muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring EndpointHandler::getName(){
|
||||||
|
return ep->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring EndpointHandler::getId(){
|
||||||
|
return ep->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
float EndpointHandler::getVolume(int channel){
|
||||||
|
return ep->getVolume(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndpointHandler::getMute(){
|
||||||
|
return ep->getMute();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EndpointHandler::getState(){
|
||||||
|
return ep->getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setBackEndpointVolumeCallbackInfoContent(uint8_t state) {
|
||||||
|
if(state == EndpointState::ENDPOINT_ACTIVE) {
|
||||||
|
callbackInfo.muted = this->getMute();
|
||||||
|
callbackInfo.mainVolume = this->getVolume(AudioChannel::CHANNEL_MAIN);
|
||||||
|
callbackInfo.channels = this->getChannelCount();
|
||||||
|
ep->setVolumeCallback(epc);
|
||||||
|
callbackInfo.channelVolumes.resize(this->callbackInfo.channels);
|
||||||
|
for(uint32_t i = 0; i < this->getChannelCount(); i++){
|
||||||
|
callbackInfo.channelVolumes.at(i) = this->getVolume(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setState(uint8_t state){
|
||||||
|
ep->setState(state);
|
||||||
|
this->setBackEndpointVolumeCallbackInfoContent(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setState(uint8_t state, uint64_t index){
|
||||||
|
ep->setState(state);
|
||||||
|
this->setFrontVisibilityInfo((EndpointState)state, index);
|
||||||
|
this->setBackEndpointVolumeCallbackInfoContent(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t EndpointHandler::getRoles(){
|
||||||
|
return ep->getRoles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setRoles(Roles newRole){
|
||||||
|
ep->setRoles(newRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::assignRoles(Roles newRole){
|
||||||
|
ep->assignRoles(newRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::removeRoles(Roles newRole){
|
||||||
|
ep->removeRoles(newRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setAddSessionWidgetFunction(std::function<void(SessionHandler*)> addSessionWidget) {
|
||||||
|
this->addSessionWidget = addSessionWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setRemoveSessionWidgetFunction(std::function<void(SessionHandler*)> removeSessionWidget) {
|
||||||
|
this->removeSessionWidget = removeSessionWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sessions */
|
||||||
|
size_t EndpointHandler::getSessionCount() {
|
||||||
|
return ep->getSessionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Session*> EndpointHandler::getSessions(){
|
||||||
|
return ep->getSessions();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SessionHandler*> EndpointHandler::getSessionHandlers(){
|
||||||
|
return this->sessionHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint* EndpointHandler::getEndpoint() {
|
||||||
|
return this->ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::addSessionSendFront(Session* session) {
|
||||||
|
ep->addSession(session);
|
||||||
|
|
||||||
|
SessionHandler* sessionHandler = new SessionHandler(this, session, (getSessionCount() - 1));
|
||||||
|
sessionHandlers.push_back(sessionHandler);
|
||||||
|
this->addSessionWidget(sessionHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::sendSessionToFront(SessionHandler* sh) {
|
||||||
|
this->addSessionWidget(sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::removeSessionFromFront(SessionHandler* sh) {
|
||||||
|
this->removeSessionWidget(sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
EndpointHandler::~EndpointHandler() {
|
||||||
|
ep->removeVolumeCallback(epc);
|
||||||
|
ep->unregisterNewSessionNotification(ensc);
|
||||||
|
epc->Release();
|
||||||
|
delete ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverseerHandler::OverseerHandler() {
|
||||||
|
this->os = new Overseer();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Endpoint*> OverseerHandler::getPlaybackEndpoints() {
|
||||||
|
return this->os->getPlaybackEndpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Endpoint*> OverseerHandler::getCaptureEndpoints() {
|
||||||
|
return this->os->getCaptureEndpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EndpointHandler*> OverseerHandler::getPlaybackEndpointHandlers(){
|
||||||
|
return playbackEndpointHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EndpointHandler*> OverseerHandler::getCaptureEndpointHandlers(){
|
||||||
|
return captureEndpointHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t OverseerHandler::getPlaybackEndpointsCount(){
|
||||||
|
return this->os->getPlaybackEndpoints().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t OverseerHandler::getCaptureEndpointsCount(){
|
||||||
|
return this->os->getCaptureEndpoints().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::reloadEndpointHandlers(){
|
||||||
|
//todo: add capture
|
||||||
|
|
||||||
|
//std::vector<EndpointHandler*>* ephs = new std::vector<EndpointHandler*>;
|
||||||
|
log_debugcpp("Playback VSize: " + std::to_string(this->getPlaybackEndpointsCount()));
|
||||||
|
|
||||||
|
for(uint64_t i = 0; i < this->getPlaybackEndpointsCount(); i++){
|
||||||
|
log_debugcpp("Creating Playback handler " + std::to_string(i));
|
||||||
|
|
||||||
|
EndpointHandler* ephexx = new EndpointHandler(i, Flows::FLOW_PLAYBACK);
|
||||||
|
//this->playbackEndpointHandlers.push_back(ephexx);
|
||||||
|
log_debugcpp("Created Playback handler " + std::to_string(i) + ", adding to vector. " + " VSize: " + std::to_string(this->playbackEndpointHandlers.size()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<EndpointHandler*>* OverseerHandler::getEndpointHandlers(){
|
log_debugcpp("Capture VSize: " +
|
||||||
return endpointHandlers;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverseerHandler::setEndpointHandlers(std::vector<EndpointHandler*> *ephs){
|
EndpointHandler* OverseerHandler::addEndpoint(std::wstring endpointId, /* out */ Flows *flow = nullptr){
|
||||||
this->endpointHandlers = ephs;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,138 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QObject>
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "backlasses.h"
|
#include "contsessionclasses.h"
|
||||||
|
//#define invoke_mem_fn(object,ptrToMember) ((object).*(ptrToMember))
|
||||||
|
//#define pinvoke_mem_fn(object,ptrToMember) ((object)->*(ptrToMember))
|
||||||
class EndpointHandler : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
EndpointHandler(Endpoint *ept, QObject *parent = nullptr);
|
|
||||||
QString getName();
|
|
||||||
float getVolume();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Endpoint *ept;
|
|
||||||
QString eptName;
|
|
||||||
//QSlider *slidy;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setValue(int value);
|
|
||||||
|
|
||||||
|
|
||||||
//signals:
|
|
||||||
|
|
||||||
|
class EndpointWidget;
|
||||||
|
class Endpoint;
|
||||||
|
class EndpointVolumeCallback;
|
||||||
|
class Overseer;
|
||||||
|
class SessionHandler;
|
||||||
|
class EndpointNewSessionCallback;
|
||||||
|
|
||||||
|
struct BackEndpointVolumeCallbackInfo {
|
||||||
|
NGuid caller;
|
||||||
|
bool muted;
|
||||||
|
float mainVolume;
|
||||||
|
size_t channels;
|
||||||
|
std::vector<float> channelVolumes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EndpointHandler {
|
||||||
class OverseerHandler : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OverseerHandler(QObject *parent = nullptr);
|
EndpointHandler(uint64_t idx, Flows flow);
|
||||||
void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
void setBackEndpointVolumeCallbackInfoContent(uint8_t state);
|
||||||
std::vector<EndpointHandler*>* getEndpointHandlers();
|
|
||||||
static Overseer getOverseer();
|
//these two, currently unused. If I use them, I should feel bad.
|
||||||
|
//EndpointVolumeCallback* getEndpointVolumeCallback();
|
||||||
|
//Endpoint* getEndpoint();
|
||||||
|
|
||||||
|
//std::wstring epName;
|
||||||
|
BackEndpointVolumeCallbackInfo* getCallbackInfo();
|
||||||
|
uint32_t getChannelCount();
|
||||||
|
|
||||||
|
void setIndex(uint64_t idx);
|
||||||
|
uint64_t getIndex();
|
||||||
|
void setVolume(int channel, float volume);
|
||||||
|
|
||||||
|
std::wstring getName();
|
||||||
|
std::wstring getId();
|
||||||
|
|
||||||
|
void setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx);
|
||||||
|
uint64_t getFrontVisibilityIndex();
|
||||||
|
EndpointState getFrontVisibilityState();
|
||||||
|
|
||||||
|
Flows getFlow();
|
||||||
|
float getVolume(int channel);
|
||||||
|
bool getMute();
|
||||||
|
size_t getState();
|
||||||
|
uint8_t getRoles();
|
||||||
|
void setRoles(Roles newRole);
|
||||||
|
void assignRoles(Roles newRole);
|
||||||
|
void removeRoles(Roles newRole);
|
||||||
|
|
||||||
|
void setVolume(NGuid guid, int channel, int value);
|
||||||
|
void setMute(NGuid guid, bool muted);
|
||||||
|
void setState(uint8_t state);
|
||||||
|
void setState(uint8_t state, uint64_t idx);
|
||||||
|
|
||||||
|
/* sessions */
|
||||||
|
size_t getSessionCount();
|
||||||
|
std::vector<SessionHandler*> getSessionHandlers();
|
||||||
|
void createNewSession();
|
||||||
|
Endpoint* getEndpoint();
|
||||||
|
|
||||||
|
/*Session*/
|
||||||
|
void addSessionSendFront(Session* session);
|
||||||
|
void setAddSessionWidgetFunction(std::function<void(SessionHandler*)> addSessionWidget);
|
||||||
|
void setRemoveSessionWidgetFunction(std::function<void(SessionHandler*)> removeSessionWidget);
|
||||||
|
void sendSessionToFront(SessionHandler* sh);
|
||||||
|
void removeSessionFromFront(SessionHandler* sh);
|
||||||
|
|
||||||
|
~EndpointHandler();
|
||||||
|
private:
|
||||||
|
std::vector<Session*> getSessions();
|
||||||
|
|
||||||
|
uint64_t idx;
|
||||||
|
Endpoint *ep = nullptr;
|
||||||
|
EndpointVolumeCallback *epc = nullptr;
|
||||||
|
Flows flow;
|
||||||
|
BackEndpointVolumeCallbackInfo callbackInfo;
|
||||||
|
struct EndpointHandlerFrontVisibility {
|
||||||
|
EndpointState visibility = EndpointState::ENDPOINT_ALL;
|
||||||
|
uint64_t frontIdx = INT_MAX;
|
||||||
|
};
|
||||||
|
EndpointHandlerFrontVisibility ephfv;
|
||||||
|
EndpointNewSessionCallback* ensc;
|
||||||
|
std::vector<SessionHandler*> sessionHandlers;
|
||||||
|
std::function<void(SessionHandler*)> addSessionWidget;
|
||||||
|
std::function<void(SessionHandler*)> removeSessionWidget;
|
||||||
|
//QSlider *slidy;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OverseerHandler {
|
||||||
|
|
||||||
|
public:
|
||||||
|
OverseerHandler();
|
||||||
|
void setChangeFrontDefaultsFunction(std::function<void(Roles, std::wstring)> changeFrontDefaults);
|
||||||
|
void changeFrontDefaultsCallback(Roles role, std::wstring endpointId);
|
||||||
|
|
||||||
|
//void setReviseEndpointShowingFunction(std::function<void(std::wstring, EndpointState)> reviseEndpointShowing);
|
||||||
|
void reviseEndpointShowing(std::wstring endpointId, EndpointState state);
|
||||||
|
void setRemoveEndpointWidgetFunction(std::function<void(uint64_t)> removeEndpointWidget);
|
||||||
|
void setAddEndpointWidgetFunction(std::function<void(EndpointHandler*)> addEndpointWidget);
|
||||||
|
|
||||||
|
void setEndpointHandlers(std::vector<EndpointHandler*> ephs);
|
||||||
|
std::vector<EndpointHandler*> getPlaybackEndpointHandlers();
|
||||||
|
std::vector<EndpointHandler*> getCaptureEndpointHandlers();
|
||||||
|
std::vector<Endpoint*> getPlaybackEndpoints();
|
||||||
|
std::vector<Endpoint*> getCaptureEndpoints();
|
||||||
|
void pushBackEndpointHandler(EndpointHandler* eph, Flows flow);
|
||||||
|
uint64_t getPlaybackEndpointsCount();
|
||||||
|
uint64_t getCaptureEndpointsCount();
|
||||||
|
void reloadEndpointHandlers();
|
||||||
|
EndpointHandler* addEndpoint(std::wstring endpointId, Flows *flow);
|
||||||
|
NGuid getGuid();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* void setSessionVolumeCallback(std::function<void(float)> changeSessionVolume);
|
||||||
|
* void setSessionVolume(float newValue, );
|
||||||
|
*/
|
||||||
|
|
||||||
private:
|
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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
79
src/cont/contsessionclasses.cpp
Normal file
79
src/cont/contsessionclasses.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
42
src/cont/contsessionclasses.h
Normal file
42
src/cont/contsessionclasses.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
//#include "contclasses.h"
|
||||||
|
|
||||||
|
class EndpointHandler;
|
||||||
|
class Session;
|
||||||
|
class SessionStateCallback;
|
||||||
|
|
||||||
|
struct SessionVolumeInfo {
|
||||||
|
//SessionVolumeInfo(bool muted, float mainVolume);
|
||||||
|
bool muted;
|
||||||
|
float mainVolume;
|
||||||
|
NGuid caller;
|
||||||
|
|
||||||
|
//size_t channels;
|
||||||
|
//std::vector<float> channelVolumes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SessionHandler {
|
||||||
|
public:
|
||||||
|
SessionHandler(EndpointHandler* eph, Session* session, size_t idx);
|
||||||
|
void setVolume(NGuid guid, int channel, int value);
|
||||||
|
float getVolume(int channel);
|
||||||
|
void setMute(NGuid guid, bool muted);
|
||||||
|
bool getMute();
|
||||||
|
void setFrontIndex(uint64_t frontIdx);
|
||||||
|
SessionState getState();
|
||||||
|
void setState(SessionState state);
|
||||||
|
uint64_t getFrontIndex();
|
||||||
|
std::wstring getName();
|
||||||
|
void reviseSessionShowing(SessionState state);
|
||||||
|
SessionVolumeInfo* getVolumeInfo();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SessionVolumeInfo svi;
|
||||||
|
EndpointHandler* eph;
|
||||||
|
Session* session;
|
||||||
|
SessionStateCallback* ssc;
|
||||||
|
size_t idx;
|
||||||
|
uint64_t frontIdx = INT_MAX;
|
||||||
|
};
|
||||||
47
src/debug.h
Normal file
47
src/debug.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG)
|
||||||
|
|
||||||
|
template<size_t Y, typename T>
|
||||||
|
std::bitset<Y> varToBitset(T info) {
|
||||||
|
std::bitset<Y> content(info);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
#ifndef _WIN32
|
||||||
|
#define log_debugcpp(str) do { \
|
||||||
|
std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define log_wdebugcpp(str) do { \
|
||||||
|
std::wcout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <debugapi.h>
|
||||||
|
#define WIDE2(x) L##x
|
||||||
|
#define WIDE1(x) WIDE2(x)
|
||||||
|
#define WFILE WIDE1(__FILE__)
|
||||||
|
#define log_debugcpp(str) { \
|
||||||
|
OutputDebugStringA(std::string("[DEBUG] (" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "): " + std::string(str) + "\n").c_str()); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define log_wdebugcpp(str) do { \
|
||||||
|
OutputDebugStringW(std::wstring(L"[DEBUG] (" + std::wstring(WFILE) + L":" + std::to_wstring(__LINE__) + L"): " + std::wstring(str) +L"\n").c_str()); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define print_as_binary(len, type, info) varToBitset<len, type>(info)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define log_debugcpp(str)
|
||||||
|
#define log_wdebugcpp(str)
|
||||||
|
#define print_as_binary(len, type, info)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Here as a quick reference, in case smthn similar is needed again */
|
||||||
|
/* typedef void (EndpointWidget::*epwMuteFunc)(bool muted); */
|
||||||
|
/* typedef void (EndpointWidget::*epwMainVolumeFunc)(float newValue); */
|
||||||
|
/* typedef void (EndpointWidget::*epwChannelVolumeFunc)(uint32_t channel, float newValue); */
|
||||||
|
/* typedef void (EndpointWidget::*epwToggleFrontFunc)(bool active); */
|
||||||
|
|
||||||
84
src/global.h
84
src/global.h
|
|
@ -1,4 +1,82 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define log_debugcpp(str) do { \
|
|
||||||
std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
|
#include <vector>
|
||||||
} while (0)
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <bitset>
|
||||||
|
#include <climits>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
//TODO: Use tr();? QTranslator
|
||||||
|
#define STRING_MUTE "Mute"
|
||||||
|
#define STRING_UNMUTE "Unmute"
|
||||||
|
#define STRING_QUIT "Quit"
|
||||||
|
#define STRING_TITLE "Mixer Fachero"
|
||||||
|
|
||||||
|
#define STRING_ROLE_CONSOLE "Console"
|
||||||
|
#define STRING_ROLE_MULTIMEDIA "Multimedia"
|
||||||
|
#define STRING_ROLE_COMMUNICATIONS "Communications"
|
||||||
|
#define STRING_ROLE_ALL "All"
|
||||||
|
|
||||||
|
#define STRING_SYSTEM_SOUNDS "System Sounds"
|
||||||
|
#define LSTRING_SYSTEM_SOUNDS L"System Sounds"
|
||||||
|
//INIT BACK
|
||||||
|
|
||||||
|
enum AudioChannel {
|
||||||
|
CHANNEL_LEFT = (1 << 0),
|
||||||
|
CHANNEL_RIGHT = (1 << 1),
|
||||||
|
CHANNEL_MAIN = ~0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EndpointState {
|
||||||
|
ENDPOINT_ACTIVE = (1 << 0),
|
||||||
|
ENDPOINT_DISABLED = (1 << 1),
|
||||||
|
ENDPOINT_NOTPRESENT = (1 << 2),
|
||||||
|
ENDPOINT_UNPLUGGED = (1 << 3),
|
||||||
|
ENDPOINT_ALL = 0x0F
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SessionState {
|
||||||
|
ACTIVE = (1 << 0),
|
||||||
|
INACTIVE = (1 << 1),
|
||||||
|
EXPIRED = (1 << 2),
|
||||||
|
DISCONNECTED = (1 << 3),
|
||||||
|
ALL = 0x0F
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Flows {
|
||||||
|
FLOW_PLAYBACK = (1 << 0),
|
||||||
|
FLOW_CAPTURE = (1 << 1),
|
||||||
|
FLOW_BOTH = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Roles {
|
||||||
|
ROLE_CONSOLE = (1 << 0),
|
||||||
|
ROLE_MULTIMEDIA = (1 << 1),
|
||||||
|
ROLE_COMMUNICATIONS = (1 << 2),
|
||||||
|
ROLE_ALL = 0x07,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NGuid {
|
||||||
|
//todo: still leaking?
|
||||||
|
uint32_t data1;
|
||||||
|
uint16_t data2;
|
||||||
|
uint16_t data3;
|
||||||
|
unsigned char data4[8];
|
||||||
|
|
||||||
|
|
||||||
|
/* void freeData4(){ */
|
||||||
|
/* int i = 0; */
|
||||||
|
/* do{ */
|
||||||
|
/* if(this->data4 + i != nullptr) free(data4 + i); */
|
||||||
|
/* i++; */
|
||||||
|
/* }while (i < 8); */
|
||||||
|
/* } */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OverseerHandler;
|
||||||
|
extern OverseerHandler *osh;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,584 @@
|
||||||
#include "qtclasses.h"
|
#include "qtclasses.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(std::vector<EndpointHandler*> *ephs, QWidget *parent) : QMainWindow(parent) {
|
template <typename T>
|
||||||
// setWindowState(Qt::WindowFullScreen);
|
CustomWidgetEvent<T>::CustomWidgetEvent(QEvent::Type type, T payload) : QEvent(type){
|
||||||
// setCentralWidget(centralWidget);
|
this->payload = payload;
|
||||||
widget = new QWidget();
|
|
||||||
layout = new QGridLayout();
|
|
||||||
|
|
||||||
widget->setLayout(layout);
|
|
||||||
setCentralWidget(widget);
|
|
||||||
//layout->addWidget(pintas, 0, 0);
|
|
||||||
|
|
||||||
setWindowTitle("slidea resbala nu c");
|
|
||||||
|
|
||||||
setEndpointHandlers(ephs);
|
|
||||||
for (unsigned int i = 0; i < this->ephs->size(); i++){
|
|
||||||
QLabel *pintas = new QLabel(ephs->at(i)->getName());
|
|
||||||
QSlider *teSlider = new QSlider(Qt::Horizontal);
|
|
||||||
teSlider->setFocusPolicy(Qt::StrongFocus);
|
|
||||||
teSlider->setTickPosition(QSlider::TicksBothSides);
|
|
||||||
teSlider->setTickInterval(5);
|
|
||||||
teSlider->setSingleStep(1);
|
|
||||||
teSlider->setRange(0,100);
|
|
||||||
float volume = ephs->at(i)->getVolume() * 100;
|
|
||||||
teSlider->setValue((int)volume);
|
|
||||||
log_debugcpp("ENDPOINT SET WITH VOLUME " << volume);
|
|
||||||
layout->addWidget(pintas, i, 0);
|
|
||||||
layout->addWidget(teSlider, i, 1);
|
|
||||||
connect(teSlider, &QSlider::valueChanged, ephs->at(i), &EndpointHandler::setValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setEndpointHandlers(std::vector<EndpointHandler*> *ephs){
|
void ExtendedCheckBox::customEvent(QEvent* ev) {
|
||||||
this->ephs = ephs;
|
QEvent::Type tipo = ev->type();
|
||||||
|
if (ev->type() == (QEvent::Type)CustomQEvent::EndpointDefaultChange) {
|
||||||
|
//todo: still prone to bugs; whack-a-mole to come
|
||||||
|
ev->setAccepted(true);
|
||||||
|
this->blockSignals(true);
|
||||||
|
if (this->isEnabled()) {
|
||||||
|
this->setCheckState(Qt::Checked);
|
||||||
|
this->setDisabled(true);
|
||||||
|
} else {
|
||||||
|
this->setDisabled(false);
|
||||||
|
this->setCheckState(Qt::Unchecked);
|
||||||
|
}
|
||||||
|
this->blockSignals(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Make sure the rest of events are handled
|
||||||
|
QCheckBox::customEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionWidget::SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent) : QWidget(parent){
|
||||||
|
//todo: based on qgridlayout, name+mute should be its own widget, same with channels
|
||||||
|
this->idx = idx;
|
||||||
|
this->sh = sh;
|
||||||
|
|
||||||
|
layout = new QGridLayout(this);
|
||||||
|
//this->setLayout(
|
||||||
|
|
||||||
|
muteButton = new QCheckBox(this);
|
||||||
|
mainLabel = new QLabel(QString::fromStdWString(sh->getName()), this);
|
||||||
|
mainSlider = new QSlider(Qt::Horizontal, this);
|
||||||
|
|
||||||
|
mainSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
mainSlider->setFocusPolicy(Qt::StrongFocus);
|
||||||
|
mainSlider->setTickPosition(QSlider::TicksBothSides);
|
||||||
|
mainSlider->setTickInterval(5);
|
||||||
|
mainSlider->setSingleStep(1);
|
||||||
|
mainSlider->setRange(0,100);
|
||||||
|
|
||||||
|
muteButton->setCheckState((sh->getMute() == false ? Qt::Unchecked : Qt::Checked));
|
||||||
|
muteButton->setText(sh->getMute() ? STRING_UNMUTE : STRING_MUTE);
|
||||||
|
float volume = sh->getVolume(AudioChannel::CHANNEL_MAIN) * 100;
|
||||||
|
mainSlider->setValue((int)volume);
|
||||||
|
log_debugcpp("SESSION SET WITH VOLUME " + std::to_string(volume));
|
||||||
|
|
||||||
|
//tip: would need to be new widget with layout in it
|
||||||
|
//mainMuteLayout = new QGridLayout();
|
||||||
|
layout->addWidget(mainLabel, 0, 0, Qt::AlignLeft | Qt::AlignBottom);
|
||||||
|
layout->addWidget(muteButton, 0, 1, Qt::AlignLeft | Qt::AlignBottom);
|
||||||
|
layout->addWidget(mainSlider, 0, 2, 1, 2);
|
||||||
|
|
||||||
|
//TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option?
|
||||||
|
connect<void(QSlider::*)(int), void(SessionWidget::*)(int)>(mainSlider, &QSlider::valueChanged, this,&SessionWidget::updateMainVolume);
|
||||||
|
connect<void(QCheckBox::*)(int), void(SessionWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&SessionWidget::updateMute));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Session Volume Polling
|
||||||
|
*/
|
||||||
|
volumePoller = new QTimer();
|
||||||
|
connect(volumePoller, &QTimer::timeout, [this, sh](){
|
||||||
|
//if (memcmp(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid)) == 0) return; CHECK IF THIS PROGRAM GENERATED THE FUNSIES IS NO LONGER IN USE FOR NOW.
|
||||||
|
//todo: global + constexpr + ratio
|
||||||
|
const float roundingFactor = 0.005;
|
||||||
|
mainSlider->blockSignals(true);
|
||||||
|
muteButton->blockSignals(true);
|
||||||
|
mainSlider->setValue((int)((sh->getVolumeInfo()->mainVolume + roundingFactor) * 100));
|
||||||
|
muteButton->setCheckState((sh->getVolumeInfo()->muted == false ? Qt::Unchecked : Qt::Checked));
|
||||||
|
muteButton->setText(sh->getVolumeInfo()->muted ? STRING_UNMUTE : STRING_MUTE);
|
||||||
|
|
||||||
|
//memcpy(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid));
|
||||||
|
|
||||||
|
//TODO: el default = objcopy frees?
|
||||||
|
//Todo: like fr pregunta
|
||||||
|
sh->getVolumeInfo()->caller = osh->getGuid();
|
||||||
|
mainSlider->blockSignals(false);
|
||||||
|
muteButton->blockSignals(false);
|
||||||
|
});
|
||||||
|
volumePoller->start(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionWidget::updateMute(int checked){
|
||||||
|
bool muted = (checked == 2 ? true : false);
|
||||||
|
this->sh->setMute(osh->getGuid(), muted);
|
||||||
|
this->muteButton->setText(this->sh->getMute() ? STRING_UNMUTE : STRING_MUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionWidget::updateMainVolume(int newValue){
|
||||||
|
this->sh->setVolume(osh->getGuid(), AudioChannel::CHANNEL_MAIN, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionWidget::~SessionWidget() {
|
||||||
|
volumePoller->stop();
|
||||||
|
delete volumePoller;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *parent) : QWidget(parent){
|
||||||
|
//todo: based on qgridlayout, name+mute should be its own widget, same with channels
|
||||||
|
row = 0;
|
||||||
|
this->idx = idx;
|
||||||
|
this->eph = eph;
|
||||||
|
//todo: sussy
|
||||||
|
this->eph->setState(EndpointState::ENDPOINT_ACTIVE, idx);
|
||||||
|
|
||||||
|
layout = new QGridLayout(this);
|
||||||
|
//this->setLayout(layout);
|
||||||
|
log_debugcpp("epw main layout parent: " + std::to_string((intptr_t)(layout->parent())));
|
||||||
|
if (parent == nullptr) { log_debugcpp("ayooooo?"); }
|
||||||
|
|
||||||
|
defaultRolesCheckBoxes = {
|
||||||
|
{Roles::ROLE_ALL, new ExtendedCheckBox(this)},
|
||||||
|
{Roles::ROLE_CONSOLE, new ExtendedCheckBox(this)},
|
||||||
|
{Roles::ROLE_MULTIMEDIA, new ExtendedCheckBox(this)},
|
||||||
|
{Roles::ROLE_COMMUNICATIONS, new ExtendedCheckBox(this)}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mute, main slider and label setup
|
||||||
|
*/
|
||||||
|
muteButton = new QCheckBox(this);
|
||||||
|
mainLabel = new QLabel(QString::fromStdWString(eph->getName()), this);
|
||||||
|
mainSlider = new QSlider(Qt::Horizontal, this);
|
||||||
|
|
||||||
|
if (this->eph->getState() != EndpointState::ENDPOINT_ACTIVE) {
|
||||||
|
layout->addWidget(mainLabel, row, 0);
|
||||||
|
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 1, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//muteButton->setStyleSheet("background-color: #A3C1DA; color: red");
|
||||||
|
mainSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
mainSlider->setFocusPolicy(Qt::StrongFocus);
|
||||||
|
mainSlider->setTickPosition(QSlider::TicksBothSides);
|
||||||
|
mainSlider->setTickInterval(5);
|
||||||
|
mainSlider->setSingleStep(1);
|
||||||
|
mainSlider->setRange(0,100);
|
||||||
|
|
||||||
|
muteButton->setCheckState((eph->getMute() == false ? Qt::Unchecked : Qt::Checked));
|
||||||
|
muteButton->setText(eph->getMute() ? STRING_UNMUTE : STRING_MUTE);
|
||||||
|
float volume = eph->getVolume(AudioChannel::CHANNEL_MAIN) * 100;
|
||||||
|
mainSlider->setValue((int)volume);
|
||||||
|
log_debugcpp("ENDPOINT SET WITH VOLUME " + std::to_string(volume));
|
||||||
|
|
||||||
|
//tip: would need to be new widget with layout in it
|
||||||
|
//mainMuteLayout = new QGridLayout();
|
||||||
|
layout->addWidget(mainLabel, row, 0, Qt::AlignLeft | Qt::AlignBottom);
|
||||||
|
layout->addWidget(muteButton, row, 1, Qt::AlignLeft | Qt::AlignBottom);
|
||||||
|
layout->addWidget(mainSlider, row, 2, 1, 2);
|
||||||
|
row++;
|
||||||
|
|
||||||
|
//TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option?
|
||||||
|
connect<void(QSlider::*)(int), void(EndpointWidget::*)(int)>(mainSlider, &QSlider::valueChanged, this,&EndpointWidget::updateMainVolume);
|
||||||
|
connect<void(QCheckBox::*)(int), void(EndpointWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&EndpointWidget::updateMute));
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Channel sliders setup
|
||||||
|
*/
|
||||||
|
uint32_t epChannelCount = eph->getChannelCount();
|
||||||
|
for(uint32_t i = 0; i < epChannelCount && epChannelCount > 1; i++){
|
||||||
|
QSlider* tmp = new QSlider(Qt::Horizontal);
|
||||||
|
QLabel* tmpLb = new QLabel("");
|
||||||
|
tmp->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
tmp->setTickInterval(5);
|
||||||
|
tmp->setSingleStep(1);
|
||||||
|
tmp->setRange(0,100);
|
||||||
|
|
||||||
|
volume = eph->getVolume(i) * 100;
|
||||||
|
tmp->setValue((int) volume);
|
||||||
|
tmpLb->setText(QString::number(volume));
|
||||||
|
this->channelSliders.push_back(tmp);
|
||||||
|
this->channelLabels.push_back(tmpLb);
|
||||||
|
layout->addWidget(tmp, row + 1, i);
|
||||||
|
layout->addWidget(tmpLb, row + 2, i);
|
||||||
|
|
||||||
|
//TODO: check if there's a need to prevent deadlocks; probably this will eventually turn into its own func
|
||||||
|
//this causes channel bar desync when back -> front. blocksignals below fix it. huh.
|
||||||
|
connect(tmp, &QSlider::valueChanged, [this, i](int newValue){
|
||||||
|
this->eph->setVolume(osh->getGuid(), i, newValue);
|
||||||
|
this->channelLabels.at(i)->setText(QString::number(newValue));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
row += 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Role ExtendedCheckBoxes setup
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint8_t assignedRoles = eph->getRoles();
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setCheckState(assignedRoles == Roles::ROLE_ALL ? Qt::Checked : Qt::Unchecked);
|
||||||
|
//todo duditas de &
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setDisabled(assignedRoles == Roles::ROLE_ALL ? true : false);
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setText(STRING_ROLE_ALL);
|
||||||
|
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setCheckState(assignedRoles & Roles::ROLE_CONSOLE ? Qt::Checked : Qt::Unchecked);
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setDisabled(assignedRoles & Roles::ROLE_CONSOLE ? true : false);
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setText(STRING_ROLE_CONSOLE);
|
||||||
|
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setCheckState(assignedRoles & Roles::ROLE_MULTIMEDIA ? Qt::Checked : Qt::Unchecked);
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setDisabled(assignedRoles & Roles::ROLE_MULTIMEDIA ? true : false);
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setText(STRING_ROLE_MULTIMEDIA);
|
||||||
|
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setCheckState(assignedRoles & Roles::ROLE_COMMUNICATIONS ? Qt::Checked : Qt::Unchecked);
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setDisabled(assignedRoles & Roles::ROLE_COMMUNICATIONS ? true : false);
|
||||||
|
defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setText(STRING_ROLE_COMMUNICATIONS);
|
||||||
|
|
||||||
|
connect(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), &QCheckBox::stateChanged,[this] {
|
||||||
|
this->eph->setRoles(Roles::ROLE_ALL);
|
||||||
|
});
|
||||||
|
connect(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), &QCheckBox::stateChanged,[this] {
|
||||||
|
this->eph->setRoles(Roles::ROLE_CONSOLE);
|
||||||
|
});
|
||||||
|
connect(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), &QCheckBox::stateChanged,[this] {
|
||||||
|
this->eph->setRoles(Roles::ROLE_MULTIMEDIA);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), &QCheckBox::stateChanged,[this] {
|
||||||
|
this->eph->setRoles(Roles::ROLE_COMMUNICATIONS);
|
||||||
|
});
|
||||||
|
|
||||||
|
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), row, 0);
|
||||||
|
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), row, 1);
|
||||||
|
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), row, 2);
|
||||||
|
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), row, 3);
|
||||||
|
row++;
|
||||||
|
/* ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EndpointVolume Polling time
|
||||||
|
*/
|
||||||
|
timer = new QTimer();
|
||||||
|
connect(timer, &QTimer::timeout, [this, eph](){
|
||||||
|
//if (memcmp(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid)) == 0) return; CHECK IF THIS PROGRAM GENERATED THE FUNSIES IS NO LONGER IN USE FOR NOW.
|
||||||
|
//todo: global + constexpr + ratio
|
||||||
|
const float roundingFactor = 0.005;
|
||||||
|
mainSlider->blockSignals(true);
|
||||||
|
muteButton->blockSignals(true);
|
||||||
|
mainSlider->setValue((int)((eph->getCallbackInfo()->mainVolume + roundingFactor) * 100));
|
||||||
|
muteButton->setCheckState((eph->getCallbackInfo()->muted == false ? Qt::Unchecked : Qt::Checked));
|
||||||
|
muteButton->setText(eph->getCallbackInfo()->muted ? STRING_UNMUTE : STRING_MUTE);
|
||||||
|
for(uint32_t i = 0; i < eph->getCallbackInfo()->channels && eph->getChannelCount() > 1; i++){
|
||||||
|
this->channelSliders.at(i)->blockSignals(true);
|
||||||
|
this->channelSliders.at(i)->setValue((int)((eph->getCallbackInfo()->channelVolumes[i] + roundingFactor) * 100));
|
||||||
|
this->channelLabels.at(i)->setText(QString::number((int)((eph->getCallbackInfo()->channelVolumes[i] + roundingFactor) * 100)));
|
||||||
|
this->channelSliders.at(i)->blockSignals(false);
|
||||||
|
}
|
||||||
|
//memcpy(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid));
|
||||||
|
|
||||||
|
//TODO: el default = objcopy frees?
|
||||||
|
//Todo: like fr pregunta
|
||||||
|
eph->getCallbackInfo()->caller = osh->getGuid();
|
||||||
|
mainSlider->blockSignals(false);
|
||||||
|
muteButton->blockSignals(false);
|
||||||
|
});
|
||||||
|
timer->start(10);
|
||||||
|
|
||||||
|
/* First SessionWidget batch */
|
||||||
|
for (size_t i = 0; i < eph->getSessionCount(); i++) {
|
||||||
|
SessionWidget* sessionWidget = new SessionWidget(i, eph->getSessionHandlers().at(i), this);
|
||||||
|
layout->addWidget(sessionWidget, row, 4);
|
||||||
|
row++;
|
||||||
|
sessionWidgets.push_back(sessionWidget);
|
||||||
|
eph->getSessionHandlers().at(i)->setFrontIndex(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add/Remove SessionWidget callback */
|
||||||
|
eph->setAddSessionWidgetFunction([this](SessionHandler* sessionHandler) {
|
||||||
|
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<SessionHandler*>((QEvent::Type)CustomQEvent::SessionWidgetCreated, sessionHandler));
|
||||||
|
});
|
||||||
|
|
||||||
|
eph->setRemoveSessionWidgetFunction([this](SessionHandler* sessionHandler) {
|
||||||
|
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<SessionHandler*>((QEvent::Type)CustomQEvent::SessionWidgetObsolete, sessionHandler));
|
||||||
|
});
|
||||||
|
|
||||||
|
//todo parent?
|
||||||
|
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 1, 0);
|
||||||
|
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 4, 0);
|
||||||
|
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 6, 0);
|
||||||
|
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 6, 1);
|
||||||
|
log_debugcpp("ENDPOINT_WIDGETED");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointWidget::addSessionWidget(CustomWidgetEvent<SessionHandler*>* ev){
|
||||||
|
uint64_t index = this->sessionWidgets.size();
|
||||||
|
SessionWidget* sw = new SessionWidget(index, ev->payload, this);
|
||||||
|
ev->payload->setFrontIndex(index);
|
||||||
|
this->layout->addWidget(sw, row, 4);
|
||||||
|
row++;
|
||||||
|
sessionWidgets.push_back(sw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointWidget::removeSessionWidget(CustomWidgetEvent<SessionHandler*>* ev){
|
||||||
|
uint64_t i = ev->payload->getFrontIndex();
|
||||||
|
this->sessionWidgets.at(i)->setParent(nullptr);
|
||||||
|
this->layout->removeWidget(sessionWidgets.at(i));
|
||||||
|
delete sessionWidgets.at(i);
|
||||||
|
sessionWidgets.at(i) = nullptr;
|
||||||
|
ev->payload->setFrontIndex(INT_MAX);
|
||||||
|
//this->sessionWidgetsUpdateTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointWidget::customEvent(QEvent* ev) {
|
||||||
|
if (ev->type() == (QEvent::Type)CustomQEvent::SessionWidgetCreated) {
|
||||||
|
ev->setAccepted(true);
|
||||||
|
this->addSessionWidget((CustomWidgetEvent<SessionHandler*>*) ev);
|
||||||
|
} else if (ev->type() == (QEvent::Type)CustomQEvent::SessionWidgetObsolete) {
|
||||||
|
ev->setAccepted(true);
|
||||||
|
this->removeSessionWidget((CustomWidgetEvent<SessionHandler*>*) ev);
|
||||||
|
}
|
||||||
|
QWidget::customEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EndpointWidget::~EndpointWidget() {
|
||||||
|
timer->stop();
|
||||||
|
delete timer;
|
||||||
|
this->eph->setFrontVisibilityInfo(EndpointState::ENDPOINT_ALL, INT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::customEvent(QEvent* ev) {
|
||||||
|
if (ev->type() == CustomQEvent::EndpointWidgetObsolete) {
|
||||||
|
ev->setAccepted(true);
|
||||||
|
this->removeEndpointWidget((CustomWidgetEvent<uint64_t>*)ev);
|
||||||
|
} else if (ev->type() == (QEvent::Type)CustomQEvent::EndpointWidgetCreated) {
|
||||||
|
ev->setAccepted(true);
|
||||||
|
this->addEndpointWidget((CustomWidgetEvent<EndpointHandler*>*)ev);
|
||||||
|
}
|
||||||
|
QMainWindow::customEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::removeEndpointWidget(CustomWidgetEvent<uint64_t>* ev){
|
||||||
|
uint64_t i = ev->payload;
|
||||||
|
this->ews.at(i)->setParent(nullptr);
|
||||||
|
this->layout->removeWidget(ews.at(i));
|
||||||
|
//uint64_t saisu = ews.size();
|
||||||
|
//delete ews.at(index);
|
||||||
|
delete ews.at(i);
|
||||||
|
ews.at(i) = nullptr;
|
||||||
|
this->ewsUpdateTimer->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::addEndpointWidget(CustomWidgetEvent<EndpointHandler*>* ev){
|
||||||
|
EndpointWidget* epw = new EndpointWidget(this->ews.size(), ev->payload, widget);
|
||||||
|
this->layout->addWidget(epw);
|
||||||
|
ews.push_back(epw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::reorderEndpointWidgetCollection() {
|
||||||
|
/* Flatten */
|
||||||
|
size_t firstNullPosition = 0;
|
||||||
|
size_t ewsSize = ews.size();
|
||||||
|
bool breakSorting = false;
|
||||||
|
|
||||||
|
//todo: is all of gui really atomic by definition? im afraid of cutting through amazing add momentos, but I think I did my homework. Must check back.
|
||||||
|
for (size_t i = 0; i < ewsSize; i++) {
|
||||||
|
if (ews.at(i) == nullptr) {
|
||||||
|
for (size_t j = (i + 1); j < ewsSize; j++) {
|
||||||
|
|
||||||
|
if (ews.at(j) != nullptr) {
|
||||||
|
ews.at(i) = ews.at(j);
|
||||||
|
ews.at(i)->setIndex(i);
|
||||||
|
ews.at(j) = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j == ewsSize - 1) {
|
||||||
|
firstNullPosition = i;
|
||||||
|
breakSorting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (breakSorting) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ews.resize(firstNullPosition + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointWidget::updateMute(int checked){
|
||||||
|
bool muted = (checked == 2 ? true : false);
|
||||||
|
this->eph->setMute(osh->getGuid(), muted);
|
||||||
|
this->muteButton->setText(this->eph->getMute() ? STRING_UNMUTE : STRING_MUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointWidget::updateMainVolume(int newValue){
|
||||||
|
this->eph->setVolume(osh->getGuid(), AudioChannel::CHANNEL_MAIN, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* void MainWindow::setPlotButton() {
|
* void EndpointWidget::updateVolume(uint32_t channel, float newValue){
|
||||||
* button = new QPushButton("push"),
|
* //this->blockSignals(true);
|
||||||
* button->setCheckable(true);
|
* int newVal = newValue * 100;
|
||||||
* connect(button, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)))
|
* if (channel == (uint32_t)AudioChannel::CHANNEL_MAIN) {
|
||||||
* QHBoxLayout *plotsLayout = new QHBoxLayout;
|
* //TIP: Above
|
||||||
* plotsLayout->setSpacing(10);
|
* //this->mainSlider->blockSignals(true);
|
||||||
* plotsLayout->addWidget(funPlot);
|
*
|
||||||
* QHBoxLayout *buttonsLayout = new QHBoxLayout ;
|
* if(this->mainSlider->value() != newVal) {
|
||||||
* buttonsLayout->addWidget(button);
|
* this->mainSlider->blockSignals(true);
|
||||||
* QVBoxLayout *widgetLayout = new QVBoxLayout;
|
* this->mainSlider->setValue(newVal);
|
||||||
* widgetLayout->addLayout(plotsLayout);
|
* this->mainSlider->blockSignals(false);
|
||||||
* widgetLayout->addLayout(buttonsLayout);
|
* }
|
||||||
* setLayout(widgetLayout);
|
* return;
|
||||||
* ...
|
* }
|
||||||
|
*
|
||||||
|
* for (size_t i = 0; i < sizeof(uint32_t) * 8 && i < channelSliders.size(); ++i) {
|
||||||
|
* if (((channel >> i) & 1) && this->channelSliders.at(i)->value() != newVal) {
|
||||||
|
* //this->channelSliders.at(i)->blockSignals(true);
|
||||||
|
*
|
||||||
|
* this->channelSliders.at(i)->setValue(newVal);
|
||||||
|
* this->channelLabels.at(i)->setText(QString::number((int)(newValue * 100)));
|
||||||
|
*
|
||||||
|
* //this->channelSliders.at(i)->blockSignals(false);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* //this->blockSignals(false);
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
EndpointHandler* EndpointWidget::getEndpointHandler(){
|
||||||
|
return this->eph;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* void EndpointWidget::updateFrontIndex(uint64_t index){
|
||||||
|
* this->idx = index;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
void EndpointWidget::setIndex(uint64_t idx){
|
||||||
|
this->idx = idx;
|
||||||
|
this->eph->setFrontVisibilityInfo(EndpointState::ENDPOINT_ACTIVE, this->idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t EndpointWidget::getIndex(){
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<Roles, ExtendedCheckBox*> EndpointWidget::getDefaultRolesWidgets() {
|
||||||
|
return defaultRolesCheckBoxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
||||||
|
// setWindowState(Qt::WindowFullScreen);
|
||||||
|
// setCentralWidget(centralWidget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registering needed custom events
|
||||||
|
*/
|
||||||
|
QEvent::registerEventType(CustomQEvent::EndpointWidgetObsolete);
|
||||||
|
QEvent::registerEventType(CustomQEvent::EndpointWidgetCreated);
|
||||||
|
QEvent::registerEventType(CustomQEvent::EndpointDefaultChange);
|
||||||
|
|
||||||
|
ewsUpdateTimer = new QTimer(this);
|
||||||
|
widget = new QWidget();
|
||||||
|
layout = new QGridLayout();
|
||||||
|
trayIcon = new QSystemTrayIcon();
|
||||||
|
trayIconMenu = new QMenu();
|
||||||
|
trayIconMenuQuit = new QAction(STRING_QUIT);
|
||||||
|
|
||||||
|
ewsUpdateTimer->setSingleShot(true);
|
||||||
|
ewsUpdateTimer->setInterval(ewsUpdateTimerFrequency);
|
||||||
|
connect(ewsUpdateTimer, &QTimer::timeout, this, &MainWindow::reorderEndpointWidgetCollection);
|
||||||
|
widget->setLayout(layout);
|
||||||
|
setCentralWidget(widget);
|
||||||
|
//layout->addWidget(pintas, 0, 0);
|
||||||
|
setWindowTitle(STRING_TITLE);
|
||||||
|
|
||||||
|
reloadEndpointWidgets();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tray Icon code
|
||||||
|
*/
|
||||||
|
trayIconMenu->addSeparator();
|
||||||
|
trayIconMenu->addAction(trayIconMenuQuit);
|
||||||
|
connect(trayIconMenuQuit, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||||
|
trayIcon->setIcon(QIcon(":/assets/notificationAreaIcon.png"));
|
||||||
|
setWindowIcon(QIcon(":/assets/notificationAreaIcon.png"));
|
||||||
|
//TODO: Extend qsystemtrayicon to change mouse click?
|
||||||
|
//show before setting tooltip required; smells like bug to me!
|
||||||
|
trayIcon->show();
|
||||||
|
trayIcon->setToolTip(STRING_TITLE);
|
||||||
|
trayIcon->setContextMenu(trayIconMenu);
|
||||||
|
connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set of function callback definitons for EndpointSituationCallback
|
||||||
|
*/
|
||||||
|
osh->setChangeFrontDefaultsFunction([this](Roles role, std::wstring endpointId) {
|
||||||
|
for (auto epw : this->ews) {
|
||||||
|
/*
|
||||||
|
* Is this the new default endpoint?
|
||||||
|
*/
|
||||||
|
if (epw->getEndpointHandler()->getId() == endpointId) {
|
||||||
|
//not necessary to keep endpointState flags up to date right now, but updating it will allow for later config files / profiles
|
||||||
|
epw->getDefaultRolesWidgets().at(role)->blockSignals(true);
|
||||||
|
epw->getEndpointHandler()->assignRoles(role);
|
||||||
|
epw->getDefaultRolesWidgets().at(role)->blockSignals(false);
|
||||||
|
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(role), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
|
||||||
|
//epw->defaultRolesCheckBoxes.at(role)->postEnableChange();
|
||||||
|
/*
|
||||||
|
* And were you THE default?
|
||||||
|
*/
|
||||||
|
if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) {
|
||||||
|
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(Roles::ROLE_ALL), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Are you the dethroned king?
|
||||||
|
*/
|
||||||
|
} else if (epw->getEndpointHandler()->getRoles() & role) {
|
||||||
|
/*
|
||||||
|
* And were you THE default up until now?
|
||||||
|
*/
|
||||||
|
if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) {
|
||||||
|
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(Roles::ROLE_ALL), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
|
||||||
|
}
|
||||||
|
|
||||||
|
epw->getDefaultRolesWidgets().at(role)->blockSignals(true);
|
||||||
|
//Same as before. ini-san will come...
|
||||||
|
epw->getEndpointHandler()->removeRoles(role);
|
||||||
|
epw->getDefaultRolesWidgets().at(role)->blockSignals(false);
|
||||||
|
QCoreApplication::instance()->postEvent(epw->getDefaultRolesWidgets().at(role), new QEvent((QEvent::Type)CustomQEvent::EndpointDefaultChange));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
osh->setRemoveEndpointWidgetFunction([this](uint64_t index) {
|
||||||
|
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<uint64_t>((QEvent::Type)CustomQEvent::EndpointWidgetObsolete, index));
|
||||||
|
});
|
||||||
|
|
||||||
|
osh->setAddEndpointWidgetFunction([this](EndpointHandler* eph) {
|
||||||
|
QCoreApplication::instance()->postEvent(this, new CustomWidgetEvent<EndpointHandler*>((QEvent::Type)CustomQEvent::EndpointWidgetCreated, eph));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::closeEvent(QCloseEvent *event) {
|
||||||
|
if (!event->spontaneous() || !isVisible()) return;
|
||||||
|
|
||||||
|
if (trayIcon->isVisible()) {
|
||||||
|
//todo: would be nice to show this to 1st time users; ini-san will come...
|
||||||
|
//this->trayIcon->showMessage("ini file calling","tratarte como un gilipollas la primera vez", QSystemTrayIcon::Information);
|
||||||
|
|
||||||
|
hide();
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason) {
|
||||||
|
switch (reason) {
|
||||||
|
case QSystemTrayIcon::Trigger:
|
||||||
|
this->showNormal();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::reloadEndpointWidgets() {
|
||||||
|
size_t i = 0;
|
||||||
|
for (size_t epwIndex = 0; i < (osh->getPlaybackEndpointHandlers().size()); i++) {
|
||||||
|
if (osh->getPlaybackEndpointHandlers().at(i)->getState() == EndpointState::ENDPOINT_ACTIVE){
|
||||||
|
log_debugcpp("EPWidget creation");
|
||||||
|
//osh->getPlaybackEndpointHandlers().at(i)->getCallbackInfo()->caller = osh->getGuid();
|
||||||
|
EndpointWidget *epw = new EndpointWidget(epwIndex, osh->getPlaybackEndpointHandlers().at(i), widget);
|
||||||
|
epwIndex++;
|
||||||
|
//alfinal estoes solopara inicializarlmao
|
||||||
|
ews.push_back(epw);
|
||||||
|
layout->addWidget(epw, i, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//todo:: tas aqui tirao, no me gustas y probablemente yo a ti tampoco
|
||||||
|
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,200 @@
|
||||||
#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 "global.h"
|
#include <QPushButton>
|
||||||
#include "contclasses.h"
|
#include <QCheckBox>
|
||||||
//#include <Q>
|
#include <QTimer>
|
||||||
//#include <QWidgets>
|
/*
|
||||||
|
* #else
|
||||||
|
* class QSlider;
|
||||||
|
* class QLabel;
|
||||||
|
* class QGridLayout;
|
||||||
|
* class QPushButton;
|
||||||
|
* class QWidget;
|
||||||
|
* class QMainWindow;
|
||||||
|
* #endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "contclasses.h"
|
||||||
|
//class EndpointHandler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* class ToggleButton : public QAbstractButton {
|
||||||
|
* Q_OBJECT
|
||||||
|
*
|
||||||
|
* public:
|
||||||
|
* ToggleButton(QWidget *parent = nullptr);
|
||||||
|
* void checkStateSet();
|
||||||
|
* bool hitButton(const QPoint &pos) const;
|
||||||
|
* void nextCheckState();
|
||||||
|
* void changeEvent(QEvent *e) override;
|
||||||
|
* bool event(QEvent *e) override;
|
||||||
|
* void focusInEvent(QFocusEvent *e) override;
|
||||||
|
* void focusOutEvent(QFocusEvent *e) override;
|
||||||
|
* void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
* void keyReleaseEvent(QKeyEvent *e) override;
|
||||||
|
* void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
* void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
* void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
* void paintEvent(QPaintEvent *e) override = 0;
|
||||||
|
* void timerEvent(QTimerEvent *e) override;
|
||||||
|
* ToggleButton(QWidget *parent = nullptr);
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
enum CustomQEvent {
|
||||||
|
EndpointWidgetObsolete = 1001,
|
||||||
|
EndpointWidgetCreated = 1002,
|
||||||
|
EndpointDefaultChange = 1003,
|
||||||
|
SessionWidgetCreated = 1004,
|
||||||
|
SessionWidgetObsolete = 1005
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class CustomWidgetEvent : public QEvent {
|
||||||
|
|
||||||
|
public:
|
||||||
|
CustomWidgetEvent(QEvent::Type type, T payload);
|
||||||
|
T payload;
|
||||||
|
|
||||||
|
};
|
||||||
|
//Q_DECLARE_METATYPE(EndpointWidgetEvent)
|
||||||
|
|
||||||
|
class ExtendedCheckBox : public QCheckBox {
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
void customEvent(QEvent* ev) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//c++11: this inherits all parent's constructors unconditionally
|
||||||
|
using QCheckBox::QCheckBox;
|
||||||
|
//alternative being calling parent ctor directly after declaring child ctor:
|
||||||
|
//B(int x) : A(x) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SessionWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent /* = nullptr */);
|
||||||
|
~SessionWidget();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateMainVolume(int newValue);
|
||||||
|
void updateMute(int checked);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *mainLabel = nullptr;
|
||||||
|
QSlider *mainSlider = nullptr;
|
||||||
|
uint64_t idx;
|
||||||
|
QGridLayout *layout = nullptr;
|
||||||
|
QCheckBox *muteButton = nullptr;
|
||||||
|
SessionHandler* sh;
|
||||||
|
QTimer* volumePoller = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EndpointWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
EndpointHandler* getEndpointHandler();
|
||||||
|
std::map<Roles, ExtendedCheckBox*> getDefaultRolesWidgets();
|
||||||
|
|
||||||
|
void setIndex(uint64_t idx);
|
||||||
|
uint64_t getIndex();
|
||||||
|
void setVolume(int channel, float volume);
|
||||||
|
|
||||||
|
~EndpointWidget();
|
||||||
|
//void updateMainVolume(float newValue);
|
||||||
|
//void updateVolume(uint32_t channel, float newValue);
|
||||||
|
//void updateMute(bool muted);
|
||||||
|
|
||||||
|
//void populateEndpointWidget(EndpointHandler *eph);
|
||||||
|
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateMainVolume(int newValue);
|
||||||
|
void updateMute(int checked);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void customEvent(QEvent* ev) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void addSessionWidget(CustomWidgetEvent<SessionHandler*>* ev);
|
||||||
|
void removeSessionWidget(CustomWidgetEvent<SessionHandler*>* ev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int row;
|
||||||
|
QCheckBox *muteButton = nullptr;
|
||||||
|
QLabel *mainLabel = nullptr, *leftChannelLabel = nullptr, *rightChannelLabel = nullptr;
|
||||||
|
QSlider *mainSlider = nullptr;
|
||||||
|
std::vector<QSlider*> channelSliders;
|
||||||
|
std::vector<QLabel*> channelLabels;
|
||||||
|
QGridLayout *layout = nullptr;
|
||||||
|
QGridLayout *mainMuteLayout = nullptr;
|
||||||
|
std::map<Roles, ExtendedCheckBox*> defaultRolesCheckBoxes;
|
||||||
|
|
||||||
|
EndpointHandler* eph;
|
||||||
|
size_t defaultRolesVectorSize = 4;
|
||||||
|
QTimer* timer = nullptr;
|
||||||
|
uint64_t idx;
|
||||||
|
std::vector<SessionWidget*> sessionWidgets;
|
||||||
|
//std::vector<EndpointHandler*> *ephs;
|
||||||
|
//std::vector<QSlider> *sliders;
|
||||||
|
|
||||||
|
//signals:
|
||||||
|
//void valueChanged(int value);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
//QWidget *centralWidget;
|
//QWidget *centralWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MainWindow(std::vector<EndpointHandler*> *ephs, QWidget *parent = nullptr);
|
MainWindow(QWidget *parent = nullptr);
|
||||||
void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
void reloadEndpointWidgets();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
void customEvent(QEvent* ev) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||||
|
void removeEndpointWidget(CustomWidgetEvent<uint64_t>* ev);
|
||||||
|
void addEndpointWidget(CustomWidgetEvent<EndpointHandler*>* ev);
|
||||||
|
void reorderEndpointWidgetCollection();
|
||||||
|
//TODO: destroy/empty existing EndpointWidgets
|
||||||
|
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<EndpointHandler*> *ephs;
|
//std::vector<EndpointHandler*> *ephs;
|
||||||
std::vector<QSlider> *sliders;
|
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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +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"
|
||||||
//TODO david #include "backlasses.h"
|
#include "global.h"
|
||||||
|
|
||||||
|
OverseerHandler *osh = nullptr;
|
||||||
//INIT BACK
|
|
||||||
OverseerHandler *osh = new OverseerHandler();
|
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue