Sample – WASAPI loopback capture (record what you hear)


In a previous post I showed how to play silence to a given audio device and hinted at a possible application.

Attached to this post is a sample WASAPI loopback capture app – amd64, x86 and source included.  This allows you to record the sound that is coming out of your speakers:

>loopback-capture -?
loopback-capture -?
loopback-capture –list-devices
loopback-capture [–device “Device long name”] [–file “file name”] [–int-16]

    -? prints this message.
    –list-devices displays the long names of all active playback devices.
    –device captures from the specified device (default if omitted)
    –file saves the output to a file (loopback-capture.wav if omitted))
    –int-16 attempts to coerce data to 16-bit integer format

There are a couple of oddities for WASAPI loopback capture.  One is that “event mode” doesn’t work for loopback capture; you can call pAudioClient->Initialize(… AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK, … ), you can call pAudioClient->SetEventHandle(…), and everything will succeed… but the “data is ready” event will never fire.  So this app creates its own waitable timer.

Another oddity is that WASAPI will only push data down to the render endpoint when there are active streams.  When nothing is playing, there is nothing to capture.

For example, play a song, and then run loopback-capture.  While loopback-capture is running, stop the song, and then start it again.  You’ll get this output when you start it back up:

>loopback-capture
Press Enter to quit…
IAudioCaptureClient::GetBuffer set flags to 0x00000001 on pass 5381 after 1088829 frames

Thread HRESULT is 0x8000ffff

The flag in question is AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY.  When the song stopped, no more data was available to capture.  Eventually the song started up again, and WASAPI dutifully reported that there was a glitch detected.  This app stops on glitches.

There are a couple of other possible ways to handle this.  One way is to ignore glitches; then if you stop a song, wait a few seconds, and start it again, then the recorded signal will omit the wait and abut the two “audio is playing” portions.

But my particular favorite way of handling this is to run silence.exe.  That way there are never any “nothing is playing” glitches, because there’s always something playing.

EDIT 11/23/2009: Updated loopback-capture.exe to ignore the glitch flag on the first packet, since Windows 7 sets it.  Also improved the interaction between the capture thread bailing out and the user pressing Enter to finish.

EDIT 11/5/2014: Go read this new post which has updated source and binaries, as well as links to better samples.

