From 8c4603c73675958efc960fbd4bb599a2909d106a Mon Sep 17 00:00:00 2001 From: Konstantin Date: Mon, 16 Jan 2023 14:52:43 +0100 Subject: Source codes --- Whisper/MF/AudioCapture.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 Whisper/MF/AudioCapture.cpp (limited to 'Whisper/MF/AudioCapture.cpp') diff --git a/Whisper/MF/AudioCapture.cpp b/Whisper/MF/AudioCapture.cpp new file mode 100644 index 0000000..17f34dc --- /dev/null +++ b/Whisper/MF/AudioCapture.cpp @@ -0,0 +1,167 @@ +#include "stdafx.h" +#include +#include +#include +#include +#include "AudioCapture.h" +#include "../API/iMediaFoundation.cl.h" +#include "../ComLightLib/comLightServer.h" +#pragma comment(lib, "Mf.lib") + +namespace +{ + struct Strings + { + CString displayName, endpoint; + }; + + HRESULT getAllocString( IMFActivate* activate, const GUID& id, CString& rdi ) + { + wchar_t* pointer = nullptr; + UINT32 cchName; + HRESULT hr = activate->GetAllocatedString( id, &pointer, &cchName ); + if( SUCCEEDED( hr ) ) + rdi.SetString( pointer, cchName ); + CoTaskMemFree( pointer ); + return hr; + } + + HRESULT getInfo( IMFActivate* activate, Strings& rdi ) + { + CHECK( getAllocString( activate, MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, rdi.displayName ) ); + CHECK( getAllocString( activate, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID, rdi.endpoint ) ); + return S_OK; + } + + HRESULT __stdcall supplyDevices( Whisper::pfnFoundCaptureDevices pfn, void* pv, IMFActivate** ppDevices, UINT32 count ) + { + if( ppDevices == nullptr || count == 0 ) + return pfn( 0, nullptr, pv ); + + std::vector strings; + strings.reserve( count ); + + for( UINT i = 0; i < count; i++ ) + { + IMFActivate* const activate = ppDevices[ i ]; + if( nullptr == activate ) + continue; + Strings info; + HRESULT hr = getInfo( activate, info ); + if( FAILED( hr ) ) + continue; + + strings.emplace_back( std::move( info ) ); + } + + const size_t len = strings.size(); + if( 0 == len ) + return pfn( 0, nullptr, pv ); + + std::vector pointers; + pointers.resize( len ); + for( size_t i = 0; i < len; i++ ) + { + const auto& src = strings[ i ]; + auto& dest = pointers[ i ]; + dest.displayName = src.displayName; + dest.endpoint = src.endpoint; + } + return pfn( (int)len, pointers.data(), pv ); + } +} + +HRESULT __stdcall Whisper::captureDeviceList( pfnFoundCaptureDevices pfn, void* pv ) +{ + // Create an attribute store to hold the search criteria. + CComPtr attrs; + CHECK( MFCreateAttributes( &attrs, 1 ) ); + // Request audio capture devices + CHECK( attrs->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID ) ); + + // Enumerate the devices + IMFActivate** ppDevices = nullptr; + UINT32 count = 0; + CHECK( MFEnumDeviceSources( attrs, &ppDevices, &count ) ); + + // Feed the data to the caller + HRESULT hr = supplyDevices( pfn, pv, ppDevices, count ); + + // Free the memory + for( DWORD i = 0; i < count; i++ ) + ppDevices[ i ]->Release(); + CoTaskMemFree( ppDevices ); + + return hr; +} + +namespace +{ + using namespace Whisper; + + class Capture : public ComLight::ObjectRoot + { + CComPtr reader; + CComPtr mediaFoundation; + sCaptureParams captureParams; + + HRESULT COMLIGHTCALL getReader( IMFSourceReader** pp ) const noexcept override final + { + if( pp == nullptr ) + return E_POINTER; + CComPtr res = reader; + *pp = res.Detach();; + return S_OK; + } + const sCaptureParams& COMLIGHTCALL getParams() const noexcept override final + { + return captureParams; + } + public: + HRESULT open( iMediaFoundation* owner, const wchar_t* endpoint, const sCaptureParams& cp ); + }; + + HRESULT Capture::open( iMediaFoundation* owner, const wchar_t* endpoint, const sCaptureParams& cp ) + { + // Create an attribute store to hold the search criteria. + CComPtr attrs; + CHECK( MFCreateAttributes( &attrs, 2 ) ); + // Request audio capture devices + CHECK( attrs->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID ) ); + CHECK( attrs->SetString( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID, endpoint ) ); + + CComPtr source; + HRESULT hr = MFCreateDeviceSource( attrs, &source ); + if( FAILED( hr ) ) + { + logErrorHr( hr, u8"MFCreateDeviceSource" ); + return hr; + } + + // TODO: implement IMFSourceReaderCallback, pass into MF_SOURCE_READER_ASYNC_CALLBACK attribute + // This is to support cancellation + hr = MFCreateSourceReaderFromMediaSource( source, nullptr, &reader ); + if( FAILED( hr ) ) + { + logErrorHr( hr, u8"MFCreateSourceReaderFromMediaSource" ); + return hr; + } + + captureParams = cp; + mediaFoundation = owner; + return S_OK; + } +} + +HRESULT __stdcall Whisper::captureOpen( iMediaFoundation* owner, const wchar_t* endpoint, const sCaptureParams& captureParams, iAudioCapture** pp ) noexcept +{ + if( nullptr == endpoint || nullptr == pp ) + return E_POINTER; + + ComLight::CComPtr> res; + CHECK( ComLight::Object::create( res ) ); + CHECK( res->open( owner, endpoint, captureParams ) ); + + res.detach( pp ); + return S_OK; +} \ No newline at end of file -- cgit v1.2.3