Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

803 lines
24 KiB

//---------------------------------------------------------------------------
//
// Module: cni.cpp
//
// Description:
//
// Connect Node Instance
//
//@@BEGIN_MSINTERNAL
// Development Team:
// Mike McLaughlin
//
// History: Date Author Comment
//
// To Do: Date Author Comment
//
//@@END_MSINTERNAL
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
//
//---------------------------------------------------------------------------
#include "common.h"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
CConnectNodeInstance::CConnectNodeInstance(
IN PCONNECT_NODE pConnectNode
)
{
Assert(this);
pConnectNode->AddPinInstance();
pConnectNode->SetConnectNodeInstance(this);
this->pConnectNode = pConnectNode;
}
CConnectNodeInstance::~CConnectNodeInstance(
)
{
Assert(this);
DPF1(95, "~CConnectNodeInstance: %08x", this);
if(pConnectNode != NULL) {
Assert(pConnectNode);
pConnectNode->RemovePinInstance();
if(pConnectNode->GetConnectNodeInstance() == this) {
pConnectNode->SetConnectNodeInstance(NULL);
}
}
pPinNodeInstanceSource->Destroy();
pPinNodeInstanceSink->Destroy();
pFilterNodeInstanceSource->Destroy();
pFilterNodeInstanceSink->Destroy();
}
NTSTATUS
CConnectNodeInstance::Create(
PSTART_NODE_INSTANCE pStartNodeInstance,
PDEVICE_NODE pDeviceNode
)
{
PFILTER_NODE_INSTANCE *ppFilterNodeInstancePrevious;
PCONNECT_NODE_INSTANCE pConnectNodeInstance = NULL;
PLOGICAL_FILTER_NODE pLogicalFilterNode;
NTSTATUS Status = STATUS_SUCCESS;
BOOL fReuseFilterInstance = TRUE;
PCONNECT_NODE pConnectNode;
pLogicalFilterNode =
pStartNodeInstance->pStartNode->pPinNode->pLogicalFilterNode;
ppFilterNodeInstancePrevious = &pStartNodeInstance->pFilterNodeInstance;
for(pConnectNode = pStartNodeInstance->pStartNode->GetFirstConnectNode();
pConnectNode != NULL;
pConnectNode = pConnectNode->GetNextConnectNode()) {
Assert(pLogicalFilterNode);
Assert(pConnectNode);
// Get existing connect node instance
fReuseFilterInstance = pConnectNode->IsReuseFilterInstance();
pConnectNodeInstance = pConnectNode->GetConnectNodeInstance();
//
// Check if the connection already exits. For reusable connections
// (for example for kmixer-render connection) do not recreate the
// connection instance.
//
if(fReuseFilterInstance && pConnectNodeInstance != NULL) {
Assert(pConnectNodeInstance);
DPF4(100, "Existing CNI: %08x %d FNI Source: %08x FNI Sink %08x",
pConnectNodeInstance,
pConnectNodeInstance->cReference,
pConnectNodeInstance->pFilterNodeInstanceSource,
pConnectNodeInstance->pFilterNodeInstanceSink);
}
else {
if(!pConnectNode->IsPinInstances()) {
DPF1(90, "CCNI::Create: no instances CN %08x", pConnectNode);
Status = STATUS_DEVICE_BUSY;
goto exit;
}
pConnectNodeInstance = new CONNECT_NODE_INSTANCE(pConnectNode);
if(pConnectNodeInstance == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
pConnectNodeInstance->fRender = pStartNodeInstance->IsRender();
Status = CFilterNodeInstance::Create(
&pConnectNodeInstance->pFilterNodeInstanceSource,
pLogicalFilterNode,
pDeviceNode,
fReuseFilterInstance);
if(!NT_SUCCESS(Status)) {
delete pConnectNodeInstance;
goto exit;
}
Assert(pConnectNodeInstance->pFilterNodeInstanceSource);
DPF4(100, "New CNI: %08x %d FNI Source: %08x FNI Sink %08x",
pConnectNodeInstance,
pConnectNodeInstance->cReference,
pConnectNodeInstance->pFilterNodeInstanceSource,
pConnectNodeInstance->pFilterNodeInstanceSink);
}
Status = pConnectNodeInstance->AddListEnd(
&pStartNodeInstance->lstConnectNodeInstance);
if(!NT_SUCCESS(Status)) {
goto exit;
}
if(*ppFilterNodeInstancePrevious == NULL) {
*ppFilterNodeInstancePrevious =
pConnectNodeInstance->pFilterNodeInstanceSource;
pConnectNodeInstance->pFilterNodeInstanceSource->AddRef();
}
ppFilterNodeInstancePrevious =
&pConnectNodeInstance->pFilterNodeInstanceSink;
pLogicalFilterNode = pConnectNode->pPinNodeSink->pLogicalFilterNode;
}
//
// This is to cover a StartNode with no Connections. So this graph
// consists of a single filter and single pin. No connection are required.
//
if(*ppFilterNodeInstancePrevious == NULL) {
Assert(pLogicalFilterNode);
Status = CFilterNodeInstance::Create(
ppFilterNodeInstancePrevious,
pLogicalFilterNode,
pDeviceNode,
fReuseFilterInstance);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Assert(*ppFilterNodeInstancePrevious);
}
exit:
return(Status);
}
NTSTATUS
CConnectNodeInstance::AddListEnd(
PCLIST_MULTI plm
)
{
NTSTATUS Status;
Status = CListMultiItem::AddListEnd(plm);
if(NT_SUCCESS(Status)) {
AddRef();
}
return(Status);
}
ENUMFUNC
CConnectNodeInstance::Destroy(
)
{
if(this != NULL) {
Assert(this);
DPF1(95, "CConnectNodeInstance::Destroy: %08x", this);
ASSERT(cReference > 0);
if(--cReference == 0) {
delete this;
}
}
return(STATUS_CONTINUE);
}
NTSTATUS
CConnectNodeInstance::Connect(
IN PWAVEFORMATEX pWaveFormatEx,
IN PKSPIN_CONNECT pPinConnectDirect
)
{
PKSPIN_CONNECT pPinConnect = NULL;
BOOL fDeletePinConnect;
NTSTATUS Status = STATUS_SUCCESS;
Assert(this);
Assert(pConnectNode);
Assert(pFilterNodeInstanceSource);
Assert(pFilterNodeInstanceSink);
ASSERT(pFilterNodeInstanceSource->pFilterNode ==
pConnectNode->pPinNodeSource->pPinInfo->pFilterNode);
ASSERT(pFilterNodeInstanceSink->pFilterNode ==
pConnectNode->pPinNodeSink->pPinInfo->pFilterNode);
DPF3(90, "CCNI::Connect: CN %08x #%d Source %s",
pConnectNode,
pConnectNode->pPinNodeSource->pPinInfo->PinId,
pFilterNodeInstanceSource->pFilterNode->DumpName());
DPF3(90, "CCNI::Connect: CNI %08x #%d Sink %s",
this,
pConnectNode->pPinNodeSink->pPinInfo->PinId,
pFilterNodeInstanceSink->pFilterNode->DumpName());
// If the Connect is supplied to this function,
// we should not delete it.
//
pPinConnect = pPinConnectDirect;
fDeletePinConnect = (NULL == pPinConnect);
if(pPinNodeInstanceSink != NULL || pPinNodeInstanceSource != NULL) {
ASSERT(NT_SUCCESS(Status));
goto exit;
}
ASSERT(pPinNodeInstanceSink == NULL && pPinNodeInstanceSource == NULL);
if (NULL == pPinConnect) {
Status = CreatePinConnect(
&pPinConnect,
pConnectNode,
pFilterNodeInstanceSink,
pFilterNodeInstanceSource,
pWaveFormatEx);
}
else {
pPinConnect->Medium = *(pConnectNode->pPinNodeSink->pMedium);
pPinConnect->Interface = *(pConnectNode->pPinNodeSink->pInterface);
pPinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
pPinConnect->Priority.PrioritySubClass = 1;
pPinConnect->PinToHandle = NULL;
}
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = CPinNodeInstance::Create(
&pPinNodeInstanceSink,
pFilterNodeInstanceSink,
pConnectNode->pPinNodeSink,
pPinConnect,
fRender
#ifdef FIX_SOUND_LEAK
,FALSE
#endif
);
if(!NT_SUCCESS(Status)) {
goto exit;
}
// Get the pin handle for the pin connecting to this pin
pPinConnect->PinToHandle = pPinNodeInstanceSink->hPin;
Status = CPinNodeInstance::Create(
&pPinNodeInstanceSource,
pFilterNodeInstanceSource,
pConnectNode->pPinNodeSource,
pPinConnect,
fRender
#ifdef FIX_SOUND_LEAK
,FALSE
#endif
);
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF2(90, "CCNI::Connect: SUCCESS PNI Source %08x PNI Sink %08x",
pPinNodeInstanceSource,
pPinNodeInstanceSink);
exit:
if(!NT_SUCCESS(Status)) {
DPF1(90, "CCNI::Connect: FAIL %08x", Status);
pPinNodeInstanceSink->Destroy();
pPinNodeInstanceSink = NULL;
pPinNodeInstanceSource->Destroy();
pPinNodeInstanceSource = NULL;
}
if (fDeletePinConnect) {
delete pPinConnect;
}
return(Status);
}
NTSTATUS
CConnectNodeInstance::SetStateTopDown(
KSSTATE NewState,
KSSTATE PreviousState,
ULONG ulFlags
)
{
NTSTATUS Status = STATUS_SUCCESS;
if(this != NULL) {
Assert(this);
if(ulFlags & SETSTATE_FLAG_SOURCE) {
Status = pPinNodeInstanceSource->SetState(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
if(ulFlags & SETSTATE_FLAG_SINK) {
Status = pPinNodeInstanceSink->SetState(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
}
exit:
return(Status);
}
NTSTATUS
CConnectNodeInstance::SetStateBottomUp(
KSSTATE NewState,
KSSTATE PreviousState,
ULONG ulFlags
)
{
NTSTATUS Status = STATUS_SUCCESS;
if(this != NULL) {
Assert(this);
if(ulFlags & SETSTATE_FLAG_SINK) {
Status = pPinNodeInstanceSink->SetState(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
if(ulFlags & SETSTATE_FLAG_SOURCE) {
Status = pPinNodeInstanceSource->SetState(
NewState,
PreviousState,
ulFlags);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
}
exit:
return(Status);
}
//---------------------------------------------------------------------------
NTSTATUS
CreatePinConnect(
PKSPIN_CONNECT *ppPinConnect,
PCONNECT_NODE pConnectNode,
PFILTER_NODE_INSTANCE pFilterNodeInstanceSink,
PFILTER_NODE_INSTANCE pFilterNodeInstanceSource,
PWAVEFORMATEX pWaveFormatExLimit
)
{
NTSTATUS Status = STATUS_SUCCESS;
Assert(pConnectNode);
Assert(pFilterNodeInstanceSink);
Assert(pFilterNodeInstanceSource);
if(pWaveFormatExLimit == NULL) {
if(pConnectNode->IsTopDown()) {
Status = CreatePinIntersection(
ppPinConnect,
pConnectNode->pPinNodeSource,
pConnectNode->pPinNodeSink,
pFilterNodeInstanceSource,
pFilterNodeInstanceSink);
}
else {
Status = CreatePinIntersection(
ppPinConnect,
pConnectNode->pPinNodeSink,
pConnectNode->pPinNodeSource,
pFilterNodeInstanceSink,
pFilterNodeInstanceSource);
}
}
else {
Status = CreateWaveFormatEx(
ppPinConnect,
pConnectNode,
pWaveFormatExLimit);
}
if(!NT_SUCCESS(Status)) {
goto exit;
}
//
// For all the normal fields in the PinConnect we could either the
// source or sink pinnode, they are same.
//
ASSERT(pConnectNode->pPinNodeSink->pMedium != NULL);
ASSERT(pConnectNode->pPinNodeSink->pInterface != NULL);
ASSERT(pConnectNode->pPinNodeSink->pDataRange != NULL);
(*ppPinConnect)->Medium = *(pConnectNode->pPinNodeSink->pMedium);
(*ppPinConnect)->Interface = *(pConnectNode->pPinNodeSink->pInterface);
(*ppPinConnect)->Priority.PriorityClass = KSPRIORITY_NORMAL;
(*ppPinConnect)->Priority.PrioritySubClass = 1;
(*ppPinConnect)->PinToHandle = NULL;
DPF2(100, "CreatePinConnect: Source #%d %s",
pConnectNode->pPinNodeSource->pPinInfo->PinId,
pFilterNodeInstanceSource->pFilterNode->DumpName());
DPF2(100, "CreatePinConnect: Sink #%d %s",
pConnectNode->pPinNodeSink->pPinInfo->PinId,
pFilterNodeInstanceSink->pFilterNode->DumpName());
exit:
return(Status);
}
NTSTATUS
CreatePinIntersection(
PKSPIN_CONNECT *ppPinConnect,
PPIN_NODE pPinNode1,
PPIN_NODE pPinNode2,
PFILTER_NODE_INSTANCE pFilterNodeInstance1,
PFILTER_NODE_INSTANCE pFilterNodeInstance2
)
{
NTSTATUS Status = STATUS_SUCCESS;
PDATARANGES pDataRangesIn = NULL;
PKSDATARANGE pDataFormatOut = NULL;
Assert(pPinNode1);
Assert(pPinNode2);
Assert(pFilterNodeInstance1);
Assert(pFilterNodeInstance2);
Status = GetPinPropertyEx(
pFilterNodeInstance2->pFileObject,
KSPROPERTY_PIN_CONSTRAINEDDATARANGES,
pPinNode2->pPinInfo->PinId,
(PVOID*)&pDataRangesIn);
if(!NT_SUCCESS(Status)) {
goto exit;
}
if(pDataRangesIn == NULL) {
Status = GetPinPropertyEx(
pFilterNodeInstance2->pFileObject,
KSPROPERTY_PIN_DATARANGES,
pPinNode2->pPinInfo->PinId,
(PVOID*)&pDataRangesIn);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
if(pDataRangesIn == NULL ||
pDataRangesIn->MultipleItem.Count == 0 ||
pDataRangesIn->MultipleItem.Size < sizeof(KSDATARANGE)) {
Trap();
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
Status = GetPinProperty2(
pFilterNodeInstance1->pFileObject,
KSPROPERTY_PIN_DATAINTERSECTION,
pPinNode1->pPinInfo->PinId,
pDataRangesIn->MultipleItem.Size,
pDataRangesIn,
(PVOID*)&pDataFormatOut);
if(!NT_SUCCESS(Status)) {
goto exit;
}
if(pDataFormatOut == NULL) {
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
*ppPinConnect = (PKSPIN_CONNECT)
new BYTE[sizeof(KSPIN_CONNECT) + pDataFormatOut->FormatSize];
if(*ppPinConnect == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if(pDataFormatOut->SampleSize == 0) {
PWAVEFORMATEX pWaveFormatEx =
GetWaveFormatExFromKsDataFormat(pDataFormatOut, NULL);
if (NULL != pWaveFormatEx) {
pDataFormatOut->SampleSize = pWaveFormatEx->nBlockAlign;
}
}
memcpy((*ppPinConnect) + 1, pDataFormatOut, pDataFormatOut->FormatSize);
DPF2(90, "CreatePinIntersection SUCCESS: 1 #%d %s",
pPinNode1->pPinInfo->PinId,
pFilterNodeInstance1->pFilterNode->DumpName());
DPF2(90, "CreatePinIntersection: 2 #%d %s",
pPinNode2->pPinInfo->PinId,
pFilterNodeInstance2->pFilterNode->DumpName());
exit:
delete pDataRangesIn;
delete pDataFormatOut;
if(!NT_SUCCESS(Status)) {
DPF3(90, "CreatePinIntersection FAIL %08x: 1 #%d %s",
Status,
pPinNode1->pPinInfo->PinId,
pFilterNodeInstance1->pFilterNode->DumpName());
DPF2(90, "CreatePinIntersection: 2 #%d %s",
pPinNode2->pPinInfo->PinId,
pFilterNodeInstance2->pFilterNode->DumpName());
}
return(Status);
}
NTSTATUS
CreateWaveFormatEx(
PKSPIN_CONNECT *ppPinConnect,
PCONNECT_NODE pConnectNode,
PWAVEFORMATEX pWaveFormatExLimit
)
{
KSDATARANGE_AUDIO DataRangeAudioIntersection;
PKSDATARANGE_AUDIO pDataRangeAudioSource;
PKSDATARANGE_AUDIO pDataRangeAudioSink;
NTSTATUS Status = STATUS_SUCCESS;
Assert(pConnectNode);
Assert(pConnectNode->pPinNodeSource);
Assert(pConnectNode->pPinNodeSink);
ASSERT(*ppPinConnect == NULL);
//
// For the WaveFormatEx specifier both source and sink pinnode's
// DataRanges need to be used to generated the PinConnect structure
//
pDataRangeAudioSource =
(PKSDATARANGE_AUDIO)pConnectNode->pPinNodeSource->pDataRange;
pDataRangeAudioSink =
(PKSDATARANGE_AUDIO)pConnectNode->pPinNodeSink->pDataRange;
if(!DataIntersectionRange(
&pDataRangeAudioSink->DataRange,
&pDataRangeAudioSource->DataRange,
&DataRangeAudioIntersection.DataRange) ||
!DataIntersectionAudio(
pDataRangeAudioSink,
pDataRangeAudioSource,
&DataRangeAudioIntersection)) {
Trap();
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
//
// Limit the playback/record format
//
if(pConnectNode->IsLimitFormat()) {
if(!LimitAudioRangeToWave(
pWaveFormatExLimit,
&DataRangeAudioIntersection)) {
DPF(20, "CreateWaveFormatEx: LimitAudioRangeToWave FAILED");
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
DPF6(20,"CreateWaveFormatEx: SR %d CH %d BPS %d | SR %d CH %d BPS %d",
pWaveFormatExLimit->nSamplesPerSec,
pWaveFormatExLimit->nChannels,
pWaveFormatExLimit->wBitsPerSample,
DataRangeAudioIntersection.MaximumSampleFrequency,
DataRangeAudioIntersection.MaximumChannels,
DataRangeAudioIntersection.MaximumBitsPerSample);
}
if(IsEqualGUID(
&DataRangeAudioIntersection.DataRange.Specifier,
&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) {
PKSDATAFORMAT_WAVEFORMATEX pDataFormatWaveFormatEx;
ULONG RegionAllocSize;
if (pWaveFormatExLimit->wFormatTag == WAVE_FORMAT_PCM) {
RegionAllocSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
}
else {
RegionAllocSize = sizeof(KSDATAFORMAT_WAVEFORMATEX) + pWaveFormatExLimit->cbSize;
}
*ppPinConnect = (PKSPIN_CONNECT)
new BYTE[sizeof(KSPIN_CONNECT) + RegionAllocSize];
if(*ppPinConnect == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
pDataFormatWaveFormatEx =
(PKSDATAFORMAT_WAVEFORMATEX)((*ppPinConnect) + 1);
WaveFormatFromAudioRange(
&DataRangeAudioIntersection,
&pDataFormatWaveFormatEx->WaveFormatEx);
if (pWaveFormatExLimit) {
//
// If we are trying the Client's data Format
//
if (pWaveFormatExLimit->wFormatTag != WAVE_FORMAT_PCM) {
ULONG CopySize;
//
// and if it is extensible format
// Set the Extensible related fields in the WaveformatEx
// structure we are building as part of PinConnect
//
//
// cast both pointers to Waveformat extensible equivalents
//
pDataFormatWaveFormatEx =
(PKSDATAFORMAT_WAVEFORMATEX)((*ppPinConnect) + 1);
pDataFormatWaveFormatEx->WaveFormatEx.wFormatTag = pWaveFormatExLimit->wFormatTag;
pDataFormatWaveFormatEx->WaveFormatEx.cbSize = pWaveFormatExLimit->cbSize;
CopySize = pWaveFormatExLimit->cbSize;
if (CopySize) {
PWAVEFORMATEX pWaveFormatExDest;
pWaveFormatExDest = &pDataFormatWaveFormatEx->WaveFormatEx;
RtlCopyMemory((pWaveFormatExDest+1),
(pWaveFormatExLimit+1),
CopySize);
}
}
}
pDataFormatWaveFormatEx->DataFormat =
DataRangeAudioIntersection.DataRange;
pDataFormatWaveFormatEx->DataFormat.FormatSize =
sizeof(KSDATAFORMAT_WAVEFORMATEX);
//
// If we are dealing extensible format - set the FormatSize to the extensible equivalent
//
if (pWaveFormatExLimit) {
pDataFormatWaveFormatEx->DataFormat.FormatSize = RegionAllocSize;
}
pDataFormatWaveFormatEx->DataFormat.SampleSize =
pDataFormatWaveFormatEx->WaveFormatEx.nBlockAlign;
DPF3(90, "CreateWaveFormatEx SUCCESS SR %d CH %d BPS %d",
pDataFormatWaveFormatEx->WaveFormatEx.nSamplesPerSec,
pDataFormatWaveFormatEx->WaveFormatEx.nChannels,
pDataFormatWaveFormatEx->WaveFormatEx.wBitsPerSample);
}
else {
Status = STATUS_INVALID_DEVICE_REQUEST;
goto exit;
}
exit:
if(!NT_SUCCESS(Status)) {
delete *ppPinConnect;
*ppPinConnect = NULL;
DPF4(90, "CreateWaveFormatEx FAILED %08x SR %d CH %d BPS %d",
Status,
pWaveFormatExLimit->nSamplesPerSec,
pWaveFormatExLimit->nChannels,
pWaveFormatExLimit->wBitsPerSample);
}
return(Status);
}
VOID
WaveFormatFromAudioRange(
PKSDATARANGE_AUDIO pDataRangeAudio,
WAVEFORMATEX *pWaveFormatEx
)
{
if(IS_VALID_WAVEFORMATEX_GUID(&pDataRangeAudio->DataRange.SubFormat)) {
pWaveFormatEx->wFormatTag =
EXTRACT_WAVEFORMATEX_ID(&pDataRangeAudio->DataRange.SubFormat);
}
else {
pWaveFormatEx->wFormatTag = WAVE_FORMAT_UNKNOWN;
}
pWaveFormatEx->nChannels = (WORD)pDataRangeAudio->MaximumChannels;
pWaveFormatEx->nSamplesPerSec = pDataRangeAudio->MaximumSampleFrequency;
pWaveFormatEx->wBitsPerSample = (WORD)pDataRangeAudio->MaximumBitsPerSample;
pWaveFormatEx->nBlockAlign =
(pWaveFormatEx->nChannels * pWaveFormatEx->wBitsPerSample)/8;
pWaveFormatEx->nAvgBytesPerSec =
pWaveFormatEx->nSamplesPerSec * pWaveFormatEx->nBlockAlign;
pWaveFormatEx->cbSize = 0;
}
BOOL
LimitAudioRangeToWave(
PWAVEFORMATEX pWaveFormatEx,
PKSDATARANGE_AUDIO pDataRangeAudio
)
{
PWAVEFORMATEXTENSIBLE pWaveFormatExtensible;
DPF5(20, "LimitAudioRangeToWave: SR: %d %d CH: %d BPS %d %d",
pDataRangeAudio->MinimumSampleFrequency,
pDataRangeAudio->MaximumSampleFrequency,
pDataRangeAudio->MaximumChannels,
pDataRangeAudio->MinimumBitsPerSample,
pDataRangeAudio->MaximumBitsPerSample);
if(pWaveFormatEx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
pWaveFormatExtensible = (PWAVEFORMATEXTENSIBLE)pWaveFormatEx;
if (!IsEqualGUID(&pWaveFormatExtensible->SubFormat, &pDataRangeAudio->DataRange.SubFormat)) {
return(FALSE);
}
}
else { // not WAVE_FORMAT_EXTENSIBLE
if(IS_VALID_WAVEFORMATEX_GUID(&pDataRangeAudio->DataRange.SubFormat)) {
if (pWaveFormatEx->wFormatTag !=
EXTRACT_WAVEFORMATEX_ID(&pDataRangeAudio->DataRange.SubFormat) ) {
return(FALSE);
}
}
}
if(pDataRangeAudio->MinimumSampleFrequency <=
pWaveFormatEx->nSamplesPerSec &&
pDataRangeAudio->MaximumSampleFrequency >=
pWaveFormatEx->nSamplesPerSec) {
pDataRangeAudio->MaximumSampleFrequency = pWaveFormatEx->nSamplesPerSec;
}
else {
return(FALSE);
}
if(pDataRangeAudio->MinimumBitsPerSample <=
pWaveFormatEx->wBitsPerSample &&
pDataRangeAudio->MaximumBitsPerSample >=
pWaveFormatEx->wBitsPerSample) {
pDataRangeAudio->MaximumBitsPerSample = pWaveFormatEx->wBitsPerSample;
}
else {
return(FALSE);
}
// Because there is no minimum channel in the data range,
// take the maximum channel to be what the requestor wants.
// i.e. don't limit the number of channels.
if(pDataRangeAudio->MaximumChannels >= pWaveFormatEx->nChannels) {
pDataRangeAudio->MaximumChannels = pWaveFormatEx->nChannels;
}
else {
return(FALSE);
}
return(TRUE);
}
//---------------------------------------------------------------------------