session volume/mute polling

This commit is contained in:
Hane 2024-02-03 15:33:59 +01:00
commit 064c16d9e7
10 changed files with 263 additions and 4 deletions

View file

@ -1,6 +1,45 @@
#include <backlasses.h> #include <backlasses.h>
#include <backfuncs.h> #include <backfuncs.h>
EndpointNewSessionCallback::EndpointNewSessionCallback(EndpointHandler* eph){
this->eph = eph;
}
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) {
return S_OK;
}
EndpointVolumeCallback::EndpointVolumeCallback(Endpoint* ep){ EndpointVolumeCallback::EndpointVolumeCallback(Endpoint* ep){
this->ep = ep; this->ep = ep;
} }

View file

@ -32,7 +32,6 @@ class Endpoint {
Flows getFlow(); Flows getFlow();
std::wstring getId(); std::wstring getId();
std::wstring getName(); std::wstring getName();
void setVolumeCallback(EndpointVolumeCallback *epc); void setVolumeCallback(EndpointVolumeCallback *epc);
void removeVolumeCallback(EndpointVolumeCallback *epc); void removeVolumeCallback(EndpointVolumeCallback *epc);
@ -134,3 +133,16 @@ class Overseer {
//std::vector<Endpoint*> *captureDevices; //std::vector<Endpoint*> *captureDevices;
}; };
class EndpointNewSessionCallback : public IAudioSessionNotification {
public:
//EndpointSituationCallback(IMMDeviceEnumerator *deviceEnumerator, std::vector<Endpoint*> playbackDevices);
EndpointNewSessionCallback(EndpointHandler *eph);
ULONG AddRef();
ULONG Release();
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
HRESULT OnSessionCreated(IAudioSessionControl *NewSession);
private:
ULONG ref = 1;
EndpointHandler *eph;
};

View file

@ -1,6 +1,126 @@
#include "backsessionclasses.h" #include "backsessionclasses.h"
#include "backfuncs.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) {
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) {
/*
* char *pszState = "?????";
*
* switch (NewState)
* {
* case AudioSessionStateActive:
* pszState = "active";
* break;
* case AudioSessionStateInactive:
* pszState = "inactive";
* break;
* }
* printf("New session state = %s\n", pszState);
*/
return S_OK;
}
HRESULT SessionStateCallback::OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason) {
/*
* char *pszReason = "?????";
*
* switch (DisconnectReason)
* {
* case DisconnectReasonDeviceRemoval:
* pszReason = "device removed";
* break;
* case DisconnectReasonServerShutdown:
* pszReason = "server shut down";
* break;
* case DisconnectReasonFormatChanged:
* pszReason = "format changed";
* break;
* case DisconnectReasonSessionLogoff:
* pszReason = "user logged off";
* break;
* case DisconnectReasonSessionDisconnected:
* pszReason = "session disconnected";
* break;
* case DisconnectReasonExclusiveModeOverride:
* pszReason = "exclusive-mode override";
* break;
* }
* printf("Audio session disconnected (reason: %s)\n",
* pszReason);
*/
return S_OK;
}
Session::Session(Endpoint* ep, IAudioSessionControl2* sessionControl, size_t idx) { Session::Session(Endpoint* ep, IAudioSessionControl2* sessionControl, size_t idx) {
this->ep = ep; this->ep = ep;
this->sessionControl = sessionControl; this->sessionControl = sessionControl;
@ -147,3 +267,11 @@ wchar_t* fileDescription = NULL;
free(fileVersionInfo); free(fileVersionInfo);
return exePath; return exePath;
} }
void Session::setStateCallback(SessionStateCallback *ssc){
sessionControl->RegisterAudioSessionNotification((IAudioSessionEvents*) ssc);
}
void Session::removeStateCallback(SessionStateCallback *ssc){
sessionControl->UnregisterAudioSessionNotification((IAudioSessionEvents*) ssc);
}

View file

