【问题标题】:How to get Audio Formats supported by physical device (WinAPI, Windows)如何获取物理设备支持的音频格式(WinAPI、Windows)
【发布时间】:2018-10-28 00:05:50
【问题描述】:

我有一个音频设备(USB 麦克风),我想找出它本机支持的音频格式(位深度和采样率),在 OS X 上有一个不错的 kAudioStreamPropertyAvailablePhysicalFormats Core Audio 属性,但我找不到在 Windows 上类似。

我知道有这个问题Windows Core Audio Api get all supported formats on capture device 但是

  • 答案很糟糕……而且我不受 Windows Core Audio API 的限制,我需要任何方法。

  • Windows 本身以某种方式知道它,因此很可能应该有一种方法,例如通过 IOCTL,DirectShow 或 WMI 或其他方式。

  • 可能有一种方法可以在 Windows 上进行 Spy 以找出它用于枚举格式的方法,但我不知道如何做到这一点。

【问题讨论】:

  • 答案有什么不好?您是否期望捕获设备本机支持的支持的捕获格式会根据用于查询它们的 API 而改变?如果是,为什么?
  • @IInspectable:IAudioClient::IsFormatSupported 的问题是你不能像在 Mac 上那样对设备说“告诉我你能做的所有事情”。取而代之的是,您必须在黑暗中投篮,直到命中。这让我最近遇到了一个only支持4通道的设备。由于我的代码只检查 1 和 2 通道,它根本不相信设备可以做任何事情。我有一些可以发布的替代代码。当我在办公桌前时我会这样做(失眠)。
  • 赞成。这是一个完全公平的问题,如果措辞有点混乱。
  • @PaulSanders:这可能是一个有效的担忧,但它根本不是这个问题所要求的,而且我很难将其读入问题中。但如果这确实是 OP 所追求的,那么这个问题应该因为不清楚而被否决。
  • @IInspectable:这对我来说很清楚,但我确实有该领域的经验。请记住,英语似乎不是 OP 的第一语言。你不应该仅仅为此投反对票——它会让人们失望。

标签: winapi wdk wasapi


【解决方案1】:

好的,这里有一些示例代码供您参考。信息就在那里,分散在网络上,但你必须搜索它。谷歌我在下面调用的函数和一些奇怪的清单常量以了解更多信息。用记事本编写的代码,可能无法编译。

下面的代码查询默认输入/输出设备。要获取安装在任何特定系统上的所有设备的 device_id,请调用 waveInGetNumDevswaveOutGetNumDevs 并从 0 开始计数。

#define INITGUID

#include "Ks.h"
#include "KsMedia.h"
#include "mmdeviceapi.h"


// Open a query handle for the default input or output device
// Call Closehandle when done.
static HANDLE QueryOpen (bool input)
{
    DWORD device_id, device_status;
    DWORD err = (input) ?
        waveInMessage ((HWAVEIN) (INT_PTR) WAVE_MAPPER,
            DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) &device_id, (DWORD_PTR) &device_status) :
        waveOutMessage ((HWAVEOUT) (INT_PTR) WAVE_MAPPER,
            DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) &device_id, (DWORD_PTR) &device_status);
    if (err)
        return INVALID_HANDLE_VALUE;

    DWORD devicePathSize;
    DWORD mm_result = (input) ? 
        waveInMessage ((HWAVEIN) (INT_PTR) device_id, DRV_QUERYDEVICEINTERFACESIZE,
            (DWORD_PTR) &devicePathSize, 0) :
        waveOutMessage ((HWAVEOUT) (INT_PTR) device_id, DRV_QUERYDEVICEINTERFACESIZE,
            (DWORD_PTR) &devicePathSize, 0);
    if (mm_result != 0)
        return INVALID_HANDLE_VALUE;

    /* apparently DRV_QUERYDEVICEINTERFACE returns a unicode interface path, although this is undocumented */
    WCHAR *devicePath = (WCHAR *) malloc (devicePathSize);

    mm_result = (input) ?
        waveInMessage ((HWAVEIN) (INT_PTR) device_id, DRV_QUERYDEVICEINTERFACE,
            (DWORD_PTR) devicePath, devicePathSize) :
        waveOutMessage ((HWAVEOUT) (INT_PTR) device_id, DRV_QUERYDEVICEINTERFACE,
            (DWORD_PTR) devicePath, devicePathSize);

    HANDLE result = (mm_result == 0) ? CreateFileW (devicePath, FILE_SHARE_READ | FILE_SHARE_WRITE,
        0, NULL, OPEN_EXISTING, 0, NULL) : INVALID_HANDLE_VALUE;

    free (devicePath);
    return result;
}


// Interrogate the default input / output device (demo code)
void InterrogateDefaultDevice (bool input)
{
    HANDLE hQuery = QueryOpen (input);
    if (hQuery == INVALID_HANDLE_VALUE)
        return;

    int pin_count = GetKSFilterPinCount (hQuery);

    for (int pinId = 0; pinId < pin_count; ++pinId)
    {
        KSPIN_COMMUNICATION communication = GetKSFilterPinPropertyCommunication (hQuery, pinId);
        KSPIN_DATAFLOW dataflow = GetKSFilterPinPropertyDataflow (h, pinId);

        if ((communication == KSPIN_COMMUNICATION_SINK || communication == KSPIN_COMMUNICATION_BOTH) &&
            (KSFilterPinPropertyIdentifiersInclude (hQuery, pinId, KSPROPERTY_PIN_INTERFACES,
                &KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_STREAMING) ||
             KSFilterPinPropertyIdentifiersInclude (hQuery, pinId, KSPROPERTY_PIN_INTERFACES,
                &KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_LOOPED_STREAMING)) &&
             KSFilterPinPropertyIdentifiersInclude (hQuery, pinId, KSPROPERTY_PIN_MEDIUMS,
                &KSMEDIUMSETID_Standard, KSMEDIUM_STANDARD_DEVIO))
        {
            KSMULTIPLE_ITEM *item = NULL;

            if (WdmGetPinPropertyMulti (hQuery, pinId, KSPROPERTY_PIN_DATARANGES, &item))
            {
                KSDATARANGE_AUDIO *dr = (KSDATARANGE_AUDIO *) (item + 1);

                for (ULONG i = 0; i < item->Count; ++i )
                {
                    printf ("%ul - %ul Hz (%ul - %ul bits per sample, upto %ul channels)\n",
                        dr->MinimumSampleFrequency, dr->MaximumSampleFrequency,
                        dr->MinimumBitsPerSample, dr->MaximumBitsPerSample, dr->MaximumChannels);

                    dr = (KSDATARANGE_AUDIO *) ((BYTE *) dr + dr->DataRange.FormatSize);
                }

                free (item);
            }
        }
    }

    CloseHandle (hQuery);
}

【讨论】:

  • 谢谢,它有效!它对我来说就像一个启示。对于以后可能会阅读此内容的人的一些提示:此处msdn.microsoft.com/en-us/library/windows/desktop/…(旧版 Windows 多媒体应用程序的设备角色)是如何从 Core Audio IMMDevice 获取 waveXXX 设备 ID 的代码示例。但是它有一个错误,请调用 cbEndpointId=0 或使用 DWORD 否则它将无法在 64 位中工作。作为第二个注意事项,上面列表中的函数需要端口音频的内部,它们是公开访问的,你需要 pa_win_wdmks_utils.c 从那里复制粘贴。
猜你喜欢
  • 1970-01-01
  • 2015-08-14
  • 2019-05-17
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2013-02-09
  • 2014-03-02
  • 1970-01-01
相关资源
最近更新 更多