minwave.cpp

来自「AC97 Sample Driver and Related Code Samp」· C++ 代码 · 共 1,667 行 · 第 1/5 页

CPP
1,667
字号
    IN      ULONG           OutputBufferLength,
    OUT     PVOID           ResultantFormat,
    OUT     PULONG          ResultantFormatLength
)
{
    PAGED_CODE ();

    DOUT (DBG_PRINT, ("[CMiniportWaveICH::DataRangeIntersection]"));

    //
    // This function gets only called if the GUIDS in the KSDATARANGE_AUDIO
    // structure that we attached to the pin are equal with the requested
    // format (see "BuildDataRangeInformation).
    // Additionally, for waveformatex portcls checks that the requested sample
    // frequency range fits into our exposed sample frequency range. Since we
    // only have discrete sample frequencies in the pin's data range, we don't
    // have to check that either.
    // There is one exception to this rule: portcls clones all WAVEFORMATEX
    // data ranges to DSOUND dataranges, so we might get a data range
    // intersection that has a DSOUND specifier. We don't support that
    // since this is only used for HW acceleration
    //
    if (IsEqualGUIDAligned (ClientsDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
    {
        DOUT (DBG_PRINT, ("[DataRangeIntersection] We don't support DSOUND specifier"));
        return STATUS_NOT_SUPPORTED;
    }
    
    //
    // Start with checking the size of the output buffer.
    //
    if (!OutputBufferLength) 
    {
        *ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
        return STATUS_BUFFER_OVERFLOW;
    } 
    
    if (OutputBufferLength < (sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX))) 
    {
        DOUT (DBG_WARNING, ("[DataRangeIntersection] Buffer too small"));
        return STATUS_BUFFER_TOO_SMALL;
    }
    
    //
    // We can only play or record multichannel (>=2 channels) except for the MIC
    // recording channel where we can only record mono. Portcls checked the channels
    // already, however, since we have no minimum channels field, the KSDATARANGE_AUDIO
    // could have MaximumChannels = 1.
    //
    if (PinId != PIN_MICIN)
    {
        // reject mono format for normal wave playback or capture.
        if (((PKSDATARANGE_AUDIO)ClientsDataRange)->MaximumChannels < 2)
        {
            DOUT (DBG_WARNING, ("[DataRangeIntersection] Mono requested for WaveIn or WaveOut"));
            return STATUS_NO_MATCH;
        }
    }

    //
    // Fill in the structure the datarange structure.
    // KSDATARANGE and KSDATAFORMAT are the same.
    //
    *(PKSDATAFORMAT)ResultantFormat = *MyDataRange;

    //
    // Modify the size of the data format structure to fit the WAVEFORMATPCMEX
    // structure.
    //
    ((PKSDATAFORMAT)ResultantFormat)->FormatSize =
        sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);

    //
    // Append the WAVEFORMATPCMEX structur.
    //
    PWAVEFORMATPCMEX WaveFormat = (PWAVEFORMATPCMEX)((PKSDATAFORMAT)ResultantFormat + 1);

    // We want a WAFEFORMATEXTENSIBLE which is equal to WAVEFORMATPCMEX.
    WaveFormat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
    // Set the number of channels
    if (PinId == PIN_WAVEOUT)
    {
        // Get the max. possible channels for playback.
        ULONG nMaxChannels = min (((PKSDATARANGE_AUDIO)ClientsDataRange)->MaximumChannels, m_wChannels);

        // We cannot play uneven number of channels
        if (nMaxChannels & 0x01)
            nMaxChannels--;
        // ... and also 0 channels wouldn't be a good request.
        if (!nMaxChannels)
            return STATUS_NO_MATCH;

        WaveFormat->Format.nChannels = (WORD)nMaxChannels;
    }
    else
        // This will be 2 for normal record and 1 for MIC record.
        WaveFormat->Format.nChannels = (WORD)((PKSDATARANGE_AUDIO)MyDataRange)->MaximumChannels;
    
    //
    // Hack for codecs that have only one sample rate converter that has both
    // playback and recording data.
    //
    if ((Streams[PIN_WAVEIN_OFFSET] || Streams[PIN_WAVEOUT_OFFSET]) &&
        !AdapterCommon->GetNodeConfig (NODEC_PCM_VSR_INDEPENDENT_RATES))
    {
        //
        // We have to return this sample rate that is used in the open stream.
        //
        ULONG   ulFrequency;

        if (Streams[PIN_WAVEIN_OFFSET])
            ulFrequency = Streams[PIN_WAVEIN_OFFSET]->GetCurrentSampleRate();
        else
            ulFrequency = Streams[PIN_WAVEOUT_OFFSET]->GetCurrentSampleRate();

        //
        // Check if this sample rate is in the requested data range of the client.
        //
        if ((((PKSDATARANGE_AUDIO)ClientsDataRange)->MaximumSampleFrequency < ulFrequency) ||
            (((PKSDATARANGE_AUDIO)ClientsDataRange)->MinimumSampleFrequency > ulFrequency))
        {
            return STATUS_NO_MATCH;
        }

        WaveFormat->Format.nSamplesPerSec = ulFrequency;
    }
    else
    {
        // Since we have discrete frequencies in the data range, min = max.
        WaveFormat->Format.nSamplesPerSec = ((PKSDATARANGE_AUDIO)MyDataRange)->MaximumSampleFrequency;
    }
    
    // Will be 16.
    WaveFormat->Format.wBitsPerSample = (WORD)((PKSDATARANGE_AUDIO)MyDataRange)->MaximumBitsPerSample;
    // Will be 2 * channels.
    WaveFormat->Format.nBlockAlign = (WaveFormat->Format.wBitsPerSample * WaveFormat->Format.nChannels) / 8;
    // That is played in a sec.
    WaveFormat->Format.nAvgBytesPerSec = WaveFormat->Format.nSamplesPerSec * WaveFormat->Format.nBlockAlign;
    // WAVEFORMATPCMEX
    WaveFormat->Format.cbSize = 22;
    // We have as many valid bits as the bit depth is (16).
    WaveFormat->Samples.wValidBitsPerSample = WaveFormat->Format.wBitsPerSample;
    // Set the channel mask
    if (PinId == PIN_WAVEOUT)
    {
        // If we can play in our configuration, then set the channel mask
        if (WaveFormat->Format.nChannels == m_wChannels)
            // Set the playback channel mask to the current speaker config.
            WaveFormat->dwChannelMask = m_dwChannelMask;
        else
        {
            //
            // We have to set a channel mask.
            // nChannles can only be 4 if we are in 6 channel mode. In that
            // case it must be a QUAD configurations. The only other value
            // allowed is 2 channels, which defaults to stereo.
            //
            if (WaveFormat->Format.nChannels == 4)
                WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_QUAD;
            else
                WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
        }
    }
    else
    {
        // This will be KSAUDIO_SPEAKER_STEREO for normal record and KSAUDIO_SPEAKER_MONO
        // for MIC record.
        if (PinId == PIN_MICIN)
            // MicIn -> 1 channel
            WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_MONO;
        else
            // normal record -> 2 channels
            WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
    }
    // Here we specify the subtype of the WAVEFORMATEXTENSIBLE.
    WaveFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

    // Now overwrite also the sample size in the ksdataformat structure.
    ((PKSDATAFORMAT)ResultantFormat)->SampleSize = WaveFormat->Format.nBlockAlign;
    
    //
    // That we will return.
    //
    *ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
    
    DOUT (DBG_STREAM, ("[DataRangeIntersection] Frequency: %d, Channels: %d, bps: %d, ChannelMask: %X",
          WaveFormat->Format.nSamplesPerSec, WaveFormat->Format.nChannels,
          WaveFormat->Format.wBitsPerSample, WaveFormat->dwChannelMask));

    // Let portcls do some work ...
    return STATUS_SUCCESS;
}


