Source code of Windows XP (NT5)
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.

859 lines
24 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: cni.cpp
  4. //
  5. // Description:
  6. //
  7. // Connect Node Instance
  8. //
  9. //@@BEGIN_MSINTERNAL
  10. // Development Team:
  11. // Mike McLaughlin
  12. //
  13. // History: Date Author Comment
  14. //
  15. // To Do: Date Author Comment
  16. //
  17. //@@END_MSINTERNAL
  18. //
  19. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  20. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  21. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  22. // PURPOSE.
  23. //
  24. // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
  25. //
  26. //---------------------------------------------------------------------------
  27. #include "common.h"
  28. //---------------------------------------------------------------------------
  29. //---------------------------------------------------------------------------
  30. CConnectNodeInstance::CConnectNodeInstance(
  31. IN PCONNECT_NODE pConnectNode
  32. )
  33. {
  34. Assert(this);
  35. pConnectNode->AddPinInstance();
  36. pConnectNode->SetConnectNodeInstance(this);
  37. this->pConnectNode = pConnectNode;
  38. }
  39. CConnectNodeInstance::~CConnectNodeInstance(
  40. )
  41. {
  42. Assert(this);
  43. DPF1(95, "~CConnectNodeInstance: %08x", this);
  44. if(pConnectNode != NULL) {
  45. Assert(pConnectNode);
  46. pConnectNode->RemovePinInstance();
  47. if(pConnectNode->GetConnectNodeInstance() == this) {
  48. pConnectNode->SetConnectNodeInstance(NULL);
  49. }
  50. }
  51. #ifdef DEBUG
  52. delete pPinConnect;
  53. #endif
  54. pPinNodeInstanceSource->Destroy();
  55. pPinNodeInstanceSink->Destroy();
  56. pFilterNodeInstanceSource->Destroy();
  57. pFilterNodeInstanceSink->Destroy();
  58. }
  59. NTSTATUS
  60. CConnectNodeInstance::Create(
  61. PSTART_NODE_INSTANCE pStartNodeInstance,
  62. PDEVICE_NODE pDeviceNode
  63. )
  64. {
  65. PFILTER_NODE_INSTANCE *ppFilterNodeInstancePrevious;
  66. PCONNECT_NODE_INSTANCE pConnectNodeInstance = NULL;
  67. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  68. NTSTATUS Status = STATUS_SUCCESS;
  69. BOOL fReuseFilterInstance = TRUE;
  70. PCONNECT_NODE pConnectNode;
  71. pLogicalFilterNode =
  72. pStartNodeInstance->pStartNode->pPinNode->pLogicalFilterNode;
  73. ppFilterNodeInstancePrevious = &pStartNodeInstance->pFilterNodeInstance;
  74. for(pConnectNode = pStartNodeInstance->pStartNode->GetFirstConnectNode();
  75. pConnectNode != NULL;
  76. pConnectNode = pConnectNode->GetNextConnectNode()) {
  77. Assert(pLogicalFilterNode);
  78. Assert(pConnectNode);
  79. // Get existing connect node instance
  80. fReuseFilterInstance = pConnectNode->IsReuseFilterInstance();
  81. pConnectNodeInstance = pConnectNode->GetConnectNodeInstance();
  82. if(fReuseFilterInstance && pConnectNodeInstance != NULL) {
  83. Assert(pConnectNodeInstance);
  84. DPF4(100, "Existing CNI: %08x %d FNI Source: %08x FNI Sink %08x",
  85. pConnectNodeInstance,
  86. pConnectNodeInstance->cReference,
  87. pConnectNodeInstance->pFilterNodeInstanceSource,
  88. pConnectNodeInstance->pFilterNodeInstanceSink);
  89. }
  90. else {
  91. if(!pConnectNode->IsPinInstances()) {
  92. DPF1(90, "CCNI::Create: no instances CN %08x", pConnectNode);
  93. Status = STATUS_DEVICE_BUSY;
  94. goto exit;
  95. }
  96. pConnectNodeInstance = new CONNECT_NODE_INSTANCE(pConnectNode);
  97. if(pConnectNodeInstance == NULL) {
  98. Status = STATUS_INSUFFICIENT_RESOURCES;
  99. goto exit;
  100. }
  101. pConnectNodeInstance->fRender = pStartNodeInstance->IsRender();
  102. Status = CFilterNodeInstance::Create(
  103. &pConnectNodeInstance->pFilterNodeInstanceSource,
  104. pLogicalFilterNode,
  105. pDeviceNode,
  106. fReuseFilterInstance);
  107. if(!NT_SUCCESS(Status)) {
  108. delete pConnectNodeInstance;
  109. goto exit;
  110. }
  111. Assert(pConnectNodeInstance->pFilterNodeInstanceSource);
  112. DPF4(100, "New CNI: %08x %d FNI Source: %08x FNI Sink %08x",
  113. pConnectNodeInstance,
  114. pConnectNodeInstance->cReference,
  115. pConnectNodeInstance->pFilterNodeInstanceSource,
  116. pConnectNodeInstance->pFilterNodeInstanceSink);
  117. }
  118. Status = pConnectNodeInstance->AddListEnd(
  119. &pStartNodeInstance->lstConnectNodeInstance);
  120. if(!NT_SUCCESS(Status)) {
  121. goto exit;
  122. }
  123. if(*ppFilterNodeInstancePrevious == NULL) {
  124. *ppFilterNodeInstancePrevious =
  125. pConnectNodeInstance->pFilterNodeInstanceSource;
  126. pConnectNodeInstance->pFilterNodeInstanceSource->AddRef();
  127. }
  128. ppFilterNodeInstancePrevious =
  129. &pConnectNodeInstance->pFilterNodeInstanceSink;
  130. pLogicalFilterNode = pConnectNode->pPinNodeSink->pLogicalFilterNode;
  131. }
  132. if(*ppFilterNodeInstancePrevious == NULL) {
  133. Assert(pLogicalFilterNode);
  134. Status = CFilterNodeInstance::Create(
  135. ppFilterNodeInstancePrevious,
  136. pLogicalFilterNode,
  137. pDeviceNode,
  138. fReuseFilterInstance);
  139. if(!NT_SUCCESS(Status)) {
  140. goto exit;
  141. }
  142. Assert(*ppFilterNodeInstancePrevious);
  143. }
  144. exit:
  145. return(Status);
  146. }
  147. NTSTATUS
  148. CConnectNodeInstance::AddListEnd(
  149. PCLIST_MULTI plm
  150. )
  151. {
  152. NTSTATUS Status;
  153. Status = CListMultiItem::AddListEnd(plm);
  154. if(NT_SUCCESS(Status)) {
  155. AddRef();
  156. }
  157. return(Status);
  158. }
  159. ENUMFUNC
  160. CConnectNodeInstance::Destroy(
  161. )
  162. {
  163. if(this != NULL) {
  164. Assert(this);
  165. DPF1(95, "CConnectNodeInstance::Destroy: %08x", this);
  166. ASSERT(cReference > 0);
  167. if(--cReference == 0) {
  168. delete this;
  169. }
  170. }
  171. return(STATUS_CONTINUE);
  172. }
  173. NTSTATUS
  174. CConnectNodeInstance::Connect(
  175. IN PWAVEFORMATEX pWaveFormatEx,
  176. IN PKSPIN_CONNECT pPinConnectDirect
  177. )
  178. {
  179. PKSPIN_CONNECT pPinConnect = NULL;
  180. BOOL fDeletePinConnect;
  181. NTSTATUS Status = STATUS_SUCCESS;
  182. Assert(this);
  183. Assert(pConnectNode);
  184. Assert(pFilterNodeInstanceSource);
  185. Assert(pFilterNodeInstanceSink);
  186. ASSERT(pFilterNodeInstanceSource->pFilterNode ==
  187. pConnectNode->pPinNodeSource->pPinInfo->pFilterNode);
  188. ASSERT(pFilterNodeInstanceSink->pFilterNode ==
  189. pConnectNode->pPinNodeSink->pPinInfo->pFilterNode);
  190. DPF3(90, "CCNI::Connect: CN %08x #%d Source %s",
  191. pConnectNode,
  192. pConnectNode->pPinNodeSource->pPinInfo->PinId,
  193. pFilterNodeInstanceSource->pFilterNode->DumpName());
  194. DPF3(90, "CCNI::Connect: CNI %08x #%d Sink %s",
  195. this,
  196. pConnectNode->pPinNodeSink->pPinInfo->PinId,
  197. pFilterNodeInstanceSink->pFilterNode->DumpName());
  198. // If the Connect is supplied to this function,
  199. // we should not delete it.
  200. //
  201. pPinConnect = pPinConnectDirect;
  202. fDeletePinConnect = (NULL == pPinConnect);
  203. if(pPinNodeInstanceSink != NULL || pPinNodeInstanceSource != NULL) {
  204. ASSERT(NT_SUCCESS(Status));
  205. goto exit;
  206. }
  207. ASSERT(pPinNodeInstanceSink == NULL && pPinNodeInstanceSource == NULL);
  208. if (NULL == pPinConnect) {
  209. Status = CreatePinConnect(
  210. &pPinConnect,
  211. pConnectNode,
  212. pFilterNodeInstanceSink,
  213. pFilterNodeInstanceSource,
  214. pWaveFormatEx);
  215. }
  216. else {
  217. pPinConnect->Medium = *(pConnectNode->pPinNodeSink->pMedium);
  218. pPinConnect->Interface = *(pConnectNode->pPinNodeSink->pInterface);
  219. pPinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
  220. pPinConnect->Priority.PrioritySubClass = 1;
  221. pPinConnect->PinToHandle = NULL;
  222. }
  223. if(!NT_SUCCESS(Status)) {
  224. goto exit;
  225. }
  226. Status = CPinNodeInstance::Create(
  227. &pPinNodeInstanceSink,
  228. pFilterNodeInstanceSink,
  229. pConnectNode->pPinNodeSink,
  230. pPinConnect,
  231. fRender
  232. #ifdef FIX_SOUND_LEAK
  233. ,FALSE
  234. #endif
  235. );
  236. if(!NT_SUCCESS(Status)) {
  237. goto exit;
  238. }
  239. // Get the pin handle for the pin connecting to this pin
  240. pPinConnect->PinToHandle = pPinNodeInstanceSink->hPin;
  241. Status = CPinNodeInstance::Create(
  242. &pPinNodeInstanceSource,
  243. pFilterNodeInstanceSource,
  244. pConnectNode->pPinNodeSource,
  245. pPinConnect,
  246. fRender
  247. #ifdef FIX_SOUND_LEAK
  248. ,FALSE
  249. #endif
  250. );
  251. if(!NT_SUCCESS(Status)) {
  252. goto exit;
  253. }
  254. DPF2(90, "CCNI::Connect: SUCCESS PNI Source %08x PNI Sink %08x",
  255. pPinNodeInstanceSource,
  256. pPinNodeInstanceSink);
  257. exit:
  258. if(!NT_SUCCESS(Status)) {
  259. DPF1(90, "CCNI::Connect: FAIL %08x", Status);
  260. pPinNodeInstanceSink->Destroy();
  261. pPinNodeInstanceSink = NULL;
  262. pPinNodeInstanceSource->Destroy();
  263. pPinNodeInstanceSource = NULL;
  264. }
  265. if (fDeletePinConnect) {
  266. delete pPinConnect;
  267. }
  268. return(Status);
  269. }
  270. NTSTATUS
  271. CConnectNodeInstance::SetStateTopDown(
  272. KSSTATE NewState,
  273. KSSTATE PreviousState,
  274. ULONG ulFlags
  275. )
  276. {
  277. NTSTATUS Status = STATUS_SUCCESS;
  278. if(this != NULL) {
  279. Assert(this);
  280. if(ulFlags & SETSTATE_FLAG_SOURCE) {
  281. Status = pPinNodeInstanceSource->SetState(
  282. NewState,
  283. PreviousState,
  284. ulFlags);
  285. if(!NT_SUCCESS(Status)) {
  286. goto exit;
  287. }
  288. }
  289. if(ulFlags & SETSTATE_FLAG_SINK) {
  290. Status = pPinNodeInstanceSink->SetState(
  291. NewState,
  292. PreviousState,
  293. ulFlags);
  294. if(!NT_SUCCESS(Status)) {
  295. goto exit;
  296. }
  297. }
  298. }
  299. exit:
  300. return(Status);
  301. }
  302. NTSTATUS
  303. CConnectNodeInstance::SetStateBottomUp(
  304. KSSTATE NewState,
  305. KSSTATE PreviousState,
  306. ULONG ulFlags
  307. )
  308. {
  309. NTSTATUS Status = STATUS_SUCCESS;
  310. if(this != NULL) {
  311. Assert(this);
  312. if(ulFlags & SETSTATE_FLAG_SINK) {
  313. Status = pPinNodeInstanceSink->SetState(
  314. NewState,
  315. PreviousState,
  316. ulFlags);
  317. if(!NT_SUCCESS(Status)) {
  318. goto exit;
  319. }
  320. }
  321. if(ulFlags & SETSTATE_FLAG_SOURCE) {
  322. Status = pPinNodeInstanceSource->SetState(
  323. NewState,
  324. PreviousState,
  325. ulFlags);
  326. if(!NT_SUCCESS(Status)) {
  327. goto exit;
  328. }
  329. }
  330. }
  331. exit:
  332. return(Status);
  333. }
  334. //---------------------------------------------------------------------------
  335. NTSTATUS
  336. CreatePinConnect(
  337. PKSPIN_CONNECT *ppPinConnect,
  338. PCONNECT_NODE pConnectNode,
  339. PFILTER_NODE_INSTANCE pFilterNodeInstanceSink,
  340. PFILTER_NODE_INSTANCE pFilterNodeInstanceSource,
  341. PWAVEFORMATEX pWaveFormatExLimit
  342. )
  343. {
  344. NTSTATUS Status = STATUS_SUCCESS;
  345. Assert(pConnectNode);
  346. Assert(pFilterNodeInstanceSink);
  347. Assert(pFilterNodeInstanceSource);
  348. if(pWaveFormatExLimit == NULL) {
  349. if(pConnectNode->IsTopDown()) {
  350. Status = CreatePinIntersection(
  351. ppPinConnect,
  352. pConnectNode->pPinNodeSource,
  353. pConnectNode->pPinNodeSink,
  354. pFilterNodeInstanceSource,
  355. pFilterNodeInstanceSink);
  356. }
  357. else {
  358. Status = CreatePinIntersection(
  359. ppPinConnect,
  360. pConnectNode->pPinNodeSink,
  361. pConnectNode->pPinNodeSource,
  362. pFilterNodeInstanceSink,
  363. pFilterNodeInstanceSource);
  364. }
  365. }
  366. else {
  367. Status = CreateWaveFormatEx(
  368. ppPinConnect,
  369. pConnectNode,
  370. pWaveFormatExLimit);
  371. }
  372. if(!NT_SUCCESS(Status)) {
  373. goto exit;
  374. }
  375. //
  376. // For all the normal fields in the PinConnect we could either the
  377. // source or sink pinnode, they are same.
  378. //
  379. ASSERT(pConnectNode->pPinNodeSink->pMedium != NULL);
  380. ASSERT(pConnectNode->pPinNodeSink->pInterface != NULL);
  381. ASSERT(pConnectNode->pPinNodeSink->pDataRange != NULL);
  382. (*ppPinConnect)->Medium = *(pConnectNode->pPinNodeSink->pMedium);
  383. (*ppPinConnect)->Interface = *(pConnectNode->pPinNodeSink->pInterface);
  384. (*ppPinConnect)->Priority.PriorityClass = KSPRIORITY_NORMAL;
  385. (*ppPinConnect)->Priority.PrioritySubClass = 1;
  386. (*ppPinConnect)->PinToHandle = NULL;
  387. DPF2(100, "CreatePinConnect: Source #%d %s",
  388. pConnectNode->pPinNodeSource->pPinInfo->PinId,
  389. pFilterNodeInstanceSource->pFilterNode->DumpName());
  390. DPF2(100, "CreatePinConnect: Sink #%d %s",
  391. pConnectNode->pPinNodeSink->pPinInfo->PinId,
  392. pFilterNodeInstanceSink->pFilterNode->DumpName());
  393. exit:
  394. return(Status);
  395. }
  396. NTSTATUS
  397. CreatePinIntersection(
  398. PKSPIN_CONNECT *ppPinConnect,
  399. PPIN_NODE pPinNode1,
  400. PPIN_NODE pPinNode2,
  401. PFILTER_NODE_INSTANCE pFilterNodeInstance1,
  402. PFILTER_NODE_INSTANCE pFilterNodeInstance2
  403. )
  404. {
  405. NTSTATUS Status = STATUS_SUCCESS;
  406. PDATARANGES pDataRangesIn = NULL;
  407. PKSDATARANGE pDataFormatOut = NULL;
  408. Assert(pPinNode1);
  409. Assert(pPinNode2);
  410. Assert(pFilterNodeInstance1);
  411. Assert(pFilterNodeInstance2);
  412. Status = GetPinPropertyEx(
  413. pFilterNodeInstance2->pFileObject,
  414. KSPROPERTY_PIN_CONSTRAINEDDATARANGES,
  415. pPinNode2->pPinInfo->PinId,
  416. (PVOID*)&pDataRangesIn);
  417. if(!NT_SUCCESS(Status)) {
  418. goto exit;
  419. }
  420. if(pDataRangesIn == NULL) {
  421. Status = GetPinPropertyEx(
  422. pFilterNodeInstance2->pFileObject,
  423. KSPROPERTY_PIN_DATARANGES,
  424. pPinNode2->pPinInfo->PinId,
  425. (PVOID*)&pDataRangesIn);
  426. if(!NT_SUCCESS(Status)) {
  427. goto exit;
  428. }
  429. }
  430. if(pDataRangesIn == NULL ||
  431. pDataRangesIn->MultipleItem.Count == 0 ||
  432. pDataRangesIn->MultipleItem.Size < sizeof(KSDATARANGE)) {
  433. Trap();
  434. Status = STATUS_INVALID_DEVICE_REQUEST;
  435. goto exit;
  436. }
  437. Status = GetPinProperty2(
  438. pFilterNodeInstance1->pFileObject,
  439. KSPROPERTY_PIN_DATAINTERSECTION,
  440. pPinNode1->pPinInfo->PinId,
  441. pDataRangesIn->MultipleItem.Size,
  442. pDataRangesIn,
  443. (PVOID*)&pDataFormatOut);
  444. if(!NT_SUCCESS(Status)) {
  445. goto exit;
  446. }
  447. if(pDataFormatOut == NULL) {
  448. Status = STATUS_INVALID_DEVICE_REQUEST;
  449. goto exit;
  450. }
  451. *ppPinConnect = (PKSPIN_CONNECT)
  452. new BYTE[sizeof(KSPIN_CONNECT) + pDataFormatOut->FormatSize];
  453. if(*ppPinConnect == NULL) {
  454. Status = STATUS_INSUFFICIENT_RESOURCES;
  455. goto exit;
  456. }
  457. if(pDataFormatOut->SampleSize == 0) {
  458. if(IsEqualGUID(
  459. &pDataFormatOut->Specifier,
  460. &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) {
  461. pDataFormatOut->SampleSize =
  462. ((PKSDATAFORMAT_WAVEFORMATEX)pDataFormatOut)->
  463. WaveFormatEx.nBlockAlign;
  464. }
  465. if(IsEqualGUID(
  466. &pDataFormatOut->Specifier,
  467. &KSDATAFORMAT_SPECIFIER_DSOUND)) {
  468. pDataFormatOut->SampleSize =
  469. ((PKSDATAFORMAT_DSOUND)pDataFormatOut)->
  470. BufferDesc.WaveFormatEx.nBlockAlign;
  471. }
  472. }
  473. memcpy((*ppPinConnect) + 1, pDataFormatOut, pDataFormatOut->FormatSize);
  474. DPF2(90, "CreatePinIntersection SUCCESS: 1 #%d %s",
  475. pPinNode1->pPinInfo->PinId,
  476. pFilterNodeInstance1->pFilterNode->DumpName());
  477. DPF2(90, "CreatePinIntersection: 2 #%d %s",
  478. pPinNode2->pPinInfo->PinId,
  479. pFilterNodeInstance2->pFilterNode->DumpName());
  480. exit:
  481. delete pDataRangesIn;
  482. delete pDataFormatOut;
  483. if(!NT_SUCCESS(Status)) {
  484. DPF3(90, "CreatePinIntersection FAIL %08x: 1 #%d %s",
  485. Status,
  486. pPinNode1->pPinInfo->PinId,
  487. pFilterNodeInstance1->pFilterNode->DumpName());
  488. DPF2(90, "CreatePinIntersection: 2 #%d %s",
  489. pPinNode2->pPinInfo->PinId,
  490. pFilterNodeInstance2->pFilterNode->DumpName());
  491. }
  492. return(Status);
  493. }
  494. NTSTATUS
  495. CreateWaveFormatEx(
  496. PKSPIN_CONNECT *ppPinConnect,
  497. PCONNECT_NODE pConnectNode,
  498. PWAVEFORMATEX pWaveFormatExLimit
  499. )
  500. {
  501. KSDATARANGE_AUDIO DataRangeAudioIntersection;
  502. PKSDATARANGE_AUDIO pDataRangeAudioSource;
  503. PKSDATARANGE_AUDIO pDataRangeAudioSink;
  504. NTSTATUS Status = STATUS_SUCCESS;
  505. Assert(pConnectNode);
  506. Assert(pConnectNode->pPinNodeSource);
  507. Assert(pConnectNode->pPinNodeSink);
  508. ASSERT(*ppPinConnect == NULL);
  509. //
  510. // For the WaveFormatEx specifier both source and sink pinnode's
  511. // DataRanges need to be used to generated the PinConnect structure
  512. //
  513. pDataRangeAudioSource =
  514. (PKSDATARANGE_AUDIO)pConnectNode->pPinNodeSource->pDataRange;
  515. pDataRangeAudioSink =
  516. (PKSDATARANGE_AUDIO)pConnectNode->pPinNodeSink->pDataRange;
  517. if(!DataIntersectionRange(
  518. &pDataRangeAudioSink->DataRange,
  519. &pDataRangeAudioSource->DataRange,
  520. &DataRangeAudioIntersection.DataRange) ||
  521. !DataIntersectionAudio(
  522. pDataRangeAudioSink,
  523. pDataRangeAudioSource,
  524. &DataRangeAudioIntersection)) {
  525. Trap();
  526. Status = STATUS_INVALID_DEVICE_REQUEST;
  527. goto exit;
  528. }
  529. //
  530. // Limit the playback/record format
  531. //
  532. if(pConnectNode->IsLimitFormat()) {
  533. if(!LimitAudioRangeToWave(
  534. pWaveFormatExLimit,
  535. &DataRangeAudioIntersection)) {
  536. DPF(20, "CreateWaveFormatEx: LimitAudioRangeToWave FAILED");
  537. Status = STATUS_INVALID_DEVICE_REQUEST;
  538. goto exit;
  539. }
  540. DPF6(20,"CreateWaveFormatEx: SR %d CH %d BPS %d | SR %d CH %d BPS %d",
  541. pWaveFormatExLimit->nSamplesPerSec,
  542. pWaveFormatExLimit->nChannels,
  543. pWaveFormatExLimit->wBitsPerSample,
  544. DataRangeAudioIntersection.MaximumSampleFrequency,
  545. DataRangeAudioIntersection.MaximumChannels,
  546. DataRangeAudioIntersection.MaximumBitsPerSample);
  547. }
  548. if(IsEqualGUID(
  549. &DataRangeAudioIntersection.DataRange.Specifier,
  550. &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) {
  551. PKSDATAFORMAT_WAVEFORMATEX pDataFormatWaveFormatEx;
  552. ULONG RegionAllocSize;
  553. if (pWaveFormatExLimit->wFormatTag == WAVE_FORMAT_PCM) {
  554. RegionAllocSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
  555. }
  556. else {
  557. RegionAllocSize = sizeof(KSDATAFORMAT_WAVEFORMATEX) + pWaveFormatExLimit->cbSize;
  558. }
  559. *ppPinConnect = (PKSPIN_CONNECT)
  560. new BYTE[sizeof(KSPIN_CONNECT) + RegionAllocSize];
  561. if(*ppPinConnect == NULL) {
  562. Status = STATUS_INSUFFICIENT_RESOURCES;
  563. goto exit;
  564. }
  565. pDataFormatWaveFormatEx =
  566. (PKSDATAFORMAT_WAVEFORMATEX)((*ppPinConnect) + 1);
  567. WaveFormatFromAudioRange(
  568. &DataRangeAudioIntersection,
  569. &pDataFormatWaveFormatEx->WaveFormatEx);
  570. if (pWaveFormatExLimit) {
  571. //
  572. // If we are trying the Client's data Format
  573. //
  574. if (pWaveFormatExLimit->wFormatTag != WAVE_FORMAT_PCM) {
  575. ULONG CopySize;
  576. //
  577. // and if it is extensible format
  578. // Set the Extensible related fields in the WaveformatEx
  579. // structure we are building as part of PinConnect
  580. //
  581. //
  582. // cast both pointers to Waveformat extensible equivalents
  583. //
  584. pDataFormatWaveFormatEx =
  585. (PKSDATAFORMAT_WAVEFORMATEX)((*ppPinConnect) + 1);
  586. pDataFormatWaveFormatEx->WaveFormatEx.wFormatTag = pWaveFormatExLimit->wFormatTag;
  587. pDataFormatWaveFormatEx->WaveFormatEx.cbSize = pWaveFormatExLimit->cbSize;
  588. CopySize = pWaveFormatExLimit->cbSize;
  589. if (CopySize) {
  590. PWAVEFORMATEX pWaveFormatExDest;
  591. pWaveFormatExDest = &pDataFormatWaveFormatEx->WaveFormatEx;
  592. RtlCopyMemory((pWaveFormatExDest+1),
  593. (pWaveFormatExLimit+1),
  594. CopySize);
  595. }
  596. }
  597. }
  598. pDataFormatWaveFormatEx->DataFormat =
  599. DataRangeAudioIntersection.DataRange;
  600. pDataFormatWaveFormatEx->DataFormat.FormatSize =
  601. sizeof(KSDATAFORMAT_WAVEFORMATEX);
  602. //
  603. // If we are dealing extensible format - set the FormatSize to the extensible equivalent
  604. //
  605. if (pWaveFormatExLimit) {
  606. pDataFormatWaveFormatEx->DataFormat.FormatSize = RegionAllocSize;
  607. }
  608. pDataFormatWaveFormatEx->DataFormat.SampleSize =
  609. pDataFormatWaveFormatEx->WaveFormatEx.nBlockAlign;
  610. DPF3(90, "CreateWaveFormatEx SUCCESS SR %d CH %d BPS %d",
  611. pDataFormatWaveFormatEx->WaveFormatEx.nSamplesPerSec,
  612. pDataFormatWaveFormatEx->WaveFormatEx.nChannels,
  613. pDataFormatWaveFormatEx->WaveFormatEx.wBitsPerSample);
  614. }
  615. else {
  616. Status = STATUS_INVALID_DEVICE_REQUEST;
  617. goto exit;
  618. }
  619. exit:
  620. if(!NT_SUCCESS(Status)) {
  621. delete *ppPinConnect;
  622. *ppPinConnect = NULL;
  623. DPF4(90, "CreateWaveFormatEx FAILED %08x SR %d CH %d BPS %d",
  624. Status,
  625. pWaveFormatExLimit->nSamplesPerSec,
  626. pWaveFormatExLimit->nChannels,
  627. pWaveFormatExLimit->wBitsPerSample);
  628. }
  629. return(Status);
  630. }
  631. VOID
  632. WaveFormatFromAudioRange(
  633. PKSDATARANGE_AUDIO pDataRangeAudio,
  634. WAVEFORMATEX *pWaveFormatEx
  635. )
  636. {
  637. if(IS_VALID_WAVEFORMATEX_GUID(&pDataRangeAudio->DataRange.SubFormat)) {
  638. pWaveFormatEx->wFormatTag =
  639. EXTRACT_WAVEFORMATEX_ID(&pDataRangeAudio->DataRange.SubFormat);
  640. }
  641. else {
  642. pWaveFormatEx->wFormatTag = WAVE_FORMAT_UNKNOWN;
  643. }
  644. pWaveFormatEx->nChannels = (WORD)pDataRangeAudio->MaximumChannels;
  645. pWaveFormatEx->nSamplesPerSec = pDataRangeAudio->MaximumSampleFrequency;
  646. pWaveFormatEx->wBitsPerSample = (WORD)pDataRangeAudio->MaximumBitsPerSample;
  647. pWaveFormatEx->nBlockAlign =
  648. (pWaveFormatEx->nChannels * pWaveFormatEx->wBitsPerSample)/8;
  649. pWaveFormatEx->nAvgBytesPerSec =
  650. pWaveFormatEx->nSamplesPerSec * pWaveFormatEx->nBlockAlign;
  651. pWaveFormatEx->cbSize = 0;
  652. }
  653. BOOL
  654. LimitAudioRangeToWave(
  655. PWAVEFORMATEX pWaveFormatEx,
  656. PKSDATARANGE_AUDIO pDataRangeAudio
  657. )
  658. {
  659. PWAVEFORMATEXTENSIBLE pWaveFormatExtensible;
  660. DPF5(20, "LimitAudioRangeToWave: SR: %d %d CH: %d BPS %d %d",
  661. pDataRangeAudio->MinimumSampleFrequency,
  662. pDataRangeAudio->MaximumSampleFrequency,
  663. pDataRangeAudio->MaximumChannels,
  664. pDataRangeAudio->MinimumBitsPerSample,
  665. pDataRangeAudio->MaximumBitsPerSample);
  666. if(pWaveFormatEx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
  667. pWaveFormatExtensible = (PWAVEFORMATEXTENSIBLE)pWaveFormatEx;
  668. if (!IsEqualGUID(&pWaveFormatExtensible->SubFormat, &pDataRangeAudio->DataRange.SubFormat)) {
  669. return(FALSE);
  670. }
  671. }
  672. else { // not WAVE_FORMAT_EXTENSIBLE
  673. if(IS_VALID_WAVEFORMATEX_GUID(&pDataRangeAudio->DataRange.SubFormat)) {
  674. if (pWaveFormatEx->wFormatTag !=
  675. EXTRACT_WAVEFORMATEX_ID(&pDataRangeAudio->DataRange.SubFormat) ) {
  676. return(FALSE);
  677. }
  678. }
  679. }
  680. if(pDataRangeAudio->MinimumSampleFrequency <=
  681. pWaveFormatEx->nSamplesPerSec &&
  682. pDataRangeAudio->MaximumSampleFrequency >=
  683. pWaveFormatEx->nSamplesPerSec) {
  684. pDataRangeAudio->MaximumSampleFrequency = pWaveFormatEx->nSamplesPerSec;
  685. }
  686. else {
  687. return(FALSE);
  688. }
  689. if(pDataRangeAudio->MinimumBitsPerSample <=
  690. pWaveFormatEx->wBitsPerSample &&
  691. pDataRangeAudio->MaximumBitsPerSample >=
  692. pWaveFormatEx->wBitsPerSample) {
  693. pDataRangeAudio->MaximumBitsPerSample = pWaveFormatEx->wBitsPerSample;
  694. }
  695. else {
  696. return(FALSE);
  697. }
  698. // Because there is no minimum channel in the data range,
  699. // take the maximum channel to be what the requestor wants.
  700. // i.e. don't limit the number of channels.
  701. if(pDataRangeAudio->MaximumChannels >= pWaveFormatEx->nChannels) {
  702. pDataRangeAudio->MaximumChannels = pWaveFormatEx->nChannels;
  703. }
  704. else {
  705. return(FALSE);
  706. }
  707. return(TRUE);
  708. }
  709. //---------------------------------------------------------------------------
  710. #ifdef DEBUG
  711. ENUMFUNC
  712. CConnectNodeInstance::Dump(
  713. )
  714. {
  715. if(this == NULL) {
  716. return(STATUS_CONTINUE);
  717. }
  718. if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
  719. dprintf("CNI: %08x cRef %08x CN %08x FNISource %08x FNISink %08x\n",
  720. this,
  721. cReference,
  722. pConnectNode,
  723. pFilterNodeInstanceSource,
  724. pFilterNodeInstanceSink);
  725. dprintf(" pPNISource: %08x pPNISink %08x\n",
  726. pPinNodeInstanceSource,
  727. pPinNodeInstanceSink);
  728. if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
  729. if(pPinNodeInstanceSource != NULL) {
  730. pPinNodeInstanceSource->Dump();
  731. }
  732. if(pPinNodeInstanceSink != NULL) {
  733. pPinNodeInstanceSink->Dump();
  734. }
  735. }
  736. if(pPinConnect != NULL) {
  737. DumpPinConnect(MAXULONG, pPinConnect);
  738. }
  739. }
  740. else {
  741. dprintf(" Fr: ");
  742. if(pPinNodeInstanceSource != NULL) {
  743. pPinNodeInstanceSource->Dump();
  744. }
  745. else {
  746. dprintf("NULL\n");
  747. }
  748. dprintf(" To: ");
  749. if(pPinNodeInstanceSink != NULL) {
  750. pPinNodeInstanceSink->Dump();
  751. }
  752. else {
  753. dprintf("NULL\n");
  754. }
  755. }
  756. return(STATUS_CONTINUE);
  757. }
  758. #endif
  759. //---------------------------------------------------------------------------