summaryrefslogtreecommitdiffstats
path: root/Whisper/MF/MediaFoundation.cpp
blob: df6990c4c2066b659740287cf688ff9b68e92620 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "stdafx.h"
#include "../API/iMediaFoundation.cl.h"
#include "mfStartup.h"
#include "../ComLightLib/comLightServer.h"
#include "loadAudioFile.h"
#include <mfidl.h>
#include <mfreadwrite.h>
#include "mfUtils.h"
#include "AudioCapture.h"
#include <mfapi.h>

namespace Whisper
{
	class AudioReader : public ComLight::ObjectRoot<iAudioReader>
	{
		CComPtr<IMFSourceReader> reader;
		bool wantStereo;
		CComPtr<iMediaFoundation> mediaFoundation;
		mutable int64_t preciseSamplesCount = 0;

		HRESULT COMLIGHTCALL getReader( IMFSourceReader** pp ) const noexcept override final
		{
			if( pp == nullptr )
				return E_POINTER;
			CComPtr<IMFSourceReader> res = reader;
			*pp = res.Detach();;
			return S_OK;
		}
		HRESULT COMLIGHTCALL requestedStereo() const noexcept override final
		{
			return wantStereo ? S_OK : S_FALSE;
		}
		HRESULT COMLIGHTCALL getDuration( int64_t& rdi ) const noexcept override final
		{
			if( reader )
			{
				if( 0 == preciseSamplesCount )
					return getStreamDuration( reader, rdi );
				else
				{	rdi = MFllMulDiv( preciseSamplesCount, 10'000'000, SAMPLE_RATE, 0 );
					return S_OK;
				}
			}
			return OLE_E_BLANK;
		}
	public:
		HRESULT open( iMediaFoundation* owner, LPCTSTR path, bool stereo )
		{
			HRESULT hr = MFCreateSourceReaderFromURL( path, nullptr, &reader );
			if( FAILED( hr ) )
			{
				logErrorHr( hr, u8"MFCreateSourceReaderFromURL failed" );
				return hr;
			}
			wantStereo = stereo;
			mediaFoundation = owner;
			logDebug16( L"Created source reader from the file \"%s\"", path );
			return S_OK;
		}
		void setPreciseSamplesCount( int64_t count ) const
		{
			preciseSamplesCount = count;
		}
	};

	void setPreciseSamplesCount( const iAudioReader* ar, int64_t count )
	{
		const AudioReader* r = static_cast<const AudioReader*>( ar );
		r->setPreciseSamplesCount( count );
	}

	class MediaFoundation : public ComLight::ObjectRoot<iMediaFoundation>
	{
		MfStartupRaii raii;
		DWORD tid = ~(DWORD)0;

		virtual HRESULT COMLIGHTCALL loadAudioFile( LPCTSTR path, bool stereo, iAudioBuffer** pp ) const noexcept override final
		{
			return Whisper::loadAudioFile( path, stereo, pp );
		}
		virtual HRESULT COMLIGHTCALL openAudioFile( LPCTSTR path, bool stereo, iAudioReader** pp ) noexcept override final
		{
			if( nullptr == path || nullptr == pp )
				return E_POINTER;

			ComLight::CComPtr<ComLight::Object<AudioReader>> res;
			CHECK( ComLight::Object<AudioReader>::create( res ) );
			CHECK( res->open( this, path, stereo ) );

			res.detach( pp );
			return S_OK;
		}
		HRESULT COMLIGHTCALL listCaptureDevices( pfnFoundCaptureDevices pfn, void* pv ) noexcept override final
		{
			return captureDeviceList( pfn, pv );
		}
		HRESULT COMLIGHTCALL openCaptureDevice( LPCTSTR endpoint, const sCaptureParams& captureParams, iAudioCapture** pp ) noexcept override final
		{
			return captureOpen( this, endpoint, captureParams, pp );
		}
	protected:

		HRESULT FinalConstruct()
		{
			CHECK( raii.startup() );
			tid = GetCurrentThreadId();
			return S_OK;
		}

	public:

		~MediaFoundation() override
		{
			assert( tid == GetCurrentThreadId() );
		}
	};
}

HRESULT COMLIGHTCALL Whisper::initMediaFoundation( iMediaFoundation** pp )
{
	if( nullptr == pp )
		return E_POINTER;

	ComLight::CComPtr<ComLight::Object<MediaFoundation>> obj;
	CHECK( ComLight::Object<MediaFoundation>::create( obj ) );
	obj.detach( pp );
	return S_OK;
}