diff --git a/assets/SoundVolumeView.exe b/assets/SoundVolumeView.exe new file mode 100644 index 0000000..4c7a7d2 Binary files /dev/null and b/assets/SoundVolumeView.exe differ diff --git a/bueno.bat b/bueno.bat index 67fbd6a..2c8ac1c 100644 --- a/bueno.bat +++ b/bueno.bat @@ -1,2 +1,4 @@ qmake -o build\Makefile .\qtest.pro +copy /Y /B .\assets\SoundVolumeView.exe .\build\debug +copy /Y /B .\assets\SoundVolumeView.exe .\build\release mingw32-make.exe -C .\build -f Makefile diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index 3b10f56..ab68c51 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -66,6 +66,124 @@ HRESULT EndpointVolumeCallback::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify return S_OK; } +/* + * EndpointSituationCallback::EndpointSituationCallback(IMMDeviceEnumerator *deviceEnumerator, std::vector playbackDevices){ + * this->deviceEnumerator = deviceEnumerator; + * this->playbackDevices = playbackDevices; + * } + */ + +void EndpointSituationCallback::fill(IMMDeviceEnumerator *deviceEnumerator, std::vector playbackDevices){ + this->deviceEnumerator = deviceEnumerator; + this->playbackDevices = playbackDevices; +} + + +ULONG EndpointSituationCallback::AddRef(){ + return InterlockedIncrement(&ref); +} + +ULONG EndpointSituationCallback::Release(){ + ULONG tempRef = InterlockedDecrement(&ref); + if (tempRef == 0) { + delete this; + } + return tempRef; +} + +HRESULT EndpointSituationCallback::QueryInterface(REFIID riid, VOID **ppvInterface) { + if (IID_IUnknown == riid) + { + AddRef(); + *ppvInterface = (IUnknown*)this; + } + else if (__uuidof(IMMNotificationClient) == riid) + { + AddRef(); + *ppvInterface = (IMMNotificationClient*)this; + } + else + { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +HRESULT EndpointSituationCallback::OnDefaultDeviceChanged(EDataFlow flow, ERole role,LPCWSTR pwstrDeviceId) { + if (flow == EDataFlow::eCapture) return E_INVALIDARG; + + Roles nRole; + switch (role) { + case ERole::eConsole: + nRole = Roles::ROLE_CONSOLE; + break; + case ERole::eMultimedia: + nRole = Roles::ROLE_MULTIMEDIA; + break; + case ERole::eCommunications: + nRole = Roles::ROLE_COMMUNICATIONS; + break; + } + + osh + + return S_OK; +} + +HRESULT EndpointSituationCallback::OnDeviceAdded(LPCWSTR pwstrDeviceId) { + + printf(" -->Added device\n"); + return S_OK; +}; + +HRESULT EndpointSituationCallback::OnDeviceRemoved(LPCWSTR pwstrDeviceId) { + + printf(" -->Removed device\n"); + return S_OK; +} + +HRESULT EndpointSituationCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { + /* + * char *pszState = "?????"; + * + * switch (dwNewState) + * { + * case DEVICE_STATE_ACTIVE: + * pszState = "ACTIVE"; + * break; + * case DEVICE_STATE_DISABLED: + * pszState = "DISABLED"; + * break; + * case DEVICE_STATE_NOTPRESENT: + * pszState = "NOTPRESENT"; + * break; + * case DEVICE_STATE_UNPLUGGED: + * pszState = "UNPLUGGED"; + * break; + * } + * + * printf(" -->New device state is DEVICE_STATE_%s (0x%8.8x)\n", + * pszState, dwNewState); + */ + + return S_OK; +} + +HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { + /* + * printf(" -->Changed device property " + * "{%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}#%d\n", + * key.fmtid.Data1, key.fmtid.Data2, key.fmtid.Data3, + * key.fmtid.Data4[0], key.fmtid.Data4[1], + * key.fmtid.Data4[2], key.fmtid.Data4[3], + * key.fmtid.Data4[4], key.fmtid.Data4[5], + * key.fmtid.Data4[6], key.fmtid.Data4[7], + * key.pid); + */ + return S_OK; +} + Endpoint::Endpoint(IMMDevice* ep, uint64_t idx){ this->endpoint = ep; this->idx = idx; @@ -168,7 +286,51 @@ uint8_t Endpoint::getRoles(){ return this->endpointRoles; } -void Endpoint::setRoles(uint8_t role){ +void Endpoint::setRoles(Roles role){ + //otro exe momento + STARTUPINFOEXW startupConfig; + PROCESS_INFORMATION processInfo; + SecureZeroMemory(&startupConfig, sizeof(STARTUPINFOEXW)); + SecureZeroMemory(&startupConfig.StartupInfo, sizeof(STARTUPINFOW)); + startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW); + SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); + + //const wchar_t* pCrutch = crutch.c_str(); + std::wstring command = L"SoundVolumeView.exe /SetDefault " + endpointId + L" "; + switch (role) { + case Roles::ROLE_ALL: + command += L"all"; + break; + case Roles::ROLE_CONSOLE: + command += std::to_wstring(0); + break; + case Roles::ROLE_MULTIMEDIA: + command += std::to_wstring(1); + break; + case Roles::ROLE_COMMUNICATIONS: + command += std::to_wstring(2); + break; + } + + if(CreateProcessW( + NULL, + (wchar_t*)command.c_str(), + NULL, + NULL, + false, + CREATE_UNICODE_ENVIRONMENT, + NULL, + NULL, + (LPSTARTUPINFOW)&startupConfig, + &processInfo + ) == true) { + WaitForSingleObject(processInfo.hProcess, INFINITE ); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } +} + +void Endpoint::assignRoles(uint8_t role){ //todo: operador virtuoso uint8_t roles = endpointRoles | role; this->endpointRoles = roles; @@ -252,30 +414,24 @@ void Overseer::reloadEndpoints() { int comparison = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, eptId.c_str(), -987, id, -987, NULL, NULL, 0); if (comparison - 2 == 0) { log_wdebugcpp("ola defaul de " << i << " es " << id); - playbackDevices.at(j)->setRoles((1 << i)); + playbackDevices.at(j)->assignRoles((1 << i)); } //uint8_t debg = playbackDevices.at(j)->getRoles(); } } } -Overseer::Overseer(){ +Overseer::Overseer() { //: epsc(deviceEnumerator, playbackDevices){ //Initializing COM library log_debugcpp("Initializing Overseer"); initCOMLibrary(); //Obtaining playback endpoint collection on this point in time reloadEndpoints(); + this->epsc.fill(deviceEnumerator, playbackDevices); + if(FAILED(deviceEnumerator->RegisterEndpointNotificationCallback(((IMMNotificationClient*)&epsc)))) { log_debugcpp("when no enchufas......"); } } -//Overseer::int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint){ -//if (FAILED(deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &endpointPtr))) -// return 1; -//return 0; -//} - -//int Overseer::getDefaultCaptureEndpoint(Endpoint** defaultEndpoint); - NGuid Overseer::getGuid() { return guid; } diff --git a/src/back/backlasses.h b/src/back/backlasses.h index 455faf1..db905a4 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -6,6 +6,7 @@ //done by qt by def #define UNICODE #include +#include #include #include #include @@ -41,7 +42,8 @@ class Endpoint { void setState(uint8_t state); uint8_t getState(); uint8_t getRoles(); - void setRoles(uint8_t role); + void setRoles(Roles role); + void assignRoles(uint8_t role); std::wstring getId(); std::wstring getName(); void setVolumeCallback(EndpointVolumeCallback *epc); @@ -77,6 +79,25 @@ class EndpointVolumeCallback : public IAudioEndpointVolumeCallback { Endpoint* ep; }; +class EndpointSituationCallback : public IMMNotificationClient { + public: + //EndpointSituationCallback(IMMDeviceEnumerator *deviceEnumerator, std::vector playbackDevices); + ULONG AddRef(); + ULONG Release(); + HRESULT QueryInterface(REFIID riid, VOID **ppvInterface); + HRESULT OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId); + HRESULT OnDeviceAdded(LPCWSTR pwstrDeviceId); + HRESULT OnDeviceRemoved(LPCWSTR pwstrDeviceId); + HRESULT OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState); + HRESULT OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key); + + void fill(IMMDeviceEnumerator *deviceEnumerator, std::vector playbackDevices); + private: + ULONG ref = 1; + IMMDeviceEnumerator *deviceEnumerator; + std::vector playbackDevices; +}; + class Overseer { //TODO singleton? public: @@ -84,6 +105,9 @@ class Overseer { std::vector getPlaybackEndpoints(); void reloadEndpoints(); NGuid getGuid(); + //void setEndpointStatusCallback(); + //void setEndpointStatusCallback(); + //~Overseer(); //int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint); //int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint); @@ -95,7 +119,8 @@ class Overseer { NGuid guid; unsigned int numPlaybackEndpoints; IMMDeviceEnumerator *deviceEnumerator; - IPolicyConfig *policyConfig; + EndpointSituationCallback epsc; + //IPolicyConfig *policyConfig; std::vector playbackDevices; void initCOMLibrary(); //IMMDeviceCollection *deviceCollection; diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp index a6978b4..da1033c 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -70,6 +70,10 @@ uint8_t EndpointHandler::getRoles(){ return ep->getRoles(); } +void EndpointHandler::setRoles(Roles newRole){ + ep->setRoles(newRole); +} + EndpointHandler::~EndpointHandler() { ep->removeVolumeCallback(epc); epc->Release(); @@ -118,6 +122,10 @@ NGuid OverseerHandler::getGuid() { return this->os->getGuid(); } +void setChangeFrontDefaultsFunction(std::function changeFrontDefaults){ + this->changeFrontDefaults = changeFrontDefaults; +} + void OverseerHandler::setEndpointHandlers(std::vector ephs){ this->endpointHandlers = ephs; } diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index bc3c96d..55d33d8 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -18,6 +18,7 @@ enum EndpointState { ENDPOINT_DISABLED = (1 << 1), ENDPOINT_NOTPRESENT = (1 << 2), ENDPOINT_UNPLUGGED = (1 << 3), + ENDPOINT_ALL = 0x0F }; enum Flows { @@ -78,6 +79,7 @@ public: bool getMute(); uint8_t getState(); uint8_t getRoles(); + void setRoles(Roles newRole); void setVolume(NGuid guid, int channel, int value); void setMute(NGuid guid, bool muted); @@ -95,6 +97,7 @@ class OverseerHandler { public: OverseerHandler(); + void setChangeFrontDefaultsFunction(std::function changeFrontDefaults); void setEndpointHandlers(std::vector ephs); std::vector getEndpointHandlers(); std::vector getPlaybackEndpoints(); @@ -105,7 +108,7 @@ public: private: Overseer *os; std::vector endpointHandlers; - + std::function changeFrontDefaults; //std::function updateFrontVolumeCallback; //std::function updateFrontMuteCallback; diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index 5f14192..1140fca 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -67,18 +67,39 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare uint8_t assignedRoles = eph->getRoles(); defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setCheckState(assignedRoles == Roles::ROLE_ALL ? Qt::Checked : Qt::Unchecked); + //todo duditas de & + defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setDisabled(assignedRoles == Roles::ROLE_ALL ? true : false); defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setText(STRING_ROLE_ALL); defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setCheckState(assignedRoles & Roles::ROLE_CONSOLE ? Qt::Checked : Qt::Unchecked); + defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setDisabled(assignedRoles & Roles::ROLE_CONSOLE ? true : false); defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE)->setText(STRING_ROLE_CONSOLE); defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setCheckState(assignedRoles & Roles::ROLE_MULTIMEDIA ? Qt::Checked : Qt::Unchecked); + defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setDisabled(assignedRoles & Roles::ROLE_MULTIMEDIA ? true : false); defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA)->setText(STRING_ROLE_MULTIMEDIA); defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setCheckState(assignedRoles & Roles::ROLE_COMMUNICATIONS ? Qt::Checked : Qt::Unchecked); + defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setDisabled(assignedRoles & Roles::ROLE_COMMUNICATIONS ? true : false); defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS)->setText(STRING_ROLE_COMMUNICATIONS); + + connect(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), &QCheckBox::stateChanged,[this] { + this->eph->setRoles(Roles::ROLE_ALL); + //todo: bloquiar pto + }); + connect(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), &QCheckBox::stateChanged,[this] { + this->eph->setRoles(Roles::ROLE_CONSOLE); + //todo: bloquiar pto + }); + connect(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), &QCheckBox::stateChanged,[this] { + this->eph->setRoles(Roles::ROLE_MULTIMEDIA); + //todo: bloquiar pto + }); + connect(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), &QCheckBox::stateChanged,[this] { + this->eph->setRoles(Roles::ROLE_COMMUNICATIONS); + //todo: bloquiar pto + }); - defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setText(STRING_ROLE_ALL); layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), 3, 0); layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), 3, 1); layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), 3, 2);