endpoint add/remove foundational work

This commit is contained in:
Hane 2023-09-06 17:57:15 +02:00
commit a6a052f348
6 changed files with 103 additions and 96 deletions

View file

@ -183,16 +183,15 @@ HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId,
Endpoint::Endpoint(IMMDevice* ep, uint64_t idx){ Endpoint::Endpoint(IMMDevice* ep, uint64_t idx){
this->endpoint = ep; this->endpoint = ep;
this->idx = idx; this->idx = idx;
//if(FAILED()) {};
DWORD tempState = 0;
if(FAILED(endpoint->GetState(&tempState))) {exit(-1);};
this->endpointState = tempState;
if (tempState == DEVICE_STATE_ACTIVE) { //todo: preguntitas owindows dword no es uint32_t even tho mingw mingas
if(FAILED(endpoint->GetState(&this->endpointState))) {exit(-1);};
if (this->endpointState == DEVICE_STATE_ACTIVE) {
if(FAILED(endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&endpointVolume))) { /* log_debugcpp("si"); */ }; 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"); */ if (FAILED(endpointVolume->GetChannelCount(&channelCount))) {};/* log_debugcpp("get channel count fail"); */
} else channelCount = 0; }
//todo:: atexit into exit Gather ID //todo:: atexit into exit Gather ID
LPWSTR tempString = nullptr; LPWSTR tempString = nullptr;
@ -250,7 +249,7 @@ void Endpoint::setState(uint8_t state){
this->endpointState = state; this->endpointState = state;
} }
uint8_t Endpoint::getState(){ size_t Endpoint::getState(){
return this->endpointState; return this->endpointState;
} }
@ -291,17 +290,34 @@ void Endpoint::setRoles(Roles role){
startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW); startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW);
SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
//const wchar_t* pCrutch = crutch.c_str();
std::wstring command = L"SoundVolumeView.exe /SetDefault " + endpointId + L" "; std::wstring command = L"SoundVolumeView.exe /SetDefault " + endpointId + L" ";
std::wstring troublePair = L"0";
switch (role) { switch (role) {
case Roles::ROLE_ALL: case Roles::ROLE_ALL:
/* /*
* one sends both, at least for now; * console or multimedia, one sends both, at least for now;
* either cos of ms or dis guy, no choice * either cos of ms or dis guy;
* but to treat them as one for now * no choice but to treat them as one for now.
* command += L"all"; * command += L"all"; and nothing else would've been nice...
*/ */
command += L"0 1"; troublePair = command + troublePair;
if(CreateProcessW(
NULL,
(wchar_t*)troublePair.c_str(),
NULL,
NULL,
false,
CREATE_UNICODE_ENVIRONMENT,
NULL,
NULL,
(LPSTARTUPINFOW)&startupConfig,
&processInfo
) == true) {
WaitForSingleObject(processInfo.hProcess, INFINITE );
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
command += L"2";
break; break;
case Roles::ROLE_CONSOLE: case Roles::ROLE_CONSOLE:
command += std::to_wstring(0); command += std::to_wstring(0);
@ -375,16 +391,18 @@ void Overseer::initCOMLibrary() {
void Overseer::reloadEndpoints() { void Overseer::reloadEndpoints() {
IMMDeviceCollection *deviceCollection; IMMDeviceCollection *deviceCollection;
// | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED // | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED
if(FAILED(deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE , &deviceCollection) )) if(FAILED(deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection) ))
{ log_debugcpp("si"); }; { log_debugcpp("si"); };
/*
//Counting them * Counting them
*/
if(FAILED(deviceCollection->GetCount(&numPlaybackEndpoints))) { log_debugcpp("si");}; if(FAILED(deviceCollection->GetCount(&numPlaybackEndpoints))) { log_debugcpp("si");};
if(numPlaybackEndpoints == 0) { log_debugcpp("si"); }; if(numPlaybackEndpoints == 0) { log_debugcpp("si"); };
/*
//Retrieving actual endpoints and storing them on their own class * Retrieving actual endpoints and storing them on their own class
*/
IMMDevice *temp; IMMDevice *temp;
for (unsigned int i = 0; i < numPlaybackEndpoints; i++){ for (unsigned int i = 0; i < numPlaybackEndpoints; i++){
if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); }; if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); };
@ -396,8 +414,10 @@ void Overseer::reloadEndpoints() {
deviceCollection->Release(); deviceCollection->Release();
//Discerning default endpoints per role /*
//order: console, multimedia, communications * Discerning default endpoints per role
* order: console, multimedia, communications
*/
for(int i = 0; i < ERole_enum_count; i++){ for(int i = 0; i < ERole_enum_count; i++){
ERole val; ERole val;
switch(i) { switch(i) {

View file

@ -40,7 +40,7 @@ class Endpoint {
void setMute(NGuid guid, bool muted); void setMute(NGuid guid, bool muted);
bool getMute(); bool getMute();
void setState(uint8_t state); void setState(uint8_t state);
uint8_t getState(); size_t getState();
uint8_t getRoles(); uint8_t getRoles();
void setRoles(Roles role); void setRoles(Roles role);
void assignRoles(uint8_t role); void assignRoles(uint8_t role);
@ -52,13 +52,13 @@ class Endpoint {
~Endpoint(); ~Endpoint();
private: private:
uint32_t channelCount; uint32_t channelCount = 0;
IMMDevice* endpoint; IMMDevice* endpoint;
IAudioEndpointVolume *endpointVolume ; IAudioEndpointVolume *endpointVolume ;
IPropertyStore *properties; IPropertyStore *properties;
std::wstring friendlyName; std::wstring friendlyName;
std::wstring endpointId; std::wstring endpointId;
uint8_t endpointState; unsigned long endpointState;
uint8_t endpointRoles = 0; uint8_t endpointRoles = 0;
uint64_t idx; uint64_t idx;
// LPWSTR endpointID = NULL; // LPWSTR endpointID = NULL;

View file

@ -7,14 +7,16 @@ EndpointHandler::EndpointHandler(uint64_t idx) {
this->ep = osh->getPlaybackEndpoints().at(idx); this->ep = osh->getPlaybackEndpoints().at(idx);
epc = new EndpointVolumeCallback(ep); epc = new EndpointVolumeCallback(ep);
//epName = ep->getName(); //epName = ep->getName();
ep->setVolumeCallback(epc); if (this->ep->getState() == EndpointState::ENDPOINT_ACTIVE) {
callbackInfo.muted = this->getMute(); callbackInfo.muted = this->getMute();
callbackInfo.mainVolume = this->getVolume(AudioChannel::CHANNEL_MAIN); callbackInfo.mainVolume = this->getVolume(AudioChannel::CHANNEL_MAIN);
callbackInfo.channels = this->getChannelCount(); callbackInfo.channels = this->getChannelCount();
ep->setVolumeCallback(epc);
callbackInfo.channelVolumes.resize(this->callbackInfo.channels); callbackInfo.channelVolumes.resize(this->callbackInfo.channels);
for(uint32_t i = 0; i < this->getChannelCount(); i++){ for(uint32_t i = 0; i < this->getChannelCount(); i++){
callbackInfo.channelVolumes[i] = this->getVolume(i); callbackInfo.channelVolumes[i] = this->getVolume(i);
} }
}
} }
/* these two, currently unused. If I use them, I should feel bad. /* these two, currently unused. If I use them, I should feel bad.
@ -72,7 +74,7 @@ bool EndpointHandler::getMute(){
return ep->getMute(); return ep->getMute();
} }
uint8_t EndpointHandler::getState(){ size_t EndpointHandler::getState(){
return ep->getState(); return ep->getState();
} }

View file

@ -79,7 +79,7 @@ public:
float getVolume(int channel); float getVolume(int channel);
bool getMute(); bool getMute();
uint8_t getState(); size_t getState();
uint8_t getRoles(); uint8_t getRoles();
void setRoles(Roles newRole); void setRoles(Roles newRole);
void assignRoles(Roles newRole); void assignRoles(Roles newRole);

View file

@ -34,10 +34,19 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare
{Roles::ROLE_COMMUNICATIONS, new ExtendedCheckBox()} {Roles::ROLE_COMMUNICATIONS, new ExtendedCheckBox()}
}; };
/*
* Mute, main slider and label setup
*/
muteButton = new QCheckBox(); muteButton = new QCheckBox();
mainLabel = new QLabel(QString::fromStdWString(eph->getName())); mainLabel = new QLabel(QString::fromStdWString(eph->getName()));
mainSlider = new QSlider(Qt::Horizontal); mainSlider = new QSlider(Qt::Horizontal);
if (this->eph->getState() != EndpointState::ENDPOINT_ACTIVE) {
layout->addWidget(mainLabel, 0, 0);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 1, 0);
return;
}
//muteButton->setStyleSheet("background-color: #A3C1DA; color: red"); //muteButton->setStyleSheet("background-color: #A3C1DA; color: red");
mainSlider->setFocusPolicy(Qt::StrongFocus); mainSlider->setFocusPolicy(Qt::StrongFocus);
mainSlider->setTickPosition(QSlider::TicksBothSides); mainSlider->setTickPosition(QSlider::TicksBothSides);
@ -63,6 +72,9 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare
connect<void(QCheckBox::*)(int), void(EndpointWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&EndpointWidget::updateMute)); connect<void(QCheckBox::*)(int), void(EndpointWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&EndpointWidget::updateMute));
/*
* Channel sliders setup
*/
for(uint32_t i = 0; i < eph->getChannelCount(); i++){ for(uint32_t i = 0; i < eph->getChannelCount(); i++){
QSlider* tmp = new QSlider(Qt::Horizontal); QSlider* tmp = new QSlider(Qt::Horizontal);
QLabel* tmpLb = new QLabel(""); QLabel* tmpLb = new QLabel("");
@ -85,6 +97,10 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare
}); });
} }
/*
* Role ExtendedCheckBoxes setup
*/
uint8_t assignedRoles = eph->getRoles(); uint8_t assignedRoles = eph->getRoles();
defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setCheckState(assignedRoles == Roles::ROLE_ALL ? Qt::Checked : Qt::Unchecked); defaultRolesCheckBoxes.at(Roles::ROLE_ALL)->setCheckState(assignedRoles == Roles::ROLE_ALL ? Qt::Checked : Qt::Unchecked);
//todo duditas de & //todo duditas de &
@ -105,20 +121,16 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare
connect(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), &QCheckBox::stateChanged,[this] { connect(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_ALL); this->eph->setRoles(Roles::ROLE_ALL);
//todo: bloquiar pto
}); });
connect(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), &QCheckBox::stateChanged,[this] { connect(defaultRolesCheckBoxes.at(Roles::ROLE_CONSOLE), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_CONSOLE); this->eph->setRoles(Roles::ROLE_CONSOLE);
//todo: bloquiar pto
}); });
connect(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), &QCheckBox::stateChanged,[this] { connect(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_MULTIMEDIA); this->eph->setRoles(Roles::ROLE_MULTIMEDIA);
//todo: bloquiar pto
}); });
connect(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), &QCheckBox::stateChanged,[this] { connect(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), &QCheckBox::stateChanged,[this] {
this->eph->setRoles(Roles::ROLE_COMMUNICATIONS); this->eph->setRoles(Roles::ROLE_COMMUNICATIONS);
//todo: bloquiar pto
}); });
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), 5, 0); layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_ALL), 5, 0);
@ -126,8 +138,11 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), 5, 2); layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_MULTIMEDIA), 5, 2);
layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), 5, 3); layout->addWidget(defaultRolesCheckBoxes.at(Roles::ROLE_COMMUNICATIONS), 5, 3);
/* ----------------------------------------------------------- */
//Polling time /*
* EndpointVolume Polling time
*/
timer = new QTimer(); timer = new QTimer();
connect(timer, &QTimer::timeout, [this, eph](){ connect(timer, &QTimer::timeout, [this, eph](){
//if (memcmp(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid)) == 0) return; CHECK IF THIS PROGRAM GENERATED THE FUNSIES IS NO LONGER IN USE FOR NOW. //if (memcmp(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid)) == 0) return; CHECK IF THIS PROGRAM GENERATED THE FUNSIES IS NO LONGER IN USE FOR NOW.
@ -151,6 +166,7 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare
muteButton->blockSignals(false); muteButton->blockSignals(false);
}); });
timer->start(10); timer->start(10);
//todo parent? //todo parent?
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 1, 0); layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 1, 0);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 4, 0); layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum), 4, 0);
@ -159,20 +175,6 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare
log_debugcpp("ENDPOINT_WIDGETED"); log_debugcpp("ENDPOINT_WIDGETED");
} }
/*
* void EndpointWidget::updateMute(bool muted){
* //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);
* }
*/
void EndpointWidget::updateMute(int checked){ void EndpointWidget::updateMute(int checked){
bool muted = (checked == 2 ? true : false); bool muted = (checked == 2 ? true : false);
this->eph->setMute(osh->getGuid(), muted); this->eph->setMute(osh->getGuid(), muted);
@ -180,7 +182,6 @@ void EndpointWidget::updateMute(int checked){
} }
void EndpointWidget::updateMainVolume(int newValue){ void EndpointWidget::updateMainVolume(int newValue){
//QObject* obj = sender();
this->eph->setVolume(osh->getGuid(), AudioChannel::CHANNEL_MAIN, newValue); this->eph->setVolume(osh->getGuid(), AudioChannel::CHANNEL_MAIN, newValue);
} }
@ -246,7 +247,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
reloadEndpointWidgets(); reloadEndpointWidgets();
//Tray Icon /*
* Tray Icon code
*/
trayIconMenu->addSeparator(); trayIconMenu->addSeparator();
trayIconMenu->addAction(trayIconMenuQuit); trayIconMenu->addAction(trayIconMenuQuit);
connect(trayIconMenuQuit, &QAction::triggered, qApp, &QCoreApplication::quit); connect(trayIconMenuQuit, &QAction::triggered, qApp, &QCoreApplication::quit);
@ -257,14 +260,16 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
trayIcon->show(); trayIcon->show();
trayIcon->setToolTip(STRING_TITLE); trayIcon->setToolTip(STRING_TITLE);
trayIcon->setContextMenu(trayIconMenu); trayIcon->setContextMenu(trayIconMenu);
//todo: ayo...
QString as = trayIcon->toolTip();
connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated); connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
/*
* Set of function callback definitinos for EndpointSituationCallback
*/
osh->setChangeFrontDefaultsFunction([this](Roles role, std::wstring endpointId) { osh->setChangeFrontDefaultsFunction([this](Roles role, std::wstring endpointId) {
for (auto epw : this->ews) { for (auto epw : this->ews) {
/*
* Is this the new default endpoint?
*/
if (epw->getEndpointHandler()->getId() == endpointId) { if (epw->getEndpointHandler()->getId() == endpointId) {
//not necessary to keep endpointState flags up to date right now, but updating it will allow for later config files / profiles //not necessary to keep endpointState flags up to date right now, but updating it will allow for later config files / profiles
epw->defaultRolesCheckBoxes.at(role)->blockSignals(true); epw->defaultRolesCheckBoxes.at(role)->blockSignals(true);
@ -272,38 +277,31 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
epw->defaultRolesCheckBoxes.at(role)->blockSignals(false); epw->defaultRolesCheckBoxes.at(role)->blockSignals(false);
QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(role), changeDefaultCheckboxEnablement); QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(role), changeDefaultCheckboxEnablement);
//epw->defaultRolesCheckBoxes.at(role)->postEnableChange(); //epw->defaultRolesCheckBoxes.at(role)->postEnableChange();
/*
* And were you THE default?
*/
if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) { if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) {
QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(Roles::ROLE_ALL), changeDefaultCheckboxEnablement); QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(Roles::ROLE_ALL), changeDefaultCheckboxEnablement);
} }
/* /*
* switch (role) { * Are you the dethroned king?
* case Roles::ROLE_CONSOLE: */
* epw->getEndpointHandler()->assignRoles(role); } else if (epw->getEndpointHandler()->getRoles() & role) {
* break; /*
* case Roles::ROLE_MULTIMEDIA: * And were you THE default up until now?
* break;
* case Roles::ROLE_COMMUNICATIONS:
* break;
*
* }
*/ */
} else {
if (epw->getEndpointHandler()->getRoles() & role) {
if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) { if (epw->getEndpointHandler()->getRoles() == Roles::ROLE_ALL) {
QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(Roles::ROLE_ALL), changeDefaultCheckboxEnablement); QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(Roles::ROLE_ALL), changeDefaultCheckboxEnablement);
} }
epw->defaultRolesCheckBoxes.at(role)->blockSignals(true); epw->defaultRolesCheckBoxes.at(role)->blockSignals(true);
//Same as before. ini-san will come...
epw->getEndpointHandler()->removeRoles(role); epw->getEndpointHandler()->removeRoles(role);
//epw->defaultRolesCheckBoxes.at(role)->setDisabled(false);
epw->defaultRolesCheckBoxes.at(role)->blockSignals(false); epw->defaultRolesCheckBoxes.at(role)->blockSignals(false);
QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(role), changeDefaultCheckboxEnablement); QCoreApplication::instance()->postEvent(epw->defaultRolesCheckBoxes.at(role), changeDefaultCheckboxEnablement);
} }
} }
}
}); });
} }
@ -342,16 +340,5 @@ void MainWindow::reloadEndpointWidgets() {
} }
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 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.at(device)->updateVolume(channel, value);
* });
* osh->setFrontMuteCallback([this](uint64_t device, bool muted) {
* if (device < ews.size())
* ews.at(device)->updateMute(muted);
* });
*/
} }

View file

@ -60,13 +60,11 @@
class ExtendedCheckBox : public QCheckBox { class ExtendedCheckBox : public QCheckBox {
Q_OBJECT Q_OBJECT
public: public:
bool event(QEvent* ev) override; bool event(QEvent* ev) override;
}; };
class EndpointWidget : public QWidget { class EndpointWidget : public QWidget {
Q_OBJECT Q_OBJECT