mixer/src/back/backlasses.cpp

460 lines
13 KiB
C++

#include <backlasses.h>
#include <backfuncs.h>
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<Endpoint*> playbackDevices){
* this->deviceEnumerator = deviceEnumerator;
* this->playbackDevices = playbackDevices;
* }
*/
void EndpointSituationCallback::fill(IMMDeviceEnumerator *deviceEnumerator, std::vector<Endpoint*> 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<Endpoint*> 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<Endpoint*> *captureEndpoints);
//IMMDeviceEnumerator** Overseer::setOrigin();