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

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

  • Comments 10

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.

Attachment: silence2.zip
Leave a Comment
  • Please add 1 and 1 and type the answer here:
  • Post
  • 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)) {

  • Yup.  Oops.

  • Fixed.

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

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

  • 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);

  • 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

  • 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

  • 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:

    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

  • 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)

Page 1 of 1 (10 items)