Comments (107)

  1. Jay says:

    Hello Matt!

    Excellent blog!

    Would you happen to know whether it’s possible to record audio from a specific application using the loopback technique?

    Thanks,

    Jay

  2. Not directly… loopback capture is the aggregate of all shared-mode streams to the device in question, post-mix.

    This also won’t work for applications that play in exclusive mode.

  3. Scott Rudy says:

    I have been looking for something similar to what Jay mentions as well. I would like to capture the audio stream for a single application to a file stream. So if loopback capture isn’t the right answer, is there one?

  4. I will provide your feedback to the audio team.

  5. Sudarsun says:

    Thanks very much for the post.. I was desperately looking for this idea for my pet project. Thanks again.

  6. ryan says:

    Thanks for this.  One of my systems (a Dell e521) is a model that has no ability to record stereo mix.  Why I think stereo mix should’ve been included, and am at a loss as to why Dell or MS would remove it, this is a decent workaround.

  7. Fredrik says:

    First of all, thanks for an interesting post!

    I’m trying to port the code to C# but have run into some trouble. Everything is up and running except the inner capturing loop. When I call iAudioCaptureClient.GetNextPacketSize it throws an AUDCLNT_E_OUT_OF_ORDER at me.

    If I skip that and call iAudioCaptureClient.GetBuffer it actually returns a couple of frames (around 400) and that data seems good. But when I call ReleaseBuffer I get an AccessViolationException and the next call to GetBuffer will now also return an AUDCLNT_E_OUT_OF_ORDER error.

    Any idea what I could be doing wrong?

  8. It sounds like your C# iAudioCaptureClient methods aren’t mapping to the IAudioCaptureClient methods correctly.; that is, the method you think you’re calling is not the method you’re actually calling.

    AUDCLNT_E_OUT_OF_ORDER is expected if you call ReleaseBuffer() without calling GetBuffer() first, or if you call GetBuffer() twice in a row without a ReleaseBuffer() in between.

    The Access Violation is harder to explain.

    Can you post (or email me) the DllImport code you’re using to define the iAudioCaptureClient methods?

  9. Baskaran B says:

    I have looked into the attachments and had the loopback-capture.exe file. How should i use the exe file to record what i hear from my system speakers? can any one help me please?

    Thnks

    Baskaran B

  10. What have you tried, and what happened when you tried it?  Note that depending on your audio hardware and drivers there are likely other ways to record what comes from your speakers: e.g., using the analog mixer.

  11. BongShin CHOI says:

    Thank you very much, Matthew!

    It’s awesome!

    I really want to on like this.

    Again thank you!

    BongShin.

  12. vinod kumar s says:

    How we can make it  the loop back capture usefull for AEC, in the sense I need to record what are the samples rendering to play back device as well as the sound capturing from microphone. If it is possible in vista could i do it in XP also?. Plz reply me…….

  13. Jansson says:

    I’d love to see a .NET port of this, too bad my C++ skills are too bad to wrap my head around this.

  14. Dan says:

    Thanks for sharing — this is great.  Will the AUDCLNT_STREAMFLAGS_EVENTCALLBACK and "data is ready" event be support for LOOPBACK in Win7?  i.e., was this a bug that will be fixed in Win7?

    Thanks again,

    Dan

  15. No, this is a design decision.  I’m lobbying for IAudioClient::Initialize(… _EVENTCALLBACK | _LOOPBACK, …) to return an error code, but that won’t happen for Win7 either.

  16. CD says:

    Maurits,

    Would you be willing to port this code to C# (or even create a DLL which I could include in a C# project)? I am willing to pay you for your time.

    CD

  17. There does seem to be a high demand for a C# WASAPI app.  For example, see this thread:

    http://social.msdn.microsoft.com/Forums/en-US/windowspro-audiodevelopment/thread/55802cf0-15dc-49ff-bc22-d0b6cb60d9d5?prof=required

    I have a little too much on my plate to take on outside projects, but thank you for the offer.

  18. Aaron Urbanski says:

    Are there any plans to make this compatible with Windows 7?

  19. Done.  The change was to create a boolean variable "bFirstPacket", initialized to true, and add this line after verifying that IAudioCaptureClient::GetBuffer(…) succeeded:

           if (bFirstPacket && AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {

               printf("Probably spurious glitch reported on first packetn");

           } else if (0 != dwFlags) {

  20. Aaron Urbanski says:

    Oh my gosh, thanks so much! This is going to be invaluable, I really appreciate it!

  21. Fernickk says:

    Hi, I can’t make it work as I lack AVRT.dll. Is this supposed to work only on Vista? What should I install to get the Dll? Weird thing the MSVC came with AVRT.lib, but not the dll…

  22. Yes, this requires Windows Vista or later.

  23. johny why says:

    is there a way to capture at rates other than 16 bits, 44.1 Khz?

    can i capture at 24 bit, 96 Khz?

    thanks

  24. johny why says:

    hi matthew,

    is there a way to stop the glitch behavior? i want to record all audio on my computer without a break, from various applications/devices, non-stop.  

    i’m a teacher, and i need this to document my audio classes.

    can you provide a version with the glitch-stop feature? this would be supremely helpful.

    thanks

  25. johny why says:

    to clarify, on my pc, your app closes when i open or close an audio-producing software. on my friend’s pc, your app does NOT close when i open or close an audio-producing software. so different pc’s may or may not create "glitches".

    my need is to open and close audio software repeatedly, without causing your recording to stop.

    thanks

  26. Edward says:

    Hi Maurits,

    Thanks for providing this good example. :)

    There is a question would like to consult with you.

    loopback-capture will capture audio with default sample rate. (my default setting is 16bit, 44100Hz)

    Is it possible to capture audio with different sample rate (such as 16bit, 48000Hz)?

    Thanks you very much. :)

    Edward

  27. Loopback capture uses the render endpoint's "mix" format (or trivial conversions thereof, such as float-to-int.)

    Converting sample rate from 44100 to 48000 is a non-trivial operation so loopback capture won't perform it.  If the render endpoint supports 48000 you could change the "mix" format.  To do so using the Sound control panel, double-click on the default playback device, go to the Advanced tab, and see if there's a suitable 48 kHz format listed in the "default format" section.

  28. Negative says:

    nAudio has a good C# example.  

    I had the exact same issue with the OUT_OF_ORDER exception on GetNextPacketSize() and it turned out that I had the wrong order of methods in my IAudioCaptureClient interface.  I definitely did not know that it mattered…

  29. thanks says:

    Thanks for the code!

    For me, for whatever reason, silence yields (within a few seconds)

    >silence

    Press Enter to quit…

    Got "feed me" event but IAudioClient::GetCurrentPadding reports buffer is full – glitch?

    The thread terminated early – something bad happened

    Thread HRESULT is 0x8000ffff

    as also loopback always (even with sound going, after a few seconds):

    loopback-capture.exe

    Press Enter to quit…

    Probably spurious glitch reported on first packet

    IAudioCaptureClient::GetBuffer set flags to 0x00000001 on pass 102 after 22400 frames

    The thread terminated early – something bad happened

    Thread HRESULT is 0x8000ffff

    perhaps it's not windows 7 friendly yet?

    Thanks.

    -r

  30. > Got "feed me" event but IAudioClient::GetCurrentPadding reports buffer is full – glitch?

    > IAudioCaptureClient::GetBuffer set flags to 0x00000001 on pass 102 after 22400 frames

    Both of these point to glitches.  Under normal circumstances, glitches shouldn't happen; they point to a problem with the system.

    Can you follow the instructions in this forum thread

    social.msdn.microsoft.com/…/1A796E5C-E808-42C0-96CD-84CEBFAF71D5

    and send me the .etl file? mateer at microsoft dot com

  31. TV says:

    Hi, I tried to compile the code, I'm using code block 10.05 and gcc that comes with code block. I got a long list of errors that start with

    C:Program Files (x86)Microsoft SDKsWindowsv7.0AIncludespecstrings.h|11|error: sal.h: No such file or directory|

    C:Program Files (x86)Microsoft SDKsWindowsv7.0AIncludewinnt.h|851|error: #error Must define a target architecture.|

    C:Program Files (x86)Microsoft SDKsWindowsv7.0AIncludewinnt.h|1202|error: pasting "(" and "__drv_nop" does not give a valid preprocessing token|

    C:Program Files (x86)Microsoft SDKsWindowsv7.0AIncludewinnt.h|12880|error: pasting "(" and "__drv_nop" does not give a valid preprocessing token|

    C:Program Files (x86)Microsoft SDKsWindowsv7.0AIncludewinnt.h|13305|error: pasting "(" and "__drv_nop" does not give a valid preprocessing token|

    C:Program Files (x86)Microsoft SDKsWindowsv7.0AIncludewinbase.h|2936|error: pasting "(" and "__drv_nop" does not give a valid preprocessing token|

    …………………..

    I was wondering how to fix this? Do I have to use vc compiler ?

    Thanks.

    TV

  32. felixz says:

    I have recorded audio from a specific application successfully, I hooked IAudioRenderClinet and copy out audio data from the buffer, it works well with Windows Media Player/Media Center and some other popular media player in China.

  33. Meg says:

    Hi, I'm not very computer-savvy, so all this coding means NOTHING to me ^^; could you explain it so people without much coding experience etc, know how it works?

  34. That's a fair question.  The general idea is, you want to be able to record the sound your computer is playing.

    One "simple" way to do this is to:

    1. go buy an audio cable

    2. plug one end in to your computer's "line out" jack

    3. plug the other end into the "line in" or "microphone"

    4. mess with the volume controls in the Sound control panel to make sure the audio is loud enough (to rise above the noise) but not too loud (so it doesn't clip)

    5. run Sound Recorder or a third-party recording application

    This way works, but it has issues.  (You have to buy an audio cable; you can't listen to what you're recording while you're recording it.)

    To make this easier, many audio sound card vendors came up an "analog mixer" solution.  This shows up as a "fake line in" called "Stereo Mix" or "Wave Out" or "What You Hear" (or various other things.)  Basically, any audio that Windows sent to the sound card is split (inside the sound card) and sent to BOTH the actual speakers you had plugged in and this "fake line in."

    Most of the time, nothing is listening to the fake line in, so that copy of the audio just gets dropped on the floor.  But if you like, you can set the default recording device to "Stereo Mix" instead of the real "Line In" and use Sound Recorder or what-have-you to record what was coming out of your speakers, rather than what was going in to your line in.

    This way of doing things adds cost to the sound card vendors – they have to put a splitter in their hardware and their driver has to expose Stereo Mix to the OS.

    So in Vista we came up with a way of doing it entirely in software.  An app that knows the new Vista audio application programming interface (WASAPI), and wants a copy of the audio that's going to the speakers, can now get it from Windows directly.  Basically, the splitter has been moved from the driver into Windows itself.  (The old way of doing things still works too.)

    The sample app attached to this blog post can be run from the command line to take a copy of whatever's playing at the moment and save it to a .wav file that you can play back later.  I intended it as an aid to developers who write applications that want to use this new way of capturing the audio that is going to the speakers.

  35. mocdiv says:

    Hi,

    this example is what i'm looking for but it has one bad issue

    "IAudioCaptureClient::GetBuffer set flags to 0x00000002 on pass 4896 after 730560 frames

    The thread terminated early – something bad happened

    Thread HRESULT is 0x8000ffff"

    and program exit.

    This happen when I test system sound like ding.wav from control panel. Is this possible to work around this?

    Regards

  36. 2 is AUDCLNT_BUFFERFLAGS_SILENT.  This is provided as a convenience for IAudioRenderClient apps who want to mark a buffer as silence without actually having to fill the buffer with silence.

    I'm a little surprised to see it being set on a capture buffer.  The audio engine should always fill the buffer with silence.  When you hit this, is the last buffer you get actually filled with silence (for the format you're using?)

  37. mocdiv says:

    Hi,

    I tested it on 2 OS.

    Vista 64 Business:

    1. if after I start loopback-capture.exe first sound is ding.wav i get exception with flags 2

    2. when loopback-capture is running and i play music I can make ding.wav without error, when i stoped music and then make ding it crashes with

    flags 2.

    Windows 7:

    Difference is i always get "Probably spurious glitch reported on first packet when some sound is played" on start of capturing, i never get this on Vista.

    Error occurs always when i play music -> stop music -> and play again i get error

    Probably spurious glitch reported on first packet

    IAudioCaptureClient::GetBuffer set flags to 0x00000001 on pass 1260 after 35040

    frames

    The thread terminated early – something bad happened

    Thread HRESULT is 0x8000ffff

    this is caused by my settings on speaker i have 24 bit and 48000hz. After change it to 16 bit and 44100hz i can play – stop – play without error but ding creates error.

    After program crash i can't open the wav file with sounds which appear to that time because file is corrupted.

  38. Arnold says:

    Hi,Maurits, I run your source code successfully, but I have a question, I want to capture what I hear, and then send the data to a client such as mobile phone, but there is a latency about 1-2 seconds, how can I solve this problem, is there any way to reduce the buffer size or get the audio data directly?

    thanks!

  39. The latency between the playback app and the loopback capture app has a lower bound of the audio engine period, which is queried in the code and is typically 10 ms.

    You mentioned a latency of 1-2 seconds.  How much of this is between the playback app and the loopback capture app, and how much is between the loopback capture app and the phone?

  40. Arnold says:

    The audio engine period is 10ms, the latency of the wifi network between mobile phone and loopback app is about 200ms.

  41. Arnold says:

    And I guess maybe the latency is from the player of the mobile phone. I used player in Android OS, maybe the player produce the latency.

  42. roger says:

    For those interested, I've bundled this up into a directshow audio capture device, which works well for me as an alternative to say virtual audio cable. github.com/…/virtual-audio-capture-grabber-device

    Enjoy, and thanks to Matthew for the initial codebase.

  43. Parag Shravagi says:

    Hi,

    This sample only works on Windows vista or later. Can somebody please help me in achieveing the same on Windows 2000 or Windows XP?

    Thanks in advance

  44. Atlas Lee says:

    Hello.

    I've searched this kind of solution to capture sound in windows.

    But I am faced on one thing.

    It's about "samplepersec".

    When I use GetMixFormat… it has 48000 for sampling rate.

    But I want to change it to 44100.

    I've found one thing about that.

    It's AUDCLNT_STREAMFLAGS_RATEADJUST. But available on win7 only.

    Not on VISTA…

    Do you think there is any other solution for it?

  45. WASAPI will generally not do sample rate conversions.  IAudioClockAdjustment is meant for a scenario where:

    * you're pulling audio from a real-time source

    * you're handing it off to a real-time sink

    * the sample rates of the source and sink nominally agree

    * but they're using slightly different clocks so they're a little bit off

    For example, if the source is a S/PDIF in, then the clock for the source is driven by the incoming data.

    So if the source and sink are both nominally 44100, but the source is really more like 44100.4, then IAudioClockAdjustment can adjust for that.

    To do a macro sample rate conversion, you would need to use a different API like Media Foundation, which has a sample rate conversion transform.

    msdn.microsoft.com/…/ff819070(v=vs.85).aspx

  46. vsibilla says:

    Hi Mauritis,

    I want to enable "Record what youe hear" on Windows 7 with WASAPI on C++, but I didn't find solution, can you help me?

    thanks

    vsibilla

  47. xpclient says:

    The sample isn't working again with Windows 8 Developer Preview.

  48. xpclient says:

    It worked for me on Windows 7 RTM 32-bit. Now on Windows 7 SP1 x64, I get:

    IAudioCaptureClient::GetBuffer set flags to 0x00000003 on pass 510 after 0 frame

    s

    The thread terminated early – something bad happened

    Thread HRESULT is 0x8000ffff

    The moment any sound plays I get this error. Until then, it "captures".

  49. Mark Heath says:

    Thanks for this post. It is very annoying for me that WASAPI doesn't capture continuously even if nothing is playing as I plan to also capture the microphone input at the same time and mix the two streams together. I guess I'll have to play silence as well (is silence.exe a well-known app – I couldn't find it).

    It would be nice to have a continuous capture flag for loopback. Also, as you say, it would be good to support Event callback. WASAPI unfortunately feels like a half-finished audio API, with the lack of built-in SRC also a major inconvenience.

  50. Mike says:

    For some reason I get an error when I try run it no matter what options I use:

    Press Enter to quit…

    IAudioCaptureClient::GetBuffer set flags to 0x00000003 on pass 1 after 0 frames

    The thread terminated early – something bad happened

    Thread HRESULT is 0x8000ffff

    Any ideas?

  51. @Mike

    3 is AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY | AUDCLNT_BUFFERFLAGS_SILENT.  What OS are you running on?

    Is the buffer you're getting actually full of silence?  You'll need to modify the code to actually write the buffer to disk, or you can look at the buffer in memory under a debugger if you set a breakpoint at the point of failure.

    It's fine for WASAPI to set the AUDCLNT_BUFFERFLAGS_SILENT flag, but it should also put actual silence in the buffer.

  52. Hi Maurits,

    Am I able to modify output sound by process *pData in pAudioCaptureClient->GetBuffer()

    I like to port your loopback-capture to a windows sound EQ effect program using WASAPI. If not possible do you have suggestions?

    Thanks

    ponglee

  53. Modifying the samples you get from the loopback capture interface will not affect what goes out of the speakers.  If you want to apply an effect to the sound produced by all applications you can write a SysFX Audio Processing Object, which will install with the audio driver.

  54. baryon81 says:

    Hi Mauritis,

    I'm trying to capture the audio output with the WASAPI loopback capture mode, without the audio output of my application.

    Do you know of a way to register an audio stream that will not get captured by WASAPI in loopback mode. Something like the exclusive mode of an audio-client but without blocking all other applications from using the same endpoint device.

  55. One thing you could do is install a Virtual Audio Cable-like solution.

    Create a virtual render endpoint and set that as a default.  Create a virtual cable going from this endpoint to the physical speakers, so all audio can be heard.

    Have your application play directly to the physical speakers.

    Do loopback capture from the virtual endpoint.

  56. Mark Schall says:

    When I am using the WASAPI Loopback, I noticed that it will still record all the audio if I mute my speakers.  Is there a way to easily sync up the main volume control with that of my capture client?

  57. You can call IAudioEndpointVolume::RegisterControlChangeNotify to be notified when the volume or mute status is changed.

  58. Thank you for providing this example. I've noticed that when I build the code (mvc++ 2010 express, Windows SDK 7.1), my hdd is typically not fast enough to keep up with the audio stream so it cuts out after 30-50 seconds (AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY), yet with your provided binaries, it is more than fast enough. If I comment out the disk write, it never reports glitching. When I've had similar issues in linux, it's been because my read and write have been in the same thread, which I solved first by increasing the audio device buffer which decreased the effect of hd latency by writing bigger blocks, and subsequently by splitting read and write threads and swapping a shared buffer between them.

    It seems like I should get a similar increased buffer effect by passing a larger number to IAudioClient::Initialize argument #3 hnsBufferDuration, say for example 25000, but that does not seem to have had any effect. I'm wondering if you had any thoughts on the matter.

  59. The version of this that we use for testing ran into the disk-slows-you-down-too-much problem too.  I fixed that by creating a work queue with a single thread, and sending the "write the data to a file" part to that thread instead of blocking the capture thread in mmioWrite.

  60. Scott says:

    Mauritis have you tried this on Windows 8 yet?  I can't get it to work (nor my own code), your app bombs out on a discontinuity glitch every time.

    Any guidance to get WASAPI capture running on Win8 would be swell. :)

  61. roger says:

    Do you know if it's possible to capture audio output from "just a single application" using any sort of loopback capture?  I know windows 7's audio mixer can control the volume of single applications, can it possibly also capture audio from single applications?

  62. @roger Windows does not provide such a feature, but if the app can be configured to play to a non-default device it's possible to jury-rig this using third-party tools like Virtual Audio Cable.

  63. Demolishun says:

    Hey Maurits, I started looking into the ability to read the currently playing audio stream because I wanted to get a vue meter of sorts my media currently being played on my machine.  Then I thought I could take it a step further.  I am going to read the stream and do some quick FFT or some other math to get a frequency graph.  Then I can feed that into a game engine real time.  The game engine will alter the experience based upon the music being played by ANY source.  So if someone wanted to play some preferred music while playing the game the game would add to the experience by altering the visuals to match the music.  I think this feature could make for some truly unique gaming experiences for end users.  Thanks for the code!

  64. Hi Maurits,

    Is there a way to change the buffer size I get?

    I'd like to get, for example, 1024 or 2048 number of samples once buffer was ready.

    Can it possible?

    thank,

    howard

  65. I have the same problem as:

    Fredrik Thu, Apr 16 2009 9:49 PM

    ===

    Everything is up and running except the inner capturing loop. When I call iAudioCaptureClient.GetNextPacketSize it throws an AUDCLNT_E_OUT_OF_ORDER at me.

    If I skip that and call iAudioCaptureClient.GetBuffer it actually returns a couple of frames (around 400) and that data seems good. But when I call ReleaseBuffer I get an AccessViolationException …

    ======

    So I can't find Frederik email. May be you can your help me?

    Thank in advance!

  66. Your wrapper is wrong. Make sure to declare the members in the interface in the same order that audioclient.idl has them listed, not in the order they're listed on MSDN.

  67. Many Thanks! You are right, it was error in the Interface declataion.

  68. I created a  win32 app in VC++ 2008,

    I got this error when building it:

    1>—— Build started: Project: winSoundDetect, Configuration: Debug Win32 ——

    1>Compiling…

    1>guid.cpp

    1>loopback-capture.cpp

    1>main.cpp

    1>prefs.cpp

    1>Generating Code…

    1>Linking…

    1>loopback-capture.obj : error LNK2019: unresolved external symbol __imp__mmioWrite@12 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>main.obj : error LNK2001: unresolved external symbol __imp__mmioWrite@12

    1>loopback-capture.obj : error LNK2019: unresolved external symbol _AvRevertMmThreadCharacteristics@4 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>loopback-capture.obj : error LNK2019: unresolved external symbol _AvSetMmThreadCharacteristicsW@8 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>loopback-capture.obj : error LNK2019: unresolved external symbol __imp__mmioAscend@12 referenced in function "long __cdecl WriteWaveHeader(struct HMMIO__ *,struct tWAVEFORMATEX const *,struct _MMCKINFO *,struct _MMCKINFO *)" (?WriteWaveHeader@@YAJPAUHMMIO__@@PBUtWAVEFORMATEX@@PAU_MMCKINFO@@2@Z)

    1>main.obj : error LNK2001: unresolved external symbol __imp__mmioAscend@12

    1>loopback-capture.obj : error LNK2019: unresolved external symbol __imp__mmioCreateChunk@12 referenced in function "long __cdecl WriteWaveHeader(struct HMMIO__ *,struct tWAVEFORMATEX const *,struct _MMCKINFO *,struct _MMCKINFO *)" (?WriteWaveHeader@@YAJPAUHMMIO__@@PBUtWAVEFORMATEX@@PAU_MMCKINFO@@2@Z)

    1>main.obj : error LNK2019: unresolved external symbol __imp__mmioDescend@16 referenced in function "int __cdecl do_everything(int,wchar_t const * * const)" (?do_everything@@YAHHQAPB_W@Z)

    1>main.obj : error LNK2019: unresolved external symbol __imp__mmioOpenW@12 referenced in function "int __cdecl do_everything(int,wchar_t const * * const)" (?do_everything@@YAHHQAPB_W@Z)

    1>prefs.obj : error LNK2001: unresolved external symbol __imp__mmioOpenW@12

    1>main.obj : error LNK2019: unresolved external symbol __imp__mmioClose@8 referenced in function "int __cdecl do_everything(int,wchar_t const * * const)" (?do_everything@@YAHHQAPB_W@Z)

    1>prefs.obj : error LNK2001: unresolved external symbol __imp__mmioClose@8

  69. looks like the 'sources' file is not recognized by VC 2008, can someone kindly give a  solution?

  70. > unresolved external symbol __imp__mmioWrite

    See the documentation for mmioWrite:

    msdn.microsoft.com/…/dd757341(v=vs.85).aspx

    "Library: Winmm.lib"

    Note that you need to link against winmm.lib; add that to your VC++ project.

  71. I did try adding libs into the VC project, by folliwng stackoverflow.com/…/how-do-i-add-a-lib-file-to-link-in-visual-c-2010

    but still got :

    1>—— Build started: Project: winSoundDetector, Configuration: Debug Win32 ——

    1>Linking…

    1>prefs.obj : error LNK2019: unresolved external symbol __imp__CoTaskMemFree@4 referenced in function "public: __thiscall CPrefs::~CPrefs(void)" (??1CPrefs@@QAE@XZ)

    1>loopback-capture.obj : error LNK2001: unresolved external symbol __imp__CoTaskMemFree@4

    …..

    I was wondering how did you compile and build? I guess some IDE or tool that will honor 'sources' file instead of manually adding the dependency libraries?

  72. > unresolved external symbol __imp__CoTaskMemFree

    Read my previous comment very carefully and see if you can figure out what you need to do to make this error go away :-)

  73. I tried to add avrt.lib, ole32.lib and winmm.lib into the project's linker input settings as the stackoverflow.com/…/how-do-i-add-a-lib-file-to-link-in-visual-c-2010 instructed,

    I also did:

    #pragma comment(lib,"avrt.lib")

    #pragma comment(lib,"Ole32.lib")

    #pragma comment(lib,"winmm.lib")

    still no luck. looks like the libs are still not seen.

  74. I think now I got a clean build by following:

    1. looks like I need the lib Not from x64 even tho I am on win7 64bit  machine,

    2. copy all the needed libs into the folder together with the cpp/h, add them in to the project through "add/existing item…"

    3. stackoverflow.com/…/error-lnk2019-unresolved-external-symbol-winmain16-referenced-in-function

    Thats a linker problem.

    Try to change Properties -> Linker -> System -> SubSystem

    from Windows (/SUBSYSTEM:WINDOWS) to Console (/SUBSYSTEM:CONSOLE)

    Thanks Maurits for providing this sample and bearing with me! :-)

  75. You should be able to add winmm.lib;avrt.lib;ole32.lib in your "Additional Dependencies" field under the linker options in your C++ project file; Visual Studio will then know whether to link x86 or x64.

    Even though your dev machine is x64, your solution is probably set to target x86; an x86 app will generally run on both x86 and x64 machines. You can change this to explicitly target x64 if you want.

  76. Corey says:

    Hi Maurits,

    I have had good success with the app until trying it on Windows 8.

    Currently I get the following output

    >loopback.exe –file test.wav

    Press Enter to quit…

    Probably spurious glitch reported on first packet

    IAudioCaptureClient::GetBuffer set flags to 0x00000001 on pass 1166 after 279360 frames

    The thread terminated early – something bad happened

    Thread HRESULT is 0x8000ffff

    This error will happen in the following conditions:

    1) I run app during silence.. and then begin to play audio.  The app will immediately crash in this case. (This was reported earlier in comment thread as well)

    2) If I am already playing sound and then start the app.. I will get about 5 seconds worth of record before.. then the same error occurs.  This will leave the audio file in a corrupted and unplayable state.

    3) If I am already playing sound and then stat the app… i then press enter to close the app (in under 5s) .. I will get a playable audio file as expected.

    Any guidance on this would be greatly appreciated.

    Thanks.

  77. Corey says:

    Update: (Windows 8 workaround)

    By simply choosing to ignore the AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY flag.. rather then error… everything seems to work fine.

    Although I am not sure if there will be implications to this on a large enough time domain.

  78. Corey Auger says:

    I have created a directshow filter that generates silence and works with win 7/8

    My work can be found here: github.com/…/AudioLoopbackFilter

  79. AmirH says:

    Hi,

    first of all sorry for my english.

    I'm trying to develop a free software that reconise the sound played by speakers (the software would run in the background, in the "notification area" of windows) and displays the music played on a label closed to the so-called "notification area" (the message should be discrete).

    My idea is to use loopback-capture derivated background program to record 25 seconds of the sound played, use a background program to convert wav->mp3 and then use lastfmfpclient product (also works in the background) to search for the artist and title of the music played.

    So first of all, I want to modify loopback-capture sources to capture 25 seconds of what is played without any prompt windows (again, in the background) but I can't compile loopback-capture sources with visual C++ 2012,

  80. AmirH says:

    here are the lines of errors :

    —————

    1>—— Build started: Project: loopback-capture, Configuration: Debug Win32 ——

    1>loopback-capture.obj : error LNK2019: unresolved external symbol __imp__mmioWrite@12 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>main.obj : error LNK2001: unresolved external symbol __imp__mmioWrite@12

    1>loopback-capture.obj : error LNK2019: unresolved external symbol __imp__mmioAscend@12 referenced in function "long __cdecl FinishWaveFile(struct HMMIO__ *,struct _MMCKINFO *,struct _MMCKINFO *)" (?FinishWaveFile@@YAJPAUHMMIO__@@PAU_MMCKINFO@@1@Z)

    1>main.obj : error LNK2001: unresolved external symbol __imp__mmioAscend@12

    1>loopback-capture.obj : error LNK2019: unresolved external symbol __imp__mmioCreateChunk@12 referenced in function "long __cdecl WriteWaveHeader(struct HMMIO__ *,struct tWAVEFORMATEX const *,struct _MMCKINFO *,struct _MMCKINFO *)" (?WriteWaveHeader@@YAJPAUHMMIO__@@PBUtWAVEFORMATEX@@PAU_MMCKINFO@@2@Z)

    1>loopback-capture.obj : error LNK2019: unresolved external symbol _AvSetMmThreadCharacteristicsW@8 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>loopback-capture.obj : error LNK2019: unresolved external symbol _AvRevertMmThreadCharacteristics@4 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>main.obj : error LNK2019: unresolved external symbol __imp__mmioOpenW@12 referenced in function "int __cdecl do_everything(int,wchar_t const * * const)" (?do_everything@@YAHHQAPB_W@Z)

    1>prefs.obj : error LNK2001: unresolved external symbol __imp__mmioOpenW@12

    1>main.obj : error LNK2019: unresolved external symbol __imp__mmioClose@8 referenced in function "int __cdecl do_everything(int,wchar_t const * * const)" (?do_everything@@YAHHQAPB_W@Z)

    1>prefs.obj : error LNK2001: unresolved external symbol __imp__mmioClose@8

    1>main.obj : error LNK2019: unresolved external symbol __imp__mmioDescend@16 referenced in function "int __cdecl do_everything(int,wchar_t const * * const)" (?do_everything@@YAHHQAPB_W@Z)

    1>C:UsersAdminGoogle DriveTRAVAUXPROGRAMMINGC++MyMusicRecognitionloopback-capturesourceloopback-captureDebugloopback-capture.exe : fatal error LNK1120: 8 unresolved externals

    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    —————

    please help me

  81. As the documentation for mmioWrite says, you need to link against winmm.lib

    msdn.microsoft.com/…/dd757341(v=vs.85).aspx

  82. AmirH says:

    Thank u for your help (and your source ^^)

    Now I have only 2 errors, do you know what is related to? :

    1>—— Build started: Project: loopback-capture, Configuration: Debug Win32 ——

    1>  prefs.cpp

    1>  main.cpp

    1>  loopback-capture.cpp

    1>  guid.cpp

    1>  Generating Code…

    1>loopback-capture.obj : error LNK2019: unresolved external symbol _AvSetMmThreadCharacteristicsW@8 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>loopback-capture.obj : error LNK2019: unresolved external symbol _AvRevertMmThreadCharacteristics@4 referenced in function "long __cdecl LoopbackCapture(struct IMMDevice *,struct HMMIO__ *,bool,void *,void *,unsigned int *)" (?LoopbackCapture@@YAJPAUIMMDevice@@PAUHMMIO__@@_NPAX3PAI@Z)

    1>C:UsersAdminGoogle DriveTRAVAUXPROGRAMMINGC++MyMusicRecognitionloopback-capturesourceloopback-captureDebugloopback-capture.exe : fatal error LNK1120: 2 unresolved externals

    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

  83. You need to look up the documentation for AvSetMmThreadCharacteristics and AvRevertMmThreadCharacteristics. That documentation will tell you what library you need to link against to get the stub implementations of those functions.

    msdn.microsoft.com/…/ms681974(v=vs.85).aspx

  84. AmirH says:

    Oh yeah thank u^^

    Once my project finished, I'll post it here.

    good job

  85. Chris says:

    Hello,

    I'm trying to find a solution that will allow me to run the Audio Loopback portion of the Passmark BurnIn test in a Windows virtual machine with out the need of loop back hardware. I found this blog and it seems like a possible solution.

    Is WASAPI (and particularly this example) a viable solution to accomplish this? Any guidance on if and how I might go about doing this?

    Thanks.

  86. Beats me. What is the "Audio Loopback portion of the Passmark BurnIn test" and what does it entail?

  87. Chris says:

    This is the BurnIn Tests software: http://www.passmark.com/…/bit.htm

    The audio loop back portion normally requires a loop back cable connecting the microphone jack to the headphone jack. It will play a specific sound frequency and then listen for any distortion of the sound.

    I only have a few of those cables. However, most of my machines are newer, and so they have the combination headphone and microphone jack.  I'm not sure if I can use a single combination jack for the loop back test, and will be looking into it.

    In the meantime, I'm curious to find out if it can be done in software. I looked at Virtual Audio Cable, but that is a pure digital loop back and guarantees no audio distortion, which would defeat the purpose of the test. Basically, I need software that can convert from digital to analog and then analog back to digital to simulate the use of headphone and microphone loop back.

    Thanks, again.

  88. I see.

    WASAPI loopback is also a pure digital loopback, which would defeat the purpose of the test in the same way that Virtual Audio Cable would defeat the purpose.

    There are Y-adapters on the market which convert a 3.5mm TRRS headset jack into a stereo 3.5mm TRS headphone jack plus a mono 3.5mm TS microphone jack. Sometimes you can just use one of these plus a loopback cable.

    Unfortunately there isn't much in the way of industry standardization around the way jack presence detection works on TRRS headset jacks (there are three states: nothing plugged in; headphone plugged in; headset plugged in) so you might have to play games with resistors to get everything to work.

  89. Chris says:

    I see. Thank you for the information and your time.

  90. Ambrish says:

    I am running into some very strange issue with loopback capture:

    1) Open a loopback capture stream on default audio endpoint (headphones)

    2) Play audio using WMP. This audio gets captured in loopback stream

    3) Terminate audio playback using ctrl+w shortcut.

    At this stage, you'll get a buzzing sound from my headphones.

    This buzzing sound will go away only after I terminate loopback capture.

    How can loopback capture affect audio going out on the device?

    Thanks

  91. @Ambrish: this sounds like a bug, either in Windows or the driver. What audio driver do you have? If you like you can send me a dxdiag: mateer at microsoft dot com

  92. alex says:

    Hi it is very interesting… do you know whether there is a way to use it in a visual basic .NET project (e.g. in a media player project) to capture what i play with the mediaplayer component?

  93. @alex:

    WASAPI is a C++-only API; it cannot be consumed directly from the .NET framework. It's possible that someone has written a P/invoke wrapper, though.

    WASAPI loopback will give you the mixed audio of all applications which are currently playing. If you want to capture only your own audio, you need to make sure you're the only application playing.

    Also, WASAPI loopback will include some kinds of audio effects that are added by the audio driver.

  94. Hassaan Nasir says:

    Hey could you please tell me how i could do the same thing in windows 8 c++/xaml?Please i need help in my project and i want to record all the music which is being played in my app.

  95. Martin says:

    Why do you code "CoTaskMemFree(pwfx);" if there is no ALLOC?

    I'm trying to get it to record MP3, so I need to understand details. Txs.

  96. @Martin: per the documentation of IAudioClient::GetMixFormat msdn.microsoft.com/…/dd370872(v=vs.85).aspx "The caller is responsible for freeing the storage, when it is no longer needed, by calling the CoTaskMemFree function" – that is, IAudioClient::GetMixFormat's implementation apparently calls CoTaskMemAlloc on the caller's behalf.

    WASAPI will not do format conversion for you; if you want to record in MP3 format, you're better off using a higher-level API like MediaCapture. You can write a custom source which does WASAPI loopback capture, then rely on the MediaCapture stack to insert format converters for you (like a PCM-to-MP3 encoder.)

  97. martin says:

    Thank you for the comment. I'll look into it, as I already found out, that simply passing the bit stream to Lame instead of mmioWrite does not work. I get a MP3 file of correct length, but the sound is very distorted, actually the original is hardly recognizable, perhaps some 5 to 10% is original, the rest is noise. I don't know what exactly is the format in the received bit stream, but is certainly not short int interleaved stereo.

  98. @martin: The format of the IAudioCaptureClient::GetBuffer(…) data should be whatever you passed to IAudioClient::Initialize.

    Note also that IAudioCaptureClient::GetBuffer and ReleaseBuffer deal in frames rather than bytes; assuming a format of stereo int16, one frame is four bytes.

  99. martin says:

    Meantime I have the idea that it works well: just that the WAV file is coded IEEE float signed 32 bit, and Lame wants 16 bit integer. Conversion to write. "Simple" wav -> mp3 encoders results are noise as well if I input a file from your capture program

  100. martin says:

    Got it all working fine, see your mail (cited above) to see how.

  101. Timi12 says:

    Maurits Hi.

    I would like to ask you to view my question about WASAPI loopback here:

    social.msdn.microsoft.com/…/rendering-audio-using-wasapi-loopback-capturing-the-speakers-volume

    Thank you for any help you can give on this.

  102. Timi12 says:

    Maurits Hi.

    I wonder if you can continue your help in this question:

    social.msdn.microsoft.com/…/rendering-audio-using-wasapi-loopback-capturing-the-speakers-volume

    Again, thanks.

  103. Timi12 says:

    Maurits Hi.

    Again thank you for your comments in

    social.msdn.microsoft.com/…/rendering-audio-using-wasapi-loopback-capturing-the-speakers-volume

    So is there another way (or what is the best way) other than WASAPI loopback in Win7 and above to get what you hear from speakers just like I get from the WASAPI loopback?

  104. Thank you for your sample.

Skip to main content