#pragma once #include "msinclude.h" #include "backsessionclasses.h" #include "global.h" #include "contclasses.h" //#include "environment.h" class EndpointVolumeCallback; class Session; // Convert a wide UTF16LE string to an UTF8 string static inline std::string utf16ToUtf8(const wchar_t* wstr) { if(!wstr || wstr[0] == '\0') return std::string(); int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); std::string str(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &str[0], size_needed, NULL, NULL); return str; } // Convert an UTF8 string to a wide UTF16LE String /* * std::wstring utf8_decode(const std::string &str) * { * if( str.empty() ) return std::wstring(); * int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); * std::wstring wstrTo( size_needed, 0 ); * MultiByteToWideChar (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed); * return wstrTo; * } */ class Endpoint { public: Endpoint(IMMDevice* endpoint, IPolicyConfig7* policyConfig, uint64_t idx = 0); //todo: how to forward declare delegate constructors? //Endpoint(IMMDevice* endpoint) : Endpoint(endpoint, 0) {}; void reloadEndpointChannels(); uint64_t getIndex(); void setIndex(uint64_t idx); void setVolume(NGuid guid, int channel, float volume); uint32_t getChannelCount(); float getVolume(int channel); void setMute(NGuid guid, bool muted); bool getMute(); void setState(EndpointState state); EndpointState getState(); Roles getRoles(); void setRoles(Roles role); void assignRoles(Roles role); void removeRoles(Roles role); void setFlow(); Flows getFlow(); float getPeakVolume(); std::wstring getId(); std::wstring getName(); void updateName(); void setVolumeCallback(EndpointVolumeCallback *epc); void removeVolumeCallback(EndpointVolumeCallback *epc); /* sessions */ std::vector getSessions(); size_t getSessionCount(); void addSession(Session* session); void registerNewSessionNotification(EndpointNewSessionCallback* ensc); void unregisterNewSessionNotification(EndpointNewSessionCallback* ensc); void deleteSessions(); void activateEndpointSessions(); //void deleteSessionManager(); std::mutex endpointSessionsMutex; ~Endpoint(); private: void inline activateEndpointVolume(); std::vector endpointSessions; uint32_t channelCount = 0; IMMDevice *endpoint; IAudioEndpointVolume *endpointVolume = nullptr; IPropertyStore *properties; IAudioMeterInformation *endpointPeakMeter = nullptr; //IAudioClient *audioClient; int64_t defTime, minTime; IAudioSessionManager2 *sessionManager = nullptr; Flows flow; std::wstring friendlyName; std::wstring descriptionName; std::wstring deviceName; std::wstring endpointId; EndpointState endpointState; Roles endpointRoles = (Roles)0; uint64_t idx; //Not implemented in llvm-mingw. Sad! todo: mingw patch IPolicyConfig7* policyConfig; }; class EndpointVolumeCallback : public IAudioEndpointVolumeCallback { public: EndpointVolumeCallback(Endpoint* ep); ULONG AddRef(); ULONG Release(); HRESULT QueryInterface(REFIID riid, VOID **ppvInterface); HRESULT OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA update); void updateVolumeInfo(AUDIO_VOLUME_NOTIFICATION_DATA newVolume, float* channelVolumes); void reportFinished(); //~EndpointVolumeCallback(); private: ULONG ref = 1; Endpoint* ep; std::atomic wait = false; }; class EndpointSituationCallback : public IMMNotificationClient { public: EndpointSituationCallback(Overseer* os); ULONG AddRef(); ULONG Release(); HRESULT QueryInterface(REFIID riid, VOID **ppvInterface); HRESULT OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId); HRESULT OnDeviceAdded(LPCWSTR pwstrDeviceId); HRESULT OnDeviceRemoved(LPCWSTR pwstrDeviceId); HRESULT OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState); HRESULT OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key); void reportFinishedStateChange(); private: ULONG ref = 1; Overseer* os; std::atomic isEpStateChanging = false; }; class Overseer { public: Overseer(); void registerEndpointSituationCallback(); NGuid getGuid(); std::vector getPlaybackEndpoints(); std::vector getCaptureEndpoints(); void updateEndpointInfo(std::wstring endpointId); void createEndpoints(Flows flow); Endpoint* addEndpoint(std::wstring endpointId, /* out */ Flows* flow); void reportFinishedStateChange(); std::mutex playbackMutex; std::mutex captureMutex; //void setEndpointStatusCallback(); //void setEndpointStatusCallback(); //~Overseer(); //int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint); //int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint); //int getCaptureEndpoints(std::vector *captureEndpoints); //IMMDeviceEnumerator** setOrigin(); ~Overseer(); private: void initCOMLibrary(); NGuid guid; IMMDeviceEnumerator *deviceEnumerator; EndpointSituationCallback epsc; std::vector playbackDevices; std::vector captureDevices; IPolicyConfig7* policyConfig; friend class Endpoint; //IMMDeviceCollection *deviceCollection; //int numCaptureEndpoints; //std::vector *captureDevices; }; class EndpointNewSessionCallback : public IAudioSessionNotification { private: struct SessionThreadParams; public: EndpointNewSessionCallback(EndpointHandler *eph); ULONG AddRef(); ULONG Release(); HRESULT QueryInterface(REFIID riid, VOID **ppvInterface); HRESULT OnSessionCreated(IAudioSessionControl *NewSession); void createSessionThread(SessionThreadParams params); private: std::atomic wait = false; ULONG ref = 1; EndpointHandler *eph; struct SessionThreadParams { EndpointHandler *eph; Session *session; bool isDelete; }; }; namespace Environment { wchar_t* getExeAbsPath(uint32_t *exeAbsPathLength); std::string createSettingsPath(SettingsTargetDirectory target); void populateSystemValues(); void openControlPanel(); ProcessedNativeEvent processTopLevelWindowMessage(void* msg); ProcessedNativeEvent updateColors(); bool checkStartup(HKEY rootKeyFlags); void updateStartupConfig(bool onStartup); void setStartupConfig(bool onStartup); bool isLightMode(); bool isToRunAtStartup(); uint32_t getAccentColor(); //todo: binary path cache unused static std::wstring exeAbsPath; static uint32_t exeAbsPathLen; static bool lightMode; static bool startup = false; static HKEY scope; static uint32_t accentColor; };