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

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