mixer/src/back/backsessionclasses.cpp
2024-02-07 16:56:23 +01:00

282 lines
8.1 KiB
C++

#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();
}