Separate pin-factories for Float and PCM

Hello,

I am making a virtual microphone and I’m struggling to make 32 Bit floats work. Well actually, they are working fine, but the certification tests do not pass.

The supported device formats are defined as follows:

#define BITS_PER_SAMPLE                	32     
#define SAMPLE_RATE                	    48000   

static
KSDATAFORMAT_WAVEFORMATEXTENSIBLE MicPinSupportedDeviceFormats[] =
{
	// 48 KHz 32-bit 1 channel FLOAT
    {
        {
            sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
            0,
            0,
            0,
            STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
            STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT),
            STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
        },
        {
            {
                WAVE_FORMAT_EXTENSIBLE,
                1,                                          
                SAMPLE_RATE,                               
                192000,                                     
                4,                                          
                BITS_PER_SAMPLE,                               
                sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
            },
            BITS_PER_SAMPLE,                                     
            KSAUDIO_SPEAKER_MONO,                           
            STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) 
        }
    },

   	// 48 KHz 32-bit 1 channel PCM
    {
        {
            sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
            0,
            0,
            0,
            STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
            STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), 
            STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
        },
        {
            {
                WAVE_FORMAT_EXTENSIBLE,
                1,
                SAMPLE_RATE,
                192000,
                4,
                BITS_PER_SAMPLE, 
                sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
            },
            BITS_PER_SAMPLE,
            KSAUDIO_SPEAKER_MONO, 
            STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
        }
    },
};

static
MODE_AND_DEFAULT_FORMAT MicPinSupportedDeviceModes[] =
{
    {
        STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
        &MicPinSupportedDeviceFormats[0].DataFormat
    },
    {
        STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
        &MicPinSupportedDeviceFormats[1].DataFormat
    },
};

static
PIN_DEVICE_FORMATS_AND_MODES MicPinDeviceFormatsAndModes[] =
{
    {
        BridgePin,
        NULL,
        0,
        NULL,
        0
    },
    {
        SystemCapturePin,
        MicPinSupportedDeviceFormats,
        SIZEOF_ARRAY(MicPinSupportedDeviceFormats),
        MicPinSupportedDeviceModes,
        SIZEOF_ARRAY(MicPinSupportedDeviceModes)
    },
};

Now I don’t actually need PCM because I’m feeding my data into the driver as floats, but without the PCM format support the microphone never shows up in the device manager. PCM alone works, but floats doesn’t. I guess Windows requires the driver to support PCM, I think Tim Roberts mentioned that somewhere.

Anyway, I continue to define the KSDATARANGE_AUDIO separately, one range for floats, one range for PCM:

static
KSDATARANGE_AUDIO MicPinDataRangesRawStream[] =
{
   {
        {
            sizeof(KSDATARANGE_AUDIO),
            KSDATARANGE_ATTRIBUTES,        
            0,
            0,
            STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
            STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT),
            STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
        },
        1,
        BITS_PER_SAMPLE,
        BITS_PER_SAMPLE,
        SAMPLE_RATE,
        SAMPLE_RATE
    },
    {
        {
            sizeof(KSDATARANGE_AUDIO),
            KSDATARANGE_ATTRIBUTES,
            0,
            0,
            STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
            STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
            STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
        },
        1,
        BITS_PER_SAMPLE,
        BITS_PER_SAMPLE,
        SAMPLE_RATE,
        SAMPLE_RATE
    },

};

While the driver works fine like this, it fails the KS Topology test, because “the mode guids should not appear more than once each per pin factory”. I also read in the Windows documentation that to support non-PCM formats, you have to have multiple pin factories.

So I decided to let the driver have two pin factories, one for PCM and one for floats.

static
PKSDATARANGE MicPinDataRangePointersStreamFloats[] =
{
    PKSDATARANGE(&MicPinDataRangesRawStream[0]),
    PKSDATARANGE(&PinDataRangeAttributeList),
};

static
PKSDATARANGE MicPinDataRangePointersStreamPCM[] =
{
    PKSDATARANGE(&MicPinDataRangesRawStream[1]),
    PKSDATARANGE(&PinDataRangeAttributeList),
};

(...)

static
PCPIN_DESCRIPTOR MicWaveMiniportPins[] =
{
    // Wave In Bridge Pin (Capture - From Topology) KSPIN_WAVE_BRIDGE
    {
        0,
        0,
        0,
        NULL,
        {
            0,
            NULL,
            0,
            NULL,
            SIZEOF_ARRAY(MicPinDataRangePointersBridge),
            MicPinDataRangePointersBridge,
            KSPIN_DATAFLOW_IN,
            KSPIN_COMMUNICATION_NONE,
            &KSCATEGORY_AUDIO,
            NULL,
            0
        }
    },

    // Capture: KSPIN_WAVE_FLOAT
    {
        1,
        1,
        0,
        NULL,
        {
            0,
            NULL,
            0,
            NULL,
            SIZEOF_ARRAY(MicPinDataRangePointersStreamFloats),
            MicPinDataRangePointersStreamFloats,
            KSPIN_DATAFLOW_OUT,
            KSPIN_COMMUNICATION_SINK,
            &KSCATEGORY_AUDIO,
            &KSAUDFNAME_RECORDING_CONTROL,
            0
        }
    },

    // Capture: KSPIN_WAVE_PCM
    {
        1,
        1,
        0,
        NULL,
        {
            0,
            NULL,
            0,
            NULL,
            SIZEOF_ARRAY(MicPinDataRangePointersStreamPCM),
            MicPinDataRangePointersStreamPCM,
            KSPIN_DATAFLOW_OUT,
            KSPIN_COMMUNICATION_SINK,
            &KSCATEGORY_AUDIO,
            NULL,
            0
        }
    },
};

The name for the PCM pins is NULL because apparently Windows defines the pins uniquely via category+name, so as far as I understand the factories must not be identical in that regard.

static
PCCONNECTION_DESCRIPTOR MicWaveMiniportConnections[] =
{
    { PCFILTER_NODE,        KSPIN_WAVE_BRIDGE,      KSNODE_WAVE_ADC,     1 },
    { KSNODE_WAVE_ADC,      0,                      PCFILTER_NODE,       KSPIN_WAVEIN_FLOAT },
    { KSNODE_WAVE_ADC,      0,                      PCFILTER_NODE,       KSPIN_WAVEIN_PCM },
};

However, the system freezes when trying to install. Looking at the dump in WinDbg doesn’t give me any clue what happened and setupapidev.log ends with the lines

     dvi:           Install Device: Configuring device completed. 19:10:26.714
     dvi:           Device Status: 0x01802001
     dvi:           Install Device: Starting device 'ROOT\VIRTUALMIC\0000'. 19:10:26.714
<ins>
àà;·ˆ\Íù; \=    ààç#ŠöCp; Äù;       

What am I doing wrong and more importantly, how can I do it right?

Lucas