📄 minwave.cpp
字号:
#endif
}
break;
case WAVE_FORMAT_DOLBY_AC3_SPDIF:
if ((PinID != PIN_WAVE_AC3_RENDER_SINK) && (PinID != -1)) {
return STATUS_INVALID_PARAMETER;
}
if ( ((waveFormat->wBitsPerSample >= MIN_BITS_PER_SAMPLE_AC3) && (waveFormat->wBitsPerSample <= MAX_BITS_PER_SAMPLE_AC3))
&& ((waveFormat->nSamplesPerSec >= MIN_SAMPLE_RATE_AC3) && (waveFormat->nSamplesPerSec <= MAX_SAMPLE_RATE_AC3))
&& (waveFormat->nChannels == MAX_CHANNELS_AC3) ) {
return isFormatAllowed(waveFormat->nSamplesPerSec, FALSE, TRUE);
}
break;
}
}
return STATUS_INVALID_PARAMETER;
}
// Tests a data range intersection
STDMETHODIMP CMiniportWaveCMI::DataRangeIntersection(ULONG PinId, PKSDATARANGE ClientDataRange, PKSDATARANGE MyDataRange, ULONG OutputBufferLength, PVOID ResultantFormat, PULONG ResultantFormatLength)
{
PAGED_CODE();
DBGPRINT(("CMiniportWaveCMI[%p]::DataRangeIntersection(%d, %p, %p, %d, %p, %p)", this, PinId, ClientDataRange, MyDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength));
if (PinId == PIN_WAVE_AC3_RENDER_SINK) {
bool isAC3Pin = true;
// Under Windows 2000 and XP, the client's DataRange should be AC3 only.
// The AC3 pin is the SPDIF pin in Windows Vista, so 2ch stereo is going to be allowed.
if (!IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_AUDIO)
&& !IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD)) {
return STATUS_NO_MATCH;
}
if (!IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF)
&& !IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD)) {
// check for Vista
isAC3Pin = false;
if (IoIsWdmVersionAvailable(0x06,0x00)) {
if (!IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_PCM)
&& !IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD)) {
return STATUS_NO_MATCH;
}
} else {
return STATUS_NO_MATCH;
}
}
if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
|| IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD)) {
*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
} else
if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
*ResultantFormatLength = sizeof(KSDATAFORMAT_DSOUND);
} else {
return STATUS_NO_MATCH;
}
// Validate return buffer size, if the request is only for the
// size of the resultant structure, return it now.
if (!OutputBufferLength) {
*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
return STATUS_BUFFER_OVERFLOW;
} else
if (OutputBufferLength < sizeof(KSDATAFORMAT_WAVEFORMATEX)) {
return STATUS_BUFFER_TOO_SMALL;
}
PKSDATAFORMAT_WAVEFORMATEX resultantFormatWFX = (PKSDATAFORMAT_WAVEFORMATEX) ResultantFormat;
PWAVEFORMATEX pWaveFormatEx;
// Return the best (only) available format.
resultantFormatWFX->DataFormat.FormatSize = *ResultantFormatLength;
resultantFormatWFX->DataFormat.Flags = 0;
resultantFormatWFX->DataFormat.SampleSize = 4; // must match nBlockAlign
resultantFormatWFX->DataFormat.Reserved = 0;
resultantFormatWFX->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
INIT_WAVEFORMATEX_GUID(&resultantFormatWFX->DataFormat.SubFormat, WAVE_FORMAT_DOLBY_AC3_SPDIF);
// Extra space for the DSound specifier
if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
PKSDATAFORMAT_DSOUND resultantFormatDSound = (PKSDATAFORMAT_DSOUND)ResultantFormat;
resultantFormatDSound->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_DSOUND;
// DSound format capabilities are not expressed
// this way in KS, so we express no capabilities.
resultantFormatDSound->BufferDesc.Flags = 0 ;
resultantFormatDSound->BufferDesc.Control = 0 ;
pWaveFormatEx = &resultantFormatDSound->BufferDesc.WaveFormatEx;
} else {
// WAVEFORMATEX or WILDCARD (WAVEFORMATEX)
resultantFormatWFX->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
pWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT)resultantFormatWFX + 1);
}
pWaveFormatEx->nChannels = 2;
pWaveFormatEx->wBitsPerSample = 16; // SPDIF
pWaveFormatEx->cbSize = 0;
if (isAC3Pin) {
pWaveFormatEx->wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
pWaveFormatEx->nSamplesPerSec = 48000;
} else {
pWaveFormatEx->wFormatTag = WAVE_FORMAT_PCM;
pWaveFormatEx->nSamplesPerSec = min( ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency, MAX_SAMPLE_RATE);
}
pWaveFormatEx->nBlockAlign = pWaveFormatEx->nChannels * pWaveFormatEx->wBitsPerSample / 8;
pWaveFormatEx->nAvgBytesPerSec = pWaveFormatEx->nSamplesPerSec * pWaveFormatEx->nBlockAlign;
return STATUS_SUCCESS;
}
if ((PinId == PIN_WAVE_RENDER_SINK) || (PinId == PIN_WAVE_CAPTURE_SINK)) {
if (!IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_PCM) &&
!IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD)) {
return STATUS_NO_MATCH;
}
if (!IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_AUDIO) &&
!IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD)) {
return STATUS_NO_MATCH;
}
if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD)) {
*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
} else
if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
*ResultantFormatLength = sizeof(KSDATAFORMAT_DSOUND);
} else {
return STATUS_NO_MATCH;
}
ULONG sampleRate = 0;
ULONG nMaxChannels = min(((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels, requestedChannelCount);
// check for Vista
if (IoIsWdmVersionAvailable(6,0) && (PinId == PIN_WAVE_RENDER_SINK)) {
nMaxChannels = ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels;
}
if (nMaxChannels & 0x01) {
nMaxChannels--;
}
if (!nMaxChannels) {
return STATUS_NO_MATCH;
}
if (isStreamRunning[PCM_OUT_STREAM]) {
sampleRate = stream[PCM_OUT_STREAM]->currentSampleRate;
} else
if (isStreamRunning[PCM_IN_STREAM]) {
sampleRate = stream[PCM_IN_STREAM]->currentSampleRate;
}
if (sampleRate == 0) {
if ((nMaxChannels > 2) && (((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency > MAX_SAMPLE_RATE_MULTI)) {
sampleRate = MAX_SAMPLE_RATE_MULTI;
} else
if ((nMaxChannels == 2) && (((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency > MAX_SAMPLE_RATE)) {
sampleRate = MAX_SAMPLE_RATE;
} else {
sampleRate = ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency;
}
}
if ((((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumSampleFrequency < sampleRate)
|| (((PKSDATARANGE_AUDIO)ClientDataRange)->MinimumSampleFrequency > sampleRate)) {
return STATUS_NO_MATCH;
}
if (PinId == PIN_WAVE_RENDER_SINK) {
if (!OutputBufferLength) {
*ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
return STATUS_BUFFER_OVERFLOW;
} else
if (OutputBufferLength < sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX)) {
return STATUS_BUFFER_TOO_SMALL;
}
if (((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels < 2) {
DBGPRINT(("[[DataRangeIntersection] mono format not supported"));
return STATUS_NO_MATCH;
}
PWAVEFORMATPCMEX WaveFormat = (PWAVEFORMATPCMEX)((PKSDATAFORMAT)ResultantFormat + 1);
if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
return STATUS_NOT_SUPPORTED;
}
*(PKSDATAFORMAT)ResultantFormat = *MyDataRange;
((PKSDATAFORMAT)ResultantFormat)->FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
WaveFormat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
WaveFormat->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
WaveFormat->Format.nChannels = (WORD)nMaxChannels;
WaveFormat->Format.wBitsPerSample = 16;
WaveFormat->Format.nBlockAlign = (WaveFormat->Format.wBitsPerSample >> 3) * WaveFormat->Format.nChannels;
WaveFormat->Format.nAvgBytesPerSec = WaveFormat->Format.nSamplesPerSec * WaveFormat->Format.nBlockAlign;
WaveFormat->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
WaveFormat->Format.nSamplesPerSec = sampleRate;
WaveFormat->Samples.wValidBitsPerSample = WaveFormat->Format.wBitsPerSample;
switch (nMaxChannels) {
case 8: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; break;
case 6: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break;
case 4: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_QUAD; break;
case 2: WaveFormat->dwChannelMask = KSAUDIO_SPEAKER_STEREO; break;
}
if (nMaxChannels == requestedChannelCount) {
WaveFormat->dwChannelMask = requestedChannelMask;
}
((PKSDATAFORMAT)ResultantFormat)->SampleSize = WaveFormat->Format.nBlockAlign;
*ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
DBGPRINT(("[DataRangeIntersection] MultiChannel Renderer: SampleRate: %d, ClientDataRange->MaxChans: %d, Channels: %d, BitPerSample: %d, BlockAlign: %d, AvgBytesPerSec: %d, ChannelMask: %08X", WaveFormat->Format.nSamplesPerSec, ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels, WaveFormat->Format.nChannels, WaveFormat->Format.wBitsPerSample, WaveFormat->Format.nBlockAlign, WaveFormat->Format.nAvgBytesPerSec, WaveFormat->dwChannelMask));
} else
if (PinId == PIN_WAVE_CAPTURE_SINK) {
PKSDATAFORMAT_WAVEFORMATEX resultantFormatWFX;
PWAVEFORMATEX pWaveFormatEx;
if (!OutputBufferLength) {
*ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
return STATUS_BUFFER_OVERFLOW;
} else
if (OutputBufferLength < sizeof(KSDATAFORMAT_WAVEFORMATEX)) {
return STATUS_BUFFER_TOO_SMALL;
}
if (nMaxChannels > 2) {
nMaxChannels = 2;
}
resultantFormatWFX = (PKSDATAFORMAT_WAVEFORMATEX) ResultantFormat;
resultantFormatWFX->DataFormat.FormatSize = *ResultantFormatLength;
resultantFormatWFX->DataFormat.Flags = 0;
resultantFormatWFX->DataFormat.SampleSize = 4;
resultantFormatWFX->DataFormat.Reserved = 0;
resultantFormatWFX->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
INIT_WAVEFORMATEX_GUID(&resultantFormatWFX->DataFormat.SubFormat, WAVE_FORMAT_PCM);
if (IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND)) {
PKSDATAFORMAT_DSOUND resultantFormatDSound;
resultantFormatDSound = (PKSDATAFORMAT_DSOUND)ResultantFormat;
resultantFormatDSound->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_DSOUND;
resultantFormatDSound->BufferDesc.Flags = 0 ;
resultantFormatDSound->BufferDesc.Control = 0 ;
pWaveFormatEx = &resultantFormatDSound->BufferDesc.WaveFormatEx;
} else {
resultantFormatWFX->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
pWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT)resultantFormatWFX + 1);
}
pWaveFormatEx->wFormatTag = WAVE_FORMAT_PCM;
pWaveFormatEx->nChannels = nMaxChannels;
pWaveFormatEx->nSamplesPerSec = sampleRate;
pWaveFormatEx->wBitsPerSample = 16;
pWaveFormatEx->cbSize = 0;
pWaveFormatEx->nBlockAlign = 4;
pWaveFormatEx->nAvgBytesPerSec = 192000;
}
return STATUS_SUCCESS;
}
return STATUS_NO_MATCH;
}
//from IMiniportWaveCyclic::NewStream()
#ifdef WAVERT
STDMETHODIMP CMiniportWaveCMI::NewStream(PMINIPORTWAVERTSTREAM *OutStream, PPORTWAVERTSTREAM OuterUnknown, ULONG PinID, BOOLEAN Capture, PKSDATAFORMAT DataFormat)
#else
STDMETHODIMP CMiniportWaveCMI::NewStream(PMINIPORTWAVECYCLICSTREAM *OutStream, PUNKNOWN OuterUnknown, POOL_TYPE PoolType, ULONG PinID, BOOLEAN Capture, PKSDATAFORMAT DataFormat, PDMACHANNEL* OutDmaChannel, PSERVICEGROUP* OutServiceGroup)
#endif
{
PAGED_CODE();
ASSERT(OutStream);
ASSERT(DataFormat);
#ifdef WAVERT
DBGPRINT(("CMiniportWaveCMI[%p]::NewStream(%p, %p, %d, %d, %p)", this, OutStream, OuterUnknown, PinID, Capture, DataFormat));
#else
ASSERT(OutDmaChannel);
ASSERT(OutServiceGroup);
DBGPRINT(("CMiniportWaveCMI[%p]::NewStream(%p, %p, %p, %d, %d, %p, %p, %p)", this, OutStream, OuterUnknown, PoolType, PinID, Capture, DataFormat, OutDmaChannel, OutServiceGroup));
#endif
NTSTATUS ntStatus = STATUS_SUCCESS;
PWAVEFORMATEX waveFormat = PWAVEFORMATEX(DataFormat + 1);
UInt32 streamIndex = PCM_OUT_STREAM;
ntStatus = validateFormat(DataFormat, PinID, Capture);
if (!NT_SUCCESS(ntStatus)) {
DBGPRINT(("invalid stream format"));
return STATUS_UNSUCCESSFUL;
}
CMIAdapter->setUInt8Bit(REG_MIXER1, EN_SPDI2DAC);
if (Capture) {
streamIndex = PCM_IN_STREAM;
} else if (WAVE_FORMAT_DOLBY_AC3_SPDIF == EXTRACT_WAVEFORMATEX_ID(&DataFormat->SubFormat)) {
streamIndex = AC3_OUT_STREAM;
}
// make sure the hardware is not already in use
if (isStreamRunning[streamIndex]) {
DBGPRINT(("Stream %d running, exiting...", streamIndex));
return STATUS_UNSUCCESSFUL;
}
if ((streamIndex == AC3_OUT_STREAM) && isStreamRunning[PCM_OUT_STREAM]) {
stream[PCM_OUT_STREAM]->SetState(KSSTATE_STOP_AC3);
}
if ((streamIndex == PCM_OUT_STREAM) && isStreamRunning[AC3_OUT_STREAM]) {
return STATUS_UNSUCCESSFUL;
}
DBGPRINT(("---StreamNo: %d, Bits: %d, Sample Rate: %d, Channels: %d, AC3: %d", streamIndex,
waveFormat->wBitsPerSample, waveFormat->nSamplesPerSec, waveFormat->nChannels,
(WAVE_FORMAT_DOLBY_AC3_SPDIF == EXTRACT_WAVEFORMATEX_ID(&DataFormat->SubFormat))));
// the DAC and ADC can only run at the same sample rate simultaneously
if ((streamIndex == PCM_IN_STREAM) && isStreamRunning[PCM_OUT_STREAM]) {
if (waveFormat->nSamplesPerSec != stream[PCM_OUT_STREAM]->currentSampleRate) {
return STATUS_UNSUCCESSFUL;
}
}
if ((streamIndex == PCM_OUT_STREAM) && isStreamRunning[PCM_IN_STREAM]) {
if (waveFormat->nSamplesPerSec != stream[PCM_IN_STREAM]->currentSampleRate) {
return STATUS_UNSUCCESSFUL;
}
}
// instantiate a stream
#ifdef WAVERT
ntStatus = CreateMiniportWaveStreamCMI(&stream[streamIndex], OuterUnknown, NonPagedPool);
#else
ntStatus = CreateMiniportWaveStreamCMI(&stream[streamIndex], OuterUnknown, PoolType);
#endif
if (!NT_SUCCESS (ntStatus)) {
DBGPRINT(("Failed to create stream"));
return ntStatus;
}
// initialize it
#ifdef WAVERT
ntStatus = stream[streamIndex]->Init(this, streamIndex, Capture, DataFormat, OuterUnknown);
#else
ntStatus = stream[streamIndex]->Init(this, streamIndex, Capture, DataFormat, DMAChannel[streamIndex], OutServiceGroup);
#endif
if (!NT_SUCCESS(ntStatus)) {
DBGPRINT(("Failed to init stream"));
stream[streamIndex]->Release();
stream[streamIndex] = NULL;
*OutStream = NULL;
#ifndef WAVERT
*OutServiceGroup = NULL;
*OutDmaChannel = NULL;
#endif
return ntStatus;
}
#ifdef WAVERT
//this has been referenced in CreateMiniportWaveStreamCMI() already
*OutStream = (PMINIPORTWAVERTSTREAM)stream[streamIndex];
#else
*OutDmaChannel = DMAChannel[streamIndex];
DMAChannel[streamIndex]->AddRef();
*OutStream = (PMINIPORTWAVECYCLICSTREAM)stream[streamIndex];
#endif
return ntStatus;
}
static NTSTATUS PropertyHandler_ChannelConfig(PPCPROPERTY_REQUEST PropertyRequest)
{
PAGED_CODE();
ASSERT(PropertyRequest);
DBGPRINT(("[PropertyHandler_ChannelConfig]"));
#ifdef WAVERT
CMiniportWaveCMI *that = (CMiniportWaveCMI *) ((PMINIPORTWAVERT)PropertyRequest->MajorTarget);
#else
CMiniportWaveCMI *that = (CMiniportWaveCMI *) ((PMINIPORTWAVECYCLIC)PropertyRequest->MajorTarget);
#endif
if (PropertyRequest->Node == KSNODE_WAVE_DAC) {
if (PropertyRequest->ValueSize == 0) {
PropertyRequest->ValueSize = sizeof(LONG);
return STATUS_BUFFER_OVERFLOW;
} else if (PropertyRequest->ValueSize < sizeof (LONG)) {
PropertyRequest->ValueSize = 0;
return STATUS_BUFFER_TOO_SMALL;
}
if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET) {
*(PLONG)PropertyRequest->Value = that->requestedChannelMask;
PropertyRequest->ValueSize = sizeof(ULONG);
return STATUS_SUCCESS;
} else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET) {
if (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_7POINT1) {
that->requestedChannelMask = *(PLONG)PropertyRequest->Value;
that->requestedChannelCount = 8;
return STATUS_SUCCESS;
}
if (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_5POINT1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -