x86UNIXRedbook.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //MGT: not needed on dedicated and help removal of SDL
  23. #ifndef TORQUE_DEDICATED
  24. #include "console/console.h"
  25. #include "platformX86UNIX/platformX86UNIX.h"
  26. #include "platform/platformRedBook.h"
  27. #include "core/strings/stringFunctions.h"
  28. #if defined(__linux__)
  29. #include <linux/cdrom.h>
  30. #include <sys/ioctl.h>
  31. #include <errno.h>
  32. #include <string.h>
  33. #endif
  34. #include <SDL/SDL.h>
  35. class UnixRedBookDevice : public RedBookDevice
  36. {
  37. #if !defined(__FreeBSD__)
  38. private:
  39. S32 mDeviceId;
  40. SDL_CD *mCD;
  41. cdrom_volctrl mOriginalVolume;
  42. bool mVolumeInitialized;
  43. #endif
  44. bool mPlaying;
  45. void openVolume();
  46. void closeVolume();
  47. void setLastError(const char *);
  48. public:
  49. UnixRedBookDevice();
  50. ~UnixRedBookDevice();
  51. bool open();
  52. bool close();
  53. bool play(U32);
  54. bool stop();
  55. bool getTrackCount(U32 *);
  56. bool getVolume(F32 *);
  57. bool setVolume(F32);
  58. bool isPlaying() { return mPlaying; }
  59. bool updateStatus();
  60. void setDeviceInfo(S32 deviceId, const char *deviceName);
  61. };
  62. //-------------------------------------------------------------------------------
  63. // Class: UnixRedBookDevice
  64. //-------------------------------------------------------------------------------
  65. UnixRedBookDevice::UnixRedBookDevice()
  66. {
  67. #if !defined(__FreeBSD__)
  68. mVolumeInitialized = false;
  69. mDeviceId = -1;
  70. mDeviceName = NULL;
  71. mCD = NULL;
  72. mPlaying = false;
  73. #endif // !defined(__FreeBSD__)
  74. }
  75. //------------------------------------------------------------------------------
  76. UnixRedBookDevice::~UnixRedBookDevice()
  77. {
  78. #if !defined(__FreeBSD__)
  79. close();
  80. #endif // !defined(__FreeBSD__)
  81. }
  82. //------------------------------------------------------------------------------
  83. bool UnixRedBookDevice::updateStatus()
  84. {
  85. #if !defined(__FreeBSD__)
  86. AssertFatal(mCD, "mCD is NULL");
  87. CDstatus status = SDL_CDStatus(mCD);
  88. if (status == CD_ERROR)
  89. {
  90. setLastError("Error accessing device");
  91. return(false);
  92. }
  93. else if (status == CD_TRAYEMPTY)
  94. {
  95. setLastError("CD tray empty");
  96. return false;
  97. }
  98. mPlaying = (status == CD_PLAYING);
  99. return true;
  100. #endif // !defined(__FreeBSD__)
  101. }
  102. //------------------------------------------------------------------------------
  103. void UnixRedBookDevice::setDeviceInfo(S32 deviceId, const char *deviceName)
  104. {
  105. #if !defined(__FreeBSD__)
  106. mDeviceId = deviceId;
  107. mDeviceName = new char[dStrlen(deviceName) + 1];
  108. dStrcpy(mDeviceName, deviceName);
  109. #endif // !defined(__FreeBSD__)
  110. }
  111. //------------------------------------------------------------------------------
  112. bool UnixRedBookDevice::open()
  113. {
  114. #if !defined(__FreeBSD__)
  115. if(mAcquired)
  116. {
  117. setLastError("Device is already open.");
  118. return(false);
  119. }
  120. // open the device
  121. mCD = SDL_CDOpen(mDeviceId);
  122. if (mCD == NULL)
  123. {
  124. setLastError(SDL_GetError());
  125. return false;
  126. }
  127. mAcquired = true;
  128. openVolume();
  129. setLastError("");
  130. return(true);
  131. #endif // !defined(__FreeBSD__)
  132. }
  133. //------------------------------------------------------------------------------
  134. bool UnixRedBookDevice::close()
  135. {
  136. #if !defined(__FreeBSD__)
  137. if(!mAcquired)
  138. {
  139. setLastError("Device has not been acquired");
  140. return(false);
  141. }
  142. stop();
  143. closeVolume();
  144. if (mCD != NULL)
  145. {
  146. SDL_CDClose(mCD);
  147. mCD = NULL;
  148. }
  149. mAcquired = false;
  150. setLastError("");
  151. return(true);
  152. #endif // !defined(__FreeBSD__)
  153. }
  154. //------------------------------------------------------------------------------
  155. bool UnixRedBookDevice::play(U32 track)
  156. {
  157. #if !defined(__FreeBSD__)
  158. if(!mAcquired)
  159. {
  160. setLastError("Device has not been acquired");
  161. return(false);
  162. }
  163. U32 numTracks;
  164. if(!getTrackCount(&numTracks))
  165. return(false);
  166. if(track >= numTracks)
  167. {
  168. setLastError("Track index is out of range");
  169. return(false);
  170. }
  171. if (!updateStatus())
  172. return false;
  173. AssertFatal(mCD, "mCD is NULL");
  174. if (SDL_CDPlayTracks(mCD, track, 0, 1, 0) == -1)
  175. {
  176. setLastError(SDL_GetError());
  177. return false;
  178. }
  179. mPlaying = true;
  180. setLastError("");
  181. return(true);
  182. #endif // !defined(__FreeBSD__)
  183. }
  184. //------------------------------------------------------------------------------
  185. bool UnixRedBookDevice::stop()
  186. {
  187. #if !defined(__FreeBSD__)
  188. if(!mAcquired)
  189. {
  190. setLastError("Device has not been acquired");
  191. return(false);
  192. }
  193. AssertFatal(mCD, "mCD is NULL");
  194. if (SDL_CDStop(mCD) == -1)
  195. {
  196. setLastError(SDL_GetError());
  197. return(false);
  198. }
  199. mPlaying = false;
  200. setLastError("");
  201. return(true);
  202. #endif // !defined(__FreeBSD__)
  203. }
  204. //------------------------------------------------------------------------------
  205. bool UnixRedBookDevice::getTrackCount(U32 * numTracks)
  206. {
  207. #if !defined(__FreeBSD__)
  208. if(!mAcquired)
  209. {
  210. setLastError("Device has not been acquired");
  211. return(false);
  212. }
  213. if (!updateStatus())
  214. return false;
  215. AssertFatal(mCD, "mCD is NULL");
  216. *numTracks = mCD->numtracks;
  217. return(true);
  218. #endif // !defined(__FreeBSD__)
  219. }
  220. template <class Type>
  221. static inline Type max(Type v1, Type v2)
  222. {
  223. #if !defined(__FreeBSD__)
  224. if (v1 <= v2)
  225. return v2;
  226. else
  227. return v1;
  228. #endif // !defined(__FreeBSD__)
  229. }
  230. //------------------------------------------------------------------------------
  231. bool UnixRedBookDevice::getVolume(F32 * volume)
  232. {
  233. #if !defined(__FreeBSD__)
  234. if(!mAcquired)
  235. {
  236. setLastError("Device has not been acquired");
  237. return(false);
  238. }
  239. if(!mVolumeInitialized)
  240. {
  241. setLastError("Volume failed to initialize");
  242. return(false);
  243. }
  244. #if defined(__linux__)
  245. AssertFatal(mCD, "mCD is NULL");
  246. setLastError("");
  247. cdrom_volctrl sysvol;
  248. if (ioctl(mCD->id, CDROMVOLREAD, &sysvol) == -1)
  249. {
  250. setLastError(strerror(errno));
  251. return(false);
  252. }
  253. U8 maxVol = max(sysvol.channel0, sysvol.channel1);
  254. // JMQTODO: support different left/right channel volumes?
  255. *volume = static_cast<F32>(maxVol) / 255.f;
  256. return true;
  257. #else
  258. return(false);
  259. #endif
  260. #endif // !defined(__FreeBSD__)
  261. }
  262. //------------------------------------------------------------------------------
  263. bool UnixRedBookDevice::setVolume(F32 volume)
  264. {
  265. #if !defined(__FreeBSD__)
  266. if(!mAcquired)
  267. {
  268. setLastError("Device has not been acquired");
  269. return(false);
  270. }
  271. if(!mVolumeInitialized)
  272. {
  273. setLastError("Volume failed to initialize");
  274. return(false);
  275. }
  276. #if defined(__linux__)
  277. AssertFatal(mCD, "mCD is NULL");
  278. setLastError("");
  279. cdrom_volctrl sysvol;
  280. volume = volume * 255.f;
  281. if (volume > 255)
  282. volume = 255;
  283. if (volume < 0)
  284. volume = 0;
  285. sysvol.channel0 = sysvol.channel1 = static_cast<__u8>(volume);
  286. if (ioctl(mCD->id, CDROMVOLCTRL, &sysvol) == -1)
  287. {
  288. setLastError(strerror(errno));
  289. return(false);
  290. }
  291. return true;
  292. #else
  293. return(false);
  294. #endif
  295. #endif // !defined(__FreeBSD__)
  296. }
  297. //------------------------------------------------------------------------------
  298. void UnixRedBookDevice::openVolume()
  299. {
  300. #if !defined(__FreeBSD__)
  301. // Its unforunate that we have to do it this way, but SDL does not currently
  302. // support setting CD audio volume
  303. #if defined(__linux__)
  304. AssertFatal(mCD, "mCD is NULL");
  305. setLastError("");
  306. if (ioctl(mCD->id, CDROMVOLREAD, &mOriginalVolume) == -1)
  307. {
  308. setLastError(strerror(errno));
  309. return;
  310. }
  311. mVolumeInitialized = true;
  312. #else
  313. setLastError("Volume failed to initialize");
  314. #endif
  315. #endif // !defined(__FreeBSD__)
  316. }
  317. void UnixRedBookDevice::closeVolume()
  318. {
  319. #if !defined(__FreeBSD__)
  320. if(!mVolumeInitialized)
  321. return;
  322. #if defined(__linux__)
  323. AssertFatal(mCD, "mCD is NULL");
  324. setLastError("");
  325. if (ioctl(mCD->id, CDROMVOLCTRL, &mOriginalVolume) == -1)
  326. {
  327. setLastError(strerror(errno));
  328. return;
  329. }
  330. #endif
  331. mVolumeInitialized = false;
  332. #endif // !defined(__FreeBSD__)
  333. }
  334. //------------------------------------------------------------------------------
  335. void UnixRedBookDevice::setLastError(const char * error)
  336. {
  337. #if !defined(__FreeBSD__)
  338. RedBook::setLastError(error);
  339. #endif // !defined(__FreeBSD__)
  340. }
  341. //------------------------------------------------------------------------------
  342. void InstallRedBookDevices()
  343. {
  344. #if !defined(__FreeBSD__)
  345. Con::printf("CD Audio Init:");
  346. if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1)
  347. {
  348. Con::printf(" Unable to initialize CD Audio: %s", SDL_GetError());
  349. return;
  350. }
  351. S32 numDrives = SDL_CDNumDrives();
  352. if (numDrives == 0)
  353. {
  354. Con::printf(" No drives found.");
  355. return;
  356. }
  357. for (int i = 0; i < numDrives; ++i)
  358. {
  359. const char * deviceName = SDL_CDName(i);
  360. Con::printf(" Installing CD Audio device: %s", deviceName);
  361. UnixRedBookDevice * device = new UnixRedBookDevice;
  362. device->setDeviceInfo(i, deviceName);
  363. RedBook::installDevice(device);
  364. }
  365. Con::printf(" ");
  366. #endif // !defined(__FreeBSD__)
  367. }
  368. //------------------------------------------------------------------------------
  369. void PollRedbookDevices()
  370. {
  371. #if !defined(__FreeBSD__)
  372. UnixRedBookDevice *device = dynamic_cast<UnixRedBookDevice*>(RedBook::getCurrentDevice());
  373. if (device == NULL || !device->isPlaying())
  374. return;
  375. static const U32 PollDelay = 1000;
  376. static U32 lastPollTime = 0;
  377. U32 curTime = Platform::getVirtualMilliseconds();
  378. if (lastPollTime != 0 &&
  379. (curTime - lastPollTime) < PollDelay)
  380. return;
  381. lastPollTime = curTime;
  382. if (device->isPlaying())
  383. {
  384. device->updateStatus();
  385. if (!device->isPlaying())
  386. RedBook::handleCallback(RedBook::PlayFinished);
  387. }
  388. #endif // !defined(__FreeBSD__)
  389. }
  390. #endif
  391. //MGT: end