#pragma once #ifndef _WIN32 #error "XAudio2 can only be built on Windows." #endif #include #include "Utilities/mutex.h" #include "Emu/Audio/AudioBackend.h" #include #include #include class XAudio2Backend final : public AudioBackend, public IXAudio2VoiceCallback, public IXAudio2EngineCallback, public IMMNotificationClient { public: XAudio2Backend(); ~XAudio2Backend() override; XAudio2Backend(const XAudio2Backend&) = delete; XAudio2Backend& operator=(const XAudio2Backend&) = delete; std::string_view GetName() const override { return "XAudio2"sv; } bool Initialized() override; bool Operational() override; bool DefaultDeviceChanged() override; bool Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize sample_size, AudioChannelCnt ch_cnt) override; void Close() override; f64 GetCallbackFrameLen() override; void Play() override; void Pause() override; private: static constexpr u32 INTERNAL_BUF_SIZE_MS = 25; Microsoft::WRL::ComPtr m_xaudio2_instance{}; IXAudio2MasteringVoice* m_master_voice{}; IXAudio2SourceVoice* m_source_voice{}; bool m_com_init_success = false; Microsoft::WRL::ComPtr m_device_enumerator{}; shared_mutex m_dev_sw_mutex{}; std::string m_current_device{}; bool m_default_dev_changed = false; std::vector m_data_buf{}; std::array(AudioChannelCnt::SURROUND_7_1)> m_last_sample{}; atomic_t m_reset_req = false; // XAudio voice callbacks void OnVoiceProcessingPassStart(UINT32 BytesRequired) override; void OnVoiceProcessingPassEnd() override {} void OnStreamEnd() override {} void OnBufferStart(void* /* pBufferContext */) override {} void OnBufferEnd(void* /* pBufferContext*/) override {} void OnLoopEnd(void* /* pBufferContext */) override {} void OnVoiceError(void* /* pBufferContext */, HRESULT /* Error */) override {} // XAudio engine callbacks void OnProcessingPassStart() override {}; void OnProcessingPassEnd() override {}; void OnCriticalError(HRESULT Error) override; // IMMNotificationClient callbacks IFACEMETHODIMP_(ULONG) AddRef() override { return 1; }; IFACEMETHODIMP_(ULONG) Release() override { return 1; }; IFACEMETHODIMP QueryInterface(REFIID /*iid*/, void** /*object*/) override { return E_NOINTERFACE; }; IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR /*device_id*/, const PROPERTYKEY /*key*/) override { return S_OK; }; IFACEMETHODIMP OnDeviceAdded(LPCWSTR /*device_id*/) override { return S_OK; }; IFACEMETHODIMP OnDeviceRemoved(LPCWSTR /*device_id*/) override { return S_OK; }; IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR /*device_id*/, DWORD /*new_state*/) override { return S_OK; }; IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR new_default_device_id) override; void CloseUnlocked(); };