From 064c16d9e7a29a1f72cc4cfe1b0a2b89b28abc9f Mon Sep 17 00:00:00 2001 From: Hane Date: Sat, 3 Feb 2024 15:33:59 +0100 Subject: [PATCH] session volume/mute polling --- src/back/backlasses.cpp | 39 ++++++++++ src/back/backlasses.h | 14 +++- src/back/backsessionclasses.cpp | 128 ++++++++++++++++++++++++++++++++ src/back/backsessionclasses.h | 24 ++++++ src/cont/contclasses.cpp | 1 - src/cont/contclasses.h | 9 +++ src/cont/contsessionclasses.cpp | 11 +++ src/cont/contsessionclasses.h | 14 ++++ src/qt/qtclasses.cpp | 25 ++++++- src/qt/qtclasses.h | 2 +- 10 files changed, 263 insertions(+), 4 deletions(-) diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index dea09b6..04aa309 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -1,6 +1,45 @@ #include #include +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){ this->ep = ep; } diff --git a/src/back/backlasses.h b/src/back/backlasses.h index 453e7a5..bda4a23 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -32,7 +32,6 @@ class Endpoint { Flows getFlow(); std::wstring getId(); std::wstring getName(); - void setVolumeCallback(EndpointVolumeCallback *epc); void removeVolumeCallback(EndpointVolumeCallback *epc); @@ -134,3 +133,16 @@ class Overseer { //std::vector *captureDevices; }; +class EndpointNewSessionCallback : public IAudioSessionNotification { + public: + //EndpointSituationCallback(IMMDeviceEnumerator *deviceEnumerator, std::vector playbackDevices); + EndpointNewSessionCallback(EndpointHandler *eph); + ULONG AddRef(); + ULONG Release(); + HRESULT QueryInterface(REFIID riid, VOID **ppvInterface); + HRESULT OnSessionCreated(IAudioSessionControl *NewSession); + + private: + ULONG ref = 1; + EndpointHandler *eph; +}; diff --git a/src/back/backsessionclasses.cpp b/src/back/backsessionclasses.cpp index 7349c19..a0a4b5e 100644 --- a/src/back/backsessionclasses.cpp +++ b/src/back/backsessionclasses.cpp @@ -1,6 +1,126 @@ #include "backsessionclasses.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) { this->ep = ep; this->sessionControl = sessionControl; @@ -147,3 +267,11 @@ wchar_t* fileDescription = NULL; free(fileVersionInfo); return exePath; } + +void Session::setStateCallback(SessionStateCallback *ssc){ + sessionControl->RegisterAudioSessionNotification((IAudioSessionEvents*) ssc); +} + +void Session::removeStateCallback(SessionStateCallback *ssc){ + sessionControl->UnregisterAudioSessionNotification((IAudioSessionEvents*) ssc); +} diff --git a/src/back/backsessionclasses.h b/src/back/backsessionclasses.h index 369dcab..3354939 100644 --- a/src/back/backsessionclasses.h +++ b/src/back/backsessionclasses.h @@ -6,6 +6,26 @@ 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 { public: @@ -15,6 +35,9 @@ class Session { void setMute(NGuid guid, bool muted); bool getMute(); std::wstring getName(); + + void setStateCallback(SessionStateCallback *ssc); + void removeStateCallback(SessionStateCallback *ssc); //uint32_t getChannelCount(); private: @@ -25,3 +48,4 @@ class Session { ISimpleAudioVolume* sessionVolume = nullptr; size_t idx; }; + diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp index 653517b..a858b0f 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -14,7 +14,6 @@ EndpointHandler::EndpointHandler(uint64_t idx, Flows flow) { //epName = ep->getName(); this->setBackEndpointVolumeCallbackInfoContent(this->getState()); osh->pushBackEndpointHandler(this, flow); - if (this->flow == Flows::FLOW_PLAYBACK && this->getState() == EndpointState::ENDPOINT_ACTIVE) { for (int i = 0; i < this->getSessionCount(); i++) { diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index a89a42a..4bdd519 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -103,6 +103,12 @@ public: void reloadEndpointHandlers(); EndpointHandler* addEndpoint(std::wstring endpointId, Flows *flow); NGuid getGuid(); + + /* Session's */ + /* + * void setSessionVolumeCallback(std::function changeSessionVolume); + * void setSessionVolume(float newValue, ); + */ private: Overseer *os; @@ -111,6 +117,9 @@ private: std::function changeFrontDefaults; std::function removeEndpointWidget; std::function addEndpointWidget; + + /* Session's */ + std::function changeSessionVolume; //std::function updateFrontVolumeCallback; //std::function updateFrontMuteCallback; diff --git a/src/cont/contsessionclasses.cpp b/src/cont/contsessionclasses.cpp index 92d6d6a..e3f69d0 100644 --- a/src/cont/contsessionclasses.cpp +++ b/src/cont/contsessionclasses.cpp @@ -5,6 +5,13 @@ SessionHandler::SessionHandler(EndpointHandler* eph, Session* session, size_t id this->eph = eph; this->idx = idx; 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){ @@ -28,3 +35,7 @@ std::wstring SessionHandler::getName(){ bool SessionHandler::getMute(){ return session->getMute(); } + +SessionVolumeInfo* SessionHandler::getVolumeInfo() { + return &svi; +} diff --git a/src/cont/contsessionclasses.h b/src/cont/contsessionclasses.h index aea425e..e637e47 100644 --- a/src/cont/contsessionclasses.h +++ b/src/cont/contsessionclasses.h @@ -5,6 +5,17 @@ class EndpointHandler; class Session; +class SessionStateCallback; + +struct SessionVolumeInfo { + //SessionVolumeInfo(bool muted, float mainVolume); + bool muted; + float mainVolume; + NGuid caller; + + //size_t channels; + //std::vector channelVolumes; +}; class SessionHandler { public: @@ -14,10 +25,13 @@ class SessionHandler { void setMute(NGuid guid, bool muted); bool getMute(); std::wstring getName(); + SessionVolumeInfo* getVolumeInfo(); private: + SessionVolumeInfo svi; EndpointHandler* eph; Session* session; + SessionStateCallback* ssc; size_t idx; }; diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index d2fdf3b..f420688 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -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? connect(mainSlider, &QSlider::valueChanged, this,&SessionWidget::updateMainVolume); connect(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){ diff --git a/src/qt/qtclasses.h b/src/qt/qtclasses.h index 3afb63f..6cf85b0 100644 --- a/src/qt/qtclasses.h +++ b/src/qt/qtclasses.h @@ -102,6 +102,7 @@ private: QGridLayout *layout = nullptr; QCheckBox *muteButton = nullptr; SessionHandler* sh; + QTimer* volumePoller = nullptr; }; class EndpointWidget : public QWidget { @@ -118,7 +119,6 @@ public: void setVolume(int channel, float volume); ~EndpointWidget(); - //void updateMainVolume(float newValue); //void updateVolume(uint32_t channel, float newValue); //void updateMute(bool muted);