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;
}
|