diff options
author | Franklin Wei <git@fwei.tk> | 2017-01-21 15:18:31 -0500 |
---|---|---|
committer | Franklin Wei <git@fwei.tk> | 2017-12-23 21:01:26 -0500 |
commit | a855d6202536ff28e5aae4f22a0f31d8f5b325d0 (patch) | |
tree | 8c75f224dd64ed360505afa8843d016b0d75000b /apps/plugins/sdl/src/cdrom | |
parent | 01c6dcf6c7b9bb1ad2fa0450f99bacc5f3d3e04b (diff) | |
download | rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.tar.gz rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.zip |
Port of Duke Nukem 3D
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL
for Rockbox.
Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
Diffstat (limited to 'apps/plugins/sdl/src/cdrom')
26 files changed, 9197 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/cdrom/SDL_cdrom.c b/apps/plugins/sdl/src/cdrom/SDL_cdrom.c new file mode 100644 index 0000000000..8f91bb1b34 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/SDL_cdrom.c | |||
@@ -0,0 +1,341 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* This is the CD-audio control API for Simple DirectMedia Layer */ | ||
25 | |||
26 | #include "SDL_cdrom.h" | ||
27 | #include "SDL_syscdrom.h" | ||
28 | |||
29 | #if !defined(__MACOS__) | ||
30 | #define CLIP_FRAMES 10 /* Some CD-ROMs won't go all the way */ | ||
31 | #endif | ||
32 | |||
33 | static int SDL_cdinitted = 0; | ||
34 | static SDL_CD *default_cdrom; | ||
35 | |||
36 | /* The system level CD-ROM control functions */ | ||
37 | struct CDcaps SDL_CDcaps = { | ||
38 | NULL, /* Name */ | ||
39 | NULL, /* Open */ | ||
40 | NULL, /* GetTOC */ | ||
41 | NULL, /* Status */ | ||
42 | NULL, /* Play */ | ||
43 | NULL, /* Pause */ | ||
44 | NULL, /* Resume */ | ||
45 | NULL, /* Stop */ | ||
46 | NULL, /* Eject */ | ||
47 | NULL, /* Close */ | ||
48 | }; | ||
49 | int SDL_numcds; | ||
50 | |||
51 | int SDL_CDROMInit(void) | ||
52 | { | ||
53 | int retval; | ||
54 | |||
55 | SDL_numcds = 0; | ||
56 | retval = SDL_SYS_CDInit(); | ||
57 | if ( retval == 0 ) { | ||
58 | SDL_cdinitted = 1; | ||
59 | } | ||
60 | default_cdrom = NULL; | ||
61 | return(retval); | ||
62 | } | ||
63 | |||
64 | /* Check to see if the CD-ROM subsystem has been initialized */ | ||
65 | static int CheckInit(int check_cdrom, SDL_CD **cdrom) | ||
66 | { | ||
67 | int okay; | ||
68 | |||
69 | okay = SDL_cdinitted; | ||
70 | if ( check_cdrom && (*cdrom == NULL) ) { | ||
71 | *cdrom = default_cdrom; | ||
72 | if ( *cdrom == NULL ) { | ||
73 | SDL_SetError("CD-ROM not opened"); | ||
74 | okay = 0; | ||
75 | } | ||
76 | } | ||
77 | if ( ! SDL_cdinitted ) { | ||
78 | SDL_SetError("CD-ROM subsystem not initialized"); | ||
79 | } | ||
80 | return(okay); | ||
81 | } | ||
82 | |||
83 | int SDL_CDNumDrives(void) | ||
84 | { | ||
85 | if ( ! CheckInit(0, NULL) ) { | ||
86 | return(-1); | ||
87 | } | ||
88 | return(SDL_numcds); | ||
89 | } | ||
90 | |||
91 | const char *SDL_CDName(int drive) | ||
92 | { | ||
93 | if ( ! CheckInit(0, NULL) ) { | ||
94 | return(NULL); | ||
95 | } | ||
96 | if ( drive >= SDL_numcds ) { | ||
97 | SDL_SetError("Invalid CD-ROM drive index"); | ||
98 | return(NULL); | ||
99 | } | ||
100 | if ( SDL_CDcaps.Name ) { | ||
101 | return(SDL_CDcaps.Name(drive)); | ||
102 | } else { | ||
103 | return(""); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | SDL_CD *SDL_CDOpen(int drive) | ||
108 | { | ||
109 | struct SDL_CD *cdrom; | ||
110 | |||
111 | if ( ! CheckInit(0, NULL) ) { | ||
112 | return(NULL); | ||
113 | } | ||
114 | if ( drive >= SDL_numcds ) { | ||
115 | SDL_SetError("Invalid CD-ROM drive index"); | ||
116 | return(NULL); | ||
117 | } | ||
118 | cdrom = (SDL_CD *)SDL_malloc(sizeof(*cdrom)); | ||
119 | if ( cdrom == NULL ) { | ||
120 | SDL_OutOfMemory(); | ||
121 | return(NULL); | ||
122 | } | ||
123 | SDL_memset(cdrom, 0, sizeof(*cdrom)); | ||
124 | cdrom->id = SDL_CDcaps.Open(drive); | ||
125 | if ( cdrom->id < 0 ) { | ||
126 | SDL_free(cdrom); | ||
127 | return(NULL); | ||
128 | } | ||
129 | default_cdrom = cdrom; | ||
130 | return(cdrom); | ||
131 | } | ||
132 | |||
133 | CDstatus SDL_CDStatus(SDL_CD *cdrom) | ||
134 | { | ||
135 | CDstatus status; | ||
136 | int i; | ||
137 | Uint32 position; | ||
138 | |||
139 | /* Check if the CD-ROM subsystem has been initialized */ | ||
140 | if ( ! CheckInit(1, &cdrom) ) { | ||
141 | return(CD_ERROR); | ||
142 | } | ||
143 | |||
144 | /* Get the current status of the drive */ | ||
145 | cdrom->numtracks = 0; | ||
146 | cdrom->cur_track = 0; | ||
147 | cdrom->cur_frame = 0; | ||
148 | status = SDL_CDcaps.Status(cdrom, &i); | ||
149 | position = (Uint32)i; | ||
150 | cdrom->status = status; | ||
151 | |||
152 | /* Get the table of contents, if there's a CD available */ | ||
153 | if ( CD_INDRIVE(status) ) { | ||
154 | if ( SDL_CDcaps.GetTOC(cdrom) < 0 ) { | ||
155 | status = CD_ERROR; | ||
156 | } | ||
157 | /* If the drive is playing, get current play position */ | ||
158 | if ( (status == CD_PLAYING) || (status == CD_PAUSED) ) { | ||
159 | for ( i=1; cdrom->track[i].offset <= position; ++i ) { | ||
160 | /* Keep looking */; | ||
161 | } | ||
162 | #ifdef DEBUG_CDROM | ||
163 | fprintf(stderr, "Current position: %d, track = %d (offset is %d)\n", | ||
164 | position, i-1, cdrom->track[i-1].offset); | ||
165 | #endif | ||
166 | cdrom->cur_track = i-1; | ||
167 | position -= cdrom->track[cdrom->cur_track].offset; | ||
168 | cdrom->cur_frame = position; | ||
169 | } | ||
170 | } | ||
171 | return(status); | ||
172 | } | ||
173 | |||
174 | int SDL_CDPlayTracks(SDL_CD *cdrom, | ||
175 | int strack, int sframe, int ntracks, int nframes) | ||
176 | { | ||
177 | int etrack, eframe; | ||
178 | int start, length; | ||
179 | |||
180 | /* Check if the CD-ROM subsystem has been initialized */ | ||
181 | if ( ! CheckInit(1, &cdrom) ) { | ||
182 | return(CD_ERROR); | ||
183 | } | ||
184 | |||
185 | /* Determine the starting and ending tracks */ | ||
186 | if ( (strack < 0) || (strack >= cdrom->numtracks) ) { | ||
187 | SDL_SetError("Invalid starting track"); | ||
188 | return(CD_ERROR); | ||
189 | } | ||
190 | if ( ! ntracks && ! nframes ) { | ||
191 | etrack = cdrom->numtracks; | ||
192 | eframe = 0; | ||
193 | } else { | ||
194 | etrack = strack+ntracks; | ||
195 | if ( etrack == strack ) { | ||
196 | eframe = sframe + nframes; | ||
197 | } else { | ||
198 | eframe = nframes; | ||
199 | } | ||
200 | } | ||
201 | if ( etrack > cdrom->numtracks ) { | ||
202 | SDL_SetError("Invalid play length"); | ||
203 | return(CD_ERROR); | ||
204 | } | ||
205 | |||
206 | /* Skip data tracks and verify frame offsets */ | ||
207 | while ( (strack <= etrack) && | ||
208 | (cdrom->track[strack].type == SDL_DATA_TRACK) ) { | ||
209 | ++strack; | ||
210 | } | ||
211 | if ( sframe >= (int)cdrom->track[strack].length ) { | ||
212 | SDL_SetError("Invalid starting frame for track %d", strack); | ||
213 | return(CD_ERROR); | ||
214 | } | ||
215 | while ( (etrack > strack) && | ||
216 | (cdrom->track[etrack-1].type == SDL_DATA_TRACK) ) { | ||
217 | --etrack; | ||
218 | } | ||
219 | if ( eframe > (int)cdrom->track[etrack].length ) { | ||
220 | SDL_SetError("Invalid ending frame for track %d", etrack); | ||
221 | return(CD_ERROR); | ||
222 | } | ||
223 | |||
224 | /* Determine start frame and play length */ | ||
225 | start = (cdrom->track[strack].offset+sframe); | ||
226 | length = (cdrom->track[etrack].offset+eframe)-start; | ||
227 | #ifdef CLIP_FRAMES | ||
228 | /* I've never seen this necessary, but xmcd does it.. */ | ||
229 | length -= CLIP_FRAMES; /* CLIP_FRAMES == 10 */ | ||
230 | #endif | ||
231 | if ( length < 0 ) { | ||
232 | return(0); | ||
233 | } | ||
234 | |||
235 | /* Play! */ | ||
236 | #ifdef DEBUG_CDROM | ||
237 | fprintf(stderr, "Playing %d frames at offset %d\n", length, start); | ||
238 | #endif | ||
239 | return(SDL_CDcaps.Play(cdrom, start, length)); | ||
240 | } | ||
241 | |||
242 | int SDL_CDPlay(SDL_CD *cdrom, int sframe, int length) | ||
243 | { | ||
244 | /* Check if the CD-ROM subsystem has been initialized */ | ||
245 | if ( ! CheckInit(1, &cdrom) ) { | ||
246 | return(CD_ERROR); | ||
247 | } | ||
248 | |||
249 | return(SDL_CDcaps.Play(cdrom, sframe, length)); | ||
250 | } | ||
251 | |||
252 | int SDL_CDPause(SDL_CD *cdrom) | ||
253 | { | ||
254 | CDstatus status; | ||
255 | int retval; | ||
256 | |||
257 | /* Check if the CD-ROM subsystem has been initialized */ | ||
258 | if ( ! CheckInit(1, &cdrom) ) { | ||
259 | return(CD_ERROR); | ||
260 | } | ||
261 | |||
262 | status = SDL_CDcaps.Status(cdrom, NULL); | ||
263 | switch (status) { | ||
264 | case CD_PLAYING: | ||
265 | retval = SDL_CDcaps.Pause(cdrom); | ||
266 | break; | ||
267 | default: | ||
268 | retval = 0; | ||
269 | break; | ||
270 | } | ||
271 | return(retval); | ||
272 | } | ||
273 | |||
274 | int SDL_CDResume(SDL_CD *cdrom) | ||
275 | { | ||
276 | CDstatus status; | ||
277 | int retval; | ||
278 | |||
279 | /* Check if the CD-ROM subsystem has been initialized */ | ||
280 | if ( ! CheckInit(1, &cdrom) ) { | ||
281 | return(CD_ERROR); | ||
282 | } | ||
283 | |||
284 | status = SDL_CDcaps.Status(cdrom, NULL); | ||
285 | switch (status) { | ||
286 | case CD_PAUSED: | ||
287 | retval = SDL_CDcaps.Resume(cdrom); | ||
288 | default: | ||
289 | retval = 0; | ||
290 | break; | ||
291 | } | ||
292 | return(retval); | ||
293 | } | ||
294 | |||
295 | int SDL_CDStop(SDL_CD *cdrom) | ||
296 | { | ||
297 | CDstatus status; | ||
298 | int retval; | ||
299 | |||
300 | /* Check if the CD-ROM subsystem has been initialized */ | ||
301 | if ( ! CheckInit(1, &cdrom) ) { | ||
302 | return(CD_ERROR); | ||
303 | } | ||
304 | |||
305 | status = SDL_CDcaps.Status(cdrom, NULL); | ||
306 | switch (status) { | ||
307 | case CD_PLAYING: | ||
308 | case CD_PAUSED: | ||
309 | retval = SDL_CDcaps.Stop(cdrom); | ||
310 | default: | ||
311 | retval = 0; | ||
312 | break; | ||
313 | } | ||
314 | return(retval); | ||
315 | } | ||
316 | |||
317 | int SDL_CDEject(SDL_CD *cdrom) | ||
318 | { | ||
319 | /* Check if the CD-ROM subsystem has been initialized */ | ||
320 | if ( ! CheckInit(1, &cdrom) ) { | ||
321 | return(CD_ERROR); | ||
322 | } | ||
323 | return(SDL_CDcaps.Eject(cdrom)); | ||
324 | } | ||
325 | |||
326 | void SDL_CDClose(SDL_CD *cdrom) | ||
327 | { | ||
328 | /* Check if the CD-ROM subsystem has been initialized */ | ||
329 | if ( ! CheckInit(1, &cdrom) ) { | ||
330 | return; | ||
331 | } | ||
332 | SDL_CDcaps.Close(cdrom); | ||
333 | SDL_free(cdrom); | ||
334 | default_cdrom = NULL; | ||
335 | } | ||
336 | |||
337 | void SDL_CDROMQuit(void) | ||
338 | { | ||
339 | SDL_SYS_CDQuit(); | ||
340 | SDL_cdinitted = 0; | ||
341 | } | ||
diff --git a/apps/plugins/sdl/src/cdrom/SDL_syscdrom.h b/apps/plugins/sdl/src/cdrom/SDL_syscdrom.h new file mode 100644 index 0000000000..0feeee5b4d --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/SDL_syscdrom.h | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is SDL_free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* This is the system specific header for the SDL CD-ROM API */ | ||
25 | |||
26 | /* Structure of CD audio control functions */ | ||
27 | extern struct CDcaps { | ||
28 | /* Get the name of the specified drive */ | ||
29 | const char *(*Name)(int drive); | ||
30 | |||
31 | /* Open the specified drive, returning a drive id, or -1 on error */ | ||
32 | int (*Open)(int drive); | ||
33 | |||
34 | /* Get table-of-contents (number of tracks + track info) for disk. | ||
35 | The TOC information should be stored in the cdrom structure. | ||
36 | This function should return 0 on success, or -1 on error. | ||
37 | */ | ||
38 | int (*GetTOC)(SDL_CD *cdrom); | ||
39 | |||
40 | /* Return the current status and play position, in frames, of the | ||
41 | drive. 'position' may be NULL, and if so, should be ignored. | ||
42 | */ | ||
43 | CDstatus (*Status)(SDL_CD *cdrom, int *position); | ||
44 | |||
45 | /* Play from frame 'start' to 'start+len' */ | ||
46 | int (*Play)(SDL_CD *cdrom, int start, int len); | ||
47 | |||
48 | /* Pause play */ | ||
49 | int (*Pause)(SDL_CD *cdrom); | ||
50 | |||
51 | /* Resume play */ | ||
52 | int (*Resume)(SDL_CD *cdrom); | ||
53 | |||
54 | /* Stop play */ | ||
55 | int (*Stop)(SDL_CD *cdrom); | ||
56 | |||
57 | /* Eject the current disk */ | ||
58 | int (*Eject)(SDL_CD *cdrom); | ||
59 | |||
60 | /* Close the specified drive */ | ||
61 | void (*Close)(SDL_CD *cdrom); | ||
62 | } SDL_CDcaps; | ||
63 | |||
64 | /* The number of available CD-ROM drives on the system */ | ||
65 | extern int SDL_numcds; | ||
66 | |||
67 | /* Function to scan the system for CD-ROM drives and fill SDL_CDcaps. | ||
68 | * This function should set SDL_numcds to the number of available CD | ||
69 | * drives. Drive 0 should be the system default CD-ROM. | ||
70 | * It should return 0, or -1 on an unrecoverable fatal error. | ||
71 | */ | ||
72 | extern int SDL_SYS_CDInit(void); | ||
73 | |||
74 | /* Function to perform any system-specific CD-ROM related cleanup */ | ||
75 | extern void SDL_SYS_CDQuit(void); | ||
76 | |||
diff --git a/apps/plugins/sdl/src/cdrom/aix/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/aix/SDL_syscdrom.c new file mode 100644 index 0000000000..e7e05585e3 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/aix/SDL_syscdrom.c | |||
@@ -0,0 +1,660 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Carsten Griwodz | ||
20 | griff@kom.tu-darmstadt.de | ||
21 | |||
22 | based on linux/SDL_syscdrom.c by Sam Lantinga | ||
23 | */ | ||
24 | #include "SDL_config.h" | ||
25 | |||
26 | #ifdef SDL_CDROM_AIX | ||
27 | |||
28 | /* Functions for system-level CD-ROM audio control */ | ||
29 | |||
30 | /*#define DEBUG_CDROM 1*/ | ||
31 | |||
32 | #include <sys/types.h> | ||
33 | #include <sys/stat.h> | ||
34 | #include <fcntl.h> | ||
35 | #include <errno.h> | ||
36 | #include <unistd.h> | ||
37 | |||
38 | #include <sys/ioctl.h> | ||
39 | #include <sys/devinfo.h> | ||
40 | #include <sys/mntctl.h> | ||
41 | #include <sys/statfs.h> | ||
42 | #include <sys/vmount.h> | ||
43 | #include <fstab.h> | ||
44 | #include <sys/scdisk.h> | ||
45 | |||
46 | #include "SDL_cdrom.h" | ||
47 | #include "../SDL_syscdrom.h" | ||
48 | |||
49 | /* The maximum number of CD-ROM drives we'll detect */ | ||
50 | #define MAX_DRIVES 16 | ||
51 | |||
52 | /* A list of available CD-ROM drives */ | ||
53 | static char *SDL_cdlist[MAX_DRIVES]; | ||
54 | static dev_t SDL_cdmode[MAX_DRIVES]; | ||
55 | |||
56 | /* The system-dependent CD control functions */ | ||
57 | static const char *SDL_SYS_CDName(int drive); | ||
58 | static int SDL_SYS_CDOpen(int drive); | ||
59 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
60 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
61 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
62 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
63 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
64 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
65 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
66 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
67 | static int SDL_SYS_CDioctl(int id, int command, void *arg); | ||
68 | |||
69 | /* Check a drive to see if it is a CD-ROM */ | ||
70 | static int CheckDrive(char *drive, struct stat *stbuf) | ||
71 | { | ||
72 | int is_cd; | ||
73 | int cdfd; | ||
74 | int ret; | ||
75 | struct devinfo info; | ||
76 | |||
77 | /* If it doesn't exist, return -1 */ | ||
78 | if ( stat(drive, stbuf) < 0 ) { | ||
79 | return -1; | ||
80 | } | ||
81 | |||
82 | /* If it does exist, verify that it's an available CD-ROM */ | ||
83 | is_cd = 0; | ||
84 | if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) { | ||
85 | cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); | ||
86 | if ( cdfd >= 0 ) { | ||
87 | ret = SDL_SYS_CDioctl( cdfd, IOCINFO, &info ); | ||
88 | if ( ret < 0 ) { | ||
89 | /* Some kind of error */ | ||
90 | is_cd = 0; | ||
91 | } else { | ||
92 | if ( info.devtype == DD_CDROM ) { | ||
93 | is_cd = 1; | ||
94 | } else { | ||
95 | is_cd = 0; | ||
96 | } | ||
97 | } | ||
98 | close(cdfd); | ||
99 | } | ||
100 | #ifdef DEBUG_CDROM | ||
101 | else | ||
102 | { | ||
103 | fprintf(stderr, "Could not open drive %s (%s)\n", drive, strerror(errno)); | ||
104 | } | ||
105 | #endif | ||
106 | } | ||
107 | return is_cd; | ||
108 | } | ||
109 | |||
110 | /* Add a CD-ROM drive to our list of valid drives */ | ||
111 | static void AddDrive(char *drive, struct stat *stbuf) | ||
112 | { | ||
113 | int i; | ||
114 | |||
115 | if ( SDL_numcds < MAX_DRIVES ) { | ||
116 | /* Check to make sure it's not already in our list. | ||
117 | This can happen when we see a drive via symbolic link. | ||
118 | */ | ||
119 | for ( i=0; i<SDL_numcds; ++i ) { | ||
120 | if ( stbuf->st_rdev == SDL_cdmode[i] ) { | ||
121 | #ifdef DEBUG_CDROM | ||
122 | fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | ||
123 | #endif | ||
124 | return; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /* Add this drive to our list */ | ||
129 | i = SDL_numcds; | ||
130 | SDL_cdlist[i] = SDL_strdup(drive); | ||
131 | if ( SDL_cdlist[i] == NULL ) { | ||
132 | SDL_OutOfMemory(); | ||
133 | return; | ||
134 | } | ||
135 | SDL_cdmode[i] = stbuf->st_rdev; | ||
136 | ++SDL_numcds; | ||
137 | #ifdef DEBUG_CDROM | ||
138 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
139 | #endif | ||
140 | } | ||
141 | } | ||
142 | |||
143 | static void CheckMounts() | ||
144 | { | ||
145 | char* buffer; | ||
146 | int bufsz; | ||
147 | struct vmount* ptr; | ||
148 | int ret; | ||
149 | |||
150 | buffer = (char*)SDL_malloc(10); | ||
151 | bufsz = 10; | ||
152 | if ( buffer==NULL ) | ||
153 | { | ||
154 | fprintf(stderr, "Could not allocate 10 bytes in aix/SDL_syscdrom.c:CheckMounts\n" ); | ||
155 | exit ( -10 ); | ||
156 | } | ||
157 | |||
158 | do | ||
159 | { | ||
160 | /* mntctrl() returns an array of all mounted filesystems */ | ||
161 | ret = mntctl ( MCTL_QUERY, bufsz, buffer ); | ||
162 | if ( ret == 0 ) | ||
163 | { | ||
164 | /* Buffer was too small, realloc. */ | ||
165 | bufsz = *(int*)buffer; /* Required size is in first word. */ | ||
166 | /* (whatever a word is in AIX 4.3.3) */ | ||
167 | /* int seems to be OK in 32bit mode. */ | ||
168 | SDL_free(buffer); | ||
169 | buffer = (char*)SDL_malloc(bufsz); | ||
170 | if ( buffer==NULL ) | ||
171 | { | ||
172 | fprintf(stderr, | ||
173 | "Could not allocate %d bytes in aix/SDL_syscdrom.c:CheckMounts\n", | ||
174 | bufsz ); | ||
175 | exit ( -10 ); | ||
176 | } | ||
177 | } | ||
178 | else if ( ret < 0 ) | ||
179 | { | ||
180 | #ifdef DEBUG_CDROM | ||
181 | fprintf(stderr, "Error reading vmount structures\n"); | ||
182 | #endif | ||
183 | return; | ||
184 | } | ||
185 | } | ||
186 | while ( ret == 0 ); | ||
187 | |||
188 | #ifdef DEBUG_CDROM | ||
189 | fprintf ( stderr, "Read %d vmount structures\n",ret ); | ||
190 | #endif | ||
191 | ptr = (struct vmount*)buffer; | ||
192 | do | ||
193 | { | ||
194 | switch(ptr->vmt_gfstype) | ||
195 | { | ||
196 | case MNT_CDROM : | ||
197 | { | ||
198 | struct stat stbuf; | ||
199 | char* text; | ||
200 | |||
201 | text = (char*)ptr + ptr->vmt_data[VMT_OBJECT].vmt_off; | ||
202 | #ifdef DEBUG_CDROM | ||
203 | fprintf(stderr, "Checking mount path: %s mounted on %s\n", | ||
204 | text, (char*)ptr + ptr->vmt_data[VMT_STUB].vmt_off ); | ||
205 | #endif | ||
206 | if ( CheckDrive( text, &stbuf) > 0) | ||
207 | { | ||
208 | AddDrive( text, &stbuf); | ||
209 | } | ||
210 | } | ||
211 | break; | ||
212 | default : | ||
213 | break; | ||
214 | } | ||
215 | ptr = (struct vmount*)((char*)ptr + ptr->vmt_length); | ||
216 | ret--; | ||
217 | } | ||
218 | while ( ret > 0 ); | ||
219 | |||
220 | free ( buffer ); | ||
221 | } | ||
222 | |||
223 | static int CheckNonmounts() | ||
224 | { | ||
225 | #ifdef _THREAD_SAFE | ||
226 | AFILE_t fsFile = NULL; | ||
227 | int passNo = 0; | ||
228 | int ret; | ||
229 | struct fstab entry; | ||
230 | struct stat stbuf; | ||
231 | |||
232 | ret = setfsent_r( &fsFile, &passNo ); | ||
233 | if ( ret != 0 ) return -1; | ||
234 | do | ||
235 | { | ||
236 | ret = getfsent_r ( &entry, &fsFile, &passNo ); | ||
237 | if ( ret == 0 ) { | ||
238 | char* l = SDL_strrchr(entry.fs_spec,'/'); | ||
239 | if ( l != NULL ) { | ||
240 | if ( !SDL_strncmp("cd",++l,2) ) { | ||
241 | #ifdef DEBUG_CDROM | ||
242 | fprintf(stderr, | ||
243 | "Found unmounted CD ROM drive with device name %s\n", | ||
244 | entry.fs_spec); | ||
245 | #endif | ||
246 | if ( CheckDrive( entry.fs_spec, &stbuf) > 0) | ||
247 | { | ||
248 | AddDrive( entry.fs_spec, &stbuf); | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | while ( ret == 0 ); | ||
255 | ret = endfsent_r ( &fsFile ); | ||
256 | if ( ret != 0 ) return -1; | ||
257 | return 0; | ||
258 | #else | ||
259 | struct fstab* entry; | ||
260 | struct stat stbuf; | ||
261 | |||
262 | setfsent(); | ||
263 | do | ||
264 | { | ||
265 | entry = getfsent(); | ||
266 | if ( entry != NULL ) { | ||
267 | char* l = SDL_strrchr(entry->fs_spec,'/'); | ||
268 | if ( l != NULL ) { | ||
269 | if ( !SDL_strncmp("cd",++l,2) ) { | ||
270 | #ifdef DEBUG_CDROM | ||
271 | fprintf(stderr,"Found unmounted CD ROM drive with device name %s", entry->fs_spec); | ||
272 | #endif | ||
273 | if ( CheckDrive( entry->fs_spec, &stbuf) > 0) | ||
274 | { | ||
275 | AddDrive( entry->fs_spec, &stbuf); | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | while ( entry != NULL ); | ||
282 | endfsent(); | ||
283 | #endif | ||
284 | } | ||
285 | |||
286 | int SDL_SYS_CDInit(void) | ||
287 | { | ||
288 | char *SDLcdrom; | ||
289 | struct stat stbuf; | ||
290 | |||
291 | /* Fill in our driver capabilities */ | ||
292 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
293 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
294 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
295 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
296 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
297 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
298 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
299 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
300 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
301 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
302 | |||
303 | /* Look in the environment for our CD-ROM drive list */ | ||
304 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
305 | if ( SDLcdrom != NULL ) { | ||
306 | char *cdpath, *delim; | ||
307 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
308 | cdpath = SDL_stack_alloc(char, len); | ||
309 | if ( cdpath != NULL ) { | ||
310 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
311 | SDLcdrom = cdpath; | ||
312 | do { | ||
313 | delim = SDL_strchr(SDLcdrom, ':'); | ||
314 | if ( delim ) { | ||
315 | *delim++ = '\0'; | ||
316 | } | ||
317 | #ifdef DEBUG_CDROM | ||
318 | fprintf(stderr, "Checking CD-ROM drive from SDL_CDROM: %s\n", SDLcdrom); | ||
319 | #endif | ||
320 | if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | ||
321 | AddDrive(SDLcdrom, &stbuf); | ||
322 | } | ||
323 | if ( delim ) { | ||
324 | SDLcdrom = delim; | ||
325 | } else { | ||
326 | SDLcdrom = NULL; | ||
327 | } | ||
328 | } while ( SDLcdrom ); | ||
329 | SDL_stack_free(cdpath); | ||
330 | } | ||
331 | |||
332 | /* If we found our drives, there's nothing left to do */ | ||
333 | if ( SDL_numcds > 0 ) { | ||
334 | return(0); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | CheckMounts(); | ||
339 | CheckNonmounts(); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | /* General ioctl() CD-ROM command function */ | ||
345 | static int SDL_SYS_CDioctl(int id, int command, void *arg) | ||
346 | { | ||
347 | int retval; | ||
348 | |||
349 | retval = ioctl(id, command, arg); | ||
350 | if ( retval < 0 ) { | ||
351 | SDL_SetError("ioctl() error: %s", strerror(errno)); | ||
352 | } | ||
353 | return retval; | ||
354 | } | ||
355 | |||
356 | static const char *SDL_SYS_CDName(int drive) | ||
357 | { | ||
358 | return(SDL_cdlist[drive]); | ||
359 | } | ||
360 | |||
361 | static int SDL_SYS_CDOpen(int drive) | ||
362 | { | ||
363 | int fd; | ||
364 | char* lastsl; | ||
365 | char* cdromname; | ||
366 | size_t len; | ||
367 | |||
368 | /* | ||
369 | * We found /dev/cd? drives and that is in our list. But we can | ||
370 | * open only the /dev/rcd? versions of those devices for Audio CD. | ||
371 | */ | ||
372 | len = SDL_strlen(SDL_cdlist[drive])+2; | ||
373 | cdromname = (char*)SDL_malloc(len); | ||
374 | SDL_strlcpy(cdromname,SDL_cdlist[drive],len); | ||
375 | lastsl = SDL_strrchr(cdromname,'/'); | ||
376 | if (lastsl) { | ||
377 | *lastsl = 0; | ||
378 | SDL_strlcat(cdromname,"/r",len); | ||
379 | lastsl = SDL_strrchr(SDL_cdlist[drive],'/'); | ||
380 | if (lastsl) { | ||
381 | lastsl++; | ||
382 | SDL_strlcat(cdromname,lastsl,len); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | #ifdef DEBUG_CDROM | ||
387 | fprintf(stderr, "Should open drive %s, opening %s\n", SDL_cdlist[drive], cdromname); | ||
388 | #endif | ||
389 | |||
390 | /* | ||
391 | * Use exclusive access. Don't use SC_DIAGNOSTICS as xmcd does because they | ||
392 | * require root priviledges, and we don't want that. SC_SINGLE provides | ||
393 | * exclusive access with less trouble. | ||
394 | */ | ||
395 | fd = openx(cdromname, O_RDONLY, NULL, SC_SINGLE); | ||
396 | if ( fd < 0 ) | ||
397 | { | ||
398 | #ifdef DEBUG_CDROM | ||
399 | fprintf(stderr, "Could not open drive %s (%s)\n", cdromname, strerror(errno)); | ||
400 | #endif | ||
401 | } | ||
402 | else | ||
403 | { | ||
404 | struct mode_form_op cdMode; | ||
405 | int ret; | ||
406 | #ifdef DEBUG_CDROM | ||
407 | cdMode.action = CD_GET_MODE; | ||
408 | ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode); | ||
409 | if ( ret < 0 ) { | ||
410 | fprintf(stderr, | ||
411 | "Could not get drive mode for %s (%s)\n", | ||
412 | cdromname, strerror(errno)); | ||
413 | } else { | ||
414 | switch(cdMode.cd_mode_form) { | ||
415 | case CD_MODE1 : | ||
416 | fprintf(stderr, | ||
417 | "Drive mode for %s is %s\n", | ||
418 | cdromname, "CD-ROM Data Mode 1"); | ||
419 | break; | ||
420 | case CD_MODE2_FORM1 : | ||
421 | fprintf(stderr, | ||
422 | "Drive mode for %s is %s\n", | ||
423 | cdromname, "CD-ROM XA Data Mode 2 Form 1"); | ||
424 | break; | ||
425 | case CD_MODE2_FORM2 : | ||
426 | fprintf(stderr, | ||
427 | "Drive mode for %s is %s\n", | ||
428 | cdromname, "CD-ROM XA Data Mode 2 Form 2"); | ||
429 | break; | ||
430 | case CD_DA : | ||
431 | fprintf(stderr, | ||
432 | "Drive mode for %s is %s\n", | ||
433 | cdromname, "CD-DA"); | ||
434 | break; | ||
435 | default : | ||
436 | fprintf(stderr, | ||
437 | "Drive mode for %s is %s\n", | ||
438 | cdromname, "unknown"); | ||
439 | break; | ||
440 | } | ||
441 | } | ||
442 | #endif | ||
443 | |||
444 | cdMode.action = CD_CHG_MODE; | ||
445 | cdMode.cd_mode_form = CD_DA; | ||
446 | ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode); | ||
447 | if ( ret < 0 ) { | ||
448 | #ifdef DEBUG_CDROM | ||
449 | fprintf(stderr, | ||
450 | "Could not set drive mode for %s (%s)\n", | ||
451 | cdromname, strerror(errno)); | ||
452 | #endif | ||
453 | SDL_SetError("ioctl() error: Could not set CD drive mode, %s", | ||
454 | strerror(errno)); | ||
455 | } else { | ||
456 | #ifdef DEBUG_CDROM | ||
457 | fprintf(stderr, | ||
458 | "Drive mode for %s set to CD_DA\n", | ||
459 | cdromname); | ||
460 | #endif | ||
461 | } | ||
462 | } | ||
463 | SDL_free(cdromname); | ||
464 | return fd; | ||
465 | } | ||
466 | |||
467 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
468 | { | ||
469 | struct cd_audio_cmd cmd; | ||
470 | struct cd_audio_cmd entry; | ||
471 | int i; | ||
472 | int okay; | ||
473 | |||
474 | cmd.audio_cmds = CD_TRK_INFO_AUDIO; | ||
475 | cmd.msf_flag = FALSE; | ||
476 | if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0 ) { | ||
477 | return -1; | ||
478 | } | ||
479 | |||
480 | okay = 0; | ||
481 | cdrom->numtracks = cmd.indexing.track_index.last_track | ||
482 | - cmd.indexing.track_index.first_track+1; | ||
483 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
484 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
485 | } | ||
486 | |||
487 | /* Read all the track TOC entries */ | ||
488 | for ( i=0; i<=cdrom->numtracks; ++i ) { | ||
489 | if ( i == cdrom->numtracks ) { | ||
490 | cdrom->track[i].id = 0xAA;; | ||
491 | } else { | ||
492 | cdrom->track[i].id = cmd.indexing.track_index.first_track+i; | ||
493 | } | ||
494 | entry.audio_cmds = CD_GET_TRK_MSF; | ||
495 | entry.indexing.track_msf.track = cdrom->track[i].id; | ||
496 | if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &entry) < 0 ) { | ||
497 | break; | ||
498 | } else { | ||
499 | cdrom->track[i].type = 0; /* don't know how to detect 0x04 data track */ | ||
500 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
501 | entry.indexing.track_msf.mins, | ||
502 | entry.indexing.track_msf.secs, | ||
503 | entry.indexing.track_msf.frames); | ||
504 | cdrom->track[i].length = 0; | ||
505 | if ( i > 0 ) { | ||
506 | cdrom->track[i-1].length = cdrom->track[i].offset | ||
507 | - cdrom->track[i-1].offset; | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | if ( i == (cdrom->numtracks+1) ) { | ||
512 | okay = 1; | ||
513 | } | ||
514 | return(okay ? 0 : -1); | ||
515 | } | ||
516 | |||
517 | /* Get CD-ROM status */ | ||
518 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
519 | { | ||
520 | CDstatus status; | ||
521 | struct cd_audio_cmd cmd; | ||
522 | cmd.audio_cmds = CD_INFO_AUDIO; | ||
523 | |||
524 | if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0 ) { | ||
525 | #ifdef DEBUG_CDROM | ||
526 | fprintf(stderr, "ioctl failed in SDL_SYS_CDStatus (%s)\n", SDL_GetError()); | ||
527 | #endif | ||
528 | status = CD_ERROR; | ||
529 | } else { | ||
530 | switch (cmd.status) { | ||
531 | case CD_NO_AUDIO: | ||
532 | case CD_COMPLETED: | ||
533 | status = CD_STOPPED; | ||
534 | break; | ||
535 | case CD_PLAY_AUDIO: | ||
536 | status = CD_PLAYING; | ||
537 | break; | ||
538 | case CD_PAUSE_AUDIO: | ||
539 | status = CD_PAUSED; | ||
540 | break; | ||
541 | case CD_NOT_VALID: | ||
542 | #ifdef DEBUG_CDROM | ||
543 | fprintf(stderr, "cdStatus failed with CD_NOT_VALID\n"); | ||
544 | #endif | ||
545 | status = CD_ERROR; | ||
546 | break; | ||
547 | case CD_STATUS_ERROR: | ||
548 | #ifdef DEBUG_CDROM | ||
549 | fprintf(stderr, "cdStatus failed with CD_STATUS_ERROR\n"); | ||
550 | #endif | ||
551 | status = CD_ERROR; | ||
552 | break; | ||
553 | default: | ||
554 | #ifdef DEBUG_CDROM | ||
555 | fprintf(stderr, "cdStatus failed with unknown error\n"); | ||
556 | #endif | ||
557 | status = CD_ERROR; | ||
558 | break; | ||
559 | } | ||
560 | } | ||
561 | if ( position ) { | ||
562 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | ||
563 | *position = MSF_TO_FRAMES( cmd.indexing.info_audio.current_mins, | ||
564 | cmd.indexing.info_audio.current_secs, | ||
565 | cmd.indexing.info_audio.current_frames); | ||
566 | } else { | ||
567 | *position = 0; | ||
568 | } | ||
569 | } | ||
570 | return status; | ||
571 | } | ||
572 | |||
573 | /* Start play */ | ||
574 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
575 | { | ||
576 | struct cd_audio_cmd cmd; | ||
577 | |||
578 | /* | ||
579 | * My CD Rom is muted by default. I think I read that this is new with | ||
580 | * AIX 4.3. SDL does not change the volume, so I need a kludge. Maybe | ||
581 | * its better to do this elsewhere? | ||
582 | */ | ||
583 | cmd.audio_cmds = CD_PLAY_AUDIO | CD_SET_VOLUME; | ||
584 | cmd.msf_flag = TRUE; | ||
585 | FRAMES_TO_MSF(start, | ||
586 | &cmd.indexing.msf.first_mins, | ||
587 | &cmd.indexing.msf.first_secs, | ||
588 | &cmd.indexing.msf.first_frames); | ||
589 | FRAMES_TO_MSF(start+length, | ||
590 | &cmd.indexing.msf.last_mins, | ||
591 | &cmd.indexing.msf.last_secs, | ||
592 | &cmd.indexing.msf.last_frames); | ||
593 | cmd.volume_type = CD_VOLUME_ALL; | ||
594 | cmd.all_channel_vol = 255; /* This is a uchar. What is a good value? No docu! */ | ||
595 | cmd.out_port_0_sel = CD_AUDIO_CHNL_0; | ||
596 | cmd.out_port_1_sel = CD_AUDIO_CHNL_1; | ||
597 | cmd.out_port_2_sel = CD_AUDIO_CHNL_2; | ||
598 | cmd.out_port_3_sel = CD_AUDIO_CHNL_3; | ||
599 | |||
600 | #ifdef DEBUG_CDROM | ||
601 | fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | ||
602 | cmd.indexing.msf.first_mins, | ||
603 | cmd.indexing.msf.first_secs, | ||
604 | cmd.indexing.msf.first_frames, | ||
605 | cmd.indexing.msf.last_mins, | ||
606 | cmd.indexing.msf.last_secs, | ||
607 | cmd.indexing.msf.last_frames); | ||
608 | #endif | ||
609 | return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd)); | ||
610 | } | ||
611 | |||
612 | /* Pause play */ | ||
613 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
614 | { | ||
615 | struct cd_audio_cmd cmd; | ||
616 | cmd.audio_cmds = CD_PAUSE_AUDIO; | ||
617 | return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd)); | ||
618 | } | ||
619 | |||
620 | /* Resume play */ | ||
621 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
622 | { | ||
623 | struct cd_audio_cmd cmd; | ||
624 | cmd.audio_cmds = CD_RESUME_AUDIO; | ||
625 | return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd)); | ||
626 | } | ||
627 | |||
628 | /* Stop play */ | ||
629 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
630 | { | ||
631 | struct cd_audio_cmd cmd; | ||
632 | cmd.audio_cmds = CD_STOP_AUDIO; | ||
633 | return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd)); | ||
634 | } | ||
635 | |||
636 | /* Eject the CD-ROM */ | ||
637 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
638 | { | ||
639 | return(SDL_SYS_CDioctl(cdrom->id, DKEJECT, 0)); | ||
640 | } | ||
641 | |||
642 | /* Close the CD-ROM handle */ | ||
643 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
644 | { | ||
645 | close(cdrom->id); | ||
646 | } | ||
647 | |||
648 | void SDL_SYS_CDQuit(void) | ||
649 | { | ||
650 | int i; | ||
651 | |||
652 | if ( SDL_numcds > 0 ) { | ||
653 | for ( i=0; i<SDL_numcds; ++i ) { | ||
654 | SDL_free(SDL_cdlist[i]); | ||
655 | } | ||
656 | SDL_numcds = 0; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | #endif /* SDL_CDROM_AIX */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/beos/SDL_syscdrom.cc b/apps/plugins/sdl/src/cdrom/beos/SDL_syscdrom.cc new file mode 100644 index 0000000000..9a62c38399 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/beos/SDL_syscdrom.cc | |||
@@ -0,0 +1,410 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_BEOS | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control on BeOS | ||
27 | (not completely implemented yet) | ||
28 | */ | ||
29 | |||
30 | #include <sys/types.h> | ||
31 | #include <sys/stat.h> | ||
32 | #include <unistd.h> | ||
33 | |||
34 | #include <scsi.h> | ||
35 | #include <Directory.h> | ||
36 | #include <Entry.h> | ||
37 | #include <Path.h> | ||
38 | |||
39 | #include "SDL_cdrom.h" | ||
40 | extern "C" { | ||
41 | #include "../SDL_syscdrom.h" | ||
42 | } | ||
43 | |||
44 | /* Constants to help us get at the SCSI table-of-contents info */ | ||
45 | #define CD_NUMTRACKS(toc) toc.toc_data[3] | ||
46 | #define CD_TRACK(toc, track) (&toc.toc_data[6+(track)*8]) | ||
47 | #define CD_TRACK_N(toc, track) CD_TRACK(toc, track)[0] | ||
48 | #define CD_TRACK_M(toc, track) CD_TRACK(toc, track)[3] | ||
49 | #define CD_TRACK_S(toc, track) CD_TRACK(toc, track)[4] | ||
50 | #define CD_TRACK_F(toc, track) CD_TRACK(toc, track)[5] | ||
51 | |||
52 | /* Constants to help us get at the SCSI position info */ | ||
53 | #define POS_TRACK(pos) pos.position[6] | ||
54 | #define POS_ABS_M(pos) pos.position[9] | ||
55 | #define POS_ABS_S(pos) pos.position[10] | ||
56 | #define POS_ABS_F(pos) pos.position[11] | ||
57 | #define POS_REL_M(pos) pos.position[13] | ||
58 | #define POS_REL_S(pos) pos.position[14] | ||
59 | #define POS_REL_F(pos) pos.position[15] | ||
60 | |||
61 | /* The maximum number of CD-ROM drives we'll detect */ | ||
62 | #define MAX_DRIVES 16 | ||
63 | |||
64 | /* A list of available CD-ROM drives */ | ||
65 | static char *SDL_cdlist[MAX_DRIVES]; | ||
66 | |||
67 | /* The system-dependent CD control functions */ | ||
68 | static const char *SDL_SYS_CDName(int drive); | ||
69 | static int SDL_SYS_CDOpen(int drive); | ||
70 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
71 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
72 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
73 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
74 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
75 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
76 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
77 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
78 | int try_dir(const char *directory); | ||
79 | |||
80 | |||
81 | /* Check a drive to see if it is a CD-ROM */ | ||
82 | static int CheckDrive(char *drive) | ||
83 | { | ||
84 | struct stat stbuf; | ||
85 | int is_cd, cdfd; | ||
86 | device_geometry info; | ||
87 | |||
88 | /* If it doesn't exist, return -1 */ | ||
89 | if ( stat(drive, &stbuf) < 0 ) { | ||
90 | return(-1); | ||
91 | } | ||
92 | |||
93 | /* If it does exist, verify that it's an available CD-ROM */ | ||
94 | is_cd = 0; | ||
95 | cdfd = open(drive, 0); | ||
96 | if ( cdfd >= 0 ) { | ||
97 | if ( ioctl(cdfd, B_GET_GEOMETRY, &info) == B_NO_ERROR ) { | ||
98 | if ( info.device_type == B_CD ) { | ||
99 | is_cd = 1; | ||
100 | } | ||
101 | } | ||
102 | close(cdfd); | ||
103 | } else { | ||
104 | /* This can happen when the drive is open .. (?) */; | ||
105 | is_cd = 1; | ||
106 | } | ||
107 | return(is_cd); | ||
108 | } | ||
109 | |||
110 | /* Add a CD-ROM drive to our list of valid drives */ | ||
111 | static void AddDrive(char *drive) | ||
112 | { | ||
113 | int i; | ||
114 | size_t len; | ||
115 | |||
116 | if ( SDL_numcds < MAX_DRIVES ) { | ||
117 | /* Add this drive to our list */ | ||
118 | i = SDL_numcds; | ||
119 | len = SDL_strlen(drive)+1; | ||
120 | SDL_cdlist[i] = (char *)SDL_malloc(len); | ||
121 | if ( SDL_cdlist[i] == NULL ) { | ||
122 | SDL_OutOfMemory(); | ||
123 | return; | ||
124 | } | ||
125 | SDL_strlcpy(SDL_cdlist[i], drive, len); | ||
126 | ++SDL_numcds; | ||
127 | #ifdef CDROM_DEBUG | ||
128 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
129 | #endif | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* IDE bus scanning magic */ | ||
134 | enum { | ||
135 | IDE_GET_DEVICES_INFO = B_DEVICE_OP_CODES_END + 50, | ||
136 | }; | ||
137 | struct ide_ctrl_info { | ||
138 | bool ide_0_present; | ||
139 | bool ide_0_master_present; | ||
140 | bool ide_0_slave_present; | ||
141 | int ide_0_master_type; | ||
142 | int ide_0_slave_type; | ||
143 | bool ide_1_present; | ||
144 | bool ide_1_master_present; | ||
145 | bool ide_1_slave_present; | ||
146 | int ide_1_master_type; | ||
147 | int ide_1_slave_type; | ||
148 | }; | ||
149 | |||
150 | int SDL_SYS_CDInit(void) | ||
151 | { | ||
152 | char *SDLcdrom; | ||
153 | |||
154 | /* Fill in our driver capabilities */ | ||
155 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
156 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
157 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
158 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
159 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
160 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
161 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
162 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
163 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
164 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
165 | |||
166 | /* Look in the environment for our CD-ROM drive list */ | ||
167 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
168 | if ( SDLcdrom != NULL ) { | ||
169 | char *cdpath, *delim; | ||
170 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
171 | cdpath = SDL_stack_alloc(char, len); | ||
172 | if ( cdpath != NULL ) { | ||
173 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
174 | SDLcdrom = cdpath; | ||
175 | do { | ||
176 | delim = SDL_strchr(SDLcdrom, ':'); | ||
177 | if ( delim ) { | ||
178 | *delim++ = '\0'; | ||
179 | } | ||
180 | if ( CheckDrive(SDLcdrom) > 0 ) { | ||
181 | AddDrive(SDLcdrom); | ||
182 | } | ||
183 | if ( delim ) { | ||
184 | SDLcdrom = delim; | ||
185 | } else { | ||
186 | SDLcdrom = NULL; | ||
187 | } | ||
188 | } while ( SDLcdrom ); | ||
189 | SDL_stack_free(cdpath); | ||
190 | } | ||
191 | |||
192 | /* If we found our drives, there's nothing left to do */ | ||
193 | if ( SDL_numcds > 0 ) { | ||
194 | return(0); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* Scan the system for CD-ROM drives */ | ||
199 | try_dir("/dev/disk"); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | |||
204 | int try_dir(const char *directory) | ||
205 | { | ||
206 | BDirectory dir; | ||
207 | dir.SetTo(directory); | ||
208 | if(dir.InitCheck() != B_NO_ERROR) { | ||
209 | return false; | ||
210 | } | ||
211 | dir.Rewind(); | ||
212 | BEntry entry; | ||
213 | while(dir.GetNextEntry(&entry) >= 0) { | ||
214 | BPath path; | ||
215 | const char *name; | ||
216 | entry_ref e; | ||
217 | |||
218 | if(entry.GetPath(&path) != B_NO_ERROR) | ||
219 | continue; | ||
220 | name = path.Path(); | ||
221 | |||
222 | if(entry.GetRef(&e) != B_NO_ERROR) | ||
223 | continue; | ||
224 | |||
225 | if(entry.IsDirectory()) { | ||
226 | if(SDL_strcmp(e.name, "floppy") == 0) | ||
227 | continue; /* ignore floppy (it is not silent) */ | ||
228 | int devfd = try_dir(name); | ||
229 | if(devfd >= 0) | ||
230 | return devfd; | ||
231 | } | ||
232 | else { | ||
233 | int devfd; | ||
234 | device_geometry g; | ||
235 | |||
236 | if(SDL_strcmp(e.name, "raw") != 0) | ||
237 | continue; /* ignore partitions */ | ||
238 | |||
239 | devfd = open(name, O_RDONLY); | ||
240 | if(devfd < 0) | ||
241 | continue; | ||
242 | |||
243 | if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) { | ||
244 | if(g.device_type == B_CD) | ||
245 | { | ||
246 | AddDrive(strdup(name)); | ||
247 | } | ||
248 | } | ||
249 | close(devfd); | ||
250 | } | ||
251 | } | ||
252 | return B_ERROR; | ||
253 | } | ||
254 | |||
255 | |||
256 | /* General ioctl() CD-ROM command function */ | ||
257 | static int SDL_SYS_CDioctl(int index, int command, void *arg) | ||
258 | { | ||
259 | int okay; | ||
260 | int fd; | ||
261 | |||
262 | okay = 0; | ||
263 | fd = open(SDL_cdlist[index], 0); | ||
264 | if ( fd >= 0 ) { | ||
265 | if ( ioctl(fd, command, arg) == B_NO_ERROR ) { | ||
266 | okay = 1; | ||
267 | } | ||
268 | close(fd); | ||
269 | } | ||
270 | return(okay ? 0 : -1); | ||
271 | } | ||
272 | |||
273 | static const char *SDL_SYS_CDName(int drive) | ||
274 | { | ||
275 | return(SDL_cdlist[drive]); | ||
276 | } | ||
277 | |||
278 | static int SDL_SYS_CDOpen(int drive) | ||
279 | { | ||
280 | return(drive); | ||
281 | } | ||
282 | |||
283 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
284 | { | ||
285 | int i; | ||
286 | scsi_toc toc; | ||
287 | |||
288 | if ( SDL_SYS_CDioctl(cdrom->id, B_SCSI_GET_TOC, &toc) == 0 ) { | ||
289 | cdrom->numtracks = CD_NUMTRACKS(toc); | ||
290 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
291 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
292 | } | ||
293 | for ( i=0; i<=cdrom->numtracks; ++i ) { | ||
294 | cdrom->track[i].id = CD_TRACK_N(toc, i); | ||
295 | /* FIXME: How do we tell on BeOS? */ | ||
296 | cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
297 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
298 | CD_TRACK_M(toc, i), | ||
299 | CD_TRACK_S(toc, i), | ||
300 | CD_TRACK_F(toc, i)); | ||
301 | cdrom->track[i].length = 0; | ||
302 | if ( i > 0 ) { | ||
303 | cdrom->track[i-1].length = | ||
304 | cdrom->track[i].offset- | ||
305 | cdrom->track[i-1].offset; | ||
306 | } | ||
307 | } | ||
308 | return(0); | ||
309 | } else { | ||
310 | return(-1); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | /* Get CD-ROM status */ | ||
315 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
316 | { | ||
317 | CDstatus status; | ||
318 | int fd; | ||
319 | int cur_frame; | ||
320 | scsi_position pos; | ||
321 | |||
322 | fd = open(SDL_cdlist[cdrom->id], 0); | ||
323 | cur_frame = 0; | ||
324 | if ( fd >= 0 ) { | ||
325 | if ( ioctl(fd, B_SCSI_GET_POSITION, &pos) == B_NO_ERROR ) { | ||
326 | cur_frame = MSF_TO_FRAMES( | ||
327 | POS_ABS_M(pos), POS_ABS_S(pos), POS_ABS_F(pos)); | ||
328 | } | ||
329 | if ( ! pos.position[1] || (pos.position[1] >= 0x13) || | ||
330 | ((pos.position[1] == 0x12) && (!pos.position[6])) ) { | ||
331 | status = CD_STOPPED; | ||
332 | } else | ||
333 | if ( pos.position[1] == 0x11 ) { | ||
334 | status = CD_PLAYING; | ||
335 | } else { | ||
336 | status = CD_PAUSED; | ||
337 | } | ||
338 | close(fd); | ||
339 | } else { | ||
340 | status = CD_TRAYEMPTY; | ||
341 | } | ||
342 | if ( position ) { | ||
343 | *position = cur_frame; | ||
344 | } | ||
345 | return(status); | ||
346 | } | ||
347 | |||
348 | /* Start play */ | ||
349 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
350 | { | ||
351 | int okay; | ||
352 | int fd; | ||
353 | scsi_play_position pos; | ||
354 | |||
355 | okay = 0; | ||
356 | fd = open(SDL_cdlist[cdrom->id], 0); | ||
357 | if ( fd >= 0 ) { | ||
358 | FRAMES_TO_MSF(start, &pos.start_m, &pos.start_s, &pos.start_f); | ||
359 | FRAMES_TO_MSF(start+length, &pos.end_m, &pos.end_s, &pos.end_f); | ||
360 | if ( ioctl(fd, B_SCSI_PLAY_POSITION, &pos) == B_NO_ERROR ) { | ||
361 | okay = 1; | ||
362 | } | ||
363 | close(fd); | ||
364 | } | ||
365 | return(okay ? 0 : -1); | ||
366 | } | ||
367 | |||
368 | /* Pause play */ | ||
369 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
370 | { | ||
371 | return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_PAUSE_AUDIO, 0)); | ||
372 | } | ||
373 | |||
374 | /* Resume play */ | ||
375 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
376 | { | ||
377 | return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_RESUME_AUDIO, 0)); | ||
378 | } | ||
379 | |||
380 | /* Stop play */ | ||
381 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
382 | { | ||
383 | return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_STOP_AUDIO, 0)); | ||
384 | } | ||
385 | |||
386 | /* Eject the CD-ROM */ | ||
387 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
388 | { | ||
389 | return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_EJECT, 0)); | ||
390 | } | ||
391 | |||
392 | /* Close the CD-ROM handle */ | ||
393 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
394 | { | ||
395 | close(cdrom->id); | ||
396 | } | ||
397 | |||
398 | void SDL_SYS_CDQuit(void) | ||
399 | { | ||
400 | int i; | ||
401 | |||
402 | if ( SDL_numcds > 0 ) { | ||
403 | for ( i=0; i<SDL_numcds; ++i ) { | ||
404 | SDL_free(SDL_cdlist[i]); | ||
405 | } | ||
406 | SDL_numcds = 0; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | #endif /* SDL_CDROM_BEOS */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/bsdi/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/bsdi/SDL_syscdrom.c new file mode 100644 index 0000000000..61edb819d2 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/bsdi/SDL_syscdrom.c | |||
@@ -0,0 +1,542 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_BSDI | ||
25 | |||
26 | /* | ||
27 | * Functions for system-level CD-ROM audio control for BSD/OS 4.x | ||
28 | * This started life out as a copy of the freebsd/SDL_cdrom.c file but was | ||
29 | * heavily modified. Works for standard (MMC) SCSI and ATAPI CDrom drives. | ||
30 | * | ||
31 | * Steven Schultz - sms@to.gd-es.com | ||
32 | */ | ||
33 | |||
34 | #include <sys/types.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include <fcntl.h> | ||
37 | #include <err.h> | ||
38 | #include <unistd.h> | ||
39 | #include <sys/ioctl.h> | ||
40 | #include </sys/dev/scsi/scsi.h> | ||
41 | #include </sys/dev/scsi/scsi_ioctl.h> | ||
42 | |||
43 | #include "SDL_cdrom.h" | ||
44 | #include "../SDL_syscdrom.h" | ||
45 | |||
46 | /* | ||
47 | * The msf_to_frame and frame_to_msf were yanked from libcdrom and inlined | ||
48 | * here so that -lcdrom doesn't have to be dragged in for something so simple. | ||
49 | */ | ||
50 | |||
51 | #define FRAMES_PER_SECOND 75 | ||
52 | #define FRAMES_PER_MINUTE (FRAMES_PER_SECOND * 60) | ||
53 | |||
54 | int | ||
55 | msf_to_frame(int minute, int second, int frame) | ||
56 | { | ||
57 | return(minute * FRAMES_PER_MINUTE + second * FRAMES_PER_SECOND + frame); | ||
58 | } | ||
59 | |||
60 | void | ||
61 | frame_to_msf(int frame, int *minp, int *secp, int *framep) | ||
62 | { | ||
63 | *minp = frame / FRAMES_PER_MINUTE; | ||
64 | *secp = (frame % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND; | ||
65 | *framep = frame % FRAMES_PER_SECOND; | ||
66 | } | ||
67 | |||
68 | /* The maximum number of CD-ROM drives we'll detect */ | ||
69 | #define MAX_DRIVES 16 | ||
70 | |||
71 | /* A list of available CD-ROM drives */ | ||
72 | static char *SDL_cdlist[MAX_DRIVES]; | ||
73 | static dev_t SDL_cdmode[MAX_DRIVES]; | ||
74 | |||
75 | /* The system-dependent CD control functions */ | ||
76 | static const char *SDL_SYS_CDName(int drive); | ||
77 | static int SDL_SYS_CDOpen(int drive); | ||
78 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
79 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
80 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
81 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
82 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
83 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
84 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
85 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
86 | |||
87 | typedef struct scsi_cdb cdb_t; | ||
88 | |||
89 | static int scsi_cmd(int fd, | ||
90 | struct scsi_cdb *cdb, | ||
91 | int cdblen, | ||
92 | int rw, | ||
93 | caddr_t data, | ||
94 | int datalen, | ||
95 | struct scsi_user_cdb *sus) | ||
96 | { | ||
97 | int scsistatus; | ||
98 | unsigned char *cp; | ||
99 | struct scsi_user_cdb suc; | ||
100 | |||
101 | /* safety checks */ | ||
102 | if (!cdb) return(-1); | ||
103 | if (rw != SUC_READ && rw != SUC_WRITE) return(-1); | ||
104 | |||
105 | suc.suc_flags = rw; | ||
106 | suc.suc_cdblen = cdblen; | ||
107 | bcopy(cdb, suc.suc_cdb, cdblen); | ||
108 | suc.suc_datalen = datalen; | ||
109 | suc.suc_data = data; | ||
110 | suc.suc_timeout = 10; /* 10 secs max for TUR or SENSE */ | ||
111 | if (ioctl(fd, SCSIRAWCDB, &suc) == -1) | ||
112 | return(-11); | ||
113 | scsistatus = suc.suc_sus.sus_status; | ||
114 | cp = suc.suc_sus.sus_sense; | ||
115 | |||
116 | /* | ||
117 | * If a place to copy the sense data back to has been provided then the | ||
118 | * caller is responsible for checking the errors and printing any information | ||
119 | * out if the status was not successful. | ||
120 | */ | ||
121 | if (scsistatus != 0 && !sus) | ||
122 | { | ||
123 | fprintf(stderr,"scsistatus = %x cmd = %x\n", | ||
124 | scsistatus, cdb[0]); | ||
125 | fprintf(stderr, "sense %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", | ||
126 | cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], | ||
127 | cp[6], cp[7], cp[8], cp[9], cp[10], cp[11], | ||
128 | cp[12], cp[13], cp[14], cp[15]); | ||
129 | return(1); | ||
130 | } | ||
131 | if (sus) | ||
132 | bcopy(&suc, sus, sizeof (struct scsi_user_cdb)); | ||
133 | if (scsistatus) | ||
134 | return(1); /* Return non-zero for unsuccessful status */ | ||
135 | return(0); | ||
136 | } | ||
137 | |||
138 | /* request vendor brand and model */ | ||
139 | unsigned char *Inquiry(int fd) | ||
140 | { | ||
141 | static struct scsi_cdb6 cdb = | ||
142 | { | ||
143 | 0x12, | ||
144 | 0, 0, 0, | ||
145 | 56, | ||
146 | 0 | ||
147 | }; | ||
148 | static unsigned char Inqbuffer[56]; | ||
149 | |||
150 | if (scsi_cmd(fd, (cdb_t *)&cdb, 6, SUC_READ, Inqbuffer, | ||
151 | sizeof(Inqbuffer), 0)) | ||
152 | return("\377"); | ||
153 | return(Inqbuffer); | ||
154 | } | ||
155 | |||
156 | #define ADD_SENSECODE 12 | ||
157 | #define ADD_SC_QUALIFIER 13 | ||
158 | |||
159 | int TestForMedium(int fd) | ||
160 | { | ||
161 | int sts, asc, ascq; | ||
162 | struct scsi_user_cdb sus; | ||
163 | static struct scsi_cdb6 cdb = | ||
164 | { | ||
165 | CMD_TEST_UNIT_READY, /* command */ | ||
166 | 0, /* reserved */ | ||
167 | 0, /* reserved */ | ||
168 | 0, /* reserved */ | ||
169 | 0, /* reserved */ | ||
170 | 0 /* reserved */ | ||
171 | }; | ||
172 | |||
173 | again: sts = scsi_cmd(fd, (cdb_t *)&cdb, 6, SUC_READ, 0, 0, &sus); | ||
174 | asc = sus.suc_sus.sus_sense[ADD_SENSECODE]; | ||
175 | ascq = sus.suc_sus.sus_sense[ADD_SC_QUALIFIER]; | ||
176 | if (asc == 0x3a && ascq == 0x0) /* no medium */ | ||
177 | return(0); | ||
178 | if (asc == 0x28 && ascq == 0x0) /* medium changed */ | ||
179 | goto again; | ||
180 | if (asc == 0x4 && ascq == 0x1 ) /* coming ready */ | ||
181 | { | ||
182 | sleep(2); | ||
183 | goto again; | ||
184 | } | ||
185 | return(1); | ||
186 | } | ||
187 | |||
188 | /* Check a drive to see if it is a CD-ROM */ | ||
189 | static int CheckDrive(char *drive, struct stat *stbuf) | ||
190 | { | ||
191 | int is_cd = 0, cdfd; | ||
192 | char *p; | ||
193 | |||
194 | /* If it doesn't exist, return -1 */ | ||
195 | if ( stat(drive, stbuf) < 0 ) { | ||
196 | return(-1); | ||
197 | } | ||
198 | |||
199 | /* If it does exist, verify that it's an available CD-ROM */ | ||
200 | cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); | ||
201 | if ( cdfd >= 0 ) { | ||
202 | p = Inquiry(cdfd); | ||
203 | if (*p == TYPE_ROM) | ||
204 | is_cd = 1; | ||
205 | close(cdfd); | ||
206 | } | ||
207 | return(is_cd); | ||
208 | } | ||
209 | |||
210 | /* Add a CD-ROM drive to our list of valid drives */ | ||
211 | static void AddDrive(char *drive, struct stat *stbuf) | ||
212 | { | ||
213 | int i; | ||
214 | |||
215 | if ( SDL_numcds < MAX_DRIVES ) { | ||
216 | /* Check to make sure it's not already in our list. | ||
217 | This can happen when we see a drive via symbolic link. | ||
218 | */ | ||
219 | for ( i=0; i<SDL_numcds; ++i ) { | ||
220 | if ( stbuf->st_rdev == SDL_cdmode[i] ) { | ||
221 | #ifdef DEBUG_CDROM | ||
222 | fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | ||
223 | #endif | ||
224 | return; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | /* Add this drive to our list */ | ||
229 | i = SDL_numcds; | ||
230 | SDL_cdlist[i] = SDL_strdup(drive); | ||
231 | if ( SDL_cdlist[i] == NULL ) { | ||
232 | SDL_OutOfMemory(); | ||
233 | return; | ||
234 | } | ||
235 | SDL_cdmode[i] = stbuf->st_rdev; | ||
236 | ++SDL_numcds; | ||
237 | #ifdef DEBUG_CDROM | ||
238 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
239 | #endif | ||
240 | } | ||
241 | } | ||
242 | |||
243 | int SDL_SYS_CDInit(void) | ||
244 | { | ||
245 | /* checklist: /dev/rsr?c */ | ||
246 | static char *checklist[] = { | ||
247 | "?0 rsr?", NULL | ||
248 | }; | ||
249 | char *SDLcdrom; | ||
250 | int i, j, exists; | ||
251 | char drive[32]; | ||
252 | struct stat stbuf; | ||
253 | |||
254 | /* Fill in our driver capabilities */ | ||
255 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
256 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
257 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
258 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
259 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
260 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
261 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
262 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
263 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
264 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
265 | |||
266 | /* Look in the environment for our CD-ROM drive list */ | ||
267 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
268 | if ( SDLcdrom != NULL ) { | ||
269 | char *cdpath, *delim; | ||
270 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
271 | cdpath = SDL_stack_alloc(char, len); | ||
272 | if ( cdpath != NULL ) { | ||
273 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
274 | SDLcdrom = cdpath; | ||
275 | do { | ||
276 | delim = SDL_strchr(SDLcdrom, ':'); | ||
277 | if ( delim ) { | ||
278 | *delim++ = '\0'; | ||
279 | } | ||
280 | if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | ||
281 | AddDrive(SDLcdrom, &stbuf); | ||
282 | } | ||
283 | if ( delim ) { | ||
284 | SDLcdrom = delim; | ||
285 | } else { | ||
286 | SDLcdrom = NULL; | ||
287 | } | ||
288 | } while ( SDLcdrom ); | ||
289 | SDL_stack_free(cdpath); | ||
290 | } | ||
291 | |||
292 | /* If we found our drives, there's nothing left to do */ | ||
293 | if ( SDL_numcds > 0 ) { | ||
294 | return(0); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | /* Scan the system for CD-ROM drives */ | ||
299 | for ( i=0; checklist[i]; ++i ) { | ||
300 | if ( checklist[i][0] == '?' ) { | ||
301 | char *insert; | ||
302 | exists = 1; | ||
303 | for ( j=checklist[i][1]; exists; ++j ) { | ||
304 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc", &checklist[i][3]); | ||
305 | insert = SDL_strchr(drive, '?'); | ||
306 | if ( insert != NULL ) { | ||
307 | *insert = j; | ||
308 | } | ||
309 | switch (CheckDrive(drive, &stbuf)) { | ||
310 | /* Drive exists and is a CD-ROM */ | ||
311 | case 1: | ||
312 | AddDrive(drive, &stbuf); | ||
313 | break; | ||
314 | /* Drive exists, but isn't a CD-ROM */ | ||
315 | case 0: | ||
316 | break; | ||
317 | /* Drive doesn't exist */ | ||
318 | case -1: | ||
319 | exists = 0; | ||
320 | break; | ||
321 | } | ||
322 | } | ||
323 | } else { | ||
324 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); | ||
325 | if ( CheckDrive(drive, &stbuf) > 0 ) { | ||
326 | AddDrive(drive, &stbuf); | ||
327 | } | ||
328 | } | ||
329 | } | ||
330 | return(0); | ||
331 | } | ||
332 | |||
333 | static const char *SDL_SYS_CDName(int drive) | ||
334 | { | ||
335 | return(SDL_cdlist[drive]); | ||
336 | } | ||
337 | |||
338 | static int SDL_SYS_CDOpen(int drive) | ||
339 | { | ||
340 | return(open(SDL_cdlist[drive], O_RDONLY | O_NONBLOCK | O_EXCL, 0)); | ||
341 | } | ||
342 | |||
343 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
344 | { | ||
345 | u_char cdb[10], buf[4], *p, *toc; | ||
346 | struct scsi_user_cdb sus; | ||
347 | int i, sts, first_track, last_track, ntracks, toc_size; | ||
348 | |||
349 | bzero(cdb, sizeof (cdb)); | ||
350 | cdb[0] = 0x43; /* Read TOC */ | ||
351 | cdb[1] = 0x2; /* MSF */ | ||
352 | cdb[8] = 4; /* size TOC header */ | ||
353 | sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, buf, 4, &sus); | ||
354 | if (sts < 0) | ||
355 | return(-1); | ||
356 | first_track = buf[2]; | ||
357 | last_track = buf[3]; | ||
358 | ntracks = last_track - first_track + 1; | ||
359 | cdrom->numtracks = ntracks; | ||
360 | toc_size = 4 + (ntracks + 1) * 8; | ||
361 | toc = (u_char *)SDL_malloc(toc_size); | ||
362 | if (toc == NULL) | ||
363 | return(-1); | ||
364 | bzero(cdb, sizeof (cdb)); | ||
365 | cdb[0] = 0x43; | ||
366 | cdb[1] = 0x2; | ||
367 | cdb[6] = first_track; | ||
368 | cdb[7] = toc_size >> 8; | ||
369 | cdb[8] = toc_size & 0xff; | ||
370 | sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, toc, toc_size, | ||
371 | &sus); | ||
372 | if (sts < 0) | ||
373 | { | ||
374 | SDL_free(toc); | ||
375 | return(-1); | ||
376 | } | ||
377 | |||
378 | for (i = 0, p = toc+4; i <= ntracks; i++, p+= 8) | ||
379 | { | ||
380 | if (i == ntracks) | ||
381 | cdrom->track[i].id = 0xAA; /* Leadout */ | ||
382 | else | ||
383 | cdrom->track[i].id = first_track + i; | ||
384 | if (p[1] & 0x20) | ||
385 | cdrom->track[i].type = SDL_DATA_TRACK; | ||
386 | else | ||
387 | cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
388 | cdrom->track[i].offset = msf_to_frame(p[5], p[6], p[7]); | ||
389 | cdrom->track[i].length = 0; | ||
390 | if (i > 0) | ||
391 | cdrom->track[i-1].length = cdrom->track[i].offset - | ||
392 | cdrom->track[i-1].offset; | ||
393 | } | ||
394 | SDL_free(toc); | ||
395 | return(0); | ||
396 | } | ||
397 | |||
398 | /* Get CD-ROM status */ | ||
399 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
400 | { | ||
401 | CDstatus status; | ||
402 | u_char cdb[10], buf[16]; | ||
403 | int sts; | ||
404 | struct scsi_user_cdb sus; | ||
405 | |||
406 | bzero(cdb, sizeof (cdb)); | ||
407 | cdb[0] = 0x42; /* read subq */ | ||
408 | cdb[1] = 0x2; /* MSF */ | ||
409 | cdb[2] = 0x40; /* q channel */ | ||
410 | cdb[3] = 1; /* current pos */ | ||
411 | cdb[7] = sizeof (buf) >> 8; | ||
412 | cdb[8] = sizeof (buf) & 0xff; | ||
413 | sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, buf, sizeof (buf), | ||
414 | &sus); | ||
415 | if (sts < 0) | ||
416 | return(-1); | ||
417 | if (sts) | ||
418 | { | ||
419 | if (TestForMedium(cdrom->id) == 0) | ||
420 | status = CD_TRAYEMPTY; | ||
421 | else | ||
422 | status = CD_ERROR; | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | switch (buf[1]) | ||
427 | { | ||
428 | case 0x11: | ||
429 | status = CD_PLAYING; | ||
430 | break; | ||
431 | case 0x12: | ||
432 | status = CD_PAUSED; | ||
433 | break; | ||
434 | case 0x13: | ||
435 | case 0x14: | ||
436 | case 0x15: | ||
437 | status = CD_STOPPED; | ||
438 | break; | ||
439 | default: | ||
440 | status = CD_ERROR; | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | if (position) | ||
445 | { | ||
446 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) | ||
447 | *position = msf_to_frame(buf[9], buf[10], buf[11]); | ||
448 | else | ||
449 | *position = 0; | ||
450 | } | ||
451 | return(status); | ||
452 | } | ||
453 | |||
454 | /* Start play */ | ||
455 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
456 | { | ||
457 | u_char cdb[10]; | ||
458 | int sts, minute, second, frame, eminute, esecond, eframe; | ||
459 | struct scsi_user_cdb sus; | ||
460 | |||
461 | bzero(cdb, sizeof(cdb)); | ||
462 | cdb[0] = 0x47; /* Play */ | ||
463 | frame_to_msf(start, &minute, &second, &frame); | ||
464 | frame_to_msf(start + length, &eminute, &esecond, &eframe); | ||
465 | cdb[3] = minute; | ||
466 | cdb[4] = second; | ||
467 | cdb[5] = frame; | ||
468 | cdb[6] = eminute; | ||
469 | cdb[7] = esecond; | ||
470 | cdb[8] = eframe; | ||
471 | sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, 0, 0, &sus); | ||
472 | return(sts); | ||
473 | } | ||
474 | |||
475 | static int | ||
476 | pauseresume(SDL_CD *cdrom, int flag) | ||
477 | { | ||
478 | u_char cdb[10]; | ||
479 | struct scsi_user_cdb sus; | ||
480 | |||
481 | bzero(cdb, sizeof (cdb)); | ||
482 | cdb[0] = 0x4b; | ||
483 | cdb[8] = flag & 0x1; | ||
484 | return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, 0, 0, &sus)); | ||
485 | } | ||
486 | |||
487 | /* Pause play */ | ||
488 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
489 | { | ||
490 | return(pauseresume(cdrom, 0)); | ||
491 | } | ||
492 | |||
493 | /* Resume play */ | ||
494 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
495 | { | ||
496 | return(pauseresume(cdrom, 1)); | ||
497 | } | ||
498 | |||
499 | /* Stop play */ | ||
500 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
501 | { | ||
502 | u_char cdb[6]; | ||
503 | struct scsi_user_cdb sus; | ||
504 | |||
505 | bzero(cdb, sizeof (cdb)); | ||
506 | cdb[0] = 0x1b; /* stop */ | ||
507 | cdb[1] = 1; /* immediate */ | ||
508 | return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 6, SUC_READ, 0, 0, &sus)); | ||
509 | } | ||
510 | |||
511 | /* Eject the CD-ROM */ | ||
512 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
513 | { | ||
514 | u_char cdb[6]; | ||
515 | struct scsi_user_cdb sus; | ||
516 | |||
517 | bzero(cdb, sizeof (cdb)); | ||
518 | cdb[0] = 0x1b; /* stop */ | ||
519 | cdb[1] = 1; /* immediate */ | ||
520 | cdb[4] = 2; /* eject */ | ||
521 | return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 6, SUC_READ, 0, 0, &sus)); | ||
522 | } | ||
523 | |||
524 | /* Close the CD-ROM handle */ | ||
525 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
526 | { | ||
527 | close(cdrom->id); | ||
528 | } | ||
529 | |||
530 | void SDL_SYS_CDQuit(void) | ||
531 | { | ||
532 | int i; | ||
533 | |||
534 | if ( SDL_numcds > 0 ) { | ||
535 | for ( i=0; i<SDL_numcds; ++i ) { | ||
536 | SDL_free(SDL_cdlist[i]); | ||
537 | } | ||
538 | } | ||
539 | SDL_numcds = 0; | ||
540 | } | ||
541 | |||
542 | #endif /* SDL_CDROM_BSDI */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/dc/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/dc/SDL_syscdrom.c new file mode 100644 index 0000000000..445ad7c25a --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/dc/SDL_syscdrom.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_DC | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #include <dc/cdrom.h> | ||
29 | #include <dc/spu.h> | ||
30 | |||
31 | #include "SDL_cdrom.h" | ||
32 | #include "../SDL_syscdrom.h" | ||
33 | |||
34 | /* The system-dependent CD control functions */ | ||
35 | static const char *SDL_SYS_CDName(int drive); | ||
36 | static int SDL_SYS_CDOpen(int drive); | ||
37 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
38 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
39 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
40 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
41 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
42 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
43 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
44 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
45 | |||
46 | |||
47 | int SDL_SYS_CDInit(void) | ||
48 | { | ||
49 | /* Fill in our driver capabilities */ | ||
50 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
51 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
52 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
53 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
54 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
55 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
56 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
57 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
58 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
59 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
60 | |||
61 | return(0); | ||
62 | } | ||
63 | |||
64 | static const char *SDL_SYS_CDName(int drive) | ||
65 | { | ||
66 | return "/cd"; | ||
67 | } | ||
68 | |||
69 | static int SDL_SYS_CDOpen(int drive) | ||
70 | { | ||
71 | return(drive); | ||
72 | } | ||
73 | |||
74 | #define TRACK_CDDA 0 | ||
75 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
76 | { | ||
77 | CDROM_TOC toc; | ||
78 | int ret,i; | ||
79 | |||
80 | ret = cdrom_read_toc(&toc,0); | ||
81 | if (ret!=ERR_OK) { | ||
82 | return -1; | ||
83 | } | ||
84 | |||
85 | cdrom->numtracks = TOC_TRACK(toc.last)-TOC_TRACK(toc.first)+1; | ||
86 | for(i=0;i<cdrom->numtracks;i++) { | ||
87 | unsigned long entry = toc.entry[i]; | ||
88 | cdrom->track[i].id = i+1; | ||
89 | cdrom->track[i].type = (TOC_CTRL(toc.entry[i])==TRACK_CDDA)?SDL_AUDIO_TRACK:SDL_DATA_TRACK; | ||
90 | cdrom->track[i].offset = TOC_LBA(entry)-150; | ||
91 | cdrom->track[i].length = TOC_LBA((i+1<toc.last)?toc.entry[i+1]:toc.leadout_sector)-TOC_LBA(entry); | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* Get CD-ROM status */ | ||
98 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
99 | { | ||
100 | int ret,dc_status,disc_type; | ||
101 | |||
102 | ret = cdrom_get_status(&dc_status,&disc_type); | ||
103 | if (ret!=ERR_OK) return CD_ERROR; | ||
104 | |||
105 | switch(dc_status) { | ||
106 | // case CD_STATUS_BUSY: | ||
107 | case CD_STATUS_PAUSED: | ||
108 | return CD_PAUSED; | ||
109 | case CD_STATUS_STANDBY: | ||
110 | return CD_STOPPED; | ||
111 | case CD_STATUS_PLAYING: | ||
112 | return CD_PLAYING; | ||
113 | // case CD_STATUS_SEEKING: | ||
114 | // case CD_STATUS_SCANING: | ||
115 | case CD_STATUS_OPEN: | ||
116 | case CD_STATUS_NO_DISC: | ||
117 | return CD_TRAYEMPTY; | ||
118 | default: | ||
119 | return CD_ERROR; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /* Start play */ | ||
124 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
125 | { | ||
126 | int ret = cdrom_cdda_play(start-150,start-150+length,1,CDDA_SECTORS); | ||
127 | return ret==ERR_OK?0:-1; | ||
128 | } | ||
129 | |||
130 | /* Pause play */ | ||
131 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
132 | { | ||
133 | int ret=cdrom_cdda_pause(); | ||
134 | return ret==ERR_OK?0:-1; | ||
135 | } | ||
136 | |||
137 | /* Resume play */ | ||
138 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
139 | { | ||
140 | int ret=cdrom_cdda_resume(); | ||
141 | return ret==ERR_OK?0:-1; | ||
142 | } | ||
143 | |||
144 | /* Stop play */ | ||
145 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
146 | { | ||
147 | int ret=cdrom_spin_down(); | ||
148 | return ret==ERR_OK?0:-1; | ||
149 | } | ||
150 | |||
151 | /* Eject the CD-ROM */ | ||
152 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
153 | { | ||
154 | return -1; | ||
155 | } | ||
156 | |||
157 | /* Close the CD-ROM handle */ | ||
158 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
159 | { | ||
160 | } | ||
161 | |||
162 | void SDL_SYS_CDQuit(void) | ||
163 | { | ||
164 | |||
165 | } | ||
166 | |||
167 | #endif /* SDL_CDROM_DC */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/dummy/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/dummy/SDL_syscdrom.c new file mode 100644 index 0000000000..9821e97958 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/dummy/SDL_syscdrom.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #if defined(SDL_CDROM_DUMMY) || defined(SDL_CDROM_DISABLED) | ||
25 | |||
26 | /* Stub functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #include "SDL_cdrom.h" | ||
29 | #include "../SDL_syscdrom.h" | ||
30 | |||
31 | int SDL_SYS_CDInit(void) | ||
32 | { | ||
33 | return(0); | ||
34 | } | ||
35 | |||
36 | void SDL_SYS_CDQuit(void) | ||
37 | { | ||
38 | return; | ||
39 | } | ||
40 | |||
41 | #endif /* SDL_CDROM_DUMMY || SDL_CDROM_DISABLED */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/freebsd/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/freebsd/SDL_syscdrom.c new file mode 100644 index 0000000000..0260c9489f --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/freebsd/SDL_syscdrom.c | |||
@@ -0,0 +1,406 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_FREEBSD | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #include <sys/types.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include <fcntl.h> | ||
31 | #include <errno.h> | ||
32 | #include <unistd.h> | ||
33 | #include <sys/cdio.h> | ||
34 | |||
35 | #include "SDL_cdrom.h" | ||
36 | #include "../SDL_syscdrom.h" | ||
37 | |||
38 | |||
39 | /* The maximum number of CD-ROM drives we'll detect */ | ||
40 | #define MAX_DRIVES 16 | ||
41 | |||
42 | /* A list of available CD-ROM drives */ | ||
43 | static char *SDL_cdlist[MAX_DRIVES]; | ||
44 | static dev_t SDL_cdmode[MAX_DRIVES]; | ||
45 | |||
46 | /* The system-dependent CD control functions */ | ||
47 | static const char *SDL_SYS_CDName(int drive); | ||
48 | static int SDL_SYS_CDOpen(int drive); | ||
49 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
50 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
51 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
52 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
53 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
54 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
55 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
56 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
57 | |||
58 | /* Some ioctl() errno values which occur when the tray is empty */ | ||
59 | #define ERRNO_TRAYEMPTY(errno) \ | ||
60 | ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL)) | ||
61 | |||
62 | /* Check a drive to see if it is a CD-ROM */ | ||
63 | static int CheckDrive(char *drive, struct stat *stbuf) | ||
64 | { | ||
65 | int is_cd, cdfd; | ||
66 | struct ioc_read_subchannel info; | ||
67 | |||
68 | /* If it doesn't exist, return -1 */ | ||
69 | if ( stat(drive, stbuf) < 0 ) { | ||
70 | return(-1); | ||
71 | } | ||
72 | |||
73 | /* If it does exist, verify that it's an available CD-ROM */ | ||
74 | is_cd = 0; | ||
75 | if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) { | ||
76 | cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); | ||
77 | if ( cdfd >= 0 ) { | ||
78 | info.address_format = CD_MSF_FORMAT; | ||
79 | info.data_format = CD_CURRENT_POSITION; | ||
80 | info.data_len = 0; | ||
81 | info.data = NULL; | ||
82 | /* Under Linux, EIO occurs when a disk is not present. | ||
83 | This isn't 100% reliable, so we use the USE_MNTENT | ||
84 | code above instead. | ||
85 | */ | ||
86 | if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) || | ||
87 | ERRNO_TRAYEMPTY(errno) ) { | ||
88 | is_cd = 1; | ||
89 | } | ||
90 | close(cdfd); | ||
91 | } | ||
92 | } | ||
93 | return(is_cd); | ||
94 | } | ||
95 | |||
96 | /* Add a CD-ROM drive to our list of valid drives */ | ||
97 | static void AddDrive(char *drive, struct stat *stbuf) | ||
98 | { | ||
99 | int i; | ||
100 | |||
101 | if ( SDL_numcds < MAX_DRIVES ) { | ||
102 | /* Check to make sure it's not already in our list. | ||
103 | This can happen when we see a drive via symbolic link. | ||
104 | */ | ||
105 | for ( i=0; i<SDL_numcds; ++i ) { | ||
106 | if ( stbuf->st_rdev == SDL_cdmode[i] ) { | ||
107 | #ifdef DEBUG_CDROM | ||
108 | fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | ||
109 | #endif | ||
110 | return; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | /* Add this drive to our list */ | ||
115 | i = SDL_numcds; | ||
116 | SDL_cdlist[i] = SDL_strdup(drive); | ||
117 | if ( SDL_cdlist[i] == NULL ) { | ||
118 | SDL_OutOfMemory(); | ||
119 | return; | ||
120 | } | ||
121 | SDL_cdmode[i] = stbuf->st_rdev; | ||
122 | ++SDL_numcds; | ||
123 | #ifdef DEBUG_CDROM | ||
124 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
125 | #endif | ||
126 | } | ||
127 | } | ||
128 | |||
129 | int SDL_SYS_CDInit(void) | ||
130 | { | ||
131 | /* checklist: /dev/cdrom,/dev/cd?c /dev/acd?c | ||
132 | /dev/matcd?c /dev/mcd?c /dev/scd?c */ | ||
133 | static char *checklist[] = { | ||
134 | "cdrom", "?0 cd?", "?0 acd?", "?0 matcd?", "?0 mcd?", "?0 scd?",NULL | ||
135 | }; | ||
136 | char *SDLcdrom; | ||
137 | int i, j, exists; | ||
138 | char drive[32]; | ||
139 | struct stat stbuf; | ||
140 | |||
141 | /* Fill in our driver capabilities */ | ||
142 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
143 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
144 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
145 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
146 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
147 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
148 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
149 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
150 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
151 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
152 | |||
153 | /* Look in the environment for our CD-ROM drive list */ | ||
154 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
155 | if ( SDLcdrom != NULL ) { | ||
156 | char *cdpath, *delim; | ||
157 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
158 | cdpath = SDL_stack_alloc(char, len); | ||
159 | if ( cdpath != NULL ) { | ||
160 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
161 | SDLcdrom = cdpath; | ||
162 | do { | ||
163 | delim = SDL_strchr(SDLcdrom, ':'); | ||
164 | if ( delim ) { | ||
165 | *delim++ = '\0'; | ||
166 | } | ||
167 | if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | ||
168 | AddDrive(SDLcdrom, &stbuf); | ||
169 | } | ||
170 | if ( delim ) { | ||
171 | SDLcdrom = delim; | ||
172 | } else { | ||
173 | SDLcdrom = NULL; | ||
174 | } | ||
175 | } while ( SDLcdrom ); | ||
176 | SDL_stack_free(cdpath); | ||
177 | } | ||
178 | |||
179 | /* If we found our drives, there's nothing left to do */ | ||
180 | if ( SDL_numcds > 0 ) { | ||
181 | return(0); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /* Scan the system for CD-ROM drives */ | ||
186 | for ( i=0; checklist[i]; ++i ) { | ||
187 | if ( checklist[i][0] == '?' ) { | ||
188 | char *insert; | ||
189 | exists = 1; | ||
190 | for ( j=checklist[i][1]; exists; ++j ) { | ||
191 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc", &checklist[i][3]); | ||
192 | insert = SDL_strchr(drive, '?'); | ||
193 | if ( insert != NULL ) { | ||
194 | *insert = j; | ||
195 | } | ||
196 | switch (CheckDrive(drive, &stbuf)) { | ||
197 | /* Drive exists and is a CD-ROM */ | ||
198 | case 1: | ||
199 | AddDrive(drive, &stbuf); | ||
200 | break; | ||
201 | /* Drive exists, but isn't a CD-ROM */ | ||
202 | case 0: | ||
203 | break; | ||
204 | /* Drive doesn't exist */ | ||
205 | case -1: | ||
206 | exists = 0; | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | } else { | ||
211 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); | ||
212 | if ( CheckDrive(drive, &stbuf) > 0 ) { | ||
213 | AddDrive(drive, &stbuf); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | return(0); | ||
218 | } | ||
219 | |||
220 | /* General ioctl() CD-ROM command function */ | ||
221 | static int SDL_SYS_CDioctl(int id, int command, void *arg) | ||
222 | { | ||
223 | int retval; | ||
224 | |||
225 | retval = ioctl(id, command, arg); | ||
226 | if ( retval < 0 ) { | ||
227 | SDL_SetError("ioctl() error: %s", strerror(errno)); | ||
228 | } | ||
229 | return(retval); | ||
230 | } | ||
231 | |||
232 | static const char *SDL_SYS_CDName(int drive) | ||
233 | { | ||
234 | return(SDL_cdlist[drive]); | ||
235 | } | ||
236 | |||
237 | static int SDL_SYS_CDOpen(int drive) | ||
238 | { | ||
239 | return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0)); | ||
240 | } | ||
241 | |||
242 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
243 | { | ||
244 | struct ioc_toc_header toc; | ||
245 | int i, okay; | ||
246 | struct ioc_read_toc_entry entry; | ||
247 | struct cd_toc_entry data; | ||
248 | |||
249 | okay = 0; | ||
250 | if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) { | ||
251 | cdrom->numtracks = toc.ending_track-toc.starting_track+1; | ||
252 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
253 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
254 | } | ||
255 | /* Read all the track TOC entries */ | ||
256 | for ( i=0; i<=cdrom->numtracks; ++i ) { | ||
257 | if ( i == cdrom->numtracks ) { | ||
258 | cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */ | ||
259 | } else { | ||
260 | cdrom->track[i].id = toc.starting_track+i; | ||
261 | } | ||
262 | entry.starting_track = cdrom->track[i].id; | ||
263 | entry.address_format = CD_MSF_FORMAT; | ||
264 | entry.data_len = sizeof(data); | ||
265 | entry.data = &data; | ||
266 | if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS, | ||
267 | &entry) < 0 ) { | ||
268 | break; | ||
269 | } else { | ||
270 | cdrom->track[i].type = data.control; | ||
271 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
272 | data.addr.msf.minute, | ||
273 | data.addr.msf.second, | ||
274 | data.addr.msf.frame); | ||
275 | cdrom->track[i].length = 0; | ||
276 | if ( i > 0 ) { | ||
277 | cdrom->track[i-1].length = | ||
278 | cdrom->track[i].offset- | ||
279 | cdrom->track[i-1].offset; | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | if ( i == (cdrom->numtracks+1) ) { | ||
284 | okay = 1; | ||
285 | } | ||
286 | } | ||
287 | return(okay ? 0 : -1); | ||
288 | } | ||
289 | |||
290 | /* Get CD-ROM status */ | ||
291 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
292 | { | ||
293 | CDstatus status; | ||
294 | struct ioc_toc_header toc; | ||
295 | struct ioc_read_subchannel info; | ||
296 | struct cd_sub_channel_info data; | ||
297 | |||
298 | info.address_format = CD_MSF_FORMAT; | ||
299 | info.data_format = CD_CURRENT_POSITION; | ||
300 | info.track = 0; | ||
301 | info.data_len = sizeof(data); | ||
302 | info.data = &data; | ||
303 | if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) { | ||
304 | if ( ERRNO_TRAYEMPTY(errno) ) { | ||
305 | status = CD_TRAYEMPTY; | ||
306 | } else { | ||
307 | status = CD_ERROR; | ||
308 | } | ||
309 | } else { | ||
310 | switch (data.header.audio_status) { | ||
311 | case CD_AS_AUDIO_INVALID: | ||
312 | case CD_AS_NO_STATUS: | ||
313 | /* Try to determine if there's a CD available */ | ||
314 | if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0) | ||
315 | status = CD_STOPPED; | ||
316 | else | ||
317 | status = CD_TRAYEMPTY; | ||
318 | break; | ||
319 | case CD_AS_PLAY_COMPLETED: | ||
320 | status = CD_STOPPED; | ||
321 | break; | ||
322 | case CD_AS_PLAY_IN_PROGRESS: | ||
323 | status = CD_PLAYING; | ||
324 | break; | ||
325 | case CD_AS_PLAY_PAUSED: | ||
326 | status = CD_PAUSED; | ||
327 | break; | ||
328 | default: | ||
329 | status = CD_ERROR; | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | if ( position ) { | ||
334 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | ||
335 | *position = MSF_TO_FRAMES( | ||
336 | data.what.position.absaddr.msf.minute, | ||
337 | data.what.position.absaddr.msf.second, | ||
338 | data.what.position.absaddr.msf.frame); | ||
339 | } else { | ||
340 | *position = 0; | ||
341 | } | ||
342 | } | ||
343 | return(status); | ||
344 | } | ||
345 | |||
346 | /* Start play */ | ||
347 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
348 | { | ||
349 | struct ioc_play_msf playtime; | ||
350 | |||
351 | FRAMES_TO_MSF(start, | ||
352 | &playtime.start_m, &playtime.start_s, &playtime.start_f); | ||
353 | FRAMES_TO_MSF(start+length, | ||
354 | &playtime.end_m, &playtime.end_s, &playtime.end_f); | ||
355 | #ifdef DEBUG_CDROM | ||
356 | fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | ||
357 | playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, | ||
358 | playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); | ||
359 | #endif | ||
360 | ioctl(cdrom->id, CDIOCSTART, 0); | ||
361 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime)); | ||
362 | } | ||
363 | |||
364 | /* Pause play */ | ||
365 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
366 | { | ||
367 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0)); | ||
368 | } | ||
369 | |||
370 | /* Resume play */ | ||
371 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
372 | { | ||
373 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0)); | ||
374 | } | ||
375 | |||
376 | /* Stop play */ | ||
377 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
378 | { | ||
379 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0)); | ||
380 | } | ||
381 | |||
382 | /* Eject the CD-ROM */ | ||
383 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
384 | { | ||
385 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0)); | ||
386 | } | ||
387 | |||
388 | /* Close the CD-ROM handle */ | ||
389 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
390 | { | ||
391 | close(cdrom->id); | ||
392 | } | ||
393 | |||
394 | void SDL_SYS_CDQuit(void) | ||
395 | { | ||
396 | int i; | ||
397 | |||
398 | if ( SDL_numcds > 0 ) { | ||
399 | for ( i=0; i<SDL_numcds; ++i ) { | ||
400 | SDL_free(SDL_cdlist[i]); | ||
401 | } | ||
402 | SDL_numcds = 0; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | #endif /* SDL_CDROM_FREEBSD */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/linux/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/linux/SDL_syscdrom.c new file mode 100644 index 0000000000..68040575b5 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/linux/SDL_syscdrom.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_LINUX | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #include <string.h> /* For strerror() */ | ||
29 | #include <sys/types.h> | ||
30 | #include <sys/stat.h> | ||
31 | #include <sys/ioctl.h> | ||
32 | #include <fcntl.h> | ||
33 | #include <errno.h> | ||
34 | #include <unistd.h> | ||
35 | #ifdef __LINUX__ | ||
36 | #ifdef HAVE_LINUX_VERSION_H | ||
37 | /* linux 2.6.9 workaround */ | ||
38 | #include <linux/version.h> | ||
39 | #if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,9) | ||
40 | #include <asm/types.h> | ||
41 | #define __le64 __u64 | ||
42 | #define __le32 __u32 | ||
43 | #define __le16 __u16 | ||
44 | #define __be64 __u64 | ||
45 | #define __be32 __u32 | ||
46 | #define __be16 __u16 | ||
47 | #endif /* linux 2.6.9 workaround */ | ||
48 | #endif /* HAVE_LINUX_VERSION_H */ | ||
49 | #include <linux/cdrom.h> | ||
50 | #endif | ||
51 | #ifdef __SVR4 | ||
52 | #include <sys/cdio.h> | ||
53 | #endif | ||
54 | |||
55 | /* Define this to use the alternative getmntent() code */ | ||
56 | #ifndef __SVR4 | ||
57 | #define USE_MNTENT | ||
58 | #endif | ||
59 | |||
60 | #ifdef USE_MNTENT | ||
61 | #if defined(__USLC__) | ||
62 | #include <sys/mntent.h> | ||
63 | #else | ||
64 | #include <mntent.h> | ||
65 | #endif | ||
66 | |||
67 | #ifndef _PATH_MNTTAB | ||
68 | #ifdef MNTTAB | ||
69 | #define _PATH_MNTTAB MNTTAB | ||
70 | #else | ||
71 | #define _PATH_MNTTAB "/etc/fstab" | ||
72 | #endif | ||
73 | #endif /* !_PATH_MNTTAB */ | ||
74 | |||
75 | #ifndef _PATH_MOUNTED | ||
76 | #define _PATH_MOUNTED "/etc/mtab" | ||
77 | #endif /* !_PATH_MOUNTED */ | ||
78 | |||
79 | #ifndef MNTTYPE_CDROM | ||
80 | #define MNTTYPE_CDROM "iso9660" | ||
81 | #endif | ||
82 | #ifndef MNTTYPE_SUPER | ||
83 | #define MNTTYPE_SUPER "supermount" | ||
84 | #endif | ||
85 | #endif /* USE_MNTENT */ | ||
86 | |||
87 | #include "SDL_cdrom.h" | ||
88 | #include "../SDL_syscdrom.h" | ||
89 | |||
90 | |||
91 | /* The maximum number of CD-ROM drives we'll detect */ | ||
92 | #define MAX_DRIVES 16 | ||
93 | |||
94 | /* A list of available CD-ROM drives */ | ||
95 | static char *SDL_cdlist[MAX_DRIVES]; | ||
96 | static dev_t SDL_cdmode[MAX_DRIVES]; | ||
97 | |||
98 | /* The system-dependent CD control functions */ | ||
99 | static const char *SDL_SYS_CDName(int drive); | ||
100 | static int SDL_SYS_CDOpen(int drive); | ||
101 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
102 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
103 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
104 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
105 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
106 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
107 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
108 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
109 | |||
110 | /* Some ioctl() errno values which occur when the tray is empty */ | ||
111 | #ifndef ENOMEDIUM | ||
112 | #define ENOMEDIUM ENOENT | ||
113 | #endif | ||
114 | #define ERRNO_TRAYEMPTY(errno) \ | ||
115 | ((errno == EIO) || (errno == ENOENT) || \ | ||
116 | (errno == EINVAL) || (errno == ENOMEDIUM)) | ||
117 | |||
118 | /* Check a drive to see if it is a CD-ROM */ | ||
119 | static int CheckDrive(char *drive, char *mnttype, struct stat *stbuf) | ||
120 | { | ||
121 | int is_cd, cdfd; | ||
122 | struct cdrom_subchnl info; | ||
123 | |||
124 | /* If it doesn't exist, return -1 */ | ||
125 | if ( stat(drive, stbuf) < 0 ) { | ||
126 | return(-1); | ||
127 | } | ||
128 | |||
129 | /* If it does exist, verify that it's an available CD-ROM */ | ||
130 | is_cd = 0; | ||
131 | if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) { | ||
132 | cdfd = open(drive, (O_RDONLY|O_NONBLOCK), 0); | ||
133 | if ( cdfd >= 0 ) { | ||
134 | info.cdsc_format = CDROM_MSF; | ||
135 | /* Under Linux, EIO occurs when a disk is not present. | ||
136 | */ | ||
137 | if ( (ioctl(cdfd, CDROMSUBCHNL, &info) == 0) || | ||
138 | ERRNO_TRAYEMPTY(errno) ) { | ||
139 | is_cd = 1; | ||
140 | } | ||
141 | close(cdfd); | ||
142 | } | ||
143 | #ifdef USE_MNTENT | ||
144 | /* Even if we can't read it, it might be mounted */ | ||
145 | else if ( mnttype && (SDL_strcmp(mnttype, MNTTYPE_CDROM) == 0) ) { | ||
146 | is_cd = 1; | ||
147 | } | ||
148 | #endif | ||
149 | } | ||
150 | return(is_cd); | ||
151 | } | ||
152 | |||
153 | /* Add a CD-ROM drive to our list of valid drives */ | ||
154 | static void AddDrive(char *drive, struct stat *stbuf) | ||
155 | { | ||
156 | int i; | ||
157 | |||
158 | if ( SDL_numcds < MAX_DRIVES ) { | ||
159 | /* Check to make sure it's not already in our list. | ||
160 | This can happen when we see a drive via symbolic link. | ||
161 | */ | ||
162 | for ( i=0; i<SDL_numcds; ++i ) { | ||
163 | if ( stbuf->st_rdev == SDL_cdmode[i] ) { | ||
164 | #ifdef DEBUG_CDROM | ||
165 | fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | ||
166 | #endif | ||
167 | return; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /* Add this drive to our list */ | ||
172 | i = SDL_numcds; | ||
173 | SDL_cdlist[i] = SDL_strdup(drive); | ||
174 | if ( SDL_cdlist[i] == NULL ) { | ||
175 | SDL_OutOfMemory(); | ||
176 | return; | ||
177 | } | ||
178 | SDL_cdmode[i] = stbuf->st_rdev; | ||
179 | ++SDL_numcds; | ||
180 | #ifdef DEBUG_CDROM | ||
181 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
182 | #endif | ||
183 | } | ||
184 | } | ||
185 | |||
186 | #ifdef USE_MNTENT | ||
187 | static void CheckMounts(const char *mtab) | ||
188 | { | ||
189 | FILE *mntfp; | ||
190 | struct mntent *mntent; | ||
191 | struct stat stbuf; | ||
192 | |||
193 | mntfp = setmntent(mtab, "r"); | ||
194 | if ( mntfp != NULL ) { | ||
195 | char *tmp; | ||
196 | char *mnt_type; | ||
197 | size_t mnt_type_len; | ||
198 | char *mnt_dev; | ||
199 | size_t mnt_dev_len; | ||
200 | |||
201 | while ( (mntent=getmntent(mntfp)) != NULL ) { | ||
202 | mnt_type_len = SDL_strlen(mntent->mnt_type) + 1; | ||
203 | mnt_type = SDL_stack_alloc(char, mnt_type_len); | ||
204 | if (mnt_type == NULL) | ||
205 | continue; /* maybe you'll get lucky next time. */ | ||
206 | |||
207 | mnt_dev_len = SDL_strlen(mntent->mnt_fsname) + 1; | ||
208 | mnt_dev = SDL_stack_alloc(char, mnt_dev_len); | ||
209 | if (mnt_dev == NULL) { | ||
210 | SDL_stack_free(mnt_type); | ||
211 | continue; | ||
212 | } | ||
213 | |||
214 | SDL_strlcpy(mnt_type, mntent->mnt_type, mnt_type_len); | ||
215 | SDL_strlcpy(mnt_dev, mntent->mnt_fsname, mnt_dev_len); | ||
216 | |||
217 | /* Handle "supermount" filesystem mounts */ | ||
218 | if ( SDL_strcmp(mnt_type, MNTTYPE_SUPER) == 0 ) { | ||
219 | tmp = SDL_strstr(mntent->mnt_opts, "fs="); | ||
220 | if ( tmp ) { | ||
221 | SDL_stack_free(mnt_type); | ||
222 | mnt_type = SDL_strdup(tmp + SDL_strlen("fs=")); | ||
223 | if ( mnt_type ) { | ||
224 | tmp = SDL_strchr(mnt_type, ','); | ||
225 | if ( tmp ) { | ||
226 | *tmp = '\0'; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | tmp = SDL_strstr(mntent->mnt_opts, "dev="); | ||
231 | if ( tmp ) { | ||
232 | SDL_stack_free(mnt_dev); | ||
233 | mnt_dev = SDL_strdup(tmp + SDL_strlen("dev=")); | ||
234 | if ( mnt_dev ) { | ||
235 | tmp = SDL_strchr(mnt_dev, ','); | ||
236 | if ( tmp ) { | ||
237 | *tmp = '\0'; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | if ( SDL_strcmp(mnt_type, MNTTYPE_CDROM) == 0 ) { | ||
243 | #ifdef DEBUG_CDROM | ||
244 | fprintf(stderr, "Checking mount path from %s: %s mounted on %s of %s\n", | ||
245 | mtab, mnt_dev, mntent->mnt_dir, mnt_type); | ||
246 | #endif | ||
247 | if (CheckDrive(mnt_dev, mnt_type, &stbuf) > 0) { | ||
248 | AddDrive(mnt_dev, &stbuf); | ||
249 | } | ||
250 | } | ||
251 | SDL_stack_free(mnt_dev); | ||
252 | SDL_stack_free(mnt_type); | ||
253 | } | ||
254 | endmntent(mntfp); | ||
255 | } | ||
256 | } | ||
257 | #endif /* USE_MNTENT */ | ||
258 | |||
259 | int SDL_SYS_CDInit(void) | ||
260 | { | ||
261 | /* checklist: /dev/cdrom, /dev/hd?, /dev/scd? /dev/sr? */ | ||
262 | static char *checklist[] = { | ||
263 | "cdrom", "?a hd?", "?0 scd?", "?0 sr?", NULL | ||
264 | }; | ||
265 | char *SDLcdrom; | ||
266 | int i, j, exists; | ||
267 | char drive[32]; | ||
268 | struct stat stbuf; | ||
269 | |||
270 | /* Fill in our driver capabilities */ | ||
271 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
272 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
273 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
274 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
275 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
276 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
277 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
278 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
279 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
280 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
281 | |||
282 | /* Look in the environment for our CD-ROM drive list */ | ||
283 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
284 | if ( SDLcdrom != NULL ) { | ||
285 | char *cdpath, *delim; | ||
286 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
287 | cdpath = SDL_stack_alloc(char, len); | ||
288 | if ( cdpath != NULL ) { | ||
289 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
290 | SDLcdrom = cdpath; | ||
291 | do { | ||
292 | delim = SDL_strchr(SDLcdrom, ':'); | ||
293 | if ( delim ) { | ||
294 | *delim++ = '\0'; | ||
295 | } | ||
296 | #ifdef DEBUG_CDROM | ||
297 | fprintf(stderr, "Checking CD-ROM drive from SDL_CDROM: %s\n", SDLcdrom); | ||
298 | #endif | ||
299 | if ( CheckDrive(SDLcdrom, NULL, &stbuf) > 0 ) { | ||
300 | AddDrive(SDLcdrom, &stbuf); | ||
301 | } | ||
302 | if ( delim ) { | ||
303 | SDLcdrom = delim; | ||
304 | } else { | ||
305 | SDLcdrom = NULL; | ||
306 | } | ||
307 | } while ( SDLcdrom ); | ||
308 | SDL_stack_free(cdpath); | ||
309 | } | ||
310 | |||
311 | /* If we found our drives, there's nothing left to do */ | ||
312 | if ( SDL_numcds > 0 ) { | ||
313 | return(0); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | #ifdef USE_MNTENT | ||
318 | /* Check /dev/cdrom first :-) */ | ||
319 | if (CheckDrive("/dev/cdrom", NULL, &stbuf) > 0) { | ||
320 | AddDrive("/dev/cdrom", &stbuf); | ||
321 | } | ||
322 | |||
323 | /* Now check the currently mounted CD drives */ | ||
324 | CheckMounts(_PATH_MOUNTED); | ||
325 | |||
326 | /* Finally check possible mountable drives in /etc/fstab */ | ||
327 | CheckMounts(_PATH_MNTTAB); | ||
328 | |||
329 | /* If we found our drives, there's nothing left to do */ | ||
330 | if ( SDL_numcds > 0 ) { | ||
331 | return(0); | ||
332 | } | ||
333 | #endif /* USE_MNTENT */ | ||
334 | |||
335 | /* Scan the system for CD-ROM drives. | ||
336 | Not always 100% reliable, so use the USE_MNTENT code above first. | ||
337 | */ | ||
338 | for ( i=0; checklist[i]; ++i ) { | ||
339 | if ( checklist[i][0] == '?' ) { | ||
340 | char *insert; | ||
341 | exists = 1; | ||
342 | for ( j=checklist[i][1]; exists; ++j ) { | ||
343 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", &checklist[i][3]); | ||
344 | insert = SDL_strchr(drive, '?'); | ||
345 | if ( insert != NULL ) { | ||
346 | *insert = j; | ||
347 | } | ||
348 | #ifdef DEBUG_CDROM | ||
349 | fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive); | ||
350 | #endif | ||
351 | switch (CheckDrive(drive, NULL, &stbuf)) { | ||
352 | /* Drive exists and is a CD-ROM */ | ||
353 | case 1: | ||
354 | AddDrive(drive, &stbuf); | ||
355 | break; | ||
356 | /* Drive exists, but isn't a CD-ROM */ | ||
357 | case 0: | ||
358 | break; | ||
359 | /* Drive doesn't exist */ | ||
360 | case -1: | ||
361 | exists = 0; | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | } else { | ||
366 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); | ||
367 | #ifdef DEBUG_CDROM | ||
368 | fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive); | ||
369 | #endif | ||
370 | if ( CheckDrive(drive, NULL, &stbuf) > 0 ) { | ||
371 | AddDrive(drive, &stbuf); | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | return(0); | ||
376 | } | ||
377 | |||
378 | /* General ioctl() CD-ROM command function */ | ||
379 | static int SDL_SYS_CDioctl(int id, int command, void *arg) | ||
380 | { | ||
381 | int retval; | ||
382 | |||
383 | retval = ioctl(id, command, arg); | ||
384 | if ( retval < 0 ) { | ||
385 | SDL_SetError("ioctl() error: %s", strerror(errno)); | ||
386 | } | ||
387 | return(retval); | ||
388 | } | ||
389 | |||
390 | static const char *SDL_SYS_CDName(int drive) | ||
391 | { | ||
392 | return(SDL_cdlist[drive]); | ||
393 | } | ||
394 | |||
395 | static int SDL_SYS_CDOpen(int drive) | ||
396 | { | ||
397 | return(open(SDL_cdlist[drive], (O_RDONLY|O_NONBLOCK), 0)); | ||
398 | } | ||
399 | |||
400 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
401 | { | ||
402 | struct cdrom_tochdr toc; | ||
403 | int i, okay; | ||
404 | struct cdrom_tocentry entry; | ||
405 | |||
406 | okay = 0; | ||
407 | if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc) == 0 ) { | ||
408 | cdrom->numtracks = toc.cdth_trk1-toc.cdth_trk0+1; | ||
409 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
410 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
411 | } | ||
412 | /* Read all the track TOC entries */ | ||
413 | for ( i=0; i<=cdrom->numtracks; ++i ) { | ||
414 | if ( i == cdrom->numtracks ) { | ||
415 | cdrom->track[i].id = CDROM_LEADOUT; | ||
416 | } else { | ||
417 | cdrom->track[i].id = toc.cdth_trk0+i; | ||
418 | } | ||
419 | entry.cdte_track = cdrom->track[i].id; | ||
420 | entry.cdte_format = CDROM_MSF; | ||
421 | if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY, | ||
422 | &entry) < 0 ) { | ||
423 | break; | ||
424 | } else { | ||
425 | if ( entry.cdte_ctrl & CDROM_DATA_TRACK ) { | ||
426 | cdrom->track[i].type = SDL_DATA_TRACK; | ||
427 | } else { | ||
428 | cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
429 | } | ||
430 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
431 | entry.cdte_addr.msf.minute, | ||
432 | entry.cdte_addr.msf.second, | ||
433 | entry.cdte_addr.msf.frame); | ||
434 | cdrom->track[i].length = 0; | ||
435 | if ( i > 0 ) { | ||
436 | cdrom->track[i-1].length = | ||
437 | cdrom->track[i].offset- | ||
438 | cdrom->track[i-1].offset; | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | if ( i == (cdrom->numtracks+1) ) { | ||
443 | okay = 1; | ||
444 | } | ||
445 | } | ||
446 | return(okay ? 0 : -1); | ||
447 | } | ||
448 | |||
449 | /* Get CD-ROM status */ | ||
450 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
451 | { | ||
452 | CDstatus status; | ||
453 | struct cdrom_tochdr toc; | ||
454 | struct cdrom_subchnl info; | ||
455 | |||
456 | info.cdsc_format = CDROM_MSF; | ||
457 | if ( ioctl(cdrom->id, CDROMSUBCHNL, &info) < 0 ) { | ||
458 | if ( ERRNO_TRAYEMPTY(errno) ) { | ||
459 | status = CD_TRAYEMPTY; | ||
460 | } else { | ||
461 | status = CD_ERROR; | ||
462 | } | ||
463 | } else { | ||
464 | switch (info.cdsc_audiostatus) { | ||
465 | case CDROM_AUDIO_INVALID: | ||
466 | case CDROM_AUDIO_NO_STATUS: | ||
467 | /* Try to determine if there's a CD available */ | ||
468 | if (ioctl(cdrom->id, CDROMREADTOCHDR, &toc)==0) | ||
469 | status = CD_STOPPED; | ||
470 | else | ||
471 | status = CD_TRAYEMPTY; | ||
472 | break; | ||
473 | case CDROM_AUDIO_COMPLETED: | ||
474 | status = CD_STOPPED; | ||
475 | break; | ||
476 | case CDROM_AUDIO_PLAY: | ||
477 | status = CD_PLAYING; | ||
478 | break; | ||
479 | case CDROM_AUDIO_PAUSED: | ||
480 | /* Workaround buggy CD-ROM drive */ | ||
481 | if ( info.cdsc_trk == CDROM_LEADOUT ) { | ||
482 | status = CD_STOPPED; | ||
483 | } else { | ||
484 | status = CD_PAUSED; | ||
485 | } | ||
486 | break; | ||
487 | default: | ||
488 | status = CD_ERROR; | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | if ( position ) { | ||
493 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | ||
494 | *position = MSF_TO_FRAMES( | ||
495 | info.cdsc_absaddr.msf.minute, | ||
496 | info.cdsc_absaddr.msf.second, | ||
497 | info.cdsc_absaddr.msf.frame); | ||
498 | } else { | ||
499 | *position = 0; | ||
500 | } | ||
501 | } | ||
502 | return(status); | ||
503 | } | ||
504 | |||
505 | /* Start play */ | ||
506 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
507 | { | ||
508 | struct cdrom_msf playtime; | ||
509 | |||
510 | FRAMES_TO_MSF(start, | ||
511 | &playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0); | ||
512 | FRAMES_TO_MSF(start+length, | ||
513 | &playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1); | ||
514 | #ifdef DEBUG_CDROM | ||
515 | fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | ||
516 | playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, | ||
517 | playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); | ||
518 | #endif | ||
519 | return(SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime)); | ||
520 | } | ||
521 | |||
522 | /* Pause play */ | ||
523 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
524 | { | ||
525 | return(SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0)); | ||
526 | } | ||
527 | |||
528 | /* Resume play */ | ||
529 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
530 | { | ||
531 | return(SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0)); | ||
532 | } | ||
533 | |||
534 | /* Stop play */ | ||
535 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
536 | { | ||
537 | return(SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0)); | ||
538 | } | ||
539 | |||
540 | /* Eject the CD-ROM */ | ||
541 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
542 | { | ||
543 | return(SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0)); | ||
544 | } | ||
545 | |||
546 | /* Close the CD-ROM handle */ | ||
547 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
548 | { | ||
549 | close(cdrom->id); | ||
550 | } | ||
551 | |||
552 | void SDL_SYS_CDQuit(void) | ||
553 | { | ||
554 | int i; | ||
555 | |||
556 | if ( SDL_numcds > 0 ) { | ||
557 | for ( i=0; i<SDL_numcds; ++i ) { | ||
558 | SDL_free(SDL_cdlist[i]); | ||
559 | } | ||
560 | SDL_numcds = 0; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | #endif /* SDL_CDROM_LINUX */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/macos/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/macos/SDL_syscdrom.c new file mode 100644 index 0000000000..10a202544e --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macos/SDL_syscdrom.c | |||
@@ -0,0 +1,525 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_MACOS | ||
25 | |||
26 | /* MacOS functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #include <Devices.h> | ||
29 | #include <Files.h> | ||
30 | #include <LowMem.h> /* Use entry table macros, not functions in InterfaceLib */ | ||
31 | |||
32 | #include "SDL_cdrom.h" | ||
33 | #include "../SDL_syscdrom.h" | ||
34 | #include "SDL_syscdrom_c.h" | ||
35 | |||
36 | /* Added by Matt Slot */ | ||
37 | #if !defined(LMGetUnitTableEntryCount) | ||
38 | #define LMGetUnitTableEntryCount() *(short *)0x01D2 | ||
39 | #endif | ||
40 | |||
41 | /* The maximum number of CD-ROM drives we'll detect */ | ||
42 | #define MAX_DRIVES 26 | ||
43 | |||
44 | /* A list of available CD-ROM drives */ | ||
45 | static long SDL_cdversion = 0; | ||
46 | static struct { | ||
47 | short dRefNum; | ||
48 | short driveNum; | ||
49 | long frames; | ||
50 | char name[256]; | ||
51 | Boolean hasAudio; | ||
52 | } SDL_cdlist[MAX_DRIVES]; | ||
53 | static StringPtr gDriverName = "\p.AppleCD"; | ||
54 | |||
55 | /* The system-dependent CD control functions */ | ||
56 | static const char *SDL_SYS_CDName(int drive); | ||
57 | static int SDL_SYS_CDOpen(int drive); | ||
58 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
59 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
60 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
61 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
62 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
63 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
64 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
65 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
66 | |||
67 | static short SDL_SYS_ShortToBCD(short value) | ||
68 | { | ||
69 | return((value % 10) + (value / 10) * 0x10); /* Convert value to BCD */ | ||
70 | } | ||
71 | |||
72 | static short SDL_SYS_BCDToShort(short value) | ||
73 | { | ||
74 | return((value % 0x10) + (value / 0x10) * 10); /* Convert value from BCD */ | ||
75 | } | ||
76 | |||
77 | int SDL_SYS_CDInit(void) | ||
78 | { | ||
79 | SInt16 dRefNum = 0; | ||
80 | SInt16 first, last; | ||
81 | |||
82 | SDL_numcds = 0; | ||
83 | |||
84 | /* Check that the software is available */ | ||
85 | if (Gestalt(kGestaltAudioCDSelector, &SDL_cdversion) || | ||
86 | !SDL_cdversion) return(0); | ||
87 | |||
88 | /* Fill in our driver capabilities */ | ||
89 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
90 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
91 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
92 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
93 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
94 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
95 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
96 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
97 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
98 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
99 | |||
100 | /* Walk the list, count each AudioCD driver, and save the refnums */ | ||
101 | first = -1; | ||
102 | last = 0 - LMGetUnitTableEntryCount(); | ||
103 | for(dRefNum = first; dRefNum >= last; dRefNum--) { | ||
104 | Str255 driverName; | ||
105 | StringPtr namePtr; | ||
106 | DCtlHandle deviceEntry; | ||
107 | |||
108 | deviceEntry = GetDCtlEntry(dRefNum); | ||
109 | if (! deviceEntry) continue; | ||
110 | |||
111 | /* Is this an .AppleCD ? */ | ||
112 | namePtr = (*deviceEntry)->dCtlFlags & (1L << dRAMBased) ? | ||
113 | ((StringPtr) ((DCtlPtr) deviceEntry)->dCtlDriver + 18) : | ||
114 | ((StringPtr) (*deviceEntry)->dCtlDriver + 18); | ||
115 | BlockMoveData(namePtr, driverName, namePtr[0]+1); | ||
116 | if (driverName[0] > gDriverName[0]) driverName[0] = gDriverName[0]; | ||
117 | if (! EqualString(driverName, gDriverName, false, false)) continue; | ||
118 | |||
119 | /* Record the basic info for each drive */ | ||
120 | SDL_cdlist[SDL_numcds].dRefNum = dRefNum; | ||
121 | BlockMoveData(namePtr + 1, SDL_cdlist[SDL_numcds].name, namePtr[0]); | ||
122 | SDL_cdlist[SDL_numcds].name[namePtr[0]] = 0; | ||
123 | SDL_cdlist[SDL_numcds].hasAudio = false; | ||
124 | SDL_numcds++; | ||
125 | } | ||
126 | return(0); | ||
127 | } | ||
128 | |||
129 | static const char *SDL_SYS_CDName(int drive) | ||
130 | { | ||
131 | return(SDL_cdlist[drive].name); | ||
132 | } | ||
133 | |||
134 | static int get_drivenum(int drive) | ||
135 | { | ||
136 | QHdr *driveQ = GetDrvQHdr(); | ||
137 | DrvQEl *driveElem; | ||
138 | |||
139 | /* Update the drive number */ | ||
140 | SDL_cdlist[drive].driveNum = 0; | ||
141 | if ( driveQ->qTail ) { | ||
142 | driveQ->qTail->qLink = 0; | ||
143 | } | ||
144 | for ( driveElem=(DrvQEl *)driveQ->qHead; driveElem; | ||
145 | driveElem = (DrvQEl *)driveElem->qLink ) { | ||
146 | if ( driveElem->dQRefNum == SDL_cdlist[drive].dRefNum ) { | ||
147 | SDL_cdlist[drive].driveNum = driveElem->dQDrive; | ||
148 | break; | ||
149 | } | ||
150 | } | ||
151 | return(SDL_cdlist[drive].driveNum); | ||
152 | } | ||
153 | |||
154 | static int SDL_SYS_CDOpen(int drive) | ||
155 | { | ||
156 | return(drive); | ||
157 | } | ||
158 | |||
159 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
160 | { | ||
161 | CDCntrlParam cdpb; | ||
162 | CDTrackData tracks[SDL_MAX_TRACKS]; | ||
163 | long i, leadout; | ||
164 | |||
165 | /* Get the number of tracks on the CD by examining the TOC */ | ||
166 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
167 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
168 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
169 | cdpb.csCode = kReadTOC; | ||
170 | cdpb.csParam.words[0] = kGetTrackRange; | ||
171 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
172 | SDL_SetError("PBControlSync() failed"); | ||
173 | return(-1); | ||
174 | } | ||
175 | |||
176 | cdrom->numtracks = | ||
177 | SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) - | ||
178 | SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1; | ||
179 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) | ||
180 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
181 | cdrom->status = CD_STOPPED; | ||
182 | cdrom->cur_track = 0; /* Apparently these are set elsewhere */ | ||
183 | cdrom->cur_frame = 0; /* Apparently these are set elsewhere */ | ||
184 | |||
185 | |||
186 | /* Get the lead out area of the CD by examining the TOC */ | ||
187 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
188 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
189 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
190 | cdpb.csCode = kReadTOC; | ||
191 | cdpb.csParam.words[0] = kGetLeadOutArea; | ||
192 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
193 | SDL_SetError("PBControlSync() failed"); | ||
194 | return(-1); | ||
195 | } | ||
196 | |||
197 | leadout = MSF_TO_FRAMES( | ||
198 | SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]), | ||
199 | SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]), | ||
200 | SDL_SYS_BCDToShort(cdpb.csParam.bytes[2])); | ||
201 | |||
202 | /* Get an array of track locations by examining the TOC */ | ||
203 | SDL_memset(tracks, 0, sizeof(tracks)); | ||
204 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
205 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
206 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
207 | cdpb.csCode = kReadTOC; | ||
208 | cdpb.csParam.words[0] = kGetTrackEntries; /* Type of Query */ | ||
209 | * ((long *) (cdpb.csParam.words+1)) = (long) tracks; | ||
210 | cdpb.csParam.words[3] = cdrom->numtracks * sizeof(tracks[0]); | ||
211 | * ((char *) (cdpb.csParam.words+4)) = 1; /* First track */ | ||
212 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
213 | SDL_SetError("PBControlSync() failed"); | ||
214 | return(-1); | ||
215 | } | ||
216 | |||
217 | /* Read all the track TOC entries */ | ||
218 | SDL_cdlist[cdrom->id].hasAudio = false; | ||
219 | for ( i=0; i<cdrom->numtracks; ++i ) | ||
220 | { | ||
221 | cdrom->track[i].id = i+1; | ||
222 | if (tracks[i].entry.control & kDataTrackMask) | ||
223 | cdrom->track[i].type = SDL_DATA_TRACK; | ||
224 | else | ||
225 | { | ||
226 | cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
227 | SDL_cdlist[SDL_numcds].hasAudio = true; | ||
228 | } | ||
229 | |||
230 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
231 | SDL_SYS_BCDToShort(tracks[i].entry.min), | ||
232 | SDL_SYS_BCDToShort(tracks[i].entry.min), | ||
233 | SDL_SYS_BCDToShort(tracks[i].entry.frame)); | ||
234 | cdrom->track[i].length = MSF_TO_FRAMES( | ||
235 | SDL_SYS_BCDToShort(tracks[i+1].entry.min), | ||
236 | SDL_SYS_BCDToShort(tracks[i+1].entry.min), | ||
237 | SDL_SYS_BCDToShort(tracks[i+1].entry.frame)) - | ||
238 | cdrom->track[i].offset; | ||
239 | } | ||
240 | |||
241 | /* Apparently SDL wants a fake last entry */ | ||
242 | cdrom->track[i].offset = leadout; | ||
243 | cdrom->track[i].length = 0; | ||
244 | |||
245 | return(0); | ||
246 | } | ||
247 | |||
248 | /* Get CD-ROM status */ | ||
249 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
250 | { | ||
251 | CDCntrlParam cdpb; | ||
252 | CDstatus status = CD_ERROR; | ||
253 | Boolean spinning = false; | ||
254 | |||
255 | if (position) *position = 0; | ||
256 | |||
257 | /* Get the number of tracks on the CD by examining the TOC */ | ||
258 | if ( ! get_drivenum(cdrom->id) ) { | ||
259 | return(CD_TRAYEMPTY); | ||
260 | } | ||
261 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
262 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
263 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
264 | cdpb.csCode = kReadTOC; | ||
265 | cdpb.csParam.words[0] = kGetTrackRange; | ||
266 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
267 | SDL_SetError("PBControlSync() failed"); | ||
268 | return(CD_ERROR); | ||
269 | } | ||
270 | |||
271 | cdrom->numtracks = | ||
272 | SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) - | ||
273 | SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1; | ||
274 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) | ||
275 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
276 | cdrom->cur_track = 0; /* Apparently these are set elsewhere */ | ||
277 | cdrom->cur_frame = 0; /* Apparently these are set elsewhere */ | ||
278 | |||
279 | |||
280 | if (1 || SDL_cdlist[cdrom->id].hasAudio) { | ||
281 | /* Get the current playback status */ | ||
282 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
283 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
284 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
285 | cdpb.csCode = kAudioStatus; | ||
286 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
287 | SDL_SetError("PBControlSync() failed"); | ||
288 | return(-1); | ||
289 | } | ||
290 | |||
291 | switch(cdpb.csParam.cd.status) { | ||
292 | case kStatusPlaying: | ||
293 | status = CD_PLAYING; | ||
294 | spinning = true; | ||
295 | break; | ||
296 | case kStatusPaused: | ||
297 | status = CD_PAUSED; | ||
298 | spinning = true; | ||
299 | break; | ||
300 | case kStatusMuted: | ||
301 | status = CD_PLAYING; /* What should I do here? */ | ||
302 | spinning = true; | ||
303 | break; | ||
304 | case kStatusDone: | ||
305 | status = CD_STOPPED; | ||
306 | spinning = true; | ||
307 | break; | ||
308 | case kStatusStopped: | ||
309 | status = CD_STOPPED; | ||
310 | spinning = false; | ||
311 | break; | ||
312 | case kStatusError: | ||
313 | default: | ||
314 | status = CD_ERROR; | ||
315 | spinning = false; | ||
316 | break; | ||
317 | } | ||
318 | |||
319 | if (spinning && position) *position = MSF_TO_FRAMES( | ||
320 | SDL_SYS_BCDToShort(cdpb.csParam.cd.minute), | ||
321 | SDL_SYS_BCDToShort(cdpb.csParam.cd.second), | ||
322 | SDL_SYS_BCDToShort(cdpb.csParam.cd.frame)); | ||
323 | } | ||
324 | else | ||
325 | status = CD_ERROR; /* What should I do here? */ | ||
326 | |||
327 | return(status); | ||
328 | } | ||
329 | |||
330 | /* Start play */ | ||
331 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
332 | { | ||
333 | CDCntrlParam cdpb; | ||
334 | |||
335 | /* Pause the current audio playback to avoid audible artifacts */ | ||
336 | if ( SDL_SYS_CDPause(cdrom) < 0 ) { | ||
337 | return(-1); | ||
338 | } | ||
339 | |||
340 | /* Specify the AudioCD playback mode */ | ||
341 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
342 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
343 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
344 | cdpb.csCode = kSetPlayMode; | ||
345 | cdpb.csParam.bytes[0] = false; /* Repeat? */ | ||
346 | cdpb.csParam.bytes[1] = kPlayModeSequential; /* Play mode */ | ||
347 | /* ¥¥¥ÊTreat as soft error, NEC Drive doesnt support this call ¥¥¥ */ | ||
348 | PBControlSync((ParmBlkPtr) &cdpb); | ||
349 | |||
350 | #if 1 | ||
351 | /* Specify the end of audio playback */ | ||
352 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
353 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
354 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
355 | cdpb.csCode = kAudioStop; | ||
356 | cdpb.csParam.words[0] = kBlockPosition; /* Position Mode */ | ||
357 | *(long *) (cdpb.csParam.words + 1) = start+length-1; /* Search Address */ | ||
358 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
359 | SDL_SetError("PBControlSync() failed"); | ||
360 | return(-1); | ||
361 | } | ||
362 | |||
363 | /* Specify the start of audio playback, and start it */ | ||
364 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
365 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
366 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
367 | cdpb.csCode = kAudioPlay; | ||
368 | cdpb.csParam.words[0] = kBlockPosition; /* Position Mode */ | ||
369 | *(long *) (cdpb.csParam.words + 1) = start+1; /* Search Address */ | ||
370 | cdpb.csParam.words[3] = false; /* Stop address? */ | ||
371 | cdpb.csParam.words[4] = kStereoPlayMode; /* Audio Play Mode */ | ||
372 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
373 | SDL_SetError("PBControlSync() failed"); | ||
374 | return(-1); | ||
375 | } | ||
376 | #else | ||
377 | /* Specify the end of audio playback */ | ||
378 | FRAMES_TO_MSF(start+length, &m, &s, &f); | ||
379 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
380 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
381 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
382 | cdpb.csCode = kAudioStop; | ||
383 | cdpb.csParam.words[0] = kTrackPosition; /* Position Mode */ | ||
384 | cdpb.csParam.words[1] = 0; /* Search Address (hiword)*/ | ||
385 | cdpb.csParam.words[2] = /* Search Address (loword)*/ | ||
386 | SDL_SYS_ShortToBCD(cdrom->numtracks); | ||
387 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
388 | SDL_SetError("PBControlSync() failed"); | ||
389 | return(-1); | ||
390 | } | ||
391 | |||
392 | /* Specify the start of audio playback, and start it */ | ||
393 | FRAMES_TO_MSF(start, &m, &s, &f); | ||
394 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
395 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
396 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
397 | cdpb.csCode = kAudioPlay; | ||
398 | cdpb.csParam.words[0] = kTrackPosition; /* Position Mode */ | ||
399 | cdpb.csParam.words[1] = 0; /* Search Address (hiword)*/ | ||
400 | cdpb.csParam.words[2] = SDL_SYS_ShortToBCD(1); /* Search Address (loword)*/ | ||
401 | cdpb.csParam.words[3] = false; /* Stop address? */ | ||
402 | cdpb.csParam.words[4] = kStereoPlayMode; /* Audio Play Mode */ | ||
403 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
404 | SDL_SetError("PBControlSync() failed"); | ||
405 | return(-1); | ||
406 | } | ||
407 | #endif | ||
408 | |||
409 | return(0); | ||
410 | } | ||
411 | |||
412 | /* Pause play */ | ||
413 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
414 | { | ||
415 | CDCntrlParam cdpb; | ||
416 | |||
417 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
418 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
419 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
420 | cdpb.csCode = kAudioPause; | ||
421 | cdpb.csParam.words[0] = 0; /* Pause/Continue Flag (hiword) */ | ||
422 | cdpb.csParam.words[1] = 1; /* Pause/Continue Flag (loword) */ | ||
423 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
424 | SDL_SetError("PBControlSync() failed"); | ||
425 | return(-1); | ||
426 | } | ||
427 | return(0); | ||
428 | } | ||
429 | |||
430 | /* Resume play */ | ||
431 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
432 | { | ||
433 | CDCntrlParam cdpb; | ||
434 | |||
435 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
436 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
437 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
438 | cdpb.csCode = kAudioPause; | ||
439 | cdpb.csParam.words[0] = 0; /* Pause/Continue Flag (hiword) */ | ||
440 | cdpb.csParam.words[1] = 0; /* Pause/Continue Flag (loword) */ | ||
441 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
442 | SDL_SetError("PBControlSync() failed"); | ||
443 | return(-1); | ||
444 | } | ||
445 | return(0); | ||
446 | } | ||
447 | |||
448 | /* Stop play */ | ||
449 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
450 | { | ||
451 | CDCntrlParam cdpb; | ||
452 | |||
453 | SDL_memset(&cdpb, 0, sizeof(cdpb)); | ||
454 | cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum; | ||
455 | cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
456 | cdpb.csCode = kAudioStop; | ||
457 | cdpb.csParam.words[0] = 0; /* Position Mode */ | ||
458 | cdpb.csParam.words[1] = 0; /* Search Address (hiword) */ | ||
459 | cdpb.csParam.words[2] = 0; /* Search Address (loword) */ | ||
460 | if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) { | ||
461 | SDL_SetError("PBControlSync() failed"); | ||
462 | return(-1); | ||
463 | } | ||
464 | return(0); | ||
465 | } | ||
466 | |||
467 | /* Eject the CD-ROM */ | ||
468 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
469 | { | ||
470 | Boolean disk = false; | ||
471 | QHdr *driveQ = GetDrvQHdr(); | ||
472 | DrvQEl *driveElem; | ||
473 | HParamBlockRec hpb; | ||
474 | ParamBlockRec cpb; | ||
475 | |||
476 | for ( driveElem = (DrvQEl *) driveQ->qHead; driveElem; driveElem = | ||
477 | (driveElem) ? ((DrvQEl *) driveElem->qLink) : | ||
478 | ((DrvQEl *) driveQ->qHead) ) { | ||
479 | if ( driveQ->qTail ) { | ||
480 | driveQ->qTail->qLink = 0; | ||
481 | } | ||
482 | if ( driveElem->dQRefNum != SDL_cdlist[cdrom->id].dRefNum ) { | ||
483 | continue; | ||
484 | } | ||
485 | |||
486 | /* Does drive contain mounted volume? If not, skip */ | ||
487 | SDL_memset(&hpb, 0, sizeof(hpb)); | ||
488 | hpb.volumeParam.ioVRefNum = driveElem->dQDrive; | ||
489 | if ( PBHGetVInfoSync(&hpb) != noErr ) { | ||
490 | continue; | ||
491 | } | ||
492 | if ( (UnmountVol(0, driveElem->dQDrive) == noErr) && | ||
493 | (Eject(0, driveElem->dQDrive) == noErr) ) { | ||
494 | driveElem = 0; /* Clear pointer to reset our loop */ | ||
495 | disk = true; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | /* If no disk is present, just eject the tray */ | ||
500 | if (! disk) { | ||
501 | SDL_memset(&cpb, 0, sizeof(cpb)); | ||
502 | cpb.cntrlParam.ioVRefNum = 0; /* No Drive */ | ||
503 | cpb.cntrlParam.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum; | ||
504 | cpb.cntrlParam.csCode = kEjectTheDisc; | ||
505 | if ( PBControlSync((ParmBlkPtr)&cpb) != noErr ) { | ||
506 | SDL_SetError("PBControlSync() failed"); | ||
507 | return(-1); | ||
508 | } | ||
509 | } | ||
510 | return(0); | ||
511 | } | ||
512 | |||
513 | /* Close the CD-ROM handle */ | ||
514 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
515 | { | ||
516 | return; | ||
517 | } | ||
518 | |||
519 | void SDL_SYS_CDQuit(void) | ||
520 | { | ||
521 | while(SDL_numcds--) | ||
522 | SDL_memset(SDL_cdlist + SDL_numcds, 0, sizeof(SDL_cdlist[0])); | ||
523 | } | ||
524 | |||
525 | #endif /* SDL_CDROM_MACOS */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/macos/SDL_syscdrom_c.h b/apps/plugins/sdl/src/cdrom/macos/SDL_syscdrom_c.h new file mode 100644 index 0000000000..e715a256d1 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macos/SDL_syscdrom_c.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* This is the MacOS specific header for the SDL CD-ROM API | ||
25 | Contributed by Matt Slot | ||
26 | */ | ||
27 | |||
28 | /* AppleCD Control calls */ | ||
29 | #define kVerifyTheDisc 5 /* Returns noErr if there is disc inserted */ | ||
30 | #define kEjectTheDisc 7 /* Eject disc from drive */ | ||
31 | #define kUserEject 80 /* Enable/disable the CD-ROM eject button */ | ||
32 | #define kReadTOC 100 /* Extract various TOC information from the disc */ | ||
33 | #define kReadQ 101 /* Extract Q subcode info for the current track */ | ||
34 | #define kAudioTrackSearch 103 /* Start playback from the indicated position */ | ||
35 | #define kAudioPlay 104 /* Start playback from the indicated position */ | ||
36 | #define kAudioPause 105 /* Pause/continue the playback */ | ||
37 | #define kAudioStop 106 /* Stop playback at the indicated position */ | ||
38 | #define kAudioStatus 107 /* Return audio play status */ | ||
39 | #define kAudioControl 109 /* Set the output volume for the audio channels */ | ||
40 | #define kReadAudioVolume 112 /* Get the output volume for the audio channels */ | ||
41 | #define kSetTrackList 122 /* Set the track program for the audio CD to play */ | ||
42 | #define kGetTrackList 123 /* Get the track program the audio CD is playing */ | ||
43 | #define kGetTrackIndex 124 /* Get the track index the audio CD is playing */ | ||
44 | #define kSetPlayMode 125 /* Set the audio tracks play mode */ | ||
45 | #define kGetPlayMode 126 /* Get the audio tracks play mode */ | ||
46 | |||
47 | /* AppleCD Status calls */ | ||
48 | #define kGetDriveType 96 /* Get the type of the physical CD-ROM drive */ | ||
49 | #define kWhoIsThere 97 /* Get a bitmap of SCSI IDs the driver controls */ | ||
50 | #define kGetBlockSize 98 /* Get current block size of the CD-ROM drive */ | ||
51 | |||
52 | /* AppleCD other constants */ | ||
53 | #define kBlockPosition 0 /* Position at the specified logical block number */ | ||
54 | #define kAbsMSFPosition 1 /* Position at the specified Min/Sec/Frame (in BCD) */ | ||
55 | #define kTrackPosition 2 /* Position at the specified track number (in BCD) */ | ||
56 | #define kIndexPosition 3 /* Position at the nth track in program (in BCD) */ | ||
57 | |||
58 | #define kMutedPlayMode 0 /* Play the audio track with no output */ | ||
59 | #define kStereoPlayMode 9 /* Play the audio track in normal stereo */ | ||
60 | |||
61 | #define kControlFieldMask 0x0D /* Bits 3,2,0 in the nibble */ | ||
62 | #define kDataTrackMask 0x04 /* Indicates Data Track */ | ||
63 | |||
64 | #define kGetTrackRange 1 /* Query TOC for track numbers */ | ||
65 | #define kGetLeadOutArea 2 /* Query TOC for "Lead Out" end of audio data */ | ||
66 | #define kGetTrackEntries 3 /* Query TOC for track starts and data types */ | ||
67 | |||
68 | #define kStatusPlaying 0 /* Audio Play operation in progress */ | ||
69 | #define kStatusPaused 1 /* CD-ROM device in Hold Track ("Pause") state */ | ||
70 | #define kStatusMuted 2 /* MUTING-ON operation in progress */ | ||
71 | #define kStatusDone 3 /* Audio Play completed */ | ||
72 | #define kStatusError 4 /* Error occurred during audio play operation */ | ||
73 | #define kStatusStopped 5 /* Audio play operation not requested */ | ||
74 | |||
75 | #define kPlayModeSequential 0 /* Play tracks in order */ | ||
76 | #define kPlayModeShuffled 1 /* Play tracks randomly */ | ||
77 | #define kPlayModeProgrammed 2 /* Use custom playlist */ | ||
78 | |||
79 | /* AppleCD Gestalt selectors */ | ||
80 | #define kGestaltAudioCDSelector 'aucd' | ||
81 | #define kDriverVersion52 0x00000520 | ||
82 | #define kDriverVersion51 0x00000510 | ||
83 | #define kDriverVersion50 0x00000500 | ||
84 | |||
85 | /* Drive type constants */ | ||
86 | #define kDriveAppleCD_SC 1 | ||
87 | #define kDriveAppleCD_SCPlus_or_150 2 | ||
88 | #define kDriveAppleCD_300_or_300Plus 3 | ||
89 | |||
90 | /* Misc constants */ | ||
91 | #define kFirstSCSIDevice -33 | ||
92 | #define kLastSCSIDevice -40 | ||
93 | |||
94 | #if PRAGMA_STRUCT_ALIGN | ||
95 | #pragma options align=mac68k | ||
96 | #endif | ||
97 | |||
98 | /* AppleCD driver parameter block */ | ||
99 | typedef struct CDCntrlParam { | ||
100 | QElemPtr qLink; | ||
101 | short qType; | ||
102 | short ioTrap; | ||
103 | Ptr ioCmdAddr; | ||
104 | IOCompletionUPP ioCompletion; | ||
105 | OSErr ioResult; | ||
106 | StringPtr ioNamePtr; | ||
107 | short ioVRefNum; | ||
108 | short ioCRefNum; | ||
109 | short csCode; | ||
110 | |||
111 | union { | ||
112 | long longs[6]; | ||
113 | short words[11]; | ||
114 | unsigned char bytes[22]; | ||
115 | struct { | ||
116 | unsigned char status; | ||
117 | unsigned char play; | ||
118 | unsigned char control; | ||
119 | unsigned char minute; | ||
120 | unsigned char second; | ||
121 | unsigned char frame; | ||
122 | } cd; | ||
123 | } csParam; | ||
124 | |||
125 | } CDCntrlParam, *CDCntrlParamPtr; | ||
126 | |||
127 | typedef union CDTrackData { | ||
128 | long value; /* Treat as a longword value */ | ||
129 | struct { | ||
130 | unsigned char reserved : 4; /* Unused by AppleCD driver */ | ||
131 | unsigned char control : 4; /* Track flags (data track?) */ | ||
132 | unsigned char min; /* Start of track (BCD) */ | ||
133 | unsigned char sec; /* Start of track (BCD) */ | ||
134 | unsigned char frame; /* Start of track (BCD) */ | ||
135 | } entry; /* Broken into fields */ | ||
136 | } CDTrackData, *CDTrackPtr; | ||
137 | |||
138 | #if PRAGMA_STRUCT_ALIGN | ||
139 | #pragma options align=reset | ||
140 | #endif | ||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c new file mode 100644 index 0000000000..97cb9b2874 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | |||
22 | This file based on Apple sample code. We haven't changed the file name, | ||
23 | so if you want to see the original search for it on apple.com/developer | ||
24 | */ | ||
25 | #include "SDL_config.h" | ||
26 | #include "SDL_endian.h" | ||
27 | |||
28 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
29 | AudioFilePlayer.cpp | ||
30 | */ | ||
31 | #include "AudioFilePlayer.h" | ||
32 | |||
33 | /* | ||
34 | void ThrowResult (OSStatus result, const char* str) | ||
35 | { | ||
36 | SDL_SetError ("Error: %s %d", str, result); | ||
37 | throw result; | ||
38 | } | ||
39 | */ | ||
40 | |||
41 | #if DEBUG | ||
42 | static void PrintStreamDesc (AudioStreamBasicDescription *inDesc) | ||
43 | { | ||
44 | if (!inDesc) { | ||
45 | printf ("Can't print a NULL desc!\n"); | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | printf ("- - - - - - - - - - - - - - - - - - - -\n"); | ||
50 | printf (" Sample Rate:%f\n", inDesc->mSampleRate); | ||
51 | printf (" Format ID:%s\n", (char*)&inDesc->mFormatID); | ||
52 | printf (" Format Flags:%lX\n", inDesc->mFormatFlags); | ||
53 | printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket); | ||
54 | printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket); | ||
55 | printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame); | ||
56 | printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame); | ||
57 | printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel); | ||
58 | printf ("- - - - - - - - - - - - - - - - - - - -\n"); | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | |||
63 | static int AudioFilePlayer_SetDestination (AudioFilePlayer *afp, AudioUnit *inDestUnit) | ||
64 | { | ||
65 | /*if (afp->mConnected) throw static_cast<OSStatus>(-1);*/ /* can't set dest if already engaged */ | ||
66 | if (afp->mConnected) | ||
67 | return 0 ; | ||
68 | |||
69 | SDL_memcpy(&afp->mPlayUnit, inDestUnit, sizeof (afp->mPlayUnit)); | ||
70 | |||
71 | OSStatus result = noErr; | ||
72 | |||
73 | |||
74 | /* we can "down" cast a component instance to a component */ | ||
75 | ComponentDescription desc; | ||
76 | result = GetComponentInfo ((Component)*inDestUnit, &desc, 0, 0, 0); | ||
77 | if (result) return 0; /*THROW_RESULT("GetComponentInfo")*/ | ||
78 | |||
79 | /* we're going to use this to know which convert routine to call | ||
80 | a v1 audio unit will have a type of 'aunt' | ||
81 | a v2 audio unit will have one of several different types. */ | ||
82 | if (desc.componentType != kAudioUnitType_Output) { | ||
83 | result = badComponentInstance; | ||
84 | /*THROW_RESULT("BAD COMPONENT")*/ | ||
85 | if (result) return 0; | ||
86 | } | ||
87 | |||
88 | /* Set the input format of the audio unit. */ | ||
89 | result = AudioUnitSetProperty (*inDestUnit, | ||
90 | kAudioUnitProperty_StreamFormat, | ||
91 | kAudioUnitScope_Input, | ||
92 | 0, | ||
93 | &afp->mFileDescription, | ||
94 | sizeof (afp->mFileDescription)); | ||
95 | /*THROW_RESULT("AudioUnitSetProperty")*/ | ||
96 | if (result) return 0; | ||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | static void AudioFilePlayer_SetNotifier(AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon) | ||
101 | { | ||
102 | afp->mNotifier = inNotifier; | ||
103 | afp->mRefCon = inRefCon; | ||
104 | } | ||
105 | |||
106 | static int AudioFilePlayer_IsConnected(AudioFilePlayer *afp) | ||
107 | { | ||
108 | return afp->mConnected; | ||
109 | } | ||
110 | |||
111 | static AudioUnit AudioFilePlayer_GetDestUnit(AudioFilePlayer *afp) | ||
112 | { | ||
113 | return afp->mPlayUnit; | ||
114 | } | ||
115 | |||
116 | static void AudioFilePlayer_Print(AudioFilePlayer *afp) | ||
117 | { | ||
118 | #if DEBUG | ||
119 | printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false")); | ||
120 | printf ("- - - - - - - - - - - - - - \n"); | ||
121 | #endif | ||
122 | } | ||
123 | |||
124 | static void AudioFilePlayer_SetStartFrame (AudioFilePlayer *afp, int frame) | ||
125 | { | ||
126 | SInt64 position = frame * 2352; | ||
127 | |||
128 | afp->mStartFrame = frame; | ||
129 | afp->mAudioFileManager->SetPosition (afp->mAudioFileManager, position); | ||
130 | } | ||
131 | |||
132 | |||
133 | static int AudioFilePlayer_GetCurrentFrame (AudioFilePlayer *afp) | ||
134 | { | ||
135 | return afp->mStartFrame + (afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) / 2352); | ||
136 | } | ||
137 | |||
138 | static void AudioFilePlayer_SetStopFrame (AudioFilePlayer *afp, int frame) | ||
139 | { | ||
140 | SInt64 position = frame * 2352; | ||
141 | |||
142 | afp->mAudioFileManager->SetEndOfFile (afp->mAudioFileManager, position); | ||
143 | } | ||
144 | |||
145 | void delete_AudioFilePlayer(AudioFilePlayer *afp) | ||
146 | { | ||
147 | if (afp != NULL) | ||
148 | { | ||
149 | afp->Disconnect(afp); | ||
150 | |||
151 | if (afp->mAudioFileManager) { | ||
152 | delete_AudioFileManager(afp->mAudioFileManager); | ||
153 | afp->mAudioFileManager = 0; | ||
154 | } | ||
155 | |||
156 | if (afp->mForkRefNum) { | ||
157 | FSCloseFork (afp->mForkRefNum); | ||
158 | afp->mForkRefNum = 0; | ||
159 | } | ||
160 | SDL_free(afp); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static int AudioFilePlayer_Connect(AudioFilePlayer *afp) | ||
165 | { | ||
166 | #if DEBUG | ||
167 | printf ("Connect:%x, engaged=%d\n", (int)afp->mPlayUnit, (afp->mConnected ? 1 : 0)); | ||
168 | #endif | ||
169 | if (!afp->mConnected) | ||
170 | { | ||
171 | if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager)) | ||
172 | return 0; | ||
173 | |||
174 | /* set the render callback for the file data to be supplied to the sound converter AU */ | ||
175 | afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc; | ||
176 | afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager; | ||
177 | |||
178 | OSStatus result = AudioUnitSetProperty (afp->mPlayUnit, | ||
179 | kAudioUnitProperty_SetRenderCallback, | ||
180 | kAudioUnitScope_Input, | ||
181 | 0, | ||
182 | &afp->mInputCallback, | ||
183 | sizeof(afp->mInputCallback)); | ||
184 | if (result) return 0; /*THROW_RESULT("AudioUnitSetProperty")*/ | ||
185 | afp->mConnected = 1; | ||
186 | } | ||
187 | |||
188 | return 1; | ||
189 | } | ||
190 | |||
191 | /* warning noted, now please go away ;-) */ | ||
192 | /* #warning This should redirect the calling of notification code to some other thread */ | ||
193 | static void AudioFilePlayer_DoNotification (AudioFilePlayer *afp, OSStatus inStatus) | ||
194 | { | ||
195 | if (afp->mNotifier) { | ||
196 | (*afp->mNotifier) (afp->mRefCon, inStatus); | ||
197 | } else { | ||
198 | SDL_SetError ("Notification posted with no notifier in place"); | ||
199 | |||
200 | if (inStatus == kAudioFilePlay_FileIsFinished) | ||
201 | afp->Disconnect(afp); | ||
202 | else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun) | ||
203 | afp->Disconnect(afp); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | static void AudioFilePlayer_Disconnect (AudioFilePlayer *afp) | ||
208 | { | ||
209 | #if DEBUG | ||
210 | printf ("Disconnect:%x,%ld, engaged=%d\n", (int)afp->mPlayUnit, 0, (afp->mConnected ? 1 : 0)); | ||
211 | #endif | ||
212 | if (afp->mConnected) | ||
213 | { | ||
214 | afp->mConnected = 0; | ||
215 | |||
216 | afp->mInputCallback.inputProc = 0; | ||
217 | afp->mInputCallback.inputProcRefCon = 0; | ||
218 | OSStatus result = AudioUnitSetProperty (afp->mPlayUnit, | ||
219 | kAudioUnitProperty_SetRenderCallback, | ||
220 | kAudioUnitScope_Input, | ||
221 | 0, | ||
222 | &afp->mInputCallback, | ||
223 | sizeof(afp->mInputCallback)); | ||
224 | if (result) | ||
225 | SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result); | ||
226 | |||
227 | afp->mAudioFileManager->Disconnect(afp->mAudioFileManager); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | typedef struct { | ||
232 | UInt32 offset; | ||
233 | UInt32 blockSize; | ||
234 | } SSNDData; | ||
235 | |||
236 | static int AudioFilePlayer_OpenFile (AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileDataSize) | ||
237 | { | ||
238 | ContainerChunk chunkHeader; | ||
239 | ChunkHeader chunk; | ||
240 | SSNDData ssndData; | ||
241 | |||
242 | OSErr result; | ||
243 | HFSUniStr255 dfName; | ||
244 | ByteCount actual; | ||
245 | SInt64 offset; | ||
246 | |||
247 | /* Open the data fork of the input file */ | ||
248 | result = FSGetDataForkName(&dfName); | ||
249 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName")*/ | ||
250 | |||
251 | result = FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm, &afp->mForkRefNum); | ||
252 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork")*/ | ||
253 | |||
254 | /* Read the file header, and check if it's indeed an AIFC file */ | ||
255 | result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual); | ||
256 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/ | ||
257 | |||
258 | if (SDL_SwapBE32(chunkHeader.ckID) != 'FORM') { | ||
259 | result = -1; | ||
260 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");*/ | ||
261 | } | ||
262 | |||
263 | if (SDL_SwapBE32(chunkHeader.formType) != 'AIFC') { | ||
264 | result = -1; | ||
265 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'");*/ | ||
266 | } | ||
267 | |||
268 | /* Search for the SSND chunk. We ignore all compression etc. information | ||
269 | in other chunks. Of course that is kind of evil, but for now we are lazy | ||
270 | and rely on the cdfs to always give us the same fixed format. | ||
271 | TODO: Parse the COMM chunk we currently skip to fill in mFileDescription. | ||
272 | */ | ||
273 | offset = 0; | ||
274 | do { | ||
275 | result = FSReadFork(afp->mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual); | ||
276 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/ | ||
277 | |||
278 | chunk.ckID = SDL_SwapBE32(chunk.ckID); | ||
279 | chunk.ckSize = SDL_SwapBE32(chunk.ckSize); | ||
280 | |||
281 | /* Skip the chunk data */ | ||
282 | offset = chunk.ckSize; | ||
283 | } while (chunk.ckID != 'SSND'); | ||
284 | |||
285 | /* Read the header of the SSND chunk. After this, we are positioned right | ||
286 | at the start of the audio data. */ | ||
287 | result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual); | ||
288 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/ | ||
289 | |||
290 | ssndData.offset = SDL_SwapBE32(ssndData.offset); | ||
291 | |||
292 | result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset); | ||
293 | if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition")*/ | ||
294 | |||
295 | /* Data size */ | ||
296 | *outFileDataSize = chunk.ckSize - ssndData.offset - 8; | ||
297 | |||
298 | /* File format */ | ||
299 | afp->mFileDescription.mSampleRate = 44100; | ||
300 | afp->mFileDescription.mFormatID = kAudioFormatLinearPCM; | ||
301 | afp->mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; | ||
302 | afp->mFileDescription.mBytesPerPacket = 4; | ||
303 | afp->mFileDescription.mFramesPerPacket = 1; | ||
304 | afp->mFileDescription.mBytesPerFrame = 4; | ||
305 | afp->mFileDescription.mChannelsPerFrame = 2; | ||
306 | afp->mFileDescription.mBitsPerChannel = 16; | ||
307 | |||
308 | return 1; | ||
309 | } | ||
310 | |||
311 | AudioFilePlayer *new_AudioFilePlayer (const FSRef *inFileRef) | ||
312 | { | ||
313 | SInt64 fileDataSize = 0; | ||
314 | |||
315 | AudioFilePlayer *afp = (AudioFilePlayer *) SDL_malloc(sizeof (AudioFilePlayer)); | ||
316 | if (afp == NULL) | ||
317 | return NULL; | ||
318 | SDL_memset(afp, '\0', sizeof (*afp)); | ||
319 | |||
320 | #define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m | ||
321 | SET_AUDIOFILEPLAYER_METHOD(SetDestination); | ||
322 | SET_AUDIOFILEPLAYER_METHOD(SetNotifier); | ||
323 | SET_AUDIOFILEPLAYER_METHOD(SetStartFrame); | ||
324 | SET_AUDIOFILEPLAYER_METHOD(GetCurrentFrame); | ||
325 | SET_AUDIOFILEPLAYER_METHOD(SetStopFrame); | ||
326 | SET_AUDIOFILEPLAYER_METHOD(Connect); | ||
327 | SET_AUDIOFILEPLAYER_METHOD(Disconnect); | ||
328 | SET_AUDIOFILEPLAYER_METHOD(DoNotification); | ||
329 | SET_AUDIOFILEPLAYER_METHOD(IsConnected); | ||
330 | SET_AUDIOFILEPLAYER_METHOD(GetDestUnit); | ||
331 | SET_AUDIOFILEPLAYER_METHOD(Print); | ||
332 | SET_AUDIOFILEPLAYER_METHOD(OpenFile); | ||
333 | #undef SET_AUDIOFILEPLAYER_METHOD | ||
334 | |||
335 | if (!afp->OpenFile (afp, inFileRef, &fileDataSize)) | ||
336 | { | ||
337 | SDL_free(afp); | ||
338 | return NULL; | ||
339 | } | ||
340 | |||
341 | /* we want about 4 seconds worth of data for the buffer */ | ||
342 | int bytesPerSecond = (UInt32) (4 * afp->mFileDescription.mSampleRate * afp->mFileDescription.mBytesPerFrame); | ||
343 | |||
344 | #if DEBUG | ||
345 | printf("File format:\n"); | ||
346 | PrintStreamDesc (&afp->mFileDescription); | ||
347 | #endif | ||
348 | |||
349 | afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum, | ||
350 | fileDataSize, | ||
351 | bytesPerSecond); | ||
352 | if (afp->mAudioFileManager == NULL) | ||
353 | { | ||
354 | delete_AudioFilePlayer(afp); | ||
355 | return NULL; | ||
356 | } | ||
357 | |||
358 | return afp; | ||
359 | } | ||
360 | |||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.h b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.h new file mode 100644 index 0000000000..886d017a59 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.h | |||
@@ -0,0 +1,178 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | |||
22 | This file based on Apple sample code. We haven't changed the file name, | ||
23 | so if you want to see the original search for it on apple.com/developer | ||
24 | */ | ||
25 | #include "SDL_config.h" | ||
26 | |||
27 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
28 | AudioFilePlayer.h | ||
29 | */ | ||
30 | #ifndef __AudioFilePlayer_H__ | ||
31 | #define __AudioFilePlayer_H__ | ||
32 | |||
33 | #include <CoreServices/CoreServices.h> | ||
34 | |||
35 | #include <AudioUnit/AudioUnit.h> | ||
36 | #if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050 | ||
37 | #include <AudioUnit/AUNTComponent.h> | ||
38 | #endif | ||
39 | |||
40 | #if (MAC_OS_X_VERSION_MAX_ALLOWED < 1050) | ||
41 | typedef SInt16 FSIORefNum; | ||
42 | #endif | ||
43 | |||
44 | #include "SDL_error.h" | ||
45 | |||
46 | const char* AudioFilePlayerErrorStr (OSStatus error); | ||
47 | |||
48 | /* | ||
49 | void ThrowResult (OSStatus result, const char *str); | ||
50 | |||
51 | #define THROW_RESULT(str) \ | ||
52 | if (result) { \ | ||
53 | ThrowResult (result, str); \ | ||
54 | } | ||
55 | */ | ||
56 | |||
57 | typedef void (*AudioFilePlayNotifier)(void *inRefCon, | ||
58 | OSStatus inStatus); | ||
59 | |||
60 | enum { | ||
61 | kAudioFilePlayErr_FilePlayUnderrun = -10000, | ||
62 | kAudioFilePlay_FileIsFinished = -10001, | ||
63 | kAudioFilePlay_PlayerIsUninitialized = -10002 | ||
64 | }; | ||
65 | |||
66 | |||
67 | struct S_AudioFileManager; | ||
68 | |||
69 | #pragma mark __________ AudioFilePlayer | ||
70 | typedef struct S_AudioFilePlayer | ||
71 | { | ||
72 | /*public:*/ | ||
73 | int (*SetDestination)(struct S_AudioFilePlayer *afp, AudioUnit *inDestUnit); | ||
74 | void (*SetNotifier)(struct S_AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon); | ||
75 | void (*SetStartFrame)(struct S_AudioFilePlayer *afp, int frame); /* seek in the file */ | ||
76 | int (*GetCurrentFrame)(struct S_AudioFilePlayer *afp); /* get the current frame position */ | ||
77 | void (*SetStopFrame)(struct S_AudioFilePlayer *afp, int frame); /* set limit in the file */ | ||
78 | int (*Connect)(struct S_AudioFilePlayer *afp); | ||
79 | void (*Disconnect)(struct S_AudioFilePlayer *afp); | ||
80 | void (*DoNotification)(struct S_AudioFilePlayer *afp, OSStatus inError); | ||
81 | int (*IsConnected)(struct S_AudioFilePlayer *afp); | ||
82 | AudioUnit (*GetDestUnit)(struct S_AudioFilePlayer *afp); | ||
83 | void (*Print)(struct S_AudioFilePlayer *afp); | ||
84 | |||
85 | /*private:*/ | ||
86 | AudioUnit mPlayUnit; | ||
87 | FSIORefNum mForkRefNum; | ||
88 | |||
89 | AURenderCallbackStruct mInputCallback; | ||
90 | |||
91 | AudioStreamBasicDescription mFileDescription; | ||
92 | |||
93 | int mConnected; | ||
94 | |||
95 | struct S_AudioFileManager* mAudioFileManager; | ||
96 | |||
97 | AudioFilePlayNotifier mNotifier; | ||
98 | void* mRefCon; | ||
99 | |||
100 | int mStartFrame; | ||
101 | |||
102 | #pragma mark __________ Private_Methods | ||
103 | |||
104 | int (*OpenFile)(struct S_AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileSize); | ||
105 | } AudioFilePlayer; | ||
106 | |||
107 | |||
108 | AudioFilePlayer *new_AudioFilePlayer(const FSRef *inFileRef); | ||
109 | void delete_AudioFilePlayer(AudioFilePlayer *afp); | ||
110 | |||
111 | |||
112 | |||
113 | #pragma mark __________ AudioFileManager | ||
114 | typedef struct S_AudioFileManager | ||
115 | { | ||
116 | /*public:*/ | ||
117 | /* this method should NOT be called by an object of this class | ||
118 | as it is called by the parent's Disconnect() method */ | ||
119 | void (*Disconnect)(struct S_AudioFileManager *afm); | ||
120 | int (*DoConnect)(struct S_AudioFileManager *afm); | ||
121 | OSStatus (*Read)(struct S_AudioFileManager *afm, char *buffer, ByteCount *len); | ||
122 | const char* (*GetFileBuffer)(struct S_AudioFileManager *afm); | ||
123 | const AudioFilePlayer *(*GetParent)(struct S_AudioFileManager *afm); | ||
124 | void (*SetPosition)(struct S_AudioFileManager *afm, SInt64 pos); /* seek/rewind in the file */ | ||
125 | int (*GetByteCounter)(struct S_AudioFileManager *afm); /* return actual bytes streamed to audio hardware */ | ||
126 | void (*SetEndOfFile)(struct S_AudioFileManager *afm, SInt64 pos); /* set the "EOF" (will behave just like it reached eof) */ | ||
127 | |||
128 | /*protected:*/ | ||
129 | AudioFilePlayer* mParent; | ||
130 | SInt16 mForkRefNum; | ||
131 | SInt64 mAudioDataOffset; | ||
132 | |||
133 | char* mFileBuffer; | ||
134 | |||
135 | int mByteCounter; | ||
136 | |||
137 | int mReadFromFirstBuffer; | ||
138 | int mLockUnsuccessful; | ||
139 | int mIsEngaged; | ||
140 | |||
141 | int mNumTimesAskedSinceFinished; | ||
142 | |||
143 | |||
144 | void* mTmpBuffer; | ||
145 | UInt32 mBufferSize; | ||
146 | UInt32 mBufferOffset; | ||
147 | /*public:*/ | ||
148 | UInt32 mChunkSize; | ||
149 | SInt64 mFileLength; | ||
150 | SInt64 mReadFilePosition; | ||
151 | int mWriteToFirstBuffer; | ||
152 | int mFinishedReadingData; | ||
153 | |||
154 | /*protected:*/ | ||
155 | OSStatus (*Render)(struct S_AudioFileManager *afm, AudioBufferList *ioData); | ||
156 | OSStatus (*GetFileData)(struct S_AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize); | ||
157 | void (*AfterRender)(struct S_AudioFileManager *afm); | ||
158 | |||
159 | /*public:*/ | ||
160 | /*static*/ | ||
161 | OSStatus (*FileInputProc)(void *inRefCon, | ||
162 | AudioUnitRenderActionFlags *ioActionFlags, | ||
163 | const AudioTimeStamp *inTimeStamp, | ||
164 | UInt32 inBusNumber, | ||
165 | UInt32 inNumberFrames, | ||
166 | AudioBufferList *ioData); | ||
167 | } AudioFileManager; | ||
168 | |||
169 | |||
170 | AudioFileManager *new_AudioFileManager (AudioFilePlayer *inParent, | ||
171 | SInt16 inForkRefNum, | ||
172 | SInt64 inFileLength, | ||
173 | UInt32 inChunkSize); | ||
174 | |||
175 | void delete_AudioFileManager(AudioFileManager *afm); | ||
176 | |||
177 | #endif | ||
178 | |||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/AudioFileReaderThread.c b/apps/plugins/sdl/src/cdrom/macosx/AudioFileReaderThread.c new file mode 100644 index 0000000000..0007c07f61 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/AudioFileReaderThread.c | |||
@@ -0,0 +1,610 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | |||
22 | This file based on Apple sample code. We haven't changed the file name, | ||
23 | so if you want to see the original search for it on apple.com/developer | ||
24 | */ | ||
25 | #include "SDL_config.h" | ||
26 | |||
27 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
28 | AudioFileManager.cpp | ||
29 | */ | ||
30 | #include "AudioFilePlayer.h" | ||
31 | #include <mach/mach.h> /* used for setting policy of thread */ | ||
32 | #include "SDLOSXCAGuard.h" | ||
33 | #include <pthread.h> | ||
34 | |||
35 | /*#include <list>*/ | ||
36 | |||
37 | /*typedef void *FileData;*/ | ||
38 | typedef struct S_FileData | ||
39 | { | ||
40 | AudioFileManager *obj; | ||
41 | struct S_FileData *next; | ||
42 | } FileData; | ||
43 | |||
44 | |||
45 | typedef struct S_FileReaderThread { | ||
46 | /*public:*/ | ||
47 | SDLOSXCAGuard* (*GetGuard)(struct S_FileReaderThread *frt); | ||
48 | void (*AddReader)(struct S_FileReaderThread *frt); | ||
49 | void (*RemoveReader)(struct S_FileReaderThread *frt, AudioFileManager* inItem); | ||
50 | int (*TryNextRead)(struct S_FileReaderThread *frt, AudioFileManager* inItem); | ||
51 | |||
52 | int mThreadShouldDie; | ||
53 | |||
54 | /*private:*/ | ||
55 | /*typedef std::list<AudioFileManager*> FileData;*/ | ||
56 | |||
57 | SDLOSXCAGuard *mGuard; | ||
58 | UInt32 mThreadPriority; | ||
59 | |||
60 | int mNumReaders; | ||
61 | FileData *mFileData; | ||
62 | |||
63 | |||
64 | void (*ReadNextChunk)(struct S_FileReaderThread *frt); | ||
65 | int (*StartFixedPriorityThread)(struct S_FileReaderThread *frt); | ||
66 | /*static*/ | ||
67 | UInt32 (*GetThreadBasePriority)(pthread_t inThread); | ||
68 | /*static*/ | ||
69 | void* (*DiskReaderEntry)(void *inRefCon); | ||
70 | } FileReaderThread; | ||
71 | |||
72 | |||
73 | static SDLOSXCAGuard* FileReaderThread_GetGuard(FileReaderThread *frt) | ||
74 | { | ||
75 | return frt->mGuard; | ||
76 | } | ||
77 | |||
78 | /* returns 1 if succeeded */ | ||
79 | static int FileReaderThread_TryNextRead (FileReaderThread *frt, AudioFileManager* inItem) | ||
80 | { | ||
81 | int didLock = 0; | ||
82 | int succeeded = 0; | ||
83 | if (frt->mGuard->Try(frt->mGuard, &didLock)) | ||
84 | { | ||
85 | /*frt->mFileData.push_back (inItem);*/ | ||
86 | /* !!! FIXME: this could be faster with a "tail" member. --ryan. */ | ||
87 | FileData *i = frt->mFileData; | ||
88 | FileData *prev = NULL; | ||
89 | |||
90 | FileData *newfd = (FileData *) SDL_malloc(sizeof (FileData)); | ||
91 | newfd->obj = inItem; | ||
92 | newfd->next = NULL; | ||
93 | |||
94 | while (i != NULL) { prev = i; i = i->next; } | ||
95 | if (prev == NULL) | ||
96 | frt->mFileData = newfd; | ||
97 | else | ||
98 | prev->next = newfd; | ||
99 | |||
100 | frt->mGuard->Notify(frt->mGuard); | ||
101 | succeeded = 1; | ||
102 | |||
103 | if (didLock) | ||
104 | frt->mGuard->Unlock(frt->mGuard); | ||
105 | } | ||
106 | |||
107 | return succeeded; | ||
108 | } | ||
109 | |||
110 | static void FileReaderThread_AddReader(FileReaderThread *frt) | ||
111 | { | ||
112 | if (frt->mNumReaders == 0) | ||
113 | { | ||
114 | frt->mThreadShouldDie = 0; | ||
115 | frt->StartFixedPriorityThread (frt); | ||
116 | } | ||
117 | frt->mNumReaders++; | ||
118 | } | ||
119 | |||
120 | static void FileReaderThread_RemoveReader (FileReaderThread *frt, AudioFileManager* inItem) | ||
121 | { | ||
122 | if (frt->mNumReaders > 0) | ||
123 | { | ||
124 | int bNeedsRelease = frt->mGuard->Lock(frt->mGuard); | ||
125 | |||
126 | /*frt->mFileData.remove (inItem);*/ | ||
127 | FileData *i = frt->mFileData; | ||
128 | FileData *prev = NULL; | ||
129 | while (i != NULL) | ||
130 | { | ||
131 | FileData *next = i->next; | ||
132 | if (i->obj != inItem) | ||
133 | prev = i; | ||
134 | else | ||
135 | { | ||
136 | if (prev == NULL) | ||
137 | frt->mFileData = next; | ||
138 | else | ||
139 | prev->next = next; | ||
140 | SDL_free(i); | ||
141 | } | ||
142 | i = next; | ||
143 | } | ||
144 | |||
145 | if (--frt->mNumReaders == 0) { | ||
146 | frt->mThreadShouldDie = 1; | ||
147 | frt->mGuard->Notify(frt->mGuard); /* wake up thread so it will quit */ | ||
148 | frt->mGuard->Wait(frt->mGuard); /* wait for thread to die */ | ||
149 | } | ||
150 | |||
151 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static int FileReaderThread_StartFixedPriorityThread (FileReaderThread *frt) | ||
156 | { | ||
157 | pthread_attr_t theThreadAttrs; | ||
158 | pthread_t pThread; | ||
159 | |||
160 | OSStatus result = pthread_attr_init(&theThreadAttrs); | ||
161 | if (result) return 0; /*THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")*/ | ||
162 | |||
163 | result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED); | ||
164 | if (result) return 0; /*THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")*/ | ||
165 | |||
166 | result = pthread_create (&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt); | ||
167 | if (result) return 0; /*THROW_RESULT("pthread_create - Create and start the thread.")*/ | ||
168 | |||
169 | pthread_attr_destroy(&theThreadAttrs); | ||
170 | |||
171 | /* we've now created the thread and started it | ||
172 | we'll now set the priority of the thread to the nominated priority | ||
173 | and we'll also make the thread fixed */ | ||
174 | thread_extended_policy_data_t theFixedPolicy; | ||
175 | thread_precedence_policy_data_t thePrecedencePolicy; | ||
176 | SInt32 relativePriority; | ||
177 | |||
178 | /* make thread fixed */ | ||
179 | theFixedPolicy.timeshare = 0; /* set to 1 for a non-fixed thread */ | ||
180 | result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); | ||
181 | if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")*/ | ||
182 | /* set priority */ | ||
183 | /* precedency policy's "importance" value is relative to spawning thread's priority */ | ||
184 | relativePriority = frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self()); | ||
185 | |||
186 | thePrecedencePolicy.importance = relativePriority; | ||
187 | result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT); | ||
188 | if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread priority.")*/ | ||
189 | |||
190 | return 1; | ||
191 | } | ||
192 | |||
193 | static UInt32 FileReaderThread_GetThreadBasePriority (pthread_t inThread) | ||
194 | { | ||
195 | thread_basic_info_data_t threadInfo; | ||
196 | policy_info_data_t thePolicyInfo; | ||
197 | unsigned int count; | ||
198 | |||
199 | /* get basic info */ | ||
200 | count = THREAD_BASIC_INFO_COUNT; | ||
201 | thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count); | ||
202 | |||
203 | switch (threadInfo.policy) { | ||
204 | case POLICY_TIMESHARE: | ||
205 | count = POLICY_TIMESHARE_INFO_COUNT; | ||
206 | thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count); | ||
207 | return thePolicyInfo.ts.base_priority; | ||
208 | break; | ||
209 | |||
210 | case POLICY_FIFO: | ||
211 | count = POLICY_FIFO_INFO_COUNT; | ||
212 | thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count); | ||
213 | if (thePolicyInfo.fifo.depressed) { | ||
214 | return thePolicyInfo.fifo.depress_priority; | ||
215 | } else { | ||
216 | return thePolicyInfo.fifo.base_priority; | ||
217 | } | ||
218 | break; | ||
219 | |||
220 | case POLICY_RR: | ||
221 | count = POLICY_RR_INFO_COUNT; | ||
222 | thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count); | ||
223 | if (thePolicyInfo.rr.depressed) { | ||
224 | return thePolicyInfo.rr.depress_priority; | ||
225 | } else { | ||
226 | return thePolicyInfo.rr.base_priority; | ||
227 | } | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static void *FileReaderThread_DiskReaderEntry (void *inRefCon) | ||
235 | { | ||
236 | FileReaderThread *frt = (FileReaderThread *)inRefCon; | ||
237 | frt->ReadNextChunk(frt); | ||
238 | #if DEBUG | ||
239 | printf ("finished with reading file\n"); | ||
240 | #endif | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static void FileReaderThread_ReadNextChunk (FileReaderThread *frt) | ||
246 | { | ||
247 | OSStatus result; | ||
248 | ByteCount dataChunkSize; | ||
249 | AudioFileManager* theItem = 0; | ||
250 | |||
251 | for (;;) | ||
252 | { | ||
253 | { /* this is a scoped based lock */ | ||
254 | int bNeedsRelease = frt->mGuard->Lock(frt->mGuard); | ||
255 | |||
256 | if (frt->mThreadShouldDie) { | ||
257 | frt->mGuard->Notify(frt->mGuard); | ||
258 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | /*if (frt->mFileData.empty())*/ | ||
263 | if (frt->mFileData == NULL) | ||
264 | { | ||
265 | frt->mGuard->Wait(frt->mGuard); | ||
266 | } | ||
267 | |||
268 | /* kill thread */ | ||
269 | if (frt->mThreadShouldDie) { | ||
270 | |||
271 | frt->mGuard->Notify(frt->mGuard); | ||
272 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); | ||
273 | return; | ||
274 | } | ||
275 | |||
276 | /*theItem = frt->mFileData.front();*/ | ||
277 | /*frt->mFileData.pop_front();*/ | ||
278 | theItem = NULL; | ||
279 | if (frt->mFileData != NULL) | ||
280 | { | ||
281 | FileData *next = frt->mFileData->next; | ||
282 | theItem = frt->mFileData->obj; | ||
283 | SDL_free(frt->mFileData); | ||
284 | frt->mFileData = next; | ||
285 | } | ||
286 | |||
287 | if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard); | ||
288 | } | ||
289 | |||
290 | if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize) | ||
291 | dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition; | ||
292 | else | ||
293 | dataChunkSize = theItem->mChunkSize; | ||
294 | |||
295 | /* this is the exit condition for the thread */ | ||
296 | if (dataChunkSize <= 0) { | ||
297 | theItem->mFinishedReadingData = 1; | ||
298 | continue; | ||
299 | } | ||
300 | /* construct pointer */ | ||
301 | char* writePtr = (char *) (theItem->GetFileBuffer(theItem) + | ||
302 | (theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize)); | ||
303 | |||
304 | /* read data */ | ||
305 | result = theItem->Read(theItem, writePtr, &dataChunkSize); | ||
306 | if (result != noErr && result != eofErr) { | ||
307 | AudioFilePlayer *afp = (AudioFilePlayer *) theItem->GetParent(theItem); | ||
308 | afp->DoNotification(afp, result); | ||
309 | continue; | ||
310 | } | ||
311 | |||
312 | if (dataChunkSize != theItem->mChunkSize) | ||
313 | { | ||
314 | writePtr += dataChunkSize; | ||
315 | |||
316 | /* can't exit yet.. we still have to pass the partial buffer back */ | ||
317 | SDL_memset(writePtr, 0, (theItem->mChunkSize - dataChunkSize)); | ||
318 | } | ||
319 | |||
320 | theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; /* switch buffers */ | ||
321 | |||
322 | if (result == eofErr) | ||
323 | theItem->mReadFilePosition = theItem->mFileLength; | ||
324 | else | ||
325 | theItem->mReadFilePosition += dataChunkSize; /* increment count */ | ||
326 | } | ||
327 | } | ||
328 | |||
329 | void delete_FileReaderThread(FileReaderThread *frt) | ||
330 | { | ||
331 | if (frt != NULL) | ||
332 | { | ||
333 | delete_SDLOSXCAGuard(frt->mGuard); | ||
334 | SDL_free(frt); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | FileReaderThread *new_FileReaderThread () | ||
339 | { | ||
340 | FileReaderThread *frt = (FileReaderThread *) SDL_malloc(sizeof (FileReaderThread)); | ||
341 | if (frt == NULL) | ||
342 | return NULL; | ||
343 | SDL_memset(frt, '\0', sizeof (*frt)); | ||
344 | |||
345 | frt->mGuard = new_SDLOSXCAGuard(); | ||
346 | if (frt->mGuard == NULL) | ||
347 | { | ||
348 | SDL_free(frt); | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | #define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m | ||
353 | SET_FILEREADERTHREAD_METHOD(GetGuard); | ||
354 | SET_FILEREADERTHREAD_METHOD(AddReader); | ||
355 | SET_FILEREADERTHREAD_METHOD(RemoveReader); | ||
356 | SET_FILEREADERTHREAD_METHOD(TryNextRead); | ||
357 | SET_FILEREADERTHREAD_METHOD(ReadNextChunk); | ||
358 | SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread); | ||
359 | SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority); | ||
360 | SET_FILEREADERTHREAD_METHOD(DiskReaderEntry); | ||
361 | #undef SET_FILEREADERTHREAD_METHOD | ||
362 | |||
363 | frt->mThreadPriority = 62; | ||
364 | return frt; | ||
365 | } | ||
366 | |||
367 | |||
368 | static FileReaderThread *sReaderThread; | ||
369 | |||
370 | |||
371 | static int AudioFileManager_DoConnect (AudioFileManager *afm) | ||
372 | { | ||
373 | if (!afm->mIsEngaged) | ||
374 | { | ||
375 | OSStatus result; | ||
376 | |||
377 | /*afm->mReadFilePosition = 0;*/ | ||
378 | afm->mFinishedReadingData = 0; | ||
379 | |||
380 | afm->mNumTimesAskedSinceFinished = 0; | ||
381 | afm->mLockUnsuccessful = 0; | ||
382 | |||
383 | ByteCount dataChunkSize; | ||
384 | |||
385 | if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize) | ||
386 | dataChunkSize = afm->mFileLength - afm->mReadFilePosition; | ||
387 | else | ||
388 | dataChunkSize = afm->mChunkSize; | ||
389 | |||
390 | result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize); | ||
391 | if (result) return 0; /*THROW_RESULT("AudioFileManager::DoConnect(): Read")*/ | ||
392 | |||
393 | afm->mReadFilePosition += dataChunkSize; | ||
394 | |||
395 | afm->mWriteToFirstBuffer = 0; | ||
396 | afm->mReadFromFirstBuffer = 1; | ||
397 | |||
398 | sReaderThread->AddReader(sReaderThread); | ||
399 | |||
400 | afm->mIsEngaged = 1; | ||
401 | } | ||
402 | /* | ||
403 | else | ||
404 | throw static_cast<OSStatus>(-1); */ /* thread has already been started */ | ||
405 | |||
406 | return 1; | ||
407 | } | ||
408 | |||
409 | static void AudioFileManager_Disconnect (AudioFileManager *afm) | ||
410 | { | ||
411 | if (afm->mIsEngaged) | ||
412 | { | ||
413 | sReaderThread->RemoveReader (sReaderThread, afm); | ||
414 | afm->mIsEngaged = 0; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | static OSStatus AudioFileManager_Read(AudioFileManager *afm, char *buffer, ByteCount *len) | ||
419 | { | ||
420 | return FSReadFork (afm->mForkRefNum, | ||
421 | fsFromStart, | ||
422 | afm->mReadFilePosition + afm->mAudioDataOffset, | ||
423 | *len, | ||
424 | buffer, | ||
425 | len); | ||
426 | } | ||
427 | |||
428 | static OSStatus AudioFileManager_GetFileData (AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize) | ||
429 | { | ||
430 | if (afm->mFinishedReadingData) | ||
431 | { | ||
432 | ++afm->mNumTimesAskedSinceFinished; | ||
433 | *inOutDataSize = 0; | ||
434 | *inOutData = 0; | ||
435 | return noErr; | ||
436 | } | ||
437 | |||
438 | if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) { | ||
439 | #if DEBUG | ||
440 | printf ("* * * * * * * Can't keep up with reading file\n"); | ||
441 | #endif | ||
442 | |||
443 | afm->mParent->DoNotification (afm->mParent, kAudioFilePlayErr_FilePlayUnderrun); | ||
444 | *inOutDataSize = 0; | ||
445 | *inOutData = 0; | ||
446 | } else { | ||
447 | *inOutDataSize = afm->mChunkSize; | ||
448 | *inOutData = afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer + afm->mChunkSize); | ||
449 | } | ||
450 | |||
451 | afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm); | ||
452 | |||
453 | afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer; | ||
454 | |||
455 | return noErr; | ||
456 | } | ||
457 | |||
458 | static void AudioFileManager_AfterRender (AudioFileManager *afm) | ||
459 | { | ||
460 | if (afm->mNumTimesAskedSinceFinished > 0) | ||
461 | { | ||
462 | int didLock = 0; | ||
463 | SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread); | ||
464 | if (guard->Try(guard, &didLock)) { | ||
465 | afm->mParent->DoNotification (afm->mParent, kAudioFilePlay_FileIsFinished); | ||
466 | if (didLock) | ||
467 | guard->Unlock(guard); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | if (afm->mLockUnsuccessful) | ||
472 | afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm); | ||
473 | } | ||
474 | |||
475 | static void AudioFileManager_SetPosition (AudioFileManager *afm, SInt64 pos) | ||
476 | { | ||
477 | if (pos < 0 || pos >= afm->mFileLength) { | ||
478 | SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n", | ||
479 | (unsigned int)pos, (unsigned int)afm->mFileLength); | ||
480 | pos = 0; | ||
481 | } | ||
482 | |||
483 | afm->mReadFilePosition = pos; | ||
484 | } | ||
485 | |||
486 | static void AudioFileManager_SetEndOfFile (AudioFileManager *afm, SInt64 pos) | ||
487 | { | ||
488 | if (pos <= 0 || pos > afm->mFileLength) { | ||
489 | SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n"); | ||
490 | pos = afm->mFileLength; | ||
491 | } | ||
492 | |||
493 | afm->mFileLength = pos; | ||
494 | } | ||
495 | |||
496 | static const char *AudioFileManager_GetFileBuffer(AudioFileManager *afm) | ||
497 | { | ||
498 | return afm->mFileBuffer; | ||
499 | } | ||
500 | |||
501 | const AudioFilePlayer *AudioFileManager_GetParent(AudioFileManager *afm) | ||
502 | { | ||
503 | return afm->mParent; | ||
504 | } | ||
505 | |||
506 | static int AudioFileManager_GetByteCounter(AudioFileManager *afm) | ||
507 | { | ||
508 | return afm->mByteCounter; | ||
509 | } | ||
510 | |||
511 | static OSStatus AudioFileManager_FileInputProc (void *inRefCon, | ||
512 | AudioUnitRenderActionFlags *ioActionFlags, | ||
513 | const AudioTimeStamp *inTimeStamp, | ||
514 | UInt32 inBusNumber, | ||
515 | UInt32 inNumberFrames, | ||
516 | AudioBufferList *ioData) | ||
517 | { | ||
518 | AudioFileManager* afm = (AudioFileManager*)inRefCon; | ||
519 | return afm->Render(afm, ioData); | ||
520 | } | ||
521 | |||
522 | static OSStatus AudioFileManager_Render (AudioFileManager *afm, AudioBufferList *ioData) | ||
523 | { | ||
524 | OSStatus result = noErr; | ||
525 | AudioBuffer *abuf; | ||
526 | UInt32 i; | ||
527 | |||
528 | for (i = 0; i < ioData->mNumberBuffers; i++) { | ||
529 | abuf = &ioData->mBuffers[i]; | ||
530 | if (afm->mBufferOffset >= afm->mBufferSize) { | ||
531 | result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize); | ||
532 | if (result) { | ||
533 | SDL_SetError ("AudioConverterFillBuffer:%ld\n", result); | ||
534 | afm->mParent->DoNotification(afm->mParent, result); | ||
535 | return result; | ||
536 | } | ||
537 | |||
538 | afm->mBufferOffset = 0; | ||
539 | } | ||
540 | |||
541 | if (abuf->mDataByteSize > afm->mBufferSize - afm->mBufferOffset) | ||
542 | abuf->mDataByteSize = afm->mBufferSize - afm->mBufferOffset; | ||
543 | abuf->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset; | ||
544 | afm->mBufferOffset += abuf->mDataByteSize; | ||
545 | |||
546 | afm->mByteCounter += abuf->mDataByteSize; | ||
547 | afm->AfterRender(afm); | ||
548 | } | ||
549 | return result; | ||
550 | } | ||
551 | |||
552 | |||
553 | void delete_AudioFileManager (AudioFileManager *afm) | ||
554 | { | ||
555 | if (afm != NULL) { | ||
556 | if (afm->mFileBuffer) { | ||
557 | free(afm->mFileBuffer); | ||
558 | } | ||
559 | |||
560 | SDL_free(afm); | ||
561 | } | ||
562 | } | ||
563 | |||
564 | |||
565 | AudioFileManager *new_AudioFileManager(AudioFilePlayer *inParent, | ||
566 | SInt16 inForkRefNum, | ||
567 | SInt64 inFileLength, | ||
568 | UInt32 inChunkSize) | ||
569 | { | ||
570 | AudioFileManager *afm; | ||
571 | |||
572 | if (sReaderThread == NULL) | ||
573 | { | ||
574 | sReaderThread = new_FileReaderThread(); | ||
575 | if (sReaderThread == NULL) | ||
576 | return NULL; | ||
577 | } | ||
578 | |||
579 | afm = (AudioFileManager *) SDL_malloc(sizeof (AudioFileManager)); | ||
580 | if (afm == NULL) | ||
581 | return NULL; | ||
582 | SDL_memset(afm, '\0', sizeof (*afm)); | ||
583 | |||
584 | #define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m | ||
585 | SET_AUDIOFILEMANAGER_METHOD(Disconnect); | ||
586 | SET_AUDIOFILEMANAGER_METHOD(DoConnect); | ||
587 | SET_AUDIOFILEMANAGER_METHOD(Read); | ||
588 | SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer); | ||
589 | SET_AUDIOFILEMANAGER_METHOD(GetParent); | ||
590 | SET_AUDIOFILEMANAGER_METHOD(SetPosition); | ||
591 | SET_AUDIOFILEMANAGER_METHOD(GetByteCounter); | ||
592 | SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile); | ||
593 | SET_AUDIOFILEMANAGER_METHOD(Render); | ||
594 | SET_AUDIOFILEMANAGER_METHOD(GetFileData); | ||
595 | SET_AUDIOFILEMANAGER_METHOD(AfterRender); | ||
596 | SET_AUDIOFILEMANAGER_METHOD(FileInputProc); | ||
597 | #undef SET_AUDIOFILEMANAGER_METHOD | ||
598 | |||
599 | afm->mParent = inParent; | ||
600 | afm->mForkRefNum = inForkRefNum; | ||
601 | afm->mBufferSize = inChunkSize; | ||
602 | afm->mBufferOffset = inChunkSize; | ||
603 | afm->mChunkSize = inChunkSize; | ||
604 | afm->mFileLength = inFileLength; | ||
605 | afm->mFileBuffer = (char*) SDL_malloc(afm->mChunkSize * 2); | ||
606 | FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset); | ||
607 | assert (afm->mFileBuffer != NULL); | ||
608 | return afm; | ||
609 | } | ||
610 | |||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.c b/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.c new file mode 100644 index 0000000000..beb87cd85b --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #include "CDPlayer.h" | ||
25 | #include "AudioFilePlayer.h" | ||
26 | #include "SDLOSXCAGuard.h" | ||
27 | |||
28 | /* we're exporting these functions into C land for SDL_syscdrom.c */ | ||
29 | /*extern "C" {*/ | ||
30 | |||
31 | /*/////////////////////////////////////////////////////////////////////////// | ||
32 | Constants | ||
33 | //////////////////////////////////////////////////////////////////////////*/ | ||
34 | |||
35 | #define kAudioCDFilesystemID (UInt16)(('J' << 8) | 'H') /* 'JH'; this avoids compiler warning */ | ||
36 | |||
37 | /* XML PList keys */ | ||
38 | #define kRawTOCDataString "Format 0x02 TOC Data" | ||
39 | #define kSessionsString "Sessions" | ||
40 | #define kSessionTypeString "Session Type" | ||
41 | #define kTrackArrayString "Track Array" | ||
42 | #define kFirstTrackInSessionString "First Track" | ||
43 | #define kLastTrackInSessionString "Last Track" | ||
44 | #define kLeadoutBlockString "Leadout Block" | ||
45 | #define kDataKeyString "Data" | ||
46 | #define kPointKeyString "Point" | ||
47 | #define kSessionNumberKeyString "Session Number" | ||
48 | #define kStartBlockKeyString "Start Block" | ||
49 | |||
50 | /*/////////////////////////////////////////////////////////////////////////// | ||
51 | Globals | ||
52 | //////////////////////////////////////////////////////////////////////////*/ | ||
53 | |||
54 | #pragma mark -- Globals -- | ||
55 | |||
56 | static int playBackWasInit = 0; | ||
57 | static AudioUnit theUnit; | ||
58 | static AudioFilePlayer* thePlayer = NULL; | ||
59 | static CDPlayerCompletionProc completionProc = NULL; | ||
60 | static SDL_mutex *apiMutex = NULL; | ||
61 | static SDL_sem *callbackSem; | ||
62 | static SDL_CD* theCDROM; | ||
63 | |||
64 | /*/////////////////////////////////////////////////////////////////////////// | ||
65 | Prototypes | ||
66 | //////////////////////////////////////////////////////////////////////////*/ | ||
67 | |||
68 | #pragma mark -- Prototypes -- | ||
69 | |||
70 | static OSStatus CheckInit (); | ||
71 | |||
72 | static void FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus); | ||
73 | |||
74 | static int RunCallBackThread (void* inRefCon); | ||
75 | |||
76 | |||
77 | #pragma mark -- Public Functions -- | ||
78 | |||
79 | void Lock () | ||
80 | { | ||
81 | if (!apiMutex) { | ||
82 | apiMutex = SDL_CreateMutex(); | ||
83 | } | ||
84 | SDL_mutexP(apiMutex); | ||
85 | } | ||
86 | |||
87 | void Unlock () | ||
88 | { | ||
89 | SDL_mutexV(apiMutex); | ||
90 | } | ||
91 | |||
92 | int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes) | ||
93 | { | ||
94 | int volumeIndex; | ||
95 | int cdVolumeCount = 0; | ||
96 | OSStatus result = noErr; | ||
97 | |||
98 | for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++) | ||
99 | { | ||
100 | FSVolumeRefNum actualVolume; | ||
101 | FSVolumeInfo volumeInfo; | ||
102 | |||
103 | memset (&volumeInfo, 0, sizeof(volumeInfo)); | ||
104 | |||
105 | result = FSGetVolumeInfo (kFSInvalidVolumeRefNum, | ||
106 | volumeIndex, | ||
107 | &actualVolume, | ||
108 | kFSVolInfoFSInfo, | ||
109 | &volumeInfo, | ||
110 | NULL, | ||
111 | NULL); | ||
112 | |||
113 | if (result == noErr) | ||
114 | { | ||
115 | if (volumeInfo.filesystemID == kAudioCDFilesystemID) /* It's an audio CD */ | ||
116 | { | ||
117 | if (volumes != NULL && cdVolumeCount < numVolumes) | ||
118 | volumes[cdVolumeCount] = actualVolume; | ||
119 | |||
120 | cdVolumeCount++; | ||
121 | } | ||
122 | } | ||
123 | else | ||
124 | { | ||
125 | /* I'm commenting this out because it seems to be harmless */ | ||
126 | /*SDL_SetError ("DetectAudioCDVolumes: FSGetVolumeInfo returned %d", result);*/ | ||
127 | } | ||
128 | } | ||
129 | |||
130 | return cdVolumeCount; | ||
131 | } | ||
132 | |||
133 | int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD) | ||
134 | { | ||
135 | HFSUniStr255 dataForkName; | ||
136 | OSStatus theErr; | ||
137 | FSIORefNum forkRefNum; | ||
138 | SInt64 forkSize; | ||
139 | Ptr forkData = 0; | ||
140 | ByteCount actualRead; | ||
141 | CFDataRef dataRef = 0; | ||
142 | CFPropertyListRef propertyListRef = 0; | ||
143 | FSRefParam fsRefPB; | ||
144 | FSRef tocPlistFSRef; | ||
145 | FSRef rootRef; | ||
146 | const char* error = "Unspecified Error"; | ||
147 | const UniChar uniName[] = { '.','T','O','C','.','p','l','i','s','t' }; | ||
148 | |||
149 | theErr = FSGetVolumeInfo(theVolume, 0, 0, kFSVolInfoNone, 0, 0, &rootRef); | ||
150 | if(theErr != noErr) { | ||
151 | error = "FSGetVolumeInfo"; | ||
152 | goto bail; | ||
153 | } | ||
154 | |||
155 | SDL_memset(&fsRefPB, '\0', sizeof (fsRefPB)); | ||
156 | |||
157 | /* get stuff from .TOC.plist */ | ||
158 | fsRefPB.ref = &rootRef; | ||
159 | fsRefPB.newRef = &tocPlistFSRef; | ||
160 | fsRefPB.nameLength = sizeof (uniName) / sizeof (uniName[0]); | ||
161 | fsRefPB.name = uniName; | ||
162 | fsRefPB.textEncodingHint = kTextEncodingUnknown; | ||
163 | |||
164 | theErr = PBMakeFSRefUnicodeSync (&fsRefPB); | ||
165 | if(theErr != noErr) { | ||
166 | error = "PBMakeFSRefUnicodeSync"; | ||
167 | goto bail; | ||
168 | } | ||
169 | |||
170 | /* Load and parse the TOC XML data */ | ||
171 | |||
172 | theErr = FSGetDataForkName (&dataForkName); | ||
173 | if (theErr != noErr) { | ||
174 | error = "FSGetDataForkName"; | ||
175 | goto bail; | ||
176 | } | ||
177 | |||
178 | theErr = FSOpenFork (&tocPlistFSRef, dataForkName.length, dataForkName.unicode, fsRdPerm, &forkRefNum); | ||
179 | if (theErr != noErr) { | ||
180 | error = "FSOpenFork"; | ||
181 | goto bail; | ||
182 | } | ||
183 | |||
184 | theErr = FSGetForkSize (forkRefNum, &forkSize); | ||
185 | if (theErr != noErr) { | ||
186 | error = "FSGetForkSize"; | ||
187 | goto bail; | ||
188 | } | ||
189 | |||
190 | /* Allocate some memory for the XML data */ | ||
191 | forkData = NewPtr (forkSize); | ||
192 | if(forkData == NULL) { | ||
193 | error = "NewPtr"; | ||
194 | goto bail; | ||
195 | } | ||
196 | |||
197 | theErr = FSReadFork (forkRefNum, fsFromStart, 0 /* offset location */, forkSize, forkData, &actualRead); | ||
198 | if(theErr != noErr) { | ||
199 | error = "FSReadFork"; | ||
200 | goto bail; | ||
201 | } | ||
202 | |||
203 | dataRef = CFDataCreate (kCFAllocatorDefault, (UInt8 *)forkData, forkSize); | ||
204 | if(dataRef == 0) { | ||
205 | error = "CFDataCreate"; | ||
206 | goto bail; | ||
207 | } | ||
208 | |||
209 | propertyListRef = CFPropertyListCreateFromXMLData (kCFAllocatorDefault, | ||
210 | dataRef, | ||
211 | kCFPropertyListImmutable, | ||
212 | NULL); | ||
213 | if (propertyListRef == NULL) { | ||
214 | error = "CFPropertyListCreateFromXMLData"; | ||
215 | goto bail; | ||
216 | } | ||
217 | |||
218 | /* Now we got the Property List in memory. Parse it. */ | ||
219 | |||
220 | /* First, make sure the root item is a CFDictionary. If not, release and bail. */ | ||
221 | if(CFGetTypeID(propertyListRef)== CFDictionaryGetTypeID()) | ||
222 | { | ||
223 | CFDictionaryRef dictRef = (CFDictionaryRef)propertyListRef; | ||
224 | |||
225 | CFDataRef theRawTOCDataRef; | ||
226 | CFArrayRef theSessionArrayRef; | ||
227 | CFIndex numSessions; | ||
228 | CFIndex index; | ||
229 | |||
230 | /* This is how we get the Raw TOC Data */ | ||
231 | theRawTOCDataRef = (CFDataRef)CFDictionaryGetValue (dictRef, CFSTR(kRawTOCDataString)); | ||
232 | |||
233 | /* Get the session array info. */ | ||
234 | theSessionArrayRef = (CFArrayRef)CFDictionaryGetValue (dictRef, CFSTR(kSessionsString)); | ||
235 | |||
236 | /* Find out how many sessions there are. */ | ||
237 | numSessions = CFArrayGetCount (theSessionArrayRef); | ||
238 | |||
239 | /* Initialize the total number of tracks to 0 */ | ||
240 | theCD->numtracks = 0; | ||
241 | |||
242 | /* Iterate over all sessions, collecting the track data */ | ||
243 | for(index = 0; index < numSessions; index++) | ||
244 | { | ||
245 | CFDictionaryRef theSessionDict; | ||
246 | CFNumberRef leadoutBlock; | ||
247 | CFArrayRef trackArray; | ||
248 | CFIndex numTracks; | ||
249 | CFIndex trackIndex; | ||
250 | UInt32 value = 0; | ||
251 | |||
252 | theSessionDict = (CFDictionaryRef) CFArrayGetValueAtIndex (theSessionArrayRef, index); | ||
253 | leadoutBlock = (CFNumberRef) CFDictionaryGetValue (theSessionDict, CFSTR(kLeadoutBlockString)); | ||
254 | |||
255 | trackArray = (CFArrayRef)CFDictionaryGetValue (theSessionDict, CFSTR(kTrackArrayString)); | ||
256 | |||
257 | numTracks = CFArrayGetCount (trackArray); | ||
258 | |||
259 | for(trackIndex = 0; trackIndex < numTracks; trackIndex++) { | ||
260 | |||
261 | CFDictionaryRef theTrackDict; | ||
262 | CFNumberRef trackNumber; | ||
263 | CFNumberRef sessionNumber; | ||
264 | CFNumberRef startBlock; | ||
265 | CFBooleanRef isDataTrack; | ||
266 | UInt32 value; | ||
267 | |||
268 | theTrackDict = (CFDictionaryRef) CFArrayGetValueAtIndex (trackArray, trackIndex); | ||
269 | |||
270 | trackNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kPointKeyString)); | ||
271 | sessionNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kSessionNumberKeyString)); | ||
272 | startBlock = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kStartBlockKeyString)); | ||
273 | isDataTrack = (CFBooleanRef) CFDictionaryGetValue (theTrackDict, CFSTR(kDataKeyString)); | ||
274 | |||
275 | /* Fill in the SDL_CD struct */ | ||
276 | int idx = theCD->numtracks++; | ||
277 | |||
278 | CFNumberGetValue (trackNumber, kCFNumberSInt32Type, &value); | ||
279 | theCD->track[idx].id = value; | ||
280 | |||
281 | CFNumberGetValue (startBlock, kCFNumberSInt32Type, &value); | ||
282 | theCD->track[idx].offset = value; | ||
283 | |||
284 | theCD->track[idx].type = (isDataTrack == kCFBooleanTrue) ? SDL_DATA_TRACK : SDL_AUDIO_TRACK; | ||
285 | |||
286 | /* Since the track lengths are not stored in .TOC.plist we compute them. */ | ||
287 | if (trackIndex > 0) { | ||
288 | theCD->track[idx-1].length = theCD->track[idx].offset - theCD->track[idx-1].offset; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /* Compute the length of the last track */ | ||
293 | CFNumberGetValue (leadoutBlock, kCFNumberSInt32Type, &value); | ||
294 | |||
295 | theCD->track[theCD->numtracks-1].length = | ||
296 | value - theCD->track[theCD->numtracks-1].offset; | ||
297 | |||
298 | /* Set offset to leadout track */ | ||
299 | theCD->track[theCD->numtracks].offset = value; | ||
300 | } | ||
301 | |||
302 | } | ||
303 | |||
304 | theErr = 0; | ||
305 | goto cleanup; | ||
306 | bail: | ||
307 | SDL_SetError ("ReadTOCData: %s returned %d", error, theErr); | ||
308 | theErr = -1; | ||
309 | cleanup: | ||
310 | |||
311 | if (propertyListRef != NULL) | ||
312 | CFRelease(propertyListRef); | ||
313 | if (dataRef != NULL) | ||
314 | CFRelease(dataRef); | ||
315 | if (forkData != NULL) | ||
316 | DisposePtr(forkData); | ||
317 | |||
318 | FSCloseFork (forkRefNum); | ||
319 | |||
320 | return theErr; | ||
321 | } | ||
322 | |||
323 | int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks) | ||
324 | { | ||
325 | OSStatus result = -1; | ||
326 | FSIterator iterator; | ||
327 | ItemCount actualObjects; | ||
328 | FSRef rootDirectory; | ||
329 | FSRef ref; | ||
330 | HFSUniStr255 nameStr; | ||
331 | |||
332 | result = FSGetVolumeInfo (theVolume, | ||
333 | 0, | ||
334 | NULL, | ||
335 | kFSVolInfoFSInfo, | ||
336 | NULL, | ||
337 | NULL, | ||
338 | &rootDirectory); | ||
339 | |||
340 | if (result != noErr) { | ||
341 | SDL_SetError ("ListTrackFiles: FSGetVolumeInfo returned %d", result); | ||
342 | return result; | ||
343 | } | ||
344 | |||
345 | result = FSOpenIterator (&rootDirectory, kFSIterateFlat, &iterator); | ||
346 | if (result == noErr) { | ||
347 | do | ||
348 | { | ||
349 | result = FSGetCatalogInfoBulk (iterator, 1, &actualObjects, | ||
350 | NULL, kFSCatInfoNone, NULL, &ref, NULL, &nameStr); | ||
351 | if (result == noErr) { | ||
352 | |||
353 | CFStringRef name; | ||
354 | name = CFStringCreateWithCharacters (NULL, nameStr.unicode, nameStr.length); | ||
355 | |||
356 | /* Look for .aiff extension */ | ||
357 | if (CFStringHasSuffix (name, CFSTR(".aiff")) || | ||
358 | CFStringHasSuffix (name, CFSTR(".cdda"))) { | ||
359 | |||
360 | /* Extract the track id from the filename */ | ||
361 | int trackID = 0, i = 0; | ||
362 | while (i < nameStr.length && !isdigit(nameStr.unicode[i])) { | ||
363 | ++i; | ||
364 | } | ||
365 | while (i < nameStr.length && isdigit(nameStr.unicode[i])) { | ||
366 | trackID = 10 * trackID +(nameStr.unicode[i] - '0'); | ||
367 | ++i; | ||
368 | } | ||
369 | |||
370 | #if DEBUG_CDROM | ||
371 | printf("Found AIFF for track %d: '%s'\n", trackID, | ||
372 | CFStringGetCStringPtr (name, CFStringGetSystemEncoding())); | ||
373 | #endif | ||
374 | |||
375 | /* Track ID's start at 1, but we want to start at 0 */ | ||
376 | trackID--; | ||
377 | |||
378 | assert(0 <= trackID && trackID <= SDL_MAX_TRACKS); | ||
379 | |||
380 | if (trackID < numTracks) | ||
381 | memcpy (&trackFiles[trackID], &ref, sizeof(FSRef)); | ||
382 | } | ||
383 | CFRelease (name); | ||
384 | } | ||
385 | } while(noErr == result); | ||
386 | FSCloseIterator (iterator); | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | int LoadFile (const FSRef *ref, int startFrame, int stopFrame) | ||
393 | { | ||
394 | int error = -1; | ||
395 | |||
396 | if (CheckInit () < 0) | ||
397 | goto bail; | ||
398 | |||
399 | /* release any currently playing file */ | ||
400 | if (ReleaseFile () < 0) | ||
401 | goto bail; | ||
402 | |||
403 | #if DEBUG_CDROM | ||
404 | printf ("LoadFile: %d %d\n", startFrame, stopFrame); | ||
405 | #endif | ||
406 | |||
407 | /*try {*/ | ||
408 | |||
409 | /* create a new player, and attach to the audio unit */ | ||
410 | |||
411 | thePlayer = new_AudioFilePlayer(ref); | ||
412 | if (thePlayer == NULL) { | ||
413 | SDL_SetError ("LoadFile: Could not create player"); | ||
414 | return -3; /*throw (-3);*/ | ||
415 | } | ||
416 | |||
417 | if (!thePlayer->SetDestination(thePlayer, &theUnit)) | ||
418 | goto bail; | ||
419 | |||
420 | if (startFrame >= 0) | ||
421 | thePlayer->SetStartFrame (thePlayer, startFrame); | ||
422 | |||
423 | if (stopFrame >= 0 && stopFrame > startFrame) | ||
424 | thePlayer->SetStopFrame (thePlayer, stopFrame); | ||
425 | |||
426 | /* we set the notifier later */ | ||
427 | /*thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL);*/ | ||
428 | |||
429 | if (!thePlayer->Connect(thePlayer)) | ||
430 | goto bail; | ||
431 | |||
432 | #if DEBUG_CDROM | ||
433 | thePlayer->Print(thePlayer); | ||
434 | fflush (stdout); | ||
435 | #endif | ||
436 | /*} | ||
437 | catch (...) | ||
438 | { | ||
439 | goto bail; | ||
440 | }*/ | ||
441 | |||
442 | error = 0; | ||
443 | |||
444 | bail: | ||
445 | return error; | ||
446 | } | ||
447 | |||
448 | int ReleaseFile () | ||
449 | { | ||
450 | int error = -1; | ||
451 | |||
452 | /* (Don't see any way that the original C++ code could throw here.) --ryan. */ | ||
453 | /*try {*/ | ||
454 | if (thePlayer != NULL) { | ||
455 | |||
456 | thePlayer->Disconnect(thePlayer); | ||
457 | |||
458 | delete_AudioFilePlayer(thePlayer); | ||
459 | |||
460 | thePlayer = NULL; | ||
461 | } | ||
462 | /*} | ||
463 | catch (...) | ||
464 | { | ||
465 | goto bail; | ||
466 | }*/ | ||
467 | |||
468 | error = 0; | ||
469 | |||
470 | /* bail: */ | ||
471 | return error; | ||
472 | } | ||
473 | |||
474 | int PlayFile () | ||
475 | { | ||
476 | OSStatus result = -1; | ||
477 | |||
478 | if (CheckInit () < 0) | ||
479 | goto bail; | ||
480 | |||
481 | /*try {*/ | ||
482 | |||
483 | // start processing of the audio unit | ||
484 | result = AudioOutputUnitStart (theUnit); | ||
485 | if (result) goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart") | ||
486 | |||
487 | /*} | ||
488 | catch (...) | ||
489 | { | ||
490 | goto bail; | ||
491 | }*/ | ||
492 | |||
493 | result = 0; | ||
494 | |||
495 | bail: | ||
496 | return result; | ||
497 | } | ||
498 | |||
499 | int PauseFile () | ||
500 | { | ||
501 | OSStatus result = -1; | ||
502 | |||
503 | if (CheckInit () < 0) | ||
504 | goto bail; | ||
505 | |||
506 | /*try {*/ | ||
507 | |||
508 | /* stop processing the audio unit */ | ||
509 | result = AudioOutputUnitStop (theUnit); | ||
510 | if (result) goto bail; /*THROW_RESULT("PauseFile: AudioOutputUnitStop")*/ | ||
511 | /*} | ||
512 | catch (...) | ||
513 | { | ||
514 | goto bail; | ||
515 | }*/ | ||
516 | |||
517 | result = 0; | ||
518 | bail: | ||
519 | return result; | ||
520 | } | ||
521 | |||
522 | void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom) | ||
523 | { | ||
524 | assert(thePlayer != NULL); | ||
525 | |||
526 | theCDROM = cdrom; | ||
527 | completionProc = proc; | ||
528 | thePlayer->SetNotifier (thePlayer, FilePlayNotificationHandler, cdrom); | ||
529 | } | ||
530 | |||
531 | int GetCurrentFrame () | ||
532 | { | ||
533 | int frame; | ||
534 | |||
535 | if (thePlayer == NULL) | ||
536 | frame = 0; | ||
537 | else | ||
538 | frame = thePlayer->GetCurrentFrame (thePlayer); | ||
539 | |||
540 | return frame; | ||
541 | } | ||
542 | |||
543 | |||
544 | #pragma mark -- Private Functions -- | ||
545 | |||
546 | static OSStatus CheckInit () | ||
547 | { | ||
548 | if (playBackWasInit) | ||
549 | return 0; | ||
550 | |||
551 | OSStatus result = noErr; | ||
552 | |||
553 | /* Create the callback semaphore */ | ||
554 | callbackSem = SDL_CreateSemaphore(0); | ||
555 | |||
556 | /* Start callback thread */ | ||
557 | SDL_CreateThread(RunCallBackThread, NULL); | ||
558 | |||
559 | { /*try {*/ | ||
560 | ComponentDescription desc; | ||
561 | |||
562 | desc.componentType = kAudioUnitType_Output; | ||
563 | desc.componentSubType = kAudioUnitSubType_DefaultOutput; | ||
564 | desc.componentManufacturer = kAudioUnitManufacturer_Apple; | ||
565 | desc.componentFlags = 0; | ||
566 | desc.componentFlagsMask = 0; | ||
567 | |||
568 | Component comp = FindNextComponent (NULL, &desc); | ||
569 | if (comp == NULL) { | ||
570 | SDL_SetError ("CheckInit: FindNextComponent returned NULL"); | ||
571 | if (result) return -1; //throw(internalComponentErr); | ||
572 | } | ||
573 | |||
574 | result = OpenAComponent (comp, &theUnit); | ||
575 | if (result) return -1; //THROW_RESULT("CheckInit: OpenAComponent") | ||
576 | |||
577 | // you need to initialize the output unit before you set it as a destination | ||
578 | result = AudioUnitInitialize (theUnit); | ||
579 | if (result) return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize") | ||
580 | |||
581 | |||
582 | playBackWasInit = true; | ||
583 | } | ||
584 | /*catch (...) | ||
585 | { | ||
586 | return -1; | ||
587 | }*/ | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus) | ||
593 | { | ||
594 | if (inStatus == kAudioFilePlay_FileIsFinished) { | ||
595 | |||
596 | /* notify non-CA thread to perform the callback */ | ||
597 | SDL_SemPost(callbackSem); | ||
598 | |||
599 | } else if (inStatus == kAudioFilePlayErr_FilePlayUnderrun) { | ||
600 | |||
601 | SDL_SetError ("CDPlayer Notification: buffer underrun"); | ||
602 | } else if (inStatus == kAudioFilePlay_PlayerIsUninitialized) { | ||
603 | |||
604 | SDL_SetError ("CDPlayer Notification: player is uninitialized"); | ||
605 | } else { | ||
606 | |||
607 | SDL_SetError ("CDPlayer Notification: unknown error %ld", inStatus); | ||
608 | } | ||
609 | } | ||
610 | |||
611 | static int RunCallBackThread (void *param) | ||
612 | { | ||
613 | for (;;) { | ||
614 | |||
615 | SDL_SemWait(callbackSem); | ||
616 | |||
617 | if (completionProc && theCDROM) { | ||
618 | #if DEBUG_CDROM | ||
619 | printf ("callback!\n"); | ||
620 | #endif | ||
621 | (*completionProc)(theCDROM); | ||
622 | } else { | ||
623 | #if DEBUG_CDROM | ||
624 | printf ("callback?\n"); | ||
625 | #endif | ||
626 | } | ||
627 | } | ||
628 | |||
629 | #if DEBUG_CDROM | ||
630 | printf ("thread dying now...\n"); | ||
631 | #endif | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | /*}; // extern "C" */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.h b/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.h new file mode 100644 index 0000000000..be1ac1826a --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifndef __CDPlayer__H__ | ||
25 | #define __CDPlayer__H__ 1 | ||
26 | |||
27 | #include <string.h> | ||
28 | |||
29 | #include <Carbon/Carbon.h> | ||
30 | #include <CoreFoundation/CoreFoundation.h> | ||
31 | #include <AudioUnit/AudioUnit.h> | ||
32 | |||
33 | #include "SDL.h" | ||
34 | #include "SDL_thread.h" | ||
35 | #include "SDL_mutex.h" | ||
36 | |||
37 | #ifdef __cplusplus | ||
38 | extern "C" { | ||
39 | #endif | ||
40 | |||
41 | typedef void (*CDPlayerCompletionProc)(SDL_CD *cdrom) ; | ||
42 | |||
43 | void Lock (); | ||
44 | |||
45 | void Unlock(); | ||
46 | |||
47 | int LoadFile (const FSRef *ref, int startFrame, int endFrame); /* pass -1 to do nothing */ | ||
48 | |||
49 | int ReleaseFile (); | ||
50 | |||
51 | int PlayFile (); | ||
52 | |||
53 | int PauseFile (); | ||
54 | |||
55 | void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom); | ||
56 | |||
57 | int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD); | ||
58 | |||
59 | int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks); | ||
60 | |||
61 | int DetectAudioCDVolumes (FSVolumeRefNum *volumes, int numVolumes); | ||
62 | |||
63 | int GetCurrentFrame (); | ||
64 | |||
65 | #ifdef __cplusplus | ||
66 | }; | ||
67 | #endif | ||
68 | |||
69 | #endif /* __CD_Player__H__ */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.c b/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.c new file mode 100644 index 0000000000..e8caf1bf10 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* | ||
25 | Note: This file hasn't been modified so technically we have to keep the disclaimer :-( | ||
26 | |||
27 | Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved. | ||
28 | |||
29 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. | ||
30 | ("Apple") in consideration of your agreement to the following terms, and your | ||
31 | use, installation, modification or redistribution of this Apple software | ||
32 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
33 | please do not use, install, modify or redistribute this Apple software. | ||
34 | |||
35 | In consideration of your agreement to abide by the following terms, and subject | ||
36 | to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs | ||
37 | copyrights in this original Apple software (the "Apple Software"), to use, | ||
38 | reproduce, modify and redistribute the Apple Software, with or without | ||
39 | modifications, in source and/or binary forms; provided that if you redistribute | ||
40 | the Apple Software in its entirety and without modifications, you must retain | ||
41 | this notice and the following text and disclaimers in all such redistributions of | ||
42 | the Apple Software. Neither the name, trademarks, service marks or logos of | ||
43 | Apple Computer, Inc. may be used to endorse or promote products derived from the | ||
44 | Apple Software without specific prior written permission from Apple. Except as | ||
45 | expressly stated in this notice, no other rights or licenses, express or implied, | ||
46 | are granted by Apple herein, including but not limited to any patent rights that | ||
47 | may be infringed by your derivative works or by other works in which the Apple | ||
48 | Software may be incorporated. | ||
49 | |||
50 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
51 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
52 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
53 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
54 | COMBINATION WITH YOUR PRODUCTS. | ||
55 | |||
56 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
57 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
58 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
59 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION | ||
60 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT | ||
61 | (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN | ||
62 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
63 | */ | ||
64 | /*============================================================================= | ||
65 | CAGuard.cp | ||
66 | |||
67 | =============================================================================*/ | ||
68 | |||
69 | /*============================================================================= | ||
70 | Includes | ||
71 | =============================================================================*/ | ||
72 | |||
73 | /* | ||
74 | #include <stdio.h> | ||
75 | #include <stdlib.h> | ||
76 | #include <string.h> | ||
77 | */ | ||
78 | #include "SDL_stdinc.h" | ||
79 | |||
80 | /*#define NDEBUG 1*/ | ||
81 | /* | ||
82 | #include <assert.h> | ||
83 | */ | ||
84 | #define assert(X) | ||
85 | |||
86 | |||
87 | #include "SDLOSXCAGuard.h" | ||
88 | |||
89 | /*#warning Need a try-based Locker too*/ | ||
90 | /*============================================================================= | ||
91 | SDLOSXCAGuard | ||
92 | =============================================================================*/ | ||
93 | |||
94 | static int SDLOSXCAGuard_Lock(SDLOSXCAGuard *cag) | ||
95 | { | ||
96 | int theAnswer = 0; | ||
97 | |||
98 | if(pthread_self() != cag->mOwner) | ||
99 | { | ||
100 | OSStatus theError = pthread_mutex_lock(&cag->mMutex); | ||
101 | (void)theError; | ||
102 | assert(theError == 0); | ||
103 | cag->mOwner = pthread_self(); | ||
104 | theAnswer = 1; | ||
105 | } | ||
106 | |||
107 | return theAnswer; | ||
108 | } | ||
109 | |||
110 | static void SDLOSXCAGuard_Unlock(SDLOSXCAGuard *cag) | ||
111 | { | ||
112 | OSStatus theError; | ||
113 | assert(pthread_self() == cag->mOwner); | ||
114 | |||
115 | cag->mOwner = 0; | ||
116 | theError = pthread_mutex_unlock(&cag->mMutex); | ||
117 | (void)theError; | ||
118 | assert(theError == 0); | ||
119 | } | ||
120 | |||
121 | static int SDLOSXCAGuard_Try (SDLOSXCAGuard *cag, int *outWasLocked) | ||
122 | { | ||
123 | int theAnswer = 0; | ||
124 | *outWasLocked = 0; | ||
125 | |||
126 | if (pthread_self() == cag->mOwner) { | ||
127 | theAnswer = 1; | ||
128 | *outWasLocked = 0; | ||
129 | } else { | ||
130 | OSStatus theError = pthread_mutex_trylock(&cag->mMutex); | ||
131 | if (theError == 0) { | ||
132 | cag->mOwner = pthread_self(); | ||
133 | theAnswer = 1; | ||
134 | *outWasLocked = 1; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return theAnswer; | ||
139 | } | ||
140 | |||
141 | static void SDLOSXCAGuard_Wait(SDLOSXCAGuard *cag) | ||
142 | { | ||
143 | OSStatus theError; | ||
144 | assert(pthread_self() == cag->mOwner); | ||
145 | |||
146 | cag->mOwner = 0; | ||
147 | |||
148 | theError = pthread_cond_wait(&cag->mCondVar, &cag->mMutex); | ||
149 | (void)theError; | ||
150 | assert(theError == 0); | ||
151 | cag->mOwner = pthread_self(); | ||
152 | } | ||
153 | |||
154 | static void SDLOSXCAGuard_Notify(SDLOSXCAGuard *cag) | ||
155 | { | ||
156 | OSStatus theError = pthread_cond_signal(&cag->mCondVar); | ||
157 | (void)theError; | ||
158 | assert(theError == 0); | ||
159 | } | ||
160 | |||
161 | |||
162 | SDLOSXCAGuard *new_SDLOSXCAGuard(void) | ||
163 | { | ||
164 | OSStatus theError; | ||
165 | SDLOSXCAGuard *cag = (SDLOSXCAGuard *) SDL_malloc(sizeof (SDLOSXCAGuard)); | ||
166 | if (cag == NULL) | ||
167 | return NULL; | ||
168 | SDL_memset(cag, '\0', sizeof (*cag)); | ||
169 | |||
170 | #define SET_SDLOSXCAGUARD_METHOD(m) cag->m = SDLOSXCAGuard_##m | ||
171 | SET_SDLOSXCAGUARD_METHOD(Lock); | ||
172 | SET_SDLOSXCAGUARD_METHOD(Unlock); | ||
173 | SET_SDLOSXCAGUARD_METHOD(Try); | ||
174 | SET_SDLOSXCAGUARD_METHOD(Wait); | ||
175 | SET_SDLOSXCAGUARD_METHOD(Notify); | ||
176 | #undef SET_SDLOSXCAGUARD_METHOD | ||
177 | |||
178 | theError = pthread_mutex_init(&cag->mMutex, NULL); | ||
179 | (void)theError; | ||
180 | assert(theError == 0); | ||
181 | |||
182 | theError = pthread_cond_init(&cag->mCondVar, NULL); | ||
183 | (void)theError; | ||
184 | assert(theError == 0); | ||
185 | |||
186 | cag->mOwner = 0; | ||
187 | return cag; | ||
188 | } | ||
189 | |||
190 | void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag) | ||
191 | { | ||
192 | if (cag != NULL) | ||
193 | { | ||
194 | pthread_mutex_destroy(&cag->mMutex); | ||
195 | pthread_cond_destroy(&cag->mCondVar); | ||
196 | SDL_free(cag); | ||
197 | } | ||
198 | } | ||
199 | |||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.h b/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.h new file mode 100644 index 0000000000..f22c6956fe --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.h | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* | ||
25 | Note: This file hasn't been modified so technically we have to keep the disclaimer :-( | ||
26 | |||
27 | |||
28 | Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved. | ||
29 | |||
30 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. | ||
31 | ("Apple") in consideration of your agreement to the following terms, and your | ||
32 | use, installation, modification or redistribution of this Apple software | ||
33 | constitutes acceptance of these terms. If you do not agree with these terms, | ||
34 | please do not use, install, modify or redistribute this Apple software. | ||
35 | |||
36 | In consideration of your agreement to abide by the following terms, and subject | ||
37 | to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs | ||
38 | copyrights in this original Apple software (the "Apple Software"), to use, | ||
39 | reproduce, modify and redistribute the Apple Software, with or without | ||
40 | modifications, in source and/or binary forms; provided that if you redistribute | ||
41 | the Apple Software in its entirety and without modifications, you must retain | ||
42 | this notice and the following text and disclaimers in all such redistributions of | ||
43 | the Apple Software. Neither the name, trademarks, service marks or logos of | ||
44 | Apple Computer, Inc. may be used to endorse or promote products derived from the | ||
45 | Apple Software without specific prior written permission from Apple. Except as | ||
46 | expressly stated in this notice, no other rights or licenses, express or implied, | ||
47 | are granted by Apple herein, including but not limited to any patent rights that | ||
48 | may be infringed by your derivative works or by other works in which the Apple | ||
49 | Software may be incorporated. | ||
50 | |||
51 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | ||
52 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | ||
53 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
54 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | ||
55 | COMBINATION WITH YOUR PRODUCTS. | ||
56 | |||
57 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | ||
58 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
59 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
60 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION | ||
61 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT | ||
62 | (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN | ||
63 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
64 | */ | ||
65 | /*============================================================================= | ||
66 | CAGuard.h | ||
67 | |||
68 | =============================================================================*/ | ||
69 | #if !defined(__CAGuard_h__) | ||
70 | #define __CAGuard_h__ | ||
71 | |||
72 | /*============================================================================= | ||
73 | Includes | ||
74 | =============================================================================*/ | ||
75 | |||
76 | #include <CoreAudio/CoreAudioTypes.h> | ||
77 | #include <pthread.h> | ||
78 | |||
79 | |||
80 | /*============================================================================= | ||
81 | CAGuard | ||
82 | |||
83 | This is your typical mutex with signalling implemented via pthreads. | ||
84 | Lock() will return true if and only if the guard is locked on that call. | ||
85 | A thread that already has the guard will receive 'false' if it locks it | ||
86 | again. Use of the stack-based CAGuard::Locker class is highly recommended | ||
87 | to properly manage the recursive nesting. The Wait calls with timeouts | ||
88 | will return true if and only if the timeout period expired. They will | ||
89 | return false if they receive notification any other way. | ||
90 | =============================================================================*/ | ||
91 | |||
92 | typedef struct S_SDLOSXCAGuard | ||
93 | { | ||
94 | |||
95 | /* Construction/Destruction */ | ||
96 | /*public:*/ | ||
97 | /* Actions */ | ||
98 | /*public:*/ | ||
99 | int (*Lock)(struct S_SDLOSXCAGuard *cag); | ||
100 | void (*Unlock)(struct S_SDLOSXCAGuard *cag); | ||
101 | int (*Try)(struct S_SDLOSXCAGuard *cag, int *outWasLocked); /* returns true if lock is free, false if not */ | ||
102 | void (*Wait)(struct S_SDLOSXCAGuard *cag); | ||
103 | void (*Notify)(struct S_SDLOSXCAGuard *cag); | ||
104 | |||
105 | /* Implementation */ | ||
106 | /*protected:*/ | ||
107 | pthread_mutex_t mMutex; | ||
108 | pthread_cond_t mCondVar; | ||
109 | pthread_t mOwner; | ||
110 | } SDLOSXCAGuard; | ||
111 | |||
112 | SDLOSXCAGuard *new_SDLOSXCAGuard(void); | ||
113 | void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag); | ||
114 | |||
115 | #endif | ||
116 | |||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom.c new file mode 100644 index 0000000000..5018750222 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom.c | |||
@@ -0,0 +1,514 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_MACOSX | ||
25 | |||
26 | #include "SDL_syscdrom_c.h" | ||
27 | |||
28 | #pragma mark -- Globals -- | ||
29 | |||
30 | static FSRef** tracks; | ||
31 | static FSVolumeRefNum* volumes; | ||
32 | static CDstatus status; | ||
33 | static int nextTrackFrame; | ||
34 | static int nextTrackFramesRemaining; | ||
35 | static int fakeCD; | ||
36 | static int currentTrack; | ||
37 | static int didReadTOC; | ||
38 | static int cacheTOCNumTracks; | ||
39 | static int currentDrive; /* Only allow 1 drive in use at a time */ | ||
40 | |||
41 | #pragma mark -- Prototypes -- | ||
42 | |||
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 | |||
54 | #pragma mark -- Helper Functions -- | ||
55 | |||
56 | /* Read a list of tracks from the volume */ | ||
57 | static int LoadTracks (SDL_CD *cdrom) | ||
58 | { | ||
59 | /* Check if tracks are already loaded */ | ||
60 | if ( tracks[cdrom->id] != NULL ) | ||
61 | return 0; | ||
62 | |||
63 | /* Allocate memory for tracks */ | ||
64 | tracks[cdrom->id] = (FSRef*) SDL_calloc (1, sizeof(**tracks) * cdrom->numtracks); | ||
65 | if (tracks[cdrom->id] == NULL) { | ||
66 | SDL_OutOfMemory (); | ||
67 | return -1; | ||
68 | } | ||
69 | |||
70 | /* Load tracks */ | ||
71 | if (ListTrackFiles (volumes[cdrom->id], tracks[cdrom->id], cdrom->numtracks) < 0) | ||
72 | return -1; | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | /* Find a file for a given start frame and length */ | ||
78 | static FSRef* GetFileForOffset (SDL_CD *cdrom, int start, int length, int *outStartFrame, int *outStopFrame) | ||
79 | { | ||
80 | int i; | ||
81 | |||
82 | for (i = 0; i < cdrom->numtracks; i++) { | ||
83 | |||
84 | if (cdrom->track[i].offset <= start && | ||
85 | start < (cdrom->track[i].offset + cdrom->track[i].length)) | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | if (i == cdrom->numtracks) | ||
90 | return NULL; | ||
91 | |||
92 | currentTrack = i; | ||
93 | |||
94 | *outStartFrame = start - cdrom->track[i].offset; | ||
95 | |||
96 | if ((*outStartFrame + length) < cdrom->track[i].length) { | ||
97 | *outStopFrame = *outStartFrame + length; | ||
98 | length = 0; | ||
99 | nextTrackFrame = -1; | ||
100 | nextTrackFramesRemaining = -1; | ||
101 | } | ||
102 | else { | ||
103 | *outStopFrame = -1; | ||
104 | length -= cdrom->track[i].length - *outStartFrame; | ||
105 | nextTrackFrame = cdrom->track[i+1].offset; | ||
106 | nextTrackFramesRemaining = length; | ||
107 | } | ||
108 | |||
109 | return &tracks[cdrom->id][i]; | ||
110 | } | ||
111 | |||
112 | /* Setup another file for playback, or stop playback (called from another thread) */ | ||
113 | static void CompletionProc (SDL_CD *cdrom) | ||
114 | { | ||
115 | |||
116 | Lock (); | ||
117 | |||
118 | if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) { | ||
119 | |||
120 | /* Load the next file to play */ | ||
121 | int startFrame, stopFrame; | ||
122 | FSRef *file; | ||
123 | |||
124 | PauseFile (); | ||
125 | ReleaseFile (); | ||
126 | |||
127 | file = GetFileForOffset (cdrom, nextTrackFrame, | ||
128 | nextTrackFramesRemaining, &startFrame, &stopFrame); | ||
129 | |||
130 | if (file == NULL) { | ||
131 | status = CD_STOPPED; | ||
132 | Unlock (); | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | LoadFile (file, startFrame, stopFrame); | ||
137 | |||
138 | SetCompletionProc (CompletionProc, cdrom); | ||
139 | |||
140 | PlayFile (); | ||
141 | } | ||
142 | else { | ||
143 | |||
144 | /* Release the current file */ | ||
145 | PauseFile (); | ||
146 | ReleaseFile (); | ||
147 | status = CD_STOPPED; | ||
148 | } | ||
149 | |||
150 | Unlock (); | ||
151 | } | ||
152 | |||
153 | |||
154 | #pragma mark -- Driver Functions -- | ||
155 | |||
156 | /* Initialize */ | ||
157 | int SDL_SYS_CDInit (void) | ||
158 | { | ||
159 | /* Initialize globals */ | ||
160 | volumes = NULL; | ||
161 | tracks = NULL; | ||
162 | status = CD_STOPPED; | ||
163 | nextTrackFrame = -1; | ||
164 | nextTrackFramesRemaining = -1; | ||
165 | fakeCD = SDL_FALSE; | ||
166 | currentTrack = -1; | ||
167 | didReadTOC = SDL_FALSE; | ||
168 | cacheTOCNumTracks = -1; | ||
169 | currentDrive = -1; | ||
170 | |||
171 | /* Fill in function pointers */ | ||
172 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
173 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
174 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
175 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
176 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
177 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
178 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
179 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
180 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
181 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
182 | |||
183 | /* | ||
184 | Read the list of "drives" | ||
185 | |||
186 | This is currently a hack that infers drives from | ||
187 | mounted audio CD volumes, rather than | ||
188 | actual CD-ROM devices - which means it may not | ||
189 | act as expected sometimes. | ||
190 | */ | ||
191 | |||
192 | /* Find out how many cd volumes are mounted */ | ||
193 | SDL_numcds = DetectAudioCDVolumes (NULL, 0); | ||
194 | |||
195 | /* | ||
196 | If there are no volumes, fake a cd device | ||
197 | so tray empty can be reported. | ||
198 | */ | ||
199 | if (SDL_numcds == 0) { | ||
200 | |||
201 | fakeCD = SDL_TRUE; | ||
202 | SDL_numcds = 1; | ||
203 | status = CD_TRAYEMPTY; | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* Allocate space for volumes */ | ||
209 | volumes = (FSVolumeRefNum*) SDL_calloc (1, sizeof(*volumes) * SDL_numcds); | ||
210 | if (volumes == NULL) { | ||
211 | SDL_OutOfMemory (); | ||
212 | return -1; | ||
213 | } | ||
214 | |||
215 | /* Allocate space for tracks */ | ||
216 | tracks = (FSRef**) SDL_calloc (1, sizeof(*tracks) * (SDL_numcds + 1)); | ||
217 | if (tracks == NULL) { | ||
218 | SDL_OutOfMemory (); | ||
219 | return -1; | ||
220 | } | ||
221 | |||
222 | /* Mark the end of the tracks array */ | ||
223 | tracks[ SDL_numcds ] = (FSRef*)-1; | ||
224 | |||
225 | /* | ||
226 | Redetect, now save all volumes for later | ||
227 | Update SDL_numcds just in case it changed | ||
228 | */ | ||
229 | { | ||
230 | int numVolumes = SDL_numcds; | ||
231 | |||
232 | SDL_numcds = DetectAudioCDVolumes (volumes, numVolumes); | ||
233 | |||
234 | /* If more cds suddenly show up, ignore them */ | ||
235 | if (SDL_numcds > numVolumes) { | ||
236 | SDL_SetError ("Some CD's were added but they will be ignored"); | ||
237 | SDL_numcds = numVolumes; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | /* Shutdown and cleanup */ | ||
245 | void SDL_SYS_CDQuit(void) | ||
246 | { | ||
247 | ReleaseFile(); | ||
248 | |||
249 | if (volumes != NULL) | ||
250 | free (volumes); | ||
251 | |||
252 | if (tracks != NULL) { | ||
253 | |||
254 | FSRef **ptr; | ||
255 | for (ptr = tracks; *ptr != (FSRef*)-1; ptr++) | ||
256 | if (*ptr != NULL) | ||
257 | free (*ptr); | ||
258 | |||
259 | free (tracks); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | /* Get the Unix disk name of the volume */ | ||
264 | static const char *SDL_SYS_CDName (int drive) | ||
265 | { | ||
266 | /* | ||
267 | * !!! FIXME: PBHGetVolParmsSync() is gone in 10.6, | ||
268 | * !!! FIXME: replaced with FSGetVolumeParms(), which | ||
269 | * !!! FIXME: isn't available before 10.5. :/ | ||
270 | */ | ||
271 | return "Mac OS X CD-ROM Device"; | ||
272 | |||
273 | #if 0 | ||
274 | OSStatus err = noErr; | ||
275 | HParamBlockRec pb; | ||
276 | GetVolParmsInfoBuffer volParmsInfo; | ||
277 | |||
278 | if (fakeCD) | ||
279 | return "Fake CD-ROM Device"; | ||
280 | |||
281 | pb.ioParam.ioNamePtr = NULL; | ||
282 | pb.ioParam.ioVRefNum = volumes[drive]; | ||
283 | pb.ioParam.ioBuffer = (Ptr)&volParmsInfo; | ||
284 | pb.ioParam.ioReqCount = (SInt32)sizeof(volParmsInfo); | ||
285 | err = PBHGetVolParmsSync(&pb); | ||
286 | |||
287 | if (err != noErr) { | ||
288 | SDL_SetError ("PBHGetVolParmsSync returned %d", err); | ||
289 | return NULL; | ||
290 | } | ||
291 | |||
292 | return volParmsInfo.vMDeviceID; | ||
293 | #endif | ||
294 | } | ||
295 | |||
296 | /* Open the "device" */ | ||
297 | static int SDL_SYS_CDOpen (int drive) | ||
298 | { | ||
299 | /* Only allow 1 device to be open */ | ||
300 | if (currentDrive >= 0) { | ||
301 | SDL_SetError ("Only one cdrom is supported"); | ||
302 | return -1; | ||
303 | } | ||
304 | else | ||
305 | currentDrive = drive; | ||
306 | |||
307 | return drive; | ||
308 | } | ||
309 | |||
310 | /* Get the table of contents */ | ||
311 | static int SDL_SYS_CDGetTOC (SDL_CD *cdrom) | ||
312 | { | ||
313 | if (fakeCD) { | ||
314 | SDL_SetError (kErrorFakeDevice); | ||
315 | return -1; | ||
316 | } | ||
317 | |||
318 | if (didReadTOC) { | ||
319 | cdrom->numtracks = cacheTOCNumTracks; | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | |||
324 | ReadTOCData (volumes[cdrom->id], cdrom); | ||
325 | didReadTOC = SDL_TRUE; | ||
326 | cacheTOCNumTracks = cdrom->numtracks; | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | /* Get CD-ROM status */ | ||
332 | static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position) | ||
333 | { | ||
334 | if (position) { | ||
335 | int trackFrame; | ||
336 | |||
337 | Lock (); | ||
338 | trackFrame = GetCurrentFrame (); | ||
339 | Unlock (); | ||
340 | |||
341 | *position = cdrom->track[currentTrack].offset + trackFrame; | ||
342 | } | ||
343 | |||
344 | return status; | ||
345 | } | ||
346 | |||
347 | /* Start playback */ | ||
348 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
349 | { | ||
350 | int startFrame, stopFrame; | ||
351 | FSRef *ref; | ||
352 | |||
353 | if (fakeCD) { | ||
354 | SDL_SetError (kErrorFakeDevice); | ||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | Lock(); | ||
359 | |||
360 | if (LoadTracks (cdrom) < 0) | ||
361 | return -2; | ||
362 | |||
363 | if (PauseFile () < 0) | ||
364 | return -3; | ||
365 | |||
366 | if (ReleaseFile () < 0) | ||
367 | return -4; | ||
368 | |||
369 | ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame); | ||
370 | if (ref == NULL) { | ||
371 | SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d", start, length); | ||
372 | return -5; | ||
373 | } | ||
374 | |||
375 | if (LoadFile (ref, startFrame, stopFrame) < 0) | ||
376 | return -6; | ||
377 | |||
378 | SetCompletionProc (CompletionProc, cdrom); | ||
379 | |||
380 | if (PlayFile () < 0) | ||
381 | return -7; | ||
382 | |||
383 | status = CD_PLAYING; | ||
384 | |||
385 | Unlock(); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | /* Pause playback */ | ||
391 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
392 | { | ||
393 | if (fakeCD) { | ||
394 | SDL_SetError (kErrorFakeDevice); | ||
395 | return -1; | ||
396 | } | ||
397 | |||
398 | Lock (); | ||
399 | |||
400 | if (PauseFile () < 0) { | ||
401 | Unlock (); | ||
402 | return -2; | ||
403 | } | ||
404 | |||
405 | status = CD_PAUSED; | ||
406 | |||
407 | Unlock (); | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | /* Resume playback */ | ||
413 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
414 | { | ||
415 | if (fakeCD) { | ||
416 | SDL_SetError (kErrorFakeDevice); | ||
417 | return -1; | ||
418 | } | ||
419 | |||
420 | Lock (); | ||
421 | |||
422 | if (PlayFile () < 0) { | ||
423 | Unlock (); | ||
424 | return -2; | ||
425 | } | ||
426 | |||
427 | status = CD_PLAYING; | ||
428 | |||
429 | Unlock (); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | /* Stop playback */ | ||
435 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
436 | { | ||
437 | if (fakeCD) { | ||
438 | SDL_SetError (kErrorFakeDevice); | ||
439 | return -1; | ||
440 | } | ||
441 | |||
442 | Lock (); | ||
443 | |||
444 | if (PauseFile () < 0) { | ||
445 | Unlock (); | ||
446 | return -2; | ||
447 | } | ||
448 | |||
449 | if (ReleaseFile () < 0) { | ||
450 | Unlock (); | ||
451 | return -3; | ||
452 | } | ||
453 | |||
454 | status = CD_STOPPED; | ||
455 | |||
456 | Unlock (); | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | /* Eject the CD-ROM (Unmount the volume) */ | ||
462 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
463 | { | ||
464 | OSStatus err; | ||
465 | pid_t dissenter; | ||
466 | |||
467 | if (fakeCD) { | ||
468 | SDL_SetError (kErrorFakeDevice); | ||
469 | return -1; | ||
470 | } | ||
471 | |||
472 | Lock (); | ||
473 | |||
474 | if (PauseFile () < 0) { | ||
475 | Unlock (); | ||
476 | return -2; | ||
477 | } | ||
478 | |||
479 | if (ReleaseFile () < 0) { | ||
480 | Unlock (); | ||
481 | return -3; | ||
482 | } | ||
483 | |||
484 | status = CD_STOPPED; | ||
485 | |||
486 | /* Eject the volume */ | ||
487 | err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter); | ||
488 | |||
489 | if (err != noErr) { | ||
490 | Unlock (); | ||
491 | SDL_SetError ("PBUnmountVol returned %d", err); | ||
492 | return -4; | ||
493 | } | ||
494 | |||
495 | status = CD_TRAYEMPTY; | ||
496 | |||
497 | /* Invalidate volume and track info */ | ||
498 | volumes[cdrom->id] = 0; | ||
499 | free (tracks[cdrom->id]); | ||
500 | tracks[cdrom->id] = NULL; | ||
501 | |||
502 | Unlock (); | ||
503 | |||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | /* Close the CD-ROM */ | ||
508 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
509 | { | ||
510 | currentDrive = -1; | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | #endif /* SDL_CDROM_MACOSX */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom_c.h b/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom_c.h new file mode 100644 index 0000000000..589c5897e6 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom_c.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* This is the Mac OS X / CoreAudio specific header for the SDL CD-ROM API | ||
25 | Contributed by Darrell Walisser and Max Horn | ||
26 | */ | ||
27 | |||
28 | /*********************************************************************************** | ||
29 | Implementation Notes | ||
30 | ********************* | ||
31 | |||
32 | This code has several limitations currently (all of which are proabaly fixable): | ||
33 | |||
34 | 1. A CD-ROM device is inferred from a mounted cdfs volume, so device 0 is | ||
35 | not necessarily the first CD-ROM device on the system. (Somewhat easy to fix | ||
36 | by useing the device name from the volume id's to reorder the volumes) | ||
37 | |||
38 | 2. You can only open and control 1 CD-ROM device at a time. (Challenging to fix, | ||
39 | due to extensive code restructuring) | ||
40 | |||
41 | 3. The status reported by SDL_CDStatus only changes to from CD_PLAYING to CD_STOPPED in | ||
42 | 1-second intervals (because the audio is buffered in 1-second chunks) If | ||
43 | the audio data is less than 1 second, the remainder is filled with silence. | ||
44 | |||
45 | If you need to play sequences back-to-back that are less that 1 second long, | ||
46 | use the frame position to determine when to play the next sequence, instead | ||
47 | of SDL_CDStatus. | ||
48 | |||
49 | This may be possible to fix with a clever usage of the AudioUnit API. | ||
50 | |||
51 | 4. When new volumes are inserted, our volume information is not updated. The only way | ||
52 | to refresh this information is to reinit the CD-ROM subsystem of SDL. To fix this, | ||
53 | one would probably have to fix point 1 above first, then figure out how to register | ||
54 | for a notification when new media is mounted in order to perform an automatic | ||
55 | rescan for cdfs volumes. | ||
56 | |||
57 | |||
58 | |||
59 | So, here comes a description of how this all works. | ||
60 | |||
61 | < Initializing > | ||
62 | |||
63 | To get things rolling, we have to locate mounted volumes that contain | ||
64 | audio (since nearly all Macs don't have analog audio-in on the sound card). | ||
65 | That's easy, since these volumes have a flag that indicates this special | ||
66 | filesystem. See DetectAudioCDVolumes() in CDPlayer.cpp for this code. | ||
67 | |||
68 | Next, we parse the invisible .TOC.plist in the root of the volume, which gets us | ||
69 | the track information (number, offset, length, leadout, etc). See ReadTOCData() in | ||
70 | CDPlayer.cpp for the skinny on this. | ||
71 | |||
72 | |||
73 | < The Playback Loop > | ||
74 | |||
75 | Now come the tricky parts. Let's start with basic audio playback. When a frame | ||
76 | range to play is requested, we must first find the .aiff files on the volume, | ||
77 | hopefully in the right order. Since these files all begin with a number "1 Audio Track", | ||
78 | etc, this is used to determine the correct track order. | ||
79 | |||
80 | Once all files are determined, we have to find what file corresponds to the start | ||
81 | and length parameter to SDL_SYS_CDPlay(). Again, this is quite simple by walking the | ||
82 | cdrom's track list. At this point, we also save the offset to the next track and frames | ||
83 | remaining, if we're going to have to play another file after the first one. See | ||
84 | GetFileForOffset() for this code. | ||
85 | |||
86 | At this point we have all info needed to start playback, so we hand off to the LoadFile() | ||
87 | function, which proceeds to do its magic and plays back the file. | ||
88 | |||
89 | When the file is finished playing, CompletionProc() is invoked, at which time we can | ||
90 | play the next file if the previously saved next track and frames remaining | ||
91 | indicates that we should. | ||
92 | |||
93 | |||
94 | < Magic > | ||
95 | |||
96 | OK, so it's not really magic, but since I don't fully understand all the hidden details it | ||
97 | seems like it to me ;-) The API's involved are the AudioUnit and AudioFile API's. These | ||
98 | appear to be an extension of CoreAudio for creating modular playback and f/x entities. | ||
99 | The important thing is that CPU usage is very low and reliability is very high. You'd | ||
100 | be hard-pressed to find a way to stutter the playback with other CPU-intensive tasks. | ||
101 | |||
102 | One part of this magic is that it uses multiple threads, which carries the usual potential | ||
103 | for disaster if not handled carefully. Playback currently requires 4 additional threads: | ||
104 | 1. The coreaudio runloop thread | ||
105 | 2. The coreaudio device i/o thread | ||
106 | 3. The file streaming thread | ||
107 | 4. The notification/callback thread | ||
108 | |||
109 | The first 2 threads are necessary evil - CoreAudio creates this no matter what the situation | ||
110 | is (even the SDL sound implementation creates theses suckers). The last two are are created | ||
111 | by us. | ||
112 | |||
113 | The file is streamed from disk using a threaded double-buffer approach. | ||
114 | This way, the high latency operation of reading from disk can be performed without interrupting | ||
115 | the real-time device thread (which amounts to avoiding dropouts). The device thread grabs the | ||
116 | buffer that isn't being read and sends it to the CoreAudio mixer where it eventually gets | ||
117 | to the sound card. | ||
118 | |||
119 | The device thread posts a notification when the file streaming thread is out of data. This | ||
120 | notification must be handled in a separate thread to avoid potential deadlock in the | ||
121 | device thread. That's where the notification thread comes in. This thread is signaled | ||
122 | whenever a notification needs to be processed, so another file can be played back if need be. | ||
123 | |||
124 | The API in CDPlayer.cpp contains synchronization because otherwise both the notification thread | ||
125 | and main thread (or another other thread using the SDL CD api) can potentially call it at the same time. | ||
126 | |||
127 | ************************************************************************************/ | ||
128 | |||
129 | |||
130 | #include "SDL_cdrom.h" | ||
131 | #include "../SDL_syscdrom.h" | ||
132 | |||
133 | #include "CDPlayer.h" | ||
134 | |||
135 | #define kErrorFakeDevice "Error: Cannot proceed since we're faking a CD-ROM device. Reinit the CD-ROM subsystem to scan for new volumes." | ||
136 | |||
diff --git a/apps/plugins/sdl/src/cdrom/mint/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/mint/SDL_syscdrom.c new file mode 100644 index 0000000000..0bc10edb72 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/mint/SDL_syscdrom.c | |||
@@ -0,0 +1,317 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_MINT | ||
25 | |||
26 | /* | ||
27 | Atari MetaDOS CD-ROM functions | ||
28 | |||
29 | Patrice Mandin | ||
30 | */ | ||
31 | |||
32 | #include <errno.h> | ||
33 | |||
34 | #include <mint/cdromio.h> | ||
35 | #include <mint/metados.h> | ||
36 | |||
37 | #include "SDL_cdrom.h" | ||
38 | #include "../SDL_syscdrom.h" | ||
39 | |||
40 | /* Some ioctl() errno values which occur when the tray is empty */ | ||
41 | #ifndef ENOMEDIUM | ||
42 | #define ENOMEDIUM ENOENT | ||
43 | #endif | ||
44 | #define ERRNO_TRAYEMPTY(errno) \ | ||
45 | ((errno == EIO) || (errno == ENOENT) || \ | ||
46 | (errno == EINVAL) || (errno == ENOMEDIUM)) | ||
47 | |||
48 | /* The maximum number of CD-ROM drives we'll detect */ | ||
49 | #define MAX_DRIVES 32 | ||
50 | |||
51 | typedef struct { | ||
52 | char device[3]; /* Physical device letter + ':' + '\0' */ | ||
53 | metaopen_t metaopen; /* Infos on opened drive */ | ||
54 | } metados_drive_t; | ||
55 | |||
56 | static metados_drive_t metados_drives[MAX_DRIVES]; | ||
57 | |||
58 | /* The system-dependent CD control functions */ | ||
59 | static const char *SDL_SYS_CDName(int drive); | ||
60 | static int SDL_SYS_CDOpen(int drive); | ||
61 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
62 | static int SDL_SYS_CDioctl(int id, int command, void *arg); | ||
63 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
64 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
65 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
66 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
67 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
68 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
69 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
70 | |||
71 | int SDL_SYS_CDInit(void) | ||
72 | { | ||
73 | metainit_t metainit={0,0,0,0}; | ||
74 | metaopen_t metaopen; | ||
75 | int i, handle; | ||
76 | struct cdrom_subchnl info; | ||
77 | |||
78 | Metainit(&metainit); | ||
79 | if (metainit.version == NULL) { | ||
80 | #ifdef DEBUG_CDROM | ||
81 | fprintf(stderr, "MetaDOS not installed\n"); | ||
82 | #endif | ||
83 | return -1; | ||
84 | } | ||
85 | |||
86 | if (metainit.drives_map == 0) { | ||
87 | #ifdef DEBUG_CDROM | ||
88 | fprintf(stderr, "No MetaDOS devices present\n"); | ||
89 | #endif | ||
90 | return -1; | ||
91 | } | ||
92 | |||
93 | SDL_numcds = 0; | ||
94 | |||
95 | for (i='A'; i<='Z'; i++) { | ||
96 | metados_drives[SDL_numcds].device[0] = 0; | ||
97 | metados_drives[SDL_numcds].device[1] = ':'; | ||
98 | metados_drives[SDL_numcds].device[2] = 0; | ||
99 | |||
100 | if (metainit.drives_map & (1<<(i-'A'))) { | ||
101 | handle = Metaopen(i, &metaopen); | ||
102 | if (handle == 0) { | ||
103 | |||
104 | info.cdsc_format = CDROM_MSF; | ||
105 | if ( (Metaioctl(i, METADOS_IOCTL_MAGIC, CDROMSUBCHNL, &info) == 0) || ERRNO_TRAYEMPTY(errno) ) { | ||
106 | metados_drives[SDL_numcds].device[0] = i; | ||
107 | ++SDL_numcds; | ||
108 | } | ||
109 | |||
110 | Metaclose(i); | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | /* Fill in our driver capabilities */ | ||
116 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
117 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
118 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
119 | |||
120 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
121 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
122 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
123 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
124 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
125 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
126 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | void SDL_SYS_CDQuit(void) | ||
132 | { | ||
133 | SDL_numcds = 0; | ||
134 | } | ||
135 | |||
136 | static const char *SDL_SYS_CDName(int drive) | ||
137 | { | ||
138 | return(metados_drives[drive].device); | ||
139 | } | ||
140 | |||
141 | static int SDL_SYS_CDOpen(int drive) | ||
142 | { | ||
143 | int handle; | ||
144 | |||
145 | handle = Metaopen(metados_drives[drive].device[0], &(metados_drives[drive].metaopen)); | ||
146 | if (handle == 0) { | ||
147 | return drive; | ||
148 | } | ||
149 | |||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
154 | { | ||
155 | Metaclose(metados_drives[cdrom->id].device[0]); | ||
156 | } | ||
157 | |||
158 | static int SDL_SYS_CDioctl(int id, int command, void *arg) | ||
159 | { | ||
160 | int retval; | ||
161 | |||
162 | retval = Metaioctl(metados_drives[id].device[0], METADOS_IOCTL_MAGIC, command, arg); | ||
163 | if ( retval < 0 ) { | ||
164 | SDL_SetError("ioctl() error: %s", strerror(errno)); | ||
165 | } | ||
166 | return(retval); | ||
167 | } | ||
168 | |||
169 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
170 | { | ||
171 | int i,okay; | ||
172 | struct cdrom_tochdr toc; | ||
173 | struct cdrom_tocentry entry; | ||
174 | |||
175 | /* Use standard ioctl() */ | ||
176 | if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)<0) { | ||
177 | return -1; | ||
178 | } | ||
179 | |||
180 | cdrom->numtracks = toc.cdth_trk1-toc.cdth_trk0+1; | ||
181 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
182 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
183 | } | ||
184 | |||
185 | /* Read all the track TOC entries */ | ||
186 | okay=1; | ||
187 | for ( i=0; i<=cdrom->numtracks; ++i ) { | ||
188 | if ( i == cdrom->numtracks ) { | ||
189 | cdrom->track[i].id = CDROM_LEADOUT; | ||
190 | } else { | ||
191 | cdrom->track[i].id = toc.cdth_trk0+i; | ||
192 | } | ||
193 | entry.cdte_track = cdrom->track[i].id; | ||
194 | entry.cdte_format = CDROM_MSF; | ||
195 | if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY, &entry) < 0 ) { | ||
196 | okay=0; | ||
197 | break; | ||
198 | } else { | ||
199 | if ( entry.cdte_ctrl & CDROM_DATA_TRACK ) { | ||
200 | cdrom->track[i].type = SDL_DATA_TRACK; | ||
201 | } else { | ||
202 | cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
203 | } | ||
204 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
205 | entry.cdte_addr.msf.minute, | ||
206 | entry.cdte_addr.msf.second, | ||
207 | entry.cdte_addr.msf.frame); | ||
208 | cdrom->track[i].length = 0; | ||
209 | if ( i > 0 ) { | ||
210 | cdrom->track[i-1].length = cdrom->track[i].offset-cdrom->track[i-1].offset; | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | return(okay ? 0 : -1); | ||
216 | } | ||
217 | |||
218 | /* Get CD-ROM status */ | ||
219 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
220 | { | ||
221 | CDstatus status; | ||
222 | struct cdrom_tochdr toc; | ||
223 | struct cdrom_subchnl info; | ||
224 | |||
225 | info.cdsc_format = CDROM_MSF; | ||
226 | if ( SDL_SYS_CDioctl(cdrom->id, CDROMSUBCHNL, &info) < 0 ) { | ||
227 | if ( ERRNO_TRAYEMPTY(errno) ) { | ||
228 | status = CD_TRAYEMPTY; | ||
229 | } else { | ||
230 | status = CD_ERROR; | ||
231 | } | ||
232 | } else { | ||
233 | switch (info.cdsc_audiostatus) { | ||
234 | case CDROM_AUDIO_INVALID: | ||
235 | case CDROM_AUDIO_NO_STATUS: | ||
236 | /* Try to determine if there's a CD available */ | ||
237 | if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)==0) { | ||
238 | status = CD_STOPPED; | ||
239 | } else { | ||
240 | status = CD_TRAYEMPTY; | ||
241 | } | ||
242 | break; | ||
243 | case CDROM_AUDIO_COMPLETED: | ||
244 | status = CD_STOPPED; | ||
245 | break; | ||
246 | case CDROM_AUDIO_PLAY: | ||
247 | status = CD_PLAYING; | ||
248 | break; | ||
249 | case CDROM_AUDIO_PAUSED: | ||
250 | /* Workaround buggy CD-ROM drive */ | ||
251 | if ( info.cdsc_trk == CDROM_LEADOUT ) { | ||
252 | status = CD_STOPPED; | ||
253 | } else { | ||
254 | status = CD_PAUSED; | ||
255 | } | ||
256 | break; | ||
257 | default: | ||
258 | status = CD_ERROR; | ||
259 | break; | ||
260 | } | ||
261 | } | ||
262 | if ( position ) { | ||
263 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | ||
264 | *position = MSF_TO_FRAMES( | ||
265 | info.cdsc_absaddr.msf.minute, | ||
266 | info.cdsc_absaddr.msf.second, | ||
267 | info.cdsc_absaddr.msf.frame); | ||
268 | } else { | ||
269 | *position = 0; | ||
270 | } | ||
271 | } | ||
272 | return(status); | ||
273 | } | ||
274 | |||
275 | /* Start play */ | ||
276 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
277 | { | ||
278 | struct cdrom_msf playtime; | ||
279 | |||
280 | FRAMES_TO_MSF(start, | ||
281 | &playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0); | ||
282 | FRAMES_TO_MSF(start+length, | ||
283 | &playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1); | ||
284 | #ifdef DEBUG_CDROM | ||
285 | fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | ||
286 | playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, | ||
287 | playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); | ||
288 | #endif | ||
289 | |||
290 | return SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime); | ||
291 | } | ||
292 | |||
293 | /* Pause play */ | ||
294 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
295 | { | ||
296 | return SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0); | ||
297 | } | ||
298 | |||
299 | /* Resume play */ | ||
300 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
301 | { | ||
302 | return SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0); | ||
303 | } | ||
304 | |||
305 | /* Stop play */ | ||
306 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
307 | { | ||
308 | return SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0); | ||
309 | } | ||
310 | |||
311 | /* Eject the CD-ROM */ | ||
312 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
313 | { | ||
314 | return SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0); | ||
315 | } | ||
316 | |||
317 | #endif /* SDL_CDROM_MINT */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/openbsd/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/openbsd/SDL_syscdrom.c new file mode 100644 index 0000000000..e4d03a6a37 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/openbsd/SDL_syscdrom.c | |||
@@ -0,0 +1,416 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_OPENBSD | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #include <sys/types.h> | ||
29 | #include <sys/ioctl.h> | ||
30 | #include <sys/stat.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <errno.h> | ||
33 | #include <unistd.h> | ||
34 | #include <sys/ioctl.h> | ||
35 | #include <sys/cdio.h> | ||
36 | |||
37 | #include "SDL_cdrom.h" | ||
38 | #include "../SDL_syscdrom.h" | ||
39 | |||
40 | |||
41 | /* The maximum number of CD-ROM drives we'll detect */ | ||
42 | #define MAX_DRIVES 16 | ||
43 | |||
44 | /* A list of available CD-ROM drives */ | ||
45 | static char *SDL_cdlist[MAX_DRIVES]; | ||
46 | static dev_t SDL_cdmode[MAX_DRIVES]; | ||
47 | |||
48 | /* The system-dependent CD control functions */ | ||
49 | static const char *SDL_SYS_CDName(int drive); | ||
50 | static int SDL_SYS_CDOpen(int drive); | ||
51 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
52 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
53 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
54 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
55 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
56 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
57 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
58 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
59 | |||
60 | /* Some ioctl() errno values which occur when the tray is empty */ | ||
61 | #define ERRNO_TRAYEMPTY(errno) \ | ||
62 | ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL) || \ | ||
63 | (errno == ENODEV)) | ||
64 | |||
65 | /* Check a drive to see if it is a CD-ROM */ | ||
66 | static int CheckDrive(char *drive, struct stat *stbuf) | ||
67 | { | ||
68 | int is_cd, cdfd; | ||
69 | struct ioc_read_subchannel info; | ||
70 | |||
71 | /* If it doesn't exist, return -1 */ | ||
72 | if ( stat(drive, stbuf) < 0 ) { | ||
73 | return(-1); | ||
74 | } | ||
75 | |||
76 | /* If it does exist, verify that it's an available CD-ROM */ | ||
77 | is_cd = 0; | ||
78 | if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) { | ||
79 | cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); | ||
80 | if ( cdfd >= 0 ) { | ||
81 | info.address_format = CD_MSF_FORMAT; | ||
82 | info.data_format = CD_CURRENT_POSITION; | ||
83 | info.data_len = 0; | ||
84 | info.data = NULL; | ||
85 | /* Under Linux, EIO occurs when a disk is not present. | ||
86 | This isn't 100% reliable, so we use the USE_MNTENT | ||
87 | code above instead. | ||
88 | */ | ||
89 | if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) || | ||
90 | ERRNO_TRAYEMPTY(errno) ) { | ||
91 | is_cd = 1; | ||
92 | } | ||
93 | close(cdfd); | ||
94 | } | ||
95 | else if (ERRNO_TRAYEMPTY(errno)) | ||
96 | is_cd = 1; | ||
97 | } | ||
98 | return(is_cd); | ||
99 | } | ||
100 | |||
101 | /* Add a CD-ROM drive to our list of valid drives */ | ||
102 | static void AddDrive(char *drive, struct stat *stbuf) | ||
103 | { | ||
104 | int i; | ||
105 | |||
106 | if ( SDL_numcds < MAX_DRIVES ) { | ||
107 | /* Check to make sure it's not already in our list. | ||
108 | This can happen when we see a drive via symbolic link. | ||
109 | */ | ||
110 | for ( i=0; i<SDL_numcds; ++i ) { | ||
111 | if ( stbuf->st_rdev == SDL_cdmode[i] ) { | ||
112 | #ifdef DEBUG_CDROM | ||
113 | fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | ||
114 | #endif | ||
115 | return; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* Add this drive to our list */ | ||
120 | i = SDL_numcds; | ||
121 | SDL_cdlist[i] = SDL_strdup(drive); | ||
122 | if ( SDL_cdlist[i] == NULL ) { | ||
123 | SDL_OutOfMemory(); | ||
124 | return; | ||
125 | } | ||
126 | SDL_cdmode[i] = stbuf->st_rdev; | ||
127 | ++SDL_numcds; | ||
128 | #ifdef DEBUG_CDROM | ||
129 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
130 | #endif | ||
131 | } | ||
132 | } | ||
133 | |||
134 | int SDL_SYS_CDInit(void) | ||
135 | { | ||
136 | static char *checklist[] = { | ||
137 | #if defined(__OPENBSD__) | ||
138 | "?0 cd?c", "cdrom", NULL | ||
139 | #elif defined(__NETBSD__) | ||
140 | "?0 cd?d", "?0 cd?c", "cdrom", NULL | ||
141 | #else | ||
142 | "?0 cd?c", "?0 acd?c", "cdrom", NULL | ||
143 | #endif | ||
144 | }; | ||
145 | char *SDLcdrom; | ||
146 | int i, j, exists; | ||
147 | char drive[32]; | ||
148 | struct stat stbuf; | ||
149 | |||
150 | /* Fill in our driver capabilities */ | ||
151 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
152 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
153 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
154 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
155 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
156 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
157 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
158 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
159 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
160 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
161 | |||
162 | /* Look in the environment for our CD-ROM drive list */ | ||
163 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
164 | if ( SDLcdrom != NULL ) { | ||
165 | char *cdpath, *delim; | ||
166 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
167 | cdpath = SDL_stack_alloc(char, len); | ||
168 | if ( cdpath != NULL ) { | ||
169 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
170 | SDLcdrom = cdpath; | ||
171 | do { | ||
172 | delim = SDL_strchr(SDLcdrom, ':'); | ||
173 | if ( delim ) { | ||
174 | *delim++ = '\0'; | ||
175 | } | ||
176 | if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | ||
177 | AddDrive(SDLcdrom, &stbuf); | ||
178 | } | ||
179 | if ( delim ) { | ||
180 | SDLcdrom = delim; | ||
181 | } else { | ||
182 | SDLcdrom = NULL; | ||
183 | } | ||
184 | } while ( SDLcdrom ); | ||
185 | SDL_stack_free(cdpath); | ||
186 | } | ||
187 | |||
188 | /* If we found our drives, there's nothing left to do */ | ||
189 | if ( SDL_numcds > 0 ) { | ||
190 | return(0); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /* Scan the system for CD-ROM drives */ | ||
195 | for ( i=0; checklist[i]; ++i ) { | ||
196 | if ( checklist[i][0] == '?' ) { | ||
197 | char *insert; | ||
198 | exists = 1; | ||
199 | for ( j=checklist[i][1]; exists; ++j ) { | ||
200 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", &checklist[i][3]); | ||
201 | insert = SDL_strchr(drive, '?'); | ||
202 | if ( insert != NULL ) { | ||
203 | *insert = j; | ||
204 | } | ||
205 | switch (CheckDrive(drive, &stbuf)) { | ||
206 | /* Drive exists and is a CD-ROM */ | ||
207 | case 1: | ||
208 | AddDrive(drive, &stbuf); | ||
209 | break; | ||
210 | /* Drive exists, but isn't a CD-ROM */ | ||
211 | case 0: | ||
212 | break; | ||
213 | /* Drive doesn't exist */ | ||
214 | case -1: | ||
215 | exists = 0; | ||
216 | break; | ||
217 | } | ||
218 | } | ||
219 | } else { | ||
220 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); | ||
221 | if ( CheckDrive(drive, &stbuf) > 0 ) { | ||
222 | AddDrive(drive, &stbuf); | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | return(0); | ||
227 | } | ||
228 | |||
229 | /* General ioctl() CD-ROM command function */ | ||
230 | static int SDL_SYS_CDioctl(int id, int command, void *arg) | ||
231 | { | ||
232 | int retval; | ||
233 | |||
234 | retval = ioctl(id, command, arg); | ||
235 | if ( retval < 0 ) { | ||
236 | SDL_SetError("ioctl() error: %s", strerror(errno)); | ||
237 | } | ||
238 | return(retval); | ||
239 | } | ||
240 | |||
241 | static const char *SDL_SYS_CDName(int drive) | ||
242 | { | ||
243 | return(SDL_cdlist[drive]); | ||
244 | } | ||
245 | |||
246 | static int SDL_SYS_CDOpen(int drive) | ||
247 | { | ||
248 | return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0)); | ||
249 | } | ||
250 | |||
251 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
252 | { | ||
253 | struct ioc_toc_header toc; | ||
254 | int i, okay; | ||
255 | struct ioc_read_toc_entry entry; | ||
256 | struct cd_toc_entry data; | ||
257 | |||
258 | okay = 0; | ||
259 | if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) { | ||
260 | cdrom->numtracks = toc.ending_track-toc.starting_track+1; | ||
261 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
262 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
263 | } | ||
264 | /* Read all the track TOC entries */ | ||
265 | for ( i=0; i<=cdrom->numtracks; ++i ) { | ||
266 | if ( i == cdrom->numtracks ) { | ||
267 | cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */ | ||
268 | } else { | ||
269 | cdrom->track[i].id = toc.starting_track+i; | ||
270 | } | ||
271 | entry.starting_track = cdrom->track[i].id; | ||
272 | entry.address_format = CD_MSF_FORMAT; | ||
273 | entry.data_len = sizeof(data); | ||
274 | entry.data = &data; | ||
275 | if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS, | ||
276 | &entry) < 0 ) { | ||
277 | break; | ||
278 | } else { | ||
279 | cdrom->track[i].type = data.control; | ||
280 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
281 | data.addr.msf.minute, | ||
282 | data.addr.msf.second, | ||
283 | data.addr.msf.frame); | ||
284 | cdrom->track[i].length = 0; | ||
285 | if ( i > 0 ) { | ||
286 | cdrom->track[i-1].length = | ||
287 | cdrom->track[i].offset- | ||
288 | cdrom->track[i-1].offset; | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | if ( i == (cdrom->numtracks+1) ) { | ||
293 | okay = 1; | ||
294 | } | ||
295 | } | ||
296 | return(okay ? 0 : -1); | ||
297 | } | ||
298 | |||
299 | /* Get CD-ROM status */ | ||
300 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
301 | { | ||
302 | CDstatus status; | ||
303 | struct ioc_toc_header toc; | ||
304 | struct ioc_read_subchannel info; | ||
305 | struct cd_sub_channel_info data; | ||
306 | |||
307 | info.address_format = CD_MSF_FORMAT; | ||
308 | info.data_format = CD_CURRENT_POSITION; | ||
309 | info.track = 0; | ||
310 | info.data_len = sizeof(data); | ||
311 | info.data = &data; | ||
312 | if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) { | ||
313 | if ( ERRNO_TRAYEMPTY(errno) ) { | ||
314 | status = CD_TRAYEMPTY; | ||
315 | } else { | ||
316 | status = CD_ERROR; | ||
317 | } | ||
318 | } else { | ||
319 | switch (data.header.audio_status) { | ||
320 | case CD_AS_AUDIO_INVALID: | ||
321 | case CD_AS_NO_STATUS: | ||
322 | /* Try to determine if there's a CD available */ | ||
323 | if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0) | ||
324 | status = CD_STOPPED; | ||
325 | else | ||
326 | status = CD_TRAYEMPTY; | ||
327 | break; | ||
328 | case CD_AS_PLAY_COMPLETED: | ||
329 | status = CD_STOPPED; | ||
330 | break; | ||
331 | case CD_AS_PLAY_IN_PROGRESS: | ||
332 | status = CD_PLAYING; | ||
333 | break; | ||
334 | case CD_AS_PLAY_PAUSED: | ||
335 | status = CD_PAUSED; | ||
336 | break; | ||
337 | default: | ||
338 | status = CD_ERROR; | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | if ( position ) { | ||
343 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | ||
344 | *position = MSF_TO_FRAMES( | ||
345 | data.what.position.absaddr.msf.minute, | ||
346 | data.what.position.absaddr.msf.second, | ||
347 | data.what.position.absaddr.msf.frame); | ||
348 | } else { | ||
349 | *position = 0; | ||
350 | } | ||
351 | } | ||
352 | return(status); | ||
353 | } | ||
354 | |||
355 | /* Start play */ | ||
356 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
357 | { | ||
358 | struct ioc_play_msf playtime; | ||
359 | |||
360 | FRAMES_TO_MSF(start, | ||
361 | &playtime.start_m, &playtime.start_s, &playtime.start_f); | ||
362 | FRAMES_TO_MSF(start+length, | ||
363 | &playtime.end_m, &playtime.end_s, &playtime.end_f); | ||
364 | #ifdef DEBUG_CDROM | ||
365 | fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | ||
366 | playtime.start_m, playtime.start_s, playtime.start_f, | ||
367 | playtime.end_m, playtime.end_s, playtime.end_f); | ||
368 | #endif | ||
369 | ioctl(cdrom->id, CDIOCSTART, 0); | ||
370 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime)); | ||
371 | } | ||
372 | |||
373 | /* Pause play */ | ||
374 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
375 | { | ||
376 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0)); | ||
377 | } | ||
378 | |||
379 | /* Resume play */ | ||
380 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
381 | { | ||
382 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0)); | ||
383 | } | ||
384 | |||
385 | /* Stop play */ | ||
386 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
387 | { | ||
388 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0)); | ||
389 | } | ||
390 | |||
391 | /* Eject the CD-ROM */ | ||
392 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
393 | { | ||
394 | SDL_SYS_CDioctl(cdrom->id, CDIOCALLOW, 0); | ||
395 | return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0)); | ||
396 | } | ||
397 | |||
398 | /* Close the CD-ROM handle */ | ||
399 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
400 | { | ||
401 | close(cdrom->id); | ||
402 | } | ||
403 | |||
404 | void SDL_SYS_CDQuit(void) | ||
405 | { | ||
406 | int i; | ||
407 | |||
408 | if ( SDL_numcds > 0 ) { | ||
409 | for ( i=0; i<SDL_numcds; ++i ) { | ||
410 | SDL_free(SDL_cdlist[i]); | ||
411 | } | ||
412 | SDL_numcds = 0; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | #endif /* SDL_CDROM_OPENBSD */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/os2/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/os2/SDL_syscdrom.c new file mode 100644 index 0000000000..6ed9c658fb --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/os2/SDL_syscdrom.c | |||
@@ -0,0 +1,393 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_OS2 | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #define INCL_MCIOS2 | ||
29 | #include <os2.h> | ||
30 | #include <os2me.h> | ||
31 | |||
32 | #include "SDL_cdrom.h" | ||
33 | #include "../SDL_syscdrom.h" | ||
34 | |||
35 | /* Size of MCI result buffer (in bytes) */ | ||
36 | #define MCI_CMDRETBUFSIZE 128 | ||
37 | |||
38 | /* The maximum number of CD-ROM drives we'll detect */ | ||
39 | #define MAX_DRIVES 16 | ||
40 | |||
41 | /* A list of available CD-ROM drives */ | ||
42 | static char *SDL_cdlist[MAX_DRIVES]; | ||
43 | //static dev_t SDL_cdmode[MAX_DRIVES]; | ||
44 | |||
45 | /* The system-dependent CD control functions */ | ||
46 | static const char *SDL_SYS_CDName(int drive); | ||
47 | static int SDL_SYS_CDOpen(int drive); | ||
48 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
49 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
50 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
51 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
52 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
53 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
54 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
55 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
56 | |||
57 | /* MCI Timing Functions */ | ||
58 | #define MCI_MMTIMEPERSECOND 3000 | ||
59 | #define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND) | ||
60 | |||
61 | |||
62 | /* Ready for MCI CDAudio Devices */ | ||
63 | int SDL_SYS_CDInit(void) | ||
64 | { | ||
65 | int i; /* generig counter */ | ||
66 | MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */ | ||
67 | CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */ | ||
68 | |||
69 | /* Fill in our driver capabilities */ | ||
70 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
71 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
72 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
73 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
74 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
75 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
76 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
77 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
78 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
79 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
80 | |||
81 | /* Get the number of CD ROMs in the System */ | ||
82 | /* Clean SysInfo structure */ | ||
83 | SDL_memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS)); | ||
84 | /* Prepare structure to Ask Numer of Audio CDs */ | ||
85 | msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ | ||
86 | msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ | ||
87 | msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ | ||
88 | if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); | ||
89 | SDL_numcds = atoi(SysInfoRet); | ||
90 | if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */ | ||
91 | |||
92 | /* Get and Add their system name to the SDL_cdlist */ | ||
93 | msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */ | ||
94 | msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */ | ||
95 | msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */ | ||
96 | for (i=0; i<SDL_numcds; i++) | ||
97 | { | ||
98 | msp.ulNumber = i+1; | ||
99 | mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_NAME | MCI_WAIT,&msp, 0); | ||
100 | SDL_cdlist[i] = SDL_strdup(SysInfoRet); | ||
101 | if ( SDL_cdlist[i] == NULL ) | ||
102 | { | ||
103 | SDL_OutOfMemory(); | ||
104 | return(-1); | ||
105 | } | ||
106 | } | ||
107 | return(0); | ||
108 | } | ||
109 | |||
110 | /* Return CDAudio System Dependent Device Name - Ready for MCI*/ | ||
111 | static const char *SDL_SYS_CDName(int drive) | ||
112 | { | ||
113 | return(SDL_cdlist[drive]); | ||
114 | } | ||
115 | |||
116 | /* Open CDAudio Device - Ready for MCI */ | ||
117 | static int SDL_SYS_CDOpen(int drive) | ||
118 | { | ||
119 | MCI_OPEN_PARMS mop; | ||
120 | MCI_SET_PARMS msp; | ||
121 | MCI_GENERIC_PARMS mgp; | ||
122 | |||
123 | /* Open the device */ | ||
124 | mop.hwndCallback = (HWND)NULL; // None | ||
125 | mop.usDeviceID = (USHORT)NULL; // Will be returned. | ||
126 | mop.pszDeviceType = (PSZ)SDL_cdlist[drive]; // CDAudio Device | ||
127 | if (LOUSHORT(mciSendCommand(0,MCI_OPEN,MCI_WAIT,&mop, 0)) != MCIERR_SUCCESS) return(CD_ERROR); | ||
128 | /* Set time format */ | ||
129 | msp.hwndCallback = (HWND)NULL; // None | ||
130 | msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure | ||
131 | msp.ulSpeedFormat = (ULONG)NULL; // No change | ||
132 | msp.ulAudio = (ULONG)NULL; // No Channel | ||
133 | msp.ulLevel = (ULONG)NULL; // No Volume | ||
134 | msp.ulOver = (ULONG)NULL; // No Delay | ||
135 | msp.ulItem = (ULONG)NULL; // No item | ||
136 | msp.ulValue = (ULONG)NULL; // No value for item flag | ||
137 | if (LOUSHORT(mciSendCommand(mop.usDeviceID,MCI_SET,MCI_WAIT | MCI_SET_TIME_FORMAT,&msp, 0)) == MCIERR_SUCCESS) return (mop.usDeviceID); | ||
138 | /* Error setting time format? - Close opened device */ | ||
139 | mgp.hwndCallback = (HWND)NULL; // None | ||
140 | mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp, 0); | ||
141 | return(CD_ERROR); | ||
142 | } | ||
143 | |||
144 | /* Get CD Table Of Contents - Ready for MCI */ | ||
145 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
146 | { | ||
147 | MCI_TOC_PARMS mtp; | ||
148 | MCI_STATUS_PARMS msp; | ||
149 | MCI_TOC_REC * mtr; | ||
150 | INT i; | ||
151 | |||
152 | /* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */ | ||
153 | if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED) return 0; | ||
154 | |||
155 | /* Get Number of Tracks */ | ||
156 | msp.hwndCallback = (HWND)NULL; /* None */ | ||
157 | msp.ulReturn = (ULONG)NULL; /* We want this information */ | ||
158 | msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS; | ||
159 | msp.ulValue = (ULONG)NULL; /* No additional information */ | ||
160 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR); | ||
161 | cdrom->numtracks = msp.ulReturn; | ||
162 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) | ||
163 | { | ||
164 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
165 | } | ||
166 | /* Alocate space for TOC data */ | ||
167 | mtr = (MCI_TOC_REC *)SDL_malloc(cdrom->numtracks*sizeof(MCI_TOC_REC)); | ||
168 | if ( mtr == NULL ) | ||
169 | { | ||
170 | SDL_OutOfMemory(); | ||
171 | return(-1); | ||
172 | } | ||
173 | /* Get TOC from CD */ | ||
174 | mtp.pBuf = mtr; | ||
175 | mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC); | ||
176 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_GETTOC,MCI_WAIT,&mtp, 0)) != MCIERR_SUCCESS) | ||
177 | { | ||
178 | SDL_OutOfMemory(); | ||
179 | SDL_free(mtr); | ||
180 | return(CD_ERROR); | ||
181 | } | ||
182 | /* Fill SDL Tracks Structure */ | ||
183 | for (i=0; i<cdrom->numtracks; i++) | ||
184 | { | ||
185 | /* Set Track ID */ | ||
186 | cdrom->track[i].id = (mtr+i)->TrackNum; | ||
187 | /* Set Track Type */ | ||
188 | msp.hwndCallback = (HWND)NULL; /* None */ | ||
189 | msp.ulReturn = (ULONG)NULL; /* We want this information */ | ||
190 | msp.ulItem = MCI_CD_STATUS_TRACK_TYPE; | ||
191 | msp.ulValue = (ULONG)((mtr+i)->TrackNum); /* Track Number? */ | ||
192 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) | ||
193 | { | ||
194 | SDL_free(mtr); | ||
195 | return (CD_ERROR); | ||
196 | } | ||
197 | if (msp.ulReturn==MCI_CD_TRACK_AUDIO) cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
198 | else cdrom->track[i].type = SDL_DATA_TRACK; | ||
199 | /* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */ | ||
200 | cdrom->track[i].length = FRAMESFROMMM((mtr+i)->ulEndAddr - (mtr+i)->ulStartAddr); | ||
201 | /* Set Track Offset */ | ||
202 | cdrom->track[i].offset = FRAMESFROMMM((mtr+i)->ulStartAddr); | ||
203 | } | ||
204 | SDL_free(mtr); | ||
205 | return(0); | ||
206 | } | ||
207 | |||
208 | |||
209 | /* Get CD-ROM status - Ready for MCI */ | ||
210 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
211 | { | ||
212 | CDstatus status; | ||
213 | MCI_STATUS_PARMS msp; | ||
214 | |||
215 | /* Get Status from MCI */ | ||
216 | msp.hwndCallback = (HWND)NULL; /* None */ | ||
217 | msp.ulReturn = (ULONG)NULL; /* We want this information */ | ||
218 | msp.ulItem = MCI_STATUS_MODE; | ||
219 | msp.ulValue = (ULONG)NULL; /* No additional information */ | ||
220 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR; | ||
221 | else | ||
222 | { | ||
223 | switch(msp.ulReturn) | ||
224 | { | ||
225 | case MCI_MODE_NOT_READY: | ||
226 | status = CD_TRAYEMPTY; | ||
227 | break; | ||
228 | case MCI_MODE_PAUSE: | ||
229 | status = CD_PAUSED; | ||
230 | break; | ||
231 | case MCI_MODE_PLAY: | ||
232 | status = CD_PLAYING; | ||
233 | break; | ||
234 | case MCI_MODE_STOP: | ||
235 | status = CD_STOPPED; | ||
236 | break; | ||
237 | /* These cases should not occour */ | ||
238 | case MCI_MODE_RECORD: | ||
239 | case MCI_MODE_SEEK: | ||
240 | default: | ||
241 | status = CD_ERROR; | ||
242 | break; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /* Determine position */ | ||
247 | if (position != NULL) /* The SDL $&$&%# CDROM call sends NULL pointer here! */ | ||
248 | { | ||
249 | if ((status == CD_PLAYING) || (status == CD_PAUSED)) | ||
250 | { | ||
251 | /* Get Position */ | ||
252 | msp.hwndCallback = (HWND)NULL; /* None */ | ||
253 | msp.ulReturn = (ULONG)NULL; /* We want this information */ | ||
254 | msp.ulItem = MCI_STATUS_POSITION; | ||
255 | msp.ulValue = (ULONG)NULL; /* No additiona info */ | ||
256 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return (CD_ERROR); | ||
257 | /* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */ | ||
258 | *position = MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),MSF_SECOND(msp.ulReturn),MSF_FRAME(msp.ulReturn)); | ||
259 | } | ||
260 | else *position = 0; | ||
261 | } | ||
262 | return(status); | ||
263 | } | ||
264 | |||
265 | /* Start play - Ready for MCI */ | ||
266 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
267 | { | ||
268 | MCI_GENERIC_PARMS mgp; | ||
269 | MCI_STATUS_PARMS msp; | ||
270 | MCI_PLAY_PARMS mpp; | ||
271 | ULONG min,sec,frm; | ||
272 | |||
273 | /* Start MSF */ | ||
274 | FRAMES_TO_MSF(start, &min, &sec, &frm); | ||
275 | MSF_MINUTE(mpp.ulFrom) = min; | ||
276 | MSF_SECOND(mpp.ulFrom) = sec; | ||
277 | MSF_FRAME(mpp.ulFrom) = frm; | ||
278 | /* End MSF */ | ||
279 | FRAMES_TO_MSF(start+length, &min, &sec, &frm); | ||
280 | MSF_MINUTE(mpp.ulTo) = min; | ||
281 | MSF_SECOND(mpp.ulTo) = sec; | ||
282 | MSF_FRAME(mpp.ulTo) = frm; | ||
283 | #ifdef DEBUG_CDROM | ||
284 | fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | ||
285 | playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, | ||
286 | playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); | ||
287 | #endif | ||
288 | /* Verifies if it is paused first... and if it is, unpause before stopping it. */ | ||
289 | msp.hwndCallback = (HWND)NULL; /* None */ | ||
290 | msp.ulReturn = (ULONG)NULL; /* We want this information */ | ||
291 | msp.ulItem = MCI_STATUS_MODE; | ||
292 | msp.ulValue = (ULONG)NULL; /* No additional information */ | ||
293 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) | ||
294 | { | ||
295 | if (msp.ulReturn == MCI_MODE_PAUSE) | ||
296 | { | ||
297 | mgp.hwndCallback = (HWND)NULL; // None | ||
298 | mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); | ||
299 | } | ||
300 | } | ||
301 | /* Now play it. */ | ||
302 | mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp | ||
303 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0; | ||
304 | return (CD_ERROR); | ||
305 | } | ||
306 | |||
307 | /* Pause play - Ready for MCI */ | ||
308 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
309 | { | ||
310 | MCI_GENERIC_PARMS mgp; | ||
311 | |||
312 | mgp.hwndCallback = (HWND)NULL; // None | ||
313 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; | ||
314 | return(CD_ERROR); | ||
315 | } | ||
316 | |||
317 | /* Resume play - Ready for MCI */ | ||
318 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
319 | { | ||
320 | MCI_GENERIC_PARMS mgp; | ||
321 | |||
322 | mgp.hwndCallback = (HWND)NULL; // None | ||
323 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; | ||
324 | return(CD_ERROR); | ||
325 | } | ||
326 | |||
327 | /* Stop play - Ready for MCI */ | ||
328 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
329 | { | ||
330 | MCI_GENERIC_PARMS mgp; | ||
331 | MCI_STATUS_PARMS msp; | ||
332 | |||
333 | /* Verifies if it is paused first... and if it is, unpause before stopping it. */ | ||
334 | msp.hwndCallback = (HWND)NULL; /* None */ | ||
335 | msp.ulReturn = (ULONG)NULL; /* We want this information */ | ||
336 | msp.ulItem = MCI_STATUS_MODE; | ||
337 | msp.ulValue = (ULONG)NULL; /* No additional information */ | ||
338 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS) | ||
339 | { | ||
340 | if (msp.ulReturn == MCI_MODE_PAUSE) | ||
341 | { | ||
342 | mgp.hwndCallback = (HWND)NULL; // None | ||
343 | mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0); | ||
344 | } | ||
345 | } | ||
346 | /* Now stops the media */ | ||
347 | mgp.hwndCallback = (HWND)NULL; // None | ||
348 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0; | ||
349 | return(CD_ERROR); | ||
350 | } | ||
351 | |||
352 | /* Eject the CD-ROM - Ready for MCI */ | ||
353 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
354 | { | ||
355 | MCI_SET_PARMS msp; | ||
356 | |||
357 | msp.hwndCallback = (HWND)NULL; // None | ||
358 | msp.ulTimeFormat = (ULONG)NULL; // No change | ||
359 | msp.ulSpeedFormat = (ULONG)NULL; // No change | ||
360 | msp.ulAudio = (ULONG)NULL; // No Channel | ||
361 | msp.ulLevel = (ULONG)NULL; // No Volume | ||
362 | msp.ulOver = (ULONG)NULL; // No Delay | ||
363 | msp.ulItem = (ULONG)NULL; // No item | ||
364 | msp.ulValue = (ULONG)NULL; // No value for item flag | ||
365 | if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0; | ||
366 | return(CD_ERROR); | ||
367 | } | ||
368 | |||
369 | /* Close the CD-ROM handle - Ready for MCI */ | ||
370 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
371 | { | ||
372 | MCI_GENERIC_PARMS mgp; | ||
373 | |||
374 | mgp.hwndCallback = (HWND)NULL; // None | ||
375 | mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0); | ||
376 | } | ||
377 | |||
378 | /* Finalize CDROM Subsystem - Ready for MCI */ | ||
379 | void SDL_SYS_CDQuit(void) | ||
380 | { | ||
381 | int i; | ||
382 | |||
383 | if ( SDL_numcds > 0 ) | ||
384 | { | ||
385 | for ( i=0; i<SDL_numcds; ++i ) | ||
386 | { | ||
387 | SDL_free(SDL_cdlist[i]); | ||
388 | } | ||
389 | SDL_numcds = 0; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | #endif /* SDL_CDROM_OS2 */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/osf/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/osf/SDL_syscdrom.c new file mode 100644 index 0000000000..8478a7b4cf --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/osf/SDL_syscdrom.c | |||
@@ -0,0 +1,444 @@ | |||
1 | /* | ||
2 | Tru64 audio module for SDL (Simple DirectMedia Layer) | ||
3 | Copyright (C) 2003 | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | |||
20 | */ | ||
21 | #include "SDL_config.h" | ||
22 | |||
23 | #ifdef SDL_CDROM_OSF | ||
24 | |||
25 | /* Functions for system-level CD-ROM audio control */ | ||
26 | |||
27 | /* #define DEBUG_CDROM 1 */ | ||
28 | |||
29 | #include <sys/types.h> | ||
30 | #include <dirent.h> | ||
31 | #include <sys/stat.h> | ||
32 | #include <fcntl.h> | ||
33 | #include <io/cam/cdrom.h> | ||
34 | #include <io/cam/rzdisk.h> | ||
35 | #include <io/common/devgetinfo.h> | ||
36 | |||
37 | #include "SDL_cdrom.h" | ||
38 | #include "../SDL_syscdrom.h" | ||
39 | |||
40 | /* The maximum number of CD-ROM drives we'll detect */ | ||
41 | #define MAX_DRIVES 16 | ||
42 | |||
43 | /* A list of available CD-ROM drives */ | ||
44 | static char *SDL_cdlist[MAX_DRIVES]; | ||
45 | static dev_t SDL_cdmode[MAX_DRIVES]; | ||
46 | |||
47 | /* The system-dependent CD control functions */ | ||
48 | static const char *SDL_SYS_CDName(int drive); | ||
49 | static int SDL_SYS_CDOpen(int drive); | ||
50 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
51 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
52 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
53 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
54 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
55 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
56 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
57 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
58 | |||
59 | /* Check a drive to see if it is a CD-ROM */ | ||
60 | /* Caution!! Not tested. */ | ||
61 | static int CheckDrive(char *drive, struct stat *stbuf) | ||
62 | { | ||
63 | int cdfd, is_cd = 0; | ||
64 | struct mode_sel_sns_params msp; | ||
65 | struct inquiry_info inq; | ||
66 | |||
67 | #ifdef DEBUG_CDROM | ||
68 | char *devtype[] = {"Disk", "Tape", "Printer", "Processor", "WORM", | ||
69 | "CD-ROM", "Scanner", "Optical", "Changer", "Comm", "Unknown"}; | ||
70 | #endif | ||
71 | |||
72 | bzero(&msp, sizeof(msp)); | ||
73 | bzero(&inq, sizeof(inq)); | ||
74 | |||
75 | /* If it doesn't exist, return -1 */ | ||
76 | if ( stat(drive, stbuf) < 0 ) { | ||
77 | return(-1); | ||
78 | } | ||
79 | |||
80 | if ( (cdfd = open(drive, (O_RDWR|O_NDELAY), 0)) >= 0 ) { | ||
81 | msp.msp_addr = (caddr_t) &inq; | ||
82 | msp.msp_pgcode = 0; | ||
83 | msp.msp_pgctrl = 0; | ||
84 | msp.msp_length = sizeof(inq); | ||
85 | msp.msp_setps = 0; | ||
86 | |||
87 | if ( ioctl(cdfd, SCSI_GET_INQUIRY_DATA, &msp) ) | ||
88 | return (0); | ||
89 | |||
90 | #ifdef DEBUG_CDROM | ||
91 | fprintf(stderr, "Device Type: %s\n", devtype[inq.perfdt]); | ||
92 | fprintf(stderr, "Vendor: %.8s\n", inq.vndrid); | ||
93 | fprintf(stderr, "Product: %.8s\n", inq.prodid); | ||
94 | fprintf(stderr, "Revision: %.8s\n", inq.revlvl); | ||
95 | #endif | ||
96 | if ( inq.perfdt == DTYPE_RODIRECT ) | ||
97 | is_cd = 1; | ||
98 | } | ||
99 | |||
100 | return(is_cd); | ||
101 | } | ||
102 | |||
103 | /* Add a CD-ROM drive to our list of valid drives */ | ||
104 | static void AddDrive(char *drive, struct stat *stbuf) | ||
105 | { | ||
106 | int i; | ||
107 | |||
108 | if ( SDL_numcds < MAX_DRIVES ) { | ||
109 | /* Check to make sure it's not already in our list. | ||
110 | * This can happen when we see a drive via symbolic link. | ||
111 | * | ||
112 | */ | ||
113 | for ( i=0; i<SDL_numcds; ++i ) { | ||
114 | if ( stbuf->st_rdev == SDL_cdmode[i] ) { | ||
115 | #ifdef DEBUG_CDROM | ||
116 | fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | ||
117 | #endif | ||
118 | return; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /* Add this drive to our list */ | ||
123 | i = SDL_numcds; | ||
124 | SDL_cdlist[i] = SDL_strdup(drive); | ||
125 | if ( SDL_cdlist[i] == NULL ) { | ||
126 | SDL_OutOfMemory(); | ||
127 | return; | ||
128 | } | ||
129 | SDL_cdmode[i] = stbuf->st_rdev; | ||
130 | ++SDL_numcds; | ||
131 | #ifdef DEBUG_CDROM | ||
132 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
133 | #endif | ||
134 | } | ||
135 | } | ||
136 | |||
137 | int SDL_SYS_CDInit(void) | ||
138 | { | ||
139 | /* checklist: | ||
140 | * | ||
141 | * Tru64 5.X (/dev/rdisk/cdrom?c) | ||
142 | * dir: /dev/rdisk, name: cdrom | ||
143 | * | ||
144 | * Digital UNIX 4.0X (/dev/rrz?c) | ||
145 | * dir: /dev, name: rrz | ||
146 | * | ||
147 | */ | ||
148 | struct { | ||
149 | char *dir; | ||
150 | char *name; | ||
151 | } checklist[] = { | ||
152 | {"/dev/rdisk", "cdrom"}, | ||
153 | {"/dev", "rrz"}, | ||
154 | {NULL, NULL}}; | ||
155 | char drive[32]; | ||
156 | char *SDLcdrom; | ||
157 | int i, j, exists; | ||
158 | struct stat stbuf; | ||
159 | |||
160 | /* Fill in our driver capabilities */ | ||
161 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
162 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
163 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
164 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
165 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
166 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
167 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
168 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
169 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
170 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
171 | |||
172 | |||
173 | /* Look in the environment for our CD-ROM drive list */ | ||
174 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
175 | if ( SDLcdrom != NULL ) { | ||
176 | char *cdpath, *delim; | ||
177 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
178 | cdpath = SDL_stack_alloc(char, len); | ||
179 | if ( cdpath != NULL ) { | ||
180 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
181 | SDLcdrom = cdpath; | ||
182 | do { | ||
183 | delim = SDL_strchr(SDLcdrom, ':'); | ||
184 | if ( delim ) { | ||
185 | *delim++ = '\0'; | ||
186 | } | ||
187 | if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | ||
188 | AddDrive(SDLcdrom, &stbuf); | ||
189 | } | ||
190 | if ( delim ) { | ||
191 | SDLcdrom = delim; | ||
192 | } else { | ||
193 | SDLcdrom = NULL; | ||
194 | } | ||
195 | } while ( SDLcdrom ); | ||
196 | SDL_stack_free(cdpath); | ||
197 | } | ||
198 | |||
199 | /* If we found our drives, there's nothing left to do */ | ||
200 | if ( SDL_numcds > 0 ) { | ||
201 | return(0); | ||
202 | } | ||
203 | } | ||
204 | /* Scan the system for CD-ROM drives */ | ||
205 | for ( i = 0; checklist[i].dir; ++i) { | ||
206 | DIR *devdir; | ||
207 | struct dirent *devent; | ||
208 | int name_len; | ||
209 | |||
210 | devdir = opendir(checklist[i].dir); | ||
211 | if (devdir) { | ||
212 | name_len = SDL_strlen(checklist[i].name); | ||
213 | while (devent = readdir(devdir)) | ||
214 | if (SDL_memcmp(checklist[i].name, devent->d_name, name_len) == 0) | ||
215 | if (devent->d_name[devent->d_namlen-1] == 'c') { | ||
216 | SDL_snprintf(drive, SDL_arraysize(drive), "%s/%s", checklist[i].dir, devent->d_name); | ||
217 | #ifdef DEBUG_CDROM | ||
218 | fprintf(stderr, "Try to add drive: %s\n", drive); | ||
219 | #endif | ||
220 | if ( CheckDrive(drive, &stbuf) > 0 ) | ||
221 | AddDrive(drive, &stbuf); | ||
222 | } | ||
223 | closedir(devdir); | ||
224 | } else { | ||
225 | #ifdef DEBUG_CDROM | ||
226 | fprintf(stderr, "cannot open dir: %s\n", checklist[i].dir); | ||
227 | #endif | ||
228 | } | ||
229 | } | ||
230 | return (0); | ||
231 | } | ||
232 | |||
233 | static const char *SDL_SYS_CDName(int drive) | ||
234 | { | ||
235 | return(SDL_cdlist[drive]); | ||
236 | } | ||
237 | |||
238 | static int SDL_SYS_CDOpen(int drive) | ||
239 | { | ||
240 | /* O_RDWR: To use ioctl(fd, SCSI_STOP_UNIT) */ | ||
241 | return(open(SDL_cdlist[drive], (O_RDWR|O_NDELAY), 0)); | ||
242 | } | ||
243 | |||
244 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
245 | { | ||
246 | struct cd_toc toc; | ||
247 | struct cd_toc_header hdr; | ||
248 | struct cd_toc_entry *cdte; | ||
249 | int i; | ||
250 | int okay = 0; | ||
251 | if ( ioctl(cdrom->id, CDROM_TOC_HEADER, &hdr) ) { | ||
252 | fprintf(stderr,"ioctl error CDROM_TOC_HEADER\n"); | ||
253 | return -1; | ||
254 | } | ||
255 | cdrom->numtracks = hdr.th_ending_track - hdr.th_starting_track + 1; | ||
256 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
257 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
258 | } | ||
259 | #ifdef DEBUG_CDROM | ||
260 | fprintf(stderr,"hdr.th_data_len1 = %d\n", hdr.th_data_len1); | ||
261 | fprintf(stderr,"hdr.th_data_len0 = %d\n", hdr.th_data_len0); | ||
262 | fprintf(stderr,"hdr.th_starting_track = %d\n", hdr.th_starting_track); | ||
263 | fprintf(stderr,"hdr.th_ending_track = %d\n", hdr.th_ending_track); | ||
264 | fprintf(stderr,"cdrom->numtracks = %d\n", cdrom->numtracks); | ||
265 | #endif | ||
266 | toc.toc_address_format = CDROM_LBA_FORMAT; | ||
267 | toc.toc_starting_track = 0; | ||
268 | toc.toc_alloc_length = (hdr.th_data_len1 << 8) + | ||
269 | hdr.th_data_len0 + sizeof(hdr); | ||
270 | if ( (toc.toc_buffer = alloca(toc.toc_alloc_length)) == NULL) { | ||
271 | fprintf(stderr,"cannot allocate toc.toc_buffer\n"); | ||
272 | return -1; | ||
273 | } | ||
274 | |||
275 | bzero (toc.toc_buffer, toc.toc_alloc_length); | ||
276 | if (ioctl(cdrom->id, CDROM_TOC_ENTRYS, &toc)) { | ||
277 | fprintf(stderr,"ioctl error CDROM_TOC_ENTRYS\n"); | ||
278 | return -1; | ||
279 | } | ||
280 | |||
281 | cdte =(struct cd_toc_entry *) ((char *) toc.toc_buffer + sizeof(hdr)); | ||
282 | for (i=0; i <= cdrom->numtracks; ++i) { | ||
283 | if (i == cdrom->numtracks ) { | ||
284 | cdrom->track[i].id = 0xAA;; | ||
285 | } else { | ||
286 | cdrom->track[i].id = hdr.th_starting_track + i; | ||
287 | } | ||
288 | |||
289 | cdrom->track[i].type = | ||
290 | cdte[i].te_control & CDROM_DATA_TRACK; | ||
291 | cdrom->track[i].offset = | ||
292 | cdte[i].te_absaddr.lba.addr3 << 24 | | ||
293 | cdte[i].te_absaddr.lba.addr2 << 16 | | ||
294 | cdte[i].te_absaddr.lba.addr1 << 8 | | ||
295 | cdte[i].te_absaddr.lba.addr0; | ||
296 | cdrom->track[i].length = 0; | ||
297 | if ( i > 0 ) { | ||
298 | cdrom->track[i - 1].length = | ||
299 | cdrom->track[i].offset - | ||
300 | cdrom->track[i - 1].offset; | ||
301 | } | ||
302 | } | ||
303 | #ifdef DEBUG_CDROM | ||
304 | for (i = 0; i <= cdrom->numtracks; i++) { | ||
305 | fprintf(stderr,"toc_entry[%d].te_track_number = %d\n", | ||
306 | i,cdte[i].te_track_number); | ||
307 | fprintf(stderr,"cdrom->track[%d].id = %d\n", i,cdrom->track[i].id); | ||
308 | fprintf(stderr,"cdrom->track[%d].type = %x\n", i,cdrom->track[i].type); | ||
309 | fprintf(stderr,"cdrom->track[%d].offset = %d\n", i,cdrom->track[i].offset); | ||
310 | fprintf(stderr,"cdrom->track[%d].length = %d\n", i,cdrom->track[i].length); | ||
311 | } | ||
312 | #endif | ||
313 | if ( i == (cdrom->numtracks+1) ) { | ||
314 | okay = 1; | ||
315 | } | ||
316 | |||
317 | return(okay ? 0 : -1); | ||
318 | } | ||
319 | |||
320 | /* Get CD-ROM status */ | ||
321 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
322 | { | ||
323 | CDstatus status; | ||
324 | struct cd_sub_channel sc; | ||
325 | struct cd_subc_channel_data scd; | ||
326 | |||
327 | sc.sch_address_format = CDROM_LBA_FORMAT; | ||
328 | sc.sch_data_format = CDROM_CURRENT_POSITION; | ||
329 | sc.sch_track_number = 0; | ||
330 | sc.sch_alloc_length = sizeof(scd); | ||
331 | sc.sch_buffer = (caddr_t)&scd; | ||
332 | if ( ioctl(cdrom->id, CDROM_READ_SUBCHANNEL, &sc) ) { | ||
333 | status = CD_ERROR; | ||
334 | fprintf(stderr,"ioctl error CDROM_READ_SUBCHANNEL \n"); | ||
335 | } else { | ||
336 | switch (scd.scd_header.sh_audio_status) { | ||
337 | case AS_AUDIO_INVALID: | ||
338 | status = CD_STOPPED; | ||
339 | break; | ||
340 | case AS_PLAY_IN_PROGRESS: | ||
341 | status = CD_PLAYING; | ||
342 | break; | ||
343 | case AS_PLAY_PAUSED: | ||
344 | status = CD_PAUSED; | ||
345 | break; | ||
346 | case AS_PLAY_COMPLETED: | ||
347 | status = CD_STOPPED; | ||
348 | break; | ||
349 | case AS_PLAY_ERROR: | ||
350 | status = CD_ERROR; | ||
351 | break; | ||
352 | case AS_NO_STATUS: | ||
353 | status = CD_STOPPED; | ||
354 | break; | ||
355 | default: | ||
356 | status = CD_ERROR; | ||
357 | break; | ||
358 | } | ||
359 | #ifdef DEBUG_CDROM | ||
360 | fprintf(stderr,"scd.scd_header.sh_audio_status = %x\n", | ||
361 | scd.scd_header.sh_audio_status); | ||
362 | #endif | ||
363 | } | ||
364 | if (position) { | ||
365 | if (status == CD_PLAYING || (status == CD_PAUSED) ) { | ||
366 | *position = | ||
367 | scd.scd_position_data.scp_absaddr.lba.addr3 << 24 | | ||
368 | scd.scd_position_data.scp_absaddr.lba.addr2 << 16 | | ||
369 | scd.scd_position_data.scp_absaddr.lba.addr1 << 8 | | ||
370 | scd.scd_position_data.scp_absaddr.lba.addr0; | ||
371 | } else { | ||
372 | *position = 0; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | return status; | ||
377 | } | ||
378 | |||
379 | /* Start play */ | ||
380 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
381 | { | ||
382 | /* | ||
383 | * Play MSF | ||
384 | */ | ||
385 | struct cd_play_audio_msf msf; | ||
386 | int end; | ||
387 | |||
388 | bzero(&msf, sizeof(msf)); | ||
389 | end = start +length; | ||
390 | FRAMES_TO_MSF(start + 150, /* LBA = 4500*M + 75*S + F - 150 */ | ||
391 | &msf.msf_starting_M_unit, | ||
392 | &msf.msf_starting_S_unit, | ||
393 | &msf.msf_starting_F_unit); | ||
394 | FRAMES_TO_MSF(end + 150, /* LBA = 4500*M + 75*S + F - 150 */ | ||
395 | &msf.msf_ending_M_unit, | ||
396 | &msf.msf_ending_S_unit, | ||
397 | &msf.msf_ending_F_unit); | ||
398 | |||
399 | return(ioctl(cdrom->id, CDROM_PLAY_AUDIO_MSF, &msf)); | ||
400 | } | ||
401 | |||
402 | /* Pause play */ | ||
403 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
404 | { | ||
405 | return(ioctl(cdrom->id, CDROM_PAUSE_PLAY)); | ||
406 | } | ||
407 | |||
408 | /* Resume play */ | ||
409 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
410 | { | ||
411 | return(ioctl(cdrom->id, CDROM_RESUME_PLAY)); | ||
412 | } | ||
413 | |||
414 | /* Stop play */ | ||
415 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
416 | { | ||
417 | return(ioctl(cdrom->id, SCSI_STOP_UNIT)); | ||
418 | } | ||
419 | |||
420 | /* Eject the CD-ROM */ | ||
421 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
422 | { | ||
423 | return(ioctl(cdrom->id, CDROM_EJECT_CADDY)); | ||
424 | } | ||
425 | |||
426 | /* Close the CD-ROM handle */ | ||
427 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
428 | { | ||
429 | close(cdrom->id); | ||
430 | } | ||
431 | |||
432 | void SDL_SYS_CDQuit(void) | ||
433 | { | ||
434 | int i; | ||
435 | |||
436 | if ( SDL_numcds > 0 ) { | ||
437 | for ( i=0; i<SDL_numcds; ++i ) { | ||
438 | SDL_free(SDL_cdlist[i]); | ||
439 | } | ||
440 | SDL_numcds = 0; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | #endif /* SDL_CDROM_OSF */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/qnx/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/qnx/SDL_syscdrom.c new file mode 100644 index 0000000000..0e38b7905e --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/qnx/SDL_syscdrom.c | |||
@@ -0,0 +1,551 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_QNX | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #include <sys/types.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include <sys/ioctl.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <errno.h> | ||
33 | #include <unistd.h> | ||
34 | #include <sys/cdrom.h> | ||
35 | #include <sys/dcmd_cam.h> | ||
36 | |||
37 | #include "SDL_timer.h" | ||
38 | #include "SDL_cdrom.h" | ||
39 | #include "../SDL_syscdrom.h" | ||
40 | |||
41 | /* The maximum number of CD-ROM drives we'll detect */ | ||
42 | #define MAX_DRIVES 16 | ||
43 | |||
44 | #define QNX_CD_OPENMODE O_RDONLY | O_EXCL | ||
45 | |||
46 | /* A list of available CD-ROM drives */ | ||
47 | static char *SDL_cdlist[MAX_DRIVES]; | ||
48 | static dev_t SDL_cdmode[MAX_DRIVES]; | ||
49 | static int SDL_cdopen[MAX_DRIVES]; | ||
50 | |||
51 | /* The system-dependent CD control functions */ | ||
52 | static const char *SDL_SYS_CDName(int drive); | ||
53 | static int SDL_SYS_CDOpen(int drive); | ||
54 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
55 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
56 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
57 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
58 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
59 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
60 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
61 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
62 | |||
63 | /* Check a drive to see if it is a CD-ROM */ | ||
64 | static int CheckDrive(char *drive, struct stat *stbuf) | ||
65 | { | ||
66 | int is_cd, cdfd; | ||
67 | cam_devinfo_t dinfo; | ||
68 | int devctlret=0; | ||
69 | |||
70 | int atapi; | ||
71 | int removable; | ||
72 | int cdb10; | ||
73 | |||
74 | /* If it doesn't exist, return -1 */ | ||
75 | if (stat(drive, stbuf) < 0) | ||
76 | { | ||
77 | return(-1); | ||
78 | } | ||
79 | |||
80 | /* If it does exist, verify that it's an available CD-ROM */ | ||
81 | is_cd = 0; | ||
82 | |||
83 | if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode)) | ||
84 | { | ||
85 | cdfd = open(drive, QNX_CD_OPENMODE); | ||
86 | if ( cdfd >= 0 ) | ||
87 | { | ||
88 | devctlret=devctl(cdfd, DCMD_CAM_DEVINFO, &dinfo, sizeof(cam_devinfo_t), NULL); | ||
89 | |||
90 | if (devctlret==EOK) | ||
91 | { | ||
92 | atapi=dinfo.flags & DEV_ATAPI; | ||
93 | removable=dinfo.flags & DEV_REMOVABLE; | ||
94 | cdb10=dinfo.flags & DEV_CDB_10; /* I'm not sure about that flag */ | ||
95 | |||
96 | /* in the near future need to add more checks for splitting cdroms from other devices */ | ||
97 | if ((atapi)&&(removable)) | ||
98 | { | ||
99 | is_cd = 1; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | close(cdfd); | ||
104 | } | ||
105 | } | ||
106 | return(is_cd); | ||
107 | } | ||
108 | |||
109 | /* Add a CD-ROM drive to our list of valid drives */ | ||
110 | static void AddDrive(char *drive, struct stat *stbuf) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | if (SDL_numcds < MAX_DRIVES) | ||
115 | { | ||
116 | /* Check to make sure it's not already in our list. | ||
117 | This can happen when we see a drive via symbolic link. */ | ||
118 | |||
119 | for (i=0; i<SDL_numcds; ++i) | ||
120 | { | ||
121 | if (stbuf->st_rdev == SDL_cdmode[i]) | ||
122 | { | ||
123 | return; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /* Add this drive to our list */ | ||
128 | |||
129 | i = SDL_numcds; | ||
130 | SDL_cdlist[i] = SDL_strdup(drive); | ||
131 | if (SDL_cdlist[i] == NULL) | ||
132 | { | ||
133 | SDL_OutOfMemory(); | ||
134 | return; | ||
135 | } | ||
136 | SDL_cdmode[i] = stbuf->st_rdev; | ||
137 | ++SDL_numcds; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | int SDL_SYS_CDInit(void) | ||
142 | { | ||
143 | /* checklist: /dev/cdrom, /dev/cd?, /dev/scd? */ | ||
144 | static char *checklist[]={"cdrom", "?0 cd?", "?1 cd?", "?0 scd?", NULL}; | ||
145 | |||
146 | char *SDLcdrom; | ||
147 | int i, j, exists; | ||
148 | char drive[32]; | ||
149 | struct stat stbuf; | ||
150 | |||
151 | /* Fill in our driver capabilities */ | ||
152 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
153 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
154 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
155 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
156 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
157 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
158 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
159 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
160 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
161 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
162 | |||
163 | /* clearing device open status */ | ||
164 | for (i=0; i<MAX_DRIVES; i++) | ||
165 | { | ||
166 | SDL_cdopen[i]=0; | ||
167 | } | ||
168 | |||
169 | /* Look in the environment for our CD-ROM drive list */ | ||
170 | SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ | ||
171 | if ( SDLcdrom != NULL ) | ||
172 | { | ||
173 | char *cdpath, *delim; | ||
174 | size_t len = SDL_strlen(SDLcdrom)+1; | ||
175 | cdpath = SDL_stack_alloc(char, len); | ||
176 | if (cdpath != NULL) | ||
177 | { | ||
178 | SDL_strlcpy(cdpath, SDLcdrom, len); | ||
179 | SDLcdrom = cdpath; | ||
180 | do { | ||
181 | delim = SDL_strchr(SDLcdrom, ':'); | ||
182 | if (delim) | ||
183 | { | ||
184 | *delim++ = '\0'; | ||
185 | } | ||
186 | if (CheckDrive(SDLcdrom, &stbuf) > 0) | ||
187 | { | ||
188 | AddDrive(SDLcdrom, &stbuf); | ||
189 | } | ||
190 | if (delim) | ||
191 | { | ||
192 | SDLcdrom = delim; | ||
193 | } | ||
194 | else | ||
195 | { | ||
196 | SDLcdrom = NULL; | ||
197 | } | ||
198 | } while (SDLcdrom); | ||
199 | SDL_stack_free(cdpath); | ||
200 | } | ||
201 | |||
202 | /* If we found our drives, there's nothing left to do */ | ||
203 | if (SDL_numcds > 0) | ||
204 | { | ||
205 | return(0); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | /* Scan the system for CD-ROM drives */ | ||
210 | for ( i=0; checklist[i]; ++i ) | ||
211 | { | ||
212 | if (checklist[i][0] == '?') | ||
213 | { | ||
214 | char* insert; | ||
215 | exists = 1; | ||
216 | |||
217 | for ( j=checklist[i][1]; exists; ++j ) | ||
218 | { | ||
219 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", &checklist[i][3]); | ||
220 | insert = SDL_strchr(drive, '?'); | ||
221 | if (insert != NULL) | ||
222 | { | ||
223 | *insert = j; | ||
224 | } | ||
225 | switch (CheckDrive(drive, &stbuf)) | ||
226 | { | ||
227 | /* Drive exists and is a CD-ROM */ | ||
228 | case 1: | ||
229 | AddDrive(drive, &stbuf); | ||
230 | break; | ||
231 | /* Drive exists, but isn't a CD-ROM */ | ||
232 | case 0: | ||
233 | break; | ||
234 | /* Drive doesn't exist */ | ||
235 | case -1: | ||
236 | exists = 0; | ||
237 | break; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | else | ||
242 | { | ||
243 | SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); | ||
244 | if (CheckDrive(drive, &stbuf) > 0) | ||
245 | { | ||
246 | AddDrive(drive, &stbuf); | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | return(0); | ||
251 | } | ||
252 | |||
253 | static const char *SDL_SYS_CDName(int drive) | ||
254 | { | ||
255 | return(SDL_cdlist[drive]); | ||
256 | } | ||
257 | |||
258 | static int SDL_SYS_CDOpen(int drive) | ||
259 | { | ||
260 | int handle; | ||
261 | |||
262 | handle=open(SDL_cdlist[drive], QNX_CD_OPENMODE); | ||
263 | |||
264 | if (handle>0) | ||
265 | { | ||
266 | SDL_cdopen[drive]=handle; | ||
267 | } | ||
268 | |||
269 | return (handle); | ||
270 | } | ||
271 | |||
272 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
273 | { | ||
274 | cdrom_read_toc_t toc; | ||
275 | int i, okay; | ||
276 | |||
277 | okay = 0; | ||
278 | if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), NULL) == 0) | ||
279 | { | ||
280 | cdrom->numtracks = toc.last_track - toc.first_track + 1; | ||
281 | if (cdrom->numtracks > SDL_MAX_TRACKS) | ||
282 | { | ||
283 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
284 | } | ||
285 | /* Read all the track TOC entries */ | ||
286 | for (i=0; i<=cdrom->numtracks; ++i) | ||
287 | { | ||
288 | if (i == cdrom->numtracks) | ||
289 | { | ||
290 | cdrom->track[i].id = CDROM_LEADOUT; | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | cdrom->track[i].id = toc.first_track+i; | ||
295 | } | ||
296 | |||
297 | cdrom->track[i].type = toc.toc_entry[i].control_adr & 0x0F; | ||
298 | cdrom->track[i].offset = toc.toc_entry[i].addr.lba; | ||
299 | cdrom->track[i].length = 0; | ||
300 | |||
301 | if (i > 0) | ||
302 | { | ||
303 | cdrom->track[i-1].length = cdrom->track[i].offset-cdrom->track[i-1].offset; | ||
304 | } | ||
305 | } | ||
306 | if (i == (cdrom->numtracks+1)) | ||
307 | { | ||
308 | okay = 1; | ||
309 | } | ||
310 | } | ||
311 | return (okay ? 0 : -1); | ||
312 | } | ||
313 | |||
314 | /* Get CD-ROM status */ | ||
315 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
316 | { | ||
317 | CDstatus status; | ||
318 | |||
319 | cdrom_read_toc_t toc; | ||
320 | cdrom_subch_data_t info; | ||
321 | cam_devinfo_t dinfo; | ||
322 | |||
323 | int devctlret=0; | ||
324 | int drive=-1; | ||
325 | int i; | ||
326 | int eagaincnt=0; | ||
327 | |||
328 | /* check media presence before read subchannel call, some cdroms can lockups */ | ||
329 | /* if no media, while calling read subchannel functions. */ | ||
330 | devctlret=devctl(cdrom->id, DCMD_CAM_DEVINFO, &dinfo, sizeof(cam_devinfo_t), NULL); | ||
331 | |||
332 | if (devctlret==EOK) | ||
333 | { | ||
334 | if ((dinfo.flags & DEV_NO_MEDIA)!=0) | ||
335 | { | ||
336 | status = CD_TRAYEMPTY; | ||
337 | if (position) | ||
338 | { | ||
339 | *position = 0; | ||
340 | } | ||
341 | return (status); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | /* if media exists, then do other stuff */ | ||
346 | |||
347 | SDL_memset(&info, 0x00, sizeof(info)); | ||
348 | info.subch_command.data_format = CDROM_SUBCH_CURRENT_POSITION; | ||
349 | |||
350 | do { | ||
351 | devctlret=devctl(cdrom->id, DCMD_CAM_CDROMSUBCHNL, &info, sizeof(info), NULL); | ||
352 | if (devctlret==EIO) | ||
353 | { | ||
354 | /* big workaround for media change, handle is unusable after that, | ||
355 | that bug was found in QNX 6.2, 6.2.1 is not released yet. */ | ||
356 | |||
357 | for (i=0; i<MAX_DRIVES; i++) | ||
358 | { | ||
359 | if (SDL_cdopen[i]==cdrom->id) | ||
360 | { | ||
361 | drive=i; | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | if (drive==-1) | ||
366 | { | ||
367 | /* that cannot happen, but ... */ | ||
368 | break; | ||
369 | } | ||
370 | close(cdrom->id); | ||
371 | cdrom->id=open(SDL_cdlist[drive], QNX_CD_OPENMODE); | ||
372 | devctlret=EAGAIN; | ||
373 | } | ||
374 | if (devctlret==EAGAIN) | ||
375 | { | ||
376 | eagaincnt++; | ||
377 | } | ||
378 | if (eagaincnt==2) | ||
379 | { | ||
380 | /* workaround for broken cdroms, which can return always EAGAIN when its not ready, */ | ||
381 | /* that mean errornous media or just no media avail */ | ||
382 | devctlret=ENXIO; | ||
383 | break; | ||
384 | } | ||
385 | } while ((devctlret==EAGAIN)||(devctlret==ESTALE)); | ||
386 | |||
387 | if (devctlret != 0) | ||
388 | { | ||
389 | if (devctlret==ENXIO) | ||
390 | { | ||
391 | status = CD_TRAYEMPTY; | ||
392 | } | ||
393 | else | ||
394 | { | ||
395 | status = CD_ERROR; | ||
396 | } | ||
397 | } | ||
398 | else | ||
399 | { | ||
400 | switch (info.current_position.header.audio_status) | ||
401 | { | ||
402 | case CDROM_AUDIO_INVALID: | ||
403 | case CDROM_AUDIO_NO_STATUS: | ||
404 | /* Try to determine if there's a CD available */ | ||
405 | if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), NULL)==0) | ||
406 | status = CD_STOPPED; | ||
407 | else | ||
408 | status = CD_TRAYEMPTY; | ||
409 | break; | ||
410 | case CDROM_AUDIO_COMPLETED: | ||
411 | status = CD_STOPPED; | ||
412 | break; | ||
413 | case CDROM_AUDIO_PLAY: | ||
414 | status = CD_PLAYING; | ||
415 | break; | ||
416 | case CDROM_AUDIO_PAUSED: | ||
417 | /* Workaround buggy CD-ROM drive */ | ||
418 | if (info.current_position.data_format == CDROM_LEADOUT) | ||
419 | { | ||
420 | status = CD_STOPPED; | ||
421 | } | ||
422 | else | ||
423 | { | ||
424 | status = CD_PAUSED; | ||
425 | } | ||
426 | break; | ||
427 | default: | ||
428 | status = CD_ERROR; | ||
429 | break; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | if (position) | ||
434 | { | ||
435 | if (status==CD_PLAYING || (status==CD_PAUSED)) | ||
436 | { | ||
437 | *position = MSF_TO_FRAMES(info.current_position.addr.msf.minute, | ||
438 | info.current_position.addr.msf.second, | ||
439 | info.current_position.addr.msf.frame); | ||
440 | } | ||
441 | else | ||
442 | { | ||
443 | *position = 0; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | return (status); | ||
448 | } | ||
449 | |||
450 | /* Start play */ | ||
451 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
452 | { | ||
453 | cdrom_playmsf_t playtime; | ||
454 | |||
455 | FRAMES_TO_MSF(start, &playtime.start_minute, &playtime.start_second, &playtime.start_frame); | ||
456 | FRAMES_TO_MSF(start+length, &playtime.end_minute, &playtime.end_second, &playtime.end_frame); | ||
457 | |||
458 | if (devctl(cdrom->id, DCMD_CAM_CDROMPLAYMSF, &playtime, sizeof(playtime), NULL) != 0) | ||
459 | { | ||
460 | return -1; | ||
461 | } | ||
462 | else | ||
463 | { | ||
464 | return 0; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | /* Pause play */ | ||
469 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
470 | { | ||
471 | if (devctl(cdrom->id, DCMD_CAM_CDROMPAUSE, NULL, 0, NULL)!=0) | ||
472 | { | ||
473 | return -1; | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | return 0; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | /* Resume play */ | ||
482 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
483 | { | ||
484 | if (devctl(cdrom->id, DCMD_CAM_CDROMRESUME, NULL, 0, NULL)!=0) | ||
485 | { | ||
486 | return -1; | ||
487 | } | ||
488 | else | ||
489 | { | ||
490 | return 0; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | /* Stop play */ | ||
495 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
496 | { | ||
497 | if (devctl(cdrom->id, DCMD_CAM_CDROMSTOP, NULL, 0, NULL)!=0) | ||
498 | { | ||
499 | return -1; | ||
500 | } | ||
501 | else | ||
502 | { | ||
503 | return 0; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | /* Eject the CD-ROM */ | ||
508 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
509 | { | ||
510 | if (devctl(cdrom->id, DCMD_CAM_EJECT_MEDIA, NULL, 0, NULL)!=0) | ||
511 | { | ||
512 | return -1; | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | return 0; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | /* Close the CD-ROM handle */ | ||
521 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
522 | { | ||
523 | int i; | ||
524 | |||
525 | for (i=0; i<MAX_DRIVES; i++) | ||
526 | { | ||
527 | if (SDL_cdopen[i]==cdrom->id) | ||
528 | { | ||
529 | SDL_cdopen[i]=0; | ||
530 | break; | ||
531 | } | ||
532 | } | ||
533 | |||
534 | close(cdrom->id); | ||
535 | } | ||
536 | |||
537 | void SDL_SYS_CDQuit(void) | ||
538 | { | ||
539 | int i; | ||
540 | |||
541 | if (SDL_numcds > 0) | ||
542 | { | ||
543 | for (i=0; i<SDL_numcds; ++i) | ||
544 | { | ||
545 | SDL_free(SDL_cdlist[i]); | ||
546 | } | ||
547 | SDL_numcds = 0; | ||
548 | } | ||
549 | } | ||
550 | |||
551 | #endif /* SDL_CDROM_QNX */ | ||
diff --git a/apps/plugins/sdl/src/cdrom/win32/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/win32/SDL_syscdrom.c new file mode 100644 index 0000000000..cac9fd3b61 --- /dev/null +++ b/apps/plugins/sdl/src/cdrom/win32/SDL_syscdrom.c | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #ifdef SDL_CDROM_WIN32 | ||
25 | |||
26 | /* Functions for system-level CD-ROM audio control */ | ||
27 | |||
28 | #define WIN32_LEAN_AND_MEAN | ||
29 | #include <windows.h> | ||
30 | #include <mmsystem.h> | ||
31 | |||
32 | #include "SDL_cdrom.h" | ||
33 | #include "../SDL_syscdrom.h" | ||
34 | |||
35 | /* This really broken?? */ | ||
36 | #define BROKEN_MCI_PAUSE /* Pausing actually stops play -- Doh! */ | ||
37 | |||
38 | /* The maximum number of CD-ROM drives we'll detect (Don't change!) */ | ||
39 | #define MAX_DRIVES 26 | ||
40 | |||
41 | /* A list of available CD-ROM drives */ | ||
42 | static char *SDL_cdlist[MAX_DRIVES]; | ||
43 | static MCIDEVICEID SDL_mciID[MAX_DRIVES]; | ||
44 | #ifdef BROKEN_MCI_PAUSE | ||
45 | static int SDL_paused[MAX_DRIVES]; | ||
46 | #endif | ||
47 | static int SDL_CD_end_position; | ||
48 | |||
49 | /* The system-dependent CD control functions */ | ||
50 | static const char *SDL_SYS_CDName(int drive); | ||
51 | static int SDL_SYS_CDOpen(int drive); | ||
52 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | ||
53 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | ||
54 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | ||
55 | static int SDL_SYS_CDPause(SDL_CD *cdrom); | ||
56 | static int SDL_SYS_CDResume(SDL_CD *cdrom); | ||
57 | static int SDL_SYS_CDStop(SDL_CD *cdrom); | ||
58 | static int SDL_SYS_CDEject(SDL_CD *cdrom); | ||
59 | static void SDL_SYS_CDClose(SDL_CD *cdrom); | ||
60 | |||
61 | |||
62 | /* Add a CD-ROM drive to our list of valid drives */ | ||
63 | static void AddDrive(char *drive) | ||
64 | { | ||
65 | int i; | ||
66 | |||
67 | if ( SDL_numcds < MAX_DRIVES ) { | ||
68 | /* Add this drive to our list */ | ||
69 | i = SDL_numcds; | ||
70 | SDL_cdlist[i] = SDL_strdup(drive); | ||
71 | if ( SDL_cdlist[i] == NULL ) { | ||
72 | SDL_OutOfMemory(); | ||
73 | return; | ||
74 | } | ||
75 | ++SDL_numcds; | ||
76 | #ifdef CDROM_DEBUG | ||
77 | fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | ||
78 | #endif | ||
79 | } | ||
80 | } | ||
81 | |||
82 | int SDL_SYS_CDInit(void) | ||
83 | { | ||
84 | /* checklist: Drive 'A' - 'Z' */ | ||
85 | int i; | ||
86 | char drive[4]; | ||
87 | |||
88 | /* Fill in our driver capabilities */ | ||
89 | SDL_CDcaps.Name = SDL_SYS_CDName; | ||
90 | SDL_CDcaps.Open = SDL_SYS_CDOpen; | ||
91 | SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | ||
92 | SDL_CDcaps.Status = SDL_SYS_CDStatus; | ||
93 | SDL_CDcaps.Play = SDL_SYS_CDPlay; | ||
94 | SDL_CDcaps.Pause = SDL_SYS_CDPause; | ||
95 | SDL_CDcaps.Resume = SDL_SYS_CDResume; | ||
96 | SDL_CDcaps.Stop = SDL_SYS_CDStop; | ||
97 | SDL_CDcaps.Eject = SDL_SYS_CDEject; | ||
98 | SDL_CDcaps.Close = SDL_SYS_CDClose; | ||
99 | |||
100 | /* Scan the system for CD-ROM drives */ | ||
101 | for ( i='A'; i<='Z'; ++i ) { | ||
102 | SDL_snprintf(drive, SDL_arraysize(drive), "%c:\\", i); | ||
103 | if ( GetDriveType(drive) == DRIVE_CDROM ) { | ||
104 | AddDrive(drive); | ||
105 | } | ||
106 | } | ||
107 | SDL_memset(SDL_mciID, 0, sizeof(SDL_mciID)); | ||
108 | return(0); | ||
109 | } | ||
110 | |||
111 | /* General ioctl() CD-ROM command function */ | ||
112 | static int SDL_SYS_CDioctl(int id, UINT msg, DWORD flags, void *arg) | ||
113 | { | ||
114 | MCIERROR mci_error; | ||
115 | |||
116 | mci_error = mciSendCommand(SDL_mciID[id], msg, flags, (DWORD_PTR)arg); | ||
117 | if ( mci_error ) { | ||
118 | char error[256]; | ||
119 | |||
120 | mciGetErrorString(mci_error, error, 256); | ||
121 | SDL_SetError("mciSendCommand() error: %s", error); | ||
122 | } | ||
123 | return(!mci_error ? 0 : -1); | ||
124 | } | ||
125 | |||
126 | static const char *SDL_SYS_CDName(int drive) | ||
127 | { | ||
128 | return(SDL_cdlist[drive]); | ||
129 | } | ||
130 | |||
131 | static int SDL_SYS_CDOpen(int drive) | ||
132 | { | ||
133 | MCI_OPEN_PARMS mci_open; | ||
134 | MCI_SET_PARMS mci_set; | ||
135 | char device[3]; | ||
136 | DWORD flags; | ||
137 | |||
138 | /* Open the requested device */ | ||
139 | mci_open.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO; | ||
140 | device[0] = *SDL_cdlist[drive]; | ||
141 | device[1] = ':'; | ||
142 | device[2] = '\0'; | ||
143 | mci_open.lpstrElementName = device; | ||
144 | flags = | ||
145 | (MCI_OPEN_TYPE|MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT); | ||
146 | if ( SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0 ) { | ||
147 | flags &= ~MCI_OPEN_SHAREABLE; | ||
148 | if ( SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0 ) { | ||
149 | return(-1); | ||
150 | } | ||
151 | } | ||
152 | SDL_mciID[drive] = mci_open.wDeviceID; | ||
153 | |||
154 | /* Set the minute-second-frame time format */ | ||
155 | mci_set.dwTimeFormat = MCI_FORMAT_MSF; | ||
156 | SDL_SYS_CDioctl(drive, MCI_SET, MCI_SET_TIME_FORMAT, &mci_set); | ||
157 | |||
158 | #ifdef BROKEN_MCI_PAUSE | ||
159 | SDL_paused[drive] = 0; | ||
160 | #endif | ||
161 | return(drive); | ||
162 | } | ||
163 | |||
164 | static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | ||
165 | { | ||
166 | MCI_STATUS_PARMS mci_status; | ||
167 | int i, okay; | ||
168 | DWORD flags; | ||
169 | |||
170 | okay = 0; | ||
171 | mci_status.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; | ||
172 | flags = MCI_STATUS_ITEM | MCI_WAIT; | ||
173 | if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0 ) { | ||
174 | cdrom->numtracks = mci_status.dwReturn; | ||
175 | if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | ||
176 | cdrom->numtracks = SDL_MAX_TRACKS; | ||
177 | } | ||
178 | /* Read all the track TOC entries */ | ||
179 | flags = MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT; | ||
180 | for ( i=0; i<cdrom->numtracks; ++i ) { | ||
181 | cdrom->track[i].id = i+1; | ||
182 | mci_status.dwTrack = cdrom->track[i].id; | ||
183 | #ifdef MCI_CDA_STATUS_TYPE_TRACK | ||
184 | mci_status.dwItem = MCI_CDA_STATUS_TYPE_TRACK; | ||
185 | if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, | ||
186 | &mci_status) < 0 ) { | ||
187 | break; | ||
188 | } | ||
189 | if ( mci_status.dwReturn == MCI_CDA_TRACK_AUDIO ) { | ||
190 | cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
191 | } else { | ||
192 | cdrom->track[i].type = SDL_DATA_TRACK; | ||
193 | } | ||
194 | #else | ||
195 | cdrom->track[i].type = SDL_AUDIO_TRACK; | ||
196 | #endif | ||
197 | mci_status.dwItem = MCI_STATUS_POSITION; | ||
198 | if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, | ||
199 | &mci_status) < 0 ) { | ||
200 | break; | ||
201 | } | ||
202 | cdrom->track[i].offset = MSF_TO_FRAMES( | ||
203 | MCI_MSF_MINUTE(mci_status.dwReturn), | ||
204 | MCI_MSF_SECOND(mci_status.dwReturn), | ||
205 | MCI_MSF_FRAME(mci_status.dwReturn)); | ||
206 | cdrom->track[i].length = 0; | ||
207 | if ( i > 0 ) { | ||
208 | cdrom->track[i-1].length = | ||
209 | cdrom->track[i].offset- | ||
210 | cdrom->track[i-1].offset; | ||
211 | } | ||
212 | } | ||
213 | if ( i == cdrom->numtracks ) { | ||
214 | mci_status.dwTrack = cdrom->track[i - 1].id; | ||
215 | mci_status.dwItem = MCI_STATUS_LENGTH; | ||
216 | if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, | ||
217 | &mci_status) == 0 ) { | ||
218 | cdrom->track[i - 1].length = MSF_TO_FRAMES( | ||
219 | MCI_MSF_MINUTE(mci_status.dwReturn), | ||
220 | MCI_MSF_SECOND(mci_status.dwReturn), | ||
221 | MCI_MSF_FRAME(mci_status.dwReturn)); | ||
222 | /* compute lead-out offset */ | ||
223 | cdrom->track[i].offset = cdrom->track[i - 1].offset + | ||
224 | cdrom->track[i - 1].length; | ||
225 | cdrom->track[i].length = 0; | ||
226 | okay = 1; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | return(okay ? 0 : -1); | ||
231 | } | ||
232 | |||
233 | /* Get CD-ROM status */ | ||
234 | static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | ||
235 | { | ||
236 | CDstatus status; | ||
237 | MCI_STATUS_PARMS mci_status; | ||
238 | DWORD flags; | ||
239 | |||
240 | flags = MCI_STATUS_ITEM | MCI_WAIT; | ||
241 | mci_status.dwItem = MCI_STATUS_MODE; | ||
242 | if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) < 0 ) { | ||
243 | status = CD_ERROR; | ||
244 | } else { | ||
245 | switch (mci_status.dwReturn) { | ||
246 | case MCI_MODE_NOT_READY: | ||
247 | case MCI_MODE_OPEN: | ||
248 | status = CD_TRAYEMPTY; | ||
249 | break; | ||
250 | case MCI_MODE_STOP: | ||
251 | #ifdef BROKEN_MCI_PAUSE | ||
252 | if ( SDL_paused[cdrom->id] ) { | ||
253 | status = CD_PAUSED; | ||
254 | } else { | ||
255 | status = CD_STOPPED; | ||
256 | } | ||
257 | #else | ||
258 | status = CD_STOPPED; | ||
259 | #endif /* BROKEN_MCI_PAUSE */ | ||
260 | break; | ||
261 | case MCI_MODE_PLAY: | ||
262 | #ifdef BROKEN_MCI_PAUSE | ||
263 | if ( SDL_paused[cdrom->id] ) { | ||
264 | status = CD_PAUSED; | ||
265 | } else { | ||
266 | status = CD_PLAYING; | ||
267 | } | ||
268 | #else | ||
269 | status = CD_PLAYING; | ||
270 | #endif /* BROKEN_MCI_PAUSE */ | ||
271 | break; | ||
272 | case MCI_MODE_PAUSE: | ||
273 | status = CD_PAUSED; | ||
274 | break; | ||
275 | default: | ||
276 | status = CD_ERROR; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | if ( position ) { | ||
281 | if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | ||
282 | mci_status.dwItem = MCI_STATUS_POSITION; | ||
283 | if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, | ||
284 | &mci_status) == 0 ) { | ||
285 | *position = MSF_TO_FRAMES( | ||
286 | MCI_MSF_MINUTE(mci_status.dwReturn), | ||
287 | MCI_MSF_SECOND(mci_status.dwReturn), | ||
288 | MCI_MSF_FRAME(mci_status.dwReturn)); | ||
289 | } else { | ||
290 | *position = 0; | ||
291 | } | ||
292 | } else { | ||
293 | *position = 0; | ||
294 | } | ||
295 | } | ||
296 | return(status); | ||
297 | } | ||
298 | |||
299 | /* Start play */ | ||
300 | static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | ||
301 | { | ||
302 | MCI_PLAY_PARMS mci_play; | ||
303 | int m, s, f; | ||
304 | DWORD flags; | ||
305 | |||
306 | flags = MCI_FROM | MCI_TO | MCI_NOTIFY; | ||
307 | mci_play.dwCallback = 0; | ||
308 | FRAMES_TO_MSF(start, &m, &s, &f); | ||
309 | mci_play.dwFrom = MCI_MAKE_MSF(m, s, f); | ||
310 | FRAMES_TO_MSF(start+length, &m, &s, &f); | ||
311 | mci_play.dwTo = MCI_MAKE_MSF(m, s, f); | ||
312 | SDL_CD_end_position = mci_play.dwTo; | ||
313 | return(SDL_SYS_CDioctl(cdrom->id, MCI_PLAY, flags, &mci_play)); | ||
314 | } | ||
315 | |||
316 | /* Pause play */ | ||
317 | static int SDL_SYS_CDPause(SDL_CD *cdrom) | ||
318 | { | ||
319 | #ifdef BROKEN_MCI_PAUSE | ||
320 | SDL_paused[cdrom->id] = 1; | ||
321 | #endif | ||
322 | return(SDL_SYS_CDioctl(cdrom->id, MCI_PAUSE, MCI_WAIT, NULL)); | ||
323 | } | ||
324 | |||
325 | /* Resume play */ | ||
326 | static int SDL_SYS_CDResume(SDL_CD *cdrom) | ||
327 | { | ||
328 | #ifdef BROKEN_MCI_PAUSE | ||
329 | MCI_STATUS_PARMS mci_status; | ||
330 | int okay; | ||
331 | int flags; | ||
332 | |||
333 | okay = 0; | ||
334 | /* Play from the current play position to the end position set earlier */ | ||
335 | flags = MCI_STATUS_ITEM | MCI_WAIT; | ||
336 | mci_status.dwItem = MCI_STATUS_POSITION; | ||
337 | if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0 ) { | ||
338 | MCI_PLAY_PARMS mci_play; | ||
339 | |||
340 | flags = MCI_FROM | MCI_TO | MCI_NOTIFY; | ||
341 | mci_play.dwCallback = 0; | ||
342 | mci_play.dwFrom = mci_status.dwReturn; | ||
343 | mci_play.dwTo = SDL_CD_end_position; | ||
344 | if (SDL_SYS_CDioctl(cdrom->id,MCI_PLAY,flags,&mci_play) == 0) { | ||
345 | okay = 1; | ||
346 | SDL_paused[cdrom->id] = 0; | ||
347 | } | ||
348 | } | ||
349 | return(okay ? 0 : -1); | ||
350 | #else | ||
351 | return(SDL_SYS_CDioctl(cdrom->id, MCI_RESUME, MCI_WAIT, NULL)); | ||
352 | #endif /* BROKEN_MCI_PAUSE */ | ||
353 | } | ||
354 | |||
355 | /* Stop play */ | ||
356 | static int SDL_SYS_CDStop(SDL_CD *cdrom) | ||
357 | { | ||
358 | return(SDL_SYS_CDioctl(cdrom->id, MCI_STOP, MCI_WAIT, NULL)); | ||
359 | } | ||
360 | |||
361 | /* Eject the CD-ROM */ | ||
362 | static int SDL_SYS_CDEject(SDL_CD *cdrom) | ||
363 | { | ||
364 | return(SDL_SYS_CDioctl(cdrom->id, MCI_SET, MCI_SET_DOOR_OPEN, NULL)); | ||
365 | } | ||
366 | |||
367 | /* Close the CD-ROM handle */ | ||
368 | static void SDL_SYS_CDClose(SDL_CD *cdrom) | ||
369 | { | ||
370 | SDL_SYS_CDioctl(cdrom->id, MCI_CLOSE, MCI_WAIT, NULL); | ||
371 | } | ||
372 | |||
373 | void SDL_SYS_CDQuit(void) | ||
374 | { | ||
375 | int i; | ||
376 | |||
377 | if ( SDL_numcds > 0 ) { | ||
378 | for ( i=0; i<SDL_numcds; ++i ) { | ||
379 | SDL_free(SDL_cdlist[i]); | ||
380 | SDL_cdlist[i] = NULL; | ||
381 | } | ||
382 | SDL_numcds = 0; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | #endif /* SDL_CDROM_WIN32 */ | ||