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.

375 lines
10 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: pni.cpp
  4. //
  5. // Description:
  6. //
  7. // Pin 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. #ifdef DEBUG
  31. PLIST_PIN_NODE_INSTANCE gplstPinNodeInstance = NULL;
  32. #endif
  33. //---------------------------------------------------------------------------
  34. CPinNodeInstance::~CPinNodeInstance(
  35. )
  36. {
  37. DPF1(90, "~CPinNodeInstance: %08x", this);
  38. Assert(this);
  39. if(pFileObject != NULL) {
  40. AssertFileObject(pFileObject);
  41. ObDereferenceObject(pFileObject);
  42. }
  43. if(hPin != NULL) {
  44. AssertStatus(ZwClose(hPin));
  45. }
  46. pFilterNodeInstance->Destroy();
  47. }
  48. NTSTATUS
  49. CPinNodeInstance::Create(
  50. PPIN_NODE_INSTANCE *ppPinNodeInstance,
  51. PFILTER_NODE_INSTANCE pFilterNodeInstance,
  52. PPIN_NODE pPinNode,
  53. PKSPIN_CONNECT pPinConnect,
  54. BOOL fRender
  55. #ifdef FIX_SOUND_LEAK
  56. ,BOOL fDirectConnection
  57. #endif
  58. )
  59. {
  60. PPIN_NODE_INSTANCE pPinNodeInstance = NULL;
  61. NTSTATUS Status = STATUS_SUCCESS;
  62. Assert(pPinNode);
  63. Assert(pPinNode->pPinInfo);
  64. Assert(pFilterNodeInstance);
  65. pPinConnect->PinId = pPinNode->pPinInfo->PinId;
  66. pPinNodeInstance = new PIN_NODE_INSTANCE();
  67. if(pPinNodeInstance == NULL) {
  68. Status = STATUS_INSUFFICIENT_RESOURCES;
  69. goto exit;
  70. }
  71. pPinNodeInstance->pPinNode = pPinNode;
  72. pPinNodeInstance->pFilterNodeInstance = pFilterNodeInstance;
  73. ASSERT(pPinNodeInstance->CurrentState == KSSTATE_STOP);
  74. pFilterNodeInstance->AddRef();
  75. pPinNodeInstance->fRender = fRender;
  76. #ifdef FIX_SOUND_LEAK
  77. pPinNodeInstance->fDirectConnection = fDirectConnection;
  78. pPinNodeInstance->ForceRun = FALSE;
  79. #endif
  80. #ifdef DEBUG
  81. DPF3(90, "CPNI::Create PN %08x #%d %s",
  82. pPinNode,
  83. pPinNode->pPinInfo->PinId,
  84. pPinNode->pPinInfo->pFilterNode->DumpName());
  85. DumpPinConnect(90, pPinConnect);
  86. #endif
  87. if (pFilterNodeInstance->hFilter == NULL) {
  88. //
  89. // If it is a GFX we have to attach to the AddGfx() context to create the pin
  90. //
  91. Status = pFilterNodeInstance->pFilterNode->CreatePin(pPinConnect,
  92. GENERIC_WRITE | OBJ_KERNEL_HANDLE,
  93. &pPinNodeInstance->hPin);
  94. }
  95. else {
  96. Status = KsCreatePin(
  97. pFilterNodeInstance->hFilter,
  98. pPinConnect,
  99. GENERIC_WRITE | OBJ_KERNEL_HANDLE,
  100. &pPinNodeInstance->hPin);
  101. }
  102. if(!NT_SUCCESS(Status)) {
  103. #ifdef DEBUG
  104. DPF4(90, "CPNI::Create PN %08x #%d %s KsCreatePin FAILED: %08x",
  105. pPinNode,
  106. pPinNode->pPinInfo->PinId,
  107. pPinNode->pPinInfo->pFilterNode->DumpName(),
  108. Status);
  109. #endif
  110. pPinNodeInstance->hPin = NULL;
  111. goto exit;
  112. }
  113. Status = ObReferenceObjectByHandle(
  114. pPinNodeInstance->hPin,
  115. GENERIC_READ | GENERIC_WRITE,
  116. NULL,
  117. KernelMode,
  118. (PVOID*)&pPinNodeInstance->pFileObject,
  119. NULL);
  120. if(!NT_SUCCESS(Status)) {
  121. pPinNodeInstance->pFileObject = NULL;
  122. goto exit;
  123. }
  124. AssertFileObject(pPinNodeInstance->pFileObject);
  125. #ifdef DEBUG
  126. Status = gplstPinNodeInstance->AddList(pPinNodeInstance);
  127. if(!NT_SUCCESS(Status)) {
  128. goto exit;
  129. }
  130. #endif
  131. DPF2(90, "CPNI::Create SUCCESS %08x PN %08x", pPinNodeInstance, pPinNode);
  132. exit:
  133. if(!NT_SUCCESS(Status)) {
  134. if (pPinNodeInstance) {
  135. pPinNodeInstance->Destroy();
  136. }
  137. pPinNodeInstance = NULL;
  138. }
  139. *ppPinNodeInstance = pPinNodeInstance;
  140. return(Status);
  141. }
  142. #ifdef DEBUG
  143. PSZ apszStates[] = { "STOP", "ACQUIRE", "PAUSE", "RUN" };
  144. #endif
  145. NTSTATUS
  146. CPinNodeInstance::SetState(
  147. KSSTATE NewState,
  148. KSSTATE PreviousState,
  149. ULONG ulFlags
  150. )
  151. {
  152. NTSTATUS Status = STATUS_SUCCESS;
  153. LONG State;
  154. if(this == NULL) {
  155. goto exit;
  156. }
  157. Assert(this);
  158. DPF9(DBG_STATE, "SetState %s to %s cR %d cP %d cA %d cS %d P# %d %s %s",
  159. apszStates[PreviousState],
  160. apszStates[NewState],
  161. cState[KSSTATE_RUN],
  162. cState[KSSTATE_PAUSE],
  163. cState[KSSTATE_ACQUIRE],
  164. cState[KSSTATE_STOP],
  165. pPinNode->pPinInfo->PinId,
  166. apszStates[CurrentState],
  167. pPinNode->pPinInfo->pFilterNode->DumpName());
  168. cState[PreviousState]--;
  169. cState[NewState]++;
  170. for(State = KSSTATE_RUN; State > KSSTATE_STOP; State--) {
  171. if(cState[State] > 0) {
  172. break;
  173. }
  174. }
  175. // ISSUE-2001/04/09-alpers
  176. // The proper fix would be to propagate the reset to the entire audio stack.
  177. // But it is considered as being to risky for now (after Beta2 of Windows XP).
  178. // This should be one of the first things we should address in Blackcomb.
  179. //
  180. #ifdef FIX_SOUND_LEAK
  181. // FIX_SOUND_LEAK is to prevent the audio stack from play/recording the last
  182. // portion of data when a new stream is started.
  183. // This temporary fix keeps the pins below splitter/kmixer sink pin in
  184. // RUNNING state.
  185. //
  186. if (fRender)
  187. {
  188. // For render pins
  189. // The criteria for keeping the pin in RUN state:
  190. // If the pin is going to PAUSE from RUN.
  191. // If the filter is below kmixer.
  192. // If the pin is not kmixer sink pin.
  193. //
  194. if ( (!fDirectConnection) &&
  195. (State == KSSTATE_PAUSE) &&
  196. (PreviousState == KSSTATE_RUN) &&
  197. (pFilterNodeInstance->pFilterNode->GetOrder() <= ORDER_MIXER) &&
  198. !(pFilterNodeInstance->pFilterNode->GetOrder() == ORDER_MIXER &&
  199. pPinNode->pPinInfo->Communication == KSPIN_COMMUNICATION_SINK) )
  200. {
  201. ForceRun = TRUE;
  202. }
  203. }
  204. else
  205. {
  206. // For capture pins
  207. // The criteria for keeping the pin in RUN state:
  208. // If the pin is going to PAUSE from RUN.
  209. // There are more than one pins in PAUSE.
  210. //
  211. if ( (State == KSSTATE_PAUSE) &&
  212. (PreviousState == KSSTATE_RUN) &&
  213. (cState[KSSTATE_PAUSE] > 1) )
  214. {
  215. DPF(DBG_STATE, "SetState: CAPTURE forcing KSSTATE_RUN");
  216. State = KSSTATE_RUN;
  217. }
  218. }
  219. if (ForceRun)
  220. {
  221. DPF(DBG_STATE, "SetState: RENDER IN FORCE KSSTATE_RUN state");
  222. State = KSSTATE_RUN;
  223. }
  224. #else
  225. for(State = KSSTATE_RUN; cState[State] <= 0; State--) {
  226. if(State == KSSTATE_STOP) {
  227. break;
  228. }
  229. }
  230. #endif
  231. #ifdef FIX_SOUND_LEAK
  232. // If the pin is forced to be in RUN state, we should go back to
  233. // regular state scheme, if and only if there are no pins in RUN state.
  234. // To prevent RUN-ACQUIRE first go to PAUSE.
  235. //
  236. if (ForceRun &&
  237. (0 == cState[KSSTATE_PAUSE]) &&
  238. (0 == cState[KSSTATE_RUN]))
  239. {
  240. KSSTATE TempState = KSSTATE_PAUSE;
  241. DPF(DBG_STATE, "SetState: Exiting FORCE KSSTATE_RUN state");
  242. DPF1(DBG_STATE, "SetState: PinConnectionProperty(%s)", apszStates[TempState]);
  243. Status = PinConnectionProperty(
  244. pFileObject,
  245. KSPROPERTY_CONNECTION_STATE,
  246. KSPROPERTY_TYPE_SET,
  247. sizeof(TempState),
  248. &TempState);
  249. if (!NT_SUCCESS(Status))
  250. {
  251. if(ulFlags & SETSTATE_FLAG_IGNORE_ERROR) {
  252. Status = STATUS_SUCCESS;
  253. }
  254. else {
  255. //
  256. // Go back to previous state if failure
  257. //
  258. cState[PreviousState]++;
  259. cState[NewState]--;
  260. goto exit;
  261. }
  262. }
  263. // Exiting the FORCE_RUN state.
  264. //
  265. CurrentState = KSSTATE_PAUSE;
  266. State = KSSTATE_ACQUIRE;
  267. ForceRun = FALSE;
  268. }
  269. #endif
  270. if(CurrentState != State) {
  271. DPF1(DBG_STATE, "SetState: PinConnectionProperty(%s)", apszStates[State]);
  272. ASSERT(State == CurrentState + 1 || State == CurrentState - 1);
  273. Status = PinConnectionProperty(
  274. pFileObject,
  275. KSPROPERTY_CONNECTION_STATE,
  276. KSPROPERTY_TYPE_SET,
  277. sizeof(State),
  278. &State);
  279. if(!NT_SUCCESS(Status)) {
  280. DPF1(5, "SetState: PinConnectionProperty FAILED %08x", Status);
  281. if(ulFlags & SETSTATE_FLAG_IGNORE_ERROR) {
  282. Status = STATUS_SUCCESS;
  283. }
  284. else {
  285. //
  286. // Go back to previous state if failure
  287. //
  288. cState[PreviousState]++;
  289. cState[NewState]--;
  290. goto exit;
  291. }
  292. }
  293. CurrentState = (KSSTATE)State;
  294. }
  295. exit:
  296. return(Status);
  297. }
  298. //---------------------------------------------------------------------------
  299. #ifdef DEBUG
  300. ENUMFUNC
  301. CPinNodeInstance::Dump(
  302. )
  303. {
  304. if(this == NULL) {
  305. return(STATUS_CONTINUE);
  306. }
  307. if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
  308. dprintf("PNI: %08x PN %08x P# %d FNI %08x FO %08x H %08x\n",
  309. this,
  310. pPinNode,
  311. pPinNode->pPinInfo->PinId,
  312. pFilterNodeInstance,
  313. pFileObject,
  314. hPin);
  315. dprintf(" State: %08x %s cState: cR %d cP %d cA %d cS %d\n",
  316. CurrentState,
  317. apszStates[CurrentState],
  318. cState[KSSTATE_RUN],
  319. cState[KSSTATE_PAUSE],
  320. cState[KSSTATE_ACQUIRE],
  321. cState[KSSTATE_STOP]);
  322. }
  323. else {
  324. dprintf("%s\n", pPinNode->pPinInfo->pFilterNode->DumpName());
  325. dprintf(" PinId: %d State: %s cState: cR %d cP %d cA %d cS %d\n",
  326. pPinNode->pPinInfo->PinId,
  327. apszStates[CurrentState],
  328. cState[KSSTATE_RUN],
  329. cState[KSSTATE_PAUSE],
  330. cState[KSSTATE_ACQUIRE],
  331. cState[KSSTATE_STOP]);
  332. }
  333. if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
  334. pFilterNodeInstance->Dump();
  335. }
  336. return(STATUS_CONTINUE);
  337. }
  338. #endif
  339. //---------------------------------------------------------------------------