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.

1758 lines
48 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: virtual.c
  4. //
  5. // Description:
  6. // Virtual Source Stuff
  7. //
  8. //
  9. //@@BEGIN_MSINTERNAL
  10. // Development Team:
  11. // Andy Nicholson
  12. //
  13. // History: Date Author Comment
  14. //
  15. // To Do: Date Author Comment
  16. //
  17. //@@END_MSINTERNAL
  18. //---------------------------------------------------------------------------
  19. //
  20. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  21. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  22. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  23. // PURPOSE.
  24. //
  25. // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
  26. //
  27. //---------------------------------------------------------------------------
  28. #include "common.h"
  29. //---------------------------------------------------------------------------
  30. // Virtual Source Data
  31. KSDATARANGE DataRangeWildCard =
  32. {
  33. sizeof(KSDATARANGE),
  34. 0,
  35. 0,
  36. 0,
  37. STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
  38. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
  39. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WILDCARD),
  40. };
  41. KSPIN_MEDIUM VirtualPinMedium =
  42. {
  43. STATICGUIDOF(KSMEDIUMSETID_Standard),
  44. KSMEDIUM_STANDARD_DEVIO
  45. };
  46. KSDATARANGE VirtualPinDataRange =
  47. {
  48. sizeof(KSDATARANGE),
  49. 0,
  50. 0,
  51. 0,
  52. STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
  53. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
  54. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE),
  55. };
  56. //---------------------------------------------------------------------------
  57. NTSTATUS
  58. CreateVirtualMixer(
  59. PDEVICE_NODE pDeviceNode
  60. )
  61. {
  62. PTOPOLOGY_CONNECTION pTopologyConnection;
  63. PVIRTUAL_SOURCE_LINE pVirtualSourceLine;
  64. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  65. PTOPOLOGY_PIN pTopologyPinSumOutput;
  66. PTOPOLOGY_NODE pTopologyNodeSum;
  67. NTSTATUS Status = STATUS_SUCCESS;
  68. PFILTER_NODE pFilterNode;
  69. PPIN_INFO pPinInfo;
  70. PPIN_NODE pPinNode;
  71. //
  72. // Create a special "virtual source" filter node and related structures
  73. //
  74. pFilterNode = new FILTER_NODE(FILTER_TYPE_AUDIO | FILTER_TYPE_VIRTUAL);
  75. if(pFilterNode == NULL) {
  76. Status = STATUS_INSUFFICIENT_RESOURCES;
  77. Trap();
  78. goto exit;
  79. }
  80. pFilterNode->SetFriendlyName(L"Virtual Mixer");
  81. Status = pFilterNode->AddDeviceInterfaceMatch(
  82. pDeviceNode->GetDeviceInterface());
  83. if(!NT_SUCCESS(Status)) {
  84. Trap();
  85. goto exit;
  86. }
  87. //
  88. // Create the logical filter node for this "virtual" filter
  89. //
  90. Status = CLogicalFilterNode::Create(&pLogicalFilterNode, pFilterNode);
  91. if(!NT_SUCCESS(Status)) {
  92. Trap();
  93. goto exit;
  94. }
  95. Status = CTopologyNode::Create(
  96. &pTopologyNodeSum,
  97. pFilterNode,
  98. MAXULONG,
  99. (GUID *)&KSNODETYPE_SUM);
  100. if(!NT_SUCCESS(Status)) {
  101. Trap();
  102. goto exit;
  103. }
  104. pTopologyNodeSum->iVirtualSource = 0;
  105. Status = pLogicalFilterNode->lstTopologyNode.AddList(pTopologyNodeSum);
  106. if(!NT_SUCCESS(Status)) {
  107. Trap();
  108. goto exit;
  109. }
  110. Status = pLogicalFilterNode->AddList(
  111. &pTopologyNodeSum->lstLogicalFilterNode);
  112. if(!NT_SUCCESS(Status)) {
  113. Trap();
  114. goto exit;
  115. }
  116. Status = CTopologyPin::Create(
  117. &pTopologyPinSumOutput,
  118. 0, // 0 output
  119. pTopologyNodeSum);
  120. if(!NT_SUCCESS(Status)) {
  121. Trap();
  122. goto exit;
  123. }
  124. //
  125. // Create a virtual sysaudio source pin
  126. //
  127. pPinInfo = new PIN_INFO(pFilterNode, 0);
  128. if(pPinInfo == NULL) {
  129. Status = STATUS_INSUFFICIENT_RESOURCES;
  130. Trap();
  131. goto exit;
  132. }
  133. pPinInfo->DataFlow = KSPIN_DATAFLOW_OUT;
  134. pPinInfo->Communication = KSPIN_COMMUNICATION_SOURCE;
  135. pPinInfo->cPinInstances.PossibleCount = MAXULONG;
  136. pFilterNode->cPins++;
  137. pPinNode = new PIN_NODE(pPinInfo);
  138. if(pPinNode == NULL) {
  139. Status = STATUS_INSUFFICIENT_RESOURCES;
  140. Trap();
  141. goto exit;
  142. }
  143. pPinNode->pMedium = INTERNAL_WILDCARD;
  144. pPinNode->pInterface = INTERNAL_WILDCARD;
  145. pPinNode->pDataRange = &DataRangeWildCard;
  146. Status = pLogicalFilterNode->lstPinNode.AddList(pPinNode);
  147. if(!NT_SUCCESS(Status)) {
  148. Trap();
  149. goto exit;
  150. }
  151. pPinNode->pLogicalFilterNode = pLogicalFilterNode;
  152. //
  153. // Connect the out of sum node to the source pin
  154. //
  155. Status = CTopologyConnection::Create(
  156. &pTopologyConnection,
  157. pFilterNode, // pFilterNode
  158. NULL, // pGraphNode
  159. pTopologyPinSumOutput, // pTopologyPin From
  160. NULL, // pTopologyPin To
  161. NULL, // pPinInfo From
  162. pPinInfo); // pPinInfo To
  163. if(!NT_SUCCESS(Status)) {
  164. Trap();
  165. goto exit;
  166. }
  167. Status = pTopologyConnection->AddList(
  168. &pLogicalFilterNode->lstTopologyConnection);
  169. if(!NT_SUCCESS(Status)) {
  170. Trap();
  171. goto exit;
  172. }
  173. FOR_EACH_LIST_ITEM(gplstVirtualSourceLine, pVirtualSourceLine) {
  174. ASSERT(pVirtualSourceLine->iVirtualSource <
  175. pDeviceNode->cVirtualSourceData);
  176. if(pDeviceNode->papVirtualSourceData[
  177. pVirtualSourceLine->iVirtualSource]->pTopologyNode != NULL) {
  178. continue;
  179. }
  180. Status = CreateVirtualLine(
  181. pDeviceNode,
  182. pFilterNode,
  183. pTopologyNodeSum,
  184. pLogicalFilterNode,
  185. pVirtualSourceLine);
  186. if(!NT_SUCCESS(Status)) {
  187. Trap();
  188. goto exit;
  189. }
  190. } END_EACH_LIST_ITEM
  191. // if new virtual source lines were created
  192. if(pFilterNode->cPins > 1) {
  193. pDeviceNode->pFilterNodeVirtual = pFilterNode;
  194. }
  195. else {
  196. delete pFilterNode;
  197. }
  198. exit:
  199. if(!NT_SUCCESS(Status)) {
  200. Trap();
  201. delete pFilterNode;
  202. }
  203. return(Status);
  204. }
  205. NTSTATUS
  206. CreateVirtualLine(
  207. PDEVICE_NODE pDeviceNode,
  208. PFILTER_NODE pFilterNode,
  209. PTOPOLOGY_NODE pTopologyNodeSum,
  210. PLOGICAL_FILTER_NODE pLogicalFilterNode,
  211. PVIRTUAL_SOURCE_LINE pVirtualSourceLine
  212. )
  213. {
  214. PTOPOLOGY_CONNECTION pTopologyConnection;
  215. NTSTATUS Status = STATUS_SUCCESS;
  216. PTOPOLOGY_NODE pTopologyNode;
  217. PTOPOLOGY_PIN pTopologyPinSumInput;
  218. PTOPOLOGY_PIN pTopologyPinVolume;
  219. PTOPOLOGY_PIN pTopologyPinMute;
  220. PPIN_INFO pPinInfo;
  221. PPIN_NODE pPinNode;
  222. //
  223. // Create a virtual sysaudio pin
  224. //
  225. pPinInfo = new PIN_INFO(pFilterNode, pVirtualSourceLine->iVirtualSource+1);
  226. if(pPinInfo == NULL) {
  227. Status = STATUS_INSUFFICIENT_RESOURCES;
  228. Trap();
  229. goto exit;
  230. }
  231. pPinInfo->DataFlow = KSPIN_DATAFLOW_IN;
  232. pPinInfo->Communication = KSPIN_COMMUNICATION_NONE;
  233. pPinInfo->pguidCategory = &pVirtualSourceLine->guidCategory;
  234. pPinInfo->pguidName = &pVirtualSourceLine->guidName;
  235. pFilterNode->cPins++;
  236. pPinNode = new PIN_NODE(pPinInfo);
  237. if(pPinNode == NULL) {
  238. Status = STATUS_INSUFFICIENT_RESOURCES;
  239. Trap();
  240. goto exit;
  241. }
  242. pPinNode->pMedium = &VirtualPinMedium;
  243. pPinNode->pDataRange = &VirtualPinDataRange;
  244. Status = pLogicalFilterNode->lstPinNode.AddList(pPinNode);
  245. if(!NT_SUCCESS(Status)) {
  246. Trap();
  247. goto exit;
  248. }
  249. pPinNode->pLogicalFilterNode = pLogicalFilterNode;
  250. //
  251. // Create a virtual volume topology node and input topology pin
  252. //
  253. Status = CTopologyNode::Create(
  254. &pTopologyNode,
  255. pFilterNode,
  256. MAXULONG,
  257. (GUID *)&KSNODETYPE_VOLUME);
  258. if(!NT_SUCCESS(Status)) {
  259. Trap();
  260. goto exit;
  261. }
  262. pTopologyNode->iVirtualSource = pVirtualSourceLine->iVirtualSource;
  263. ASSERT(pVirtualSourceLine->iVirtualSource <
  264. pDeviceNode->cVirtualSourceData);
  265. pDeviceNode->papVirtualSourceData[
  266. pVirtualSourceLine->iVirtualSource]->pTopologyNode = pTopologyNode;
  267. Status = pLogicalFilterNode->lstTopologyNode.AddList(pTopologyNode);
  268. if(!NT_SUCCESS(Status)) {
  269. Trap();
  270. goto exit;
  271. }
  272. Status = pLogicalFilterNode->AddList(&pTopologyNode->lstLogicalFilterNode);
  273. if(!NT_SUCCESS(Status)) {
  274. Trap();
  275. goto exit;
  276. }
  277. Status = CTopologyPin::Create(
  278. &pTopologyPinVolume,
  279. KSNODEPIN_STANDARD_IN, // 1 = input
  280. pTopologyNode);
  281. if(!NT_SUCCESS(Status)) {
  282. Trap();
  283. goto exit;
  284. }
  285. //
  286. // Create a connection from virtual pin to volume node
  287. //
  288. Status = CTopologyConnection::Create(
  289. &pTopologyConnection,
  290. pFilterNode, // pFilterNode
  291. NULL, // pGraphNode
  292. NULL, // pTopologyPin From
  293. pTopologyPinVolume, // pTopologyPin To
  294. pPinInfo, // pPinInfo From
  295. NULL); // pPinInfo To
  296. if(!NT_SUCCESS(Status)) {
  297. Trap();
  298. goto exit;
  299. }
  300. Status = pTopologyConnection->AddList(
  301. &pLogicalFilterNode->lstTopologyConnection);
  302. if(!NT_SUCCESS(Status)) {
  303. Trap();
  304. goto exit;
  305. }
  306. Status = CTopologyPin::Create(
  307. &pTopologyPinVolume,
  308. KSNODEPIN_STANDARD_OUT, // 0 = output
  309. pTopologyNode);
  310. if(!NT_SUCCESS(Status)) {
  311. Trap();
  312. goto exit;
  313. }
  314. //
  315. // Create a virtual mute topology node and input topology pin
  316. //
  317. Status = CTopologyNode::Create(
  318. &pTopologyNode,
  319. pFilterNode,
  320. MAXULONG,
  321. (GUID *)&KSNODETYPE_MUTE);
  322. if(!NT_SUCCESS(Status)) {
  323. Trap();
  324. goto exit;
  325. }
  326. pTopologyNode->iVirtualSource = pVirtualSourceLine->iVirtualSource;
  327. Status = pLogicalFilterNode->lstTopologyNode.AddList(pTopologyNode);
  328. if(!NT_SUCCESS(Status)) {
  329. Trap();
  330. goto exit;
  331. }
  332. Status = pLogicalFilterNode->AddList(&pTopologyNode->lstLogicalFilterNode);
  333. if(!NT_SUCCESS(Status)) {
  334. Trap();
  335. goto exit;
  336. }
  337. Status = CTopologyPin::Create(
  338. &pTopologyPinMute,
  339. KSNODEPIN_STANDARD_IN, // 1 = input
  340. pTopologyNode);
  341. if(!NT_SUCCESS(Status)) {
  342. Trap();
  343. goto exit;
  344. }
  345. //
  346. // Create a connection from volume node to mute node pin
  347. //
  348. Status = CTopologyConnection::Create(
  349. &pTopologyConnection,
  350. pFilterNode, // pFilterNode
  351. NULL, // pGraphNode
  352. pTopologyPinVolume, // pTopologyPin From
  353. pTopologyPinMute, // pTopologyPin To
  354. NULL, // pPinInfo From
  355. NULL); // pPinInfo To
  356. if(!NT_SUCCESS(Status)) {
  357. Trap();
  358. goto exit;
  359. }
  360. Status = pTopologyConnection->AddList(
  361. &pLogicalFilterNode->lstTopologyConnection);
  362. if(!NT_SUCCESS(Status)) {
  363. Trap();
  364. goto exit;
  365. }
  366. Status = CTopologyPin::Create(
  367. &pTopologyPinMute,
  368. KSNODEPIN_STANDARD_OUT, // 1 = output
  369. pTopologyNode);
  370. if(!NT_SUCCESS(Status)) {
  371. Trap();
  372. goto exit;
  373. }
  374. Status = CTopologyPin::Create(
  375. &pTopologyPinSumInput,
  376. pVirtualSourceLine->iVirtualSource + 1, // >= 1 input
  377. pTopologyNodeSum);
  378. if(!NT_SUCCESS(Status)) {
  379. Trap();
  380. goto exit;
  381. }
  382. //
  383. // Create a connection from mute node to sum node pin
  384. //
  385. Status = CTopologyConnection::Create(
  386. &pTopologyConnection,
  387. pFilterNode, // pFilterNode
  388. NULL, // pGraphNode
  389. pTopologyPinMute, // pTopologyPin From
  390. pTopologyPinSumInput, // pTopologyPin To
  391. NULL, // pPinInfo From
  392. NULL); // pPinInfo To
  393. if(!NT_SUCCESS(Status)) {
  394. Trap();
  395. goto exit;
  396. }
  397. Status = pTopologyConnection->AddList(
  398. &pLogicalFilterNode->lstTopologyConnection);
  399. if(!NT_SUCCESS(Status)) {
  400. Trap();
  401. goto exit;
  402. }
  403. exit:
  404. return(Status);
  405. }
  406. //---------------------------------------------------------------------------
  407. ENUMFUNC
  408. VirtualizeFindPin(
  409. IN PTOPOLOGY_CONNECTION pTopologyConnection,
  410. IN BOOL fToDirection,
  411. IN PVOID pReference
  412. )
  413. {
  414. NTSTATUS Status = STATUS_CONTINUE;
  415. IN PPIN_INFO pPinInfo;
  416. Assert(pTopologyConnection);
  417. if(!IS_CONNECTION_TYPE(pTopologyConnection, FILTER)) {
  418. Status = STATUS_DEAD_END;
  419. goto exit;
  420. }
  421. if(fToDirection) {
  422. pPinInfo = pTopologyConnection->pPinInfoTo;
  423. }
  424. else {
  425. pPinInfo = pTopologyConnection->pPinInfoFrom;
  426. }
  427. if(pPinInfo == NULL) {
  428. ASSERT(Status == STATUS_CONTINUE);
  429. goto exit;
  430. }
  431. if(pPinInfo->pguidCategory == NULL) {
  432. ASSERT(Status == STATUS_CONTINUE);
  433. goto exit;
  434. }
  435. if(IsEqualGUID(pPinInfo->pguidCategory, &KSNODETYPE_SPEAKER)) {
  436. Status = STATUS_SUCCESS;
  437. }
  438. exit:
  439. return(Status);
  440. }
  441. ENUMFUNC
  442. EnumerateVirtualizeFindPin(
  443. IN PTOPOLOGY_CONNECTION pTopologyConnection,
  444. IN BOOL fToDirection
  445. )
  446. {
  447. ENUM_TOPOLOGY EnumTopology;
  448. NTSTATUS Status;
  449. Assert(pTopologyConnection);
  450. EnumTopology.cTopologyRecursion = 0;
  451. EnumTopology.Function = VirtualizeFindPin;
  452. EnumTopology.fToDirection = fToDirection;
  453. EnumTopology.pReference = NULL;
  454. Status = EnumerateTopologyConnection(pTopologyConnection, &EnumTopology);
  455. return(Status);
  456. }
  457. ENUMFUNC
  458. VirtualizeFindNode(
  459. IN PTOPOLOGY_CONNECTION pTopologyConnection,
  460. IN BOOL fToDirection,
  461. OUT PTOPOLOGY_NODE *ppTopologyNode,
  462. IN GUID const *pguidType
  463. )
  464. {
  465. NTSTATUS Status = STATUS_CONTINUE;
  466. PTOPOLOGY_PIN pTopologyPin;
  467. Assert(pTopologyConnection);
  468. if(!IS_CONNECTION_TYPE(pTopologyConnection, FILTER)) {
  469. Status = STATUS_DEAD_END;
  470. goto exit;
  471. }
  472. if(fToDirection) {
  473. pTopologyPin = pTopologyConnection->pTopologyPinTo;
  474. }
  475. else {
  476. pTopologyPin = pTopologyConnection->pTopologyPinFrom;
  477. }
  478. if(pTopologyPin == NULL) {
  479. ASSERT(Status == STATUS_CONTINUE);
  480. goto exit;
  481. }
  482. if(IsEqualGUID(pTopologyPin->pTopologyNode->pguidType, &KSNODETYPE_SUM)) {
  483. Status = STATUS_DEAD_END;
  484. goto exit;
  485. }
  486. if(IsEqualGUID(pTopologyPin->pTopologyNode->pguidType, &KSNODETYPE_MUX)) {
  487. Status = STATUS_DEAD_END;
  488. goto exit;
  489. }
  490. if(IsEqualGUID(pTopologyPin->pTopologyNode->pguidType, pguidType)) {
  491. Status = EnumerateVirtualizeFindPin(pTopologyConnection, fToDirection);
  492. if(NT_SUCCESS(Status)) {
  493. *ppTopologyNode = pTopologyPin->pTopologyNode;
  494. }
  495. ASSERT(Status != STATUS_DEAD_END);
  496. }
  497. exit:
  498. return(Status);
  499. }
  500. ENUMFUNC
  501. VirtualizeFindMute(
  502. IN PTOPOLOGY_CONNECTION pTopologyConnection,
  503. IN BOOL fToDirection,
  504. OUT PTOPOLOGY_NODE *ppTopologyNode
  505. )
  506. {
  507. return(VirtualizeFindNode(
  508. pTopologyConnection,
  509. fToDirection,
  510. ppTopologyNode,
  511. &KSNODETYPE_MUTE));
  512. }
  513. ENUMFUNC
  514. VirtualizeFindVolume(
  515. IN PTOPOLOGY_CONNECTION pTopologyConnection,
  516. IN BOOL fToDirection,
  517. OUT PTOPOLOGY_NODE *ppTopologyNode
  518. )
  519. {
  520. return(VirtualizeFindNode(
  521. pTopologyConnection,
  522. fToDirection,
  523. ppTopologyNode,
  524. &KSNODETYPE_VOLUME));
  525. }
  526. VOID
  527. VirtualizeTopologyNode(
  528. IN PDEVICE_NODE pDeviceNode,
  529. IN PTOPOLOGY_NODE pTopologyNode,
  530. IN PVIRTUAL_SOURCE_LINE pVirtualSourceLine
  531. )
  532. {
  533. DPF3(100, "VirtualizeTopologyNode: real node #%d index %d %s",
  534. pTopologyNode->ulRealNodeNumber,
  535. pVirtualSourceLine->iVirtualSource,
  536. DbgGuid2Sz(&pVirtualSourceLine->guidCategory));
  537. ASSERT(
  538. (pTopologyNode->iVirtualSource == MAXULONG) ||
  539. (pTopologyNode->iVirtualSource == pVirtualSourceLine->iVirtualSource));
  540. // The PinId of a virtual pininfo has VirtualSourceData index
  541. pTopologyNode->iVirtualSource = pVirtualSourceLine->iVirtualSource;
  542. if(pVirtualSourceLine->ulFlags & VSL_FLAGS_CREATE_ONLY) {
  543. pTopologyNode->ulFlags |= TN_FLAGS_DONT_FORWARD;
  544. }
  545. ASSERT(pTopologyNode->iVirtualSource < pDeviceNode->cVirtualSourceData);
  546. //
  547. // Store the topologyNode in virtualsource structures for further usage.
  548. //
  549. if(IsEqualGUID(pTopologyNode->pguidType, &KSNODETYPE_VOLUME)) {
  550. pDeviceNode->papVirtualSourceData[
  551. pTopologyNode->iVirtualSource]->pTopologyNode = pTopologyNode;
  552. }
  553. }
  554. NTSTATUS
  555. AddVirtualMute(
  556. IN PDEVICE_NODE pDeviceNode,
  557. IN PTOPOLOGY_NODE pTopologyNodeVolume,
  558. IN PVIRTUAL_SOURCE_LINE pVirtualSourceLine
  559. )
  560. {
  561. PTOPOLOGY_CONNECTION pTopologyConnectionNew = NULL;
  562. PTOPOLOGY_CONNECTION pTopologyConnection = NULL;
  563. PTOPOLOGY_NODE pTopologyNodeMute = NULL;
  564. PTOPOLOGY_PIN pTopologyPinMuteInput = NULL;
  565. PTOPOLOGY_PIN pTopologyPinMuteOutput = NULL;
  566. PTOPOLOGY_PIN pTopologyPinVolumeOutput = NULL;
  567. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  568. NTSTATUS Status;
  569. ASSERT(pTopologyNodeVolume->iVirtualSource != MAXULONG);
  570. FOR_EACH_LIST_ITEM(
  571. &pTopologyNodeVolume->lstTopologyPin,
  572. pTopologyPinVolumeOutput) {
  573. if(pTopologyPinVolumeOutput->ulPinNumber == KSNODEPIN_STANDARD_OUT) {
  574. break;
  575. }
  576. } END_EACH_LIST_ITEM
  577. if(pTopologyPinVolumeOutput == NULL) {
  578. Trap();
  579. Status = STATUS_INVALID_DEVICE_REQUEST;
  580. goto exit;
  581. }
  582. ASSERT(pTopologyPinVolumeOutput->ulPinNumber == KSNODEPIN_STANDARD_OUT);
  583. FOR_EACH_LIST_ITEM(
  584. &pTopologyPinVolumeOutput->lstTopologyConnection,
  585. pTopologyConnection) {
  586. Assert(pTopologyConnection);
  587. if(EnumerateVirtualizeFindPin(
  588. pTopologyConnection,
  589. TRUE) == STATUS_SUCCESS) { // Assumes KSPIN_DATAFLOW_IN
  590. break;
  591. }
  592. } END_EACH_LIST_ITEM
  593. if(pTopologyConnection == NULL) {
  594. Trap();
  595. Status = STATUS_INVALID_DEVICE_REQUEST;
  596. goto exit;
  597. }
  598. ASSERT(pTopologyConnection->pTopologyPinFrom == pTopologyPinVolumeOutput);
  599. Status = CTopologyNode::Create(
  600. &pTopologyNodeMute,
  601. pTopologyNodeVolume->pFilterNode,
  602. MAXULONG,
  603. (GUID *)&KSNODETYPE_MUTE);
  604. if(!NT_SUCCESS(Status)) {
  605. Trap();
  606. goto exit;
  607. }
  608. VirtualizeTopologyNode(pDeviceNode, pTopologyNodeMute, pVirtualSourceLine);
  609. Status = CTopologyPin::Create(
  610. &pTopologyPinMuteInput,
  611. KSNODEPIN_STANDARD_IN, // 1 = input
  612. pTopologyNodeMute);
  613. if(!NT_SUCCESS(Status)) {
  614. Trap();
  615. goto exit;
  616. }
  617. Status = CTopologyPin::Create(
  618. &pTopologyPinMuteOutput,
  619. KSNODEPIN_STANDARD_OUT, // 0 = output
  620. pTopologyNodeMute);
  621. if(!NT_SUCCESS(Status)) {
  622. Trap();
  623. goto exit;
  624. }
  625. Status = CTopologyConnection::Create(
  626. &pTopologyConnectionNew,
  627. pTopologyNodeVolume->pFilterNode, // pFilterNode
  628. NULL, // pGraphNode
  629. pTopologyPinVolumeOutput, // pTopologyPin From
  630. pTopologyPinMuteInput, // pTopologyPin To
  631. NULL, // pPinInfo From
  632. NULL); // pPinInfo To
  633. if(!NT_SUCCESS(Status)) {
  634. Trap();
  635. goto exit;
  636. }
  637. Status = pTopologyConnection->AddList(
  638. &pTopologyPinMuteOutput->lstTopologyConnection);
  639. if(!NT_SUCCESS(Status)) {
  640. Trap();
  641. goto exit;
  642. }
  643. FOR_EACH_LIST_ITEM(
  644. &pTopologyNodeVolume->lstLogicalFilterNode,
  645. pLogicalFilterNode) {
  646. Status = pLogicalFilterNode->AddList(
  647. &pTopologyNodeMute->lstLogicalFilterNode);
  648. if(!NT_SUCCESS(Status)) {
  649. Trap();
  650. goto exit;
  651. }
  652. Status = pLogicalFilterNode->lstTopologyNode.AddList(pTopologyNodeMute);
  653. if(!NT_SUCCESS(Status)) {
  654. Trap();
  655. goto exit;
  656. }
  657. Status = pTopologyConnectionNew->AddList(
  658. &pLogicalFilterNode->lstTopologyConnection);
  659. if(!NT_SUCCESS(Status)) {
  660. Trap();
  661. goto exit;
  662. }
  663. } END_EACH_LIST_ITEM
  664. pTopologyConnection->pTopologyPinFrom = pTopologyPinMuteOutput;
  665. pTopologyConnection->RemoveList(
  666. &pTopologyPinVolumeOutput->lstTopologyConnection);
  667. exit:
  668. if(!NT_SUCCESS(Status)) {
  669. Trap();
  670. if(pTopologyConnectionNew != NULL) {
  671. Trap();
  672. pTopologyConnectionNew->Destroy();
  673. }
  674. if(pTopologyNodeMute != NULL) {
  675. if(pTopologyNodeVolume != NULL) {
  676. Trap();
  677. pTopologyNodeMute->RemoveList(
  678. &pTopologyNodeVolume->pFilterNode->lstTopologyNode);
  679. FOR_EACH_LIST_ITEM(
  680. &pTopologyNodeVolume->lstLogicalFilterNode,
  681. pLogicalFilterNode) {
  682. pLogicalFilterNode->lstTopologyNode.RemoveList(
  683. pTopologyNodeMute);
  684. } END_EACH_LIST_ITEM
  685. }
  686. pTopologyNodeMute->Destroy();
  687. }
  688. }
  689. return(Status);
  690. }
  691. NTSTATUS
  692. VirtualizeTopology(
  693. PDEVICE_NODE pDeviceNode,
  694. PFILTER_NODE pFilterNode
  695. )
  696. {
  697. PVIRTUAL_SOURCE_LINE pVirtualSourceLine;
  698. PTOPOLOGY_NODE pTopologyNodeVolume;
  699. PTOPOLOGY_NODE pTopologyNodeMute;
  700. NTSTATUS Status = STATUS_SUCCESS;
  701. PPIN_INFO pPinInfo;
  702. FOR_EACH_LIST_ITEM(&pFilterNode->lstPinInfo, pPinInfo) {
  703. if(pPinInfo->pguidCategory == NULL) {
  704. continue;
  705. }
  706. FOR_EACH_LIST_ITEM(gplstVirtualSourceLine, pVirtualSourceLine) {
  707. if(pPinInfo->DataFlow != KSPIN_DATAFLOW_IN) {
  708. continue;
  709. }
  710. if(!IsEqualGUID(
  711. pPinInfo->pguidCategory,
  712. &pVirtualSourceLine->guidCategory)) {
  713. continue;
  714. }
  715. if(EnumerateTopology(
  716. pPinInfo,
  717. (TOP_PFN)VirtualizeFindVolume,
  718. &pTopologyNodeVolume) == STATUS_SUCCESS) {
  719. VirtualizeTopologyNode(
  720. pDeviceNode,
  721. pTopologyNodeVolume,
  722. pVirtualSourceLine);
  723. if(EnumerateTopology(
  724. pPinInfo,
  725. (TOP_PFN)VirtualizeFindMute,
  726. &pTopologyNodeMute) == STATUS_SUCCESS) {
  727. VirtualizeTopologyNode(
  728. pDeviceNode,
  729. pTopologyNodeMute,
  730. pVirtualSourceLine);
  731. }
  732. else {
  733. Status = AddVirtualMute(
  734. pDeviceNode,
  735. pTopologyNodeVolume,
  736. pVirtualSourceLine);
  737. if(!NT_SUCCESS(Status)) {
  738. Trap();
  739. goto exit;
  740. }
  741. }
  742. }
  743. } END_EACH_LIST_ITEM
  744. } END_EACH_LIST_ITEM
  745. exit:
  746. return(Status);
  747. }
  748. //---------------------------------------------------------------------------
  749. NTSTATUS
  750. CreateVirtualSource(
  751. IN PIRP pIrp,
  752. PSYSAUDIO_CREATE_VIRTUAL_SOURCE pCreateVirtualSource,
  753. OUT PULONG pulMixerPinId
  754. )
  755. {
  756. PVIRTUAL_SOURCE_LINE pVirtualSourceLine = NULL;
  757. NTSTATUS Status = STATUS_SUCCESS;
  758. PFILTER_INSTANCE pFilterInstance;
  759. PIO_STACK_LOCATION pIrpStack;
  760. PDEVICE_NODE pDeviceNode;
  761. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  762. pFilterInstance = (PFILTER_INSTANCE)pIrpStack->FileObject->FsContext;
  763. Assert(pFilterInstance);
  764. //
  765. // VirtualSources are not created if there is already an active pin
  766. // instance on this filter.
  767. //
  768. if(!pFilterInstance->IsChildInstance()) {
  769. DPF(5, "CreateVirtualSource: FAILED - open pin instances");
  770. Status = STATUS_INVALID_DEVICE_REQUEST;
  771. goto exit;
  772. }
  773. //
  774. // Make sure that this is not a duplicate.
  775. //
  776. FOR_EACH_LIST_ITEM(gplstVirtualSourceLine, pVirtualSourceLine) {
  777. if(!IsEqualGUID(
  778. &pVirtualSourceLine->guidCategory,
  779. &pCreateVirtualSource->PinCategory)) {
  780. continue;
  781. }
  782. if(!IsEqualGUID(
  783. &pVirtualSourceLine->guidName,
  784. &pCreateVirtualSource->PinName)) {
  785. continue;
  786. }
  787. ASSERT(NT_SUCCESS(Status));
  788. goto dup;
  789. } END_EACH_LIST_ITEM
  790. pVirtualSourceLine = new VIRTUAL_SOURCE_LINE(pCreateVirtualSource);
  791. if(pVirtualSourceLine == NULL) {
  792. Status = STATUS_INSUFFICIENT_RESOURCES;
  793. Trap();
  794. goto exit;
  795. }
  796. FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
  797. DPF2(60, "CreateVirtualSource: DN %08x %s",
  798. pDeviceNode,
  799. pDeviceNode->DumpName());
  800. Status = pDeviceNode->Update();
  801. if(!NT_SUCCESS(Status)) {
  802. Trap();
  803. goto exit;
  804. }
  805. } END_EACH_LIST_ITEM
  806. dup:
  807. *pulMixerPinId = pVirtualSourceLine->iVirtualSource;
  808. pIrp->IoStatus.Information = sizeof(ULONG);
  809. exit:
  810. if(!NT_SUCCESS(Status)) {
  811. delete pVirtualSourceLine;
  812. }
  813. return(Status);
  814. }
  815. NTSTATUS
  816. AttachVirtualSource(
  817. IN PIRP pIrp,
  818. IN PSYSAUDIO_ATTACH_VIRTUAL_SOURCE pAttachVirtualSource,
  819. IN OUT PVOID pData
  820. )
  821. {
  822. PVIRTUAL_NODE_DATA pVirtualNodeData = NULL;
  823. PSTART_NODE_INSTANCE pStartNodeInstance;
  824. PVIRTUAL_SOURCE_DATA pVirtualSourceData;
  825. NTSTATUS Status = STATUS_SUCCESS;
  826. PPIN_INSTANCE pPinInstance;
  827. PDEVICE_NODE pDeviceNode;
  828. LONG Channel;
  829. Status = ::GetStartNodeInstance(pIrp, &pStartNodeInstance);
  830. if(!NT_SUCCESS(Status)) {
  831. goto exit;
  832. }
  833. pPinInstance = pStartNodeInstance->pPinInstance;
  834. Assert(pPinInstance);
  835. Assert(pPinInstance->pFilterInstance);
  836. Assert(pPinInstance->pFilterInstance->pGraphNodeInstance);
  837. pDeviceNode = pPinInstance->pFilterInstance->GetDeviceNode();
  838. Assert(pDeviceNode);
  839. if(pAttachVirtualSource->MixerPinId >= pDeviceNode->cVirtualSourceData) {
  840. DPF(5, "AttachVirtualSource: invalid MixerPinId");
  841. Status = STATUS_INVALID_DEVICE_REQUEST;
  842. goto exit;
  843. }
  844. ASSERT(pDeviceNode->papVirtualSourceData != NULL);
  845. pVirtualSourceData =
  846. pDeviceNode->papVirtualSourceData[pAttachVirtualSource->MixerPinId];
  847. Assert(pVirtualSourceData);
  848. Status = GetVolumeNodeNumber(pPinInstance, pVirtualSourceData);
  849. if(!NT_SUCCESS(Status)) {
  850. Trap();
  851. goto exit;
  852. }
  853. if(pPinInstance->ulVolumeNodeNumber == MAXULONG) {
  854. ASSERT(NT_SUCCESS(Status));
  855. goto exit;
  856. }
  857. pVirtualNodeData = new VIRTUAL_NODE_DATA(
  858. pStartNodeInstance,
  859. pVirtualSourceData);
  860. if(pVirtualNodeData == NULL) {
  861. Trap();
  862. Status = STATUS_INSUFFICIENT_RESOURCES;
  863. goto exit;
  864. }
  865. if(pVirtualSourceData->pTopologyNode->ulRealNodeNumber != MAXULONG) {
  866. ULONG ulNodeNumber;
  867. //
  868. // Get the volume control range for the physical node
  869. //
  870. ulNodeNumber = pPinInstance->pFilterInstance->pGraphNodeInstance->
  871. paulNodeNumber[pAttachVirtualSource->MixerPinId];
  872. if(ulNodeNumber == pPinInstance->ulVolumeNodeNumber) {
  873. ASSERT(NT_SUCCESS(Status));
  874. delete pVirtualNodeData;
  875. goto exit;
  876. }
  877. Status = pStartNodeInstance->GetTopologyNodeFileObject(
  878. &pVirtualNodeData->pFileObject,
  879. ulNodeNumber);
  880. if(!NT_SUCCESS(Status)) {
  881. Trap();
  882. goto exit;
  883. }
  884. pVirtualNodeData->NodeId =
  885. pVirtualSourceData->pTopologyNode->ulRealNodeNumber;
  886. Status = GetControlRange(pVirtualNodeData);
  887. if(!NT_SUCCESS(Status)) {
  888. goto exit;
  889. }
  890. pVirtualSourceData->MinimumValue = pVirtualNodeData->MinimumValue;
  891. pVirtualSourceData->MaximumValue = pVirtualNodeData->MaximumValue;
  892. pVirtualSourceData->Steps = pVirtualNodeData->Steps;
  893. }
  894. Status = pStartNodeInstance->GetTopologyNodeFileObject(
  895. &pVirtualNodeData->pFileObject,
  896. pPinInstance->ulVolumeNodeNumber);
  897. if(!NT_SUCCESS(Status)) {
  898. Trap();
  899. goto exit;
  900. }
  901. pVirtualNodeData->NodeId = pPinInstance->pFilterInstance->
  902. pGraphNodeInstance->papTopologyNode[pPinInstance->ulVolumeNodeNumber]->
  903. ulRealNodeNumber;
  904. Status = GetControlRange(pVirtualNodeData);
  905. if(!NT_SUCCESS(Status)) {
  906. goto exit;
  907. }
  908. for(Channel = 0; Channel < pVirtualSourceData->cChannels; Channel++) {
  909. Status = SetVirtualVolume(pVirtualNodeData, Channel);
  910. if(!NT_SUCCESS(Status)) {
  911. Trap();
  912. goto exit;
  913. }
  914. }
  915. exit:
  916. if(!NT_SUCCESS(Status)) {
  917. delete pVirtualNodeData;
  918. }
  919. return(Status);
  920. }
  921. NTSTATUS
  922. FilterVirtualPropertySupportHandler(
  923. IN PIRP pIrp,
  924. IN PKSNODEPROPERTY pNodeProperty,
  925. IN OUT PVOID pData
  926. )
  927. {
  928. PGRAPH_NODE_INSTANCE pGraphNodeInstance;
  929. PTOPOLOGY_NODE pTopologyNode;
  930. NTSTATUS Status;
  931. Status = GetGraphNodeInstance(pIrp, &pGraphNodeInstance);
  932. if(!NT_SUCCESS(Status)) {
  933. goto exit;
  934. }
  935. Assert(pGraphNodeInstance);
  936. Status = STATUS_NOT_FOUND;
  937. if((pNodeProperty->Property.Flags & KSPROPERTY_TYPE_TOPOLOGY) == 0) {
  938. DPF(5, "FilterVirtualPropertySupportHandler: no TOPOLOGY bit");
  939. ASSERT(Status == STATUS_NOT_FOUND);
  940. goto exit;
  941. }
  942. if(pNodeProperty->NodeId >=
  943. pGraphNodeInstance->Topology.TopologyNodesCount) {
  944. DPF(5, "FilterVirtualPropertySupportHandler: invalid node #");
  945. ASSERT(Status == STATUS_NOT_FOUND);
  946. goto exit;
  947. }
  948. pTopologyNode = pGraphNodeInstance->papTopologyNode[pNodeProperty->NodeId];
  949. Assert(pTopologyNode);
  950. if(pTopologyNode->ulRealNodeNumber == MAXULONG) {
  951. ASSERT(pTopologyNode->iVirtualSource != MAXULONG);
  952. Status = STATUS_SOME_NOT_MAPPED;
  953. goto exit;
  954. }
  955. ASSERT(Status == STATUS_NOT_FOUND);
  956. exit:
  957. return(Status);
  958. }
  959. NTSTATUS
  960. FilterVirtualPropertyHandler(
  961. IN PIRP pIrp,
  962. IN PKSNODEPROPERTY pNodeProperty,
  963. IN OUT PLONG plLevel
  964. )
  965. {
  966. PGRAPH_NODE_INSTANCE pGraphNodeInstance;
  967. PVIRTUAL_SOURCE_DATA pVirtualSourceData;
  968. PVIRTUAL_NODE_DATA pVirtualNodeData;
  969. PIO_STACK_LOCATION pIrpStack;
  970. PTOPOLOGY_NODE pTopologyNode;
  971. LONG StopChannel, Channel;
  972. NTSTATUS Status;
  973. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  974. Status = GetGraphNodeInstance(pIrp, &pGraphNodeInstance);
  975. if(!NT_SUCCESS(Status)) {
  976. goto exit;
  977. }
  978. Assert(pGraphNodeInstance);
  979. if(((pNodeProperty->Property.Flags & KSPROPERTY_TYPE_TOPOLOGY) == 0) ||
  980. (pNodeProperty->NodeId >=
  981. pGraphNodeInstance->Topology.TopologyNodesCount)) {
  982. DPF(5, "FilterVirtualPropertyHandler: invalid property");
  983. Status = STATUS_NOT_FOUND;
  984. goto exit;
  985. }
  986. pTopologyNode = pGraphNodeInstance->papTopologyNode[pNodeProperty->NodeId];
  987. Assert(pTopologyNode);
  988. if(pTopologyNode->iVirtualSource == MAXULONG) {
  989. Status = STATUS_NOT_FOUND;
  990. goto exit;
  991. }
  992. ASSERT(pTopologyNode->iVirtualSource < gcVirtualSources);
  993. ASSERT(pGraphNodeInstance->pGraphNode->pDeviceNode->
  994. papVirtualSourceData != NULL);
  995. pVirtualSourceData = pGraphNodeInstance->pGraphNode->pDeviceNode->
  996. papVirtualSourceData[pTopologyNode->iVirtualSource];
  997. Assert(pVirtualSourceData);
  998. //
  999. // ISSUE: 03/07/2002 These checks are totally irrelevant.
  1000. // KS would have never called this functions if these conditions
  1001. // have not been met before.
  1002. //
  1003. if(pIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  1004. sizeof(KSNODEPROPERTY_AUDIO_CHANNEL) ||
  1005. (pNodeProperty->Property.Id != KSPROPERTY_AUDIO_VOLUMELEVEL &&
  1006. pNodeProperty->Property.Id != KSPROPERTY_AUDIO_MUTE)) {
  1007. Trap();
  1008. Status = STATUS_INVALID_DEVICE_REQUEST;
  1009. goto exit;
  1010. }
  1011. Channel = ((PKSNODEPROPERTY_AUDIO_CHANNEL)pNodeProperty)->Channel;
  1012. StopChannel = Channel;
  1013. if(Channel == MAXULONG) {
  1014. Channel = 0;
  1015. StopChannel = pVirtualSourceData->cChannels - 1;
  1016. }
  1017. if(Channel >= MAX_NUM_CHANNELS || Channel < 0) {
  1018. Status = STATUS_INVALID_DEVICE_REQUEST;
  1019. goto exit;
  1020. }
  1021. for(; Channel <= StopChannel; Channel++) {
  1022. if(IsEqualGUID(pTopologyNode->pguidType, &KSNODETYPE_MUTE)) {
  1023. if(pNodeProperty->Property.Flags & KSPROPERTY_TYPE_GET) {
  1024. *plLevel = pVirtualSourceData->fMuted[Channel];
  1025. pIrp->IoStatus.Information = sizeof(LONG);
  1026. }
  1027. else {
  1028. ASSERT(pNodeProperty->Property.Flags & KSPROPERTY_TYPE_SET);
  1029. pVirtualSourceData->fMuted[Channel] = *plLevel;
  1030. if(pTopologyNode->ulRealNodeNumber == MAXULONG) {
  1031. Status = SetPhysicalVolume(
  1032. pGraphNodeInstance,
  1033. pVirtualSourceData,
  1034. Channel);
  1035. if(!NT_SUCCESS(Status)) {
  1036. Trap();
  1037. goto exit;
  1038. }
  1039. }
  1040. }
  1041. }
  1042. else if(IsEqualGUID(pTopologyNode->pguidType, &KSNODETYPE_VOLUME)) {
  1043. if(pNodeProperty->Property.Flags & KSPROPERTY_TYPE_GET) {
  1044. *plLevel = pVirtualSourceData->lLevel[Channel];
  1045. pIrp->IoStatus.Information = sizeof(LONG);
  1046. }
  1047. else {
  1048. ASSERT(pNodeProperty->Property.Flags & KSPROPERTY_TYPE_SET);
  1049. pVirtualSourceData->lLevel[Channel] = *plLevel;
  1050. }
  1051. }
  1052. else {
  1053. DPF2(5, "Invalid TopologyNode Prop.Id %d Node.Id %d",
  1054. pNodeProperty->Property.Id,
  1055. pTopologyNode->ulRealNodeNumber);
  1056. Status = STATUS_INVALID_DEVICE_REQUEST;
  1057. goto exit;
  1058. }
  1059. ASSERT(NT_SUCCESS(Status));
  1060. if(pNodeProperty->Property.Flags & KSPROPERTY_TYPE_SET) {
  1061. FOR_EACH_LIST_ITEM(
  1062. &pVirtualSourceData->lstVirtualNodeData,
  1063. pVirtualNodeData) {
  1064. ASSERT(pVirtualSourceData ==
  1065. pVirtualNodeData->pVirtualSourceData);
  1066. Status = SetVirtualVolume(pVirtualNodeData, Channel);
  1067. if(!NT_SUCCESS(Status)) {
  1068. Trap();
  1069. goto exit;
  1070. }
  1071. } END_EACH_LIST_ITEM
  1072. }
  1073. }
  1074. if(pTopologyNode->ulRealNodeNumber == MAXULONG ||
  1075. pTopologyNode->ulFlags & TN_FLAGS_DONT_FORWARD ||
  1076. pNodeProperty->Property.Flags & KSPROPERTY_TYPE_GET) {
  1077. Status = STATUS_SUCCESS;
  1078. }
  1079. else {
  1080. // If topology node has a real node number, forward the irp to it
  1081. Status = STATUS_NOT_FOUND;
  1082. }
  1083. exit:
  1084. return(Status);
  1085. }
  1086. NTSTATUS
  1087. PinVirtualPropertySupportHandler(
  1088. IN PIRP pIrp,
  1089. IN PKSNODEPROPERTY pNodeProperty,
  1090. IN OUT PVOID pData
  1091. )
  1092. {
  1093. return(STATUS_NOT_FOUND);
  1094. }
  1095. NTSTATUS
  1096. PinVirtualPropertyHandler(
  1097. IN PIRP pIrp,
  1098. IN PKSNODEPROPERTY_AUDIO_CHANNEL pNodePropertyAudioChannel,
  1099. IN OUT PLONG plLevel
  1100. )
  1101. {
  1102. PSTART_NODE_INSTANCE pStartNodeInstance;
  1103. PFILTER_INSTANCE pFilterInstance;
  1104. NTSTATUS Status = STATUS_SUCCESS;
  1105. PKSNODEPROPERTY pNodeProperty;
  1106. PPIN_INSTANCE pPinInstance;
  1107. LONG StopChannel, Channel;
  1108. Status = ::GetStartNodeInstance(pIrp, &pStartNodeInstance);
  1109. if(!NT_SUCCESS(Status)) {
  1110. goto exit;
  1111. }
  1112. pPinInstance = pStartNodeInstance->pPinInstance;
  1113. Assert(pPinInstance);
  1114. pFilterInstance = pPinInstance->pFilterInstance;
  1115. Assert(pFilterInstance);
  1116. Assert(pFilterInstance->pGraphNodeInstance);
  1117. pNodeProperty = &pNodePropertyAudioChannel->NodeProperty;
  1118. if(((pNodeProperty->Property.Flags & KSPROPERTY_TYPE_TOPOLOGY) == 0) ||
  1119. (pNodeProperty->NodeId >=
  1120. pFilterInstance->pGraphNodeInstance->Topology.TopologyNodesCount)) {
  1121. DPF(5, "PinVirtualPropertyHandler: invalid property");
  1122. Status = STATUS_INVALID_DEVICE_REQUEST;
  1123. goto exit;
  1124. }
  1125. if(pStartNodeInstance->pVirtualNodeData == NULL ||
  1126. pPinInstance->ulVolumeNodeNumber == MAXULONG ||
  1127. pPinInstance->ulVolumeNodeNumber != pNodeProperty->NodeId) {
  1128. Status = STATUS_NOT_FOUND;
  1129. goto exit;
  1130. }
  1131. Assert(pStartNodeInstance->pVirtualNodeData);
  1132. Assert(pStartNodeInstance->pVirtualNodeData->pVirtualSourceData);
  1133. StopChannel = Channel = pNodePropertyAudioChannel->Channel;
  1134. if(Channel == MAXULONG) {
  1135. Channel = 0;
  1136. StopChannel = pStartNodeInstance->pVirtualNodeData->
  1137. pVirtualSourceData->cChannels - 1;
  1138. }
  1139. if(Channel >= MAX_NUM_CHANNELS || Channel < 0) {
  1140. Status = STATUS_INVALID_DEVICE_REQUEST;
  1141. goto exit;
  1142. }
  1143. for(; Channel <= StopChannel; Channel++) {
  1144. if(pNodeProperty->Property.Flags & KSPROPERTY_TYPE_GET) {
  1145. *plLevel = pStartNodeInstance->pVirtualNodeData->lLevel[Channel];
  1146. pIrp->IoStatus.Information = sizeof(LONG);
  1147. ASSERT(NT_SUCCESS(Status));
  1148. }
  1149. else {
  1150. ASSERT(pNodeProperty->Property.Flags & KSPROPERTY_TYPE_SET);
  1151. pStartNodeInstance->pVirtualNodeData->lLevel[Channel] = *plLevel;
  1152. Status = SetVirtualVolume(
  1153. pStartNodeInstance->pVirtualNodeData,
  1154. Channel);
  1155. if(!NT_SUCCESS(Status)) {
  1156. Trap();
  1157. goto exit;
  1158. }
  1159. }
  1160. }
  1161. exit:
  1162. return(Status);
  1163. }
  1164. NTSTATUS
  1165. GetControlRange(
  1166. PVIRTUAL_NODE_DATA pVirtualNodeData
  1167. )
  1168. {
  1169. PKSPROPERTY_DESCRIPTION pPropertyDescription = NULL;
  1170. PKSPROPERTY_MEMBERSHEADER pMemberHeader;
  1171. PKSPROPERTY_STEPPING_LONG pSteppingLong;
  1172. NTSTATUS Status = STATUS_SUCCESS;
  1173. // Setup the defaults
  1174. pVirtualNodeData->MinimumValue = (-96 * 65536);
  1175. pVirtualNodeData->MaximumValue = 0;
  1176. pVirtualNodeData->Steps = (65536/2); // 1/2 db steps
  1177. Status = QueryPropertyRange(
  1178. pVirtualNodeData->pFileObject,
  1179. &KSPROPSETID_Audio,
  1180. KSPROPERTY_AUDIO_VOLUMELEVEL,
  1181. pVirtualNodeData->NodeId,
  1182. &pPropertyDescription);
  1183. if(!NT_SUCCESS(Status)) {
  1184. goto exit;
  1185. }
  1186. if((pPropertyDescription->MembersListCount == 0) ||
  1187. (!IsEqualGUID(
  1188. &pPropertyDescription->PropTypeSet.Set,
  1189. &KSPROPTYPESETID_General)) ||
  1190. (pPropertyDescription->PropTypeSet.Id != VT_I4)) {
  1191. Status = STATUS_NOT_SUPPORTED;
  1192. goto exit;
  1193. }
  1194. pMemberHeader = (PKSPROPERTY_MEMBERSHEADER)(pPropertyDescription + 1);
  1195. if(pMemberHeader->MembersFlags & KSPROPERTY_MEMBER_STEPPEDRANGES) {
  1196. pSteppingLong = (PKSPROPERTY_STEPPING_LONG)(pMemberHeader + 1);
  1197. pVirtualNodeData->MinimumValue = pSteppingLong->Bounds.SignedMinimum;
  1198. pVirtualNodeData->MaximumValue = pSteppingLong->Bounds.SignedMaximum;
  1199. pVirtualNodeData->Steps = pSteppingLong->SteppingDelta;
  1200. }
  1201. else {
  1202. Trap();
  1203. Status = STATUS_NOT_SUPPORTED;
  1204. goto exit;
  1205. }
  1206. exit:
  1207. delete pPropertyDescription;
  1208. return(STATUS_SUCCESS);
  1209. }
  1210. NTSTATUS
  1211. QueryPropertyRange(
  1212. PFILE_OBJECT pFileObject,
  1213. CONST GUID *pguidPropertySet,
  1214. ULONG ulPropertyId,
  1215. ULONG ulNodeId,
  1216. PKSPROPERTY_DESCRIPTION *ppPropertyDescription
  1217. )
  1218. {
  1219. KSPROPERTY_DESCRIPTION PropertyDescription;
  1220. KSNODEPROPERTY NodeProperty;
  1221. ULONG BytesReturned;
  1222. NTSTATUS Status;
  1223. NodeProperty.Property.Set = *pguidPropertySet;
  1224. NodeProperty.Property.Id = ulPropertyId;
  1225. NodeProperty.Property.Flags =
  1226. KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
  1227. NodeProperty.NodeId = ulNodeId;
  1228. NodeProperty.Reserved = 0;
  1229. AssertFileObject(pFileObject);
  1230. Status = KsSynchronousIoControlDevice(
  1231. pFileObject,
  1232. KernelMode,
  1233. IOCTL_KS_PROPERTY,
  1234. &NodeProperty,
  1235. sizeof(NodeProperty),
  1236. &PropertyDescription,
  1237. sizeof(PropertyDescription),
  1238. &BytesReturned);
  1239. if(!NT_SUCCESS(Status)) {
  1240. goto exit;
  1241. }
  1242. ASSERT(BytesReturned == sizeof(PropertyDescription));
  1243. *ppPropertyDescription =
  1244. (PKSPROPERTY_DESCRIPTION)new BYTE[PropertyDescription.DescriptionSize];
  1245. if(*ppPropertyDescription == NULL) {
  1246. Status = STATUS_INSUFFICIENT_RESOURCES;
  1247. goto exit;
  1248. }
  1249. AssertFileObject(pFileObject);
  1250. Status = KsSynchronousIoControlDevice(
  1251. pFileObject,
  1252. KernelMode,
  1253. IOCTL_KS_PROPERTY,
  1254. &NodeProperty,
  1255. sizeof( NodeProperty ),
  1256. *ppPropertyDescription,
  1257. PropertyDescription.DescriptionSize,
  1258. &BytesReturned);
  1259. if(!NT_SUCCESS(Status)) {
  1260. delete *ppPropertyDescription;
  1261. *ppPropertyDescription = NULL;
  1262. goto exit;
  1263. }
  1264. exit:
  1265. return(Status);
  1266. }
  1267. NTSTATUS
  1268. SetVirtualVolume(
  1269. PVIRTUAL_NODE_DATA pVirtualNodeData,
  1270. LONG Channel
  1271. )
  1272. {
  1273. KSNODEPROPERTY_AUDIO_CHANNEL NodePropertyAudioChannel;
  1274. NTSTATUS Status = STATUS_SUCCESS;
  1275. ULONG BytesReturned;
  1276. LONG lLevel;
  1277. ASSERT(pVirtualNodeData->NodeId != MAXULONG);
  1278. Assert(pVirtualNodeData->pVirtualSourceData);
  1279. NodePropertyAudioChannel.NodeProperty.Property.Set =
  1280. KSPROPSETID_Audio;
  1281. NodePropertyAudioChannel.NodeProperty.Property.Id =
  1282. KSPROPERTY_AUDIO_VOLUMELEVEL;
  1283. NodePropertyAudioChannel.NodeProperty.Property.Flags =
  1284. KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
  1285. NodePropertyAudioChannel.NodeProperty.NodeId = pVirtualNodeData->NodeId;
  1286. NodePropertyAudioChannel.Channel = Channel;
  1287. NodePropertyAudioChannel.Reserved = 0;
  1288. if(pVirtualNodeData->pVirtualSourceData->fMuted[Channel]) {
  1289. lLevel = LONG_MIN;
  1290. }
  1291. else {
  1292. if(pVirtualNodeData->pVirtualSourceData->lLevel[Channel] == LONG_MIN) {
  1293. lLevel = LONG_MIN;
  1294. }
  1295. else {
  1296. lLevel = pVirtualNodeData->lLevel[Channel];
  1297. if(lLevel != LONG_MIN) {
  1298. lLevel += pVirtualNodeData->pVirtualSourceData->lLevel[Channel];
  1299. lLevel = MapVirtualLevel(pVirtualNodeData, lLevel);
  1300. }
  1301. }
  1302. }
  1303. AssertFileObject(pVirtualNodeData->pFileObject);
  1304. Status = KsSynchronousIoControlDevice(
  1305. pVirtualNodeData->pFileObject,
  1306. KernelMode,
  1307. IOCTL_KS_PROPERTY,
  1308. &NodePropertyAudioChannel,
  1309. sizeof(KSNODEPROPERTY_AUDIO_CHANNEL),
  1310. &lLevel,
  1311. sizeof(LONG),
  1312. &BytesReturned);
  1313. if(!NT_SUCCESS(Status)) {
  1314. DPF4(10, "SetVirtualVolume: [%d] SNI %08x N# %u FAILED %08x",
  1315. Channel,
  1316. pVirtualNodeData->pStartNodeInstance,
  1317. pVirtualNodeData->NodeId,
  1318. Status);
  1319. }
  1320. return(STATUS_SUCCESS);
  1321. }
  1322. NTSTATUS
  1323. SetPhysicalVolume(
  1324. PGRAPH_NODE_INSTANCE pGraphNodeInstance,
  1325. PVIRTUAL_SOURCE_DATA pVirtualSourceData,
  1326. LONG Channel
  1327. )
  1328. {
  1329. KSNODEPROPERTY_AUDIO_CHANNEL NodePropertyAudioChannel;
  1330. NTSTATUS Status = STATUS_SUCCESS;
  1331. PFILE_OBJECT pFileObject;
  1332. ULONG BytesReturned;
  1333. LONG lLevel;
  1334. Assert(pGraphNodeInstance);
  1335. Assert(pVirtualSourceData);
  1336. ASSERT(IsEqualGUID(
  1337. pVirtualSourceData->pTopologyNode->pguidType,
  1338. &KSNODETYPE_VOLUME));
  1339. if(pVirtualSourceData->pTopologyNode->ulRealNodeNumber == MAXULONG) {
  1340. ASSERT(NT_SUCCESS(Status));
  1341. goto exit;
  1342. }
  1343. ASSERT(pVirtualSourceData->pTopologyNode->iVirtualSource <
  1344. gcVirtualSources);
  1345. Status = pGraphNodeInstance->GetTopologyNodeFileObject(
  1346. &pFileObject,
  1347. pGraphNodeInstance->paulNodeNumber[
  1348. pVirtualSourceData->pTopologyNode->iVirtualSource]);
  1349. if(!NT_SUCCESS(Status)) {
  1350. Trap();
  1351. goto exit;
  1352. }
  1353. NodePropertyAudioChannel.NodeProperty.Property.Set =
  1354. KSPROPSETID_Audio;
  1355. NodePropertyAudioChannel.NodeProperty.Property.Id =
  1356. KSPROPERTY_AUDIO_VOLUMELEVEL;
  1357. NodePropertyAudioChannel.NodeProperty.Property.Flags =
  1358. KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
  1359. NodePropertyAudioChannel.NodeProperty.NodeId =
  1360. pVirtualSourceData->pTopologyNode->ulRealNodeNumber;
  1361. NodePropertyAudioChannel.Channel = Channel;
  1362. NodePropertyAudioChannel.Reserved = 0;
  1363. if(pVirtualSourceData->fMuted[Channel]) {
  1364. lLevel = LONG_MIN;
  1365. }
  1366. else {
  1367. lLevel = pVirtualSourceData->lLevel[Channel];
  1368. }
  1369. AssertFileObject(pFileObject);
  1370. Status = KsSynchronousIoControlDevice(
  1371. pFileObject,
  1372. KernelMode,
  1373. IOCTL_KS_PROPERTY,
  1374. &NodePropertyAudioChannel,
  1375. sizeof(KSNODEPROPERTY_AUDIO_CHANNEL),
  1376. &lLevel,
  1377. sizeof(LONG),
  1378. &BytesReturned);
  1379. if(!NT_SUCCESS(Status)) {
  1380. Trap();
  1381. goto exit;
  1382. }
  1383. exit:
  1384. if(!NT_SUCCESS(Status)) {
  1385. DPF2(10, "SetPhysicalVolume: [%d] FAILED %08x", Channel, Status);
  1386. }
  1387. return(Status);
  1388. }
  1389. LONG
  1390. MapVirtualLevel(
  1391. PVIRTUAL_NODE_DATA pVirtualNodeData,
  1392. LONG lLevel
  1393. )
  1394. {
  1395. DPF4(100, "MapVirtualLevel: from %d max %d min %d step %d",
  1396. lLevel / 65536,
  1397. pVirtualNodeData->pVirtualSourceData->MaximumValue / 65536,
  1398. pVirtualNodeData->pVirtualSourceData->MinimumValue / 65536,
  1399. pVirtualNodeData->pVirtualSourceData->Steps / 65536);
  1400. if(lLevel != LONG_MIN) {
  1401. lLevel += pVirtualNodeData->MaximumValue -
  1402. pVirtualNodeData->pVirtualSourceData->MaximumValue;
  1403. }
  1404. DPF4(100, "MapVirtualLevel: to %d max %d min %d step %d",
  1405. lLevel / 65536,
  1406. pVirtualNodeData->MaximumValue / 65536,
  1407. pVirtualNodeData->MinimumValue / 65536,
  1408. pVirtualNodeData->Steps / 65536);
  1409. return(lLevel);
  1410. }
  1411. NTSTATUS
  1412. GetVolumeNodeNumber(
  1413. PPIN_INSTANCE pPinInstance,
  1414. PVIRTUAL_SOURCE_DATA pVirtualSourceData OPTIONAL
  1415. )
  1416. {
  1417. PSTART_NODE pStartNode;
  1418. NTSTATUS Status = STATUS_SUCCESS;
  1419. KSAUDIO_MIXCAP_TABLE AudioMixCapTable;
  1420. Assert(pPinInstance);
  1421. Assert(pPinInstance->pFilterInstance);
  1422. Assert(pPinInstance->pFilterInstance->pGraphNodeInstance);
  1423. if(pPinInstance->ulVolumeNodeNumber == MAXULONG) {
  1424. Assert(pPinInstance->pStartNodeInstance);
  1425. pStartNode = pPinInstance->pStartNodeInstance->pStartNode;
  1426. Assert(pStartNode);
  1427. Assert(pStartNode->GetStartInfo());
  1428. pPinInstance->ulVolumeNodeNumber =
  1429. pStartNode->GetStartInfo()->ulVolumeNodeNumberPre;
  1430. if(pStartNode->GetStartInfo()->ulVolumeNodeNumberSuperMix != MAXULONG &&
  1431. pStartNode->GetStartInfo()->ulVolumeNodeNumberPost != MAXULONG) {
  1432. Status = GetSuperMixCaps(
  1433. &AudioMixCapTable,
  1434. pPinInstance->pStartNodeInstance,
  1435. pStartNode->GetStartInfo()->ulVolumeNodeNumberSuperMix);
  1436. if(!NT_SUCCESS(Status)) {
  1437. Status = STATUS_SUCCESS;
  1438. goto exit;
  1439. }
  1440. if(AudioMixCapTable.OutputChannels != 1) {
  1441. pPinInstance->ulVolumeNodeNumber =
  1442. pStartNode->GetStartInfo()->ulVolumeNodeNumberPost;
  1443. if(pVirtualSourceData != NULL) {
  1444. pVirtualSourceData->cChannels =
  1445. AudioMixCapTable.OutputChannels;
  1446. }
  1447. }
  1448. }
  1449. DPF2(100, "GetVolumeNodeNumber: SN %08x %02x",
  1450. pStartNode,
  1451. pPinInstance->ulVolumeNodeNumber);
  1452. }
  1453. exit:
  1454. return(Status);
  1455. }
  1456. NTSTATUS
  1457. GetSuperMixCaps(
  1458. OUT PKSAUDIO_MIXCAP_TABLE pAudioMixCapTable,
  1459. IN PSTART_NODE_INSTANCE pStartNodeInstance,
  1460. IN ULONG NodeId
  1461. )
  1462. {
  1463. NTSTATUS Status = STATUS_SUCCESS;
  1464. KSNODEPROPERTY NodeProperty;
  1465. PFILE_OBJECT pFileObject;
  1466. ULONG BytesReturned;
  1467. Assert(pStartNodeInstance);
  1468. ASSERT(NodeId != MAXULONG);
  1469. Status = pStartNodeInstance->GetTopologyNodeFileObject(
  1470. &pFileObject,
  1471. NodeId);
  1472. if(!NT_SUCCESS(Status)) {
  1473. Trap();
  1474. goto exit;
  1475. }
  1476. NodeProperty.Property.Set = KSPROPSETID_Audio;
  1477. NodeProperty.Property.Id = KSPROPERTY_AUDIO_MIX_LEVEL_CAPS;
  1478. NodeProperty.Property.Flags =
  1479. KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
  1480. NodeProperty.NodeId = pStartNodeInstance->pPinInstance->pFilterInstance->
  1481. pGraphNodeInstance->papTopologyNode[NodeId]->ulRealNodeNumber;
  1482. NodeProperty.Reserved = 0;
  1483. ASSERT(NodeProperty.NodeId != MAXULONG);
  1484. AssertFileObject(pFileObject);
  1485. Status = KsSynchronousIoControlDevice(
  1486. pFileObject,
  1487. KernelMode,
  1488. IOCTL_KS_PROPERTY,
  1489. &NodeProperty,
  1490. sizeof(KSNODEPROPERTY),
  1491. pAudioMixCapTable,
  1492. sizeof(KSAUDIO_MIXCAP_TABLE) - sizeof(KSAUDIO_MIX_CAPS),
  1493. &BytesReturned);
  1494. exit:
  1495. return(Status);
  1496. }