1+ #include " CaptureLoop.h"
2+
3+ CaptureLoop::CaptureLoop (Config *pConfig, const AudioDevice *pRenderDevice, IAudioRenderClient *pRenderClient, IAudioCaptureClient *pCaptureClient, const std::vector<Input*> &inputs, const std::vector<Output*> &outputs) {
4+ _pConfig = pConfig;
5+ _pRenderDevice = pRenderDevice;
6+ _pRenderClient = pRenderClient;
7+ _pCaptureClient = pCaptureClient;
8+ _inputs = inputs;
9+ _outputs = outputs;
10+ _nChannelsIn = inputs.size ();
11+ _nChannelsOut = outputs.size ();
12+
13+ // Initialize clipping detection
14+ _pClippingChannels = new float [_nChannelsOut];
15+ memset (_pClippingChannels, 0 , _nChannelsOut * sizeof (float ));
16+
17+ // Initialize conditions
18+ _pUsedChannels = new time_t [_nChannelsIn];
19+ memset (_pUsedChannels, 0 , _nChannelsIn * sizeof (time_t ));
20+ Condition::init (_pUsedChannels);
21+ }
22+
23+ CaptureLoop::~CaptureLoop () {
24+ delete[] _pUsedChannels;
25+ delete[] _pClippingChannels;
26+ }
27+
28+ void CaptureLoop::capture () {
29+ UINT32 numFramesAvailable, i, j;
30+ HRESULT hr;
31+ DWORD flags;
32+ time_t now;
33+ float *pCaptureBuffer, *pRenderBuffer;
34+ size_t loopCounter = 0 ;
35+ size_t renderBlockSize = sizeof (float ) * _nChannelsOut;
36+
37+ // Run infinite capture loop
38+ while (true ) {
39+ // Check for samples in capture buffer
40+ hr = _pCaptureClient->GetNextPacketSize (&numFramesAvailable);
41+ assertHrResult (hr);
42+
43+ while (numFramesAvailable != 0 ) {
44+ // Get capture buffer pointer and number of available frames.
45+ hr = _pCaptureClient->GetBuffer ((BYTE**)&pCaptureBuffer, &numFramesAvailable, &flags, NULL , NULL );
46+ assertHrResult (hr);
47+
48+ // Must read entire capture buffer at once. Wait until render buffer has enough space available.
49+ while (numFramesAvailable > _pRenderDevice->getBufferFrameCountAvailable ()) {
50+ // Date::sleepMillis(1);
51+ }
52+
53+ // Get render buffer
54+ hr = _pRenderClient->GetBuffer (numFramesAvailable, (BYTE**)&pRenderBuffer);
55+ assertHrResult (hr);
56+
57+ // Set default value to 0 so we can add/mix values to it later
58+ memset (pRenderBuffer, 0 , numFramesAvailable * renderBlockSize);
59+
60+ // Get current timestamp to mark playing channels with
61+ now = Date::getCurrentTimeMillis ();
62+
63+ // Iterate all capture frames
64+ for (i = 0 ; i < numFramesAvailable; ++i) {
65+ for (j = 0 ; j < _nChannelsIn; ++j) {
66+ // Identify which channels are playing.
67+ if (pCaptureBuffer[j] != 0 ) {
68+ _pUsedChannels[j] = now;
69+ }
70+
71+ // Route sample to outputs
72+ _inputs[j]->route (pCaptureBuffer[j], pRenderBuffer);
73+ }
74+
75+ for (j = 0 ; j < _nChannelsOut; ++j) {
76+ // Apply output filters
77+ pRenderBuffer[j] = (float )_outputs[j]->process (pRenderBuffer[j]);
78+
79+ // Check for digital clipping
80+ if (abs (pRenderBuffer[j]) > 1.0 ) {
81+ _pClippingChannels[j] = max (_pClippingChannels[j], abs (pRenderBuffer[j]));
82+ }
83+ }
84+
85+ // Move buffers to next sample
86+ pCaptureBuffer += _nChannelsIn;
87+ pRenderBuffer += _nChannelsOut;
88+ }
89+
90+ // Release / flush buffers
91+ hr = _pCaptureClient->ReleaseBuffer (numFramesAvailable);
92+ assertHrResult (hr);
93+ hr = _pRenderClient->ReleaseBuffer (numFramesAvailable, 0 );
94+ assertHrResult (hr);
95+
96+ // Check for more samples in capture buffer
97+ hr = _pCaptureClient->GetNextPacketSize (&numFramesAvailable);
98+ assertHrResult (hr);
99+ }
100+
101+ if (loopCounter == 1000 ) {
102+ loopCounter = 0 ;
103+ // Check if config file has changed
104+ checkConfig ();
105+ // Check for unused channels
106+ checkUsedChannels ();
107+ // Check for clipping out channels
108+ checkClippingChannels ();
109+ }
110+ ++loopCounter;
111+
112+ // Short sleep just to not busy wait all resources.
113+ Date::sleepMillis (1 );
114+ }
115+ }
0 commit comments