#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) { SessionState newState;// = sh->getState(); switch (NewState) { case AudioSessionStateActive: newState = SessionState::ACTIVE; break; case AudioSessionStateInactive: newState = SessionState::INACTIVE; break; case AudioSessionStateExpired: newState = SessionState::EXPIRED; break; } sh->reviseSessionShowing(newState); return S_OK; } HRESULT SessionStateCallback::OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason) { sh->setState(SessionState::DISCONNECTED); sh->reviseSessionShowing(SessionState::DISCONNECTED); return S_OK; } Session::Session(Endpoint* ep, IAudioSessionControl2* sessionControl, size_t idx) { this->ep = ep; this->sessionControl = sessionControl; this->idx = idx; AudioSessionState msState; sessionControl->GetState(&msState); switch (msState) { case AudioSessionState::AudioSessionStateActive: this->sessionState = SessionState::ACTIVE; break; case AudioSessionState::AudioSessionStateInactive: this->sessionState = SessionState::INACTIVE; break; case AudioSessionState::AudioSessionStateExpired: this->sessionState = SessionState::EXPIRED; break; } sessionControl->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&sessionVolume); DWORD pid; sessionControl->GetProcessId(&pid); if (sessionControl->IsSystemSoundsSession() == S_OK) this->sessionName = std::wstring(LSTRING_SYSTEM_SOUNDS); else { LPWSTR sessionDisplayName; this->sessionControl->GetDisplayName(&sessionDisplayName); if (!wcscmp(sessionDisplayName, L"")) this->sessionName = this->fetchProcessName(pid); else this->sessionName = std::wstring(sessionDisplayName); CoTaskMemFree(sessionDisplayName); } } float Session::getVolume(int channel){ float volume; if (channel == AudioChannel::CHANNEL_MAIN) { if(FAILED(sessionVolume->GetMasterVolume(&volume))) { /* log_debugcpp("si") */;} } else { return 0.0; //if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */} } return volume; } /* * uint32_t Endpoint::getChannelCount(){ * return (uint32_t)channelCount; * } */ std::wstring Session::getName() { return sessionName; } bool Session::getMute() { BOOL mut; if(FAILED(sessionVolume->GetMute(&mut))) { /* TIP: Below */ } bool mute = (bool)mut; return mute; } void Session::setVolume(NGuid guid, int channel, float volume) { //TIP: There used to be log messages here. Now, it's a ghost town. GUID tempMsGuid = NGuidToGUID(guid); if (channel == AudioChannel::CHANNEL_MAIN) { if(FAILED(sessionVolume->SetMasterVolume(volume, &tempMsGuid))) {}; } else { //if(FAILED(sessionVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) {}; } } void Session::setIndex(size_t idx) { this->idx = idx; } void Session::setMute(NGuid guid, bool muted) { GUID tempMsGuid = NGuidToGUID(guid); if(FAILED(sessionVolume->SetMute(muted, &tempMsGuid))) { log_wdebugcpp(std::wstring(L"SessionVolume null?")); }; } std::wstring Session::fetchProcessName(DWORD pid) { /* * https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot * https://stackoverflow.com/questions/11843368/how-to-get-process-description */ /* Executable path retrieval */ std::wstring exePath = L""; HANDLE processList = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); if (processList == INVALID_HANDLE_VALUE) { log_wdebugcpp(L"aye no procname."); return exePath; } MODULEENTRY32W me32w; me32w.dwSize = sizeof(MODULEENTRY32W); if(Module32FirstW(processList, &me32w)) { do { if (me32w.th32ProcessID == pid) { exePath = std::wstring(me32w.szExePath); break; /* * However, if the calling process is a 32-bit process, you must call the * QueryFullProcessImageName function to retrieve the full path of the * executable file for a 64-bit process. */ } } while(Module32NextW(processList, &me32w)); } CloseHandle(processList); /* File description retrieval */ struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage; } *translationArray; DWORD filler; DWORD fileVersionInfoSize = GetFileVersionInfoSizeW(exePath.c_str(), &filler); if (!fileVersionInfoSize) return exePath; void* fileVersionInfo = malloc(fileVersionInfoSize); if(!GetFileVersionInfoW(exePath.c_str(),0,fileVersionInfoSize, fileVersionInfo)) return exePath; UINT translationArrayLen = 0; if (!VerQueryValueW(fileVersionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayLen)) return exePath; bool match = false; for (UINT i = 0; i < (translationArrayLen / sizeof(LANGANDCODEPAGE)); i++) { wchar_t fileDescriptionKey[256]; LANGID defaultUILanguage = GetUserDefaultUILanguage(); if (defaultUILanguage != translationArray[i].wLanguage) continue; match = true; wchar_t* fileDescription = NULL; UINT fileDescriptionSize = 0; swprintf(fileDescriptionKey, L"\\StringFileInfo\\%04x%04x\\FileDescription", translationArray[i].wLanguage, translationArray[i].wCodePage); if (VerQueryValueW(fileVersionInfo, fileDescriptionKey, (LPVOID*)&fileDescription, &fileDescriptionSize)) { exePath = std::wstring(fileDescription); } } if (!match && 1 <= (translationArrayLen / sizeof(LANGANDCODEPAGE))) { wchar_t fileDescriptionKey[256]; wchar_t* fileDescription = NULL; UINT fileDescriptionSize = 0; swprintf(fileDescriptionKey, L"\\StringFileInfo\\%04x%04x\\FileDescription", translationArray[0].wLanguage, translationArray[0].wCodePage); if (VerQueryValueW(fileVersionInfo, fileDescriptionKey, (LPVOID*)&fileDescription, &fileDescriptionSize)) { exePath = std::wstring(fileDescription); } } free(fileVersionInfo); return exePath; } //todo: conflicting names. change callback name void Session::setState(SessionState state) { sessionState = state; } SessionState Session::getState() { return sessionState; } void Session::setStateCallback(SessionStateCallback *ssc){ sessionControl->RegisterAudioSessionNotification((IAudioSessionEvents*) ssc); } void Session::removeStateCallback(SessionStateCallback *ssc){ sessionControl->UnregisterAudioSessionNotification((IAudioSessionEvents*) ssc); } Session::~Session() { sessionControl->Release(); sessionVolume->Release(); }