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.

1245 lines
33 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: sni.cpp
  4. //
  5. // Description:
  6. //
  7. // Start 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. WAVEFORMATEX aWaveFormatEx[] = {
  30. {
  31. WAVE_FORMAT_PCM, // wFormatTag
  32. 2, // nChannels
  33. 44100, // nSamplesPerSec
  34. 0, // nAvgBytesPerSec
  35. 0, // nBlockAlign
  36. 16, // wBitsPerSample
  37. 0, // cbSize
  38. },
  39. {
  40. WAVE_FORMAT_PCM, // wFormatTag
  41. 1, // nChannels
  42. 44100, // nSamplesPerSec
  43. 0, // nAvgBytesPerSec
  44. 0, // nBlockAlign
  45. 16, // wBitsPerSample
  46. 0, // cbSize
  47. },
  48. {
  49. WAVE_FORMAT_PCM, // wFormatTag
  50. 2, // nChannels
  51. 44100, // nSamplesPerSec
  52. 0, // nAvgBytesPerSec
  53. 0, // nBlockAlign
  54. 8, // wBitsPerSample
  55. 0, // cbSize
  56. },
  57. {
  58. WAVE_FORMAT_PCM, // wFormatTag
  59. 1, // nChannels
  60. 44100, // nSamplesPerSec
  61. 0, // nAvgBytesPerSec
  62. 0, // nBlockAlign
  63. 8, // wBitsPerSample
  64. 0, // cbSize
  65. },
  66. {
  67. WAVE_FORMAT_PCM, // wFormatTag
  68. 2, // nChannels
  69. 48000, // nSamplesPerSec
  70. 0, // nAvgBytesPerSec
  71. 0, // nBlockAlign
  72. 16, // wBitsPerSample
  73. 0, // cbSize
  74. },
  75. {
  76. WAVE_FORMAT_PCM, // wFormatTag
  77. 1, // nChannels
  78. 48000, // nSamplesPerSec
  79. 0, // nAvgBytesPerSec
  80. 0, // nBlockAlign
  81. 16, // wBitsPerSample
  82. 0, // cbSize
  83. },
  84. {
  85. WAVE_FORMAT_PCM, // wFormatTag
  86. 2, // nChannels
  87. 48000, // nSamplesPerSec
  88. 0, // nAvgBytesPerSec
  89. 0, // nBlockAlign
  90. 8, // wBitsPerSample
  91. 0, // cbSize
  92. },
  93. {
  94. WAVE_FORMAT_PCM, // wFormatTag
  95. 1, // nChannels
  96. 48000, // nSamplesPerSec
  97. 0, // nAvgBytesPerSec
  98. 0, // nBlockAlign
  99. 8, // wBitsPerSample
  100. 0, // cbSize
  101. },
  102. {
  103. WAVE_FORMAT_PCM, // wFormatTag
  104. 2, // nChannels
  105. 32000, // nSamplesPerSec
  106. 0, // nAvgBytesPerSec
  107. 0, // nBlockAlign
  108. 16, // wBitsPerSample
  109. 0, // cbSize
  110. },
  111. {
  112. WAVE_FORMAT_PCM, // wFormatTag
  113. 1, // nChannels
  114. 32000, // nSamplesPerSec
  115. 0, // nAvgBytesPerSec
  116. 0, // nBlockAlign
  117. 16, // wBitsPerSample
  118. 0, // cbSize
  119. },
  120. {
  121. WAVE_FORMAT_PCM, // wFormatTag
  122. 2, // nChannels
  123. 32000, // nSamplesPerSec
  124. 0, // nAvgBytesPerSec
  125. 0, // nBlockAlign
  126. 8, // wBitsPerSample
  127. 0, // cbSize
  128. },
  129. {
  130. WAVE_FORMAT_PCM, // wFormatTag
  131. 1, // nChannels
  132. 32000, // nSamplesPerSec
  133. 0, // nAvgBytesPerSec
  134. 0, // nBlockAlign
  135. 8, // wBitsPerSample
  136. 0, // cbSize
  137. },
  138. {
  139. WAVE_FORMAT_PCM, // wFormatTag
  140. 2, // nChannels
  141. 22050, // nSamplesPerSec
  142. 0, // nAvgBytesPerSec
  143. 0, // nBlockAlign
  144. 16, // wBitsPerSample
  145. 0, // cbSize
  146. },
  147. {
  148. WAVE_FORMAT_PCM, // wFormatTag
  149. 1, // nChannels
  150. 22050, // nSamplesPerSec
  151. 0, // nAvgBytesPerSec
  152. 0, // nBlockAlign
  153. 16, // wBitsPerSample
  154. 0, // cbSize
  155. },
  156. {
  157. WAVE_FORMAT_PCM, // wFormatTag
  158. 2, // nChannels
  159. 22050, // nSamplesPerSec
  160. 0, // nAvgBytesPerSec
  161. 0, // nBlockAlign
  162. 8, // wBitsPerSample
  163. 0, // cbSize
  164. },
  165. {
  166. WAVE_FORMAT_PCM, // wFormatTag
  167. 1, // nChannels
  168. 22050, // nSamplesPerSec
  169. 0, // nAvgBytesPerSec
  170. 0, // nBlockAlign
  171. 8, // wBitsPerSample
  172. 0, // cbSize
  173. },
  174. {
  175. WAVE_FORMAT_PCM, // wFormatTag
  176. 2, // nChannels
  177. 16000, // nSamplesPerSec
  178. 0, // nAvgBytesPerSec
  179. 0, // nBlockAlign
  180. 16, // wBitsPerSample
  181. 0, // cbSize
  182. },
  183. {
  184. WAVE_FORMAT_PCM, // wFormatTag
  185. 1, // nChannels
  186. 16000, // nSamplesPerSec
  187. 0, // nAvgBytesPerSec
  188. 0, // nBlockAlign
  189. 16, // wBitsPerSample
  190. 0, // cbSize
  191. },
  192. {
  193. WAVE_FORMAT_PCM, // wFormatTag
  194. 2, // nChannels
  195. 16000, // nSamplesPerSec
  196. 0, // nAvgBytesPerSec
  197. 0, // nBlockAlign
  198. 8, // wBitsPerSample
  199. 0, // cbSize
  200. },
  201. {
  202. WAVE_FORMAT_PCM, // wFormatTag
  203. 1, // nChannels
  204. 16000, // nSamplesPerSec
  205. 0, // nAvgBytesPerSec
  206. 0, // nBlockAlign
  207. 8, // wBitsPerSample
  208. 0, // cbSize
  209. },
  210. {
  211. WAVE_FORMAT_PCM, // wFormatTag
  212. 2, // nChannels
  213. 11025, // nSamplesPerSec
  214. 0, // nAvgBytesPerSec
  215. 0, // nBlockAlign
  216. 16, // wBitsPerSample
  217. 0, // cbSize
  218. },
  219. {
  220. WAVE_FORMAT_PCM, // wFormatTag
  221. 1, // nChannels
  222. 11025, // nSamplesPerSec
  223. 0, // nAvgBytesPerSec
  224. 0, // nBlockAlign
  225. 16, // wBitsPerSample
  226. 0, // cbSize
  227. },
  228. {
  229. WAVE_FORMAT_PCM, // wFormatTag
  230. 2, // nChannels
  231. 11025, // nSamplesPerSec
  232. 0, // nAvgBytesPerSec
  233. 0, // nBlockAlign
  234. 8, // wBitsPerSample
  235. 0, // cbSize
  236. },
  237. {
  238. WAVE_FORMAT_PCM, // wFormatTag
  239. 1, // nChannels
  240. 11025, // nSamplesPerSec
  241. 0, // nAvgBytesPerSec
  242. 0, // nBlockAlign
  243. 8, // wBitsPerSample
  244. 0, // cbSize
  245. },
  246. {
  247. WAVE_FORMAT_PCM, // wFormatTag
  248. 2, // nChannels
  249. 8000, // nSamplesPerSec
  250. 0, // nAvgBytesPerSec
  251. 0, // nBlockAlign
  252. 16, // wBitsPerSample
  253. 0, // cbSize
  254. },
  255. {
  256. WAVE_FORMAT_PCM, // wFormatTag
  257. 1, // nChannels
  258. 8000, // nSamplesPerSec
  259. 0, // nAvgBytesPerSec
  260. 0, // nBlockAlign
  261. 16, // wBitsPerSample
  262. 0, // cbSize
  263. },
  264. {
  265. WAVE_FORMAT_PCM, // wFormatTag
  266. 2, // nChannels
  267. 8000, // nSamplesPerSec
  268. 0, // nAvgBytesPerSec
  269. 0, // nBlockAlign
  270. 8, // wBitsPerSample
  271. 0, // cbSize
  272. },
  273. {
  274. WAVE_FORMAT_PCM, // wFormatTag
  275. 1, // nChannels
  276. 8000, // nSamplesPerSec
  277. 0, // nAvgBytesPerSec
  278. 0, // nBlockAlign
  279. 8, // wBitsPerSample
  280. 0, // cbSize
  281. },
  282. };
  283. //---------------------------------------------------------------------------
  284. //---------------------------------------------------------------------------
  285. NTSTATUS
  286. CStartNodeInstance::Create(
  287. PPIN_INSTANCE pPinInstance,
  288. PSTART_NODE pStartNode,
  289. PKSPIN_CONNECT pPinConnect,
  290. PWAVEFORMATEX pWaveFormatExRequested,
  291. PWAVEFORMATEX pWaveFormatExRegistry
  292. )
  293. {
  294. PSTART_NODE_INSTANCE pStartNodeInstance = NULL;
  295. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  296. Assert(pPinInstance);
  297. Assert(pStartNode);
  298. Assert(pStartNode->pPinNode);
  299. DPF3(90, "CSNI::Create SN %08x #%d %s",
  300. pStartNode,
  301. pStartNode->pPinNode->pPinInfo->PinId,
  302. pStartNode->pPinNode->pPinInfo->pFilterNode->DumpName());
  303. #ifdef DEBUG
  304. DumpDataRange(95, (PKSDATARANGE_AUDIO)pStartNode->pPinNode->pDataRange);
  305. #endif
  306. if(!CompareIdentifier(
  307. pStartNode->pPinNode->pMedium,
  308. &pPinConnect->Medium)) {
  309. Trap();
  310. DPF1(90, "CSNI::Create: Medium %08X", pStartNode);
  311. ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
  312. goto exit;
  313. }
  314. if(!CompareIdentifier(
  315. pStartNode->pPinNode->pInterface,
  316. &pPinConnect->Interface)) {
  317. DPF1(90, "CSNI::Create: Interface %08X", pStartNode);
  318. ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
  319. goto exit;
  320. }
  321. if(!CompareDataRangeGuids(
  322. pStartNode->pPinNode->pDataRange,
  323. (PKSDATARANGE)(pPinConnect + 1))) {
  324. DPF1(90, "CSNI::Create: DataRange GUID %08X", pStartNode);
  325. ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
  326. goto exit;
  327. }
  328. //
  329. // VOICE MANAGEMENT and HW ACCELARATION
  330. // For HW accelarated pins we are not relying on local sysaudio
  331. // instance counts. PinCreate request will be sent down to the driver.
  332. // It is upto the driver to reject the request based on its capabilities.
  333. //
  334. if ((pStartNode->pPinNode->pPinInfo->pFilterNode->GetType() & FILTER_TYPE_RENDERER) &&
  335. (KSPIN_DATAFLOW_IN == pStartNode->pPinNode->pPinInfo->DataFlow) &&
  336. (KSPIN_COMMUNICATION_SINK == pStartNode->pPinNode->pPinInfo->Communication)) {
  337. DPF(20,"StartInfo::IsPinInstances return TRUE for HW");
  338. }
  339. else {
  340. if(!pStartNode->IsPinInstances()) {
  341. DPF1(90, "CSNI::Create: no instances SN %08X", pStartNode);
  342. Status = STATUS_DEVICE_BUSY;
  343. goto exit;
  344. }
  345. }
  346. pStartNodeInstance = new START_NODE_INSTANCE(pPinInstance, pStartNode);
  347. if(pStartNodeInstance == NULL) {
  348. Status = STATUS_INSUFFICIENT_RESOURCES;
  349. goto exit;
  350. }
  351. #ifndef UNDER_NT
  352. //
  353. // Try the format from the registry
  354. //
  355. if(pWaveFormatExRegistry != NULL) {
  356. DPF3(90, "CSNI::Create: Registry SR %d CH %d BPS %d",
  357. pWaveFormatExRegistry->nSamplesPerSec,
  358. pWaveFormatExRegistry->nChannels,
  359. pWaveFormatExRegistry->wBitsPerSample);
  360. Status = pStartNodeInstance->Connect(
  361. pPinInstance->pFilterInstance->GetDeviceNode(),
  362. pPinConnect,
  363. pWaveFormatExRegistry,
  364. NULL);
  365. }
  366. #endif
  367. //
  368. // If capture pin, try some intelligent variations of requested format
  369. //
  370. if(!NT_SUCCESS(Status) &&
  371. pWaveFormatExRequested != NULL &&
  372. pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT) {
  373. DPF(90, "CSNI::Create: IntelligentConnect");
  374. Status = pStartNodeInstance->IntelligentConnect(
  375. pPinInstance->pFilterInstance->GetDeviceNode(),
  376. pPinConnect,
  377. pWaveFormatExRequested);
  378. //
  379. // If the graph contains only splitter and capturer, only the
  380. // requested format can succeed.
  381. // So exit here.
  382. //
  383. if (pStartNodeInstance->pStartNode->IsCaptureFormatStrict()) {
  384. DPF1(50, "CSNI::Create: CaptureFormatStrict Bailing Out: Status %X", Status);
  385. goto exit;
  386. }
  387. }
  388. //
  389. // If capture pin and if aec is included, negotiate format between
  390. // aec and capture device.
  391. //
  392. if(!NT_SUCCESS(Status) &&
  393. pStartNode->IsAecIncluded() &&
  394. pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT) {
  395. PKSPIN_CONNECT pPinConnectDirect = NULL;
  396. DPF(90, "CSNI::Create: AecConnection");
  397. Status = pStartNodeInstance->AecConnectionFormat(
  398. pPinInstance->pFilterInstance->GetDeviceNode(),
  399. &pPinConnectDirect);
  400. //
  401. // Try mono/stereo formats first.
  402. //
  403. if (NT_SUCCESS(Status)) {
  404. for (WORD i = 1; i <= 2; i++) {
  405. ModifyPinConnect(pPinConnectDirect, i);
  406. Status = pStartNodeInstance->Connect(
  407. pPinInstance->pFilterInstance->GetDeviceNode(),
  408. pPinConnect,
  409. NULL,
  410. pPinConnectDirect);
  411. if (NT_SUCCESS(Status)) {
  412. break;
  413. }
  414. }
  415. }
  416. if (pPinConnectDirect) {
  417. delete pPinConnectDirect;
  418. }
  419. }
  420. //
  421. // Try pin data intersection
  422. //
  423. if(!NT_SUCCESS(Status)) {
  424. DPF(90, "CSNI::Create: Data Intersection");
  425. Status = pStartNodeInstance->Connect(
  426. pPinInstance->pFilterInstance->GetDeviceNode(),
  427. pPinConnect,
  428. NULL,
  429. NULL);
  430. }
  431. if(!NT_SUCCESS(Status)) {
  432. int i;
  433. //
  434. // Try each waveformatex limit until success
  435. //
  436. for(i = 0; i < SIZEOF_ARRAY(aWaveFormatEx); i++) {
  437. DPF3(90, "CSNI::Create: Array SR %d CH %d BPS %d",
  438. aWaveFormatEx[i].nSamplesPerSec,
  439. aWaveFormatEx[i].nChannels,
  440. aWaveFormatEx[i].wBitsPerSample);
  441. Status = pStartNodeInstance->Connect(
  442. pPinInstance->pFilterInstance->GetDeviceNode(),
  443. pPinConnect,
  444. &aWaveFormatEx[i],
  445. NULL);
  446. if(NT_SUCCESS(Status)) {
  447. break;
  448. }
  449. }
  450. }
  451. if(!NT_SUCCESS(Status)) {
  452. goto exit;
  453. }
  454. Status = pStartNodeInstance->CreateTopologyTable(
  455. pPinInstance->pFilterInstance->pGraphNodeInstance);
  456. if(!NT_SUCCESS(Status)) {
  457. Trap();
  458. goto exit;
  459. }
  460. ASSERT(pStartNodeInstance->CurrentState == KSSTATE_STOP);
  461. #ifdef DEBUG
  462. pStartNodeInstance->pPinConnect = (PKSPIN_CONNECT)
  463. new BYTE[sizeof(KSPIN_CONNECT) +
  464. ((PKSDATARANGE)(pPinConnect + 1))->FormatSize];
  465. if(pStartNodeInstance->pPinConnect != NULL) {
  466. memcpy(
  467. pStartNodeInstance->pPinConnect,
  468. pPinConnect,
  469. sizeof(KSPIN_CONNECT) +
  470. ((PKSDATARANGE)(pPinConnect + 1))->FormatSize);
  471. }
  472. #endif
  473. DPF1(90, "CSNI::Create: SUCCESS %08x", pStartNodeInstance);
  474. exit:
  475. if(!NT_SUCCESS(Status)) {
  476. DPF1(90, "CSNI::Create: FAIL %08x", Status);
  477. delete pStartNodeInstance;
  478. }
  479. return(Status);
  480. }
  481. CStartNodeInstance::CStartNodeInstance(
  482. PPIN_INSTANCE pPinInstance,
  483. PSTART_NODE pStartNode
  484. )
  485. {
  486. this->pStartNode = pStartNode;
  487. pStartNode->AddPinInstance();
  488. this->pPinInstance = pPinInstance;
  489. pPinInstance->pStartNodeInstance = this;
  490. AddList(
  491. &pPinInstance->pFilterInstance->pGraphNodeInstance->lstStartNodeInstance);
  492. }
  493. CStartNodeInstance::~CStartNodeInstance(
  494. )
  495. {
  496. PINSTANCE pInstance;
  497. ASSERT(this != NULL);
  498. Assert(this);
  499. Assert(pPinInstance);
  500. DPF1(95, "~CSNI: %08x", this);
  501. RemoveList();
  502. SetState(KSSTATE_STOP, SETSTATE_FLAG_IGNORE_ERROR);
  503. pStartNode->RemovePinInstance();
  504. pPinNodeInstance->Destroy(); // also see CSNI::CleanUp
  505. pFilterNodeInstance->Destroy(); //
  506. delete papFileObjectTopologyTable;
  507. delete pVirtualNodeData;
  508. #ifdef DEBUG
  509. delete pPinConnect;
  510. #endif
  511. pPinInstance->pStartNodeInstance = NULL;
  512. pPinInstance->ParentInstance.Invalidate();
  513. }
  514. VOID
  515. CStartNodeInstance::CleanUp(
  516. )
  517. {
  518. Assert(this);
  519. ASSERT(papFileObjectTopologyTable == NULL);
  520. ASSERT(pVirtualNodeData == NULL);
  521. ASSERT(CurrentState == KSSTATE_STOP);
  522. pPinNodeInstance->Destroy();
  523. pPinNodeInstance = NULL;
  524. pFilterNodeInstance->Destroy();
  525. pFilterNodeInstance = NULL;
  526. lstConnectNodeInstance.DestroyList();
  527. }
  528. NTSTATUS
  529. CStartNodeInstance::IntelligentConnect(
  530. PDEVICE_NODE pDeviceNode,
  531. PKSPIN_CONNECT pPinConnect,
  532. PWAVEFORMATEX pWaveFormatEx
  533. )
  534. {
  535. PWAVEFORMATEXTENSIBLE pWaveFormatExtensible;
  536. NTSTATUS Status;
  537. BOOL Continue;
  538. WORD NumChannels, BitWidth;
  539. PBYTE pWaveFormat = NULL;
  540. ULONG RegionAllocSize, RegionCopySize;
  541. BOOL IsFloat = FALSE;
  542. WORD MaxBitWidth, MinBitWidth, MaxChannels, MinChannels;
  543. //
  544. // First copy the user requested format into a local structure
  545. // (because we will tamper it later for different params)
  546. //
  547. if (pWaveFormatEx->wFormatTag == WAVE_FORMAT_PCM) {
  548. RegionAllocSize = sizeof(WAVEFORMATEX);
  549. RegionCopySize = sizeof(PCMWAVEFORMAT);
  550. }
  551. else {
  552. RegionAllocSize = sizeof(WAVEFORMATEX) + pWaveFormatEx->cbSize;
  553. RegionCopySize = RegionAllocSize;
  554. }
  555. pWaveFormat = new(BYTE[RegionAllocSize]);
  556. if (!pWaveFormat) {
  557. Status = STATUS_INSUFFICIENT_RESOURCES;
  558. goto exit;
  559. }
  560. RtlCopyMemory(pWaveFormat, pWaveFormatEx, RegionCopySize);
  561. //
  562. // cast for convenient access
  563. //
  564. pWaveFormatExtensible = (PWAVEFORMATEXTENSIBLE) pWaveFormat;
  565. if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_PCM) {
  566. pWaveFormatExtensible->Format.cbSize = 0;
  567. }
  568. DPF3(90, "CSNI::Create: Client SR %d CH %d BPS %d",
  569. pWaveFormatExtensible->Format.nSamplesPerSec,
  570. pWaveFormatExtensible->Format.nChannels,
  571. pWaveFormatExtensible->Format.wBitsPerSample);
  572. //
  573. // and try the requested format first
  574. //
  575. Status = this->Connect(
  576. pDeviceNode,
  577. pPinConnect,
  578. (PWAVEFORMATEX)pWaveFormatEx,
  579. NULL);
  580. //
  581. // If the graph contains only splitter and capturer, only the
  582. // requested format can succeed.
  583. // So exit here.
  584. //
  585. if (pStartNode->IsCaptureFormatStrict()) {
  586. goto exit;
  587. }
  588. if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
  589. IsFloat = TRUE;
  590. }
  591. if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
  592. if (IsEqualGUID(&pWaveFormatExtensible->SubFormat,&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
  593. IsFloat = TRUE;
  594. }
  595. }
  596. if (IsFloat == FALSE) {
  597. if (pWaveFormatExtensible->Format.wFormatTag != WAVE_FORMAT_PCM) {
  598. if (pWaveFormatExtensible->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
  599. goto exit;
  600. }
  601. else {
  602. if (!IsEqualGUID(&pWaveFormatExtensible->SubFormat,&KSDATAFORMAT_SUBTYPE_PCM)) {
  603. goto exit;
  604. }
  605. }
  606. }
  607. MaxBitWidth = (pWaveFormatExtensible->Format.wBitsPerSample>16)?pWaveFormatExtensible->Format.wBitsPerSample:16;
  608. MinBitWidth = 8;
  609. }
  610. else {
  611. MaxBitWidth = MinBitWidth = pWaveFormatEx->wBitsPerSample;
  612. }
  613. //
  614. // MaxChannels = (pWaveFormatExtensible->nChannels > 2) ? pWaveFormatExtensible->nChannels:2;
  615. // We can do this, what would be the channle mask for WaveFormatExtensible?
  616. //
  617. MaxChannels = 2;
  618. MinChannels = 1;
  619. //
  620. // If that failed with the same sample rate try different
  621. // combinations of numchannels & bitwidth
  622. //
  623. // Tries 4 combinations of STEREO/MONO & 8/16 bits
  624. // More intelligence can be built based upon device capability
  625. // (also does not check whether we tried a combination earlier)
  626. //
  627. if (!NT_SUCCESS(Status)) {
  628. Continue = TRUE;
  629. for (NumChannels = MaxChannels; (NumChannels >= MinChannels) && Continue; NumChannels--) {
  630. for (BitWidth = MaxBitWidth;
  631. (BitWidth >= MinBitWidth) && Continue;
  632. BitWidth=(BitWidth%8)?((BitWidth/8)*8):(BitWidth-8)) {
  633. pWaveFormatExtensible->Format.nChannels = NumChannels;
  634. pWaveFormatExtensible->Format.wBitsPerSample = BitWidth;
  635. pWaveFormatExtensible->Format.nBlockAlign = (NumChannels * BitWidth)/8;
  636. pWaveFormatExtensible->Format.nAvgBytesPerSec = pWaveFormatExtensible->Format.nSamplesPerSec *
  637. pWaveFormatExtensible->Format.nBlockAlign;
  638. if (pWaveFormatExtensible->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
  639. pWaveFormatExtensible->Samples.wValidBitsPerSample = BitWidth;
  640. if (NumChannels == 1) {
  641. pWaveFormatExtensible->dwChannelMask = SPEAKER_FRONT_CENTER;
  642. }
  643. else {
  644. pWaveFormatExtensible->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
  645. }
  646. }
  647. DPF3(90, "CSNI::Create: Client SR %d CH %d BPS %d",
  648. pWaveFormatExtensible->Format.nSamplesPerSec,
  649. pWaveFormatExtensible->Format.nChannels,
  650. pWaveFormatExtensible->Format.wBitsPerSample);
  651. Status = this->Connect(pDeviceNode,
  652. pPinConnect,
  653. (PWAVEFORMATEX)pWaveFormatExtensible,
  654. NULL);
  655. if (NT_SUCCESS(Status)) {
  656. Continue = FALSE;
  657. }
  658. }
  659. }
  660. }
  661. exit:
  662. delete [] pWaveFormat;
  663. return(Status);
  664. }
  665. NTSTATUS
  666. CStartNodeInstance::AecConnectionFormat(
  667. PDEVICE_NODE pDeviceNode,
  668. PKSPIN_CONNECT *ppPinConnect)
  669. {
  670. PCLIST_ITEM pListItem;
  671. PCONNECT_NODE_INSTANCE pConnectNodeInstance;
  672. PCONNECT_NODE_INSTANCE pBottomConnection;
  673. PCONNECT_NODE_INSTANCE pAecConnection = NULL;
  674. NTSTATUS Status = STATUS_SUCCESS;
  675. *ppPinConnect = NULL;
  676. Status = CConnectNodeInstance::Create(this, pDeviceNode);
  677. if(!NT_SUCCESS(Status)) {
  678. goto exit;
  679. }
  680. //
  681. // Get Aec Source and Capture Sink pins.
  682. //
  683. pListItem = lstConnectNodeInstance.GetListLast();
  684. pBottomConnection = lstConnectNodeInstance.GetListData(pListItem);
  685. FOR_EACH_LIST_ITEM_BACKWARD(&lstConnectNodeInstance, pConnectNodeInstance) {
  686. if (pConnectNodeInstance->pConnectNode->pPinNodeSource->
  687. pPinInfo->pFilterNode->GetType() & FILTER_TYPE_AEC) {
  688. pAecConnection = pConnectNodeInstance;
  689. break;
  690. }
  691. } END_EACH_LIST_ITEM
  692. if (NULL == pAecConnection || NULL == pBottomConnection) {
  693. DPF(5, "CSNI::AecConnectionFormat: Cannot find Aec or Capture");
  694. Status = STATUS_INVALID_DEVICE_REQUEST;
  695. goto exit;
  696. }
  697. DPF3(20, "Aec : %X %d %s",
  698. pAecConnection,
  699. pAecConnection->pConnectNode->pPinNodeSource->pPinInfo->PinId,
  700. pAecConnection->pConnectNode->pPinNodeSource->pPinInfo->pFilterNode->DumpName());
  701. DPF3(20, "Capture : %X %d %s",
  702. pBottomConnection,
  703. pBottomConnection->pConnectNode->pPinNodeSink->pPinInfo->PinId,
  704. pBottomConnection->pConnectNode->pPinNodeSink->pPinInfo->pFilterNode->DumpName());
  705. //
  706. // Find the intersection between kmixer source and capture sink.
  707. //
  708. Status = CreatePinIntersection(
  709. ppPinConnect,
  710. pBottomConnection->pConnectNode->pPinNodeSink,
  711. pAecConnection->pConnectNode->pPinNodeSource,
  712. pBottomConnection->pFilterNodeInstanceSink,
  713. pAecConnection->pFilterNodeInstanceSource);
  714. if(!NT_SUCCESS(Status)) {
  715. DPF(5, "CSNI::AecConnectionFormat: No intersection found");
  716. Status = STATUS_INVALID_DEVICE_REQUEST;
  717. goto exit;
  718. }
  719. #ifdef DEBUG
  720. DumpDataFormat(20, (PKSDATAFORMAT) (*ppPinConnect + 1));
  721. #endif
  722. exit:
  723. if(!NT_SUCCESS(Status)) {
  724. DPF2(90, "CSNI::AecConnectionFormat: %08x FAIL %08x", this, Status);
  725. if (*ppPinConnect) {
  726. ExFreePool(*ppPinConnect);
  727. *ppPinConnect = NULL;
  728. }
  729. }
  730. CleanUp();
  731. return(Status);
  732. } // AecConnectionFormat
  733. NTSTATUS
  734. CStartNodeInstance::Connect(
  735. PDEVICE_NODE pDeviceNode,
  736. PKSPIN_CONNECT pPinConnect,
  737. PWAVEFORMATEX pWaveFormatEx,
  738. PKSPIN_CONNECT pPinConnectDirect
  739. )
  740. {
  741. PCONNECT_NODE_INSTANCE pConnectNodeInstance;
  742. NTSTATUS Status = STATUS_SUCCESS;
  743. Status = CConnectNodeInstance::Create(this, pDeviceNode);
  744. if(!NT_SUCCESS(Status)) {
  745. goto exit;
  746. }
  747. //
  748. // Do all the bottom up connecting
  749. //
  750. FOR_EACH_LIST_ITEM_BACKWARD(&lstConnectNodeInstance, pConnectNodeInstance) {
  751. if(!pConnectNodeInstance->IsTopDown()) {
  752. //
  753. // For Aec sink pin do intersection, no matter what the format is.
  754. //
  755. if (pConnectNodeInstance->pFilterNodeInstanceSink->
  756. pFilterNode->GetType() & FILTER_TYPE_AEC) {
  757. Status = pConnectNodeInstance->Connect(NULL, NULL);
  758. }
  759. else {
  760. Status = pConnectNodeInstance->Connect(
  761. pWaveFormatEx,
  762. pPinConnectDirect);
  763. }
  764. if(!NT_SUCCESS(Status)) {
  765. goto exit;
  766. }
  767. }
  768. } END_EACH_LIST_ITEM
  769. pPinConnect->PinToHandle = NULL;
  770. Status = CPinNodeInstance::Create(
  771. &pPinNodeInstance,
  772. pFilterNodeInstance,
  773. pStartNode->pPinNode,
  774. pPinConnect,
  775. (pStartNode->fRender)
  776. #ifdef FIX_SOUND_LEAK
  777. ,lstConnectNodeInstance.IsLstEmpty()
  778. #endif
  779. );
  780. if(!NT_SUCCESS(Status)) {
  781. goto exit;
  782. }
  783. //
  784. // Do all the top down connecting
  785. //
  786. FOR_EACH_LIST_ITEM(&lstConnectNodeInstance, pConnectNodeInstance) {
  787. if(pConnectNodeInstance->IsTopDown()) {
  788. //
  789. // Rely on DataIntersection for all Topdown connections
  790. //
  791. Status = pConnectNodeInstance->Connect(NULL, NULL);
  792. if(!NT_SUCCESS(Status)) {
  793. goto exit;
  794. }
  795. }
  796. } END_EACH_LIST_ITEM
  797. DPF1(90, "CSNI::Connect: %08x SUCCESS", this);
  798. exit:
  799. if(!NT_SUCCESS(Status)) {
  800. DPF2(90, "CSNI::Connect: %08x FAIL %08x", this, Status);
  801. CleanUp();
  802. }
  803. return(Status);
  804. }
  805. NTSTATUS
  806. CStartNodeInstance::CreateTopologyTable(
  807. PGRAPH_NODE_INSTANCE pGraphNodeInstance
  808. )
  809. {
  810. PCONNECT_NODE_INSTANCE pConnectNodeInstance;
  811. NTSTATUS Status = STATUS_SUCCESS;
  812. PFILTER_NODE pFilterNode = NULL;
  813. ULONG n;
  814. Assert(this);
  815. Assert(pGraphNodeInstance);
  816. if(pGraphNodeInstance->Topology.TopologyNodesCount != 0) {
  817. ASSERT(papFileObjectTopologyTable == NULL);
  818. papFileObjectTopologyTable =
  819. new PFILE_OBJECT[pGraphNodeInstance->Topology.TopologyNodesCount];
  820. if(papFileObjectTopologyTable == NULL) {
  821. Status = STATUS_INSUFFICIENT_RESOURCES;
  822. goto exit;
  823. }
  824. }
  825. for(n = 0; n < pGraphNodeInstance->Topology.TopologyNodesCount; n++) {
  826. // if filter node is the same as last time, no need to search
  827. if(pFilterNode == pGraphNodeInstance->papTopologyNode[n]->pFilterNode) {
  828. ASSERT(n != 0);
  829. ASSERT(pFilterNode != NULL);
  830. papFileObjectTopologyTable[n] = papFileObjectTopologyTable[n - 1];
  831. continue;
  832. }
  833. pFilterNode = pGraphNodeInstance->papTopologyNode[n]->pFilterNode;
  834. Assert(pFilterNode);
  835. //
  836. // Now find a filter instance and a pin instance in this graph
  837. // instance for this filter node.
  838. //
  839. Assert(pPinNodeInstance);
  840. if(pPinNodeInstance->pPinNode->pPinInfo->pFilterNode == pFilterNode) {
  841. papFileObjectTopologyTable[n] = pPinNodeInstance->pFileObject;
  842. continue;
  843. }
  844. FOR_EACH_LIST_ITEM_BACKWARD( // Top Down
  845. &lstConnectNodeInstance,
  846. pConnectNodeInstance) {
  847. Assert(pConnectNodeInstance);
  848. Assert(pConnectNodeInstance->pPinNodeInstanceSink);
  849. Assert(pConnectNodeInstance->pPinNodeInstanceSink->pPinNode);
  850. Assert(
  851. pConnectNodeInstance->pPinNodeInstanceSink->pPinNode->pPinInfo);
  852. //
  853. // Use the sink pin handle for now. This should be fine until
  854. // Sysaudio supports a spliter.
  855. //
  856. if(pConnectNodeInstance->pPinNodeInstanceSink->
  857. pPinNode->pPinInfo->pFilterNode == pFilterNode) {
  858. papFileObjectTopologyTable[n] =
  859. pConnectNodeInstance->pPinNodeInstanceSink->pFileObject;
  860. break;
  861. }
  862. } END_EACH_LIST_ITEM
  863. }
  864. DPF1(90, "CreatePinInstanceTopologyTable PI: %08x",
  865. papFileObjectTopologyTable);
  866. exit:
  867. return(Status);
  868. }
  869. NTSTATUS
  870. CStartNodeInstance::GetTopologyNodeFileObject(
  871. OUT PFILE_OBJECT *ppFileObject,
  872. IN ULONG NodeId
  873. )
  874. {
  875. PGRAPH_NODE_INSTANCE pGraphNodeInstance;
  876. NTSTATUS Status = STATUS_SUCCESS;
  877. if(this == NULL) {
  878. Status = STATUS_NO_SUCH_DEVICE;
  879. goto exit;
  880. }
  881. Assert(this);
  882. ASSERT(pPinInstance != NULL);
  883. Status = pPinInstance->pFilterInstance->GetGraphNodeInstance(
  884. &pGraphNodeInstance);
  885. if(!NT_SUCCESS(Status)) {
  886. goto exit;
  887. }
  888. Assert(pGraphNodeInstance);
  889. if(NodeId >= pGraphNodeInstance->cTopologyNodes) {
  890. Trap();
  891. Status = STATUS_INVALID_DEVICE_REQUEST;
  892. goto exit;
  893. }
  894. if(papFileObjectTopologyTable == NULL ||
  895. papFileObjectTopologyTable[NodeId] == NULL) {
  896. Status = pGraphNodeInstance->GetTopologyNodeFileObject(
  897. ppFileObject,
  898. NodeId);
  899. if(!NT_SUCCESS(Status)) {
  900. goto exit;
  901. }
  902. }
  903. else {
  904. *ppFileObject = papFileObjectTopologyTable[NodeId];
  905. }
  906. exit:
  907. return(Status);
  908. }
  909. //---------------------------------------------------------------------------
  910. NTSTATUS
  911. CStartNodeInstance::SetState(
  912. KSSTATE NewState,
  913. ULONG ulFlags
  914. )
  915. {
  916. NTSTATUS Status = STATUS_SUCCESS;
  917. LONG State;
  918. Assert(this);
  919. if(NewState < KSSTATE_STOP || NewState >= MAX_STATES) {
  920. Status = STATUS_INVALID_PARAMETER;
  921. goto exit;
  922. }
  923. if(CurrentState == NewState) {
  924. ASSERT(NT_SUCCESS(Status));
  925. goto exit;
  926. }
  927. if(CurrentState < NewState) {
  928. for(State = CurrentState + 1; State <= NewState; State++) {
  929. Status = SetStateTopDown(
  930. (KSSTATE)State,
  931. CurrentState,
  932. ulFlags | SETSTATE_FLAG_SINK | SETSTATE_FLAG_SOURCE);
  933. if(!NT_SUCCESS(Status)) {
  934. goto exit;
  935. }
  936. CurrentState = (KSSTATE)State;
  937. }
  938. }
  939. else {
  940. for(State = CurrentState - 1; State >= NewState; State--) {
  941. Status = SetStateBottomUp(
  942. (KSSTATE)State,
  943. CurrentState,
  944. ulFlags | SETSTATE_FLAG_SINK | SETSTATE_FLAG_SOURCE);
  945. if(!NT_SUCCESS(Status)) {
  946. goto exit;
  947. }
  948. CurrentState = (KSSTATE)State;
  949. }
  950. }
  951. ASSERT(CurrentState == NewState);
  952. exit:
  953. return(Status);
  954. }
  955. NTSTATUS
  956. CStartNodeInstance::SetStateTopDown(
  957. KSSTATE NewState,
  958. KSSTATE PreviousState,
  959. ULONG ulFlags
  960. )
  961. {
  962. PCONNECT_NODE_INSTANCE pConnectNodeInstance;
  963. NTSTATUS Status = STATUS_SUCCESS;
  964. if(this != NULL) {
  965. Assert(this);
  966. if(ulFlags & SETSTATE_FLAG_SINK) {
  967. Status = pPinNodeInstance->SetState(
  968. NewState,
  969. PreviousState,
  970. ulFlags);
  971. if(!NT_SUCCESS(Status)) {
  972. goto exit;
  973. }
  974. }
  975. FOR_EACH_LIST_ITEM(
  976. &lstConnectNodeInstance,
  977. pConnectNodeInstance) {
  978. Status = pConnectNodeInstance->SetStateTopDown(
  979. NewState,
  980. PreviousState,
  981. ulFlags);
  982. if(!NT_SUCCESS(Status)) {
  983. goto exit;
  984. }
  985. } END_EACH_LIST_ITEM
  986. }
  987. exit:
  988. return(Status);
  989. }
  990. NTSTATUS
  991. CStartNodeInstance::SetStateBottomUp(
  992. KSSTATE NewState,
  993. KSSTATE PreviousState,
  994. ULONG ulFlags
  995. )
  996. {
  997. PCONNECT_NODE_INSTANCE pConnectNodeInstance;
  998. NTSTATUS Status = STATUS_SUCCESS;
  999. if(this != NULL) {
  1000. Assert(this);
  1001. FOR_EACH_LIST_ITEM_BACKWARD(
  1002. &lstConnectNodeInstance,
  1003. pConnectNodeInstance) {
  1004. Status = pConnectNodeInstance->SetStateBottomUp(
  1005. NewState,
  1006. PreviousState,
  1007. ulFlags);
  1008. if(!NT_SUCCESS(Status)) {
  1009. goto exit;
  1010. }
  1011. } END_EACH_LIST_ITEM
  1012. if(ulFlags & SETSTATE_FLAG_SINK) {
  1013. Status = pPinNodeInstance->SetState(
  1014. NewState,
  1015. PreviousState,
  1016. ulFlags);
  1017. if(!NT_SUCCESS(Status)) {
  1018. goto exit;
  1019. }
  1020. }
  1021. }
  1022. exit:
  1023. return(Status);
  1024. }
  1025. //---------------------------------------------------------------------------
  1026. #ifdef DEBUG
  1027. ENUMFUNC
  1028. CStartNodeInstance::Dump(
  1029. )
  1030. {
  1031. PCONNECT_NODE_INSTANCE pConnectNodeInstance;
  1032. extern PSZ apszStates[];
  1033. if(this == NULL) {
  1034. return(STATUS_CONTINUE);
  1035. }
  1036. if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
  1037. dprintf("SNI: %08x SN %08x PI %08x FNI %08x VND %08x papFO %08x\n",
  1038. this,
  1039. pStartNode,
  1040. pPinInstance,
  1041. pFilterNodeInstance,
  1042. pVirtualNodeData,
  1043. papFileObjectTopologyTable);
  1044. dprintf(" State: %08x %s\n",
  1045. CurrentState,
  1046. apszStates[CurrentState]);
  1047. if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
  1048. if(pPinNodeInstance != NULL) {
  1049. pPinNodeInstance->Dump();
  1050. }
  1051. }
  1052. if(pPinConnect != NULL) {
  1053. DumpPinConnect(MAXULONG, pPinConnect);
  1054. }
  1055. }
  1056. else {
  1057. dprintf(" To: ");
  1058. if(pPinNodeInstance != NULL) {
  1059. pPinNodeInstance->Dump();
  1060. }
  1061. else {
  1062. dprintf("NULL\n");
  1063. }
  1064. }
  1065. if(ulDebugFlags & DEBUG_FLAGS_TOPOLOGY) {
  1066. PGRAPH_NODE_INSTANCE pGraphNodeInstance;
  1067. pGraphNodeInstance = pPinInstance->pFilterInstance->pGraphNodeInstance;
  1068. if(pGraphNodeInstance != NULL) {
  1069. Assert(pGraphNodeInstance);
  1070. for(ULONG i = 0;
  1071. i < pGraphNodeInstance->Topology.TopologyNodesCount;
  1072. i++) {
  1073. if(papFileObjectTopologyTable[i] != NULL) {
  1074. dprintf(" %02x FO %08x %s\n",
  1075. i,
  1076. papFileObjectTopologyTable[i],
  1077. pGraphNodeInstance->papTopologyNode[i]->pFilterNode->
  1078. DumpName());
  1079. }
  1080. }
  1081. }
  1082. }
  1083. if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
  1084. FOR_EACH_LIST_ITEM(&lstConnectNodeInstance, pConnectNodeInstance) {
  1085. pConnectNodeInstance->Dump();
  1086. } END_EACH_LIST_ITEM
  1087. }
  1088. dprintf("\n");
  1089. return(STATUS_CONTINUE);
  1090. }
  1091. #endif
  1092. //---------------------------------------------------------------------------