x86UNIXRedbook.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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. #include "console/console.h"
  23. #include "platformX86UNIX/platformX86UNIX.h"
  24. #include "platform/platformRedBook.h"
  25. #include "core/strings/stringFunctions.h"
  26. #if defined(__linux__)
  27. #include <linux/cdrom.h>
  28. #include <sys/ioctl.h>
  29. #include <errno.h>
  30. #include <string.h>
  31. #endif
  32. #include <SDL/SDL.h>
  33. class UnixRedBookDevice : public RedBookDevice
  34. {
  35. #if !defined(__FreeBSD__)
  36. private:
  37. S32 mDeviceId;
  38. SDL_CD *mCD;
  39. cdrom_volctrl mOriginalVolume;
  40. bool mVolumeInitialized;
  41. #endif
  42. bool mPlaying;
  43. void openVolume();
  44. void closeVolume();
  45. void setLastError(const char *);
  46. public:
  47. UnixRedBookDevice();
  48. ~UnixRedBookDevice();
  49. bool open();
  50. bool close();
  51. bool play(U32);
  52. bool stop();
  53. bool getTrackCount(U32 *);
  54. bool getVolume(F32 *);
  55. bool setVolume(F32);
  56. bool isPlaying() { return mPlaying; }
  57. bool updateStatus();
  58. void setDeviceInfo(S32 deviceId, const char *deviceName);
  59. };
  60. //-------------------------------------------------------------------------------
  61. // Class: UnixRedBookDevice
  62. //-------------------------------------------------------------------------------
  63. UnixRedBookDevice::UnixRedBookDevice()
  64. {
  65. #if !defined(__FreeBSD__)
  66. mVolumeInitialized = false;
  67. mDeviceId = -1;
  68. mDeviceName = NULL;
  69. mCD = NULL;
  70. mPlaying = false;
  71. #endif // !defined(__FreeBSD__)
  72. }
  73. //------------------------------------------------------------------------------
  74. UnixRedBookDevice::~UnixRedBookDevice()
  75. {
  76. #if !defined(__FreeBSD__)
  77. close();
  78. #endif // !defined(__FreeBSD__)
  79. }
  80. //------------------------------------------------------------------------------
  81. bool UnixRedBookDevice::updateStatus()
  82. {
  83. #if !defined(__FreeBSD__)
  84. AssertFatal(mCD, "mCD is NULL");
  85. CDstatus status = SDL_CDStatus(mCD);
  86. if (status == CD_ERROR)
  87. {
  88. setLastError("Error accessing device");
  89. return(false);
  90. }
  91. else if (status == CD_TRAYEMPTY)
  92. {
  93. setLastError("CD tray empty");
  94. return false;
  95. }
  96. mPlaying = (status == CD_PLAYING);
  97. return true;
  98. #endif // !defined(__FreeBSD__)
  99. }
  100. //------------------------------------------------------------------------------
  101. void UnixRedBookDevice::setDeviceInfo(S32 deviceId, const char *deviceName)
  102. {
  103. #if !defined(__FreeBSD__)
  104. mDeviceId = deviceId;
  105. mDeviceName = new char[dStrlen(deviceName) + 1];
  106. dStrcpy(mDeviceName, deviceName);
  107. #endif // !defined(__FreeBSD__)
  108. }
  109. //------------------------------------------------------------------------------
  110. bool UnixRedBookDevice::open()
  111. {
  112. #if !defined(__FreeBSD__)
  113. if(mAcquired)
  114. {
  115. setLastError("Device is already open.");
  116. return(false);
  117. }
  118. // open the device
  119. mCD = SDL_CDOpen(mDeviceId);
  120. if (mCD == NULL)
  121. {
  122. setLastError(SDL_GetError());
  123. return false;
  124. }
  125. mAcquired = true;
  126. openVolume();
  127. setLastError("");
  128. return(true);
  129. #endif // !defined(__FreeBSD__)
  130. }
  131. //------------------------------------------------------------------------------
  132. bool UnixRedBookDevice::close()
  133. {
  134. #if !defined(__FreeBSD__)
  135. if(!mAcquired)
  136. {
  137. setLastError("Device has not been acquired");
  138. return(false);
  139. }
  140. stop();
  141. closeVolume();
  142. if (mCD != NULL)
  143. {
  144. SDL_CDClose(mCD);
  145. mCD = NULL;
  146. }
  147. mAcquired = false;
  148. setLastError("");
  149. return(true);
  150. #endif // !defined(__FreeBSD__)
  151. }
  152. //------------------------------------------------------------------------------
  153. bool UnixRedBookDevice::play(U32 track)
  154. {
  155. #if !defined(__FreeBSD__)
  156. if(!mAcquired)
  157. {
  158. setLastError("Device has not been acquired");
  159. return(false);
  160. }
  161. U32 numTracks;
  162. if(!getTrackCount(&numTracks))
  163. return(false);
  164. if(track >= numTracks)
  165. {
  166. setLastError("Track index is out of range");
  167. return(false);
  168. }
  169. if (!updateStatus())
  170. return false;
  171. AssertFatal(mCD, "mCD is NULL");
  172. if (SDL_CDPlayTracks(mCD, track, 0, 1, 0) == -1)
  173. {
  174. setLastError(SDL_GetError());
  175. return false;
  176. }
  177. mPlaying = true;
  178. setLastError("");
  179. return(true);
  180. #endif // !defined(__FreeBSD__)
  181. }
  182. //------------------------------------------------------------------------------
  183. bool UnixRedBookDevice::stop()
  184. {
  185. #if !defined(__FreeBSD__)
  186. if(!mAcquired)
  187. {
  188. setLastError("Device has not been acquired");
  189. return(false);
  190. }
  191. AssertFatal(mCD, "mCD is NULL");
  192. if (SDL_CDStop(mCD) == -1)
  193. {
  194. setLastError(SDL_GetError());
  195. return(false);
  196. }
  197. mPlaying = false;
  198. setLastError("");
  199. return(true);
  200. #endif // !defined(__FreeBSD__)
  201. }
  202. //------------------------------------------------------------------------------
  203. bool UnixRedBookDevice::getTrackCount(U32 * numTracks)
  204. {
  205. #if !defined(__FreeBSD__)
  206. if(!mAcquired)
  207. {
  208. setLastError("Device has not been acquired");
  209. return(false);
  210. }
  211. if (!updateStatus())
  212. return false;
  213. AssertFatal(mCD, "mCD is NULL");
  214. *numTracks = mCD->numtracks;
  215. return(true);
  216. #endif // !defined(__FreeBSD__)
  217. }
  218. template <class Type>
  219. static inline Type max(Type v1, Type v2)
  220. {
  221. #if !defined(__FreeBSD__)
  222. if (v1 <= v2)
  223. return v2;
  224. else
  225. return v1;
  226. #endif // !defined(__FreeBSD__)
  227. }
  228. //------------------------------------------------------------------------------
  229. bool UnixRedBookDevice::getVolume(F32 * volume)
  230. {
  231. #if !defined(__FreeBSD__)
  232. if(!mAcquired)
  233. {
  234. setLastError("Device has not been acquired");
  235. return(false);
  236. }
  237. if(!mVolumeInitialized)
  238. {
  239. setLastError("Volume failed to initialize");
  240. return(false);
  241. }
  242. #if defined(__linux__)
  243. AssertFatal(mCD, "mCD is NULL");
  244. setLastError("");
  245. cdrom_volctrl sysvol;
  246. if (ioctl(mCD->id, CDROMVOLREAD, &sysvol) == -1)
  247. {
  248. setLastError(strerror(errno));
  249. return(false);
  250. }
  251. U8 maxVol = max(sysvol.channel0, sysvol.channel1);
  252. // JMQTODO: support different left/right channel volumes?
  253. *volume = static_cast<F32>(maxVol) / 255.f;
  254. return true;
  255. #else
  256. return(false);
  257. #endif
  258. #endif // !defined(__FreeBSD__)
  259. }
  260. //------------------------------------------------------------------------------
  261. bool UnixRedBookDevice::setVolume(F32 volume)
  262. {
  263. #if !defined(__FreeBSD__)
  264. if(!mAcquired)
  265. {
  266. setLastError("Device has not been acquired");
  267. return(false);
  268. }
  269. if(!mVolumeInitialized)
  270. {
  271. setLastError("Volume failed to initialize");
  272. return(false);
  273. }
  274. #if defined(__linux__)
  275. AssertFatal(mCD, "mCD is NULL");
  276. setLastError("");
  277. cdrom_volctrl sysvol;
  278. volume = volume * 255.f;
  279. if (volume > 255)
  280. volume = 255;
  281. if (volume < 0)
  282. volume = 0;
  283. sysvol.channel0 = sysvol.channel1 = static_cast<__u8>(volume);
  284. if (ioctl(mCD->id, CDROMVOLCTRL, &sysvol) == -1)
  285. {
  286. setLastError(strerror(errno));
  287. return(false);
  288. }
  289. return true;
  290. #else
  291. return(false);
  292. #endif
  293. #endif // !defined(__FreeBSD__)
  294. }
  295. //------------------------------------------------------------------------------
  296. void UnixRedBookDevice::openVolume()
  297. {
  298. #if !defined(__FreeBSD__)
  299. // Its unforunate that we have to do it this way, but SDL does not currently
  300. // support setting CD audio volume
  301. #if defined(__linux__)
  302. AssertFatal(mCD, "mCD is NULL");
  303. setLastError("");
  304. if (ioctl(mCD->id, CDROMVOLREAD, &mOriginalVolume) == -1)
  305. {
  306. setLastError(strerror(errno));
  307. return;
  308. }
  309. mVolumeInitialized = true;
  310. #else
  311. setLastError("Volume failed to initialize");
  312. #endif
  313. #endif // !defined(__FreeBSD__)
  314. }
  315. void UnixRedBookDevice::closeVolume()
  316. {
  317. #if !defined(__FreeBSD__)
  318. if(!mVolumeInitialized)
  319. return;
  320. #if defined(__linux__)
  321. AssertFatal(mCD, "mCD is NULL");
  322. setLastError("");
  323. if (ioctl(mCD->id, CDROMVOLCTRL, &mOriginalVolume) == -1)
  324. {
  325. setLastError(strerror(errno));
  326. return;
  327. }
  328. #endif
  329. mVolumeInitialized = false;
  330. #endif // !defined(__FreeBSD__)
  331. }
  332. //------------------------------------------------------------------------------
  333. void UnixRedBookDevice::setLastError(const char * error)
  334. {
  335. #if !defined(__FreeBSD__)
  336. RedBook::setLastError(error);
  337. #endif // !defined(__FreeBSD__)
  338. }
  339. //------------------------------------------------------------------------------
  340. void InstallRedBookDevices()
  341. {
  342. #if !defined(__FreeBSD__)
  343. Con::printf("CD Audio Init:");
  344. if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1)
  345. {
  346. Con::printf(" Unable to initialize CD Audio: %s", SDL_GetError());
  347. return;
  348. }
  349. S32 numDrives = SDL_CDNumDrives();
  350. if (numDrives == 0)
  351. {
  352. Con::printf(" No drives found.");
  353. return;
  354. }
  355. for (int i = 0; i < numDrives; ++i)
  356. {
  357. const char * deviceName = SDL_CDName(i);
  358. Con::printf(" Installing CD Audio device: %s", deviceName);
  359. UnixRedBookDevice * device = new UnixRedBookDevice;
  360. device->setDeviceInfo(i, deviceName);
  361. RedBook::installDevice(device);
  362. }
  363. Con::printf(" ");
  364. #endif // !defined(__FreeBSD__)
  365. }
  366. //------------------------------------------------------------------------------
  367. void PollRedbookDevices()
  368. {
  369. #if !defined(__FreeBSD__)
  370. UnixRedBookDevice *device = dynamic_cast<UnixRedBookDevice*>(RedBook::getCurrentDevice());
  371. if (device == NULL || !device->isPlaying())
  372. return;
  373. static const U32 PollDelay = 1000;
  374. static U32 lastPollTime = 0;
  375. U32 curTime = Platform::getVirtualMilliseconds();
  376. if (lastPollTime != 0 &&
  377. (curTime - lastPollTime) < PollDelay)
  378. return;
  379. lastPollTime = curTime;
  380. if (device->isPlaying())
  381. {
  382. device->updateStatus();
  383. if (!device->isPlaying())
  384. RedBook::handleCallback(RedBook::PlayFinished);
  385. }
  386. #endif // !defined(__FreeBSD__)
  387. }