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 + -
显示快捷键?