diff --git a/.gitignore b/.gitignore
index fde2162..a4ce7f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
build
*.rdbg
*.pdb
+*.ps1
+*.exe
Makefile
Makefile.Debug
Makefile.Release
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cf1a785
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# Mixer
+
+## Build
+
+* Toolchain: [llvm-mingw UCRT 20220906](https://github.com/mstorsjo/llvm-mingw/releases/tag/20220906).
+
+* Clone [this](https://code.qt.io/cgit/qt/qt5.git/tag/?h=v6.3.2) Qt branch
+
+* Build Qt from sources following [this](https://wiki.qt.io/Building_Qt_6_from_Git) guide and executing `configure.bat` as such:
+
+```
+..\qt6\configure.bat -prefix ..\install -static -debug -opensource -confirm-license -qt-zlib -qt-libpng -qt-webp -qt-libjpeg -qt-freetype -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquick3dphysics -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtsensors -skip qtwayland -skip qtwebglplugin -skip qtwebview -skip webengine -nomake examples -nomake tests
+```
+
+* Clone this repo and execute `bueno.bat`.
\ No newline at end of file
diff --git a/assets.qrc b/assets.qrc
new file mode 100644
index 0000000..2206a8a
--- /dev/null
+++ b/assets.qrc
@@ -0,0 +1,10 @@
+
+
+ assets/selawk.ttf
+ assets/notificationAreaIcon.png
+ assets/style.qss
+ assets/logo.ico
+ assets/mute.svg
+ assets/unmute.svg
+
+
diff --git a/assets/installer.ico b/assets/installer.ico
new file mode 100644
index 0000000..b4e6f82
Binary files /dev/null and b/assets/installer.ico differ
diff --git a/assets/installer.xcf b/assets/installer.xcf
new file mode 100644
index 0000000..96669f1
Binary files /dev/null and b/assets/installer.xcf differ
diff --git a/assets/logo.ico b/assets/logo.ico
new file mode 100644
index 0000000..daac4a4
Binary files /dev/null and b/assets/logo.ico differ
diff --git a/assets/logo.png b/assets/logo.png
new file mode 100644
index 0000000..259e37b
Binary files /dev/null and b/assets/logo.png differ
diff --git a/assets/logo.xcf b/assets/logo.xcf
new file mode 100644
index 0000000..69cafac
Binary files /dev/null and b/assets/logo.xcf differ
diff --git a/assets/notificationAreaIcon.png b/assets/notificationAreaIcon.png
new file mode 100644
index 0000000..0252332
Binary files /dev/null and b/assets/notificationAreaIcon.png differ
diff --git a/assets/selawk.ttf b/assets/selawk.ttf
new file mode 100644
index 0000000..736bac3
Binary files /dev/null and b/assets/selawk.ttf differ
diff --git a/assets/style.qss b/assets/style.qss
new file mode 100644
index 0000000..4f6466c
--- /dev/null
+++ b/assets/style.qss
@@ -0,0 +1,6 @@
+QMainWindow { background: rgba(100,100,100,100); }
+
+
+
+
+QCheckBox:hover, QCheckBox:checked { color: white }
\ No newline at end of file
diff --git a/assets/uninstaller.ico b/assets/uninstaller.ico
new file mode 100644
index 0000000..24278c2
Binary files /dev/null and b/assets/uninstaller.ico differ
diff --git a/bueno.bat b/bueno.bat
index cd190f0..540be60 100644
--- a/bueno.bat
+++ b/bueno.bat
@@ -1,2 +1,7 @@
-qmake -o build\Makefile .\qtest.pro
-mingw32-make.exe -C .\build -f Makefile.Release
+taskkill /F /IM "MixerQ.exe"
+taskkill /F /IM "MixerQd.exe"
+qmake -o build\Makefile .\qtest.pro
+REM mingw32-make.exe -C .\build -f Makefile.Release
+mingw32-make.exe -C .\build -f Makefile.Debug
+REM makensis /DBUILDTYPE=release install\installer.nsi
+REM makensis /DBUILDTYPE=debug install\installer.nsi
diff --git a/install/installer.nsi b/install/installer.nsi
new file mode 100644
index 0000000..7e62045
--- /dev/null
+++ b/install/installer.nsi
@@ -0,0 +1,265 @@
+;Auto versioning-------------------------------
+
+ !makensis "/DBUILDTYPE=${BUILDTYPE} version.nsi"
+ !system "GetVersion.exe"
+ !include "Version.txt"
+ ;optional cleanup
+ !delfile "GetVersion.exe"
+ !delfile "Version.txt"
+
+;Includes--------------------------------
+
+ !include "MUI2.nsh"
+ !include "nsDialogs.nsh"
+ !include "LogicLib.nsh"
+ !include "${NSISDIR}\Contrib\Language files\English.nsh"
+ !include "${NSISDIR}\Contrib\Language files\Spanish.nsh"
+ ;!include "${NSISDIR}\Contrib\Language files\English.nsh"
+
+
+;Defines----------------------------------
+ !define MUI_LANGDLL_ALLLANGUAGES
+ !define MUI_UNICON "..\assets\uninstaller.ico"
+ !define MUI_ICON "..\assets\installer.ico"
+
+
+;--------------------------------
+;General
+
+ ;Name and file
+ !if ${BUILDTYPE} == "release"
+ Name "MixerQ"
+ !else
+ Name "MixerQd"
+ !endif
+ OutFile "..\build\bin\MixerQ-installer-${version}.exe"
+
+ ;Get installation folder from registry if available
+ ;InstallDirRegKey HKCU "Software\Modern UI Test" ""
+
+ Unicode True
+ Var Is_Admin
+ Var Install_Type
+
+ ;Request application privileges for UAC. If admin is not available, only user-level install will be available
+ RequestExecutionLevel highest
+;--------------------------------
+;Interface Settings
+
+ !define MUI_ABORTWARNING
+
+;--------------------------------
+;Pages
+ !insertmacro MUI_PAGE_WELCOME
+ !insertmacro MUI_PAGE_LICENSE "..\LICENSE.txt"
+ ;!insertmacro MULTIUSER_PAGE_INSTALLMODE
+ Page Custom InstallTargetPage
+ ;!insertmacro MUI_PAGE_COMPONENTS
+ !define MUI_PAGE_CUSTOMFUNCTION_PRE Skip_Directory_Func
+ !insertmacro MUI_PAGE_DIRECTORY
+ !insertmacro MUI_PAGE_INSTFILES
+ !insertmacro MUI_PAGE_FINISH
+
+ !insertmacro MUI_UNPAGE_WELCOME
+ !insertmacro MUI_UNPAGE_CONFIRM
+ !insertmacro MUI_UNPAGE_INSTFILES
+ !insertmacro MUI_UNPAGE_FINISH
+
+;--------------------------------
+;Languages
+
+ !insertmacro MUI_LANGUAGE "English"
+ !insertmacro MUI_LANGUAGE "Spanish"
+ !insertmacro MUI_LANGUAGE "SpanishInternational"
+
+ ;English----------------------------
+ LangString Header_Title ${LANG_ENGLISH} "Configure Install"
+ LangString Header_Subtitle ${LANG_ENGLISH} "Customize install settings"
+ LangString Option_Scope ${LANG_ENGLISH} "Select for whom will $(^Name) be installed: "
+ LangString Scope_Machine ${LANG_ENGLISH} "All users"
+ LangString Scope_User ${LANG_ENGLISH} "Current user"
+
+ ;Spanish/SpanishInternational----------------------------
+ LangString Header_Title ${LANG_SPANISH} "Configurar instalación"
+ LangString Header_Subtitle ${LANG_SPANISH} "Elija los ajustes de la instalación"
+ LangString Option_Scope ${LANG_SPANISH} "$(^Name) será instalado para: "
+ LangString Scope_Machine ${LANG_SPANISH} "Todos los usuarios"
+ LangString Scope_User ${LANG_SPANISH} "Usuario actual"
+
+ LangString Header_Title ${LANG_SPANISHINTERNATIONAL} "Configurar instalación"
+ LangString Header_Subtitle ${LANG_SPANISHINTERNATIONAL} "Elija los ajustes de la instalación"
+ LangString Option_Scope ${LANG_SPANISHINTERNATIONAL} "$(^Name) será instalado para: "
+ LangString Scope_Machine ${LANG_SPANISHINTERNATIONAL} "Todos los usuarios"
+ LangString Scope_User ${LANG_SPANISHINTERNATIONAL} "Usuario actual"
+
+;Functions------------------------------
+ Function Skip_Directory_Func
+ ;StrCmp $Install_Type "user" dontSkip
+ Abort # skip the page
+ ;dontSkip:
+ FunctionEnd
+
+ !macro ONINIT un
+ Function ${un}.onInit
+ ; The value of SetShellVarContext detetmines whether SHCTX is HKLM or HKCU
+ ; and whether SMPROGRAMS refers to all users or just the current
+ !insertmacro MUI_LANGDLL_DISPLAY
+ UserInfo::GetAccountType
+ Pop $0
+ ${If} $0 == "Admin"
+ ; If we're an admin, default to installing to C:\Program Files
+ SetShellVarContext all
+ ; StrCpy $INSTDIR "$PROGRAMFILES64\$(^Name)"
+ StrCpy $Is_Admin "true"
+ ${Else}
+ ; If we're just a user, default to installing to ~\AppData\Local
+ SetShellVarContext current
+ ; StrCpy $INSTDIR "$LOCALAPPDATA\$(^Name)"
+ StrCpy $Is_Admin "false"
+ ${EndIf}
+
+ ; ${If} $INSTDIR == ""
+ ; ; This only happens in the installer, because the uninstaller already knows INSTDIR
+ ; ReadRegStr $0 SHCTX "Software\${PRODUCT_NAME}" ""
+
+ ; ${If} $0 != ""
+ ; ; If we're already installed, use the existing directory
+ ; StrCpy $INSTDIR "$0"
+ ; ${Else}
+ ; StrCpy $INSTDIR "$INSTDIR_BASE\${PRODUCT_NAME}"
+ ; ${Endif}
+ ; ${Endif}
+ FunctionEnd
+ !macroend
+
+!insertmacro ONINIT ""
+!insertmacro ONINIT "un"
+
+;NSDialog InstallTarget Page definition---------------------------------
+
+Function InstallTargetPage
+ !insertmacro MUI_HEADER_TEXT $(Header_Title) $(Header_Subtitle)
+ ;MessageBox MB_OK "Install type $Install_Type"
+ ;MessageBox MB_OK "Build type ${BUILDTYPE}"
+ nsDialogs::Create 1018
+ Pop $0
+
+ FindWindow $0 "#32770"
+ GetDlgItem $1 $0 1 ;next/install button
+ SendMessage $1 ${WM_SETTEXT} 1 "STR:$(^InstallBtn)"
+ Pop $0
+
+ ${NSD_CreateLabel} 0 0 100% 10% $(Option_Scope)
+ Pop $3
+
+ ${NSD_CreateFirstRadioButton} 0 12% 40% 6% $(Scope_Machine)
+ Pop $1
+ ${If} $Is_Admin == "false"
+ EnableWindow $1 0
+ StrCpy $INSTDIR "$LOCALAPPDATA\$(^Name)"
+ ${Else}
+ SendMessage $1 ${BM_CLICK} "" "" ;Set default
+ StrCpy $INSTDIR "$PROGRAMFILES64\$(^Name)"
+ ${EndIf}
+ ${NSD_OnClick} $1 All_Users_Click
+
+ ${NSD_CreateAdditionalRadioButton} 0 24% 40% 6% $(Scope_User)
+ Pop $2
+ ${IfThen} $Is_Admin == "false" ${|} SendMessage $2 ${BM_CLICK} "" "" ${|}
+ ${NSD_OnClick} $2 Current_User_Click
+
+ nsDialogs::Show
+FunctionEnd
+
+Function All_Users_Click
+ Pop $0
+ SetShellVarContext all
+ StrCpy $INSTDIR "$PROGRAMFILES64\$(^Name)"
+ StrCpy $Install_Type "machine"
+ ;${NSD_SetText} $0 "machine"
+ ;FindWindow $0 "#32770"
+ ;GetDlgItem $1 $0 1 ;next/install button
+ ;SendMessage $1 ${WM_SETTEXT} 1 "STR:$(^InstallBtn)"
+FunctionEnd
+
+Function Current_User_Click
+ Pop $0
+ SetShellVarContext current
+ StrCpy $INSTDIR "$LOCALAPPDATA\$(^Name)"
+ StrCpy $Install_Type "user"
+ ;${NSD_SetText} $0 "user"
+ ;FindWindow $0 "#32770"
+ ;GetDlgItem $1 $0 1 ;next/install button
+ ;SendMessage $1 ${WM_SETTEXT} 1 "STR:$(^NextBtn)"
+FunctionEnd
+
+;Default section----------------------
+Section
+ SetRegView 64
+ SetOutPath $INSTDIR
+
+ !if ${BUILDTYPE} == "release"
+ File "..\build\bin\MixerQ.exe"
+ !else
+ File "..\build\bin\MixerQd.exe"
+ !endif
+ File "..\LICENSE.txt"
+
+ ;Start menu shortcut
+ createDirectory "$SMPROGRAMS\$(^Name)"
+ createShortCut "$SMPROGRAMS\$(^Name)\$(^Name).lnk" "$INSTDIR\$(^Name).exe"
+ createShortCut "$SMPROGRAMS\$(^Name)\Uninstall$(^Name).lnk" "$INSTDIR\Uninstall$(^Name).exe"
+
+ ;Store installation folder
+ WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "DisplayName" "$(^Name)"
+ WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "UninstallString" '"$INSTDIR\Uninstall$(^Name).exe"'
+ WriteRegDWORD SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "NoModify" 1
+ WriteRegDWORD SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "NoRepair" 1
+ WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$(^Name)" "$INSTDIR\$(^Name)"
+
+ ;Create uninstaller
+ WriteUninstaller "$INSTDIR\Uninstall$(^Name).exe"
+
+SectionEnd
+
+
+;--------------------------------
+;Descriptions
+
+ ; ;Language strings
+ ; LangString DESC_SecDummy ${LANG_ENGLISH} "A test section."
+
+ ; ;Assign language strings to sections
+ ; !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+ ; !insertmacro MUI_DESCRIPTION_TEXT ${SecDummy} $(DESC_SecDummy)
+ ; !insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+ SetRegView 64
+
+ SetShellVarContext current
+ DeleteRegValue HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$(^Name)"
+ DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
+ Delete "$SMPROGRAMS\$(^Name)\$(^Name).lnk"
+ Delete "$SMPROGRAMS\$(^Name)\Uninstall$(^Name).lnk"
+ RMDir "$SMPROGRAMS\$(^Name)"
+
+ ${If} $Is_Admin == "true"
+ SetShellVarContext all
+ DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$(^Name)"
+ DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
+ Delete "$SMPROGRAMS\$(^Name)\$(^Name).lnk"
+ Delete "$SMPROGRAMS\$(^Name)\Uninstall$(^Name).lnk"
+ RMDir "$SMPROGRAMS\$(^Name)"
+ ${EndIf}
+
+ Delete "$INSTDIR\$(^Name).exe"
+ Delete "$INSTDIR\LICENSE.txt"
+ Delete "$INSTDIR\Uninstall$(^Name).exe"
+ ;!define PRODUCT_UNINST_ROOT_KEY "HKLM"
+ RMDir "$INSTDIR"
+
+SectionEnd
diff --git a/install/version.nsi b/install/version.nsi
new file mode 100644
index 0000000..5e85c8c
--- /dev/null
+++ b/install/version.nsi
@@ -0,0 +1,26 @@
+!if ${BUILDTYPE} == "release"
+ !define File "..\build\bin\MixerQ.exe"
+!else
+ !define File "..\build\bin\MixerQd.exe"
+!endif
+
+OutFile "GetVersion.exe"
+SilentInstall silent
+RequestExecutionLevel user ; don't write $EXEDIR\Version.txt with admin permissions and prevent invoking UAC
+
+Section
+
+ ## Get file version
+ GetDllVersion "${File}" $R0 $R1
+ IntOp $R2 $R0 / 0x00010000
+ IntOp $R3 $R0 & 0x0000FFFF
+ IntOp $R4 $R1 / 0x00010000
+ IntOp $R5 $R1 & 0x0000FFFF
+ StrCpy $R1 "$R2.$R3.$R4.$R5"
+
+ ## Write it to a !define for use in main script
+ FileOpen $R0 "$EXEDIR\Version.txt" w
+ FileWrite $R0 '!define version "$R1"'
+ FileClose $R0
+
+SectionEnd
\ No newline at end of file
diff --git a/qtest.pro b/qtest.pro
index 7f7dbb8..42a1165 100644
--- a/qtest.pro
+++ b/qtest.pro
@@ -1,8 +1,28 @@
-CONFIG += debug console
-QT += widgets
-INCLUDEPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
-DESTPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
-VPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
-SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp contclasses.cpp
-HEADERS += qtclasses.h backlasses.h contclasses.h global.h
-#DESTDIR += "build"
+TEMPLATE = app
+QMAKE_CXXFLAGS += --target=x86_64-w64-mingw32 -Werror=return-type
+QMAKE_LFLAGS += --target=x86_64-w64-mingw32 -v
+CONFIG(release, debug|release) {
+ TARGET = MixerQ
+ DESTDIR = bin
+ VERSION = 0.9.0.0
+ #QMAKE_CXXFLAGS += -O2 < Default. Modifying requires removing.
+} else {
+ TARGET = MixerQd
+ DESTDIR = bin
+ VERSION = 0.9.0.1
+ QMAKE_CXXFLAGS += -g -gcodeview -O0
+ QMAKE_LFLAGS += -g -Wl,-pdb=
+}
+
+LIBS += -lWinmm -lodbc32 -lodbccp32 -luuid -loleaut32 -lole32 -lshell32 -ladvapi32 -lcomdlg32 -lwinspool -lgdi32 -luser32 -lkernel32 -lpropsys -static -stdlib=libc++ -lunwind
+DEFINES += QT_LOGGING_TO_CONSOLE=1 WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602
+DEFINES_DEBUG += DEBUG
+
+QT += widgets network svg
+INCLUDEPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\back\reimpl" "$$PWD\src\cont"
+VPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\back\reimpl" "$$PWD\src\cont"
+
+SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp backsessionclasses.cpp contclasses.cpp contsessionclasses.cpp settings.cpp
+HEADERS += qtclasses.h backlasses.h backsessionclasses.h contclasses.h contsessionclasses.h global.h debug.h backfuncs.h ipolicyconfig.h msinclude.h meterslider.h qtvisuals.h settings.h
+RESOURCES = assets.qrc
+RC_ICONS += assets/logo.ico
diff --git a/src/back/backfuncs.h b/src/back/backfuncs.h
new file mode 100644
index 0000000..b8e1c6c
--- /dev/null
+++ b/src/back/backfuncs.h
@@ -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;
+}
diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp
index 61e3562..74af6a0 100644
--- a/src/back/backlasses.cpp
+++ b/src/back/backlasses.cpp
@@ -1,40 +1,585 @@
-#include
+#include "backlasses.h"
+#include "backfuncs.h"
-Endpoint::Endpoint(IMMDevice* ep){
- this->endpoint = ep;
- if(FAILED(endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&endpointVolume))) { log_debugcpp("si"); };
- //Obtaining friendly name: IPropertyStore creates PROPVARIANT per field
- // hr = endpointPtr->GetId(&endpointID);
- endpoint->OpenPropertyStore(STGM_READ, &properties);
- PROPVARIANT pv;
- properties->GetValue(PKEY_Device_FriendlyName , &pv);
- friendlyName = pv.pwszVal;
+using namespace Environment;
+
+EndpointNewSessionCallback::EndpointNewSessionCallback(EndpointHandler* eph){
+ this->eph = eph;
}
-LPWSTR Endpoint::getName(){
+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;
+
+ IAudioSessionControl2* sessionControl;
+ //ISimmpleAudioVolume* sessionVolume;
+ if (FAILED(NewSession->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl))) { log_wdebugcpp(L"no nueva sesion......"); };
+ if (sessionControl) {
+ Session* newSession = new Session(this->eph->getEndpoint(), sessionControl);
+
+ SessionThreadParams tp = { .eph = this->eph, .session = newSession, .isDelete = false };
+ wait = true;
+ std::thread newSessionThread(&EndpointNewSessionCallback::createSessionThread, this, tp);
+ newSessionThread.detach();
+ while(wait);
+ }
+
+ return S_OK;
+}
+
+void EndpointNewSessionCallback::createSessionThread(SessionThreadParams params) {
+ params.eph->addSessionSendFront(params.session);
+ this->wait = false;
+}
+
+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;
+
+ AUDIO_VOLUME_NOTIFICATION_DATA paramCopy;
+ memcpy(¶mCopy, pNotify, sizeof(AUDIO_VOLUME_NOTIFICATION_DATA));
+ float* channelVolumes = (float*)malloc(pNotify->nChannels * sizeof(float));
+ for (int i = 0; i < pNotify->nChannels; i++) {
+ channelVolumes[i] = pNotify->afChannelVolumes[i];
+ }
+ wait = true;
+ std::thread updateVolumeThread(&EndpointVolumeCallback::updateVolumeInfo, this, paramCopy, channelVolumes);
+ updateVolumeThread.detach();
+ while(wait);
+ return S_OK;
+}
+
+void EndpointVolumeCallback::updateVolumeInfo(AUDIO_VOLUME_NOTIFICATION_DATA newVolume, float* channelVolumes) {
+ //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->handlersPlaybackMutex.lock();
+ osh->handlersCaptureMutex.lock();
+ osh->lockEndpoints();
+ osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data1 \
+ = newVolume.guidEventContext.Data1;
+ osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data2 \
+ = newVolume.guidEventContext.Data2;
+ osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data3 \
+ = newVolume.guidEventContext.Data3;
+ for(int i = 0; i < 8 /* Data4 size */; i++){
+ osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data4[i] = newVolume.guidEventContext.Data4[i];
+ }
+
+ //memcpy(&osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller, &newVolume.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 = newVolume.bMuted;
+ eph->getCallbackInfo()->mainVolume = newVolume.fMasterVolume;
+ eph->getCallbackInfo()->channels = newVolume.nChannels;
+
+
+ UINT j = 0;
+ //todo: do while here caused stack corruption; sus
+ while(j < newVolume.nChannels) {
+ if (flow & Flows::FLOW_PLAYBACK)
+ eph->getCallbackInfo()->channelVolumes[j] = channelVolumes[j];
+ else
+ eph->getCallbackInfo()->channelVolumes[j] = channelVolumes[j];
+ j++;
+ }
+ free(channelVolumes);
+ osh->unlockEndpoints();
+ osh->handlersPlaybackMutex.unlock();
+ osh->handlersCaptureMutex.unlock();
+ wait = false;
+}
+
+void EndpointVolumeCallback::reportFinished() {
+ this->wait = false;
+}
+
+EndpointSituationCallback::EndpointSituationCallback(Overseer* os){
+ this->os = os;
+}
+
+
+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;
+ if (!pwstrDeviceId) 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->roleBucketEntryCallback(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);
+ log_wdebugcpp(L"Endpoint state change for " + endpointId);
+ EndpointState newState;
+ switch (dwNewState) {
+ case DEVICE_STATE_ACTIVE:
+ newState = EndpointState::ENDPOINT_ACTIVE;
+ break;
+ case DEVICE_STATE_DISABLED:
+ newState = EndpointState::ENDPOINT_DISABLED;
+ break;
+ case DEVICE_STATE_NOTPRESENT:
+ newState = EndpointState::ENDPOINT_NOTPRESENT;
+ break;
+ case DEVICE_STATE_UNPLUGGED:
+ newState = EndpointState::ENDPOINT_UNPLUGGED;
+ break;
+ }
+ isEpStateChanging.exchange(true);
+ std::thread newEndpointThread(&OverseerHandler::reviseEndpointShowing, osh,
+ endpointId, newState);
+ newEndpointThread.detach();
+ while(isEpStateChanging);
+ return S_OK;
+}
+
+HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) {
+ isEpStateChanging.exchange(true);
+ std::thread propertyThread(&Overseer::updateEndpointInfo, os, std::wstring(pwstrDeviceId));
+ propertyThread.detach();
+ while(isEpStateChanging);
+ return S_OK;
+}
+
+void EndpointSituationCallback::reportFinishedStateChange() {
+ this->isEpStateChanging.exchange(false);
+ return;
+}
+
+Endpoint::Endpoint(IMMDevice* ep, IPolicyConfig7* policyConfig, uint64_t idx) {
+ this->endpoint = ep;
+ this->idx = idx;
+ this->policyConfig = policyConfig;
+ /*
+ * It can't multiflag, it's that stupid. MS momento.
+ * Only shows most relevant flag according to MS, i.e. 0110 sends 0010
+ */
+ DWORD state;
+ if(FAILED(endpoint->GetState(&state))) {exit(-2);};
+ this->endpointState = (EndpointState)state;
+
+ if(this->endpointState == EndpointState::ENDPOINT_ACTIVE) {
+ activateEndpointVolume();
+
+ //if(FAILED(endpoint->Activate(__uuidof(IAudioClient),
+ // CLSCTX_ALL, NULL, (void**)&audioClient))) { log_debugcpp("audioclntbros..."); }
+ //audioClient->GetDevicePeriod(&defTime, &minTime);
+
+ }
+
+ //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);
+ this->updateName();
+ this->setFlow();
+
+ reloadEndpointChannels();
+}
+
+void Endpoint::updateName() {
+ PROPVARIANT pv;
+ #define store_name(key, propvariant, wstr) do { \
+ properties->GetValue(key, &propvariant); \
+ if (pv.pwszVal == nullptr) wstr = L"Unnamed Not Present Endpoint"; \
+ else wstr = std::wstring(pv.pwszVal); \
+ } while (0)
+
+ store_name(PKEY_Device_FriendlyName, pv, friendlyName);
+ store_name(PKEY_Device_DeviceDesc, pv, descriptionName);
+ store_name(PKEY_DeviceInterface_FriendlyName, pv, deviceName);
+ #undef store_name
+ log_wdebugcpp(L"Endpoint name: " + friendlyName);
+}
+
+void Endpoint::activateEndpointSessions() {
+ if (this->flow != Flows::FLOW_PLAYBACK) {
+ log_debugcpp("recording. No seshes for u :(");
+ return;
+ }
+
+ if (!sessionManager) {
+ if (FAILED(endpoint->Activate(__uuidof(IAudioSessionManager2),
+ CLSCTX_ALL, NULL, (void**) &sessionManager))) {
+ log_debugcpp("Couldn't open session manager2, huh");
+ return;
+ }
+ }
+
+ IAudioSessionEnumerator* sessionEnumerator = nullptr;
+ if (FAILED(sessionManager->GetSessionEnumerator(&sessionEnumerator))) { log_wdebugcpp(L"sesEnumeratorBros..."); exit(-5); return; }
+
+ endpointSessions.resize(1, nullptr);
+ int sessionCount;
+ sessionEnumerator->GetCount(&sessionCount);
+ for (int i = 0; i < sessionCount; i++) {
+ IAudioSessionControl* sessionControlTmp;
+ if (FAILED(sessionEnumerator->GetSession(i, (IAudioSessionControl**)&sessionControlTmp))) {
+ exit(-6);
+ }
+ IAudioSessionControl2* sessionControl;
+ if(FAILED(sessionControlTmp->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl))){
+ exit(-7);
+ }
+ sessionControlTmp->Release();
+ Session* session = new Session(this, sessionControl, (size_t)i);
+ if (sessionControl->IsSystemSoundsSession() == S_OK) endpointSessions[0] = session;
+ else endpointSessions.push_back(session);
+ }
+ sessionEnumerator->Release();
+}
+
+/*
+ * void Endpoint::deleteSessionManager() {
+ * sessionManager->Release();
+ * sessionManager = nullptr;
+ * }
+ */
+
+void Endpoint::addSession(Session* session) {
+ session->setIndex(this->getSessionCount());
+ endpointSessions.push_back(session);
+}
+
+void Endpoint::activateEndpointVolume() {
+ //If this EP is created after init, COM won't be initialized on the executing thread.
+ HRESULT result = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
+ if (this->endpointVolume == nullptr) {
+ if(FAILED(endpoint->Activate(
+ IID_IAudioEndpointVolume,
+ CLSCTX_ALL,
+ NULL,
+ (void**)&this->endpointVolume))) {
+ log_debugcpp("No volume, huh");
+ }
+
+ //todo: check header
+ if(FAILED(endpoint->Activate(__uuidof(IAudioMeterInformation),
+ CLSCTX_ALL, NULL, (void**)&endpointPeakMeter))) {
+ log_debugcpp("peakbros...");
+ }
+ }
+ if (result == S_OK)
+ CoUninitialize();
+}
+
+void Endpoint::reloadEndpointChannels() {
+ if (this->endpointState == DEVICE_STATE_ACTIVE) {
+ if (FAILED(endpointVolume->GetChannelCount(&channelCount))) {log_debugcpp("get channel count fail");};/* */
+ }
+}
+
+void Endpoint::setIndex(uint64_t idx){
+ this->idx = idx;
+}
+
+uint64_t Endpoint::getIndex(){
+ return idx;
+}
+
+std::wstring Endpoint::getName(){
return friendlyName;
}
-float Endpoint::getVolume(){
+std::wstring Endpoint::getId(){
+ return endpointId;
+}
+
+float Endpoint::getPeakVolume() {
+ float peakVol;
+ if(endpointPeakMeter) endpointPeakMeter->GetPeakValue(&peakVol);
+ else return 0;
+ return peakVol;
+}
+
+float Endpoint::getVolume(int channel){
float volume;
- if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { log_debugcpp("si");}
+ if (channel == AudioChannel::CHANNEL_MAIN) {
+ if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { /* log_debugcpp("si") */;}
+ } else {
+ if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */}
+ }
return volume;
}
-void Endpoint::setVolume(float volume) {
- if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, NULL))) { log_debugcpp("si"); };
+uint32_t Endpoint::getChannelCount(){
+ return (uint32_t)channelCount;
}
-//Endpoint::~Endpoint(){
-// free(friendlyName);
-// properties->Release();
-// endpointVolume->Release();
-// endpoint->Release();
-//}
+bool Endpoint::getMute(){
+ BOOL mut;
+ if(FAILED(endpointVolume->GetMute(&mut))) { /* TIP: Below */ }
+ bool mute = (bool)mut;
+ return mute;
+}
+void Endpoint::setState(EndpointState state){
+ this->endpointState = state;
+ if(state == EndpointState::ENDPOINT_ACTIVE) {
+ this->activateEndpointVolume();
+ this->reloadEndpointChannels();
+ }
+}
-void Overseer::initCOMLibrary(){
- if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { log_debugcpp("si"); };
+EndpointState 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))) {
+ log_wdebugcpp(L"Master volume failed for endpoint: " + friendlyName);
+ };
+ } else {
+ if(FAILED(endpointVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) {
+ log_wdebugcpp(L"Channel " + std::to_wstring(channel) + L" volume failed for endpoint: " + friendlyName);
+ };
+ }
+}
+
+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){
+ if (!policyConfig) return;
+
+ bool allRoles = false;
+ ERole val;
+ switch(role) {
+ case Roles::ROLE_CONSOLE:
+ val = eConsole;
+ break;
+ case Roles::ROLE_MULTIMEDIA:
+ val = eMultimedia;
+ break;
+ case Roles::ROLE_COMMUNICATIONS:
+ val = eCommunications;
+ break;
+ default:
+ allRoles = true;
+ break;
+ }
+ if (allRoles) {
+ policyConfig->SetDefaultEndpoint(endpointId.c_str(), eMultimedia);
+ //policyConfig->SetDefaultEndpoint(endpointId.c_str(), eConsole);
+ policyConfig->SetDefaultEndpoint(endpointId.c_str(), eCommunications);
+ } else policyConfig->SetDefaultEndpoint(endpointId.c_str(), val);
+}
+
+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;
+ if(FAILED(this->endpoint->QueryInterface(__uuidof(IMMEndpoint), (void**)&flowGetter)))
+ { log_debugcpp("no flow..."); }
+ EDataFlow MSflow;
+ flowGetter->GetDataFlow(&MSflow);
+ this->flow = (MSflow == EDataFlow::eRender ? Flows::FLOW_PLAYBACK : Flows::FLOW_CAPTURE);
+ log_debugcpp("Endpoint flow: " + std::to_string(flow));
+ flowGetter->Release();
+}
+
+Flows Endpoint::getFlow() {
+ return this->flow;
+}
+
+/* sessions */
+std::vector Endpoint::getSessions() {
+ return endpointSessions;
+}
+
+size_t Endpoint::getSessionCount() {
+ size_t sessionCount;
+ sessionCount = endpointSessions.size();
+ return sessionCount;
+}
+
+void Endpoint::registerNewSessionNotification(EndpointNewSessionCallback* ensc){
+ sessionManager->RegisterSessionNotification(ensc);
+}
+
+void Endpoint::unregisterNewSessionNotification(EndpointNewSessionCallback* ensc){
+ sessionManager->UnregisterSessionNotification(ensc);
+}
+
+void Endpoint::deleteSessions() {
+ for (auto session : endpointSessions) {
+ delete session;
+ }
+ endpointSessions.resize(0);
+}
+
+Endpoint::~Endpoint(){
+ //EPs are never deleted.
+ log_wdebugcpp(L"murio endpoint-san uwu");
+ properties->Release();
+ endpointVolume->Release();
+ endpoint->Release();
+ sessionManager->Release();
+ for (auto session : endpointSessions) {
+ delete session;
+ }
+}
+
+void Overseer::initCOMLibrary() {
+ if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) {
+ log_debugcpp("Not even COM?"); };
//Retrieving endpoint enumerator
@@ -42,60 +587,462 @@ void Overseer::initCOMLibrary(){
if(FAILED(CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL,
CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
(void**)&deviceEnumerator)) )
- { log_debugcpp("si"); };
+ { log_debugcpp("No MMDeviceEnum. Weird."); };
+ 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);
+
+ HRESULT hre = CoCreateInstance(__uuidof(CPolicyConfigClient),
+ NULL, CLSCTX_ALL,
+ __uuidof(IPolicyConfig7), (LPVOID *)&policyConfig);
+ if (hre != S_OK) exit(-1);
+
+ //TODO: Release lpguid?
+ //TODO: Uninitialize COM
}
-void Overseer::reloadEndpoints() {
+void Overseer::createEndpoints(Flows flow) {
IMMDeviceCollection *deviceCollection;
+ unsigned int numEndpoints;
+ EDataFlow MSflow = (flow == Flows::FLOW_PLAYBACK ? EDataFlow::eRender : EDataFlow::eCapture);
// | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED
- if(FAILED(deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection) ))
+ // NOTPRESENT shows a lot of garbage, unnamed devices.
+ if(FAILED(deviceEnumerator->EnumAudioEndpoints(MSflow, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED, &deviceCollection) ))
{ log_debugcpp("si"); };
-
- //Counting them
- if(FAILED(deviceCollection->GetCount(&numPlaybackEndpoints))) { log_debugcpp("si");};
- if(numPlaybackEndpoints == 0) { log_debugcpp("si"); };
-
+ /*
+ * Counting them
+ */
+ if(FAILED(deviceCollection->GetCount(&numEndpoints))) { log_debugcpp("si");};
+ if(numEndpoints == 0) { log_debugcpp("si"); };
- //Retrieving actual endpoints and storing them on their own class
- for (unsigned int i = 0; i < numPlaybackEndpoints; i++){
- IMMDevice *temp;
+ /*
+ * Retrieving actual endpoints and storing them on their own collection
+ */
+ IMMDevice *temp;
+ for (unsigned int i = 0; i < numEndpoints; i++){
if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); };
- Endpoint *endpoint = new Endpoint(temp);
- this->playbackDevices.push_back(endpoint);
- //TODO: le porblemx std::cout << "ola" << std::endl;
+ Endpoint *endpoint = new Endpoint(temp, policyConfig, i);
+ if (flow == Flows::FLOW_PLAYBACK)
+ this->playbackDevices.push_back(endpoint);
+ else
+ this->captureDevices.push_back(endpoint);
+ //TODO: le porblemx std::cout + "ola" + std::endl;
}
deviceCollection->Release();
+
+ /*
+ * 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);
+ if (!temp) continue;
+
+ 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) {
+ //This method is only called from the new endpoint callback and its subsequent thread,
+ //so another STA can be safely instantiated
+ if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) {
+ log_debugcpp("EP Callback Thread failed. Sad!");
+ return nullptr;
+ }
+ IMMDevice* newep;
+ if(FAILED(deviceEnumerator->GetDevice((LPCWSTR)endpointId.c_str(), &newep)))
+ log_debugcpp("ay caramba con la hot metida. Sad!");
+
+ Endpoint *endpoint = new Endpoint(newep, policyConfig);
+
+ 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;
+ CoUninitialize();
+ return endpoint;
+}
+
+void Overseer::reportFinishedStateChange() {
+ epsc.reportFinishedStateChange();
+}
+
+Overseer::Overseer() : epsc(this) {
+ log_debugcpp("Initializing Overseer");
+
+ //Storing exe path for later use (mainly "Run on startup")
+ log_debugcpp("-Caching exe path");
+ uint32_t cPathLen = 0;
+ wchar_t* cPath = getExeAbsPath(&cPathLen);
+ exeAbsPath = cPath;
+
+ //Detecting install scope
+ wchar_t *machine = wcsstr(cPath, L"Program Files");
+ if (!machine)
+ Environment::scope = HKEY_CURRENT_USER;
+ else Environment::scope = HKEY_LOCAL_MACHINE;
+ free(cPath);
+
//Initializing COM library
+ log_debugcpp("-Initializing COM");
initCOMLibrary();
- //Obtaining playback endpoint collection on this point in time
- reloadEndpoints();
+ //Obtaining playback endpoint collection
+ createEndpoints(Flows::FLOW_PLAYBACK);
+ //reloadEndpoints(Flows::FLOW_CAPTURE);
}
-//Overseer::int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint){
-//if (FAILED(deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &endpointPtr)))
-// return 1;
-//return 0;
-//}
+NGuid Overseer::getGuid() {
+ return guid;
+}
-//int Overseer::getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
+void Overseer::registerEndpointSituationCallback() {
+ if(FAILED(deviceEnumerator->RegisterEndpointNotificationCallback(((IMMNotificationClient*)&epsc)))) { log_debugcpp("when no enchufas......"); }
+}
std::vector Overseer::getPlaybackEndpoints() {
return playbackDevices;
}
-//Overseer::~Overseer(){
- // deviceEnumerator->Release();
- // for(unsigned long long i = 0; i < playbackDevices.size(); i++){
- //delete(playbackDevices.at(i));
- //}
- //}
+std::vector Overseer::getCaptureEndpoints() {
+ return captureDevices;
+}
+
+void Overseer::updateEndpointInfo(std::wstring endpointId) {
+ //todo: reintroduce capture devices
+ playbackMutex.lock();
+ log_wdebugcpp(L"new name Endpoint id: " + endpointId);
+ for(auto ep : playbackDevices) {
+ if (ep->getId() == endpointId && ep->getState() == EndpointState::ENDPOINT_ACTIVE) {
+ ep->updateName();
+ osh->updateFrontEndpointName(ep);
+ break;
+ }
+ }
+ playbackMutex.unlock();
+ epsc.reportFinishedStateChange();
+}
+
+Overseer::~Overseer(){
+ //Overseer is never deleted. This is to annotate what would need to be taken care of.
+ log_debugcpp("jej");
+ deviceEnumerator->Release();
+ for(unsigned long long i = 0; i < playbackDevices.size(); i++){
+ delete(playbackDevices.at(i));
+ }
+}
+
+wchar_t* Environment::getExeAbsPath(uint32_t *exeAbsPathLength) {
+ wchar_t *exeAbsPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS, sizeof(wchar_t));
+ *exeAbsPathLength = GetModuleFileNameW(
+ NULL,
+ exeAbsPath,
+ UNICODE_STRING_MAX_CHARS
+ );
+ return exeAbsPath;
+}
+
+std::string Environment::createSettingsPath(SettingsTargetDirectory target) {
+ wchar_t* settingsPath = nullptr;
+ wchar_t settingsFile[] = L"\\settings.ini";
+ uint32_t settingsFileLen = (sizeof(settingsFile) / sizeof(wchar_t)) - 1;
+ wchar_t maxPathBypass[] = L"\\\\?\\";
+ uint32_t exePathLength = 0;
+ wchar_t folderPath[] = L"\\" LAPP_NAME;
+ uint32_t maxPathBypassLen = (sizeof(maxPathBypass)/ sizeof(wchar_t)) - 1;
+ uint32_t folderPathLen = (sizeof(folderPath) / sizeof(wchar_t)) - 1;
+ wchar_t* roamingPath = nullptr;
+
+ log_wdebugcpp(L"Bypass size: " + std::to_wstring((sizeof(maxPathBypass)/sizeof(maxPathBypass[0]))));
+
+ switch(target) {
+ case HOME_DIR:
+ {
+ if(SHGetKnownFolderPath(
+ FOLDERID_RoamingAppData,
+ 0,
+ NULL,
+ &roamingPath)
+ == S_OK) {
+ //Retrieve path len
+ uint32_t pathLen = 0;
+ wchar_t currentChar = roamingPath[pathLen];
+ while(currentChar != '\0') {
+ pathLen++;
+ currentChar = roamingPath[pathLen];
+ }
+
+ settingsPath = (wchar_t*)calloc(pathLen +
+ maxPathBypassLen +
+ folderPathLen +
+ settingsFileLen,
+ sizeof(wchar_t));
+ memcpy(settingsPath, maxPathBypass, sizeof(wchar_t) * maxPathBypassLen);
+ memcpy(settingsPath + (maxPathBypassLen), roamingPath, sizeof(wchar_t) * pathLen);
+ CoTaskMemFree(roamingPath);
+ memcpy(settingsPath + (maxPathBypassLen + pathLen),
+ folderPath, sizeof(wchar_t) * folderPathLen);
+ log_wdebugcpp(L"Settings folder path: " + std::wstring(settingsPath));
+
+ if(CreateDirectoryW(settingsPath, NULL) || GetLastError() == ERROR_ALREADY_EXISTS) {
+ memcpy(settingsPath + (maxPathBypassLen + pathLen + folderPathLen),
+ settingsFile, sizeof(wchar_t) * settingsFileLen);
+ std::string utf8path = utf16ToUtf8(settingsPath);
+ free(settingsPath);
+ return utf8path;
+ }
+ }
+ }
+ return nullptr;
+ break;
+ case APP_PATH:
+ {
+ //Executable dir
+ settingsPath = getExeAbsPath(&exePathLength);
+
+ //reverse wcsstr
+ while(exePathLength >= 0) {
+ if(settingsPath[exePathLength] == '\\') {
+ memset(settingsPath + exePathLength,
+ 0,
+ (UNICODE_STRING_MAX_CHARS - exePathLength) * sizeof(wchar_t));
+ break;
+ } else exePathLength--;
+ }
+ log_wdebugcpp(L"Exe folder: " + std::wstring(settingsPath));
+ if((UNICODE_STRING_MAX_CHARS - exePathLength) > (settingsFileLen + 1)) {
+ memcpy(settingsPath + exePathLength, settingsFile, sizeof(wchar_t) * settingsFileLen);
+ std::string utf8path = utf16ToUtf8(settingsPath);
+ free(settingsPath);
+ return utf8path;
+ }
+ }
+ return nullptr;
+ break;
+ default:
+ return nullptr;
+ break;
+ }
+ return nullptr;
+}
+
+void Environment::populateSystemValues() {
+ updateColors();
+ Environment::startup = checkStartup(scope);
+}
+
+void Environment::openControlPanel() {
+ 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"rundll32 shell32, Control_RunDLL mmsys.cpl";
+ if(CreateProcessW(
+ NULL,
+ (wchar_t*)command.c_str(),
+ NULL,
+ NULL,
+ false,
+ CREATE_UNICODE_ENVIRONMENT,
+ NULL,
+ NULL,
+ (LPSTARTUPINFOW)&startupConfig,
+ &processInfo
+ ) == true) {
+ CloseHandle(processInfo.hProcess);
+ CloseHandle(processInfo.hThread);
+ }
+}
+
+ProcessedNativeEvent Environment::processTopLevelWindowMessage(void* msg) {
+#ifdef WIN32
+ MSG *message = static_cast(msg);
+ switch(message->message) {
+ case WM_SETTINGCHANGE:
+ //TODO: This looks like a future pain point. Ex handler would come in clutch
+ if(message->lParam && !wcscmp(((wchar_t*)message->lParam), L"ImmersiveColorSet"))
+ return updateColors();
+ break;
+ default:
+ return ProcessedNativeEvent::NONE;
+ break;
+ }
+ return ProcessedNativeEvent::NONE;
+ //if (message->message != WM_SETTINGCHANGE) {return false;}
+#endif
+}
+
+ProcessedNativeEvent Environment::updateColors() {
+ // DwmGetColorizationColor( WM_DWMCOLORIZATIONCOLORCHANGED
+ DWORD value = 0;
+ DWORD size = sizeof(DWORD);
+
+ LSTATUS result;
+
+ //Theme bg color
+ result = RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", L"AppsUseLightTheme", RRF_RT_REG_DWORD, nullptr, &value, &size);
+ lightMode = (bool)value;
+
+ //Accent color
+ result = RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\DWM", L"ColorizationColor", RRF_RT_REG_DWORD, nullptr, &value, &size);
+ if (result == ERROR_SUCCESS) {
+ accentColor = value;
+ } else accentColor = 0xffffffff;
+
+ return ProcessedNativeEvent::COLORS;
+}
+
+bool Environment::checkStartup(HKEY rootKeyFlags) {
+ //LSTATUS result;
+ DWORD typeReturned;
+
+ //Checking if app entry exists
+ if(RegGetValueW(rootKeyFlags, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", LAPP_NAME, RRF_RT_REG_SZ, &typeReturned, nullptr, nullptr) != ERROR_SUCCESS && typeReturned != REG_SZ)
+ return false;
+ else return true;
+}
+
+void Environment::updateStartupConfig(bool onStartup) {
+ wchar_t regSubKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run\\";
+
+ if(!onStartup) {
+ HKEY runKey;
+ if (RegOpenKeyExW(
+ scope,
+ regSubKey,
+ 0,
+ KEY_SET_VALUE,
+ &runKey
+ )
+ == ERROR_SUCCESS) {
+ RegDeleteValueW(runKey, LAPP_NAME);
+ RegCloseKey(runKey);
+ }
+ } else {
+ LSTATUS result;
+ uint32_t cPathLen = 0;
+ wchar_t* cPath = getExeAbsPath(&cPathLen);
+ wchar_t* regPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS + 2, sizeof(wchar_t));
+ //char* v = 0xFF'00'00'00'00'00'00'21;
+ regPath[0] = L'"';
+ memcpy(regPath + 1, cPath, sizeof(wchar_t) * cPathLen);
+ memcpy(regPath + cPathLen + 1, L"\"", sizeof(wchar_t) * 2);
+
+ result = RegSetKeyValueW(
+ scope,
+ regSubKey,
+ LAPP_NAME,
+ REG_SZ,
+ (void*)regPath,
+ (cPathLen + 3) * sizeof(wchar_t));
+ /*
+ * if (result != ERROR_SUCCESS) {
+ * wchar_t* error;
+ * FormatMessageW(
+ * FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ * nullptr,
+ * (DWORD)result,
+ * LANG_USER_DEFAULT,
+ * error,
+ * 1,
+ * nullptr);
+ * LocalFree(error);
+ * }
+ */
+ free(cPath);
+ }
+ return;
+}
+
+void Environment::setStartupConfig(bool onStartup) {
+ //TODO: Use the cache!!!! lol
+ uint32_t cPathLen = 0;
+ wchar_t* cPath = getExeAbsPath(&cPathLen);
+ wchar_t startupParam[] = L"--change-startup";
+ uint32_t startupParamLen = (sizeof(startupParam) / sizeof(wchar_t)) - 1;
+ wchar_t* completeParam = (wchar_t*)calloc(startupParamLen + 3, sizeof(wchar_t));
+ memcpy(completeParam, startupParam, sizeof(wchar_t) * startupParamLen);
+ if (onStartup)
+ memcpy(completeParam + startupParamLen, L" 1", sizeof(wchar_t) * 3);
+ else
+ memcpy(completeParam + startupParamLen, L" 0", sizeof(wchar_t) * 3);
+
+ if(scope == HKEY_LOCAL_MACHINE) {
+ ShellExecuteW(
+ NULL,
+ L"runas",
+ cPath,
+ completeParam,
+ NULL, // default dir
+ SW_SHOWNORMAL
+ );
+ } else {
+ Environment::updateStartupConfig(onStartup);
+ }
+ free(cPath);
+ free(completeParam);
+ return;
+}
+
+bool Environment::isLightMode() {
+ return lightMode;
+}
+
+bool Environment::isToRunAtStartup() {
+ return startup;
+}
+
+uint32_t Environment::getAccentColor() {
+ return accentColor;
+}
//int Overseer::getCaptureEndpoints(std::vector *captureEndpoints);
diff --git a/src/back/backlasses.h b/src/back/backlasses.h
index 90bc88b..5acedba 100644
--- a/src/back/backlasses.h
+++ b/src/back/backlasses.h
@@ -1,60 +1,240 @@
#pragma once
-#define WIN32_LEAN_AND_MEAN
+#include "msinclude.h"
+#include "backsessionclasses.h"
#include "global.h"
-#include
-#include
+#include "contclasses.h"
+//#include "environment.h"
-#include
-#include
-#include
-#include
-#include
+class EndpointVolumeCallback;
+class Session;
-#include
-#include
-#include
-//#include
-//#include
-#include
+// Convert a wide UTF16LE string to an UTF8 string
+static inline std::string utf16ToUtf8(const wchar_t* wstr) {
+ if(!wstr || wstr[0] == '\0') return std::string();
+ int size_needed = WideCharToMultiByte(CP_UTF8,
+ 0,
+ wstr,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ std::string str(size_needed, 0);
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ wstr,
+ -1,
+ &str[0],
+ size_needed,
+ NULL,
+ NULL);
+ return str;
+}
+
+// Convert an UTF8 string to a wide UTF16LE String
+/*
+ * std::wstring utf8_decode(const std::string &str)
+ * {
+ * if( str.empty() ) return std::wstring();
+ * int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
+ * std::wstring wstrTo( size_needed, 0 );
+ * MultiByteToWideChar (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
+ * return wstrTo;
+ * }
+ */
class Endpoint {
public:
- Endpoint(IMMDevice* endpoint);
- void setVolume(float volume);
- float getVolume();
- LPWSTR getName();
- //~Endpoint();
+ Endpoint(IMMDevice* endpoint, IPolicyConfig7* policyConfig, uint64_t idx = 0);
+ //todo: how to forward declare delegate constructors?
+ //Endpoint(IMMDevice* endpoint) : Endpoint(endpoint, 0) {};
+ void reloadEndpointChannels();
+ uint64_t getIndex();
+ void setIndex(uint64_t idx);
+ void setVolume(NGuid guid, int channel, float volume);
+ uint32_t getChannelCount();
+ float getVolume(int channel);
+ void setMute(NGuid guid, bool muted);
+ bool getMute();
+ void setState(EndpointState state);
+ EndpointState getState();
+ Roles getRoles();
+ void setRoles(Roles role);
+ void assignRoles(Roles role);
+ void removeRoles(Roles role);
+ void setFlow();
+ Flows getFlow();
+ float getPeakVolume();
+ std::wstring getId();
+ std::wstring getName();
+ void updateName();
+
+ void setVolumeCallback(EndpointVolumeCallback *epc);
+ void removeVolumeCallback(EndpointVolumeCallback *epc);
+
+ /* sessions */
+ std::vector getSessions();
+ size_t getSessionCount();
+ void addSession(Session* session);
+ void registerNewSessionNotification(EndpointNewSessionCallback* ensc);
+ void unregisterNewSessionNotification(EndpointNewSessionCallback* ensc);
+ void deleteSessions();
+ void activateEndpointSessions();
+ //void deleteSessionManager();
+ std::mutex endpointSessionsMutex;
+ ~Endpoint();
private:
- IMMDevice* endpoint;
- IAudioEndpointVolume *endpointVolume ;
+ void inline activateEndpointVolume();
+
+ std::vector endpointSessions;
+ uint32_t channelCount = 0;
+ IMMDevice *endpoint;
+ IAudioEndpointVolume *endpointVolume = nullptr;
IPropertyStore *properties;
- LPWSTR friendlyName;
- // LPWSTR endpointID = NULL;
+ IAudioMeterInformation *endpointPeakMeter = nullptr;
+ //IAudioClient *audioClient;
+ int64_t defTime, minTime;
+ IAudioSessionManager2 *sessionManager = nullptr;
+ Flows flow;
+ std::wstring friendlyName;
+ std::wstring descriptionName;
+ std::wstring deviceName;
+ std::wstring endpointId;
+ EndpointState endpointState;
+ Roles endpointRoles = (Roles)0;
+ uint64_t idx;
+ //Not implemented in llvm-mingw. Sad! todo: mingw patch
+ IPolicyConfig7* policyConfig;
+};
+
+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);
+ void updateVolumeInfo(AUDIO_VOLUME_NOTIFICATION_DATA newVolume, float* channelVolumes);
+ void reportFinished();
+ //~EndpointVolumeCallback();
+
+ private:
+ ULONG ref = 1;
+ Endpoint* ep;
+ std::atomic wait = false;
+};
+
+class EndpointSituationCallback : public IMMNotificationClient {
+ public:
+ EndpointSituationCallback(Overseer* os);
+ 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 reportFinishedStateChange();
+ private:
+ ULONG ref = 1;
+ Overseer* os;
+ std::atomic isEpStateChanging = false;
};
class Overseer {
- //TODO singleton?
+
public:
Overseer();
+ void registerEndpointSituationCallback();
+ NGuid getGuid();
+
std::vector getPlaybackEndpoints();
- void reloadEndpoints();
+ std::vector getCaptureEndpoints();
+ void updateEndpointInfo(std::wstring endpointId);
+
+ void createEndpoints(Flows flow);
+ Endpoint* addEndpoint(std::wstring endpointId, /* out */ Flows* flow);
+
+ void reportFinishedStateChange();
+
+ std::mutex playbackMutex;
+ std::mutex captureMutex;
+ //void setEndpointStatusCallback();
+ //void setEndpointStatusCallback();
+
//~Overseer();
//int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint);
//int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
//int getCaptureEndpoints(std::vector *captureEndpoints);
//IMMDeviceEnumerator** setOrigin();
- //~Overseer();
+ ~Overseer();
private:
- unsigned int numPlaybackEndpoints;
- IMMDeviceEnumerator *deviceEnumerator;
- std::vector playbackDevices;
void initCOMLibrary();
+
+ NGuid guid;
+
+ IMMDeviceEnumerator *deviceEnumerator;
+ EndpointSituationCallback epsc;
+
+ std::vector playbackDevices;
+ std::vector captureDevices;
+ IPolicyConfig7* policyConfig;
+ friend class Endpoint;
//IMMDeviceCollection *deviceCollection;
//int numCaptureEndpoints;
//std::vector *captureDevices;
};
+class EndpointNewSessionCallback : public IAudioSessionNotification {
+ private:
+ struct SessionThreadParams;
+
+ public:
+ EndpointNewSessionCallback(EndpointHandler *eph);
+ ULONG AddRef();
+ ULONG Release();
+ HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
+ HRESULT OnSessionCreated(IAudioSessionControl *NewSession);
+ void createSessionThread(SessionThreadParams params);
+
+ private:
+ std::atomic wait = false;
+ ULONG ref = 1;
+ EndpointHandler *eph;
+
+ struct SessionThreadParams {
+ EndpointHandler *eph;
+ Session *session;
+ bool isDelete;
+ };
+};
+
+namespace Environment {
+ wchar_t* getExeAbsPath(uint32_t *exeAbsPathLength);
+ std::string createSettingsPath(SettingsTargetDirectory target);
+ void populateSystemValues();
+ void openControlPanel();
+ ProcessedNativeEvent processTopLevelWindowMessage(void* msg);
+ ProcessedNativeEvent updateColors();
+ bool checkStartup(HKEY rootKeyFlags);
+ void updateStartupConfig(bool onStartup);
+ void setStartupConfig(bool onStartup);
+ bool isLightMode();
+ bool isToRunAtStartup();
+ uint32_t getAccentColor();
+
+ //todo: binary path cache unused
+ static std::wstring exeAbsPath;
+ static uint32_t exeAbsPathLen;
+ static bool lightMode;
+ static bool startup = false;
+ static HKEY scope;
+ static uint32_t accentColor;
+};
diff --git a/src/back/backsessionclasses.cpp b/src/back/backsessionclasses.cpp
new file mode 100644
index 0000000..c9aaa85
--- /dev/null
+++ b/src/back/backsessionclasses.cpp
@@ -0,0 +1,425 @@
+#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) {
+ //TODO: Preguntar
+ while(sh->getVolumeInfo()->isNameChanged == true);
+
+ sh->setName(std::wstring(NewDisplayName));
+ sh->getVolumeInfo()->isNameChanged = true;
+ 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) {
+ if (DisconnectReason != DisconnectReasonDeviceRemoval) {
+ 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;
+ //https://matthewvaneerde.wordpress.com/2012/06/08/getting-audio-peak-meter-values-for-all-active-audio-sessions/
+ if (FAILED(sessionControl->QueryInterface(__uuidof(IAudioMeterInformation), (void**)&meterInformation))) { log_wdebugcpp(L"sPeakbros......"); };
+ //meterInformation = (IAudioMeterInformation*)sessionControl;
+
+ 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"")) {
+ std::wstring exePath;
+ if (getExePath(pid, &exePath)) {
+ this->sessionName = exePath;
+ if (fetchName(exePath, pid)) goto nameFound;
+ }
+ if (fetchNameViaWindowName(pid, &this->sessionName)) goto nameFound;
+ } else {
+ this->sessionName = std::wstring(sessionDisplayName);
+ goto nameFound;
+ }
+
+ nameFound:
+ 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;
+}
+
+float Session::getPeakVolume() {
+ float peakVol;
+ if(meterInformation) meterInformation->GetPeakValue(&peakVol);
+ else return 0;
+ return peakVol;
+}
+
+/*
+ * uint32_t Endpoint::getChannelCount(){
+ * return (uint32_t)channelCount;
+ * }
+ */
+
+std::wstring Session::getName() {
+ return sessionName;
+}
+
+void Session::setName(std::wstring newName) {
+ this->sessionName = newName;
+}
+
+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?")); };
+}
+
+bool Session::getExePath(DWORD pid, std::wstring *exePath) {
+ //std::wstring msixName;
+ HANDLE processHandle;
+ wchar_t fileName[UNICODE_STRING_MAX_CHARS];
+ processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
+ if (processHandle != NULL) {
+ if (GetModuleFileNameEx(processHandle, NULL, fileName, UNICODE_STRING_MAX_CHARS) == 0) {
+ CloseHandle(processHandle);
+ return false;
+ }
+ } else {
+ log_wdebugcpp(L"aye no procname. -> " + std::to_wstring(GetLastError()));
+ return false;
+ }
+
+ *exePath = std::wstring(fileName);
+ return true;
+}
+
+bool Session::fetchNameViaFD(std::wstring exePath, DWORD pid, std::wstring *sessionName) {
+ /* File description retrieval: size and available lang-codepages */
+ struct LANGANDCODEPAGE {
+ WORD wLanguage;
+ WORD wCodePage;
+ } *translationArray;
+
+ DWORD filler;
+ DWORD fileVersionInfoSize = GetFileVersionInfoSizeExW
+ (FILE_VER_GET_LOCALISED | FILE_VER_GET_NEUTRAL, exePath.c_str(), &filler);
+ if (!fileVersionInfoSize) return false;
+
+ void* fileVersionInfo = malloc(fileVersionInfoSize);
+ if(!GetFileVersionInfoExW(FILE_VER_GET_LOCALISED | FILE_VER_GET_NEUTRAL,
+ exePath.c_str(),0,fileVersionInfoSize, fileVersionInfo)) {
+ return false;
+ }
+
+ UINT translationArrayLen = 0;
+ if (!VerQueryValueW(fileVersionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayLen)) {
+ free(fileVersionInfo);
+ return false;
+ }
+ //File descriptor parsing
+ //TODO: https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserpreferreduilanguages
+ /* It is possible to retrieve user languages and try to use one of those before falling back to whatever
+ * is available. Also possible to hardcode en-US or any other lang-codepage combo. When an actual translation
+ * sysem is put in place, I'll come finish this up.
+ */
+ uint64_t availableLangs = (translationArrayLen / sizeof(LANGANDCODEPAGE));
+ if (!availableLangs) { free(fileVersionInfo); return false; }
+
+ int8_t syslangIdx = -1;
+ wchar_t metadataStringKey[256];
+ wchar_t* metadataString = NULL;
+ for (UINT i = 0; i < availableLangs; i++) {
+ LANGID defaultUILanguage = GetUserDefaultUILanguage();
+ if (defaultUILanguage != translationArray[i].wLanguage)
+ continue;
+
+ syslangIdx = i;
+ break;
+ }
+
+ UINT metadataStringSize = 0;
+ swprintf(metadataStringKey, L"\\StringFileInfo\\%04x%04x\\FileDescription",
+ translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wLanguage,
+ translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wCodePage);
+ if (VerQueryValueW(fileVersionInfo, metadataStringKey, (LPVOID*)&metadataString, &metadataStringSize)
+ && metadataString[0] != '\0') {
+ free(fileVersionInfo);
+ *sessionName = std::wstring(metadataString);
+ return true;
+ }
+ swprintf(metadataStringKey, L"\\StringFileInfo\\%04x%04x\\ProductName",
+ translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wLanguage,
+ translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wCodePage);
+ if (VerQueryValueW(fileVersionInfo, metadataStringKey, (LPVOID*)&metadataString, &metadataStringSize)
+ && metadataString[0] != '\0') {
+ free(fileVersionInfo);
+ *sessionName = std::wstring(metadataString);
+ return true;
+ }
+
+ if(fileVersionInfo)
+ free(fileVersionInfo);
+
+ return false;
+}
+
+
+bool Session::fetchNameViaMSIX(std::wstring exePath, DWORD pid, std::wstring *sessionName) {
+ HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
+ if(!process) return false;
+
+ //constant missing in mingw64. TB removed when I upgrade to a mingw64 ver that has it
+ #define APPLICATION_USER_MODEL_ID_MAX_LENGTH 130
+ uint32_t length = APPLICATION_USER_MODEL_ID_MAX_LENGTH;
+ PWSTR userModelId = (PWSTR)malloc(length * sizeof(wchar_t));
+ if(GetApplicationUserModelId(process, &length, userModelId) != ERROR_SUCCESS) {
+ CloseHandle(process);
+ return false;
+ }
+ CloseHandle(process);
+
+ static constexpr wchar_t* prefix = L"shell:appsfolder\\";
+ uint32_t prefixLen = wcslen(prefix);
+ uint32_t userModelIdLen = wcslen(userModelId);
+ wchar_t* fullName;
+ fullName = (prefixLen + userModelIdLen < length)
+ ? (wchar_t*)malloc(length * sizeof(wchar_t))
+ : (wchar_t*)malloc((length * 2) * sizeof(wchar_t));
+ for (int32_t i = prefixLen - 1; i >= 0; i--) {
+ fullName[i] = prefix[i];
+ }
+ for (uint32_t i = 0; i < userModelIdLen + 1; i++) {
+ fullName[prefixLen + i] = userModelId[i];
+ }
+
+ IShellItem* si;
+ HRESULT hr = SHCreateItemFromParsingName(fullName,
+ nullptr,
+ IID_IShellItem,
+ (void**)&si
+ );
+ free(fullName);
+ LPWSTR humanName = nullptr;
+ si->GetDisplayName(SIGDN_NORMALDISPLAY, &humanName);
+ if(humanName && humanName[0] != '\0') {
+ *sessionName = std::wstring(humanName);
+ CoTaskMemFree(humanName);
+ }
+ if(si) si->Release();
+
+ if (sessionName->length() > 0)
+ return true;
+ else return false;
+}
+
+
+bool Session::fetchNameViaWindowName(DWORD pid, std::wstring *sessionName) {
+ //lParam is documented as in, so... Beware of future explosions, ig?
+ std::pair params = { 0, pid };
+
+ BOOL result = EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
+ auto pParams = (std::pair*)(lParam);
+
+ DWORD processId;
+ //IsWindowVisible(hwnd) &&&& GetWindow(hwnd, GW_OWNER) == 0
+ if ( GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second) {
+ int length = GetWindowTextLength(hwnd);
+ if (!length) return TRUE;
+
+ // Stop enumerating
+ SetLastError(-1);
+ pParams->first = hwnd;
+ return FALSE;
+ }
+
+ // Continue enumerating
+ return TRUE;
+ } , (LPARAM)¶ms);
+
+ if(!result && GetLastError() == -1 && params.first) {
+ //todo: double-dipping length... Not a fan
+ int length = GetWindowTextLength(params.first);
+ wchar_t* buffer = new wchar_t[length + 1];
+ GetWindowTextW(params.first, buffer, length + 1);
+ *sessionName = buffer;
+ delete[] buffer;
+ return true;
+ }
+ return false;
+}
+
+bool Session::fetchName(std::wstring exePath, DWORD pid) {
+ /*
+ * if(fetchNameViaWindowName(exePath, pid, &this->sessionName))
+ * return;
+ * else if(fetchNameViaMSIX(exePath, pid, &this->sessionName))
+ * return;
+ * else if(!fetchNameViaFD(exePath, pid, &this->sessionName))
+ * this->sessionName = exePath;
+ */
+
+ if(fetchNameViaFD(exePath, pid, &this->sessionName))
+ return true;
+ return fetchNameViaMSIX(exePath, pid, &this->sessionName);
+ //else if(!fetchNameViaWindowName(exePath, pid, &this->sessionName))
+ /// this->sessionName = 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() {
+ meterInformation->Release();
+ sessionControl->Release();
+ sessionVolume->Release();
+ meterInformation = nullptr;
+ sessionControl = nullptr;
+ sessionVolume = nullptr;
+}
diff --git a/src/back/backsessionclasses.h b/src/back/backsessionclasses.h
new file mode 100644
index 0000000..ae87f0a
--- /dev/null
+++ b/src/back/backsessionclasses.h
@@ -0,0 +1,64 @@
+#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);
+ float getPeakVolume();
+ void setMute(NGuid guid, bool muted);
+ bool getMute();
+ SessionState getState();
+ void setState(SessionState state);
+ void setIndex(size_t idx);
+ std::wstring getName();
+ void setName(std::wstring newName);
+ void setStateCallback(SessionStateCallback *ssc);
+ void removeStateCallback(SessionStateCallback *ssc);
+ ~Session();
+ //uint32_t getChannelCount();
+
+ private:
+ bool getExePath(DWORD pid, /*out*/ std::wstring *exePath);
+ bool fetchName(std::wstring exePath, DWORD pid);
+ bool fetchNameViaFD(std::wstring exePath, DWORD pid, /*out*/ std::wstring *sessionName);
+ bool fetchNameViaMSIX(std::wstring exePath, DWORD pid, /*out*/ std::wstring *sessionName);
+ bool fetchNameViaWindowName(DWORD pid, /*out*/ std::wstring *sessionName);
+ /* std::wstring fetchProcessName(DWORD pid); */
+ std::wstring sessionName;
+ SessionState sessionState;
+ Endpoint* ep;
+ IAudioSessionControl2* sessionControl = nullptr;
+ IAudioMeterInformation* meterInformation = nullptr;
+ ISimpleAudioVolume* sessionVolume = nullptr;
+ size_t idx;
+};
+
diff --git a/src/back/ipolicyconfig.h b/src/back/ipolicyconfig.h
new file mode 100644
index 0000000..7b474bb
--- /dev/null
+++ b/src/back/ipolicyconfig.h
@@ -0,0 +1,311 @@
+#pragma once
+
+#ifndef __IPolicyConfig7_FWD_DEFINED__
+#define __IPolicyConfig7_FWD_DEFINED__
+typedef interface IPolicyConfig7 IPolicyConfig7;
+#ifdef __cplusplus
+interface IPolicyConfig7;
+#endif
+#endif /* __IPolicyConfig7_FWD_DEFINED__ */
+
+#ifndef __CPolicyConfigClient_FWD_DEFINED__
+#define __CPolicyConfigClient_FWD_DEFINED__
+typedef class CPolicyConfigClient CPolicyConfigClient;
+#endif /* __CPolicyConfigClient_FWD_DEFINED__ */
+
+/*****************************************************************************
+ * CPolicyConfigClient coclass
+ */
+
+DEFINE_GUID(CLSID_CPolicyConfigClient, 0x870af99c, 0x171d, 0x4f9e, 0xaf,0x0d, 0xe6,0x3d,0xf4,0x0c,0x2b,0xc9);
+#ifdef __cplusplus
+class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") CPolicyConfigClient;
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(CPolicyConfigClient, 0x870af99c, 0x171d, 0x4f9e, 0xaf,0x0d, 0xe6,0x3d,0xf4,0x0c,0x2b,0xc9)
+#endif
+#endif
+
+
+/*****************************************************************************
+ * IPolicyConfig7 interface
+ */
+#ifndef __IPolicyConfig7_INTERFACE_DEFINED__
+#define __IPolicyConfig7_INTERFACE_DEFINED__
+DEFINE_GUID(IID_IPolicyConfig7, 0xf8679f50, 0x850a, 0x41cf, 0x9c,0x72, 0x43,0x0f,0x29,0x02,0x90,0xc8);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+MIDL_INTERFACE("f8679f50-850a-41cf-9c72-430f290290c8")
+IPolicyConfig7 : 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
+ );
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IPolicyConfig7, 0xf8679f50, 0x850a, 0x41cf, 0x9c,0x72, 0x43,0x0f,0x29,0x02,0x90,0xc8)
+#endif
+
+#endif
+
+
+#endif /* __IPolicyConfig7_INTERFACE_DEFINED__ */
+
+
+
+
+/* __CRT_UUID_DECL(IPolicyConfig10, 0xca286fc3, 0x91fd, 0x42c3, 0x8e,0x9b, 0xca,0xaf,0xa6,0x62,0x42,0xe3) */
+/* __CRT_UUID_DECL(CPolicyConfigClient, 0x870af99c, 0x171d, 0x4f9e, 0xaf,0x0d, 0xe6,0x3d,0xf4,0x0c,0x2b,0xc9) */
+
+
+/* // ---------------------------------------------------------------------------- */
+/* // 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 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 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 *\/ */
+/* /\* }; *\/ */
diff --git a/src/back/msinclude.h b/src/back/msinclude.h
new file mode 100644
index 0000000..52fccbd
--- /dev/null
+++ b/src/back/msinclude.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include
+
+//done by qt by def #define UNICODE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+//#include
+
+#include
+#include
+#include
+//#include
+//#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ipolicyconfig.h"
+#include "audiometerinfo.h"
+
+// IAudioMeterInformation
+/* GUID manual; */
+/* manual.Data1 = 0xc02216f6; */
+/* manual.Data2 = 0x8c67; */
+/* manual.Data3 = 0x4b5b; */
+/* manual.Data4[0] = 0x9d; */
+/* manual.Data4[1] = 0x00; */
+/* manual.Data4[2] = 0xd0; */
+/* manual.Data4[3] = 0x08; */
+/* manual.Data4[4] = 0xe7; */
+/* manual.Data4[5] = 0x3e; */
+/* manual.Data4[6] = 0x00; */
+/* manual.Data4[7] = 0x64; */
+//if(FAILED(endpoint->Activate((const _GUID) manual,
+
+//IMMEndpoint
+/* 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; */
diff --git a/src/back/reimpl/audiometerinfo.h b/src/back/reimpl/audiometerinfo.h
new file mode 100644
index 0000000..618ad34
--- /dev/null
+++ b/src/back/reimpl/audiometerinfo.h
@@ -0,0 +1,130 @@
+#ifndef __IAudioMeterInformation_FWD_DEFINED__
+#define __IAudioMeterInformation_FWD_DEFINED__
+typedef interface IAudioMeterInformation IAudioMeterInformation;
+
+#endif /* __IAudioMeterInformation_FWD_DEFINED__ */
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* interface __MIDL_itf_endpointvolume_0000_0003 */
+/* [local] */
+
+#ifndef __IAudioMeterInformation_INTERFACE_DEFINED__
+#define __IAudioMeterInformation_INTERFACE_DEFINED__
+
+/* interface IAudioMeterInformation */
+/* [unique][helpstring][nonextensible][uuid][local][object] */
+
+DEFINE_GUID(IID_IAudioMeterInformation, 0xc02216f6, 0x8c67, 0x4b5b, 0x9d,0x00, 0xd0,0x08,0xe7,0x3e,0x00,0x64);
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("c02216f6-8c67-4b5b-9d00-d008e73e0064")
+ IAudioMeterInformation : public IUnknown
+ {
+ public:
+ virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetPeakValue(
+ /* [out] */ float *pfPeak) = 0;
+
+ virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMeteringChannelCount(
+ /* [annotation][out] */
+ _Out_ UINT *pnChannelCount) = 0;
+
+ virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelsPeakValues(
+ /* [in] */ UINT32 u32ChannelCount,
+ /* [size_is][out] */ float *afPeakValues) = 0;
+
+ virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE QueryHardwareSupport(
+ /* [annotation][out] */
+ _Out_ DWORD *pdwHardwareSupportMask) = 0;
+
+ };
+
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(IAudioMeterInformation, 0xc02216f6, 0x8c67, 0x4b5b, 0x9d,0x00, 0xd0,0x08,0xe7,0x3e,0x00,0x64)
+#endif
+#else /* C style interface */
+
+ typedef struct IAudioMeterInformationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAudioMeterInformation * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAudioMeterInformation * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAudioMeterInformation * This);
+
+ /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetPeakValue )(
+ IAudioMeterInformation * This,
+ /* [out] */ float *pfPeak);
+
+ /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetMeteringChannelCount )(
+ IAudioMeterInformation * This,
+ /* [annotation][out] */
+ _Out_ UINT *pnChannelCount);
+
+ /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetChannelsPeakValues )(
+ IAudioMeterInformation * This,
+ /* [in] */ UINT32 u32ChannelCount,
+ /* [size_is][out] */ float *afPeakValues);
+
+ /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *QueryHardwareSupport )(
+ IAudioMeterInformation * This,
+ /* [annotation][out] */
+ _Out_ DWORD *pdwHardwareSupportMask);
+
+ END_INTERFACE
+ } IAudioMeterInformationVtbl;
+
+ interface IAudioMeterInformation
+ {
+ CONST_VTBL struct IAudioMeterInformationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAudioMeterInformation_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAudioMeterInformation_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAudioMeterInformation_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAudioMeterInformation_GetPeakValue(This,pfPeak) \
+ ( (This)->lpVtbl -> GetPeakValue(This,pfPeak) )
+
+#define IAudioMeterInformation_GetMeteringChannelCount(This,pnChannelCount) \
+ ( (This)->lpVtbl -> GetMeteringChannelCount(This,pnChannelCount) )
+
+#define IAudioMeterInformation_GetChannelsPeakValues(This,u32ChannelCount,afPeakValues) \
+ ( (This)->lpVtbl -> GetChannelsPeakValues(This,u32ChannelCount,afPeakValues) )
+
+#define IAudioMeterInformation_QueryHardwareSupport(This,pdwHardwareSupportMask) \
+ ( (This)->lpVtbl -> QueryHardwareSupport(This,pdwHardwareSupportMask) )
+
+#endif /* COBJMACROS */
+
+#endif /* C style interface */
+
+#endif /* __IAudioMeterInformation_INTERFACE_DEFINED__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp
index 30b2688..d2188f0 100644
--- a/src/cont/contclasses.cpp
+++ b/src/cont/contclasses.cpp
@@ -1,36 +1,464 @@
+#include "backlasses.h"
#include "contclasses.h"
-Overseer OverseerHandler::os;
-
-EndpointHandler::EndpointHandler(Endpoint *ept, QObject *parent) : QObject(parent) {
- this->ept = ept;
- eptName = QString::fromStdWString(ept->getName());
+void setConfigDirToDefaults() {
+ #define tryFileDir(dir, create) do { \
+ OverseerHandler::settingsPath = Environment::createSettingsPath(dir); \
+ set = ini::UserSettings::createSettings(OverseerHandler::settingsPath.c_str(), create); \
+ if(set) { \
+ return; \
+ } else OverseerHandler::settingsPath.clear(); \
+ } while(0)
+ #define tryOpenFileDir(dir) tryFileDir(dir, false)
+ #define tryCreateFileDir(dir) tryFileDir(dir, true)
+
+ tryOpenFileDir(SettingsTargetDirectory::APP_PATH);
+ tryOpenFileDir(SettingsTargetDirectory::HOME_DIR);
+ tryCreateFileDir(SettingsTargetDirectory::HOME_DIR);
+ tryCreateFileDir(SettingsTargetDirectory::APP_PATH);
+
+ return;
+ #undef tryOpenFileDir
+ #undef tryCreateFileDir
+ #undef tryFileDir
}
-void EndpointHandler::setValue(int value){
- ept->setVolume((float)value / 100);
+EndpointHandler::EndpointHandler(uint64_t idx, Flows flow) {
+ this->idx = idx;
+ this->flow = flow;
+ this->ep = (flow == Flows::FLOW_PLAYBACK ? osh->getPlaybackEndpoints().at(idx) : osh->getCaptureEndpoints().at(idx));
+
+ this->callbackInfo.caller = osh->getGuid();
+ //epName = ep->getName();
+ this->setBackEndpointVolumeCallbackInfoContent(this->getState());
+ osh->pushBackEndpointHandler(this, flow);
}
-QString EndpointHandler::getName(){
- return eptName;
+void OverseerHandler::pushBackEndpointHandler(EndpointHandler* eph, Flows flow) {
+ if (eph == nullptr) return;
+ if (flow == Flows::FLOW_PLAYBACK)
+ this->playbackEndpointHandlers.push_back(eph);
+ else
+ this->captureEndpointHandlers.push_back(eph);
+ return;
}
-float EndpointHandler::getVolume(){
- return ept->getVolume();
+void EndpointHandler::setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx){
+ ephfv.visibility = state;
+ ephfv.frontIdx = frontIdx;
}
-Overseer OverseerHandler::getOverseer(){
- return os;
+uint64_t EndpointHandler::getFrontVisibilityIndex(){
+ return ephfv.frontIdx;
}
-OverseerHandler::OverseerHandler(QObject *parent) : QObject(parent) {
+EndpointState EndpointHandler::getFrontVisibilityState(){
+ return ephfv.visibility;
+}
+
+Flows EndpointHandler::getFlow(){
+ return ep->getFlow();
+}
+
+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();
+ if (!epc) {
+ epc = new EndpointVolumeCallback(ep);
+ ep->setVolumeCallback(epc);
+ }
+ callbackInfo.channelVolumes.resize(this->callbackInfo.channels);
+ for(uint32_t i = 0; i < this->getChannelCount(); i++){
+ callbackInfo.channelVolumes.at(i) = this->getVolume(i);
+ }
+ }
+}
+
+void EndpointHandler::setState(EndpointState state){
+ ep->setState(state);
+ this->setBackEndpointVolumeCallbackInfoContent(state);
+}
+
+void EndpointHandler::setState(EndpointState state, uint64_t index){
+ ep->setState(state);
+ this->setFrontVisibilityInfo((EndpointState)state, index);
+ this->setBackEndpointVolumeCallbackInfoContent(state);
+}
+
+float EndpointHandler::getPeakVolume() {
+ return ep->getPeakVolume();
+}
+
+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 addSessionWidget) {
+ this->addSessionWidget = addSessionWidget;
+}
+
+void EndpointHandler::setRemoveSessionWidgetFunction(std::function removeSessionWidget) {
+ this->removeSessionWidget = removeSessionWidget;
+}
+
+/* sessions */
+size_t EndpointHandler::getSessionCount() {
+ return ep->getSessionCount();
+}
+
+std::vector EndpointHandler::getSessions(){
+ return ep->getSessions();
+}
+
+std::vector EndpointHandler::getSessionHandlers(){
+ return this->sessionHandlers;
+}
+
+Endpoint* EndpointHandler::getEndpoint() {
+ return this->ep;
+}
+
+void EndpointHandler::addSessionSendFront(Session* session) {
+ if(!ep->endpointSessionsMutex.try_lock()) return;
+ sessionHandlersMutex.lock();
+ this->ep->addSession(session);
+ SessionHandler* sessionHandler = new SessionHandler(this, session, (getSessionCount() - 1));
+
+ sessionHandlers.push_back(sessionHandler);
+ ep->endpointSessionsMutex.unlock();
+ sessionHandlersMutex.unlock();
+ this->addSessionWidget(sessionHandler);
}
-std::vector* OverseerHandler::getEndpointHandlers(){
- return endpointHandlers;
+void EndpointHandler::sendSessionToFront(SessionHandler* sh) {
+ this->addSessionWidget(sh);
}
-void OverseerHandler::setEndpointHandlers(std::vector *ephs){
- this->endpointHandlers = ephs;
+void EndpointHandler::removeSessionFromFront(SessionHandler* sh) {
+ this->removeSessionWidget(sh);
}
+
+void EndpointHandler::deleteSessions() {
+ ep->unregisterNewSessionNotification(ensc);
+ ensc->Release();
+ ensc = nullptr;
+ for (auto sh : sessionHandlers) {
+ delete sh;
+ }
+ sessionHandlers.resize(0);
+ ep->deleteSessions();
+ //ep->deleteSessionManager();
+}
+
+void EndpointHandler::createSessionHandlers() {
+ ep->activateEndpointSessions();
+ 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::createSessionHandlersCallback() {
+ ensc = new EndpointNewSessionCallback(this);
+ ep->registerNewSessionNotification(ensc);
+}
+
+void EndpointHandler::lockSessionCollections() {
+ this->sessionHandlersMutex.lock();
+ this->ep->endpointSessionsMutex.lock();
+}
+
+void EndpointHandler::unlockSessionCollections() {
+ this->sessionHandlersMutex.unlock();
+ this->ep->endpointSessionsMutex.unlock();
+}
+
+void EndpointHandler::removeVolumeCallback() {
+ ep->removeVolumeCallback(epc);
+ epc->Release();
+ epc = nullptr;
+}
+
+EndpointHandler::~EndpointHandler() {
+ ep->removeVolumeCallback(epc);
+ ep->unregisterNewSessionNotification(ensc);
+ epc->Release();
+ delete ep;
+}
+
+OverseerHandler::OverseerHandler() {
+ this->os = new Overseer();
+}
+
+void OverseerHandler::setSettingsPath(std::string path) {
+ OverseerHandler::settingsPath = path;
+}
+
+std::string OverseerHandler::getSettingsPath(){
+ return OverseerHandler::settingsPath;
+}
+
+void OverseerHandler::updateStartupConfig(bool onStartup) {
+ Environment::updateStartupConfig(onStartup);
+}
+
+void OverseerHandler::setStartupConfig(bool onStartup) {
+ Environment::setStartupConfig(onStartup);
+}
+
+void OverseerHandler::populateSystemValues() {
+ Environment::populateSystemValues();
+}
+
+void OverseerHandler::openControlPanel() {
+ Environment::openControlPanel();
+}
+
+ProcessedNativeEvent OverseerHandler::processTopLevelWindowMessage(void* msg) {
+ return Environment::processTopLevelWindowMessage(msg);
+}
+
+bool OverseerHandler::isLightMode() {
+ return Environment::isLightMode();
+}
+
+bool OverseerHandler::isToRunAtStartup() {
+ return Environment::isToRunAtStartup();
+}
+
+uint32_t OverseerHandler::getAccentColor() {
+ return Environment::getAccentColor();
+}
+
+std::vector OverseerHandler::getPlaybackEndpoints() {
+ return this->os->getPlaybackEndpoints();
+}
+
+std::vector OverseerHandler::getCaptureEndpoints() {
+ return this->os->getCaptureEndpoints();
+}
+
+std::vector OverseerHandler::getPlaybackEndpointHandlers(){
+ return playbackEndpointHandlers;
+}
+
+std::vector OverseerHandler::getCaptureEndpointHandlers(){
+ return captureEndpointHandlers;
+}
+
+uint64_t OverseerHandler::getPlaybackEndpointsCount(){
+ return this->os->getPlaybackEndpoints().size();
+}
+
+uint64_t OverseerHandler::getCaptureEndpointsCount(){
+ return this->os->getCaptureEndpoints().size();
+}
+
+void OverseerHandler::createEndpointHandlers(){
+ //todo: add capture
+
+ //std::vector* ephs = new std::vector;
+ 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));
+ new EndpointHandler(i, Flows::FLOW_PLAYBACK);
+ log_debugcpp("Created Playback handler " + std::to_string(i) + ", adding to vector. " + " VSize: " + std::to_string(this->playbackEndpointHandlers.size()));
+
+ }
+
+ log_debugcpp("Capture VSize: " +
+ std::to_string(this->getCaptureEndpointsCount()));
+
+ for(uint64_t i = 0; i < this->getCaptureEndpointsCount(); i++) {
+ log_debugcpp("Creating Capture handler " + std::to_string(i));
+ new EndpointHandler(i, Flows::FLOW_CAPTURE);
+ 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;
+ */
+ }
+ os->registerEndpointSituationCallback();
+}
+
+EndpointHandler* OverseerHandler::addEndpoint(std::wstring endpointId, /* out */ Flows *flow = nullptr) {
+ //This method is only called from the new endpoint callback and its subsequent thread
+ 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);
+ if (flow != nullptr) *flow = localFlow;
+ return newEph;
+}
+
+void OverseerHandler::reportFinishedStateChange() {
+ os->reportFinishedStateChange();
+}
+
+NGuid OverseerHandler::getGuid() {
+ return this->os->getGuid();
+}
+
+/*
+ * void OverseerHandler::setChangeFrontDefaultsFunction(std::function changeFrontDefaults){
+ * this->changeFrontDefaults = changeFrontDefaults;
+ * }
+ *
+ * void OverseerHandler::changeFrontDefaultsCallback(Roles role, std::wstring endpointId) {
+ * this->changeFrontDefaults(role, endpointId);
+ * }
+ */
+
+void OverseerHandler::roleBucketEntryCallback(Roles role, std::wstring endpointId){
+ this->roleBucketEntry(role, endpointId);
+}
+
+void OverseerHandler::setRoleBucketEntryFunction(std::function roleBucketEntry) {
+ this->roleBucketEntry = roleBucketEntry;
+}
+
+void OverseerHandler::updateFrontEndpointName(Endpoint* ep) {
+ //todo: reintroduce capture devices
+ for (auto eph : playbackEndpointHandlers) {
+ if (eph->getEndpoint() == ep) eph->getCallbackInfo()->updateName = true;
+ }
+}
+
+void OverseerHandler::reviseEndpointShowing(std::wstring endpointId, EndpointState state) {
+ //TODO: Race condition!!!!!
+ std::vector allHandlers;
+ handlersPlaybackMutex.lock();
+ handlersCaptureMutex.lock();
+ os->playbackMutex.lock();
+ os->captureMutex.lock();
+ 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) goto end;
+ //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) goto end;
+
+ if (eph && EndpointState::ENDPOINT_ACTIVE & state) {
+ eph->setState(EndpointState::ENDPOINT_ACTIVE);
+ this->addEndpointWidget(eph);
+ } else if (eph && eph->getFrontVisibilityState() == EndpointState::ENDPOINT_ACTIVE) {
+ eph->removeVolumeCallback();
+ this->removeEndpointWidget(eph->getFrontVisibilityIndex());
+ }
+
+ end:
+ handlersPlaybackMutex.unlock();
+ handlersCaptureMutex.unlock();
+ os->playbackMutex.unlock();
+ os->captureMutex.unlock();
+ os->reportFinishedStateChange();
+ return;
+}
+
+void OverseerHandler::setAddEndpointWidgetFunction(std::function addEndpointWidget){
+ this->addEndpointWidget = addEndpointWidget;
+}
+
+void OverseerHandler::setRemoveEndpointWidgetFunction(std::function removeEndpointWidget){
+ this->removeEndpointWidget = removeEndpointWidget;
+}
+
+void OverseerHandler::setEndpointHandlers(std::vector ephs){
+ this->playbackEndpointHandlers = ephs;
+}
+
+void OverseerHandler::lockEndpoints() {
+ os->playbackMutex.lock();
+ os->captureMutex.lock();
+}
+
+void OverseerHandler::unlockEndpoints() {
+ os->playbackMutex.unlock();
+ os->captureMutex.unlock();
+}
+
diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h
index 647ca1d..cd0e03e 100644
--- a/src/cont/contclasses.h
+++ b/src/cont/contclasses.h
@@ -1,49 +1,168 @@
#pragma once
-#include
+
#include "global.h"
-#include "backlasses.h"
-
-
-class EndpointHandler : public QObject {
- Q_OBJECT
-
-public:
- EndpointHandler(Endpoint *ept, QObject *parent = nullptr);
- QString getName();
- float getVolume();
-
-private:
- Endpoint *ept;
- QString eptName;
- //QSlider *slidy;
-
-public slots:
- void setValue(int value);
-
-
-//signals:
+#include "settings.h"
+#include "contsessionclasses.h"
+//#define invoke_mem_fn(object,ptrToMember) ((object).*(ptrToMember))
+//#define pinvoke_mem_fn(object,ptrToMember) ((object)->*(ptrToMember))
+class EndpointWidget;
+class Endpoint;
+class EndpointVolumeCallback;
+class Overseer;
+class SessionHandler;
+class EndpointNewSessionCallback;
+struct BackEndpointVolumeCallbackInfo {
+ NGuid caller;
+ bool muted;
+ float mainVolume;
+ size_t channels;
+ std::vector channelVolumes;
+ bool updateName = false;
};
+void setConfigDirToDefaults();
-class OverseerHandler : public QObject {
- Q_OBJECT
+class EndpointHandler {
+
+public:
+ EndpointHandler(uint64_t idx, Flows flow);
+ void setBackEndpointVolumeCallbackInfoContent(uint8_t state);
+
+ //todo: replace all getEndpointHandler()
+ //todo: name refactor
+ BackEndpointVolumeCallbackInfo* getCallbackInfo();
+ uint32_t getChannelCount();
+
+ void setIndex(uint64_t idx);
+ uint64_t getIndex();
+ void setVolume(int channel, float volume);
+
+ std::wstring getName();
+ void setName(std::wstring newName);
+ 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(EndpointState state);
+ void setState(EndpointState state, uint64_t idx);
+
+ float getPeakVolume();
+ /* sessions */
+ size_t getSessionCount();
+ std::vector getSessionHandlers();
+ void createNewSession();
+ Endpoint* getEndpoint();
+
+ /*Session*/
+ void addSessionSendFront(Session* session);
+ void setAddSessionWidgetFunction(std::function addSessionWidget);
+ void setRemoveSessionWidgetFunction(std::function removeSessionWidget);
+ void sendSessionToFront(SessionHandler* sh);
+ void removeSessionFromFront(SessionHandler* sh);
+ void deleteSessions();
+ void createSessionHandlers();
+ void createSessionHandlersCallback();
+ std::mutex sessionHandlersMutex;
+ void lockSessionCollections();
+ void unlockSessionCollections();
+ void removeVolumeCallback();
+
+ ~EndpointHandler();
+private:
+ std::vector 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 sessionHandlers;
+ std::function addSessionWidget;
+ std::function removeSessionWidget;
+ //QSlider *slidy;
+};
+
+class OverseerHandler {
public:
- OverseerHandler(QObject *parent = nullptr);
- void setEndpointHandlers(std::vector *ephs);
- std::vector* getEndpointHandlers();
- static Overseer getOverseer();
+ OverseerHandler();
+ static void setSettingsPath(std::string path);
+ static std::string getSettingsPath();
+ static inline std::string settingsPath;
+ void updateStartupConfig(bool onStartup);
+ void setStartupConfig(bool onStartup);
+ void populateSystemValues();
+ void openControlPanel();
+ ProcessedNativeEvent processTopLevelWindowMessage(void* msg);
+ bool isLightMode();
+ bool isToRunAtStartup();
+ uint32_t getAccentColor();
+
+ //void setChangeFrontDefaultsFunction(std::function changeFrontDefaults);
+ //void changeFrontDefaultsCallback(Roles role, std::wstring endpointId);
+
+ void roleBucketEntryCallback(Roles role, std::wstring endpointId);
+ void setRoleBucketEntryFunction(std::function roleBucketEntry);
+
+ void updateFrontEndpointName(Endpoint* ep);
+ //void setReviseEndpointShowingFunction(std::function reviseEndpointShowing);
+ void reviseEndpointShowing(std::wstring endpointId, EndpointState state);
+ void setRemoveEndpointWidgetFunction(std::function removeEndpointWidget);
+ void setAddEndpointWidgetFunction(std::function addEndpointWidget);
+
+ void setEndpointHandlers(std::vector ephs);
+ std::vector getPlaybackEndpointHandlers();
+ std::vector getCaptureEndpointHandlers();
+ std::vector getPlaybackEndpoints();
+ std::vector getCaptureEndpoints();
+ void pushBackEndpointHandler(EndpointHandler* eph, Flows flow);
+ uint64_t getPlaybackEndpointsCount();
+ uint64_t getCaptureEndpointsCount();
+ void createEndpointHandlers();
+ EndpointHandler* addEndpoint(std::wstring endpointId, Flows *flow);
+ void reportFinishedStateChange();
+ NGuid getGuid();
+
+ std::mutex handlersPlaybackMutex;
+ std::mutex handlersCaptureMutex;
+ void lockEndpoints();
+ void unlockEndpoints();
private:
- static Overseer os;
- std::vector *endpointHandlers;
- //QSlider *slidy;
-
- //public slots:
- //void setValue(int value);
-
-
+ Overseer *os;
+ std::vector playbackEndpointHandlers;
+ std::vector captureEndpointHandlers;
+ std::function changeFrontDefaults;
+ std::function removeEndpointWidget;
+ std::function addEndpointWidget;
+ std::function roleBucketEntry;
+
+ /* Session's */
+ std::function changeSessionVolume;
+
+ //std::function updateFrontVolumeCallback;
+ //std::function updateFrontMuteCallback;
+
};
diff --git a/src/cont/contsessionclasses.cpp b/src/cont/contsessionclasses.cpp
new file mode 100644
index 0000000..0f6caaf
--- /dev/null
+++ b/src/cont/contsessionclasses.cpp
@@ -0,0 +1,91 @@
+#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();
+}
+
+void SessionHandler::setName(std::wstring newName){
+ session->setName(newName);
+}
+
+float SessionHandler::getPeakVolume(){
+ return session->getPeakVolume();
+}
+
+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;
+ }
+}
+
+SessionHandler::~SessionHandler() {
+ session->removeStateCallback(ssc);
+ ssc->Release();
+}
diff --git a/src/cont/contsessionclasses.h b/src/cont/contsessionclasses.h
new file mode 100644
index 0000000..24c0ba7
--- /dev/null
+++ b/src/cont/contsessionclasses.h
@@ -0,0 +1,44 @@
+#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;
+ std::atomic isNameChanged = false;
+ //size_t channels;
+ //std::vector 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();
+ float getPeakVolume();
+ void setName(std::wstring newName);
+ void reviseSessionShowing(SessionState state);
+ SessionVolumeInfo* getVolumeInfo();
+ ~SessionHandler();
+ private:
+ SessionVolumeInfo svi;
+ EndpointHandler* eph;
+ Session* session;
+ SessionStateCallback* ssc;
+ size_t idx;
+ uint64_t frontIdx = INT_MAX;
+};
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..61855c1
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG)
+
+#define PIPE_NAME "Mixerq-dev"
+
+#ifdef INIT_FILELOG
+ std::wstring_convert, wchar_t> converter;
+ FILE* fileLog;
+ errno_t lfResult;
+ bool writable = false;
+
+ void inline initializeFileLogging() {
+ lfResult = fopen_s(&fileLog, "log.txt", "w");
+ if (!lfResult) writable = true;
+ else writable = false;
+ }
+
+#else
+ extern std::wstring_convert, wchar_t> converter;
+ extern errno_t lfResult;
+ extern FILE* fileLog;
+ extern bool writable;
+ extern bool initializeFileLogging();
+#endif
+
+#define initialize_file_log() initializeFileLogging()
+
+template
+std::bitset varToBitset(T info) {
+ std::bitset content(info);
+ return content;
+}
+
+#define print_as_binary(info) varToBitset(info).to_string()
+
+#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
+#include
+#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 //_WIN32
+
+#define log_to_file(fmt, cnt...) do { \
+ if(writable) fprintf_s(fileLog, fmt,##cnt); \
+} while (0)
+
+#define close_file_log_buffer() do { \
+ if(writable) { fflush(fileLog); fclose(fileLog); } \
+} while (0)
+
+#else
+#define log_debugcpp(str)
+#define log_wdebugcpp(str)
+#define print_as_binary(info)
+#define log_to_file(fmt, cnt...)
+#define initialize_file_log() false
+#define close_file_log_buffer()
+#define PIPE_NAME "Mixerq"
+#endif //DEBUG
+
+/* 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); */
+
diff --git a/src/global.h b/src/global.h
index c44b7e5..8799892 100644
--- a/src/global.h
+++ b/src/global.h
@@ -1,4 +1,117 @@
#pragma once
-#define log_debugcpp(str) do { \
- std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
- } while (0)
+
+#define __STDC_WANT_LIB_EXT1__ 1
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include