none
IAudioClient::Release() and IAudioCaptureClient::Release() Never Return

    Question

  • Hi,

    I am having a problem when I unplug my USB microphone while capturing audio from it.  I call:

                    hr = p_mic->p_captureClient->GetBuffer(&pDataInput, &numSamp, &flags, NULL, NULL);

    which returns an error that the device has been invalidated.  Because the device has been invalidated, I want to release both the capture client and the audio client that retrieved it:

     

        SAFE_RELEASE(p_mic->p_audioClientInput);
        SAFE_RELEASE(p_mic->p_captureClient);

    However, my call to release the capture client never returns.  I tried changing the order in which I release the interfaces:

        SAFE_RELEASE(p_mic->p_captureClient);
        SAFE_RELEASE(p_mic->p_audioClientInput);

    And then the audio client's call to Release() would never return.

     

    I saw this thread: http://social.msdn.microsoft.com/Forums/en-US/windowspro-audiodevelopment/thread/e5de6a76-46eb-4943-8500-28158e5bc573/, which explains that getting the capture client service and releasing it must be done in the same thread.  I am running a single-threaded program, and I am still seeing this error.  Any advice?

    Thanks,
    Bill 

    EDIT: I should have mentioned that I only see this error when I initialize the audio client in exclusive mode.

    EDIT2: Here's some sample code that can reproduce the issue.  If you unplug the microphone, while the code is in the while loop, the second release call never returns.  GetAudioFormat just tries a bunch of permutations of audio formats and sampling rates to find one that the device supports in exclusive mode.

     

                hr = CoCreateInstance(
                        (__uuidof(MMDeviceEnumerator)), NULL,
                        CLSCTX_ALL, (__uuidof(IMMDeviceEnumerator)),
                        (void**)&p_deviceEnumerator);
                 PRINT_ERR_ON_FAIL(hr)
                hr = p_deviceEnumerator->GetDefaultAudioEndpoint(
                        eCapture, eConsole, &pDev);
                  PRINT_ERR_ON_FAIL(hr)
                hr = pDev->Activate(
                        __uuidof(IAudioClient), CLSCTX_ALL,
                        NULL, (void**)&(p_audioClient));
                 PRINT_ERR_ON_FAIL(hr)
    
                SAFE_RELEASE(p_deviceEnumerator);
                SAFE_RELEASE(pDev);
    
                WAVEFORMATEXTENSIBLE pwfext;
                AUDCLNT_SHAREMODE sm;
                GetAudioFormat(p_audioClient, &pwfext, &sm);
    
                hr = p_audioClient->Initialize(
                        sm,
                        0,
                        60*REFTIMES_PER_MILLISEC,
                        0,
                        &(pwfext.Format),
                        NULL);
                  PRINT_ERR_ON_FAIL(hr)
                hr = p_audioClient->GetService(
                        __uuidof(IAudioCaptureClient),
                        (VOID**)&(p_captureClient));
                   PRINT_ERR_ON_FAIL(hr)
                printf("Being test...");
                int i = 0;
                BYTE* pDataInput;
                UINT32 numSamp;
                DWORD flags=0;
                hr = p_audioClient->Start();
                 PRINT_ERR_ON_FAIL(hr)
                while(i < 10000)
                {
                    i++;
                    Sleep(1);       
                    hr = p_captureClient->GetBuffer(&pDataInput, &numSamp, &flags, NULL, NULL);
                    if (FAILED(hr))
                    {
                        p_audioClient->Stop();
                        printf("Error1! 0x%08x", hr);
                        p_captureClient->Release();
                        p_audioClient->Release();
                        printf("Error!");
                        break;
                    }
                    p_captureClient->ReleaseBuffer(numSamp);
                }
                printf("End test...");
    

     

     

    • Edited by BillFinn Wednesday, October 12, 2011 3:01 PM
    Tuesday, October 11, 2011 9:49 PM

