#include #include EndpointVolumeCallback::EndpointVolumeCallback(Endpoint* ep){ this->ep = ep; } ULONG EndpointVolumeCallback::AddRef(){ return InterlockedIncrement(&ref); } ULONG EndpointVolumeCallback::Release(){ ULONG tempRef = InterlockedDecrement(&ref); if (tempRef == 0) { delete this; } return tempRef; } HRESULT EndpointVolumeCallback::QueryInterface(REFIID riid, VOID **ppvInterface) { if (IID_IUnknown == riid) { AddRef(); *ppvInterface = (IUnknown*)this; } else if (__uuidof(IAudioEndpointVolumeCallback) == riid) { AddRef(); *ppvInterface = (IAudioEndpointVolumeCallback*)this; } else { *ppvInterface = NULL; return E_NOINTERFACE; } return S_OK; } HRESULT EndpointVolumeCallback::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) { if (pNotify == NULL) return E_INVALIDARG; //delete osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller; //osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.freeData4(); //Could've made a function or = override to hide this within Nguid, but back in cont = bad. osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data1 \ = pNotify->guidEventContext.Data1; osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data2 \ = pNotify->guidEventContext.Data2; osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data3 \ = pNotify->guidEventContext.Data3; for(int i = 0; i < 8 /* Data4 size */; i++){ osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data4[i] = pNotify->guidEventContext.Data4[i]; } //memcpy(&osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller, &pNotify->guidEventContext,sizeof(NGuid) ); osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->muted = pNotify->bMuted; osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->mainVolume = pNotify->fMasterVolume; osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->channels = pNotify->nChannels; UINT i = 0; do { osh->getEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->channelVolumes[i] = pNotify->afChannelVolumes[i]; } while(i++ < pNotify->nChannels); return S_OK; } /* * EndpointSituationCallback::EndpointSituationCallback(IMMDeviceEnumerator *deviceEnumerator, std::vector playbackDevices){ * this->deviceEnumerator = deviceEnumerator; * this->playbackDevices = playbackDevices; * } */ void EndpointSituationCallback::fill(IMMDeviceEnumerator *deviceEnumerator, std::vector playbackDevices){ this->deviceEnumerator = deviceEnumerator; this->playbackDevices = playbackDevices; } ULONG EndpointSituationCallback::AddRef(){ return InterlockedIncrement(&ref); } ULONG EndpointSituationCallback::Release(){ ULONG tempRef = InterlockedDecrement(&ref); if (tempRef == 0) { delete this; } return tempRef; } HRESULT EndpointSituationCallback::QueryInterface(REFIID riid, VOID **ppvInterface) { if (IID_IUnknown == riid) { AddRef(); *ppvInterface = (IUnknown*)this; } else if (__uuidof(IMMNotificationClient) == riid) { AddRef(); *ppvInterface = (IMMNotificationClient*)this; } else { *ppvInterface = NULL; return E_NOINTERFACE; } return S_OK; } HRESULT EndpointSituationCallback::OnDefaultDeviceChanged(EDataFlow flow, ERole role,LPCWSTR pwstrDeviceId) { if (flow == EDataFlow::eCapture) return E_INVALIDARG; Roles nRole; switch (role) { case ERole::eConsole: nRole = Roles::ROLE_CONSOLE; break; case ERole::eMultimedia: nRole = Roles::ROLE_MULTIMEDIA; break; case ERole::eCommunications: nRole = Roles::ROLE_COMMUNICATIONS; break; } std::wstring wstringEndpointId = pwstrDeviceId; osh->changeFrontDefaultsCallback(nRole, wstringEndpointId); return S_OK; } HRESULT EndpointSituationCallback::OnDeviceAdded(LPCWSTR pwstrDeviceId) { return S_OK; }; HRESULT EndpointSituationCallback::OnDeviceRemoved(LPCWSTR pwstrDeviceId) { return S_OK; } HRESULT EndpointSituationCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { /* * char *pszState = "?????"; * * switch (dwNewState) * { * case DEVICE_STATE_ACTIVE: * pszState = "ACTIVE"; * break; * case DEVICE_STATE_DISABLED: * pszState = "DISABLED"; * break; * case DEVICE_STATE_NOTPRESENT: * pszState = "NOTPRESENT"; * break; * case DEVICE_STATE_UNPLUGGED: * pszState = "UNPLUGGED"; * break; * } * * printf(" -->New device state is DEVICE_STATE_%s (0x%8.8x)\n", * pszState, dwNewState); */ return S_OK; } HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { /* * printf(" -->Changed device property " * "{%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}#%d\n", * key.fmtid.Data1, key.fmtid.Data2, key.fmtid.Data3, * key.fmtid.Data4[0], key.fmtid.Data4[1], * key.fmtid.Data4[2], key.fmtid.Data4[3], * key.fmtid.Data4[4], key.fmtid.Data4[5], * key.fmtid.Data4[6], key.fmtid.Data4[7], * key.pid); */ return S_OK; } Endpoint::Endpoint(IMMDevice* ep, uint64_t idx){ this->endpoint = ep; this->idx = idx; //if(FAILED()) {}; DWORD tempState = 0; if(FAILED(endpoint->GetState(&tempState))) {exit(-1);}; this->endpointState = tempState; if (tempState == DEVICE_STATE_ACTIVE) { 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"); */ } else channelCount = 0; //todo:: atexit into exit Gather ID LPWSTR tempString = nullptr; if (FAILED(endpoint->GetId(&tempString))) {exit(-1);}; endpointId = std::wstring(tempString); log_wdebugcpp(endpointId); CoTaskMemFree(tempString); endpoint->OpenPropertyStore(STGM_READ, &properties); PROPVARIANT pv; properties->GetValue(PKEY_Device_FriendlyName , &pv); friendlyName = std::wstring(pv.pwszVal); } void Endpoint::setIndex(uint64_t idx){ this->idx = idx; } uint64_t Endpoint::getIndex(){ return idx; } std::wstring Endpoint::getName(){ return friendlyName; } std::wstring Endpoint::getId(){ return endpointId; } float Endpoint::getVolume(int channel){ float volume; if (channel == AudioChannel::CHANNEL_MAIN) { if(FAILED(endpointVolume->GetMasterVolumeLevelScalar(&volume))) { /* log_debugcpp("si") */;} } else { if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */} } return volume; } uint32_t Endpoint::getChannelCount(){ return (uint32_t)channelCount; } bool Endpoint::getMute(){ BOOL mut; if(FAILED(endpointVolume->GetMute(&mut))) { /* TIP: Below */ } bool mute = (bool)mut; return mute; } void Endpoint::setState(uint8_t state){ this->endpointState = state; } uint8_t Endpoint::getState(){ return this->endpointState; } void Endpoint::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(endpointVolume->SetMasterVolumeLevelScalar(volume, &tempMsGuid))) {}; } else { if(FAILED(endpointVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) { }; } } void Endpoint::setMute(NGuid guid, bool muted) { GUID tempMsGuid = NGuidToGUID(guid); if(FAILED(endpointVolume->SetMute(muted, &tempMsGuid))) { /* TIP: Above */ }; } void Endpoint::setVolumeCallback(EndpointVolumeCallback *epc){ endpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); } void Endpoint::removeVolumeCallback(EndpointVolumeCallback *epc){ endpointVolume->UnregisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); } uint8_t Endpoint::getRoles(){ return this->endpointRoles; } void Endpoint::setRoles(Roles role){ //otro exe momento STARTUPINFOEXW startupConfig; PROCESS_INFORMATION processInfo; SecureZeroMemory(&startupConfig, sizeof(STARTUPINFOEXW)); SecureZeroMemory(&startupConfig.StartupInfo, sizeof(STARTUPINFOW)); startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW); SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); //const wchar_t* pCrutch = crutch.c_str(); std::wstring command = L"SoundVolumeView.exe /SetDefault " + endpointId + L" "; switch (role) { case Roles::ROLE_ALL: /* * one sends both, at least for now; * either cos of ms or dis guy, no choice * but to treat them as one for now * command += L"all"; */ command += L"0 1"; break; case Roles::ROLE_CONSOLE: command += std::to_wstring(0); break; case Roles::ROLE_MULTIMEDIA: command += std::to_wstring(1); break; case Roles::ROLE_COMMUNICATIONS: command += std::to_wstring(2); break; } if(CreateProcessW( NULL, (wchar_t*)command.c_str(), NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL, (LPSTARTUPINFOW)&startupConfig, &processInfo ) == true) { WaitForSingleObject(processInfo.hProcess, INFINITE ); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); } } void Endpoint::assignRoles(uint8_t role){ uint8_t roles = endpointRoles | role; this->endpointRoles = roles; } void Endpoint::removeRoles(uint8_t role){ uint8_t roles = endpointRoles ^ role; this->endpointRoles = roles; } Endpoint::~Endpoint(){ log_debugcpp("murio endpoint-san uwu"); properties->Release(); endpointVolume->Release(); endpoint->Release(); } void Overseer::initCOMLibrary() { if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE))) { log_debugcpp("si"); }; //Retrieving endpoint enumerator //MMDeviceEnumerator es el CLSID de toda la vaina de MMDevicear if(FAILED(CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&deviceEnumerator)) ) { log_debugcpp("si"); }; GUID tempGuid; if(FAILED(CoCreateGuid(&tempGuid))) { log_debugcpp("Failed to obtain GUID: " ); }; this->guid = GUIDToNGuid(&tempGuid); //if(FAILED(CoCreateInstance(__uuidof(CPolicyConfigClient), // NULL, CLSCTX_ALL, __uuidof(IPolicyConfig10), (LPVOID *)&policyConfig))) {exit(-1);} //TODO: Release lpguid? //TODO: Uninitialize COM } void Overseer::reloadEndpoints() { IMMDeviceCollection *deviceCollection; // | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED if(FAILED(deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE , &deviceCollection) )) { log_debugcpp("si"); }; //Counting them if(FAILED(deviceCollection->GetCount(&numPlaybackEndpoints))) { log_debugcpp("si");}; if(numPlaybackEndpoints == 0) { log_debugcpp("si"); }; //Retrieving actual endpoints and storing them on their own class IMMDevice *temp; for (unsigned int i = 0; i < numPlaybackEndpoints; i++){ if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); }; Endpoint *endpoint = new Endpoint(temp, i); //endpoint->setIndex(i); this->playbackDevices.push_back(endpoint); //TODO: le porblemx std::cout << "ola" << std::endl; } deviceCollection->Release(); //Discerning default endpoints per role //order: console, multimedia, communications for(int i = 0; i < ERole_enum_count; i++){ ERole val; switch(i) { case 0: val = eConsole; break; case 1: val = eMultimedia; break; case 2: val = eCommunications; break; } deviceEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, val, &temp); LPWSTR id = nullptr; for (unsigned int j = 0; j < numPlaybackEndpoints; j++){ std::wstring eptId = playbackDevices.at(j)->getId(); temp->GetId(&id); int comparison = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, eptId.c_str(), -987, id, -987, NULL, NULL, 0); if (comparison - 2 == 0) { log_wdebugcpp("ola defaul de " << i << " es " << id); playbackDevices.at(j)->assignRoles((1 << i)); } //uint8_t debg = playbackDevices.at(j)->getRoles(); } } } Overseer::Overseer() { //: epsc(deviceEnumerator, playbackDevices){ //Initializing COM library log_debugcpp("Initializing Overseer"); initCOMLibrary(); //Obtaining playback endpoint collection on this point in time reloadEndpoints(); this->epsc.fill(deviceEnumerator, playbackDevices); if(FAILED(deviceEnumerator->RegisterEndpointNotificationCallback(((IMMNotificationClient*)&epsc)))) { log_debugcpp("when no enchufas......"); } } NGuid Overseer::getGuid() { return guid; } std::vector Overseer::getPlaybackEndpoints() { return playbackDevices; } Overseer::~Overseer(){ log_debugcpp("cum"); deviceEnumerator->Release(); for(unsigned long long i = 0; i < playbackDevices.size(); i++){ delete(playbackDevices.at(i)); } } //int Overseer::getCaptureEndpoints(std::vector *captureEndpoints); //IMMDeviceEnumerator** Overseer::setOrigin();