diff --git a/bueno.bat b/bueno.bat index cd190f0..67fbd6a 100644 --- a/bueno.bat +++ b/bueno.bat @@ -1,2 +1,2 @@ qmake -o build\Makefile .\qtest.pro -mingw32-make.exe -C .\build -f Makefile.Release +mingw32-make.exe -C .\build -f Makefile diff --git a/qtest.pro b/qtest.pro index abfbb93..511e78a 100644 --- a/qtest.pro +++ b/qtest.pro @@ -1,8 +1,12 @@ +QMAKE_CXXFLAGS += --target=x86_64-w64-mingw32 -g -gcodeview +#QMAKE_LINK += clang++ +QMAKE_LFLAGS += --target=x86_64-w64-mingw32 -g -gcodeview -Wl,-pdb= -v +DEFINES += DEBUG 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 debug.h +HEADERS += qtclasses.h backlasses.h contclasses.h global.h debug.h backfuncs.h #DESTDIR += "build" diff --git a/src/back/backfuncs.h b/src/back/backfuncs.h new file mode 100644 index 0000000..06adc7e --- /dev/null +++ b/src/back/backfuncs.h @@ -0,0 +1,33 @@ +GUID NGuidToGUID(NGuid* guid) { + GUID msGuid = GUID(); + msGuid.Data1 = guid->data1; + msGuid.Data2 = guid->data2; + msGuid.Data3 = guid->data3; + msGuid.Data1 = guid->data1; + 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 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 acd4f3a..5269c29 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -1,17 +1,102 @@ #include +#include -Endpoint::Endpoint(IMMDevice* ep){ +EndpointCallback::EndpointCallback(Endpoint* ep){ + this->ep = ep; +} + +ULONG EndpointCallback::AddRef(){ + return InterlockedIncrement(&ref); +} + +ULONG EndpointCallback::Release(){ + ULONG tempRef = InterlockedDecrement(&ref); + if (tempRef == 0) { + delete this; + } + return tempRef; +} + +HRESULT EndpointCallback::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 EndpointCallback::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) { + if (pNotify == NULL) return E_INVALIDARG; + + float extraChannelVol[pNotify->nChannels]; + bool multiChannel = false; + AUDIO_VOLUME_NOTIFICATION_DATA eventData = *pNotify; + if(pNotify->nChannels > 1) { + multiChannel = true; + for (UINT i = 0; i < pNotify->nChannels; i++){ + extraChannelVol[i] = pNotify->afChannelVolumes[i]; + } + } + NGuid* guid = osh->getGuid(); + + if (memcmp(guid, &eventData, sizeof(*guid)) == 0) { + log_debugcpp("Onnanokotify says You Shall Not Update Thy Interface."); + } else { + log_debugcpp("Onnanokotify says Stored: " << guid->data1); + log_debugcpp("Onnanokotify says Grace of God: " << eventData.guidEventContext.Data1); + osh->updateMuteCallback(this->ep->getIndex(), eventData.bMuted); + osh->updateVolumeCallback(this->ep->getIndex(), AudioChannel::CHANNEL_MAIN ,eventData.fMasterVolume); + log_debugcpp("Onnanokotify says Reported Channel Qty: " << eventData.nChannels); + + if(multiChannel) + for(UINT i = 0; i < eventData.nChannels; i++) { + osh->updateVolumeCallback(this->ep->getIndex(), (uint32_t)i, extraChannelVol[i]); + } + else + osh->updateVolumeCallback(this->ep->getIndex(), (uint32_t)0, pNotify->afChannelVolumes[0]); + } + + return S_OK; +} + +/* EndpointCallback::~EndpointCallback(){ + * PAUDIO_VOLUME_NOTIFICATION_DATA->Release(); + * } */ + +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); endpoint->OpenPropertyStore(STGM_READ, &properties); PROPVARIANT pv; properties->GetValue(PKEY_Device_FriendlyName , &pv); - friendlyName = pv.pwszVal; + friendlyName = std::wstring(pv.pwszVal); } -LPWSTR Endpoint::getName(){ +void Endpoint::setIndex(uint64_t idx){ + this->idx = idx; +} + +uint64_t Endpoint::getIndex(){ + return idx; +} + + +std::wstring Endpoint::getName(){ return friendlyName; } @@ -25,6 +110,10 @@ float Endpoint::getVolume(int channel){ return volume; } +uint32_t Endpoint::getChannelCount(){ + return (uint32_t)channelCount; +} + bool Endpoint::getMute(){ BOOL mut; @@ -50,34 +139,44 @@ bool Endpoint::getMute(){ */ -void Endpoint::setVolume(int channel, float volume) { - if (channel == ENDPOINT_MASTER_VOLUME) { - if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, NULL))) { log_debugcpp("si"); }; +void Endpoint::setVolume(NGuid* guid, int channel, float volume) { + GUID tempMsGuid = NGuidToGUID(guid); + if (channel == AudioChannel::CHANNEL_MAIN) { + if(FAILED(endpointVolume->SetMasterVolumeLevelScalar(volume, &tempMsGuid))) { log_debugcpp("MASTER VOLUME FAILED"); }; } else { - if(FAILED(endpointVolume->SetChannelVolumeLevelScalar(channel, volume, NULL))) { log_debugcpp("si"); }; + log_debugcpp("Windows: Channel being updated: " << channel); + if(FAILED(endpointVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) { log_debugcpp("CHANNEL "<< channel <<" VOLUME FAILED"); }; } } -void Endpoint::setMute() { - log_debugcpp("bool mute arrives as " << mut); - BOOL mut; - if(FAILED(endpointVolume->GetMute(&mut))) { log_debugcpp("si"); } - log_debugcpp("translate to BOOL as " << mute); - if(FAILED(endpointVolume->SetMute((mut == false ? 1 : 0), NULL))) { log_debugcpp("si"); }; +void Endpoint::setMute(NGuid* guid, bool muted) { + //BOOL mut; + //log_debugcpp("bool mute arrives as " << mut); + //if(FAILED(endpointVolume->GetMute(&mut))) { log_debugcpp("si"); } + //log_debugcpp("translate to BOOL as " << mut); + //TODO: use new funcs + GUID tempMsGuid = NGuidToGUID(guid); + if(FAILED(endpointVolume->SetMute(muted, &tempMsGuid))) { log_debugcpp("MUTE FAILED"); }; } +void Endpoint::setCallback(EndpointCallback *epc){ + endpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); +} + +void Endpoint::removeCallback(EndpointCallback *epc){ + endpointVolume->UnregisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); +} Endpoint::~Endpoint(){ log_debugcpp("cum"); - free(friendlyName); properties->Release(); endpointVolume->Release(); endpoint->Release(); } - -void Overseer::initCOMLibrary(){ - if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { log_debugcpp("si"); }; +void Overseer::initCOMLibrary() { + if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) { + log_debugcpp("si"); }; //Retrieving endpoint enumerator @@ -87,6 +186,11 @@ void Overseer::initCOMLibrary(){ (void**)&deviceEnumerator)) ) { log_debugcpp("si"); }; + GUID tempGuid; + if(FAILED(CoCreateGuid(&tempGuid))) { log_debugcpp("Failed to obtain GUID: " ); }; + this->guid = GUIDToNGuid(&tempGuid); + //TODO: Release lpguid? + //TODO: Uninitialize COM } void Overseer::reloadEndpoints() { @@ -105,7 +209,8 @@ void Overseer::reloadEndpoints() { for (unsigned int i = 0; i < numPlaybackEndpoints; i++){ IMMDevice *temp; if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); }; - Endpoint *endpoint = new Endpoint(temp); + Endpoint *endpoint = new Endpoint(temp, i); + //endpoint->setIndex(i); this->playbackDevices.push_back(endpoint); //TODO: le porblemx std::cout << "ola" << std::endl; } @@ -115,6 +220,7 @@ void Overseer::reloadEndpoints() { Overseer::Overseer(){ //Initializing COM library + log_debugcpp("Initializing Overseer"); initCOMLibrary(); //Obtaining playback endpoint collection on this point in time @@ -129,6 +235,11 @@ Overseer::Overseer(){ //int Overseer::getDefaultCaptureEndpoint(Endpoint** defaultEndpoint); +//TODO guid +NGuid* Overseer::getGuid() { + return &guid; +} + std::vector Overseer::getPlaybackEndpoints() { return playbackDevices; } diff --git a/src/back/backlasses.h b/src/back/backlasses.h index ebfe0e5..0e816a8 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -1,10 +1,11 @@ #pragma once #define WIN32_LEAN_AND_MEAN +//done by qt by def #define UNICODE -#include "debug.h" -#include "global.h" -#include -#include +//#include "debug.h" +/* #include */ +/* #include */ +/* #include */ #include #include @@ -19,33 +20,60 @@ //#include #include +#include "global.h" +#include "contclasses.h" + +class EndpointCallback; + class Endpoint { public: - Endpoint(IMMDevice* endpoint); - void setVolume(int channel, float volume); - /* float getLeftChannelVolume(); */ - /* float getRightChannelVolume(); */ + Endpoint(IMMDevice* endpoint, uint64_t idx); + 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(); + void setMute(NGuid* guid, bool muted); bool getMute(); - LPWSTR getName(); + std::wstring getName(); + void setCallback(EndpointCallback *epc); + void removeCallback(EndpointCallback *epc); ~Endpoint(); private: + uint32_t channelCount; IMMDevice* endpoint; IAudioEndpointVolume *endpointVolume ; IPropertyStore *properties; - LPWSTR friendlyName; + std::wstring friendlyName; + uint64_t idx; // LPWSTR endpointID = NULL; }; +class EndpointCallback : public IAudioEndpointVolumeCallback { + + public: + EndpointCallback(Endpoint* ep); + + ULONG AddRef(); + ULONG Release(); + HRESULT QueryInterface(REFIID riid, VOID **ppvInterface); + HRESULT OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA update); + //~EndpointCallback(); + + private: + ULONG ref = 1; + Endpoint* ep; +}; + class Overseer { //TODO singleton? public: Overseer(); std::vector getPlaybackEndpoints(); void reloadEndpoints(); + NGuid* getGuid(); //~Overseer(); //int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint); //int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint); @@ -54,6 +82,7 @@ class Overseer { ~Overseer(); private: + NGuid guid; unsigned int numPlaybackEndpoints; IMMDeviceEnumerator *deviceEnumerator; std::vector playbackDevices; diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp index bd05f88..381550b 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -1,50 +1,138 @@ +#include "backlasses.h" #include "contclasses.h" +//TODO: pragma once +//TODO: ????? Overseer OverseerHandler::os; -EndpointHandler::EndpointHandler(Endpoint *ept, QObject *parent) : QObject(parent) { - this->ept = ept; - eptName = QString::fromStdWString(ept->getName()); +EndpointHandler::EndpointHandler(uint64_t idx) { + //std::vector endpoints = osh->getPlaybackEndpoints().at(idx); + this->ep = osh->getPlaybackEndpoints().at(idx); + epc = new EndpointCallback(ep); + //epName = ep->getName(); + ep->setCallback(epc); } + +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::setValue(int channel, int value){ +void EndpointHandler::setVolume(NGuid* guid, int channel, int value){ if (channel == ENDPOINT_MASTER_VOLUME) - ept->setVolume(channel, (float)value / 100); - else ept->setVolume(channel, (float)value / 100); + ep->setVolume(guid, channel, (float)value / 100); + else ep->setVolume(guid, channel, (float)value / 100); } -void EndpointHandler::setMute(){ +void EndpointHandler::setMute(NGuid* guid, bool muted){ //Qt momento, de ahi el param? log_debugcpp("kinda handling the muting tbh"); - ept->setMute(); + ep->setMute(guid, muted); } -QString EndpointHandler::getName(){ - return eptName; +std::wstring EndpointHandler::getName(){ + return ep->getName(); } float EndpointHandler::getVolume(int channel){ - return ept->getVolume(channel); + return ep->getVolume(channel); } bool EndpointHandler::getMute(){ - return ept->getMute(); + return ep->getMute(); } -Overseer* OverseerHandler::getOverseer(){ - return &os; +EndpointHandler::~EndpointHandler() { + ep->removeCallback(epc); + epc->Release(); + delete ep; } -OverseerHandler::OverseerHandler(QObject *parent) : QObject(parent) { - +std::vector OverseerHandler::getPlaybackEndpoints() { + return this->os.getPlaybackEndpoints(); } -std::vector* OverseerHandler::getEndpointHandlers(){ + +std::vector OverseerHandler::getEndpointHandlers(){ return endpointHandlers; } -void OverseerHandler::setEndpointHandlers(std::vector *ephs){ +uint64_t OverseerHandler::getPlaybackEndpointsCount(){ + return this->os.getPlaybackEndpoints().size(); +} + +void OverseerHandler::reloadEndpointHandlers(){ + //std::vector* ephs = new std::vector; + log_debugcpp(" VSize: " << this->getPlaybackEndpointsCount()); + + for(uint64_t i = 0; i < this->getPlaybackEndpointsCount(); i++){ + log_debugcpp("Creating handler " << i); + + if(i < (this->endpointHandlers.size()) && + this->endpointHandlers.at(i) != nullptr) + delete endpointHandlers.at(i); + + EndpointHandler* eph = new EndpointHandler(i); + log_debugcpp("Created handler " << i << ", adding to vector. " << " VSize: " << this->getPlaybackEndpointsCount()); + + if (i >= this->endpointHandlers.size()) + endpointHandlers.push_back(eph); + else endpointHandlers.at(i) = eph; + } + //setEndpointHandlers(ephs); +} + +NGuid* OverseerHandler::getGuid() { + return this->os.getGuid(); +} + +void OverseerHandler::setEndpointHandlers(std::vector ephs){ this->endpointHandlers = ephs; } + +void OverseerHandler::setFrontVolumeCallback(std::function f) { + this->updateFrontVolumeCallback = f; +} + +void OverseerHandler::setFrontMuteCallback(std::function f) { + this->updateFrontMuteCallback = f; +} + +void OverseerHandler::updateMuteCallback(uint64_t idx, bool muted){ + updateFrontMuteCallback(idx, muted); +} + +/* + * void OverseerHandler::updateMainVolumeCallback(uint64_t idx, float newVal){ + * + * } + */ + +void OverseerHandler::updateVolumeCallback(uint64_t idx, uint32_t channel, float newVal){ + if (channel == (uint32_t)AudioChannel::CHANNEL_MAIN) { + log_debugcpp("mainvolcallback float: " << newVal); + updateFrontVolumeCallback(idx, AudioChannel::CHANNEL_MAIN, newVal); + return; + } + + + // convert channel to bitmask + uint32_t i = 0; + while (i < channel) + i++; + uint32_t mask = (1 << i); + + log_debugcpp("Back->Cont Channel: " << mask << " volcallback float: " << newVal); + + updateFrontVolumeCallback(idx, mask, newVal); +} diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index c562b73..320564f 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -1,48 +1,84 @@ #pragma once -#include -#include "backlasses.h" +#define invoke_mem_fn(object,ptrToMember) ((object).*(ptrToMember)) +#define pinvoke_mem_fn(object,ptrToMember) ((object)->*(ptrToMember)) +/* #ifndef QTBLESSED */ +/* //#define Q_OBJECT */ +/* class QWidget{}; */ +/* class QMainWindow{}; */ +/* #endif */ -class EndpointHandler : public QObject { - Q_OBJECT +class EndpointWidget; +class Endpoint; +class EndpointCallback; +class Overseer; +enum AudioChannel { + CHANNEL_LEFT = (1 << 0), + CHANNEL_RIGHT = (1 << 1), + CHANNEL_MAIN = ~0, +}; + +struct NGuid { + uint32_t data1; + uint16_t data2; + uint16_t data3; + unsigned char data4[8]; +}; + +class EndpointHandler { + public: - EndpointHandler(Endpoint *ept, QObject *parent = nullptr); - QString getName(); + EndpointHandler(uint64_t idx); + //TODO: get(); + Endpoint *ep = nullptr; + EndpointCallback *epc = nullptr; + //std::wstring epName; + + uint32_t getChannelCount(); + + void setIndex(uint64_t idx); + uint64_t getIndex(); + void setVolume(int channel, float volume); + + std::wstring getName(); float getVolume(int channel); bool getMute(); - -private: - Endpoint *ept; - QString eptName; - //QSlider *slidy; -public slots: - void setValue(int channel, int value); - void setMute(); + void setVolume(NGuid* guid, int channel, int value); + void setMute(NGuid* guid, bool muted); + + ~EndpointHandler(); +private: + uint64_t idx; + //QSlider *slidy; + //signals: }; -class OverseerHandler : public QObject { - Q_OBJECT +class OverseerHandler { public: - OverseerHandler(QObject *parent = nullptr); - void setEndpointHandlers(std::vector *ephs); - std::vector* getEndpointHandlers(); - static Overseer* getOverseer(); + //OverseerHandler(); + void setEndpointHandlers(std::vector ephs); + std::vector getEndpointHandlers(); + std::vector getPlaybackEndpoints(); + uint64_t getPlaybackEndpointsCount(); + void reloadEndpointHandlers(); + NGuid* getGuid(); + void updateMuteCallback(uint64_t idx, bool muted); + void setFrontMuteCallback(std::function f); + void setFrontVolumeCallback(std::function f); + //void updateMainVolumeCallback(uint64_t idx, float newVal); + void updateVolumeCallback(uint64_t idx, uint32_t channel, float newVal); private: static Overseer os; - std::vector *endpointHandlers; - //QSlider *slidy; - - //public slots: - //void setValue(int value); - - - + std::vector endpointHandlers; + std::function updateFrontVolumeCallback; + std::function updateFrontMuteCallback; + }; diff --git a/src/debug.h b/src/debug.h index f91232b..e80893f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -2,9 +2,28 @@ #if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG) +template +std::bitset varToBitset(T info) { + std::bitset content(info); + return content; +} + #define log_debugcpp(str) do { \ std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \ } while (0) + +#define print_as_binary(len, type, info) varToBitset(info) + #else -#define log_debugcpp(str) +#define log_debugcpp(str) +#define print_as_binary(len, type, info) #endif + +/* Here as a quick reference, in case smthn similar is needed again */ +/* typedef void (EndpointWidget::*epwMuteFunc)(bool muted); */ +/* typedef void (EndpointWidget::*epwMainVolumeFunc)(float newValue); */ +/* typedef void (EndpointWidget::*epwChannelVolumeFunc)(uint32_t channel, float newValue); */ +/* typedef void (EndpointWidget::*epwToggleFrontFunc)(bool active); */ + + + diff --git a/src/global.h b/src/global.h index 96d177b..c4cf2af 100644 --- a/src/global.h +++ b/src/global.h @@ -1,15 +1,20 @@ #pragma once -//TODO enum capullo +#include +#include +#include +#include + +#include "debug.h" + #define ENDPOINT_MASTER_VOLUME -1 -#define ENDPOINT_LEFT_CHANNEL_VOLUME 0 -#define ENDPOINT_RIGHT_CHANNEL_VOLUME 1 +/* #define ENDPOINT_LEFT_CHANNEL_VOLUME 0 */ +/* #define ENDPOINT_RIGHT_CHANNEL_VOLUME 1 */ #define STRING_MUTE "Mute" #define STRING_UNMUTE "Unmute" //INIT BACK - class OverseerHandler; extern OverseerHandler *osh; diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index 0cac13d..155cd90 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -1,5 +1,20 @@ #include "qtclasses.h" +/* + * ToggleButton::ToggleButton(QWidget *parent) : QAbstractButton(parent) { + * this->setCheckable(true); + * } + * + * ToggleButton::~ToggleButton(){ + * + * } + * + * void ToggleButton::checkStateSet(){ } + * + * bool hitButton(const QPoint &pos) { + * + * } + */ EndpointWidget::EndpointWidget(EndpointHandler* eph, QWidget *parent) : QWidget(parent){ this->eph = eph; @@ -8,36 +23,21 @@ EndpointWidget::EndpointWidget(EndpointHandler* eph, QWidget *parent) : QWidget( log_debugcpp("olaW"); if (parent == nullptr) { log_debugcpp("owo?"); } - muteButton = new QPushButton(); - mainLabel = new QLabel(eph->getName()); - leftChannelLabel = new QLabel("88"); - rightChannelLabel = new QLabel("77"); + muteButton = new QCheckBox(); + mainLabel = new QLabel(QString::fromStdWString(eph->getName())); mainSlider = new QSlider(Qt::Horizontal); - leftChannelSlider = new QSlider(Qt::Horizontal); - rightChannelSlider = new QSlider(Qt::Horizontal); - - muteButton->setStyleSheet("background-color: #A3C1DA; color: red"); + + //muteButton->setStyleSheet("background-color: #A3C1DA; color: red"); mainSlider->setFocusPolicy(Qt::StrongFocus); mainSlider->setTickPosition(QSlider::TicksBothSides); mainSlider->setTickInterval(5); mainSlider->setSingleStep(1); mainSlider->setRange(0,100); - leftChannelSlider->setTickInterval(5); - leftChannelSlider->setSingleStep(1); - leftChannelSlider->setRange(0,100); - rightChannelSlider->setTickInterval(5); - rightChannelSlider->setSingleStep(1); - rightChannelSlider->setRange(0,100); + muteButton->setCheckState((eph->getMute() == false ? Qt::Unchecked : Qt::Checked)); muteButton->setText(eph->getMute() ? STRING_UNMUTE : STRING_MUTE); float volume = eph->getVolume(ENDPOINT_MASTER_VOLUME) * 100; mainSlider->setValue((int)volume); - volume = eph->getVolume(ENDPOINT_LEFT_CHANNEL_VOLUME) * 100; - leftChannelSlider->setValue((int)volume); - leftChannelLabel->setText(QString::number(volume)); - volume = eph->getVolume(ENDPOINT_RIGHT_CHANNEL_VOLUME) * 100; - rightChannelSlider->setValue((int)volume); - rightChannelLabel->setText(QString::number(volume)); log_debugcpp("ENDPOINT SET WITH VOLUME " << volume); mainMuteLayout = new QGridLayout(); @@ -45,25 +45,108 @@ EndpointWidget::EndpointWidget(EndpointHandler* eph, QWidget *parent) : QWidget( mainMuteLayout->addWidget(mainLabel, 0, 0); mainMuteLayout->addWidget(muteButton, 0, 1); layout->addWidget(mainSlider, 0, 1); - layout->addWidget(leftChannelSlider, 1, 0); - layout->addWidget(leftChannelLabel, 2, 0); - layout->addWidget(rightChannelSlider, 1, 1); - layout->addWidget(rightChannelLabel, 2, 1); + + connect(mainSlider, &QSlider::valueChanged, this,&EndpointWidget::updateMainVolume); + connect(muteButton, &QCheckBox::stateChanged, this, (&EndpointWidget::updateMute)); + + for(uint32_t i = 0; i < eph->getChannelCount(); i++){ + QSlider* tmp = new QSlider(Qt::Horizontal); + QLabel* tmpLb = new QLabel(""); + tmp->setTickInterval(5); + tmp->setSingleStep(1); + tmp->setRange(0,100); + volume = eph->getVolume(i) * 100; + tmp->setValue((int) volume); + tmpLb->setText(QString::number(volume)); + this->channelSliders.push_back(tmp); + this->channelLabels.push_back(tmpLb); + layout->addWidget(tmp, 1, i); + layout->addWidget(tmpLb, 2, i); + //TODO: check if there's a need to prevent deadlocks; probably this will eventually turn into its own func + connect(tmp, &QSlider::valueChanged, [this, i](int newValue){ this->eph->setVolume(osh->getGuid(), i, newValue); this->channelLabels.at(i)->setText(QString::number(newValue)); }); + } + layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 3, 0); layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 3, 1); - - /* - * connect(mainSlider, &QSlider::valueChanged, eph, &EndpointHandler::setValue); - */ - connect(mainSlider, &QSlider::valueChanged, [this](int newValue){this->eph->setValue(ENDPOINT_MASTER_VOLUME, newValue); }); - connect(leftChannelSlider, &QSlider::valueChanged, [this](int newValue){ this->eph->setValue(ENDPOINT_LEFT_CHANNEL_VOLUME, newValue); this->leftChannelLabel->setText(QString::number(newValue)); }); - connect(rightChannelSlider, &QSlider::valueChanged, [this](int newValue){ this->eph->setValue(ENDPOINT_RIGHT_CHANNEL_VOLUME, newValue); this->rightChannelLabel->setText(QString::number(newValue)); }); - connect(muteButton, &QPushButton::clicked, [this](bool clicked){ log_debugcpp("cliqui" << clicked << "cloqui"); this->eph->setMute(); this->muteButton->setText(this->eph->getMute() ? STRING_UNMUTE : STRING_MUTE); }); log_debugcpp("ENDPOINT_WIDGETED"); } +void EndpointWidget::updateMute(bool muted){ + log_debugcpp("cliqui callboqui cloqui"); + //TIP: Blocksignals here to diagnose slider visuals locking when playing DJ with external volume bar. Functionality is restored when mute checkbox is clicked. + //this->blockSignals(true); + //this->muteButton->blockSignals(true); + + //this->eph->setMute(osh->getGuid(), muted); + this->muteButton->setChecked(muted); + this->muteButton->setText(this->eph->getMute() ? STRING_UNMUTE : STRING_MUTE); + //this->muteButton->blockSignals(false); + //this->blockSignals(false); +} -MainWindow::MainWindow(std::vector *ephs, QWidget *parent) : QMainWindow(parent) { +void EndpointWidget::updateMute(int checked){ + log_debugcpp("cliqui slOtty cloqui"); + bool muted = (checked == 2 ? true : false); + log_debugcpp("int: " << checked << " bool: " << muted); + this->eph->setMute(osh->getGuid(), muted); + //this->muteButton->setCheckState(); + this->muteButton->setText(this->eph->getMute() ? STRING_UNMUTE : STRING_MUTE); +} + +void EndpointWidget::updateMainVolume(int newValue){ + log_debugcpp("updateMainVolume slot."); + this->eph->setVolume(osh->getGuid(), ENDPOINT_MASTER_VOLUME, newValue); +} + +void EndpointWidget::updateVolume(uint32_t channel, float newValue){ + //this->blockSignals(true); + int newVal = newValue * 100; + if (channel == (uint32_t)AudioChannel::CHANNEL_MAIN) { + log_debugcpp("mainvolcallback int: " << newVal); + //this->mainSlider->blockSignals(true); + + if(this->mainSlider->value() != newVal) { + this->mainSlider->setValue(newVal); + } + return; + } + + log_debugcpp("Cont->Front Channel:: " << channel << " volcallback int: " << newVal); + + for (size_t i = 0; i < sizeof(uint32_t) * 8 && i < channelSliders.size(); ++i) { + if (((channel >> i) & 1) && this->channelSliders.at(i)->value() != newVal) { + //this->channelSliders.at(i)->blockSignals(true); + + this->channelSliders.at(i)->setValue(newVal); + this->channelLabels.at(i)->setText(QString::number((int)(newValue * 100))); + + //this->channelSliders.at(i)->blockSignals(false); + } + } + + //this->blockSignals(false); +} + +/* + * void EndpointWidget::toggleFrontEvents(bool active){ + * this->muteButton->blockSignals(active); + * this->mainSlider->blockSignals(active); + * for(uint32_t i = 0; i < this->channelSliders.size(); i++){ + * this->channelSliders.at(i)->blockSignals(active); + * } + * } + */ + + +void EndpointWidget::setIndex(uint64_t idx){ + this->idx = idx; +} + +uint64_t EndpointWidget::getIndex(){ + return idx; +} + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // setWindowState(Qt::WindowFullScreen); // setCentralWidget(centralWidget); widget = new QWidget(); @@ -74,27 +157,31 @@ MainWindow::MainWindow(std::vector *ephs, QWidget *parent) : Q //layout->addWidget(pintas, 0, 0); setWindowTitle("slidea resbala nu c"); + + reloadEndpointWidgets(); +} - /*s - * setEndpointHandlers(ephs); - */ +void MainWindow::reloadEndpointWidgets() { unsigned int i = 0; - for (; i < ephs->size(); i++) { + for (; i < (osh->getEndpointHandlers().size()); i++) { log_debugcpp("EPWidget creation"); - EndpointWidget *epw = new EndpointWidget(ephs->at(i), widget); + EndpointWidget *epw = new EndpointWidget(osh->getEndpointHandlers().at(i), widget); ews.push_back(epw); layout->addWidget(epw, i, 0); } + layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), i, 0); + + osh->setFrontVolumeCallback([this](uint64_t device, uint32_t channel, float value) { + if (device < ews.size()) + ews[device]->updateVolume(channel, value); + }); + osh->setFrontMuteCallback([this](uint64_t device, bool muted) { + if (device < ews.size()) + ews[device]->updateMute(muted); + }); } -/* - * void MainWindow::setEndpointHandlers(std::vector *ephs){ - * this->ephs = ephs; - */ - - - /* * void MainWindow::setPlotButton() { * button = new QPushButton("push"), @@ -112,3 +199,4 @@ MainWindow::MainWindow(std::vector *ephs, QWidget *parent) : Q * ... */ + diff --git a/src/qt/qtclasses.h b/src/qt/qtclasses.h index a02bff8..c5eee14 100644 --- a/src/qt/qtclasses.h +++ b/src/qt/qtclasses.h @@ -1,54 +1,104 @@ #pragma once + #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include #include #include #include #include #include #include -#include "contclasses.h" -//#include -//#include +#include +/* + * #else + * class QSlider; + * class QLabel; + * class QGridLayout; + * class QPushButton; + * class QWidget; + * class QMainWindow; + * #endif + */ +#include "global.h" +#include "contclasses.h" +//class EndpointHandler; + +/* + * class ToggleButton : public QAbstractButton { + * Q_OBJECT + * + * public: + * ToggleButton(QWidget *parent = nullptr); + * void checkStateSet(); + * bool hitButton(const QPoint &pos) const; + * void nextCheckState(); + * void changeEvent(QEvent *e) override; + * bool event(QEvent *e) override; + * void focusInEvent(QFocusEvent *e) override; + * void focusOutEvent(QFocusEvent *e) override; + * void keyPressEvent(QKeyEvent *e) override; + * void keyReleaseEvent(QKeyEvent *e) override; + * void mouseMoveEvent(QMouseEvent *e) override; + * void mousePressEvent(QMouseEvent *e) override; + * void mouseReleaseEvent(QMouseEvent *e) override; + * void paintEvent(QPaintEvent *e) override = 0; + * void timerEvent(QTimerEvent *e) override; + * ToggleButton(QWidget *parent = nullptr); + * }; + */ class EndpointWidget : public QWidget { Q_OBJECT public: EndpointWidget(EndpointHandler* eph, QWidget *parent = nullptr); - //void populateEndpointWidget(EndpointHandler *eph); - //void setEndpointHandlers(std::vector *ephs); - -private: + //TODO: get(); EndpointHandler* eph; - QPushButton *muteButton = nullptr; + void setIndex(uint64_t idx); + uint64_t getIndex(); + + void setVolume(int channel, float volume); + + QCheckBox *muteButton = nullptr; QLabel *mainLabel = nullptr, *leftChannelLabel = nullptr, *rightChannelLabel = nullptr; QSlider *mainSlider = nullptr; - QSlider *leftChannelSlider = nullptr; - QSlider *rightChannelSlider = nullptr; + std::vector channelSliders; + std::vector channelLabels; QGridLayout *layout = nullptr; QGridLayout *mainMuteLayout = nullptr; + //void updateMainVolume(float newValue); + void updateVolume(uint32_t channel, float newValue); + void updateMute(bool muted); + //void toggleFrontEvents(bool active); + + //void populateEndpointWidget(EndpointHandler *eph); + //void setEndpointHandlers(std::vector *ephs); + +public slots: + void updateMainVolume(int newValue); + void updateMute(int checked); + +private: + uint64_t idx; //std::vector *ephs; //std::vector *sliders; - - //public slots: - // void setEndpointHandlers(std::vector *ephs); //signals: //void valueChanged(int value); }; - class MainWindow : public QMainWindow { Q_OBJECT //QWidget *centralWidget; public: - MainWindow(std::vector *ephs, QWidget *parent = nullptr); + MainWindow(QWidget *parent = nullptr); + void reloadEndpointWidgets(); + + //TODO: destroy/empty existing EndpointWidgets //void setEndpointHandlers(std::vector *ephs); private: diff --git a/src/qtestmain.cpp b/src/qtestmain.cpp index 883d7e7..15d18fc 100644 --- a/src/qtestmain.cpp +++ b/src/qtestmain.cpp @@ -1,14 +1,15 @@ -#include -#include - //#include //#include //#include + +//#define QTBLESSED #include #include +//#include "contclasses.h" #include "qtclasses.h" +#include "global.h" OverseerHandler *osh = new OverseerHandler(); @@ -21,19 +22,16 @@ QApplication* createApplication(int &argc, char *argv[]) int main (int argc, char* argv[]) { //QApplication::setStyle("windowsvista"); //INIT CONT - std::vector epts = OverseerHandler::getOverseer()->getPlaybackEndpoints(); - std::vector* ephs = new std::vector; - for(unsigned int i = 0; i < epts.size(); i++){ - EndpointHandler *eph = new EndpointHandler(epts.at(i)); - ephs->push_back(eph); - } + log_debugcpp("main init"); + osh->reloadEndpointHandlers(); + log_debugcpp("Reloaded endpoint handlers"); - osh->setEndpointHandlers(ephs); //INIT FRONT QScopedPointer app(createApplication(argc, argv)); - MainWindow window = MainWindow(ephs); + MainWindow window = MainWindow(); //window.setEndpointHandlers(ephs); app->setStyle("windowsvista"); window.show(); return app->exec(); } +