簡體   English   中英

默認端點上的音頻會話輪詢有時會在Win7上崩潰

[英]Polling for audio sessions on default endpoint sometimes crashes on Win7

我正在開發一個應用程序,該應用程序每X毫秒輪詢默認音頻呈現端點上音頻會話的狀態和峰值級別,並基於此實現一些邏輯。 它似乎在Windows 10上運行良好,但是在Windows 7上,當我更改默認播放設備時(例如,在USB耳機和PC揚聲器之間切換時),偶爾會崩潰。 崩潰發生的確切行在運行之間會發生變化,但是通常是當我訪問IAudioSessionControl或IAudioSessionControl2指針進行各種WASAPI調用時。 我可以從ProcDump創建並由WinDbg分析的堆棧跟蹤中了解到,當默認播放設備發生更改時,代表音頻會話的COM對象被破壞了(即使我已經獲得並且仍然持有指向這些對象接口的指針),然后我的輪詢線程在我通過接口指針訪問它們的地方隨機崩潰。 我發現也許我做錯了事,所以這導致我進入Matthew van Eerde的博客樣本 ,他在其中進行了相同的查詢(甚至更多),但是針對系統中所有可用的音頻端點。 因此,我修改了他的示例程序,使其每5毫秒執行一次,並且僅針對默認的渲染終結點執行此操作,並且在Windows 7上偶爾也會發生相同的崩潰。

這是該示例的精簡版本,有時在播放設備之間切換時會導致崩潰。 我通常會在設備之間來回切換約2分鍾內收到崩潰信息。 YMMV。

#include <windows.h>
#include <atlbase.h>
#include <stdio.h>
#include <mmdeviceapi.h>
#include <audiopolicy.h>
#include <endpointvolume.h>
#include <functiondiscoverykeys_devpkey.h>

#define LOG(format, ...) wprintf(format L"\n", __VA_ARGS__)

class CoUninitializeOnExit {
public:
    CoUninitializeOnExit() {}
    ~CoUninitializeOnExit() {
        CoUninitialize();
    }
};

class PropVariantClearOnExit {
public:
    PropVariantClearOnExit(PROPVARIANT *p) : m_p(p) {}
    ~PropVariantClearOnExit() {
        PropVariantClear(m_p);
    }
private:
    PROPVARIANT *m_p;
};

