Udostępnij za pośrednictwem


Draining the WASAPI capture buffer fully

This blog post has moved to https://matthewvaneerde.wordpress.com/2014/11/05/draining-the-wasapi-capture-buffer-fully/

Comments

  • Anonymous
    December 20, 2014
    The comment has been removed

  • Anonymous
    January 15, 2015
    when I stop playing why it still capture

  • Anonymous
    January 19, 2015
    in win7 after capture for few minits the flag was set to AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY do you have any solutions,I'm in china and my english is poor my email:8569504@qq.com thinks

  • Anonymous
    March 29, 2015
    Hi. Just wondering is this open source? I'm looking for something like this for my school project.

  • Anonymous
    March 30, 2015
    @Sunny do with the source as you like.

  • Anonymous
    July 31, 2015
    I failed to compile/build this example code. Could you please help to tell me how to build it? use what compiler/WDK? my error message is as below? path contains nonexistant c:userssamappdataroamingpythonscripts, removing BUILD: Compile and Link for x86 BUILD: Loading c:winddk7600.16385.1build.dat... BUILD: Computing Include file dependencies: BUILD: Start time: Sat Aug 01 16:24:47 2015 BUILD: Examining e:studytemploopback-capturesource directory for files to compile.    e:studytemploopback-capturesource Invalidating OACR warning log for 'root:x86chk' BUILD: Saving c:winddk7600.16385.1build.dat... BUILD: Compiling and Linking e:studytemploopback-capturesource directory Configuring OACR for 'root:x86chk' - <OACR on> Compiling - guid.cpp Compiling - main.cpp Compiling - loopback-capture.cpp 1>errors in directory e:studytemploopback-capturesource 1>e:studytemploopback-capturesourceloopback-capture.cpp(6) : error C1083: Cannot open include file: 'audioclie nt.h': No such file or directory Compiling - prefs.cpp Compiling - generating code... 1>NMAKE : fatal error U1073: don't know how to make 'C:WinDDK7600.16385.1libwin7i386avrt.lib' 1>nmake.exe /nologo BUILDMSG=Stop. -i /nologo /f c:winddk7600.16385.1binmakefile.def BUILD_PASS=PASS2 LINKONLY= 1 NOPASS0=1 MAKEDIR_RELATIVE_TO_BASEDIR= failed - rc = 2 BUILD: Finish time: Sat Aug 01 16:24:51 2015 BUILD: Done    6 files compiled - 1 Warning - 3 Errors - 1,114 LPS e:studytemploopback-capturesource>

  • Anonymous
    August 03, 2015
    > Cannot open include file: 'audioclient.h': No such file or directory audioclient.h ships as part of the SDK (not the WDK.)

  • Anonymous
    August 03, 2015
    Yes, I installed the MicroSoft SDK as below: c:Program Files (x86)Microsoft SDKsWindowsv7.1AIncludeAudioclient.h How can I build your example code? use Visual Studio? or WDK? If I use WDK, it will give me this error: C:temp4loopback-capturesource>build path contains nonexistant c:appsactivepython34, removing path contains nonexistant c:appsactivepython34scripts, removing path contains nonexistant c:appsanaconda3, removing path contains nonexistant c:appsanaconda3scripts, removing path contains nonexistant c:userscz1936appdataroamingpythonscripts, removing path contains nonexistant c:program files (x86)dbankclickup, removing path contains nonexistant c:klocworkinsight_10.1_command_linebin, removing BUILD: Compile and Link for x86 BUILD: Loading c:winddk7600.16385.1build.dat... BUILD: Computing Include file dependencies: BUILD: Start time: Tue Aug 04 13:07:00 2015 BUILD: Examining c:temp4loopback-capturesource directory for files to compile.    c:temp4loopback-capturesource Invalidating OACR warning log for 'root:x86chk' BUILD: Saving c:winddk7600.16385.1build.dat... BUILD: Compiling and Linking c:temp4loopback-capturesource directory Configuring OACR for 'root:x86chk' - <OACR on> Compiling - guid.cpp Compiling - main.cpp Compiling - loopback-capture.cpp 1>errors in directory c:temp4loopback-capturesource 1>c:temp4loopback-capturesourceloopback-capture.cpp(6) : error C1083: Cannot open include file: 'audioclient.h': No such file or directory Compiling - prefs.cpp Compiling - generating code... 1>NMAKE : fatal error U1073: don't know how to make 'C:WinDDK7600.16385.1libwin7i386avrt.lib' 1>nmake.exe /nologo BUILDMSG=Stop. -i /nologo /f c:winddk7600.16385.1binmakefile.def BUILD_PASS=PASS2 LINKONLY=1 NOPASS0=1 MAKEDIR_RELATIVE_TO_BASEDIR= failed - rc = 2 BUILD: Finish time: Tue Aug 04 13:07:14 2015 BUILD: Done    6 files compiled - 7 Warnings - 3 Errors - 1,114 LPS

  • Anonymous
    March 30, 2016
    Hi,I am trying to capture an audio stream like you do and as explained at https://msdn.microsoft.com/en-us/library/windows/desktop/dd370800%28v=vs.85%29.aspx, but I am facing some issues. As per https://msdn.microsoft.com/en-us/library/windows/desktop/dd370872%28v=vs.85%29.aspx, "When creating a shared-mode stream for an audio endpoint device, the Initialize method always accepts the stream format obtained from a GetMixFormat call on the same device", but I am observing a different behavior. When I call GetMixFormat, I get the format with following properties:Format tag: 0xfffe, channels: 0x0008, sampling rate: 0x0000bb80, bytes per sec: 0x000bb800, block align: 0x0010, bits per sample: 0x0010If I pass the same format to the Initialize call, it fails with the AUDCLNT_E_UNSUPPORTED_FORMAT error. I have noticed that although the GetMixFormat function returns 8 channels, the actual audio hardware supports only 4 channel audio. One more interesting observation is that this happens only when Nahimic software is enabled on the MSI notebook, and if that software is disabled/uninstalled, then GetMixFormat returns only 2 channels and Initialize call also succeeds with that format.I want my application to work even when Nahimic is enabled. If I send 2 channels (and update the block align and other fields accordingly) in the format call sent to Initialize, then it succeeds but I am unable to capture any audio. What should be the right way to capture audio when Nahimic is enabled?Thanks.

    • Anonymous
      May 12, 2016
      > Format tag: 0xfffeThis is WAVE_FORMAT_EXTENSIBLE. Can you cast the pointer to WAVEFORMATEXTENSIBLE* and log the rest of the members too?
  • Anonymous
    September 08, 2016
    Thank You Matthew!Dear Matthew,I just wanted to thank you so much for providing this sample code on github, I was able to compile on the first try.I wanted to give back to you in some way, and the community, so I hope my code offering here is seen as a very respective gift.I had to modify only a small amount of code in order to prevent two issues from occurring:1. The .exe ending prematurely when no sound is playing, which makes it the responsability of the calling code to know if there truly is active audio incoming or if the loopback-capture really should exit. 2. The occasional occurrence of the flag AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY or the flag AUDCLNT_BUFFERFLAGS_SILENT causing an early exit and without the wave file being fully created.Again with these small changes your awesome offering, Matthew, becomes industry-standard WASAPI loopback code immediately. It already is of course, but it becomes easy for new users to implement into their audio projects :)Please note I printed out the actual error names to make it easy for inexperienced developers to know what to look up on MSDN if they get one of these errors, rather than a numeric error code which is harder to understand (at least it was for me)~~~Very Slightly Modified Code So No Early Exit and no Exit on AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITYIn loopback-capture.cpphr = pAudioCaptureClient->GetBuffer( &pData, &nNumFramesToRead, &dwFlags, NULL, NULL );if (FAILED(hr)) { ERR(L"IAudioCaptureClient::GetBuffer failed on pass %u after %u frames: hr = 0x%08x", nPasses, *pnFrames, hr); if(hr == AUDCLNT_S_BUFFER_EMPTY) { ERR(L"GetBuffer Error is ~ AUDCLNT_S_BUFFER_EMPTY"); } else if(hr == AUDCLNT_E_BUFFER_ERROR) { ERR(L"GetBuffer Error is ~ AUDCLNT_E_BUFFER_ERROR"); } else if(hr == AUDCLNT_E_OUT_OF_ORDER) { ERR(L"GetBuffer Error is ~ AUDCLNT_E_OUT_OF_ORDER"); } else if(hr == AUDCLNT_E_DEVICE_INVALIDATED) { ERR(L"GetBuffer Error is ~ AUDCLNT_E_DEVICE_INVALIDATED"); } else if(hr == AUDCLNT_E_BUFFER_OPERATION_PENDING) { ERR(L"GetBuffer Error is ~ AUDCLNT_E_BUFFER_OPERATION_PENDING"); } else if(hr == AUDCLNT_E_SERVICE_NOT_RUNNING) { ERR(L"GetBuffer Error is ~ AUDCLNT_E_SERVICE_NOT_RUNNING"); } else if(hr == E_POINTER){ ERR(L"GetBuffer Error is ~ E_POINTER"); } return hr;}if (bFirstPacket && AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) { //LOG(L"%s", L"Probably spurious glitch reported on first packet");} else if (0 != dwFlags) { if(AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) { LOG(L"Flag Discontinuity"); } else if(AUDCLNT_BUFFERFLAGS_SILENT == dwFlags) { LOG(L"Flag Silent"); } else if(AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR == dwFlags) { LOG(L"Time Stamp Error"); } else { LOG(L"Audio not started yet (or unknown error), waiting for 0.01 seconds"); Sleep(10); } //LOG(L"IAudioCaptureClient::GetBuffer set flags to 0x%08x on pass %u after %u frames", dwFlags, nPasses, *pnFrames); //return E_UNEXPECTED; hr = pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead); if (FAILED(hr)) { ERR(L"IAudioCaptureClient::ReleaseBuffer failed on pass %u after %u frames: hr = 0x%08x", nPasses, *pnFrames, hr); return hr; } continue;}if (0 == nNumFramesToRead) {//.... rest of code as already perfectCode Modification Notes:Please note I still return an error if the buffer could not be released, which indicates a more fundamental problem than the more likely cases of silence or discontinuities which are unusual states that can be recovered from.I chose to continue rather than to pass through because Matthew's awesome code is expecting valid data at that point and I've intercepted a reason for which the pass through should not occur. Further Analysis and Improvement:One thing to note, I am actually dropping the discontinuous frame entirely, I am not sure if that is a good idea or not. I don't know if that actually helps "catch up" or simply is a loss of data or some combination of both, but in my tests it was inaudible whenever I got discontinuities, I got about 4 in one test with no auditory impact.Thank you again Matthew, and I hope my code offering is seen as helpful and does help people use your awesome handiwork to achieve their audio software dreams and goals♥Rama