Skip to content

Commit

Permalink
Improve WASAPI Capturer
Browse files Browse the repository at this point in the history
  • Loading branch information
Jin Jae-yeon committed May 8, 2017
1 parent 2b7074a commit fed5003
Show file tree
Hide file tree
Showing 6 changed files with 328 additions and 77 deletions.
34 changes: 27 additions & 7 deletions DaramCam.Test/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ int main ( void )
hWnd = DCGetActiveWindowFromProcess ( process );*/

IStream * stream;
SHCreateStreamOnFileEx ( TEXT ( "Z:\\Test.png" ), STGM_READWRITE | STGM_CREATE, 0, false, 0, &stream );
/*SHCreateStreamOnFileEx ( TEXT ( "Z:\\Test.png" ), STGM_READWRITE | STGM_CREATE, 0, false, 0, &stream );
//DCGDIScreenCapturer * screenCapturer = new DCGDIScreenCapturer ( hWnd );
DCDXGIScreenCapturer * screenCapturer = new DCDXGIScreenCapturer ();
Expand All @@ -59,27 +59,47 @@ int main ( void )
SHCreateStreamOnFileEx ( TEXT ( "Z:\\Test.gif" ), STGM_READWRITE | STGM_CREATE, 0, false, 0, &stream );
DCVideoGenerator * vidGen = new DCWICVideoGenerator ( /*16*/33 );
DCVideoGenerator * vidGen = new DCWICVideoGenerator ( 16 );
vidGen->Begin ( stream, screenCapturer );
Sleep ( 10000 );
vidGen->End ();
stream->Release ();
delete vidGen;
delete screenCapturer;
delete screenCapturer;/**/

/*DCWASAPIAudioCapturer * audioCapturer = new DCWASAPIAudioCapturer ();
/**/
///// Audio Capture
std::vector<IMMDevice*> devices;
DCWASAPIAudioCapturer::GetMultimediaDevices ( devices );

SHCreateStreamOnFileEx ( TEXT ( "Z:\\Test.m4a" ), STGM_READWRITE | STGM_CREATE, 0, false, 0, &stream );
for ( int i = 0; i < devices.size (); ++i )
{
IPropertyStore * propStore;
devices [ i ]->OpenPropertyStore ( STGM_READ, &propStore );
PROPVARIANT pv;
propStore->GetValue ( { { 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0 }, 14 }, &pv );

printf ( "Device %d: %S\n", i, pv.bstrVal );
}
printf ( "> " );

int selected;
scanf ( "%d", &selected );

DCWASAPIAudioCapturer * audioCapturer = new DCWASAPIAudioCapturer ( devices [ selected ] );
DCWASAPIAudioCapturer::ReleaseMultimediaDevices ( devices );

SHCreateStreamOnFileEx ( TEXT ( "Z:\\Test.wav" ), STGM_READWRITE | STGM_CREATE, 0, false, 0, &stream );

DCAudioGenerator * audGen = new DCMFAudioGenerator ( DCMFAudioType_AAC );
DCAudioGenerator * audGen = new DCWaveAudioGenerator ();

audGen->Begin ( stream, audioCapturer );
Sleep ( 10000 );
audGen->End ();

delete audioCapturer;*/
delete audioCapturer;/**/

DCShutdown ();

Expand Down
70 changes: 58 additions & 12 deletions DaramCam/DaramCam.WASAPIAudioCapturer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ const IID IID_IMMDeviceEnumerator = __uuidof( IMMDeviceEnumerator );
const IID IID_IAudioClient = __uuidof( IAudioClient );
const IID IID_IAudioCaptureClient = __uuidof( IAudioCaptureClient );

DCWASAPIAudioCapturer::DCWASAPIAudioCapturer ()
DCWASAPIAudioCapturer::DCWASAPIAudioCapturer ( IMMDevice * pDevice )
: byteArray ( nullptr )
{
HRESULT hr = CoCreateInstance ( CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, ( void** ) &pEnumerator );

pEnumerator->GetDefaultAudioEndpoint ( eRender, eConsole, &pDevice );

pDevice->Activate ( IID_IAudioClient, CLSCTX_ALL, NULL, ( void** ) &pAudioClient );

pAudioClient->GetMixFormat ( &pwfx );
Expand Down Expand Up @@ -43,13 +39,13 @@ DCWASAPIAudioCapturer::DCWASAPIAudioCapturer ()
}

REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
pAudioClient->Initialize ( AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, hnsRequestedDuration, 0, pwfx, NULL );
pAudioClient->Initialize ( AUDCLNT_SHAREMODE_SHARED, GetStreamFlags (), hnsRequestedDuration, 0, pwfx, NULL );

REFERENCE_TIME hnsDefaultDevicePeriod;
pAudioClient->GetDevicePeriod ( &hnsDefaultDevicePeriod, NULL );
pAudioClient->GetBufferSize ( &bufferFrameCount );

hr = pAudioClient->GetService ( IID_IAudioCaptureClient, ( void** ) &pCaptureClient );
pAudioClient->GetService ( IID_IAudioCaptureClient, ( void** ) &pCaptureClient );

byteArray = new char [ byteArrayLength = 46000 * 128 ];

Expand Down Expand Up @@ -77,8 +73,6 @@ DCWASAPIAudioCapturer::~DCWASAPIAudioCapturer ()

pCaptureClient->Release ();
pAudioClient->Release ();
pDevice->Release ();
pEnumerator->Release ();
}

void DCWASAPIAudioCapturer::Begin ()
Expand All @@ -100,11 +94,11 @@ void * DCWASAPIAudioCapturer::GetAudioData ( unsigned * bufferLength )
UINT32 packetLength = 0;
DWORD totalLength = 0;

pCaptureClient->GetNextPacketSize ( &packetLength );
HRESULT hr;
hr = pCaptureClient->GetNextPacketSize ( &packetLength );

bool bFirstPacket = true;
HRESULT hr;
for ( hr = pCaptureClient->GetNextPacketSize ( &packetLength ); SUCCEEDED ( hr ) && packetLength > 0; hr = pCaptureClient->GetNextPacketSize ( &packetLength ) )
while ( SUCCEEDED ( hr ) && packetLength > 0 )
{
BYTE *pData;
UINT32 nNumFramesToRead;
Expand All @@ -127,10 +121,62 @@ void * DCWASAPIAudioCapturer::GetAudioData ( unsigned * bufferLength )
return nullptr;

bFirstPacket = false;

hr = pCaptureClient->GetNextPacketSize ( &packetLength );
}

DWORD dwWaitResult = WaitForMultipleObjects ( 1, &hWakeUp, FALSE, INFINITE );

*bufferLength = totalLength;
return byteArray;
}

DWORD DCWASAPIAudioCapturer::GetStreamFlags () { return 0; }

void DCWASAPIAudioCapturer::GetMultimediaDevices ( std::vector<IMMDevice*> & devices )
{
IMMDeviceEnumerator *pEnumerator;
IMMDeviceCollection * pCollection;

CoCreateInstance ( CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, ( void** ) &pEnumerator );
pEnumerator->EnumAudioEndpoints ( eCapture, DEVICE_STATE_ACTIVE, &pCollection );

UINT collectionCount;
pCollection->GetCount ( &collectionCount );
for ( UINT i = 0; i < collectionCount; ++i )
{
IMMDevice * pDevice;
pCollection->Item ( i, &pDevice );
devices.push_back ( pDevice );
}

pCollection->Release ();
pEnumerator->Release ();
}

void DCWASAPIAudioCapturer::ReleaseMultimediaDevices ( std::vector<IMMDevice*> & devices )
{
for ( auto i = devices.begin (); i != devices.end (); ++i )
( *i )->Release ();
devices.clear ();
}

IMMDevice * DCWASAPIAudioCapturer::GetDefaultMultimediaDevice ()
{
IMMDeviceEnumerator *pEnumerator;
IMMDevice * pDevice;

CoCreateInstance ( CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, ( void** ) &pEnumerator );
pEnumerator->GetDefaultAudioEndpoint ( eRender, eConsole, &pDevice );
pEnumerator->Release ();

return pDevice;
}