int _cdecl wmain() {
    HRESULT hr = S_OK;

    hr = CoInitialize(NULL);
    if (FAILED(hr)) {
        LOG(L"CoInitialize failed: hr = 0x%08x", hr);
        return -__LINE__;
    }
    CoUninitializeOnExit cuoe;

    while (1)
    {
      Sleep(5);
      // get default device
      CComPtr<IMMDeviceEnumerator> pMMDeviceEnumerator;
      hr = pMMDeviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
      if (FAILED(hr)) {
        LOG(L"CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x", hr);
        return -__LINE__;
      }

      CComPtr<IMMDevice> pMMDevice;
      hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pMMDevice);
      if (FAILED(hr)) {
        LOG(L"IMMDeviceEnumerator::GetDefaultAudioEndpoint failed: hr = 0x%08x", hr);
        return -__LINE__;
      }

      // get the name of the endpoint
      CComPtr<IPropertyStore> pPropertyStore;
      hr = pMMDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
      if (FAILED(hr)) {
        LOG(L"IMMDevice::OpenPropertyStore failed: hr = 0x%08x", hr);
        return -__LINE__;
      }

      PROPVARIANT v; PropVariantInit(&v);
      PropVariantClearOnExit pvcoe(&v);
      hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &v);
      if (FAILED(hr)) {
        LOG(L"IPropertyStore::GetValue(PKEY_Device_FriendlyName) failed: hr = 0x%08x", hr);
        return -__LINE__;
      }
      if (VT_LPWSTR != v.vt) {
        LOG(L"PKEY_Device_FriendlyName has unexpected vartype %u", v.vt);
        return -__LINE__;
      }

      LOG(L"Selected playback device: %s\n", v.pwszVal);

      // get a session enumerator
      CComPtr<IAudioSessionManager2> pAudioSessionManager2;
      hr = pMMDevice->Activate(
        __uuidof(IAudioSessionManager2),
        CLSCTX_ALL,
        nullptr,
        reinterpret_cast<void **>(&pAudioSessionManager2)
      );
      if (FAILED(hr)) {
        LOG(L"IMMDevice::Activate(IAudioSessionManager2) failed: hr = 0x%08x", hr);
        return -__LINE__;
      }

      CComPtr<IAudioSessionEnumerator> pAudioSessionEnumerator;
      hr = pAudioSessionManager2->GetSessionEnumerator(&pAudioSessionEnumerator);
      if (FAILED(hr)) {
        LOG(L"IAudioSessionManager2::GetSessionEnumerator() failed: hr = 0x%08x", hr);
        return -__LINE__;
      }

      // iterate over all the sessions
      int count = 0;
      hr = pAudioSessionEnumerator->GetCount(&count);
      if (FAILED(hr)) {
        LOG(L"IAudioSessionEnumerator::GetCount() failed: hr = 0x%08x", hr);
        return -__LINE__;
      }

      for (int session = 0; session < count; session++) {
        // get the session control
        CComPtr<IAudioSessionControl> pAudioSessionControl;
        hr = pAudioSessionEnumerator->GetSession(session, &pAudioSessionControl);
        if (FAILED(hr)) {
          LOG(L"IAudioSessionEnumerator::GetSession() failed: hr = 0x%08x", hr);
          return -__LINE__;
        }

        AudioSessionState state;
        hr = pAudioSessionControl->GetState(&state);
        if (FAILED(hr)) {
          LOG(L"IAudioSessionControl::GetState() failed: hr = 0x%08x", hr);
          return -__LINE__;
        }

        CComPtr<IAudioSessionControl2> pAudioSessionControl2;
        hr = pAudioSessionControl->QueryInterface(IID_PPV_ARGS(&pAudioSessionControl2));
        if (FAILED(hr)) {
          LOG(L"IAudioSessionControl::QueryInterface(IAudioSessionControl2) failed: hr = 0x%08x", hr);
          return -__LINE__;
        }

        DWORD pid = 0;
        hr = pAudioSessionControl2->GetProcessId(&pid);
        if (FAILED(hr)) {
          LOG(L"IAudioSessionControl2::GetProcessId() failed: hr = 0x%08x", hr);
          return -__LINE__;
        }

        hr = pAudioSessionControl2->IsSystemSoundsSession();
        if (FAILED(hr)) {
          LOG(L"IAudioSessionControl2::IsSystemSoundsSession() failed: hr = 0x%08x", hr);
          return -__LINE__;
        }

        bool bIsSystemSoundsSession = (S_OK == hr);

        // get the current audio peak meter level for this session
        CComPtr<IAudioMeterInformation> pAudioMeterInformation;
        hr = pAudioSessionControl->QueryInterface(IID_PPV_ARGS(&pAudioMeterInformation));
        if (FAILED(hr)) {
          LOG(L"IAudioSessionControl::QueryInterface(IAudioMeterInformation) failed: hr = 0x%08x", hr);
          return -__LINE__;
        }

        float peak = 0.0f;
        hr = pAudioMeterInformation->GetPeakValue(&peak);
        if (FAILED(hr)) {
          LOG(L"IAudioMeterInformation::GetPeakValue() failed: hr = 0x%08x", hr);
          return -__LINE__;
        }

        LOG(
          L"    Session #%d\n"
          L"        State: %d\n"
          L"        Peak value: %g\n"
          L"        Process ID: %u\n"
          L"        System sounds session: %s",
          session,
          state,
          peak,
          pid,
          (bIsSystemSoundsSession ? L"yes" : L"no")
        );

      } // session
    } // while

    return 0;
}

這是故障轉儲分析的一個實例: https : //pastebin.com/tvRV8ukY
Windows 7的Core Audio API實現是否存在此問題,或者我做錯了什么? 謝謝。

我最終通過電子郵件聯系了Matthew van Eerde,他說這的確像Windows 7上的Core Audio API中的競賽情況一樣,我最好的選擇是向Microsoft提出支持請求。
謝謝您的幫助,馬修!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM