x86UNIXRedbook.cc 11 KB

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