DCWASAPILoopbackAudioCapturer::DCWASAPILoopbackAudioCapturer ()
: DCWASAPIAudioCapturer ( DCWASAPIAudioCapturer::GetDefaultMultimediaDevice () )
{

}

DWORD DCWASAPILoopbackAudioCapturer::GetStreamFlags () { return AUDCLNT_STREAMFLAGS_LOOPBACK; }
93 changes: 93 additions & 0 deletions DaramCam/DaramCam.WaveAudioGenerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "DaramCam.h"

DCWaveAudioGenerator::DCWaveAudioGenerator ()
: stream ( nullptr ), capturer ( nullptr )
{
}


DWORD WINAPI WAVAG_Progress ( LPVOID vg )
{
DCWaveAudioGenerator * audioGen = ( DCWaveAudioGenerator* ) vg;

audioGen->capturer->Begin ();

HRESULT hr;

unsigned total = 0;
while ( audioGen->threadRunning )
{
unsigned bufferLength;
void * data = audioGen->capturer->GetAudioData ( &bufferLength );
if ( data == nullptr )
continue;
audioGen->stream->Write ( data, bufferLength, nullptr );
total += bufferLength;
}

audioGen->capturer->End ();

ULARGE_INTEGER temp;

LARGE_INTEGER riffSeeker = { 0, };
riffSeeker.QuadPart = 4;
hr = audioGen->stream->Seek ( riffSeeker, STREAM_SEEK_SET, &temp );
int totalFileSize = total + 44;
hr = audioGen->stream->Write ( &totalFileSize, 4, nullptr );

LARGE_INTEGER dataSeeker = { 0, };
dataSeeker.QuadPart = 40;
hr = audioGen->stream->Seek ( dataSeeker, STREAM_SEEK_SET, &temp );
hr = audioGen->stream->Write ( &total, 4, nullptr );

LARGE_INTEGER endPointSeeker = { 0, };
endPointSeeker.QuadPart = 0;
hr = audioGen->stream->Seek ( endPointSeeker, STREAM_SEEK_END, nullptr );

hr = audioGen->stream->Commit ( STGC_DEFAULT );

return 0;
}

void DCWaveAudioGenerator::Begin ( IStream * _stream, DCAudioCapturer * _capturer )
{
stream = _stream;
capturer = _capturer;

stream->Write ( "RIFF", 4, nullptr );
LARGE_INTEGER riffSeeker = { 0, };
riffSeeker.QuadPart = 4;
stream->Seek ( riffSeeker, STREAM_SEEK_CUR, nullptr );
stream->Write ( "WAVE", 4, nullptr );

int fmtSize = 16;
short audioType = WAVE_FORMAT_PCM;
short audioChannels = capturer->GetChannels ();
int sampleRate = capturer->GetSamplerate ();
short blockAlign = capturer->GetBitsPerSample () / 8;
short bitsPerSample = capturer->GetBitsPerSample ();
int byteRate = audioChannels * bitsPerSample * sampleRate / 8;

stream->Write ( "fmt ", 4, nullptr );
stream->Write ( &fmtSize, 4, nullptr );
stream->Write ( &audioType, 2, nullptr );
stream->Write ( &audioChannels, 2, nullptr );
stream->Write ( &sampleRate, 4, nullptr );
stream->Write ( &byteRate, 4, nullptr );
stream->Write ( &blockAlign, 2, nullptr );
stream->Write ( &bitsPerSample, 2, nullptr );

stream->Write ( "data", 4, nullptr );
LARGE_INTEGER dataSeeker = { 0, };
riffSeeker.QuadPart = 4;
stream->Seek ( dataSeeker, STREAM_SEEK_CUR, nullptr );

threadRunning = true;
threadHandle = CreateThread ( nullptr, 0, WAVAG_Progress, this, 0, 0 );
}

void DCWaveAudioGenerator::End ()
{
threadRunning = false;
WaitForSingleObject ( threadHandle, INFINITE );
}
Loading

0 comments on commit fed5003

Please sign in to comment.