PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/source/sdl/i_midirpc.cpp

https://bitbucket.org/ichera/autodoom
C++ | 383 lines | 214 code | 61 blank | 108 comment | 11 complexity | 3b6b9b958d2b83156fcf6434226dea86 MD5 | raw file
Possible License(s): GPL-3.0, AGPL-3.0, LGPL-3.0, LGPL-2.1
  1. // Emacs style mode select -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // Copyright (C) 2013 James Haley et al.
  5. //
  6. // This program is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with this program. If not, see http://www.gnu.org/licenses/
  18. //
  19. //----------------------------------------------------------------------------
  20. //
  21. // DESCRIPTION:
  22. //
  23. // Client Interface to RPC Midi Server
  24. //
  25. //-----------------------------------------------------------------------------
  26. #ifdef EE_FEATURE_MIDIRPC
  27. #include <windows.h>
  28. #include "../../midiproc/midiproc.h"
  29. #include "../m_qstr.h"
  30. #if defined(_DEBUG) && defined(EE_RPC_DEBUG)
  31. #define DEBUGOUT(s) puts(s)
  32. #else
  33. #define DEBUGOUT(s)
  34. #endif
  35. //=============================================================================
  36. //
  37. // Data
  38. //
  39. static unsigned char *szStringBinding; // RPC client binding string
  40. static bool serverInit = false; // if true, server was started
  41. static bool clientInit = false; // if true, client was bound
  42. // server process information
  43. static STARTUPINFO si;
  44. static PROCESS_INFORMATION pi;
  45. //=============================================================================
  46. //
  47. // RPC Memory Management
  48. //
  49. void __RPC_FAR * __RPC_USER midl_user_allocate(size_t size)
  50. {
  51. return malloc(size);
  52. }
  53. void __RPC_USER midl_user_free(void __RPC_FAR *p)
  54. {
  55. free(p);
  56. }
  57. //=============================================================================
  58. //
  59. // RPC Wrappers
  60. //
  61. //
  62. // CHECK_RPC_STATUS
  63. //
  64. // If either server or client initialization failed, we don't try to make any
  65. // RPC calls.
  66. //
  67. #define CHECK_RPC_STATUS() \
  68. if(!serverInit || !clientInit) \
  69. return false
  70. //
  71. // I_MidiRPCRegisterSong
  72. //
  73. // Prepare the RPC MIDI engine to receive new song data, and transmit the song
  74. // data to the server process.
  75. //
  76. bool I_MidiRPCRegisterSong(void *data, int size)
  77. {
  78. unsigned int rpcSize = static_cast<unsigned int>(size);
  79. CHECK_RPC_STATUS();
  80. RpcTryExcept
  81. {
  82. MidiRPC_PrepareNewSong();
  83. // TODO: Try passing it as one chunk; if this ends up not working,
  84. // I'll have to stream it in as smaller divisions.
  85. MidiRPC_AddChunk(rpcSize, static_cast<byte *>(data));
  86. }
  87. RpcExcept(1)
  88. {
  89. DEBUGOUT("I_MidiRPCRegisterSong failed");
  90. return false;
  91. }
  92. RpcEndExcept
  93. DEBUGOUT("I_MidiRPCRegisterSong succeeded");
  94. return true;
  95. }
  96. //
  97. // I_MidiRPCPlaySong
  98. //
  99. // Tell the RPC server to start playing a song.
  100. //
  101. bool I_MidiRPCPlaySong(bool looping)
  102. {
  103. CHECK_RPC_STATUS();
  104. RpcTryExcept
  105. {
  106. MidiRPC_PlaySong(looping ? TRUE : FALSE);
  107. }
  108. RpcExcept(1)
  109. {
  110. DEBUGOUT("I_MidiRPCPlaySong failed");
  111. return false;
  112. }
  113. RpcEndExcept
  114. DEBUGOUT("I_MidiRPCPlaySong succeeded");
  115. return true;
  116. }
  117. //
  118. // I_MidiRPCStopSong
  119. //
  120. // Tell the RPC server to stop any currently playing song.
  121. //
  122. bool I_MidiRPCStopSong()
  123. {
  124. CHECK_RPC_STATUS();
  125. RpcTryExcept
  126. {
  127. MidiRPC_StopSong();
  128. }
  129. RpcExcept(1)
  130. {
  131. DEBUGOUT("I_MidiRPCStopSong failed");
  132. return false;
  133. }
  134. RpcEndExcept
  135. DEBUGOUT("I_MidiRPCStopSong succeeded");
  136. return true;
  137. }
  138. //
  139. // I_MidiRPCSetVolume
  140. //
  141. // Change the volume level of music played by the RPC midi server.
  142. //
  143. bool I_MidiRPCSetVolume(int volume)
  144. {
  145. CHECK_RPC_STATUS();
  146. RpcTryExcept
  147. {
  148. MidiRPC_ChangeVolume(volume);
  149. }
  150. RpcExcept(1)
  151. {
  152. DEBUGOUT("I_MidiRPCSetVolume failed");
  153. return false;
  154. }
  155. RpcEndExcept
  156. DEBUGOUT("I_MidiRPCSetVolume succeeded");
  157. return true;
  158. }
  159. //
  160. // I_MidiRPCPauseSong
  161. //
  162. // Pause the music being played by the server. In actuality, due to SDL_mixer
  163. // limitations, this just temporarily sets the volume to zero.
  164. //
  165. bool I_MidiRPCPauseSong()
  166. {
  167. CHECK_RPC_STATUS();
  168. RpcTryExcept
  169. {
  170. MidiRPC_PauseSong();
  171. }
  172. RpcExcept(1)
  173. {
  174. DEBUGOUT("I_MidiRPCPauseSong failed");
  175. return false;
  176. }
  177. RpcEndExcept
  178. DEBUGOUT("I_MidiRPCPauseSong succeeded");
  179. return true;
  180. }
  181. //
  182. // I_MidiRPCResumeSong
  183. //
  184. // Resume a song after having paused it.
  185. //
  186. bool I_MidiRPCResumeSong()
  187. {
  188. CHECK_RPC_STATUS();
  189. RpcTryExcept
  190. {
  191. MidiRPC_ResumeSong();
  192. }
  193. RpcExcept(1)
  194. {
  195. DEBUGOUT("I_MidiRPCResumeSong failed");
  196. return false;
  197. }
  198. RpcEndExcept
  199. DEBUGOUT("I_MidiRPCResumeSong succeeded");
  200. return true;
  201. }
  202. //=============================================================================
  203. //
  204. // Public Interface
  205. //
  206. //
  207. // I_MidiRPCInitServer
  208. //
  209. // Start up the RPC MIDI server.
  210. //
  211. bool I_MidiRPCInitServer()
  212. {
  213. struct stat sbuf;
  214. char filename[MAX_PATH+1];
  215. memset(filename, 0, sizeof(filename));
  216. GetModuleFileName(NULL, filename, MAX_PATH);
  217. qstring module;
  218. module = filename;
  219. module.removeFileSpec();
  220. module.pathConcatenate("midiproc.exe");
  221. DEBUGOUT(module.constPtr());
  222. // Look for executable file
  223. if(stat(module.constPtr(), &sbuf))
  224. {
  225. DEBUGOUT("Could not find midiproc");
  226. return false;
  227. }
  228. si.cb = sizeof(si);
  229. BOOL result = CreateProcess(module.constPtr(), NULL, NULL, NULL, FALSE,
  230. 0, NULL, NULL, &si, &pi);
  231. if(result)
  232. {
  233. DEBUGOUT("RPC server started");
  234. serverInit = true;
  235. }
  236. else
  237. DEBUGOUT("CreateProcess failed to start midiproc");
  238. return !!result;
  239. }
  240. //
  241. // I_MidiRPCInitClient
  242. //
  243. // Initialize client RPC bindings and bind to the server.
  244. //
  245. bool I_MidiRPCInitClient()
  246. {
  247. RPC_STATUS status;
  248. // If server didn't start, client cannot be bound.
  249. if(!serverInit)
  250. return false;
  251. // Compose binding string
  252. status =
  253. RpcStringBindingCompose
  254. (
  255. NULL,
  256. (RPC_CSTR)("ncalrpc"),
  257. NULL,
  258. (RPC_CSTR)("2d4dc2f9-ce90-4080-8a00-1cb819086970"),
  259. NULL,
  260. &szStringBinding
  261. );
  262. if(status)
  263. {
  264. DEBUGOUT("RPC binding composition failed");
  265. return false;
  266. }
  267. // Create binding handle
  268. status = RpcBindingFromStringBinding(szStringBinding, &hMidiRPCBinding);
  269. if(status)
  270. {
  271. DEBUGOUT("RPC client binding failed");
  272. return false;
  273. }
  274. DEBUGOUT("RPC client initialized");
  275. clientInit = true;
  276. return true;
  277. }
  278. //
  279. // I_MidiRPCClientShutDown
  280. //
  281. // Shutdown the RPC Client
  282. //
  283. void I_MidiRPCClientShutDown()
  284. {
  285. // stop the server
  286. if(serverInit)
  287. {
  288. RpcTryExcept
  289. {
  290. MidiRPC_StopServer();
  291. }
  292. RpcExcept(1)
  293. {
  294. DEBUGOUT("Exception thrown when stopping RPC server");
  295. }
  296. RpcEndExcept
  297. serverInit = false;
  298. }
  299. if(szStringBinding)
  300. {
  301. RpcStringFree(&szStringBinding);
  302. szStringBinding = NULL;
  303. }
  304. if(hMidiRPCBinding)
  305. {
  306. RpcBindingFree(&hMidiRPCBinding);
  307. hMidiRPCBinding = NULL;
  308. }
  309. clientInit = false;
  310. }
  311. //
  312. // I_MidiRPCReady
  313. //
  314. // Returns true if both server and client initialized successfully.
  315. //
  316. bool I_MidiRPCReady()
  317. {
  318. CHECK_RPC_STATUS();
  319. return true;
  320. }
  321. #endif
  322. // EOF