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.

364 lines
12 KiB

  1. /* audiosrv.cpp
  2. * Copyright (c) 2000-2001 Microsoft Corporation
  3. */
  4. #include <nt.h>
  5. #include <ntrtl.h>
  6. #include <nturtl.h>
  7. #undef ASSERT
  8. #include <stdio.h>
  9. #include <windows.h>
  10. #include <setupapi.h>
  11. #include <dbt.h>
  12. #include <ks.h>
  13. #include <ksmedia.h>
  14. #include <svcs.h>
  15. #include "debug.h"
  16. #include "list.h"
  17. #include "audiosrv.h"
  18. #include "service.h"
  19. #include "agfxs.h"
  20. #include "mme.h"
  21. #include "ts.h"
  22. //
  23. // Note in general don't rely on compiler init of global
  24. // variables since service might be stopped and restarted
  25. // without this DLL being freed and then reloaded.
  26. //
  27. PSVCHOST_GLOBAL_DATA gpSvchostSharedGlobals = NULL;
  28. BOOL fRpcStarted;
  29. HANDLE hHeap;
  30. HDEVNOTIFY hdevNotifyAudio;
  31. HDEVNOTIFY hdevNotifyRender;
  32. HDEVNOTIFY hdevNotifyCapture;
  33. HDEVNOTIFY hdevNotifyDataTransform;
  34. HDEVNOTIFY hdevNotifySysaudio;
  35. //
  36. // Upon loading this DLL, svchost will find this exported function
  37. // and pass a pointer to useful shared globals.
  38. void SvchostPushServiceGlobals(IN PSVCHOST_GLOBAL_DATA pSvchostSharedGlobals)
  39. {
  40. gpSvchostSharedGlobals = pSvchostSharedGlobals;
  41. }
  42. //--------------------------------------------------------------------------;
  43. //
  44. // AudioSrvRpcIfCallback
  45. //
  46. // Description:
  47. // RPC security callback function. See MSDN for RpcServerRegisterIfEx
  48. // IfCallback parameter. This security callback function will fail any
  49. // non local RPC calls. It checks this by using the internal RPC
  50. // function I_RpcBindingInqTransportType.
  51. //
  52. // Arguments:
  53. // See MSDN for RPC_IF_CALLBACK_FN.
  54. //
  55. // Return value:
  56. // See MSDN for RPC_IF_CALLBACK_FN.
  57. //
  58. // History:
  59. // 05/02/2002 FrankYe Created
  60. //
  61. //--------------------------------------------------------------------------;
  62. RPC_STATUS RPC_ENTRY AudioSrvRpcIfCallback(IN RPC_IF_HANDLE Interface, IN void *Context)
  63. {
  64. unsigned int type;
  65. RPC_STATUS status;
  66. status = I_RpcBindingInqTransportType(Context, &type);
  67. if (RPC_S_OK != status) return ERROR_ACCESS_DENIED;
  68. if (TRANSPORT_TYPE_LPC != type) return ERROR_ACCESS_DENIED;
  69. return RPC_S_OK;
  70. }
  71. // Stub initialization function.
  72. DWORD MyServiceInitialization(SERVICE_STATUS_HANDLE ssh, DWORD argc, LPTSTR *argv, DWORD *specificError)
  73. {
  74. DEV_BROADCAST_DEVICEINTERFACE dbdi;
  75. LONG status;
  76. // dprintf(TEXT("MyServiceInitialization\n"));
  77. status = ERROR_SUCCESS;;
  78. fRpcStarted = FALSE;
  79. hdevNotifyAudio = NULL;
  80. hdevNotifyRender = NULL;
  81. hdevNotifyCapture = NULL;
  82. hdevNotifyDataTransform = NULL;
  83. hdevNotifySysaudio = NULL;
  84. gplistSessionNotifications = new CListSessionNotifications;
  85. if (!gplistSessionNotifications) status = ERROR_OUTOFMEMORY;
  86. if (!status) status = gplistSessionNotifications->Initialize();
  87. if (!status) {
  88. ZeroMemory(&dbdi, sizeof(dbdi));
  89. dbdi.dbcc_size = sizeof(dbdi);
  90. dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  91. dbdi.dbcc_classguid = KSCATEGORY_AUDIO;
  92. hdevNotifyAudio = RegisterDeviceNotification(ssh, &dbdi, DEVICE_NOTIFY_SERVICE_HANDLE);
  93. if (!hdevNotifyAudio) status = GetLastError();
  94. }
  95. if (!status) {
  96. ZeroMemory(&dbdi, sizeof(dbdi));
  97. dbdi.dbcc_size = sizeof(dbdi);
  98. dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  99. dbdi.dbcc_classguid = KSCATEGORY_RENDER;
  100. hdevNotifyRender = RegisterDeviceNotification(ssh, &dbdi, DEVICE_NOTIFY_SERVICE_HANDLE);
  101. if (!hdevNotifyRender) status = GetLastError();
  102. }
  103. if (!status) {
  104. ZeroMemory(&dbdi, sizeof(dbdi));
  105. dbdi.dbcc_size = sizeof(dbdi);
  106. dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  107. dbdi.dbcc_classguid = KSCATEGORY_CAPTURE;
  108. hdevNotifyCapture = RegisterDeviceNotification(ssh, &dbdi, DEVICE_NOTIFY_SERVICE_HANDLE);
  109. if (!hdevNotifyCapture) status = GetLastError();
  110. }
  111. if (!status) {
  112. ZeroMemory(&dbdi, sizeof(dbdi));
  113. dbdi.dbcc_size = sizeof(dbdi);
  114. dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  115. dbdi.dbcc_classguid = KSCATEGORY_DATATRANSFORM;
  116. hdevNotifyDataTransform = RegisterDeviceNotification(ssh, &dbdi, DEVICE_NOTIFY_SERVICE_HANDLE);
  117. if (!hdevNotifyDataTransform) status = GetLastError();
  118. }
  119. if (!status) {
  120. ZeroMemory(&dbdi, sizeof(dbdi));
  121. dbdi.dbcc_size = sizeof(dbdi);
  122. dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  123. dbdi.dbcc_classguid = KSCATEGORY_SYSAUDIO;
  124. hdevNotifySysaudio = RegisterDeviceNotification(ssh, &dbdi, DEVICE_NOTIFY_SERVICE_HANDLE);
  125. if (!hdevNotifySysaudio) status = GetLastError();
  126. }
  127. if (!status) {
  128. NTSTATUS ntstatus;
  129. ntstatus = RpcServerUseAllProtseqsIf(RPC_C_PROTSEQ_MAX_REQS_DEFAULT, AudioSrv_v1_0_s_ifspec, NULL);
  130. if (!ntstatus) ntstatus = RpcServerRegisterIfEx(AudioSrv_v1_0_s_ifspec, NULL, NULL, RPC_IF_AUTOLISTEN, RPC_C_LISTEN_MAX_CALLS_DEFAULT, AudioSrvRpcIfCallback);
  131. if (!ntstatus) {
  132. fRpcStarted = TRUE;
  133. } else {
  134. // ISSUE-2000/10/10-FrankYe Try to convert to proper win32 error.
  135. status = RPC_S_SERVER_UNAVAILABLE;
  136. }
  137. }
  138. if (!status) {
  139. status = MME_ServiceStart();
  140. }
  141. if (status) {
  142. // Rely on MyServiceTerminate to clean up anything
  143. // that is partially initialized.
  144. }
  145. return status;
  146. } // end MyServiceInitialization
  147. void MyServiceTerminate(void)
  148. {
  149. //
  150. // Stop the Rpc server
  151. //
  152. if (fRpcStarted) {
  153. NTSTATUS status;
  154. status = RpcServerUnregisterIf(AudioSrv_v1_0_s_ifspec, NULL, 1);
  155. if (status) dprintf(TEXT("ServiceStop: StopRpcServerEx returned NTSTATUS=%08Xh\n"), status);
  156. fRpcStarted = FALSE;
  157. }
  158. //
  159. // Unregister PnP notifications
  160. //
  161. if (hdevNotifySysaudio) UnregisterDeviceNotification(hdevNotifySysaudio);
  162. if (hdevNotifyDataTransform) UnregisterDeviceNotification(hdevNotifyDataTransform);
  163. if (hdevNotifyCapture) UnregisterDeviceNotification(hdevNotifyCapture);
  164. if (hdevNotifyRender) UnregisterDeviceNotification(hdevNotifyRender);
  165. if (hdevNotifyAudio) UnregisterDeviceNotification(hdevNotifyAudio);
  166. hdevNotifySysaudio = NULL;
  167. hdevNotifyDataTransform = NULL;
  168. hdevNotifyCapture = NULL;
  169. hdevNotifyRender = NULL;
  170. hdevNotifyAudio = NULL;
  171. //
  172. // Clean up any remaining session notifications and delete list
  173. //
  174. if (gplistSessionNotifications) {
  175. POSITION pos = gplistSessionNotifications->GetHeadPosition();
  176. while (pos)
  177. {
  178. PSESSIONNOTIFICATION pNotification;
  179. pNotification = gplistSessionNotifications->GetNext(pos);
  180. CloseHandle(pNotification->Event);
  181. delete pNotification;
  182. }
  183. delete gplistSessionNotifications;
  184. }
  185. gplistSessionNotifications = NULL;
  186. //
  187. // Clean up GFX support
  188. //
  189. GFX_ServiceStop();
  190. return;
  191. }
  192. DWORD ServiceDeviceEvent(DWORD EventType, LPVOID EventData)
  193. {
  194. PDEV_BROADCAST_DEVICEINTERFACE dbdi = (PDEV_BROADCAST_DEVICEINTERFACE)EventData;
  195. switch (EventType)
  196. {
  197. case DBT_DEVICEARRIVAL:
  198. if (dbdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) break;
  199. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) MME_AudioInterfaceArrival(dbdi->dbcc_name);
  200. if (dbdi->dbcc_classguid == KSCATEGORY_SYSAUDIO) GFX_SysaudioInterfaceArrival(dbdi->dbcc_name);
  201. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) GFX_AudioInterfaceArrival(dbdi->dbcc_name);
  202. if (dbdi->dbcc_classguid == KSCATEGORY_RENDER) GFX_RenderInterfaceArrival(dbdi->dbcc_name);
  203. if (dbdi->dbcc_classguid == KSCATEGORY_CAPTURE) GFX_CaptureInterfaceArrival(dbdi->dbcc_name);
  204. if (dbdi->dbcc_classguid == KSCATEGORY_DATATRANSFORM) GFX_DataTransformInterfaceArrival(dbdi->dbcc_name);
  205. return NO_ERROR;
  206. case DBT_DEVICEQUERYREMOVEFAILED:
  207. if (dbdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) break;
  208. if (dbdi->dbcc_classguid == KSCATEGORY_SYSAUDIO) GFX_SysaudioInterfaceArrival(dbdi->dbcc_name);
  209. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) GFX_AudioInterfaceArrival(dbdi->dbcc_name);
  210. if (dbdi->dbcc_classguid == KSCATEGORY_RENDER) GFX_RenderInterfaceArrival(dbdi->dbcc_name);
  211. if (dbdi->dbcc_classguid == KSCATEGORY_CAPTURE) GFX_CaptureInterfaceArrival(dbdi->dbcc_name);
  212. if (dbdi->dbcc_classguid == KSCATEGORY_DATATRANSFORM) GFX_DataTransformInterfaceArrival(dbdi->dbcc_name);
  213. return NO_ERROR;
  214. case DBT_DEVICEQUERYREMOVE:
  215. if (dbdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) break;
  216. if (dbdi->dbcc_classguid == KSCATEGORY_SYSAUDIO) GFX_SysaudioInterfaceRemove(dbdi->dbcc_name);
  217. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) GFX_AudioInterfaceRemove(dbdi->dbcc_name);
  218. if (dbdi->dbcc_classguid == KSCATEGORY_RENDER) GFX_RenderInterfaceRemove(dbdi->dbcc_name);
  219. if (dbdi->dbcc_classguid == KSCATEGORY_CAPTURE) GFX_CaptureInterfaceRemove(dbdi->dbcc_name);
  220. if (dbdi->dbcc_classguid == KSCATEGORY_DATATRANSFORM) GFX_DataTransformInterfaceRemove(dbdi->dbcc_name);
  221. return NO_ERROR;
  222. case DBT_DEVICEREMOVEPENDING:
  223. if (dbdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) break;
  224. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) MME_AudioInterfaceRemove(dbdi->dbcc_name);
  225. if (dbdi->dbcc_classguid == KSCATEGORY_SYSAUDIO) GFX_SysaudioInterfaceRemove(dbdi->dbcc_name);
  226. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) GFX_AudioInterfaceRemove(dbdi->dbcc_name);
  227. if (dbdi->dbcc_classguid == KSCATEGORY_RENDER) GFX_RenderInterfaceRemove(dbdi->dbcc_name);
  228. if (dbdi->dbcc_classguid == KSCATEGORY_CAPTURE) GFX_CaptureInterfaceRemove(dbdi->dbcc_name);
  229. if (dbdi->dbcc_classguid == KSCATEGORY_DATATRANSFORM) GFX_DataTransformInterfaceRemove(dbdi->dbcc_name);
  230. return NO_ERROR;
  231. case DBT_DEVICEREMOVECOMPLETE:
  232. if (dbdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) break;
  233. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) MME_AudioInterfaceRemove(dbdi->dbcc_name);
  234. if (dbdi->dbcc_classguid == KSCATEGORY_SYSAUDIO) GFX_SysaudioInterfaceRemove(dbdi->dbcc_name);
  235. if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO) GFX_AudioInterfaceRemove(dbdi->dbcc_name);
  236. if (dbdi->dbcc_classguid == KSCATEGORY_RENDER) GFX_RenderInterfaceRemove(dbdi->dbcc_name);
  237. if (dbdi->dbcc_classguid == KSCATEGORY_CAPTURE) GFX_CaptureInterfaceRemove(dbdi->dbcc_name);
  238. if (dbdi->dbcc_classguid == KSCATEGORY_DATATRANSFORM) GFX_DataTransformInterfaceRemove(dbdi->dbcc_name);
  239. return NO_ERROR;
  240. default:
  241. return ERROR_CALL_NOT_IMPLEMENTED;
  242. }
  243. return ERROR_CALL_NOT_IMPLEMENTED;
  244. }
  245. void ServiceStop(void)
  246. {
  247. dprintf(TEXT("ServiceStop\n"));
  248. ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
  249. MyServiceTerminate();
  250. ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);
  251. return;
  252. }
  253. VOID ServiceStart(SERVICE_STATUS_HANDLE ssh, DWORD dwArgc, LPTSTR *lpszArgv)
  254. {
  255. DWORD status;
  256. DWORD specificError;
  257. // dprintf(TEXT("ServiceStart\n"));
  258. status = MyServiceInitialization(ssh, dwArgc, lpszArgv, &specificError);
  259. if (!status) {
  260. // dprintf(TEXT("MyServiceInitialization succeeded\n"));
  261. ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
  262. } else {
  263. dprintf(TEXT("MyServiceInitialization returned status=%d\n"), status);
  264. ReportStatusToSCMgr(SERVICE_STOPPED, status, 0);
  265. }
  266. return;
  267. }
  268. void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t cb)
  269. {
  270. return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
  271. }
  272. void __RPC_USER MIDL_user_free( void __RPC_FAR * pv)
  273. {
  274. HeapFree(hHeap, 0, pv);
  275. }
  276. BOOL DllMain(PVOID hModule, ULONG Reason, PCONTEXT pContext)
  277. {
  278. BOOL result = TRUE;
  279. static BOOL fGfxResult = FALSE;
  280. static BOOL fMmeResult = FALSE;
  281. if (DLL_PROCESS_ATTACH == Reason)
  282. {
  283. hHeap = GetProcessHeap();
  284. result = fGfxResult = GFX_DllProcessAttach();
  285. if (result) result = fMmeResult = MME_DllProcessAttach();
  286. if (!result)
  287. {
  288. if (fMmeResult) MME_DllProcessDetach();
  289. if (fGfxResult) GFX_DllProcessDetach();
  290. fMmeResult = FALSE;
  291. fGfxResult = FALSE;
  292. }
  293. }
  294. else if (DLL_PROCESS_DETACH == Reason)
  295. {
  296. if (fMmeResult) MME_DllProcessDetach();
  297. if (fGfxResult) GFX_DllProcessDetach();
  298. fMmeResult = FALSE;
  299. fGfxResult = FALSE;
  300. }
  301. return result;
  302. }