SDL_syscdrom.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:11k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15.     Sam Lantinga
  16.     slouken@libsdl.org
  17. */
  18. #ifdef SAVE_RCSID
  19. static char rcsid =
  20.  "@(#) $Id: SDL_syscdrom.c,v 1.4 2002/04/22 21:38:02 wmay Exp $";
  21. #endif
  22. /* Functions for system-level CD-ROM audio control */
  23. #include <sys/types.h>
  24. #include <sys/ioctl.h>
  25. #include <stdlib.h>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <errno.h>
  31. #include <unistd.h>
  32. #include <sys/ioctl.h>
  33. #include <sys/cdio.h>
  34. #include "SDL_error.h"
  35. #include "SDL_cdrom.h"
  36. #include "SDL_syscdrom.h"
  37. /* The maximum number of CD-ROM drives we'll detect */
  38. #define MAX_DRIVES 16
  39. /* A list of available CD-ROM drives */
  40. static char *SDL_cdlist[MAX_DRIVES];
  41. static dev_t SDL_cdmode[MAX_DRIVES];
  42. /* The system-dependent CD control functions */
  43. static const char *SDL_SYS_CDName(int drive);
  44. static int SDL_SYS_CDOpen(int drive);
  45. static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
  46. static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
  47. static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
  48. static int SDL_SYS_CDPause(SDL_CD *cdrom);
  49. static int SDL_SYS_CDResume(SDL_CD *cdrom);
  50. static int SDL_SYS_CDStop(SDL_CD *cdrom);
  51. static int SDL_SYS_CDEject(SDL_CD *cdrom);
  52. static void SDL_SYS_CDClose(SDL_CD *cdrom);
  53. /* Some ioctl() errno values which occur when the tray is empty */
  54. #define ERRNO_TRAYEMPTY(errno)
  55. ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL) || 
  56.  (errno == ENODEV))
  57. /* Check a drive to see if it is a CD-ROM */
  58. static int CheckDrive(char *drive, struct stat *stbuf)
  59. {
  60. int is_cd, cdfd;
  61. struct ioc_read_subchannel info;
  62. /* If it doesn't exist, return -1 */
  63. if ( stat(drive, stbuf) < 0 ) {
  64. return(-1);
  65. }
  66. /* If it does exist, verify that it's an available CD-ROM */
  67. is_cd = 0;
  68. if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
  69. cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
  70. if ( cdfd >= 0 ) {
  71. info.address_format = CD_MSF_FORMAT;
  72. info.data_format = CD_CURRENT_POSITION;
  73. info.data_len = 0;
  74. info.data = NULL;
  75. /* Under Linux, EIO occurs when a disk is not present.
  76.    This isn't 100% reliable, so we use the USE_MNTENT
  77.    code above instead.
  78.  */
  79. if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) ||
  80. ERRNO_TRAYEMPTY(errno) ) {
  81. is_cd = 1;
  82. }
  83. close(cdfd);
  84. }
  85. else if (ERRNO_TRAYEMPTY(errno))
  86. is_cd = 1;
  87. }
  88. return(is_cd);
  89. }
  90. /* Add a CD-ROM drive to our list of valid drives */
  91. static void AddDrive(char *drive, struct stat *stbuf)
  92. {
  93. int i;
  94. if ( SDL_numcds < MAX_DRIVES ) {
  95. /* Check to make sure it's not already in our list.
  96.      This can happen when we see a drive via symbolic link.
  97.  */
  98. for ( i=0; i<SDL_numcds; ++i ) {
  99. if ( stbuf->st_rdev == SDL_cdmode[i] ) {
  100. #ifdef DEBUG_CDROM
  101.   fprintf(stderr, "Duplicate drive detected: %s == %sn", drive, SDL_cdlist[i]);
  102. #endif
  103. return;
  104. }
  105. }
  106. /* Add this drive to our list */
  107. i = SDL_numcds;
  108. SDL_cdlist[i] = (char *)malloc(strlen(drive)+1);
  109. if ( SDL_cdlist[i] == NULL ) {
  110. SDL_OutOfMemory();
  111. return;
  112. }
  113. strcpy(SDL_cdlist[i], drive);
  114. SDL_cdmode[i] = stbuf->st_rdev;
  115. ++SDL_numcds;
  116. #ifdef DEBUG_CDROM
  117.   fprintf(stderr, "Added CD-ROM drive: %sn", drive);
  118. #endif
  119. }
  120. }
  121. int  SDL_SYS_CDInit(void)
  122. {
  123. static char *checklist[] = {
  124. #ifdef __OpenBSD__
  125. "?0 cd?c", "cdrom", NULL
  126. #else
  127. "?0 cd?c", "?0 acd?c", "cdrom", NULL
  128. #endif
  129. };
  130. char *SDLcdrom;
  131. int i, j, exists;
  132. char drive[32];
  133. struct stat stbuf;
  134. /* Fill in our driver capabilities */
  135. SDL_CDcaps.Name = SDL_SYS_CDName;
  136. SDL_CDcaps.Open = SDL_SYS_CDOpen;
  137. SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
  138. SDL_CDcaps.Status = SDL_SYS_CDStatus;
  139. SDL_CDcaps.Play = SDL_SYS_CDPlay;
  140. SDL_CDcaps.Pause = SDL_SYS_CDPause;
  141. SDL_CDcaps.Resume = SDL_SYS_CDResume;
  142. SDL_CDcaps.Stop = SDL_SYS_CDStop;
  143. SDL_CDcaps.Eject = SDL_SYS_CDEject;
  144. SDL_CDcaps.Close = SDL_SYS_CDClose;
  145. /* Look in the environment for our CD-ROM drive list */
  146. SDLcdrom = getenv("SDL_CDROM"); /* ':' separated list of devices */
  147. if ( SDLcdrom != NULL ) {
  148. char *cdpath, *delim;
  149. cdpath = malloc(strlen(SDLcdrom)+1);
  150. if ( cdpath != NULL ) {
  151. strcpy(cdpath, SDLcdrom);
  152. SDLcdrom = cdpath;
  153. do {
  154. delim = strchr(SDLcdrom, ':');
  155. if ( delim ) {
  156. *delim++ = '';
  157. }
  158. if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
  159. AddDrive(SDLcdrom, &stbuf);
  160. }
  161. if ( delim ) {
  162. SDLcdrom = delim;
  163. } else {
  164. SDLcdrom = NULL;
  165. }
  166. } while ( SDLcdrom );
  167. free(cdpath);
  168. }
  169. /* If we found our drives, there's nothing left to do */
  170. if ( SDL_numcds > 0 ) {
  171. return(0);
  172. }
  173. }
  174. /* Scan the system for CD-ROM drives */
  175. for ( i=0; checklist[i]; ++i ) {
  176. if ( checklist[i][0] == '?' ) {
  177. char *insert;
  178. exists = 1;
  179. for ( j=checklist[i][1]; exists; ++j ) {
  180. sprintf(drive, "/dev/%s", &checklist[i][3]);
  181. insert = strchr(drive, '?');
  182. if ( insert != NULL ) {
  183. *insert = j;
  184. }
  185. switch (CheckDrive(drive, &stbuf)) {
  186. /* Drive exists and is a CD-ROM */
  187. case 1:
  188. AddDrive(drive, &stbuf);
  189. break;
  190. /* Drive exists, but isn't a CD-ROM */
  191. case 0:
  192. break;
  193. /* Drive doesn't exist */
  194. case -1:
  195. exists = 0;
  196. break;
  197. }
  198. }
  199. } else {
  200. sprintf(drive, "/dev/%s", checklist[i]);
  201. if ( CheckDrive(drive, &stbuf) > 0 ) {
  202. AddDrive(drive, &stbuf);
  203. }
  204. }
  205. }
  206. return(0);
  207. }
  208. /* General ioctl() CD-ROM command function */
  209. static int SDL_SYS_CDioctl(int id, int command, void *arg)
  210. {
  211. int retval;
  212. retval = ioctl(id, command, arg);
  213. if ( retval < 0 ) {
  214. SDL_SetError("ioctl() error: %s", strerror(errno));
  215. }
  216. return(retval);
  217. }
  218. static const char *SDL_SYS_CDName(int drive)
  219. {
  220. return(SDL_cdlist[drive]);
  221. }
  222. static int SDL_SYS_CDOpen(int drive)
  223. {
  224. return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0));
  225. }
  226. static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
  227. {
  228. struct ioc_toc_header toc;
  229. int i, okay;
  230. struct ioc_read_toc_entry entry;
  231. struct cd_toc_entry data;
  232. okay = 0;
  233. if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) {
  234. cdrom->numtracks = toc.ending_track-toc.starting_track+1;
  235. if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
  236. cdrom->numtracks = SDL_MAX_TRACKS;
  237. }
  238. /* Read all the track TOC entries */
  239. for ( i=0; i<=cdrom->numtracks; ++i ) {
  240. if ( i == cdrom->numtracks ) {
  241. cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */
  242. } else {
  243. cdrom->track[i].id = toc.starting_track+i;
  244. }
  245. entry.starting_track = cdrom->track[i].id;
  246. entry.address_format = CD_MSF_FORMAT;
  247. entry.data_len = sizeof(data);
  248. entry.data = &data;
  249. if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS,
  250. &entry) < 0 ) {
  251. break;
  252. } else {
  253. cdrom->track[i].type = data.control;
  254. cdrom->track[i].offset = MSF_TO_FRAMES(
  255. data.addr.msf.minute,
  256. data.addr.msf.second,
  257. data.addr.msf.frame);
  258. cdrom->track[i].length = 0;
  259. if ( i > 0 ) {
  260. cdrom->track[i-1].length =
  261. cdrom->track[i].offset-
  262. cdrom->track[i-1].offset;
  263. }
  264. }
  265. }
  266. if ( i == (cdrom->numtracks+1) ) {
  267. okay = 1;
  268. }
  269. }
  270. return(okay ? 0 : -1);
  271. }
  272. /* Get CD-ROM status */
  273. static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
  274. {
  275. CDstatus status;
  276. struct ioc_toc_header toc;
  277. struct ioc_read_subchannel info;
  278. struct cd_sub_channel_info data;
  279. info.address_format = CD_MSF_FORMAT;
  280. info.data_format = CD_CURRENT_POSITION;
  281. info.track = 0;
  282. info.data_len = sizeof(data);
  283. info.data = &data;
  284. if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) {
  285. if ( ERRNO_TRAYEMPTY(errno) ) {
  286. status = CD_TRAYEMPTY;
  287. } else {
  288. status = CD_ERROR;
  289. }
  290. } else {
  291. switch (data.header.audio_status) {
  292. case CD_AS_AUDIO_INVALID:
  293. case CD_AS_NO_STATUS:
  294. /* Try to determine if there's a CD available */
  295. if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0)
  296. status = CD_STOPPED;
  297. else
  298. status = CD_TRAYEMPTY;
  299. break;
  300. case CD_AS_PLAY_COMPLETED:
  301. status = CD_STOPPED;
  302. break;
  303. case CD_AS_PLAY_IN_PROGRESS:
  304. status = CD_PLAYING;
  305. break;
  306. case CD_AS_PLAY_PAUSED:
  307. status = CD_PAUSED;
  308. break;
  309. default:
  310. status = CD_ERROR;
  311. break;
  312. }
  313. }
  314. if ( position ) {
  315. if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
  316. *position = MSF_TO_FRAMES(
  317. data.what.position.absaddr.msf.minute,
  318. data.what.position.absaddr.msf.second,
  319. data.what.position.absaddr.msf.frame);
  320. } else {
  321. *position = 0;
  322. }
  323. }
  324. return(status);
  325. }
  326. /* Start play */
  327. static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
  328. {
  329. struct ioc_play_msf playtime;
  330. FRAMES_TO_MSF(start,
  331. &playtime.start_m, &playtime.start_s, &playtime.start_f);
  332. FRAMES_TO_MSF(start+length,
  333. &playtime.end_m, &playtime.end_s, &playtime.end_f);
  334. #ifdef DEBUG_CDROM
  335.   fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%dn",
  336. playtime.start_m, playtime.start_s, playtime.start_f,
  337. playtime.end_m, playtime.end_s, playtime.end_f);
  338. #endif
  339. ioctl(cdrom->id, CDIOCSTART, 0);
  340. return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime));
  341. }
  342. /* Pause play */
  343. static int SDL_SYS_CDPause(SDL_CD *cdrom)
  344. {
  345. return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0));
  346. }
  347. /* Resume play */
  348. static int SDL_SYS_CDResume(SDL_CD *cdrom)
  349. {
  350. return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0));
  351. }
  352. /* Stop play */
  353. static int SDL_SYS_CDStop(SDL_CD *cdrom)
  354. {
  355. return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0));
  356. }
  357. /* Eject the CD-ROM */
  358. static int SDL_SYS_CDEject(SDL_CD *cdrom)
  359. {
  360. return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0));
  361. }
  362. /* Close the CD-ROM handle */
  363. static void SDL_SYS_CDClose(SDL_CD *cdrom)
  364. {
  365. close(cdrom->id);
  366. }
  367. void SDL_SYS_CDQuit(void)
  368. {
  369. int i;
  370. if ( SDL_numcds > 0 ) {
  371. for ( i=0; i<SDL_numcds; ++i ) {
  372. free(SDL_cdlist[i]);
  373. }
  374. SDL_numcds = 0;
  375. }
  376. }