#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) { if (eph->getFlow() == Flows::FLOW_CAPTURE) return S_OK; HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); IAudioSessionControl2* sessionControl; //ISimmpleAudioVolume* sessionVolume; if (FAILED(NewSession->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl))) { log_wdebugcpp(L"no nueva sesion......"); }; if (sessionControl) { sessionControl->AddRef(); //sessionControl->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&sessionVolume); Session* newSession = new Session(this->eph->getEndpoint(), sessionControl); eph->addSessionSendFront(newSession); } if (result == S_OK) CoUninitialize(); return S_OK; } 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->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller; //osh->getPlaybackEndpointHandlers().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->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data1 \ = pNotify->guidEventContext.Data1; osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data2 \ = pNotify->guidEventContext.Data2; osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data3 \ = pNotify->guidEventContext.Data3; for(int i = 0; i < 8 /* Data4 size */; i++){ osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller.data4[i] = pNotify->guidEventContext.Data4[i]; } //memcpy(&osh->getPlaybackEndpointHandlers().at(this->ep->getIndex())->getCallbackInfo()->caller, &pNotify->guidEventContext,sizeof(NGuid) ); Flows flow = this->ep->getFlow(); EndpointHandler* eph = nullptr; if (flow & Flows::FLOW_PLAYBACK) { eph = osh->getPlaybackEndpointHandlers().at(this->ep->getIndex()); } else { eph = osh->getCaptureEndpointHandlers().at(this->ep->getIndex()); } eph->getCallbackInfo()->muted = pNotify->bMuted; eph->getCallbackInfo()->mainVolume = pNotify->fMasterVolume; eph->getCallbackInfo()->channels = pNotify->nChannels; UINT j = 0; //todo: do while here caused stack corruption; sus while(j < pNotify->nChannels) { if (flow & Flows::FLOW_PLAYBACK) eph->getCallbackInfo()->channelVolumes[j] = pNotify->afChannelVolumes[j]; else eph->getCallbackInfo()->channelVolumes[j] = pNotify->afChannelVolumes[j]; j++; } return S_OK; } /* * EndpointSituationCallback::EndpointSituationCallback(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; log_wdebugcpp(L"we got za defol 4 " + wstringEndpointId); osh->changeFrontDefaultsCallback(nRole, wstringEndpointId); return S_OK; } HRESULT EndpointSituationCallback::OnDeviceAdded(LPCWSTR pwstrDeviceId) { log_wdebugcpp(L"ayo we eventing za adin " + std::wstring(pwstrDeviceId)); return S_OK; }; HRESULT EndpointSituationCallback::OnDeviceRemoved(LPCWSTR pwstrDeviceId) { log_wdebugcpp(L"ayo we eventing za rmovin " + std::wstring(pwstrDeviceId)); return S_OK; } HRESULT EndpointSituationCallback::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { std::wstring endpointId = std::wstring(pwstrDeviceId); switch (dwNewState){ case DEVICE_STATE_ACTIVE: osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_ACTIVE); break; case DEVICE_STATE_DISABLED: osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_DISABLED); break; case DEVICE_STATE_NOTPRESENT: osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_NOTPRESENT); break; case DEVICE_STATE_UNPLUGGED: osh->reviseEndpointShowing(endpointId, EndpointState::ENDPOINT_UNPLUGGED); break; } return S_OK; } HRESULT EndpointSituationCallback::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { /* * log_debugcpp(" -->Changed device property " + * key.fmtid.Data1 + key.fmtid.Data2 + key.fmtid.Data3 + "\n" + * key.fmtid.Data4[0]+ key.fmtid.Data4[1]+ "\n"+ * key.fmtid.Data4[2]+ key.fmtid.Data4[3] + "\n"+ * key.fmtid.Data4[4]+ key.fmtid.Data4[5] + "\n"+ * key.fmtid.Data4[6]+ key.fmtid.Data4[7]+ "\n"+ * " pid " + key.pid); */ return S_OK; } Endpoint::Endpoint(IMMDevice* ep, uint64_t idx){ this->endpoint = ep; this->idx = idx; /* * It can't multiflag, it's that stupid. MS momento. * Only shows most relevant flag according to MS, i.e. 0110 sends 0010 */ //todo: preguntitas owindows dword no es uint32_t even tho mingw mingas if(FAILED(endpoint->GetState(&this->endpointState))) {exit(-2);}; if(this->endpointState == EndpointState::ENDPOINT_ACTIVE) { activateEndpointVolume(); } reloadEndpointChannels(); /* todo: check header * if(FAILED(endpoint->Activate(__uuidof(IAudioMeterInformation), * CLSCTX_ALL, NULL, (void**)&endpointPeakMeter))) { log_debugcpp("peakbros..."); } */ //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); if (pv.pwszVal == nullptr) friendlyName = L"Unnamed Not Present Endpoint"; else friendlyName = std::wstring(pv.pwszVal); this->setFlow(); if (this->flow == Flows::FLOW_PLAYBACK) { activateEndpointSessions(); } } void Endpoint::activateEndpointSessions() { //sessionManager; if (FAILED(endpoint->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**) &sessionManager))) { log_wdebugcpp(L"sesionbros..."); return; } IAudioSessionEnumerator* sessionEnumerator = nullptr; if (FAILED(sessionManager->GetSessionEnumerator(&sessionEnumerator))) { log_wdebugcpp(L"sesEnumeratorBros..."); return; } endpointSessions.resize(1, nullptr); int sessionCount; sessionEnumerator->GetCount(&sessionCount); for (int i = 0; i < sessionCount; i++) { IAudioSessionControl* sessionControlTmp; sessionEnumerator->GetSession(i, (IAudioSessionControl**)&sessionControlTmp); //todo:: asegurar lo del dynamic_cast IAudioSessionControl2* sessionControl; sessionControlTmp->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&sessionControl); sessionControl->AddRef(); sessionControlTmp->Release(); Session* session = new Session(this, sessionControl, (size_t)i); if (sessionControl->IsSystemSoundsSession() == S_OK) endpointSessions[0] = session; else endpointSessions.push_back(session); } sessionEnumerator->Release(); } void Endpoint::addSession(Session* session) { session->setIndex(this->getSessionCount()); endpointSessions.push_back(session); } void Endpoint::activateEndpointVolume() { //bool extraThread = false; /* * Forgive me, for MS has sinned, and now I must too. */ if (this->endpointVolume == nullptr){ HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); endpoint->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&this->endpointVolume); //if (endpointVolume == nullptr) { //why they returning 0 after dealing with the error jfc CO_E_NOTINITIALIZED) { //CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); //extraThread = true; //goto initialized; //} //log_debugcpp(std::string("no endpointVolume (IAudioEndpointVolume)")); if (result == S_OK) CoUninitialize(); } } void Endpoint::reloadEndpointChannels() { if (this->endpointState == DEVICE_STATE_ACTIVE) { if (FAILED(endpointVolume->GetChannelCount(&channelCount))) {log_debugcpp("get channel count fail");};/* */ } } 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; if(state == EndpointState::ENDPOINT_ACTIVE) { this->activateEndpointVolume(); this->reloadEndpointChannels(); } } size_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))) { log_wdebugcpp(std::wstring(L"EndpointVolume null?")); }; } void Endpoint::setVolumeCallback(EndpointVolumeCallback *epc){ if(endpointVolume == nullptr) { this->activateEndpointVolume(); } endpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); } void Endpoint::removeVolumeCallback(EndpointVolumeCallback *epc){ endpointVolume->UnregisterControlChangeNotify((IAudioEndpointVolumeCallback*)epc); } Roles Endpoint::getRoles(){ return this->endpointRoles; } void Endpoint::setRoles(Roles role){ //todo: 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)); std::wstring command = L"SoundVolumeView.exe /SetDefault " + endpointId + L" "; std::wstring troublePair = L"0"; switch (role) { case Roles::ROLE_ALL: /* * console or multimedia, 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"; and nothing else would've been nice... */ troublePair = command + troublePair; if(CreateProcessW( NULL, (wchar_t*)troublePair.c_str(), NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL, (LPSTARTUPINFOW)&startupConfig, &processInfo ) == true) { WaitForSingleObject(processInfo.hProcess, INFINITE ); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); } command += L"2"; 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(Roles role){ Roles roles = (Roles)(endpointRoles | role); this->endpointRoles = roles; } void Endpoint::removeRoles(Roles role){ Roles roles = (Roles)(endpointRoles ^ role); this->endpointRoles = roles; } void Endpoint::setFlow() { IMMEndpoint* flowGetter; //this should be as simple as writing IID_IMMEndpoint, but it just won't find the macro, so I copied it. Sad. GUID manual; manual.Data1 = 0x1be09788; manual.Data2 = 0x6894; manual.Data3 = 0x4089; manual.Data4[0] = 0x85; manual.Data4[1] = 0x86; manual.Data4[2] = 0x9a; manual.Data4[3] = 0x2a; manual.Data4[4] = 0x6c; manual.Data4[5] = 0x26; manual.Data4[6] = 0x5a; manual.Data4[7] = 0xc5; if(FAILED(this->endpoint->QueryInterface((const _GUID)manual, (void**)&flowGetter))) { log_debugcpp("no flow..."); } EDataFlow MSflow; HRESULT vafllar = flowGetter->GetDataFlow(&MSflow); this->flow = (MSflow == EDataFlow::eRender ? Flows::FLOW_PLAYBACK : Flows::FLOW_CAPTURE); flowGetter->Release(); } Flows Endpoint::getFlow() { return this->flow; } /* sessions */ std::vector Endpoint::getSessions() { return endpointSessions; } size_t Endpoint::getSessionCount() { return endpointSessions.size(); } void Endpoint::registerNewSessionNotification(EndpointNewSessionCallback* ensc){ sessionManager->RegisterSessionNotification(ensc); } void Endpoint::unregisterNewSessionNotification(EndpointNewSessionCallback* ensc){ sessionManager->UnregisterSessionNotification(ensc); } Endpoint::~Endpoint(){ log_wdebugcpp(L"murio endpoint-san uwu"); properties->Release(); endpointVolume->Release(); endpoint->Release(); sessionManager->Release(); } void Overseer::initCOMLibrary() { OutputDebugStringW(L"EPWidget creation\n"); 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: " ); }; //todo: wtf? why is it working? floats are ptrs... 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(Flows flow) { IMMDeviceCollection *deviceCollection; unsigned int numEndpoints; EDataFlow MSflow = (flow == Flows::FLOW_PLAYBACK ? EDataFlow::eRender : EDataFlow::eCapture); // | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED // NOTPRESENT shows a lot of garbage, unnamed devices. if(FAILED(deviceEnumerator->EnumAudioEndpoints(MSflow, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED, &deviceCollection) )) { log_debugcpp("si"); }; /* * Counting them */ if(FAILED(deviceCollection->GetCount(&numEndpoints))) { log_debugcpp("si");}; if(numEndpoints == 0) { log_debugcpp("si"); }; /* * Retrieving actual endpoints and storing them on their own class */ IMMDevice *temp; for (unsigned int i = 0; i < numEndpoints; i++){ if(deviceCollection->Item(i, &temp) != 0) { log_debugcpp("si"); }; Endpoint *endpoint = new Endpoint(temp, i); if (flow == Flows::FLOW_PLAYBACK) this->playbackDevices.push_back(endpoint); else this->captureDevices.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(MSflow, val, &temp); LPWSTR id = nullptr; if (flow == Flows::FLOW_PLAYBACK) { for (unsigned int j = 0; j < numEndpoints; 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(L"ola defaul playback de " + std::to_wstring(i) + L" es " + id); playbackDevices.at(j)->assignRoles((Roles)(1 << i)); } } } else { for (unsigned int j = 0; j < numEndpoints; j++){ std::wstring eptId = captureDevices.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(L"ola defaul capture de " + std::to_wstring(i) + L" es " + id); captureDevices.at(j)->assignRoles((Roles)(1 << i)); } } } } } Endpoint* Overseer::addEndpoint(std::wstring endpointId, /* out */Flows* flow = nullptr) { IMMDevice* newep; if(FAILED(deviceEnumerator->GetDevice((LPCWSTR)endpointId.c_str(), &newep))) log_debugcpp("ay caramba con la hot metida."); Endpoint *endpoint = new Endpoint(newep); Flows getFlow = endpoint->getFlow(); if (getFlow == Flows::FLOW_PLAYBACK) { endpoint->setIndex(osh->getPlaybackEndpointsCount()); this->playbackDevices.push_back(endpoint); } else { endpoint->setIndex(osh->getCaptureEndpointsCount()); this->captureDevices.push_back(endpoint); } if (flow != nullptr) *flow = getFlow; return endpoint; } Overseer::Overseer() { //: epsc(deviceEnumerator, playbackDevices){ //Initializing COM library log_debugcpp("Initializing Overseer"); initCOMLibrary(); //Obtaining playback endpoint collection on this point in time reloadEndpoints(Flows::FLOW_PLAYBACK); //reloadEndpoints(Flows::FLOW_CAPTURE); //Registering for endpoint information callback //this->epsc.fill(deviceEnumerator, playbackDevices, captureDevices); //this->epsc.fill(deviceEnumerator); if(FAILED(deviceEnumerator->RegisterEndpointNotificationCallback(((IMMNotificationClient*)&epsc)))) { log_debugcpp("when no enchufas......"); } } void Overseer::openControlPanel() { STARTUPINFOEXW startupConfig; PROCESS_INFORMATION processInfo; SecureZeroMemory(&startupConfig, sizeof(STARTUPINFOEXW)); SecureZeroMemory(&startupConfig.StartupInfo, sizeof(STARTUPINFOW)); startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW); SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); std::wstring command = L"rundll32 shell32, Control_RunDLL mmsys.cpl"; if(CreateProcessW( NULL, (wchar_t*)command.c_str(), NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL, (LPSTARTUPINFOW)&startupConfig, &processInfo ) == true) { CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); } } NGuid Overseer::getGuid() { return guid; } std::vector Overseer::getPlaybackEndpoints() { return playbackDevices; } std::vector Overseer::getCaptureEndpoints() { return captureDevices; } 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();