diff --git a/qtest.pro b/qtest.pro index 8e3d0d0..b4af8be 100644 --- a/qtest.pro +++ b/qtest.pro @@ -10,7 +10,7 @@ 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 debug.h backfuncs.h +HEADERS += qtclasses.h backlasses.h contclasses.h global.h debug.h backfuncs.h ipolicyconfig.h RESOURCES = assets.qrc #DESTDIR += "build" diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index dba9c69..40abc4c 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -1,15 +1,15 @@ #include #include -EndpointCallback::EndpointCallback(Endpoint* ep){ +EndpointVolumeCallback::EndpointVolumeCallback(Endpoint* ep){ this->ep = ep; } -ULONG EndpointCallback::AddRef(){ +ULONG EndpointVolumeCallback::AddRef(){ return InterlockedIncrement(&ref); } -ULONG EndpointCallback::Release(){ +ULONG EndpointVolumeCallback::Release(){ ULONG tempRef = InterlockedDecrement(&ref); if (tempRef == 0) { delete this; @@ -17,7 +17,7 @@ ULONG EndpointCallback::Release(){ return tempRef; } -HRESULT EndpointCallback::QueryInterface(REFIID riid, VOID **ppvInterface) { +HRESULT EndpointVolumeCallback::QueryInterface(REFIID riid, VOID **ppvInterface) { if (IID_IUnknown == riid) { AddRef(); @@ -36,10 +36,9 @@ HRESULT EndpointCallback::QueryInterface(REFIID riid, VOID **ppvInterface) { return S_OK; } -HRESULT EndpointCallback::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) { +HRESULT EndpointVolumeCallback::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) { if (pNotify == NULL) return E_INVALIDARG; - //TODO: MEMORY LEAK. FREE DATA4 FROM NGUID. //TODO: el default = objcopy frees? //delete osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller; //osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.freeData4(); @@ -71,10 +70,24 @@ HRESULT EndpointCallback::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) { Endpoint::Endpoint(IMMDevice* ep, uint64_t idx){ this->endpoint = ep; this->idx = idx; - if(FAILED(endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&endpointVolume))) { log_debugcpp("si"); }; - if (FAILED(endpointVolume->GetChannelCount(&channelCount))) log_debugcpp("get channel count fail"); - //Obtaining friendly name: IPropertyStore creates PROPVARIANT per field - // hr = endpointPtr->GetId(&endpointID); + //if(FAILED()) {}; + DWORD tempState = 0; + if(FAILED(endpoint->GetState(&tempState))) {exit(-1);}; + this->endpointState = tempState; + + if (tempState == DEVICE_STATE_ACTIVE) { + if(FAILED(endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&endpointVolume))) { /* log_debugcpp("si"); */ }; + + if (FAILED(endpointVolume->GetChannelCount(&channelCount))) {};/* log_debugcpp("get channel count fail"); */ + } else channelCount = 0; + + //todo:: atexit into exit Gather ID + LPWSTR tempString = nullptr; + if (FAILED(endpoint->GetId(&tempString))) {exit(-1);}; + endpointId = std::wstring(tempString); + log_wdebugcpp(endpointId); + CoTaskMemFree(tempString); + endpoint->OpenPropertyStore(STGM_READ, &properties); PROPVARIANT pv; properties->GetValue(PKEY_Device_FriendlyName , &pv); @@ -94,6 +107,10 @@ std::wstring Endpoint::getName(){ return friendlyName; } +std::wstring Endpoint::getId(){ + return endpointId; +} + float Endpoint::getVolume(int channel){ float volume; if (channel == AudioChannel::CHANNEL_MAIN) { @@ -116,19 +133,13 @@ bool Endpoint::getMute(){ return mute; } -/* - * float Endpoint::getLeftChannelVolume(){ - * float volume; - * if(FAILED(endpointVolume-> GetChannelVolumeLevelScalar(0, &volume)) { log_debugcpp("si"); } ); - * return volume; - * } - * - * float Endpoint::getRightChannelVolume(){ - * float volume; - * if(FAILED(endpointVolume-> GetChannelVolumeLevelScalar(1, &volume)) { log_debugcpp("si");} - * return volume; - * } - */ +void Endpoint::setState(uint8_t state){ + this->endpointState = state; +} + +uint8_t Endpoint::getState(){ + return this->endpointState; +} void Endpoint::setVolume(NGuid* guid, int channel, float volume) { @@ -146,16 +157,26 @@ void Endpoint::setMute(NGuid* guid, bool muted) { if(FAILED(endpointVolume->SetMute(muted, &tempMsGuid))) { /* TIP: Above */ }; } -void Endpoint::setCallback(EndpointCallback *epc){ +void Endpoint::setVolumeCallback(EndpointVolumeCallback *epc){ endpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); } -void Endpoint::removeCallback(EndpointCallback *epc){ +void Endpoint::removeVolumeCallback(EndpointVolumeCallback *epc){ endpointVolume->UnregisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); } +uint8_t Endpoint::getRoles(){ + return this->endpointRoles; +} + +void Endpoint::setRoles(uint8_t role){ + //todo: operador virtuoso + uint8_t roles = endpointRoles | role; + this->endpointRoles = roles; +} + Endpoint::~Endpoint(){ - log_debugcpp("cum"); + log_debugcpp("murio endpoint-san uwu"); properties->Release(); endpointVolume->Release(); endpoint->Release(); @@ -183,7 +204,7 @@ void Overseer::initCOMLibrary() { void Overseer::reloadEndpoints() { IMMDeviceCollection *deviceCollection; // | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED - if(FAILED(deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection) )) + if(FAILED(deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE , &deviceCollection) )) { log_debugcpp("si"); }; @@ -193,8 +214,8 @@ void Overseer::reloadEndpoints() { //Retrieving actual endpoints and storing them on their own class + IMMDevice *temp; for (unsigned int i = 0; i < numPlaybackEndpoints; i++){ - IMMDevice *temp; if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); }; Endpoint *endpoint = new Endpoint(temp, i); //endpoint->setIndex(i); @@ -203,6 +224,36 @@ void Overseer::reloadEndpoints() { } 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(EDataFlow::eRender, val, &temp); + LPWSTR id = nullptr; + + for (unsigned int j = 0; j < numPlaybackEndpoints; j++){ + std::wstring test = playbackDevices.at(j)->getId(); + temp->GetId(&id); + int comparison = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, test.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)); + } + //uint8_t debg = playbackDevices.at(j)->getRoles(); + } + } } Overseer::Overseer(){ diff --git a/src/back/backlasses.h b/src/back/backlasses.h index 0e816a8..f79de72 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -19,11 +19,12 @@ //#include //#include #include +#include #include "global.h" #include "contclasses.h" -class EndpointCallback; +class EndpointVolumeCallback; class Endpoint { @@ -36,9 +37,14 @@ class Endpoint { float getVolume(int channel); void setMute(NGuid* guid, bool muted); bool getMute(); + void setState(uint8_t state); + uint8_t getState(); + uint8_t getRoles(); + void setRoles(uint8_t role); + std::wstring getId(); std::wstring getName(); - void setCallback(EndpointCallback *epc); - void removeCallback(EndpointCallback *epc); + void setVolumeCallback(EndpointVolumeCallback *epc); + void removeVolumeCallback(EndpointVolumeCallback *epc); ~Endpoint(); private: @@ -47,20 +53,23 @@ class Endpoint { IAudioEndpointVolume *endpointVolume ; IPropertyStore *properties; std::wstring friendlyName; + std::wstring endpointId; + uint8_t endpointState; + uint8_t endpointRoles = 0; uint64_t idx; // LPWSTR endpointID = NULL; }; -class EndpointCallback : public IAudioEndpointVolumeCallback { +class EndpointVolumeCallback : public IAudioEndpointVolumeCallback { public: - EndpointCallback(Endpoint* ep); + EndpointVolumeCallback(Endpoint* ep); ULONG AddRef(); ULONG Release(); HRESULT QueryInterface(REFIID riid, VOID **ppvInterface); HRESULT OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA update); - //~EndpointCallback(); + //~EndpointVolumeCallback(); private: ULONG ref = 1; diff --git a/src/back/ipolicyconfig.h b/src/back/ipolicyconfig.h new file mode 100644 index 0000000..203188c --- /dev/null +++ b/src/back/ipolicyconfig.h @@ -0,0 +1,180 @@ +// ---------------------------------------------------------------------------- +// PolicyConfig.h +// Undocumented COM-interface IPolicyConfig. +// Use for set default audio render endpoint +// @author EreTIk +// ---------------------------------------------------------------------------- + + +#pragma once + + +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( + __in PCWSTR wszDeviceId, + __in 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/cont/contclasses.cpp b/src/cont/contclasses.cpp index f51125d..edfa18b 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -8,9 +8,9 @@ Overseer OverseerHandler::os; EndpointHandler::EndpointHandler(uint64_t idx) { //std::vector endpoints = osh->getPlaybackEndpoints().at(idx); this->ep = osh->getPlaybackEndpoints().at(idx); - epc = new EndpointCallback(ep); + epc = new EndpointVolumeCallback(ep); //epName = ep->getName(); - ep->setCallback(epc); + ep->setVolumeCallback(epc); callbackInfo.muted = this->getMute(); callbackInfo.mainVolume = this->getVolume(AudioChannel::CHANNEL_MAIN); callbackInfo.channels = this->getChannelCount(); @@ -20,7 +20,7 @@ EndpointHandler::EndpointHandler(uint64_t idx) { } } -BackEndpointCallbackInfo* EndpointHandler::getCallbackInfo(){ +BackEndpointVolumeCallbackInfo* EndpointHandler::getCallbackInfo(){ return &this->callbackInfo; } @@ -61,8 +61,20 @@ bool EndpointHandler::getMute(){ return ep->getMute(); } +uint8_t EndpointHandler::getState(){ + return ep->getState(); +} + +void EndpointHandler::setState(uint8_t state){ + ep->setState(state); +} + +uint8_t EndpointHandler::getRoles(){ + return ep->getRoles(); +} + EndpointHandler::~EndpointHandler() { - ep->removeCallback(epc); + ep->removeVolumeCallback(epc); epc->Release(); delete ep; } diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index 3cde72a..0b8b733 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -4,7 +4,7 @@ class EndpointWidget; class Endpoint; -class EndpointCallback; +class EndpointVolumeCallback; class Overseer; enum AudioChannel { @@ -13,6 +13,26 @@ enum AudioChannel { CHANNEL_MAIN = ~0, }; +enum EndpointState { + ENDPOINT_ACTIVE = (1 << 0), + ENDPOINT_DISABLED = (1 << 1), + ENDPOINT_NOTPRESENT = (1 << 2), + ENDPOINT_UNPLUGGED = (1 << 3), +}; + +enum Flows { + FLOW_PLAYBACK = (1 << 0), + FLOW_CAPTURE = (1 << 1), + FLOW_BOTH = (1 << 2), +}; + +enum Roles { + ROLE_CONSOLE = (1 << 0), + ROLE_MULTIMEDIA = (1 << 1), + ROLE_COMMUNICATIONS = (1 << 2), + ROLE_ALL = (7 << 0), +}; + struct NGuid { uint32_t data1; uint16_t data2; @@ -29,7 +49,7 @@ struct NGuid { /* } */ }; -struct BackEndpointCallbackInfo { +struct BackEndpointVolumeCallbackInfo { NGuid caller; bool muted; float mainVolume; @@ -43,10 +63,10 @@ public: EndpointHandler(uint64_t idx); //TODO: get(); Endpoint *ep = nullptr; - EndpointCallback *epc = nullptr; + EndpointVolumeCallback *epc = nullptr; //std::wstring epName; - BackEndpointCallbackInfo* getCallbackInfo(); + BackEndpointVolumeCallbackInfo* getCallbackInfo(); uint32_t getChannelCount(); void setIndex(uint64_t idx); @@ -56,14 +76,17 @@ public: std::wstring getName(); float getVolume(int channel); bool getMute(); - + uint8_t getState(); + uint8_t getRoles(); + void setVolume(NGuid* guid, int channel, int value); void setMute(NGuid* guid, bool muted); + void setState(uint8_t state); ~EndpointHandler(); private: uint64_t idx; - BackEndpointCallbackInfo callbackInfo; + BackEndpointVolumeCallbackInfo callbackInfo; //QSlider *slidy; }; diff --git a/src/debug.h b/src/debug.h index e80893f..8e309cf 100644 --- a/src/debug.h +++ b/src/debug.h @@ -12,10 +12,15 @@ std::bitset varToBitset(T info) { 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) + #define print_as_binary(len, type, info) varToBitset(info) #else #define log_debugcpp(str) +#define log_wdebugcpp(str) #define print_as_binary(len, type, info) #endif diff --git a/src/global.h b/src/global.h index 8d5a768..0ae2a75 100644 --- a/src/global.h +++ b/src/global.h @@ -11,7 +11,12 @@ #define STRING_MUTE "Mute" #define STRING_UNMUTE "Unmute" #define STRING_QUIT "Quit" -#define STRING_TITLE "Mixer Fachero" +#define STRING_TITLE "Mixer Fachero" + +#define STRING_ROLE_CONSOLE "Console" +#define STRING_ROLE_MULTIMEDIA "Multimedia" +#define STRING_ROLE_COMMUNICATIONS "Communications" +#define STRING_ROLE_ALL "All" //INIT BACK class OverseerHandler; diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index 53bd91a..9641e04 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -8,6 +8,14 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare log_debugcpp("olaW"); if (parent == nullptr) { log_debugcpp("owo?"); } + + defaultRolesCheckBoxes = { + {Roles::ROLE_ALL, new QCheckBox()}, + {Roles::ROLE_CONSOLE, new QCheckBox()}, + {Roles::ROLE_MULTIMEDIA, new QCheckBox()}, + {Roles::ROLE_COMMUNICATIONS, new QCheckBox()} + }; + muteButton = new QCheckBox(); mainLabel = new QLabel(QString::fromStdWString(eph->getName())); mainSlider = new QSlider(Qt::Horizontal); @@ -58,6 +66,18 @@ 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); + /* + * {ROLE_ALL, new QCheckBox(this)}, + * {ROLE_CONSOLE, new QCheckBox(this)}, + * {ROLE_MULTIMEDIA, new QCheckBox(this)}, + * {ROLE_COMMUNICATIONS, new QCheckBox(this)} + * }; + */ + layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), 3, 0); + + //Polling time timer = new QTimer(this); connect(timer, &QTimer::timeout, [this, eph](){ diff --git a/src/qt/qtclasses.h b/src/qt/qtclasses.h index b8cffe8..4082fc7 100644 --- a/src/qt/qtclasses.h +++ b/src/qt/qtclasses.h @@ -76,6 +76,8 @@ public: std::vector channelLabels; QGridLayout *layout = nullptr; QGridLayout *mainMuteLayout = nullptr; + std::map defaultRolesCheckBoxes; + //void updateMainVolume(float newValue); //void updateVolume(uint32_t channel, float newValue); //void updateMute(bool muted); @@ -88,6 +90,7 @@ public slots: void updateMute(int checked); private: + size_t defaultRolesVectorSize = 4; QTimer* timer = nullptr; uint64_t idx; //std::vector *ephs;