Sample – playing silence via WASAPI event-driven (pull) mode


Be vewy vewy quiet - we'we hunting wabbits.
    -- Elmer Fudd

Attached is a mini-app I've written to play silence to any given playback device using WASAPI event-driven (pull) mode.  Source, x86 binary, and amd64 binary are attached.

Usage statement:

>silence -?
silence
silence -?
silence --list-devices
silence --device "Device long name"

    With no arguments, plays silence to the default audio device.
    -? prints this message.
    --list-devices displays the long names of all active playback devices.
    --device plays silence to the specified device.

>silence --list-devices
Active render endpoints found: 2
    Speakers (USB Audio Device)
    Headphones (High Definition Audio Device)

>silence --device "Headphones (High Definition Audio Device)"
Press Enter to quit...
Received stop event after 488 passes

While it's playing it shows up in the Volume Mixer:

 http://blogs.msdn.com/photos/matthew_van_eerde/images/9191979/original.aspx

Why would I write such a thing?

Well, there is the pedagogical exercise of writing a WASAPI event-driven render loop.

But there is also a practical application of an active silence stream, having to do with loopback capture.  More on this in a future post...

EDIT: 7/30/2009 - fixed bug where I was treating the GetCurrentPadding value as the amount of free space in the buffer when in fact it's the amount of used space.

While I was at it, added an icon and exited immediately on errors rather than waiting for the caller to hit Enter.

EDIT: 9/28/2015 - moved source to https://github.com/mvaneerde/blog/tree/master/silence

silence.zip

Comments (14)

  1. Serhij says:

    Useful article, but I suppose there is a bug in source code, look for correct version below:

          hr = pAudioRenderClient->GetBuffer(nFramesInBuffer-nFramesOfPadding, &pData);

           if (FAILED(hr)) {

           hr = pAudioRenderClient->ReleaseBuffer(nFramesInBuffer-nFramesOfPadding, AUDCLNT_BUFFERFLAGS_SILENT);

           if (FAILED(hr)) {

  2. Serhij says:

    Yup, thanks, now works! Your articles helped me a lot.

  3. ooo says:

    Could it play sin wave ,and hit key to stop?

  4. Yes.  If you want it to play a sine wave, you would take this section of silence.cpp:

           // *** AT THIS POINT ***

           // If you wanted to render something besides silence,

           // you would fill the buffer pData

           // with (nFramesInBuffer – nFramesOfPadding) worth of audio data

           // this should be in the same wave format

           // that the stream was initialized with

           //

           // In particular, if you didn't want to use the mix format,

           // you would need to either ask for a different format in IAudioClient::Initialize

           // or do a format conversion

           //

           // If you do, then change the AUDCLNT_BUFFERFLAGS_SILENT flags value below to 0

    And change it to something like:

    float *pSamples = (float*)pData; // the mix format is float

    // these should probably be parameters

    const double signalFrequency = 440.0;

    const double amplitude = 0.5;

    const double dc = 0.0;

    // this doesn't really need to be static but it does need to persist

    // across calls to GetBuffer / ReleaseBuffer

    static double phase = 0.0;

    for (frame = 0; frame < nFramesInBuffer – nFramesOfPadding; frame++) {

       float sampleValue = (float)(amplitude * sin(phase) + dc);

       phase += signalFrequency / pwfx->nSamplesPerSec;

       while (phase > 2 * pi) { phase -= 2 * pi; }

       for (channel = 0; channel < pwfx->nChannels; channel++) {

           pSamples[frame * pwfx->nChannels + channel] = sampleValue;

       }

    }

    Also, change this line:

           hr = pAudioRenderClient->ReleaseBuffer(nFramesInBuffer – nFramesOfPadding, AUDCLNT_BUFFERFLAGS_SILENT);

    to

           hr = pAudioRenderClient->ReleaseBuffer(nFramesInBuffer – nFramesOfPadding, 0);

  5. mocdiv says:

    I'm working on loopback capture, to handle silent I want to try solution with playing silence all the time, but when I run it, silence is being played for a short moment and then is showing error

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

    What could be the cause?

    Regards

  6. If you're getting "need more data" notifications but the buffer is full there's likely a glitch.  There are many possible causes; it could be a bug in the audio engine, in the audio driver, or it could be that some other process (probably a driver) is holding off the system.

    Can you take "glitch logs" and send them to me?  Follow the instructions in this thread:

    social.msdn.microsoft.com/…/1a796e5c-e808-42c0-96cd-84cebfaf71d5

  7. mocdiv says:

    Hi,

    I make a report as You wish. Report is from Windows 7. I follow all steps You mention in Your comment.

    Here are the results:

    http://www.sendspace.pl/…/aeab4dcf2712c9e0297982f

    I hope You can help to get me an idea why this is happening. I want to write DirectShow source filter with audio from speakers as source. But I need good way of starting recording from speakers when nothing is playing. I need record silence as a part of my recording.

    I found also an issue in Your blog. Always when I  post a comment first attempt is failed, I don't get any confirmation and comment is not showing in comments list, and I have to write again. In contact form I also found this issue.

    Regards

  8. Hi mocdiv.

    Thank you for sending the glitch trace.  I looked at it with some of the glitch trace folks here and there appear to be two potentially related problems.

    The first problem is in my source – I'm registering for the Multimedia Class Scheduler Service, but under the wrong class.  An audio thread should register using the "Audio" or "Pro Audio" classes; I'm incorrectly registering using the "Playback" class.

    Can you change this code:

       // register with MMCSS

       DWORD nTaskIndex = 0;

       HANDLE hTask = AvSetMmThreadCharacteristics(L"Playback", &nTaskIndex);

    to this:

       // register with MMCSS

       DWORD nTaskIndex = 0;

       HANDLE hTask = AvSetMmThreadCharacteristics(L"Audio", &nTaskIndex);

    ?

    The second problem appears to be related to aqq.exe taking up too much of audiodg.exe's time.  Does this problem only reproduce when aqq.exe is running?

    If you like you can contact me directly at (mateer at microsoft dot com)

  9. Keith Haugen says:

    I had a question — to check how the silence flag works, I put your silence.exe and a loopback capture executable that checks the flags returned in GetBuffer, and when I would start silence directed towards an endpoint and then did the loopback capture on that endpoint, the flags returned from GetBuffer did not have the silence bit set. I tried the same thing with Windows Media player, and when I would pause it my loopback capture did indicate that the silence flag was set. What am I missing in regards to the silence flag and loopback capture? Thanks!

    1. It sounds like some audio processing object is clearing the flag between silence.exe and loopback-capture.exe. Arguably a bug.

  10. Keith Haugen says:

    Another question, related similar to the “Playback” vs “Audio” issue from a previous response — I have another playback application that even when registering as “Pro Audio” will every so often indicate that GetCurrentPadding indicates a full buffer (using the same manner of detection as silence.exe). You mentioned previously that in the other user’s case something was taking up a lot of audiodg.exe’s time. How can I check for that (and see what it is that is taking up all the time if that is the case)?

    1. > GetCurrentPadding indicates a full buffer

      A full buffer means the thing that is supposed to read from the buffer didn’t, yet. This might mean a glitch.

      Grabbing media logs would allow figuring out why.

      You can send us logs using the Feedback Hub – https://blogs.msdn.microsoft.com/matthew_van_eerde/2016/09/26/report-problems-with-logs-and-suggest-features-with-the-feedback-hub/

      Or you can grab them the old-fashioned way – https://blogs.msdn.microsoft.com/matthew_van_eerde/2017/01/09/collecting-audio-logs-the-old-fashioned-way/

Skip to main content