/*****************************************************************************
 * CMiniportWaveICH::TestDataFormat
 *****************************************************************************
 * Checks if the passed data format is known to the driver and verifies that
 * the number of channels, the width of one sample match to the AC97
 * specification.
 */
NTSTATUS CMiniportWaveICH::TestDataFormat
(
    IN  PKSDATAFORMAT Format,
    IN  WavePins      Pin
)
{
    PAGED_CODE ();

    ASSERT (Format);

    DOUT (DBG_PRINT, ("[CMiniportWaveICH::TestDataFormat]"));

    //
    // KSDATAFORMAT contains three GUIDs to support extensible format.  The
    // first two GUIDs identify the type of data.  The third indicates the
    // type of specifier used to indicate format specifics.  We are only
    // supporting PCM audio formats that use WAVEFORMATEX.
    //
    if (!IsEqualGUIDAligned (Format->MajorFormat, KSDATAFORMAT_TYPE_AUDIO) ||
        !IsEqualGUIDAligned (Format->SubFormat, KSDATAFORMAT_SUBTYPE_PCM)  ||
        !IsEqualGUIDAligned (Format->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
    {
        DOUT (DBG_ERROR, ("[TestDataFormat] Invalid format type!"));
        return STATUS_INVALID_PARAMETER;
    }

    PWAVEFORMATPCMEX waveFormat = (PWAVEFORMATPCMEX)(Format + 1);

    //
    // If the size doesn't match, then something is messed up.
    //
    if (Format->FormatSize < (sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX)))
    {
        DOUT (DBG_WARNING, ("[TestDataFormat] Invalid FormatSize!"));
        return STATUS_INVALID_PARAMETER;
    }
            
    //
    // We only support PCM, 16-bit.
    //
    if (waveFormat->Format.wBitsPerSample != 16)
    {
        DOUT (DBG_WARNING, ("[TestDataFormat] Bits Per Sample must be 16!"));
        return STATUS_INVALID_PARAMETER;
    }
    
    //
    // We support WaveFormatPCMEX (=WAVEFORMATEXTENSIBLE) or WaveFormatPCM.
    //
    if ((waveFormat->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) &&
        (waveFormat->Format.wFormatTag != WAVE_FORMAT_PCM))
    {
        DOUT (DBG_WARNING, ("[TestDataFormat] Invalid Format Tag!"));
        return STATUS_INVALID_PARAMETER;
    }

    //
    // Make additional checks for the WAVEFORMATEXTENSIBLE
    //
    if (waveFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
    {
        //
        // If the size doesn't match, then something is messed up.
        //
        if (Format->FormatSize < (sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX)))
        {
            DOUT (DBG_WARNING, ("[TestDataFormat] Invalid FormatSize!"));
            return STATUS_INVALID_PARAMETER;
        }
        
        //
        // Check also the subtype (PCM) and the size of the extended data.
        //
        if (!IsEqualGUIDAligned (waveFormat->SubFormat, KSDATAFORMAT_SUBTYPE_PCM) ||
            (waveFormat->Format.cbSize < (sizeof(WAVEFORMATPCMEX) - sizeof(WAVEFORMATEX))))
        {
            DOUT (DBG_WARNING, ("[TestDataFormat] Unsupported WAVEFORMATEXTENSIBLE!"));
            return STATUS_INVALID_PARAMETER;
        }

        //
        // Check the channel mask. We support 1, 2 channels or whatever was set
        // with the Speaker config dialog.
        //
        if (((waveFormat->Format.nChannels == 1) &&
             (waveFormat->dwChannelMask != KSAUDIO_SPEAKER_MONO)) ||
            ((waveFormat->Format.nChannels == 2) &&
             (waveFormat->dwChannelMask != KSAUDIO_SPEAKER_STEREO)) ||
            ((waveFormat->Format.nChannels == m_wChannels) &&
             (waveFormat->dwChannelMask != m_dwChannelMask)))
        {
            DOUT (DBG_WARNING, ("[TestDataFormat] Channel Mask!"));
            return STATUS_INVALID_PARAMETER;
        }
    }
        
    //
    // Check the number of channels.
    //
    switch (Pin)
    {
        case PIN_MICIN:     // 1 channel
            if (waveFormat->Format.nChannels != 1)
            {
                DOUT (DBG_WARNING, ("[TestDataFormat] Invalid Number of Channels for PIN_MICIN!"));
                return STATUS_INVALID_PARAMETER;
            }
            break;
        case PIN_WAVEIN:    // 2 channels
            if (waveFormat->Format.nChannels != 2)
            {
                DOUT (DBG_WARNING, ("[TestDataFormat] Invalid Number of Channels for PIN_WAVEIN!"));
                return STATUS_INVALID_PARAMETER;
            }
            break;
        case PIN_WAVEOUT:   // channel and mask from PropertyChannelConfig or standard.
            if (waveFormat->Format.nChannels != m_wChannels)
            {
                DOUT (DBG_WARNING, ("[TestDataFormat] Invalid Number of Channels for PIN_WAVEOUT!"));
                return STATUS_INVALID_PARAMETER;
            }
            break;
    }
    
    //
    // Print the information.
    //
    if (waveFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
    {
        DOUT (DBG_STREAM, ("[TestDataFormat] PCMEX - Frequency: %d, Channels: %d, bps: %d, ChannelMask: %X",
              waveFormat->Format.nSamplesPerSec, waveFormat->Format.nChannels,
              waveFormat->Format.wBitsPerSample, waveFormat->dwChannelMask));
    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?