All replies

  • I have more specific test code that reproduces this problem repeatedly.  Has anyone else seen this problem while trying to use microphones in exclusive mode?

    Steps:
    1) Execute the code below with a USB microphone plugged in and selected as the default capture device.
    2) Unplug the the USB microphone after the words "Begin test..." appear on the console.
    3) Observe that nothing else gets printed, and the program is hung in the IAudioClient::Release() call.

    Code:

     

    #define REFTIMES_PER_MILLISEC  10000
    #define SAFE_RELEASE(punk)  \
        if ((punk) != NULL)  \
    { (punk)->Release(); (punk) = NULL; }
    #define PRINT_ERR_ON_FAIL(hr) \
        if ((FAILED(hr))) \
    { printf("Failed line: %d with hr: 0x%08x", __LINE__, hr);}
    
    IMMDeviceEnumerator *p_deviceEnumerator = NULL;
    IMMDevice *pDev = NULL;
    IAudioClient *p_audioClient = NULL;
    IAudioCaptureClient *p_captureClient = NULL;
    WAVEFORMATEXTENSIBLE pwfext;
    AUDCLNT_SHAREMODE sm;
    HRESULT hr;
    int i = 0;
    BYTE* pDataInput;
    UINT32 numSamp;
    DWORD flags=0;
    
    hr = CoCreateInstance(
            (__uuidof(MMDeviceEnumerator)), NULL,
            CLSCTX_ALL, (__uuidof(IMMDeviceEnumerator)),
            (void**)&p_deviceEnumerator);
    PRINT_ERR_ON_FAIL(hr);
    hr = p_deviceEnumerator->GetDefaultAudioEndpoint(
            eCapture, eConsole, &pDev);
    PRINT_ERR_ON_FAIL(hr);
    hr = pDev->Activate(
            __uuidof(IAudioClient), CLSCTX_ALL,
            NULL, (void**)&(p_audioClient));
    PRINT_ERR_ON_FAIL(hr);
    
    SAFE_RELEASE(p_deviceEnumerator);
    SAFE_RELEASE(pDev);
    
    sm = AUDCLNT_SHAREMODE_EXCLUSIVE;
    pwfext.Format.wFormatTag = WAVE_FORMAT_PCM;
    pwfext.Format.nChannels = 1;
    pwfext.Format.nSamplesPerSec = 0xbb80;
    pwfext.Format.nAvgBytesPerSec = 0x17700;
    pwfext.Format.nBlockAlign = 2;
    pwfext.Format.wBitsPerSample = 0x10;
    pwfext.Format.cbSize = 0;
    
    hr = p_audioClient->Initialize(
            sm,
            0,
            60*REFTIMES_PER_MILLISEC,
            0,
            &(pwfext.Format),
            NULL);
    PRINT_ERR_ON_FAIL(hr);
    hr = p_audioClient->GetService(
            __uuidof(IAudioCaptureClient),
            (VOID**)&(p_captureClient));
    PRINT_ERR_ON_FAIL(hr);
    printf("Begin test...\n");
    hr = p_audioClient->Start();
    PRINT_ERR_ON_FAIL(hr);
    while(i < 10000)
    {
        i++;
        Sleep(1);       
        hr = p_captureClient->GetBuffer(&pDataInput, &numSamp, &flags, NULL, NULL);
        if (FAILED(hr))
        {
            p_audioClient->Stop();
            printf("Error code: 0x%08x\n", hr);
            p_captureClient->Release();
            printf("Finished releasing capture client.\n");
            p_audioClient->Release();
            printf("Finished releasing audio client.\n");
            break;
        }
        p_captureClient->ReleaseBuffer(numSamp);
    }
    printf("End test...\n");
    p_audioClient->Stop();
    p_captureClient->Release();
    p_audioClient->Release();
    
    

     

    Output when leaving the device connected:

    Begin test...
    End test...

    Output when disconnecting the device:

    Begin test...
    Error code: 0x88890004
    Finished releasing capture client.

     

     

     

    Wednesday, October 19, 2011 3:21 PM
  • Has anyone else seen this problem?  Is anyone else using a microphone in exclusive mode?
    Monday, October 24, 2011 6:28 PM
  • Doesn't repro for me, either with an HD Audio microphone with jack sense or with a USB audio microphone. Here's my slight modification of your code:

     

    // main.cpp

    #include <windows.h>
    #include <stdio.h>
    #include <mmdeviceapi.h>
    #include <audioclient.h>

    #define REFTIMES_PER_MILLISEC  10000
    #define SAFE_RELEASE(punk)  \
        if ((punk) != NULL)  \
        { (punk)->Release(); (punk) = NULL; }

    #define PRINT_ERR_ON_FAIL(hr) \
        if ((FAILED(hr))) \
        { printf("Failed line: %d with hr: 0x%08x", __LINE__, hr); }

    int _cdecl wmain() {

        CoInitialize(NULL);

        IMMDeviceEnumerator *p_deviceEnumerator = NULL;
        IMMDevice *pDev = NULL;
        IAudioClient *p_audioClient = NULL;
        IAudioCaptureClient *p_captureClient = NULL;
        WAVEFORMATEXTENSIBLE pwfext;
        AUDCLNT_SHAREMODE sm;
        HRESULT hr;
        int i = 0;
        BYTE* pDataInput;
        UINT32 numSamp;
        DWORD flags=0;

        hr = CoCreateInstance(
                (__uuidof(MMDeviceEnumerator)), NULL,
                CLSCTX_ALL, (__uuidof(IMMDeviceEnumerator)),
                (void**)&p_deviceEnumerator);
        PRINT_ERR_ON_FAIL(hr);
        hr = p_deviceEnumerator->GetDefaultAudioEndpoint(
                eCapture, eConsole, &pDev);
        PRINT_ERR_ON_FAIL(hr);
        hr = pDev->Activate(
                __uuidof(IAudioClient), CLSCTX_ALL,
                NULL, (void**)&(p_audioClient));
        PRINT_ERR_ON_FAIL(hr);

        SAFE_RELEASE(p_deviceEnumerator);
        SAFE_RELEASE(pDev);

        sm = AUDCLNT_SHAREMODE_EXCLUSIVE;
        pwfext.Format.wFormatTag = WAVE_FORMAT_PCM;
        pwfext.Format.nChannels = 1;
        pwfext.Format.nSamplesPerSec = 44100;
        pwfext.Format.nAvgBytesPerSec = 2 * 1 * 44100;
        pwfext.Format.nBlockAlign = 2 * 1;
        pwfext.Format.wBitsPerSample = 16;
        pwfext.Format.cbSize = 0;

        hr = p_audioClient->Initialize(
                sm,
                0,
                60*REFTIMES_PER_MILLISEC,
                0,
                &(pwfext.Format),
                NULL);
        PRINT_ERR_ON_FAIL(hr);
        hr = p_audioClient->GetService(
                __uuidof(IAudioCaptureClient),
                (VOID**)&(p_captureClient));
        PRINT_ERR_ON_FAIL(hr);
        printf("Begin test...\n");
        hr = p_audioClient->Start();
        PRINT_ERR_ON_FAIL(hr);
        bool bReleased = false;
        while(i < 1000)
        {
            i++;
            Sleep(1);      
            hr = p_captureClient->GetBuffer(&pDataInput, &numSamp, &flags, NULL, NULL);
            if (FAILED(hr))
            {
                p_audioClient->Stop();
                printf("Error code: 0x%08x\n", hr);
                p_captureClient->Release();
                printf("Finished releasing capture client.\n");
                p_audioClient->Release();
                printf("Finished releasing audio client.\n");
                bReleased = true;
                break;
            }
            p_captureClient->ReleaseBuffer(numSamp);
        }
        printf("End test...\n");
        if (!bReleased) {
            p_audioClient->Stop();
            p_captureClient->Release();
            p_audioClient->Release();
        }
       
        CoUninitialize();
       
        return 0;
    }

     

    Here's the output I get:

    Begin test...
    Error code: 0x88890004
    Finished releasing capture client.
    Finished releasing audio client.
    End test...


    Matthew van Eerde
    Monday, October 24, 2011 10:03 PM
    Moderator
  • Thanks for the info Matthew.

    I created an exe with your modified code.  (Thanks for wrapping it into a self-contained format.  I was yanking it from a larger test harness that I have.)  I have run it on three different Windows 7 machines with three different USB microphones, and I am still having the same problem.  A couple of questions:

    1) Did you physically remove the microphone from the USB port in the middle of the test?
    2) Can you send me your command-line options for compiling the project?  Here are mine:
    /ZI /nologo /W3 /WX- /Od /Oy- /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\Scratch.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd /analyze- /errorReport:queue 

    And here are my link options, for completeness:
    /OUT:"Debug\Scratch.exe" /NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"Debug\Scratch.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /PDB:"Debug\Scratch.pdb" /PGD:"Debug\Scratch.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE  

    I had to use the /MTd option instead of /MDd because one of the machines I was trying to test on did not have msvcr100d.dll.

    Can you think of any other differences that we may have that may cause the difference?

    TIA,

    Bill 

    Tuesday, October 25, 2011 3:14 PM
  • I was trying it on Windows 8.


    Matthew van Eerde
    Wednesday, October 26, 2011 3:33 PM
    Moderator
  • Here's what cl.exe sees:

    1>cl /Fo"e:\sd\fbl_multimedia_media\object\x86fre\developer\mateer\release_bug\objfre\i386/"
    1>   /FC
    1>   /Ii386
    1>   /I.
    1>   /Ie:\sd\fbl_multimedia_media\object\x86fre\developer\mateer\release_bug\objfre\i386
    1>   /Ie:\sd\fbl_multimedia_media\public\x86fre\oak\inc
    1>   /Ie:\sd\fbl_multimedia_media\public\x86fre\sdk\inc
    1>   /Ie:\sd\fbl_multimedia_media\public\x86fre\sdk\inc\minwin
    1>   /Ie:\sd\fbl_multimedia_media\public\x86fre\sdk\inc\mincore
    1>   /Ie:\sd\fbl_multimedia_media\public\x86fre\internal\sdk\inc
    1>   /Ie:\sd\fbl_multimedia_media\public\x86fre\internal\oak\inc
    1>   /Ie:\sd\fbl_multimedia_media\public\x86fre\sdk\inc\crt
    1>   /D_X86_=1
    1>   /Di386=1
    1>   /DSTD_CALL
    1>   /DCONDITION_HANDLING=1
    1>   /DNT_UP=1
    1>   /DNT_INST=0
    1>   /DWIN32=100
    1>   /D_NT1X_=100
    1>   /DWINNT=1
    1>   /D_WIN32_WINNT=0x0501
    1>   /DWINVER=0x0501
    1>   /D_WIN32_IE=0x0603
    1>   /DWIN32_LEAN_AND_MEAN=1
    1>   /DDEVL=1
    1>   /D__BUILDDATE__=110912-1352
    1>   /D__BUILDMACHINE__=fbl_multimedia_media(mateer)
    1>   /DFPO=0
    1>   /DNDEBUG
    1>   /D_DLL=1
    1>   /D_MT=1
    1>   -DUNICODE
    1>   -D_UNICODE
    1>   -D_APISET_WINDOWS_VERSION=0x601
    1>   -D_APISET_MINWIN_VERSION=0x0100
    1>   -D_APISET_MINCORE_VERSION=0x0100
    1>   /DNTDDI_VERSION=0x05010200
    1>   /DPSAPI_VERSION=1
    1>   /DBUILD_WINDOWS
    1>   -D_USE_DECLSPECS_FOR_SAL=1
    1>   /c
    1>   /Zc:wchar_t-
    1>   /Zl
    1>   /Zp8
    1>   /Gy
    1>   /Gm-
    1>   /W4
    1>   /WX
    1>   /WX
    1>   /Gz
    1>   /hotpatch
    1>   /d1import_no_registry
    1>   /EHs-c-
    1>   /GR-
    1>   /GF
    1>   /GS
    1>   /Zi
    1>   /Oxs
    1>   /GL
    1>   /Oy-
    1>   /Zi
    1>   /Fde:\sd\fbl_multimedia_media\object\x86fre\developer\mateer\release_bug\objfre\i386\
    1>   /d1nodatetime
    1>   /d1trimfile:d:\sd\fbl_multimedia_media\
    1>   /d1trimfile:e:\sd\fbl_multimedia_media\public\x86fre\
    1>   /d1trimfile:e:\sd\fbl_multimedia_media\object\x86fre\
    1>   /d1trimfile:e:\sd\fbl_multimedia_media\binaries\x86fre\
    1>   /d2AllowCompatibleILVersions
    1>   /d2Zi+
    1>   /wd4986
    1>   /wd4987
    1>   /wd4471
    1>   /wd4369
    1>   /wd4309
    1>   /wd4603
    1>   /wd4627
    1>   /FIe:\sd\fbl_multimedia_media\public\x86fre\sdk\inc\warning.h
    1>   /FIe:\sd\fbl_multimedia_media\public\x86fre\internal\Base\inc\warning_x.h
    1>   .\main.cpp


    Matthew van Eerde
    Wednesday, October 26, 2011 3:36 PM
    Moderator
  • I wonder if this is a driver issue.  Can you run dxdiag, Save All Information, and send a dxdiag.txt to me via email? mateer at microsoft dot com
    Matthew van Eerde
    Wednesday, October 26, 2011 3:40 PM
    Moderator
  • I am now able to create a similar (but possibly debuggable) issue with an HD Audio Device Microphone.  Sometimes the code runs to completion without any problems, and sometimes I get this exception.

    I use the same code, except that I don't hard-code the number of channels to 1.  My HD microphone has 2 channels, so I call GetMixFormat(), and I use the number of channels that it returns when I try to initialize the IAudioClient.

    Rather than never returning from Release(), I am now seeing an exception thrown upon calling GetBuffer().

    I found the following hotfix for Windows Vista, but supposedly this issue was fixed in Windows 7 (which is the OS I am running).

    http://support.microsoft.com/kb/957569

    Code:

    // MicLoop.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <windows.h>
    #include <stdio.h>
    #include <mmdeviceapi.h>
    #include <audioclient.h>
    #define DIM(x) (sizeof(x) / sizeof(x[0]))
    #define REFTIMES_PER_MILLISEC  10000
    #define SAFE_RELEASE(punk)  \
        if ((punk) != NULL)  \
        { (punk)->Release(); (punk) = NULL; }
    #define EXIT_ON_FAIL(hr) \
        if ((FAILED(hr))) \
        { printf("Failed line: %d with hr: 0x%08x", __LINE__, hr); exit(-1);}
    #define SAFE_MEM_FREE(punk)  \
        if ((punk) != NULL)  \
    { CoTaskMemFree(punk); (punk) = NULL; }
    
    int _cdecl wmain() {
        CoInitialize(NULL);
        IMMDeviceEnumerator *p_deviceEnumerator = NULL;
        IMMDevice *pDev = NULL;
        IAudioClient *p_audioClient = NULL;
        IAudioCaptureClient *p_captureClient = NULL;
        WAVEFORMATEXTENSIBLE pwfext;
        AUDCLNT_SHAREMODE sm;
        HRESULT hr;
        int i = 0;
        BYTE* pDataInput;
        UINT32 numSamp;
        DWORD flags=0;
        hr = CoCreateInstance(
                (__uuidof(MMDeviceEnumerator)), NULL,
                CLSCTX_ALL, (__uuidof(IMMDeviceEnumerator)),
                (void**)&p_deviceEnumerator);
        EXIT_ON_FAIL(hr);
        hr = p_deviceEnumerator->GetDefaultAudioEndpoint(
                eCapture, eConsole, &pDev);
        EXIT_ON_FAIL(hr);
        hr = pDev->Activate(
                __uuidof(IAudioClient), CLSCTX_ALL,
                NULL, (void**)&(p_audioClient));
        EXIT_ON_FAIL(hr);
        SAFE_RELEASE(p_deviceEnumerator);
        SAFE_RELEASE(pDev);
    
    
        WAVEFORMATEX *pwfxShared = NULL;
        hr = p_audioClient->GetMixFormat(&pwfxShared);
        EXIT_ON_FAIL(hr);
    
        int numChans = pwfxShared->nChannels;
        printf("Num chans: %d\n", numChans);
    
        SAFE_MEM_FREE(pwfxShared);
        sm = AUDCLNT_SHAREMODE_EXCLUSIVE;
        int formatSize = 16; //bits
        pwfext.Format.wFormatTag = WAVE_FORMAT_PCM;
        pwfext.Format.nChannels = numChans;
        pwfext.Format.nSamplesPerSec = 44100;
        pwfext.Format.nAvgBytesPerSec = (formatSize / 8) * numChans * 44100;
        pwfext.Format.nBlockAlign = (formatSize / 8) * numChans;
        pwfext.Format.wBitsPerSample = formatSize;
        pwfext.Format.cbSize = 0;
        hr = p_audioClient->Initialize(
                sm,
                0,
                60*REFTIMES_PER_MILLISEC,
                0,
                &(pwfext.Format),
                NULL);
        EXIT_ON_FAIL(hr);
    
        hr = p_audioClient->GetService(
                __uuidof(IAudioCaptureClient),
                (VOID**)&(p_captureClient));
        EXIT_ON_FAIL(hr);
        printf("Begin test...\n");
        hr = p_audioClient->Start();
        EXIT_ON_FAIL(hr);
        bool bReleased = false;
        while(i < 10000)
        {
            i++;
            Sleep(1);       
            hr = p_captureClient->GetBuffer(&pDataInput, &numSamp, &flags, NULL, NULL);
            if (FAILED(hr))
            {
                p_audioClient->Stop();
                printf("Error code: 0x%08x\n", hr);
                p_captureClient->Release();
                printf("Finished releasing capture client.\n");
                p_audioClient->Release();
                printf("Finished releasing audio client.\n");
                bReleased = true;
                break;
            }
            p_captureClient->ReleaseBuffer(numSamp);
        }
        printf("End test...\n");
        if (!bReleased) {
            p_audioClient->Stop();
            p_captureClient->Release();
            p_audioClient->Release();
        }
    
        CoUninitialize();
    
        return 0;
    }
    
    


    Thursday, October 27, 2011 7:36 PM
  • Can you save a dump of the application in the crash state and send it to me?

    Task Manager | Processes | right-click micloop.exe | Create dump file

    With luck I can see where in audiokse.dll it's crashing.


    Matthew van Eerde
    Thursday, October 27, 2011 9:20 PM
    Moderator
  • One potential cause:

    http://support.microsoft.com/kb/957569

    "If the returned ppData pointer is NULL, the application must skip the audio render or capture operation"

    So instead of:

            hr = p_captureClient->GetBuffer(&pDataInput, &numSamp, &flags, NULL, NULL);
            if (FAILED(hr))

    Perhaps:

            hr = p_captureClient->GetBuffer(&pDataInput, &numSamp, &flags, NULL, NULL);
            if (FAILED(hr)) {
                ...
            } else if (NULL == pDataInput) {
                printf("...");
                continue;
            }


    Matthew van Eerde
    Thursday, October 27, 2011 9:24 PM
    Moderator
  • How about the result? I meet the same  problem  too(In windows vista ultimate). anyone can help me?
    Thursday, June 28, 2012 7:48 AM
  • How about the result? I meet the same  problem  too(In windows vista ultimate). anyone can help me?

    Thursday, June 28, 2012 7:48 AM