@ -6,6 +6,26 @@
class Endpoint; 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 { class Session {
public: public:
@ -15,6 +35,9 @@ class Session {
void setMute(NGuid guid, bool muted); void setMute(NGuid guid, bool muted);
bool getMute(); bool getMute();
std::wstring getName(); std::wstring getName();
void setStateCallback(SessionStateCallback *ssc);
void removeStateCallback(SessionStateCallback *ssc);
//uint32_t getChannelCount(); //uint32_t getChannelCount();
private: private:
@ -25,3 +48,4 @@ class Session {
ISimpleAudioVolume* sessionVolume = nullptr; ISimpleAudioVolume* sessionVolume = nullptr;
size_t idx; size_t idx;
}; };

View file

@ -14,7 +14,6 @@ EndpointHandler::EndpointHandler(uint64_t idx, Flows flow) {
//epName = ep->getName(); //epName = ep->getName();
this->setBackEndpointVolumeCallbackInfoContent(this->getState()); this->setBackEndpointVolumeCallbackInfoContent(this->getState());
osh->pushBackEndpointHandler(this, flow); osh->pushBackEndpointHandler(this, flow);
if (this->flow == Flows::FLOW_PLAYBACK && this->getState() == EndpointState::ENDPOINT_ACTIVE) { if (this->flow == Flows::FLOW_PLAYBACK && this->getState() == EndpointState::ENDPOINT_ACTIVE) {
for (int i = 0; i < this->getSessionCount(); i++) { for (int i = 0; i < this->getSessionCount(); i++) {

View file

@ -103,6 +103,12 @@ public:
void reloadEndpointHandlers(); void reloadEndpointHandlers();
EndpointHandler* addEndpoint(std::wstring endpointId, Flows *flow); EndpointHandler* addEndpoint(std::wstring endpointId, Flows *flow);
NGuid getGuid(); NGuid getGuid();
/* Session's */
/*
* void setSessionVolumeCallback(std::function<void(float)> changeSessionVolume);
* void setSessionVolume(float newValue, );
*/
private: private:
Overseer *os; Overseer *os;
@ -111,6 +117,9 @@ private:
std::function<void(Roles, std::wstring /* endpointid */)> changeFrontDefaults; std::function<void(Roles, std::wstring /* endpointid */)> changeFrontDefaults;
std::function<void(uint64_t /* epw id */)> removeEndpointWidget; std::function<void(uint64_t /* epw id */)> removeEndpointWidget;
std::function<void(EndpointHandler*)> addEndpointWidget; std::function<void(EndpointHandler*)> addEndpointWidget;
/* Session's */
std::function<void(float)> changeSessionVolume;
//std::function<void(uint64_t /* device */, uint32_t /* channel */, float /* value */)> updateFrontVolumeCallback; //std::function<void(uint64_t /* device */, uint32_t /* channel */, float /* value */)> updateFrontVolumeCallback;
//std::function<void(uint64_t /* device */, bool /* mute */)> updateFrontMuteCallback; //std::function<void(uint64_t /* device */, bool /* mute */)> updateFrontMuteCallback;

View file

@ -5,6 +5,13 @@ SessionHandler::SessionHandler(EndpointHandler* eph, Session* session, size_t id
this->eph = eph; this->eph = eph;
this->idx = idx; this->idx = idx;
this->session = session; 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){ void SessionHandler::setVolume(NGuid guid, int channel, int value){
@ -28,3 +35,7 @@ std::wstring SessionHandler::getName(){
bool SessionHandler::getMute(){ bool SessionHandler::getMute(){
return session->getMute(); return session->getMute();
} }
SessionVolumeInfo* SessionHandler::getVolumeInfo() {
return &svi;
}

View file

@ -5,6 +5,17 @@
class EndpointHandler; class EndpointHandler;
class Session; class Session;
class SessionStateCallback;
struct SessionVolumeInfo {
//SessionVolumeInfo(bool muted, float mainVolume);
bool muted;
float mainVolume;
NGuid caller;
//size_t channels;
//std::vector<float> channelVolumes;
};
class SessionHandler { class SessionHandler {
public: public:
@ -14,10 +25,13 @@ class SessionHandler {
void setMute(NGuid guid, bool muted); void setMute(NGuid guid, bool muted);
bool getMute(); bool getMute();
std::wstring getName(); std::wstring getName();
SessionVolumeInfo* getVolumeInfo();
private: private:
SessionVolumeInfo svi;
EndpointHandler* eph; EndpointHandler* eph;
Session* session; Session* session;
SessionStateCallback* ssc;
size_t idx; size_t idx;
}; };

View file

@ -59,7 +59,30 @@ SessionWidget::SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent)
//TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option? //TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option?
connect<void(QSlider::*)(int), void(SessionWidget::*)(int)>(mainSlider, &QSlider::valueChanged, this,&SessionWidget::updateMainVolume); connect<void(QSlider::*)(int), void(SessionWidget::*)(int)>(mainSlider, &QSlider::valueChanged, this,&SessionWidget::updateMainVolume);
connect<void(QCheckBox::*)(int), void(SessionWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&SessionWidget::updateMute)); connect<void(QCheckBox::*)(int), void(SessionWidget::*)(int)>(muteButton, &QCheckBox::stateChanged, this, (&SessionWidget::updateMute));
/*
* Session Volume Polling
*/
volumePoller = new QTimer();
connect(volumePoller, &QTimer::timeout, [this, sh](){
//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.
//todo: global + constexpr + ratio
const float roundingFactor = 0.005;
mainSlider->blockSignals(true);
muteButton->blockSignals(true);
mainSlider->setValue((int)((sh->getVolumeInfo()->mainVolume + roundingFactor) * 100));
muteButton->setCheckState((sh->getVolumeInfo()->muted == false ? Qt::Unchecked : Qt::Checked));
muteButton->setText(sh->getVolumeInfo()->muted ? STRING_UNMUTE : STRING_MUTE);
//memcpy(osh->callbackInfo[idx]->caller, osh->getGuid(), sizeof(NGuid));
//TODO: el default = objcopy frees?
//Todo: like fr pregunta
sh->getVolumeInfo()->caller = osh->getGuid();
mainSlider->blockSignals(false);
muteButton->blockSignals(false);
});
volumePoller->start(10);
} }
void SessionWidget::updateMute(int checked){ void SessionWidget::updateMute(int checked){

View file

@ -102,6 +102,7 @@ private:
QGridLayout *layout = nullptr; QGridLayout *layout = nullptr;
QCheckBox *muteButton = nullptr; QCheckBox *muteButton = nullptr;
SessionHandler* sh; SessionHandler* sh;
QTimer* volumePoller = nullptr;
}; };
class EndpointWidget : public QWidget { class EndpointWidget : public QWidget {
@ -118,7 +119,6 @@ public:
void setVolume(int channel, float volume); void setVolume(int channel, float volume);
~EndpointWidget(); ~EndpointWidget();
//void updateMainVolume(float newValue); //void updateMainVolume(float newValue);
//void updateVolume(uint32_t channel, float newValue); //void updateVolume(uint32_t channel, float newValue);
//void updateMute(bool muted); //void updateMute(bool muted);