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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
/*
* (C) 2009-2013 see Authors.txt
*
* This file is part of MPC-HC.
*
* MPC-HC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* MPC-HC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "BaseClasses/streams.h"
#include <dsound.h>
#include <MMReg.h> //must be before other Wasapi headers
#include <strsafe.h>
#include <mmdeviceapi.h>
#include <avrt.h>
#include <audioclient.h>
#include <endpointvolume.h>
#include <FunctionDiscoveryKeys_devpkey.h>
#include "MpcAudioRendererSettingsWnd.h"
#include "SoundTouch/include/SoundTouch.h"
#define MpcAudioRendererName L"MPC-HC Audio Renderer"
// REFERENCE_TIME time units per second and per millisecond
#define REFTIMES_PER_SEC 10000000.0
#define REFTIMES_PER_MILLISEC 10000.0
// if you get a compilation error on AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED,
// uncomment the #define below
#define AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED AUDCLNT_ERR(0x019)
class __declspec(uuid("601D2A2B-9CDE-40bd-8650-0485E3522727"))
CMpcAudioRenderer : public CBaseRenderer
, public IBasicAudio
, public ISpecifyPropertyPages2
, public IMpcAudioRendererFilter
{
public:
CMpcAudioRenderer(LPUNKNOWN punk, HRESULT* phr);
virtual ~CMpcAudioRenderer();
static const AMOVIESETUP_FILTER sudASFilter;
HRESULT CheckInputType(const CMediaType* mtIn);
virtual HRESULT CheckMediaType(const CMediaType* pmt);
virtual HRESULT DoRenderSample(IMediaSample* pMediaSample);
virtual void OnReceiveFirstSample(IMediaSample* pMediaSample);
BOOL ScheduleSample(IMediaSample* pMediaSample);
virtual HRESULT SetMediaType(const CMediaType* pmt);
virtual HRESULT CompleteConnect(IPin* pReceivePin);
HRESULT EndOfStream();
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
// === IMediaFilter
STDMETHOD(Run)(REFERENCE_TIME tStart);
STDMETHOD(Stop)();
STDMETHOD(Pause)();
// === IDispatch (pour IBasicAudio)
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid);
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr);
// === IBasicAudio
STDMETHOD(put_Volume)(long lVolume);
STDMETHOD(get_Volume)(long* plVolume);
STDMETHOD(put_Balance)(long lBalance);
STDMETHOD(get_Balance)(long* plBalance);
// === ISpecifyPropertyPages2
STDMETHODIMP GetPages(CAUUID* pPages);
STDMETHODIMP CreatePage(const GUID& guid, IPropertyPage** ppPage);
// === IMpcAudioRendererFilter
STDMETHODIMP Apply();
STDMETHODIMP SetWasapiMode(BOOL nValue);
STDMETHODIMP_(BOOL) GetWasapiMode();
STDMETHODIMP SetMuteFastForward(BOOL nValue);
STDMETHODIMP_(BOOL) GetMuteFastForward();
STDMETHODIMP SetSoundDevice(CString nValue);
STDMETHODIMP_(CString) GetSoundDevice();
// CMpcAudioRenderer
private:
HRESULT DoRenderSampleDirectSound(IMediaSample* pMediaSample);
HRESULT InitCoopLevel();
HRESULT ClearBuffer();
HRESULT CreateDSBuffer();
HRESULT GetReferenceClockInterface(REFIID riid, void** ppv);
HRESULT WriteSampleToDSBuffer(IMediaSample* pMediaSample, bool* looped);
LPDIRECTSOUND8 m_pDS;
LPDIRECTSOUNDBUFFER m_pDSBuffer;
DWORD m_dwDSWriteOff;
WAVEFORMATEX* m_pWaveFileFormat;
int m_nDSBufSize;
CBaseReferenceClock* m_pReferenceClock;
double m_dRate;
long m_lVolume;
soundtouch::SoundTouch* m_pSoundTouch;
CCritSec m_csProps;
// CMpcAudioRenderer WASAPI methods
HRESULT GetAvailableAudioDevices(IMMDeviceCollection** ppMMDevices);
HRESULT GetAudioDevice(IMMDevice** ppMMDevice);
HRESULT CreateAudioClient(IMMDevice* pMMDevice, IAudioClient** ppAudioClient);
HRESULT InitAudioClient(WAVEFORMATEX* pWaveFormatEx, IAudioClient* pAudioClient, IAudioRenderClient** ppRenderClient);
HRESULT CheckAudioClient(WAVEFORMATEX* pWaveFormatEx);
bool CheckFormatChanged(const WAVEFORMATEX* pWaveFormatEx, WAVEFORMATEX** ppNewWaveFormatEx);
HRESULT DoRenderSampleWasapi(IMediaSample* pMediaSample);
HRESULT GetBufferSize(WAVEFORMATEX* pWaveFormatEx, REFERENCE_TIME* pHnsBufferPeriod);
// WASAPI variables
bool m_useWASAPI;
bool m_useWASAPIAfterRestart;
bool m_bMuteFastForward;
CString m_csSound_Device;
IMMDevice* pMMDevice;
IAudioClient* pAudioClient;
IAudioRenderClient* pRenderClient;
UINT32 nFramesInBuffer;
REFERENCE_TIME hnsPeriod, hnsActualDuration;
HANDLE hTask;
CCritSec m_csCheck;
UINT32 bufferSize;
bool isAudioClientStarted;
DWORD lastBufferTime;
// avrt.dll (Vista or greater)
typedef HANDLE(__stdcall* PTR_AvSetMmThreadCharacteristicsW)(LPCWSTR TaskName, LPDWORD TaskIndex);
typedef BOOL (__stdcall* PTR_AvRevertMmThreadCharacteristics)(HANDLE AvrtHandle);
HMODULE m_hLibAVRT;
PTR_AvSetMmThreadCharacteristicsW pfAvSetMmThreadCharacteristicsW;
PTR_AvRevertMmThreadCharacteristics pfAvRevertMmThreadCharacteristics;
};
|