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.

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