#pragma once #include #include #include #include #include #include #include #include #include "Common.h" using namespace Microsoft::WRL; class CLoopbackCapture : public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler > { public: //CLoopbackCapture() = default; ~CLoopbackCapture(); HRESULT StartCaptureAsync(DWORD processId, bool includeProcessTree); HRESULT StopCaptureAsync(); METHODASYNCCALLBACK(CLoopbackCapture, StartCapture, OnStartCapture); METHODASYNCCALLBACK(CLoopbackCapture, StopCapture, OnStopCapture); METHODASYNCCALLBACK(CLoopbackCapture, SampleReady, OnSampleReady); METHODASYNCCALLBACK(CLoopbackCapture, FinishCapture, OnFinishCapture); // IActivateAudioInterfaceCompletionHandler STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation* operation); std::string buffer; private: // NB: All states >= Initialized will allow some methods // to be called successfully on the Audio Client enum class DeviceState { Uninitialized, Error, Initialized, Starting, Capturing, Stopping, Stopped, }; HRESULT OnStartCapture(IMFAsyncResult* pResult); HRESULT OnStopCapture(IMFAsyncResult* pResult); HRESULT OnFinishCapture(IMFAsyncResult* pResult); HRESULT OnSampleReady(IMFAsyncResult* pResult); HRESULT InitializeLoopbackCapture(); HRESULT CreateWAVFile(); HRESULT FixWAVHeader(); HRESULT OnAudioSampleRequested(); HRESULT ActivateAudioInterface(DWORD processId, bool includeProcessTree); HRESULT FinishCaptureAsync(); HRESULT SetDeviceStateErrorIfFailed(HRESULT hr); wil::com_ptr_nothrow m_AudioClient; WAVEFORMATEX m_CaptureFormat{}; UINT32 m_BufferFrames = 0; wil::com_ptr_nothrow m_AudioCaptureClient; wil::com_ptr_nothrow m_SampleReadyAsyncResult; wil::unique_event_nothrow m_SampleReadyEvent; MFWORKITEM_KEY m_SampleReadyKey = 0; wil::critical_section m_CritSec; DWORD m_dwQueueID = 0; DWORD m_cbHeaderSize = 0; DWORD m_cbDataSize = 0; std::mutex bufferlock; // These two members are used to communicate between the main thread // and the ActivateCompleted callback. HRESULT m_activateResult = E_UNEXPECTED; DeviceState m_DeviceState{ DeviceState::Uninitialized }; wil::unique_event_nothrow m_hActivateCompleted; wil::unique_event_nothrow m_hCaptureStopped; };