CD-ROM support is so passé :)
--HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%403773
This commit is contained in:
parent
8c260f6e84
commit
633d710201
40 changed files with 3 additions and 9394 deletions
2
TODO
2
TODO
|
@ -50,4 +50,4 @@ we should do it though, since the 1.2 series should not break binary
|
||||||
compatibility in this way.
|
compatibility in this way.
|
||||||
|
|
||||||
Requests:
|
Requests:
|
||||||
* PCM and CDROM volume control (deprecated, but possible)
|
* PCM volume control (deprecated, but possible)
|
||||||
|
|
80
configure.in
80
configure.in
|
@ -206,7 +206,6 @@ fi
|
||||||
# Standard C sources
|
# Standard C sources
|
||||||
SOURCES="$SOURCES $srcdir/src/*.c"
|
SOURCES="$SOURCES $srcdir/src/*.c"
|
||||||
SOURCES="$SOURCES $srcdir/src/audio/*.c"
|
SOURCES="$SOURCES $srcdir/src/audio/*.c"
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/*.c"
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cpuinfo/*.c"
|
SOURCES="$SOURCES $srcdir/src/cpuinfo/*.c"
|
||||||
SOURCES="$SOURCES $srcdir/src/events/*.c"
|
SOURCES="$SOURCES $srcdir/src/events/*.c"
|
||||||
SOURCES="$SOURCES $srcdir/src/file/*.c"
|
SOURCES="$SOURCES $srcdir/src/file/*.c"
|
||||||
|
@ -265,12 +264,6 @@ if test x$enable_power != xyes; then
|
||||||
else
|
else
|
||||||
SOURCES="$SOURCES $srcdir/src/power/*.c"
|
SOURCES="$SOURCES $srcdir/src/power/*.c"
|
||||||
fi
|
fi
|
||||||
AC_ARG_ENABLE(cdrom,
|
|
||||||
AC_HELP_STRING([--enable-cdrom], [Enable the cdrom subsystem [[default=yes]]]),
|
|
||||||
, enable_cdrom=yes)
|
|
||||||
if test x$enable_cdrom != xyes; then
|
|
||||||
AC_DEFINE(SDL_CDROM_DISABLED)
|
|
||||||
fi
|
|
||||||
AC_ARG_ENABLE(threads,
|
AC_ARG_ENABLE(threads,
|
||||||
AC_HELP_STRING([--enable-threads], [Enable the threading subsystem [[default=yes]]]),
|
AC_HELP_STRING([--enable-threads], [Enable the threading subsystem [[default=yes]]]),
|
||||||
, enable_threads=yes)
|
, enable_threads=yes)
|
||||||
|
@ -2481,41 +2474,6 @@ case "$host" in
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
# Set up files for the cdrom library
|
|
||||||
if test x$enable_cdrom = xyes; then
|
|
||||||
case $ARCH in
|
|
||||||
linux|solaris)
|
|
||||||
AC_DEFINE(SDL_CDROM_LINUX)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/linux/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
;;
|
|
||||||
*freebsd*)
|
|
||||||
AC_DEFINE(SDL_CDROM_FREEBSD)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/freebsd/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
;;
|
|
||||||
*openbsd*|*netbsd*)
|
|
||||||
AC_DEFINE(SDL_CDROM_OPENBSD)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/openbsd/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
;;
|
|
||||||
bsdi)
|
|
||||||
AC_DEFINE(SDL_CDROM_BSDI)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/bsdi/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
;;
|
|
||||||
aix)
|
|
||||||
AC_DEFINE(SDL_CDROM_AIX)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/aix/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
;;
|
|
||||||
osf)
|
|
||||||
AC_DEFINE(SDL_CDROM_OSF)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/osf/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
# Set up files for the thread library
|
# Set up files for the thread library
|
||||||
if test x$enable_threads = xyes -a x$use_pthreads != xyes -a x$use_pth != xyes -a x$ARCH = xirix; then
|
if test x$enable_threads = xyes -a x$use_pthreads != xyes -a x$use_pth != xyes -a x$ARCH = xirix; then
|
||||||
AC_DEFINE(SDL_THREAD_SPROC)
|
AC_DEFINE(SDL_THREAD_SPROC)
|
||||||
|
@ -2560,12 +2518,6 @@ case "$host" in
|
||||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lasound"
|
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lasound"
|
||||||
have_audio=yes
|
have_audio=yes
|
||||||
fi
|
fi
|
||||||
# Set up files for the cdrom library
|
|
||||||
if test x$enable_cdrom = xyes; then
|
|
||||||
AC_DEFINE(SDL_CDROM_QNX)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/qnx/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
fi
|
|
||||||
# Set up files for the timer library
|
# Set up files for the timer library
|
||||||
if test x$enable_timers = xyes; then
|
if test x$enable_timers = xyes; then
|
||||||
AC_DEFINE(SDL_TIMER_UNIX)
|
AC_DEFINE(SDL_TIMER_UNIX)
|
||||||
|
@ -2743,12 +2695,6 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||||
SOURCES="$SOURCES $srcdir/src/power/windows/SDL_syspower.c"
|
SOURCES="$SOURCES $srcdir/src/power/windows/SDL_syspower.c"
|
||||||
have_power=yes
|
have_power=yes
|
||||||
fi
|
fi
|
||||||
# Set up files for the cdrom library
|
|
||||||
if test x$enable_cdrom = xyes; then
|
|
||||||
AC_DEFINE(SDL_CDROM_WIN32)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/win32/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
fi
|
|
||||||
# Set up files for the thread library
|
# Set up files for the thread library
|
||||||
if test x$enable_threads = xyes; then
|
if test x$enable_threads = xyes; then
|
||||||
AC_DEFINE(SDL_THREAD_WIN32)
|
AC_DEFINE(SDL_THREAD_WIN32)
|
||||||
|
@ -2801,12 +2747,6 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||||
SOURCES="$SOURCES $srcdir/src/joystick/beos/*.cc"
|
SOURCES="$SOURCES $srcdir/src/joystick/beos/*.cc"
|
||||||
have_joystick=yes
|
have_joystick=yes
|
||||||
fi
|
fi
|
||||||
# Set up files for the cdrom library
|
|
||||||
if test x$enable_cdrom = xyes; then
|
|
||||||
AC_DEFINE(SDL_CDROM_BEOS)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/beos/*.cc"
|
|
||||||
have_cdrom=yes
|
|
||||||
fi
|
|
||||||
# Set up files for the thread library
|
# Set up files for the thread library
|
||||||
if test x$enable_threads = xyes; then
|
if test x$enable_threads = xyes; then
|
||||||
AC_DEFINE(SDL_THREAD_BEOS)
|
AC_DEFINE(SDL_THREAD_BEOS)
|
||||||
|
@ -2910,12 +2850,6 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||||
SOURCES="$SOURCES $srcdir/src/power/macosx/*.c"
|
SOURCES="$SOURCES $srcdir/src/power/macosx/*.c"
|
||||||
have_power=yes
|
have_power=yes
|
||||||
fi
|
fi
|
||||||
# Set up files for the cdrom library
|
|
||||||
if test x$enable_cdrom = xyes; then
|
|
||||||
AC_DEFINE(SDL_CDROM_MACOSX)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/macosx/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
fi
|
|
||||||
# Set up files for the timer library
|
# Set up files for the timer library
|
||||||
if test x$enable_timers = xyes; then
|
if test x$enable_timers = xyes; then
|
||||||
AC_DEFINE(SDL_TIMER_UNIX)
|
AC_DEFINE(SDL_TIMER_UNIX)
|
||||||
|
@ -2929,7 +2863,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
|
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
|
||||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit"
|
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit"
|
||||||
# If either the audio or CD driver is used, add the AudioUnit framework
|
# If either the audio or CD driver is used, add the AudioUnit framework
|
||||||
if test x$enable_audio = xyes -o x$enable_cdrom = xyes; then
|
if test x$enable_audio = xyes; then
|
||||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit"
|
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
@ -2959,12 +2893,6 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||||
SOURCES="$SOURCES $srcdir/src/joystick/mint/*.c"
|
SOURCES="$SOURCES $srcdir/src/joystick/mint/*.c"
|
||||||
have_joystick=yes
|
have_joystick=yes
|
||||||
fi
|
fi
|
||||||
# Set up files for the cdrom library
|
|
||||||
if test x$enable_cdrom = xyes; then
|
|
||||||
AC_DEFINE(SDL_CDROM_MINT)
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/mint/*.c"
|
|
||||||
have_cdrom=yes
|
|
||||||
fi
|
|
||||||
# Set up files for the timer library
|
# Set up files for the timer library
|
||||||
if test x$enable_timers = xyes; then
|
if test x$enable_timers = xyes; then
|
||||||
if test x$enable_threads = xyes -a x$enable_pth = xyes; then
|
if test x$enable_threads = xyes -a x$enable_pth = xyes; then
|
||||||
|
@ -3025,12 +2953,6 @@ if test x$have_haptic != xyes; then
|
||||||
fi
|
fi
|
||||||
SOURCES="$SOURCES $srcdir/src/haptic/dummy/*.c"
|
SOURCES="$SOURCES $srcdir/src/haptic/dummy/*.c"
|
||||||
fi
|
fi
|
||||||
if test x$have_cdrom != xyes; then
|
|
||||||
if test x$enable_cdrom = xyes; then
|
|
||||||
AC_DEFINE(SDL_CDROM_DISABLED)
|
|
||||||
fi
|
|
||||||
SOURCES="$SOURCES $srcdir/src/cdrom/dummy/*.c"
|
|
||||||
fi
|
|
||||||
if test x$have_threads != xyes; then
|
if test x$have_threads != xyes; then
|
||||||
if test x$enable_threads = xyes; then
|
if test x$enable_threads = xyes; then
|
||||||
AC_DEFINE(SDL_THREADS_DISABLED)
|
AC_DEFINE(SDL_THREADS_DISABLED)
|
||||||
|
|
|
@ -78,7 +78,6 @@ Enjoy!
|
||||||
#include "SDL_stdinc.h"
|
#include "SDL_stdinc.h"
|
||||||
#include "SDL_atomic.h"
|
#include "SDL_atomic.h"
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "SDL_cpuinfo.h"
|
#include "SDL_cpuinfo.h"
|
||||||
#include "SDL_endian.h"
|
#include "SDL_endian.h"
|
||||||
#include "SDL_error.h"
|
#include "SDL_error.h"
|
||||||
|
@ -109,7 +108,6 @@ extern "C" {
|
||||||
#define SDL_INIT_TIMER 0x00000001
|
#define SDL_INIT_TIMER 0x00000001
|
||||||
#define SDL_INIT_AUDIO 0x00000010
|
#define SDL_INIT_AUDIO 0x00000010
|
||||||
#define SDL_INIT_VIDEO 0x00000020
|
#define SDL_INIT_VIDEO 0x00000020
|
||||||
#define SDL_INIT_CDROM 0x00000100
|
|
||||||
#define SDL_INIT_JOYSTICK 0x00000200
|
#define SDL_INIT_JOYSTICK 0x00000200
|
||||||
#define SDL_INIT_HAPTIC 0x00001000
|
#define SDL_INIT_HAPTIC 0x00001000
|
||||||
#define SDL_INIT_NOPARACHUTE 0x00100000 /* Don't catch fatal signals */
|
#define SDL_INIT_NOPARACHUTE 0x00100000 /* Don't catch fatal signals */
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file SDL_cdrom.h
|
|
||||||
*
|
|
||||||
* This is the CD-audio control API for Simple DirectMedia Layer
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDL_cdrom_h
|
|
||||||
#define _SDL_cdrom_h
|
|
||||||
|
|
||||||
#include "SDL_stdinc.h"
|
|
||||||
#include "SDL_error.h"
|
|
||||||
|
|
||||||
#include "begin_code.h"
|
|
||||||
/* Set up for C function definitions, even when using C++ */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
extern "C" {
|
|
||||||
/* *INDENT-ON* */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* In order to use these functions, SDL_Init() must have been called
|
|
||||||
with the SDL_INIT_CDROM flag. This causes SDL to scan the system
|
|
||||||
for CD-ROM drives, and load appropriate drivers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM tracks on a disk */
|
|
||||||
#define SDL_MAX_TRACKS 99
|
|
||||||
|
|
||||||
/* The types of CD-ROM track possible */
|
|
||||||
#define SDL_AUDIO_TRACK 0x00
|
|
||||||
#define SDL_DATA_TRACK 0x04
|
|
||||||
|
|
||||||
/* The possible states which a CD-ROM drive can be in. */
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
CD_TRAYEMPTY,
|
|
||||||
CD_STOPPED,
|
|
||||||
CD_PLAYING,
|
|
||||||
CD_PAUSED,
|
|
||||||
CD_ERROR = -1
|
|
||||||
} CDstatus;
|
|
||||||
|
|
||||||
/* Given a status, returns true if there's a disk in the drive */
|
|
||||||
#define CD_INDRIVE(status) ((int)(status) > 0)
|
|
||||||
|
|
||||||
typedef struct SDL_CDtrack
|
|
||||||
{
|
|
||||||
Uint8 id; /* Track number */
|
|
||||||
Uint8 type; /* Data or audio track */
|
|
||||||
Uint16 unused;
|
|
||||||
Uint32 length; /* Length, in frames, of this track */
|
|
||||||
Uint32 offset; /* Offset, in frames, from start of disk */
|
|
||||||
} SDL_CDtrack;
|
|
||||||
|
|
||||||
/* This structure is only current as of the last call to SDL_CDStatus() */
|
|
||||||
typedef struct SDL_CD
|
|
||||||
{
|
|
||||||
int id; /* Private drive identifier */
|
|
||||||
CDstatus status; /* Current drive status */
|
|
||||||
|
|
||||||
/* The rest of this structure is only valid if there's a CD in drive */
|
|
||||||
int numtracks; /* Number of tracks on disk */
|
|
||||||
int cur_track; /* Current track position */
|
|
||||||
int cur_frame; /* Current frame offset within current track */
|
|
||||||
SDL_CDtrack track[SDL_MAX_TRACKS + 1];
|
|
||||||
} SDL_CD;
|
|
||||||
|
|
||||||
/* Conversion functions from frames to Minute/Second/Frames and vice versa */
|
|
||||||
#define CD_FPS 75
|
|
||||||
#define FRAMES_TO_MSF(f, M,S,F) { \
|
|
||||||
int value = f; \
|
|
||||||
*(F) = value%CD_FPS; \
|
|
||||||
value /= CD_FPS; \
|
|
||||||
*(S) = value%60; \
|
|
||||||
value /= 60; \
|
|
||||||
*(M) = value; \
|
|
||||||
}
|
|
||||||
#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F))
|
|
||||||
|
|
||||||
/* CD-audio API functions: */
|
|
||||||
|
|
||||||
/* Returns the number of CD-ROM drives on the system, or -1 if
|
|
||||||
SDL_Init() has not been called with the SDL_INIT_CDROM flag.
|
|
||||||
*/
|
|
||||||
extern DECLSPEC int SDLCALL SDL_CDNumDrives(void);
|
|
||||||
|
|
||||||
/* Returns a human-readable, system-dependent identifier for the CD-ROM.
|
|
||||||
Example:
|
|
||||||
"/dev/cdrom"
|
|
||||||
"E:"
|
|
||||||
"/dev/disk/ide/1/master"
|
|
||||||
*/
|
|
||||||
extern DECLSPEC const char *SDLCALL SDL_CDName(int drive);
|
|
||||||
|
|
||||||
/* Opens a CD-ROM drive for access. It returns a drive handle on success,
|
|
||||||
or NULL if the drive was invalid or busy. This newly opened CD-ROM
|
|
||||||
becomes the default CD used when other CD functions are passed a NULL
|
|
||||||
CD-ROM handle.
|
|
||||||
Drives are numbered starting with 0. Drive 0 is the system default CD-ROM.
|
|
||||||
*/
|
|
||||||
extern DECLSPEC SDL_CD *SDLCALL SDL_CDOpen(int drive);
|
|
||||||
|
|
||||||
/* This function returns the current status of the given drive.
|
|
||||||
If the drive has a CD in it, the table of contents of the CD and current
|
|
||||||
play position of the CD will be stored in the SDL_CD structure.
|
|
||||||
*/
|
|
||||||
extern DECLSPEC CDstatus SDLCALL SDL_CDStatus(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Play the given CD starting at 'start_track' and 'start_frame' for 'ntracks'
|
|
||||||
tracks and 'nframes' frames. If both 'ntrack' and 'nframe' are 0, play
|
|
||||||
until the end of the CD. This function will skip data tracks.
|
|
||||||
This function should only be called after calling SDL_CDStatus() to
|
|
||||||
get track information about the CD.
|
|
||||||
For example:
|
|
||||||
// Play entire CD:
|
|
||||||
if ( CD_INDRIVE(SDL_CDStatus(cdrom)) )
|
|
||||||
SDL_CDPlayTracks(cdrom, 0, 0, 0, 0);
|
|
||||||
// Play last track:
|
|
||||||
if ( CD_INDRIVE(SDL_CDStatus(cdrom)) ) {
|
|
||||||
SDL_CDPlayTracks(cdrom, cdrom->numtracks-1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
// Play first and second track and 10 seconds of third track:
|
|
||||||
if ( CD_INDRIVE(SDL_CDStatus(cdrom)) )
|
|
||||||
SDL_CDPlayTracks(cdrom, 0, 0, 2, 10);
|
|
||||||
|
|
||||||
This function returns 0, or -1 if there was an error.
|
|
||||||
*/
|
|
||||||
extern DECLSPEC int SDLCALL SDL_CDPlayTracks(SDL_CD * cdrom,
|
|
||||||
int start_track,
|
|
||||||
int start_frame, int ntracks,
|
|
||||||
int nframes);
|
|
||||||
|
|
||||||
/* Play the given CD starting at 'start' frame for 'length' frames.
|
|
||||||
It returns 0, or -1 if there was an error.
|
|
||||||
*/
|
|
||||||
extern DECLSPEC int SDLCALL SDL_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
|
|
||||||
/* Pause play -- returns 0, or -1 on error */
|
|
||||||
extern DECLSPEC int SDLCALL SDL_CDPause(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Resume play -- returns 0, or -1 on error */
|
|
||||||
extern DECLSPEC int SDLCALL SDL_CDResume(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Stop play -- returns 0, or -1 on error */
|
|
||||||
extern DECLSPEC int SDLCALL SDL_CDStop(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Eject CD-ROM -- returns 0, or -1 on error */
|
|
||||||
extern DECLSPEC int SDLCALL SDL_CDEject(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Closes the handle for the CD-ROM drive */
|
|
||||||
extern DECLSPEC void SDLCALL SDL_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
}
|
|
||||||
/* *INDENT-ON* */
|
|
||||||
#endif
|
|
||||||
#include "close_code.h"
|
|
||||||
|
|
||||||
#endif /* _SDL_video_h */
|
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -160,7 +160,6 @@
|
||||||
|
|
||||||
/* Allow disabling of core subsystems */
|
/* Allow disabling of core subsystems */
|
||||||
#undef SDL_AUDIO_DISABLED
|
#undef SDL_AUDIO_DISABLED
|
||||||
#undef SDL_CDROM_DISABLED
|
|
||||||
#undef SDL_CPUINFO_DISABLED
|
#undef SDL_CPUINFO_DISABLED
|
||||||
#undef SDL_EVENTS_DISABLED
|
#undef SDL_EVENTS_DISABLED
|
||||||
#undef SDL_FILE_DISABLED
|
#undef SDL_FILE_DISABLED
|
||||||
|
@ -204,22 +203,6 @@
|
||||||
#undef SDL_AUDIO_DRIVER_FUSIONSOUND
|
#undef SDL_AUDIO_DRIVER_FUSIONSOUND
|
||||||
#undef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
|
#undef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
|
||||||
|
|
||||||
/* Enable various cdrom drivers */
|
|
||||||
#undef SDL_CDROM_AIX
|
|
||||||
#undef SDL_CDROM_BEOS
|
|
||||||
#undef SDL_CDROM_BSDI
|
|
||||||
#undef SDL_CDROM_DC
|
|
||||||
#undef SDL_CDROM_DUMMY
|
|
||||||
#undef SDL_CDROM_FREEBSD
|
|
||||||
#undef SDL_CDROM_LINUX
|
|
||||||
#undef SDL_CDROM_MACOSX
|
|
||||||
#undef SDL_CDROM_MINT
|
|
||||||
#undef SDL_CDROM_OPENBSD
|
|
||||||
#undef SDL_CDROM_OS2
|
|
||||||
#undef SDL_CDROM_OSF
|
|
||||||
#undef SDL_CDROM_QNX
|
|
||||||
#undef SDL_CDROM_WIN32
|
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#undef SDL_INPUT_LINUXEV
|
#undef SDL_INPUT_LINUXEV
|
||||||
#undef SDL_INPUT_TSLIB
|
#undef SDL_INPUT_TSLIB
|
||||||
|
|
|
@ -88,9 +88,6 @@ typedef unsigned long uintptr_t;
|
||||||
#define SDL_AUDIO_DRIVER_DISK 1
|
#define SDL_AUDIO_DRIVER_DISK 1
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
|
|
||||||
/* Enable various cdrom drivers */
|
|
||||||
#define SDL_CDROM_DC 1
|
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#define SDL_JOYSTICK_DC 1
|
#define SDL_JOYSTICK_DC 1
|
||||||
#define SDL_HAPTIC_DUMMY 1
|
#define SDL_HAPTIC_DUMMY 1
|
||||||
|
|
|
@ -106,9 +106,6 @@ typedef unsigned long uintptr_t;
|
||||||
/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
|
/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
|
|
||||||
/* Enable the stub cdrom driver (src/cdrom/dummy/\*.c) */
|
|
||||||
#define SDL_CDROM_DISABLED 1
|
|
||||||
|
|
||||||
/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
|
/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
|
||||||
#define SDL_HAPTIC_DISABLED 1
|
#define SDL_HAPTIC_DISABLED 1
|
||||||
|
|
||||||
|
|
|
@ -106,9 +106,6 @@
|
||||||
#define SDL_AUDIO_DRIVER_DISK 1
|
#define SDL_AUDIO_DRIVER_DISK 1
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
|
|
||||||
/* Enable various cdrom drivers */
|
|
||||||
#define SDL_CDROM_MACOSX 1
|
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#define SDL_JOYSTICK_IOKIT 1
|
#define SDL_JOYSTICK_IOKIT 1
|
||||||
#define SDL_HAPTIC_IOKIT 1
|
#define SDL_HAPTIC_IOKIT 1
|
||||||
|
|
|
@ -43,9 +43,6 @@ typedef unsigned long uintptr_t;
|
||||||
/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
|
/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
|
|
||||||
/* Enable the stub cdrom driver (src/cdrom/dummy/\*.c) */
|
|
||||||
#define SDL_CDROM_DISABLED 1
|
|
||||||
|
|
||||||
/* Enable the stub joystick driver (src/joystick/dummy/\*.c) */
|
/* Enable the stub joystick driver (src/joystick/dummy/\*.c) */
|
||||||
#define SDL_JOYSTICK_DISABLED 1
|
#define SDL_JOYSTICK_DISABLED 1
|
||||||
|
|
||||||
|
|
|
@ -96,9 +96,6 @@ typedef unsigned __PTRDIFF_TYPE__ uintptr_t;
|
||||||
#define SDL_AUDIO_DRIVER_NDS 1
|
#define SDL_AUDIO_DRIVER_NDS 1
|
||||||
/*#define SDL_AUDIO_DRIVER_DUMMY 1 TODO: uncomment this later*/
|
/*#define SDL_AUDIO_DRIVER_DUMMY 1 TODO: uncomment this later*/
|
||||||
|
|
||||||
/* DS doesn't have optical media */
|
|
||||||
#define SDL_CDROM_DISABLED 1
|
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#define SDL_JOYSTICK_NDS 1
|
#define SDL_JOYSTICK_NDS 1
|
||||||
/*#define SDL_JOYSTICK_DUMMY 1 TODO: uncomment this later*/
|
/*#define SDL_JOYSTICK_DUMMY 1 TODO: uncomment this later*/
|
||||||
|
|
|
@ -116,9 +116,6 @@ typedef unsigned long long uint64_t;
|
||||||
#define SDL_AUDIO_DRIVER_DISK 1
|
#define SDL_AUDIO_DRIVER_DISK 1
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
|
|
||||||
/* Enable various cdrom drivers */
|
|
||||||
#define SDL_CDROM_OS2 1
|
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#define SDL_JOYSTICK_OS2 1
|
#define SDL_JOYSTICK_OS2 1
|
||||||
#define SDL_HAPTIC_DUMMY 1
|
#define SDL_HAPTIC_DUMMY 1
|
||||||
|
|
|
@ -95,7 +95,6 @@
|
||||||
#define HAVE_SETJMP 1
|
#define HAVE_SETJMP 1
|
||||||
#define HAVE_NANOSLEEP 1
|
#define HAVE_NANOSLEEP 1
|
||||||
|
|
||||||
#define SDL_CDROM_DISABLED 1
|
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
#define SDL_AUDIO_DRIVER_OSS 1
|
#define SDL_AUDIO_DRIVER_OSS 1
|
||||||
|
|
||||||
|
|
|
@ -150,13 +150,6 @@ typedef unsigned int uintptr_t;
|
||||||
#define SDL_AUDIO_DRIVER_DISK 1
|
#define SDL_AUDIO_DRIVER_DISK 1
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
|
|
||||||
/* Enable various cdrom drivers */
|
|
||||||
#ifdef _WIN32_WCE
|
|
||||||
#define SDL_CDROM_DISABLED 1
|
|
||||||
#else
|
|
||||||
#define SDL_CDROM_WIN32 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#ifdef _WIN32_WCE
|
#ifdef _WIN32_WCE
|
||||||
#define SDL_JOYSTICK_DISABLED 1
|
#define SDL_JOYSTICK_DISABLED 1
|
||||||
|
|
26
src/SDL.c
26
src/SDL.c
|
@ -42,10 +42,6 @@ extern void SDL_JoystickQuit(void);
|
||||||
extern int SDL_HapticInit(void);
|
extern int SDL_HapticInit(void);
|
||||||
extern int SDL_HapticQuit(void);
|
extern int SDL_HapticQuit(void);
|
||||||
#endif
|
#endif
|
||||||
#if !SDL_CDROM_DISABLED
|
|
||||||
extern int SDL_CDROMInit(void);
|
|
||||||
extern void SDL_CDROMQuit(void);
|
|
||||||
#endif
|
|
||||||
#if !SDL_TIMERS_DISABLED
|
#if !SDL_TIMERS_DISABLED
|
||||||
extern void SDL_StartTicks(void);
|
extern void SDL_StartTicks(void);
|
||||||
extern int SDL_TimerInit(void);
|
extern int SDL_TimerInit(void);
|
||||||
|
@ -145,22 +141,6 @@ SDL_InitSubSystem(Uint32 flags)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if !SDL_CDROM_DISABLED
|
|
||||||
/* Initialize the CD-ROM subsystem */
|
|
||||||
if ((flags & SDL_INIT_CDROM) && !(SDL_initialized & SDL_INIT_CDROM)) {
|
|
||||||
if (SDL_CDROMInit() < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
SDL_initialized |= SDL_INIT_CDROM;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (flags & SDL_INIT_CDROM) {
|
|
||||||
SDL_SetError("SDL not built with cdrom support");
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,12 +178,6 @@ void
|
||||||
SDL_QuitSubSystem(Uint32 flags)
|
SDL_QuitSubSystem(Uint32 flags)
|
||||||
{
|
{
|
||||||
/* Shut down requested initialized subsystems */
|
/* Shut down requested initialized subsystems */
|
||||||
#if !SDL_CDROM_DISABLED
|
|
||||||
if ((flags & SDL_initialized & SDL_INIT_CDROM)) {
|
|
||||||
SDL_CDROMQuit();
|
|
||||||
SDL_initialized &= ~SDL_INIT_CDROM;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if !SDL_JOYSTICK_DISABLED
|
#if !SDL_JOYSTICK_DISABLED
|
||||||
if ((flags & SDL_initialized & SDL_INIT_JOYSTICK)) {
|
if ((flags & SDL_initialized & SDL_INIT_JOYSTICK)) {
|
||||||
SDL_JoystickQuit();
|
SDL_JoystickQuit();
|
||||||
|
|
|
@ -1,357 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/* This is the CD-audio control API for Simple DirectMedia Layer */
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "SDL_syscdrom.h"
|
|
||||||
|
|
||||||
#define CLIP_FRAMES 10 /* Some CD-ROMs won't go all the way */
|
|
||||||
|
|
||||||
static int SDL_cdinitted = 0;
|
|
||||||
static SDL_CD *default_cdrom;
|
|
||||||
|
|
||||||
/* The system level CD-ROM control functions */
|
|
||||||
struct CDcaps SDL_CDcaps = {
|
|
||||||
NULL, /* Name */
|
|
||||||
NULL, /* Open */
|
|
||||||
NULL, /* GetTOC */
|
|
||||||
NULL, /* Status */
|
|
||||||
NULL, /* Play */
|
|
||||||
NULL, /* Pause */
|
|
||||||
NULL, /* Resume */
|
|
||||||
NULL, /* Stop */
|
|
||||||
NULL, /* Eject */
|
|
||||||
NULL, /* Close */
|
|
||||||
};
|
|
||||||
|
|
||||||
int SDL_numcds;
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDROMInit(void)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
SDL_numcds = 0;
|
|
||||||
retval = SDL_SYS_CDInit();
|
|
||||||
if (retval == 0) {
|
|
||||||
SDL_cdinitted = 1;
|
|
||||||
}
|
|
||||||
default_cdrom = NULL;
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check to see if the CD-ROM subsystem has been initialized */
|
|
||||||
static int
|
|
||||||
CheckInit(int check_cdrom, SDL_CD ** cdrom)
|
|
||||||
{
|
|
||||||
int okay;
|
|
||||||
|
|
||||||
okay = SDL_cdinitted;
|
|
||||||
if (check_cdrom && (*cdrom == NULL)) {
|
|
||||||
*cdrom = default_cdrom;
|
|
||||||
if (*cdrom == NULL) {
|
|
||||||
SDL_SetError("CD-ROM not opened");
|
|
||||||
okay = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!SDL_cdinitted) {
|
|
||||||
SDL_SetError("CD-ROM subsystem not initialized");
|
|
||||||
}
|
|
||||||
return (okay);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDNumDrives(void)
|
|
||||||
{
|
|
||||||
if (!CheckInit(0, NULL)) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
return (SDL_numcds);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
SDL_CDName(int drive)
|
|
||||||
{
|
|
||||||
if (!CheckInit(0, NULL)) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if (drive >= SDL_numcds) {
|
|
||||||
SDL_SetError("Invalid CD-ROM drive index");
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if (SDL_CDcaps.Name) {
|
|
||||||
return (SDL_CDcaps.Name(drive));
|
|
||||||
} else {
|
|
||||||
return ("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_CD *
|
|
||||||
SDL_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
struct SDL_CD *cdrom;
|
|
||||||
|
|
||||||
if (!CheckInit(0, NULL)) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if (drive >= SDL_numcds) {
|
|
||||||
SDL_SetError("Invalid CD-ROM drive index");
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
cdrom = (SDL_CD *) SDL_malloc(sizeof(*cdrom));
|
|
||||||
if (cdrom == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
SDL_memset(cdrom, 0, sizeof(*cdrom));
|
|
||||||
cdrom->id = SDL_CDcaps.Open(drive);
|
|
||||||
if (cdrom->id < 0) {
|
|
||||||
SDL_free(cdrom);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
default_cdrom = cdrom;
|
|
||||||
return (cdrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
CDstatus
|
|
||||||
SDL_CDStatus(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
int i;
|
|
||||||
Uint32 position;
|
|
||||||
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the current status of the drive */
|
|
||||||
cdrom->numtracks = 0;
|
|
||||||
cdrom->cur_track = 0;
|
|
||||||
cdrom->cur_frame = 0;
|
|
||||||
status = SDL_CDcaps.Status(cdrom, &i);
|
|
||||||
position = (Uint32) i;
|
|
||||||
cdrom->status = status;
|
|
||||||
|
|
||||||
/* Get the table of contents, if there's a CD available */
|
|
||||||
if (CD_INDRIVE(status)) {
|
|
||||||
if (SDL_CDcaps.GetTOC(cdrom) < 0) {
|
|
||||||
status = CD_ERROR;
|
|
||||||
}
|
|
||||||
/* If the drive is playing, get current play position */
|
|
||||||
if ((status == CD_PLAYING) || (status == CD_PAUSED)) {
|
|
||||||
for (i = 1; cdrom->track[i].offset <= position; ++i) {
|
|
||||||
/* Keep looking */ ;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Current position: %d, track = %d (offset is %d)\n",
|
|
||||||
position, i - 1, cdrom->track[i - 1].offset);
|
|
||||||
#endif
|
|
||||||
cdrom->cur_track = i - 1;
|
|
||||||
position -= cdrom->track[cdrom->cur_track].offset;
|
|
||||||
cdrom->cur_frame = position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDPlayTracks(SDL_CD * cdrom,
|
|
||||||
int strack, int sframe, int ntracks, int nframes)
|
|
||||||
{
|
|
||||||
int etrack, eframe;
|
|
||||||
int start, length;
|
|
||||||
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the starting and ending tracks */
|
|
||||||
if ((strack < 0) || (strack >= cdrom->numtracks)) {
|
|
||||||
SDL_SetError("Invalid starting track");
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
if (!ntracks && !nframes) {
|
|
||||||
etrack = cdrom->numtracks;
|
|
||||||
eframe = 0;
|
|
||||||
} else {
|
|
||||||
etrack = strack + ntracks;
|
|
||||||
if (etrack == strack) {
|
|
||||||
eframe = sframe + nframes;
|
|
||||||
} else {
|
|
||||||
eframe = nframes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (etrack > cdrom->numtracks) {
|
|
||||||
SDL_SetError("Invalid play length");
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip data tracks and verify frame offsets */
|
|
||||||
while ((strack <= etrack) &&
|
|
||||||
(cdrom->track[strack].type == SDL_DATA_TRACK)) {
|
|
||||||
++strack;
|
|
||||||
}
|
|
||||||
if (sframe >= (int) cdrom->track[strack].length) {
|
|
||||||
SDL_SetError("Invalid starting frame for track %d", strack);
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
while ((etrack > strack) &&
|
|
||||||
(cdrom->track[etrack - 1].type == SDL_DATA_TRACK)) {
|
|
||||||
--etrack;
|
|
||||||
}
|
|
||||||
if (eframe > (int) cdrom->track[etrack].length) {
|
|
||||||
SDL_SetError("Invalid ending frame for track %d", etrack);
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine start frame and play length */
|
|
||||||
start = (cdrom->track[strack].offset + sframe);
|
|
||||||
length = (cdrom->track[etrack].offset + eframe) - start;
|
|
||||||
#ifdef CLIP_FRAMES
|
|
||||||
/* I've never seen this necessary, but xmcd does it.. */
|
|
||||||
length -= CLIP_FRAMES; /* CLIP_FRAMES == 10 */
|
|
||||||
#endif
|
|
||||||
if (length < 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Play! */
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Playing %d frames at offset %d\n", length, start);
|
|
||||||
#endif
|
|
||||||
return (SDL_CDcaps.Play(cdrom, start, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDPlay(SDL_CD * cdrom, int sframe, int length)
|
|
||||||
{
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (SDL_CDcaps.Play(cdrom, sframe, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = SDL_CDcaps.Status(cdrom, NULL);
|
|
||||||
switch (status) {
|
|
||||||
case CD_PLAYING:
|
|
||||||
retval = SDL_CDcaps.Pause(cdrom);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
retval = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = SDL_CDcaps.Status(cdrom, NULL);
|
|
||||||
switch (status) {
|
|
||||||
case CD_PAUSED:
|
|
||||||
retval = SDL_CDcaps.Resume(cdrom);
|
|
||||||
default:
|
|
||||||
retval = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = SDL_CDcaps.Status(cdrom, NULL);
|
|
||||||
switch (status) {
|
|
||||||
case CD_PLAYING:
|
|
||||||
case CD_PAUSED:
|
|
||||||
retval = SDL_CDcaps.Stop(cdrom);
|
|
||||||
default:
|
|
||||||
retval = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
return (SDL_CDcaps.Eject(cdrom));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
/* Check if the CD-ROM subsystem has been initialized */
|
|
||||||
if (!CheckInit(1, &cdrom)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_CDcaps.Close(cdrom);
|
|
||||||
SDL_free(cdrom);
|
|
||||||
default_cdrom = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_CDROMQuit(void)
|
|
||||||
{
|
|
||||||
SDL_SYS_CDQuit();
|
|
||||||
SDL_cdinitted = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is SDL_free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/* This is the system specific header for the SDL CD-ROM API */
|
|
||||||
|
|
||||||
/* Structure of CD audio control functions */
|
|
||||||
extern struct CDcaps
|
|
||||||
{
|
|
||||||
/* Get the name of the specified drive */
|
|
||||||
const char *(*Name) (int drive);
|
|
||||||
|
|
||||||
/* Open the specified drive, returning a drive id, or -1 on error */
|
|
||||||
int (*Open) (int drive);
|
|
||||||
|
|
||||||
/* Get table-of-contents (number of tracks + track info) for disk.
|
|
||||||
The TOC information should be stored in the cdrom structure.
|
|
||||||
This function should return 0 on success, or -1 on error.
|
|
||||||
*/
|
|
||||||
int (*GetTOC) (SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Return the current status and play position, in frames, of the
|
|
||||||
drive. 'position' may be NULL, and if so, should be ignored.
|
|
||||||
*/
|
|
||||||
CDstatus(*Status) (SDL_CD * cdrom, int *position);
|
|
||||||
|
|
||||||
/* Play from frame 'start' to 'start+len' */
|
|
||||||
int (*Play) (SDL_CD * cdrom, int start, int len);
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
int (*Pause) (SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
int (*Resume) (SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
int (*Stop) (SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Eject the current disk */
|
|
||||||
int (*Eject) (SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Close the specified drive */
|
|
||||||
void (*Close) (SDL_CD * cdrom);
|
|
||||||
} SDL_CDcaps;
|
|
||||||
|
|
||||||
/* The number of available CD-ROM drives on the system */
|
|
||||||
extern int SDL_numcds;
|
|
||||||
|
|
||||||
/* Function to scan the system for CD-ROM drives and fill SDL_CDcaps.
|
|
||||||
* This function should set SDL_numcds to the number of available CD
|
|
||||||
* drives. Drive 0 should be the system default CD-ROM.
|
|
||||||
* It should return 0, or -1 on an unrecoverable fatal error.
|
|
||||||
*/
|
|
||||||
extern int SDL_SYS_CDInit(void);
|
|
||||||
|
|
||||||
/* Function to perform any system-specific CD-ROM related cleanup */
|
|
||||||
extern void SDL_SYS_CDQuit(void);
|
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,665 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Carsten Griwodz
|
|
||||||
griff@kom.tu-darmstadt.de
|
|
||||||
|
|
||||||
based on linux/SDL_syscdrom.c by Sam Lantinga
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_AIX
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
/*#define DEBUG_CDROM 1*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/devinfo.h>
|
|
||||||
#include <sys/mntctl.h>
|
|
||||||
#include <sys/statfs.h>
|
|
||||||
#include <sys/vmount.h>
|
|
||||||
#include <fstab.h>
|
|
||||||
#include <sys/scdisk.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDioctl(int id, int command, void *arg);
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int is_cd;
|
|
||||||
int cdfd;
|
|
||||||
int ret;
|
|
||||||
struct devinfo info;
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, stbuf) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
|
||||||
is_cd = 0;
|
|
||||||
if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode)) {
|
|
||||||
cdfd = open(drive, (O_RDONLY | O_EXCL | O_NONBLOCK), 0);
|
|
||||||
if (cdfd >= 0) {
|
|
||||||
ret = SDL_SYS_CDioctl(cdfd, IOCINFO, &info);
|
|
||||||
if (ret < 0) {
|
|
||||||
/* Some kind of error */
|
|
||||||
is_cd = 0;
|
|
||||||
} else {
|
|
||||||
if (info.devtype == DD_CDROM) {
|
|
||||||
is_cd = 1;
|
|
||||||
} else {
|
|
||||||
is_cd = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(cdfd);
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Could not open drive %s (%s)\n", drive,
|
|
||||||
strerror(errno));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return is_cd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Check to make sure it's not already in our list.
|
|
||||||
This can happen when we see a drive via symbolic link.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
if (stbuf->st_rdev == SDL_cdmode[i]) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Duplicate drive detected: %s == %s\n",
|
|
||||||
drive, SDL_cdlist[i]);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_cdmode[i] = stbuf->st_rdev;
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
CheckMounts()
|
|
||||||
{
|
|
||||||
char *buffer;
|
|
||||||
int bufsz;
|
|
||||||
struct vmount *ptr;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
buffer = (char *) SDL_malloc(10);
|
|
||||||
bufsz = 10;
|
|
||||||
if (buffer == NULL) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Could not allocate 10 bytes in aix/SDL_syscdrom.c:CheckMounts\n");
|
|
||||||
exit(-10);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
/* mntctrl() returns an array of all mounted filesystems */
|
|
||||||
ret = mntctl(MCTL_QUERY, bufsz, buffer);
|
|
||||||
if (ret == 0) {
|
|
||||||
/* Buffer was too small, realloc. */
|
|
||||||
bufsz = *(int *) buffer; /* Required size is in first word. */
|
|
||||||
/* (whatever a word is in AIX 4.3.3) */
|
|
||||||
/* int seems to be OK in 32bit mode. */
|
|
||||||
SDL_free(buffer);
|
|
||||||
buffer = (char *) SDL_malloc(bufsz);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Could not allocate %d bytes in aix/SDL_syscdrom.c:CheckMounts\n",
|
|
||||||
bufsz);
|
|
||||||
exit(-10);
|
|
||||||
}
|
|
||||||
} else if (ret < 0) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Error reading vmount structures\n");
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} while (ret == 0);
|
|
||||||
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Read %d vmount structures\n", ret);
|
|
||||||
#endif
|
|
||||||
ptr = (struct vmount *) buffer;
|
|
||||||
do {
|
|
||||||
switch (ptr->vmt_gfstype) {
|
|
||||||
case MNT_CDROM:
|
|
||||||
{
|
|
||||||
struct stat stbuf;
|
|
||||||
char *text;
|
|
||||||
|
|
||||||
text = (char *) ptr + ptr->vmt_data[VMT_OBJECT].vmt_off;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Checking mount path: %s mounted on %s\n", text,
|
|
||||||
(char *) ptr + ptr->vmt_data[VMT_STUB].vmt_off);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(text, &stbuf) > 0) {
|
|
||||||
AddDrive(text, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ptr = (struct vmount *) ((char *) ptr + ptr->vmt_length);
|
|
||||||
ret--;
|
|
||||||
} while (ret > 0);
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
CheckNonmounts()
|
|
||||||
{
|
|
||||||
#ifdef _THREAD_SAFE
|
|
||||||
AFILE_t fsFile = NULL;
|
|
||||||
int passNo = 0;
|
|
||||||
int ret;
|
|
||||||
struct fstab entry;
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
ret = setfsent_r(&fsFile, &passNo);
|
|
||||||
if (ret != 0)
|
|
||||||
return -1;
|
|
||||||
do {
|
|
||||||
ret = getfsent_r(&entry, &fsFile, &passNo);
|
|
||||||
if (ret == 0) {
|
|
||||||
char *l = SDL_strrchr(entry.fs_spec, '/');
|
|
||||||
if (l != NULL) {
|
|
||||||
if (!SDL_strncmp("cd", ++l, 2)) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Found unmounted CD ROM drive with device name %s\n",
|
|
||||||
entry.fs_spec);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(entry.fs_spec, &stbuf) > 0) {
|
|
||||||
AddDrive(entry.fs_spec, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ret == 0);
|
|
||||||
ret = endfsent_r(&fsFile);
|
|
||||||
if (ret != 0)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
struct fstab *entry;
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
setfsent();
|
|
||||||
do {
|
|
||||||
entry = getfsent();
|
|
||||||
if (entry != NULL) {
|
|
||||||
char *l = SDL_strrchr(entry->fs_spec, '/');
|
|
||||||
if (l != NULL) {
|
|
||||||
if (!SDL_strncmp("cd", ++l, 2)) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Found unmounted CD ROM drive with device name %s",
|
|
||||||
entry->fs_spec);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(entry->fs_spec, &stbuf) > 0) {
|
|
||||||
AddDrive(entry->fs_spec, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (entry != NULL);
|
|
||||||
endfsent();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
char *SDLcdrom;
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Checking CD-ROM drive from SDL_CDROM: %s\n",
|
|
||||||
SDLcdrom);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(SDLcdrom, &stbuf) > 0) {
|
|
||||||
AddDrive(SDLcdrom, &stbuf);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckMounts();
|
|
||||||
CheckNonmounts();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General ioctl() CD-ROM command function */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDioctl(int id, int command, void *arg)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = ioctl(id, command, arg);
|
|
||||||
if (retval < 0) {
|
|
||||||
SDL_SetError("ioctl() error: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
char *lastsl;
|
|
||||||
char *cdromname;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We found /dev/cd? drives and that is in our list. But we can
|
|
||||||
* open only the /dev/rcd? versions of those devices for Audio CD.
|
|
||||||
*/
|
|
||||||
len = SDL_strlen(SDL_cdlist[drive]) + 2;
|
|
||||||
cdromname = (char *) SDL_malloc(len);
|
|
||||||
SDL_strlcpy(cdromname, SDL_cdlist[drive], len);
|
|
||||||
lastsl = SDL_strrchr(cdromname, '/');
|
|
||||||
if (lastsl) {
|
|
||||||
*lastsl = 0;
|
|
||||||
SDL_strlcat(cdromname, "/r", len);
|
|
||||||
lastsl = SDL_strrchr(SDL_cdlist[drive], '/');
|
|
||||||
if (lastsl) {
|
|
||||||
lastsl++;
|
|
||||||
SDL_strlcat(cdromname, lastsl, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Should open drive %s, opening %s\n", SDL_cdlist[drive],
|
|
||||||
cdromname);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use exclusive access. Don't use SC_DIAGNOSTICS as xmcd does because they
|
|
||||||
* require root priviledges, and we don't want that. SC_SINGLE provides
|
|
||||||
* exclusive access with less trouble.
|
|
||||||
*/
|
|
||||||
fd = openx(cdromname, O_RDONLY, NULL, SC_SINGLE);
|
|
||||||
if (fd < 0) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Could not open drive %s (%s)\n", cdromname,
|
|
||||||
strerror(errno));
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
struct mode_form_op cdMode;
|
|
||||||
int ret;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
cdMode.action = CD_GET_MODE;
|
|
||||||
ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Could not get drive mode for %s (%s)\n",
|
|
||||||
cdromname, strerror(errno));
|
|
||||||
} else {
|
|
||||||
switch (cdMode.cd_mode_form) {
|
|
||||||
case CD_MODE1:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Drive mode for %s is %s\n",
|
|
||||||
cdromname, "CD-ROM Data Mode 1");
|
|
||||||
break;
|
|
||||||
case CD_MODE2_FORM1:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Drive mode for %s is %s\n",
|
|
||||||
cdromname, "CD-ROM XA Data Mode 2 Form 1");
|
|
||||||
break;
|
|
||||||
case CD_MODE2_FORM2:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Drive mode for %s is %s\n",
|
|
||||||
cdromname, "CD-ROM XA Data Mode 2 Form 2");
|
|
||||||
break;
|
|
||||||
case CD_DA:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Drive mode for %s is %s\n", cdromname, "CD-DA");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Drive mode for %s is %s\n", cdromname, "unknown");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cdMode.action = CD_CHG_MODE;
|
|
||||||
cdMode.cd_mode_form = CD_DA;
|
|
||||||
ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode);
|
|
||||||
if (ret < 0) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Could not set drive mode for %s (%s)\n",
|
|
||||||
cdromname, strerror(errno));
|
|
||||||
#endif
|
|
||||||
SDL_SetError
|
|
||||||
("ioctl() error: Could not set CD drive mode, %s",
|
|
||||||
strerror(errno));
|
|
||||||
} else {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Drive mode for %s set to CD_DA\n", cdromname);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SDL_free(cdromname);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct cd_audio_cmd cmd;
|
|
||||||
struct cd_audio_cmd entry;
|
|
||||||
int i;
|
|
||||||
int okay;
|
|
||||||
|
|
||||||
cmd.audio_cmds = CD_TRK_INFO_AUDIO;
|
|
||||||
cmd.msf_flag = FALSE;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
cdrom->numtracks = cmd.indexing.track_index.last_track
|
|
||||||
- cmd.indexing.track_index.first_track + 1;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read all the track TOC entries */
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
cdrom->track[i].id = 0xAA;;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].id = cmd.indexing.track_index.first_track + i;
|
|
||||||
}
|
|
||||||
entry.audio_cmds = CD_GET_TRK_MSF;
|
|
||||||
entry.indexing.track_msf.track = cdrom->track[i].id;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &entry) < 0) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].type = 0; /* don't know how to detect 0x04 data track */
|
|
||||||
cdrom->track[i].offset =
|
|
||||||
MSF_TO_FRAMES(entry.indexing.track_msf.mins,
|
|
||||||
entry.indexing.track_msf.secs,
|
|
||||||
entry.indexing.track_msf.frames);
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length = cdrom->track[i].offset
|
|
||||||
- cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == (cdrom->numtracks + 1)) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
struct cd_audio_cmd cmd;
|
|
||||||
cmd.audio_cmds = CD_INFO_AUDIO;
|
|
||||||
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "ioctl failed in SDL_SYS_CDStatus (%s)\n",
|
|
||||||
SDL_GetError());
|
|
||||||
#endif
|
|
||||||
status = CD_ERROR;
|
|
||||||
} else {
|
|
||||||
switch (cmd.status) {
|
|
||||||
case CD_NO_AUDIO:
|
|
||||||
case CD_COMPLETED:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case CD_PLAY_AUDIO:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case CD_PAUSE_AUDIO:
|
|
||||||
status = CD_PAUSED;
|
|
||||||
break;
|
|
||||||
case CD_NOT_VALID:
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "cdStatus failed with CD_NOT_VALID\n");
|
|
||||||
#endif
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
case CD_STATUS_ERROR:
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "cdStatus failed with CD_STATUS_ERROR\n");
|
|
||||||
#endif
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "cdStatus failed with unknown error\n");
|
|
||||||
#endif
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
*position =
|
|
||||||
MSF_TO_FRAMES(cmd.indexing.info_audio.current_mins,
|
|
||||||
cmd.indexing.info_audio.current_secs,
|
|
||||||
cmd.indexing.info_audio.current_frames);
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
struct cd_audio_cmd cmd;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* My CD Rom is muted by default. I think I read that this is new with
|
|
||||||
* AIX 4.3. SDL does not change the volume, so I need a kludge. Maybe
|
|
||||||
* its better to do this elsewhere?
|
|
||||||
*/
|
|
||||||
cmd.audio_cmds = CD_PLAY_AUDIO | CD_SET_VOLUME;
|
|
||||||
cmd.msf_flag = TRUE;
|
|
||||||
FRAMES_TO_MSF(start,
|
|
||||||
&cmd.indexing.msf.first_mins,
|
|
||||||
&cmd.indexing.msf.first_secs,
|
|
||||||
&cmd.indexing.msf.first_frames);
|
|
||||||
FRAMES_TO_MSF(start + length,
|
|
||||||
&cmd.indexing.msf.last_mins,
|
|
||||||
&cmd.indexing.msf.last_secs, &cmd.indexing.msf.last_frames);
|
|
||||||
cmd.volume_type = CD_VOLUME_ALL;
|
|
||||||
cmd.all_channel_vol = 255; /* This is a uchar. What is a good value? No docu! */
|
|
||||||
cmd.out_port_0_sel = CD_AUDIO_CHNL_0;
|
|
||||||
cmd.out_port_1_sel = CD_AUDIO_CHNL_1;
|
|
||||||
cmd.out_port_2_sel = CD_AUDIO_CHNL_2;
|
|
||||||
cmd.out_port_3_sel = CD_AUDIO_CHNL_3;
|
|
||||||
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
|
|
||||||
cmd.indexing.msf.first_mins,
|
|
||||||
cmd.indexing.msf.first_secs,
|
|
||||||
cmd.indexing.msf.first_frames,
|
|
||||||
cmd.indexing.msf.last_mins,
|
|
||||||
cmd.indexing.msf.last_secs, cmd.indexing.msf.last_frames);
|
|
||||||
#endif
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct cd_audio_cmd cmd;
|
|
||||||
cmd.audio_cmds = CD_PAUSE_AUDIO;
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct cd_audio_cmd cmd;
|
|
||||||
cmd.audio_cmds = CD_RESUME_AUDIO;
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct cd_audio_cmd cmd;
|
|
||||||
cmd.audio_cmds = CD_STOP_AUDIO;
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, DKEJECT, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_AIX */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,427 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_BEOS
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control on BeOS
|
|
||||||
(not completely implemented yet)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <scsi.h>
|
|
||||||
#include <Directory.h>
|
|
||||||
#include <Entry.h>
|
|
||||||
#include <Path.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Constants to help us get at the SCSI table-of-contents info */
|
|
||||||
#define CD_NUMTRACKS(toc) toc.toc_data[3]
|
|
||||||
#define CD_TRACK(toc, track) (&toc.toc_data[6+(track)*8])
|
|
||||||
#define CD_TRACK_N(toc, track) CD_TRACK(toc, track)[0]
|
|
||||||
#define CD_TRACK_M(toc, track) CD_TRACK(toc, track)[3]
|
|
||||||
#define CD_TRACK_S(toc, track) CD_TRACK(toc, track)[4]
|
|
||||||
#define CD_TRACK_F(toc, track) CD_TRACK(toc, track)[5]
|
|
||||||
|
|
||||||
/* Constants to help us get at the SCSI position info */
|
|
||||||
#define POS_TRACK(pos) pos.position[6]
|
|
||||||
#define POS_ABS_M(pos) pos.position[9]
|
|
||||||
#define POS_ABS_S(pos) pos.position[10]
|
|
||||||
#define POS_ABS_F(pos) pos.position[11]
|
|
||||||
#define POS_REL_M(pos) pos.position[13]
|
|
||||||
#define POS_REL_S(pos) pos.position[14]
|
|
||||||
#define POS_REL_F(pos) pos.position[15]
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
int try_dir(const char *directory);
|
|
||||||
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive)
|
|
||||||
{
|
|
||||||
struct stat stbuf;
|
|
||||||
int is_cd, cdfd;
|
|
||||||
device_geometry info;
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, &stbuf) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
|
||||||
is_cd = 0;
|
|
||||||
cdfd = open(drive, 0);
|
|
||||||
if (cdfd >= 0) {
|
|
||||||
if (ioctl(cdfd, B_GET_GEOMETRY, &info) == B_NO_ERROR) {
|
|
||||||
if (info.device_type == B_CD) {
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(cdfd);
|
|
||||||
} else {
|
|
||||||
/* This can happen when the drive is open .. (?) */ ;
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
return (is_cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
len = SDL_strlen(drive) + 1;
|
|
||||||
SDL_cdlist[i] = (char *) SDL_malloc(len);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_strlcpy(SDL_cdlist[i], drive, len);
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef CDROM_DEBUG
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IDE bus scanning magic */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
IDE_GET_DEVICES_INFO = B_DEVICE_OP_CODES_END + 50,
|
|
||||||
};
|
|
||||||
struct ide_ctrl_info
|
|
||||||
{
|
|
||||||
bool ide_0_present;
|
|
||||||
bool ide_0_master_present;
|
|
||||||
bool ide_0_slave_present;
|
|
||||||
int ide_0_master_type;
|
|
||||||
int ide_0_slave_type;
|
|
||||||
bool ide_1_present;
|
|
||||||
bool ide_1_master_present;
|
|
||||||
bool ide_1_slave_present;
|
|
||||||
int ide_1_master_type;
|
|
||||||
int ide_1_slave_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
char *SDLcdrom;
|
|
||||||
int raw_fd;
|
|
||||||
struct ide_ctrl_info info;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
if (CheckDrive(SDLcdrom) > 0) {
|
|
||||||
AddDrive(SDLcdrom);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives */
|
|
||||||
try_dir("/dev/disk");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
try_dir(const char *directory)
|
|
||||||
{
|
|
||||||
BDirectory dir;
|
|
||||||
dir.SetTo(directory);
|
|
||||||
if (dir.InitCheck() != B_NO_ERROR) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
dir.Rewind();
|
|
||||||
BEntry entry;
|
|
||||||
while (dir.GetNextEntry(&entry) >= 0) {
|
|
||||||
BPath path;
|
|
||||||
const char *name;
|
|
||||||
entry_ref e;
|
|
||||||
|
|
||||||
if (entry.GetPath(&path) != B_NO_ERROR)
|
|
||||||
continue;
|
|
||||||
name = path.Path();
|
|
||||||
|
|
||||||
if (entry.GetRef(&e) != B_NO_ERROR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (entry.IsDirectory()) {
|
|
||||||
if (SDL_strcmp(e.name, "floppy") == 0)
|
|
||||||
continue; /* ignore floppy (it is not silent) */
|
|
||||||
int devfd = try_dir(name);
|
|
||||||
if (devfd >= 0)
|
|
||||||
return devfd;
|
|
||||||
} else {
|
|
||||||
int devfd;
|
|
||||||
device_geometry g;
|
|
||||||
|
|
||||||
if (SDL_strcmp(e.name, "raw") != 0)
|
|
||||||
continue; /* ignore partitions */
|
|
||||||
|
|
||||||
devfd = open(name, O_RDONLY);
|
|
||||||
if (devfd < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
|
|
||||||
if (g.device_type == B_CD) {
|
|
||||||
AddDrive(strdup(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(devfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* General ioctl() CD-ROM command function */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDioctl(int index, int command, void *arg)
|
|
||||||
{
|
|
||||||
int okay;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
fd = open(SDL_cdlist[index], 0);
|
|
||||||
if (fd >= 0) {
|
|
||||||
if (ioctl(fd, command, arg) == B_NO_ERROR) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
return (drive);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
scsi_toc toc;
|
|
||||||
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, B_SCSI_GET_TOC, &toc) == 0) {
|
|
||||||
cdrom->numtracks = CD_NUMTRACKS(toc);
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
cdrom->track[i].id = CD_TRACK_N(toc, i);
|
|
||||||
/* FIXME: How do we tell on BeOS? */
|
|
||||||
cdrom->track[i].type = SDL_AUDIO_TRACK;
|
|
||||||
cdrom->track[i].offset = MSF_TO_FRAMES(CD_TRACK_M(toc, i),
|
|
||||||
CD_TRACK_S(toc, i),
|
|
||||||
CD_TRACK_F(toc, i));
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
} else {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
int fd;
|
|
||||||
int cur_frame;
|
|
||||||
scsi_position pos;
|
|
||||||
|
|
||||||
fd = open(SDL_cdlist[cdrom->id], 0);
|
|
||||||
cur_frame = 0;
|
|
||||||
if (fd >= 0) {
|
|
||||||
if (ioctl(fd, B_SCSI_GET_POSITION, &pos) == B_NO_ERROR) {
|
|
||||||
cur_frame =
|
|
||||||
MSF_TO_FRAMES(POS_ABS_M(pos), POS_ABS_S(pos), POS_ABS_F(pos));
|
|
||||||
}
|
|
||||||
if (!pos.position[1] || (pos.position[1] >= 0x13) ||
|
|
||||||
((pos.position[1] == 0x12) && (!pos.position[6]))) {
|
|
||||||
status = CD_STOPPED;
|
|
||||||
} else if (pos.position[1] == 0x11) {
|
|
||||||
status = CD_PLAYING;
|
|
||||||
} else {
|
|
||||||
status = CD_PAUSED;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
} else {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
*position = cur_frame;
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
int okay;
|
|
||||||
int fd;
|
|
||||||
scsi_play_position pos;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
fd = open(SDL_cdlist[cdrom->id], 0);
|
|
||||||
if (fd >= 0) {
|
|
||||||
FRAMES_TO_MSF(start, &pos.start_m, &pos.start_s, &pos.start_f);
|
|
||||||
FRAMES_TO_MSF(start + length, &pos.end_m, &pos.end_s, &pos.end_f);
|
|
||||||
if (ioctl(fd, B_SCSI_PLAY_POSITION, &pos) == B_NO_ERROR) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_PAUSE_AUDIO, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_RESUME_AUDIO, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_STOP_AUDIO, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, B_SCSI_EJECT, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_BEOS */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,550 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_BSDI
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Functions for system-level CD-ROM audio control for BSD/OS 4.x
|
|
||||||
* This started life out as a copy of the freebsd/SDL_cdrom.c file but was
|
|
||||||
* heavily modified. Works for standard (MMC) SCSI and ATAPI CDrom drives.
|
|
||||||
*
|
|
||||||
* Steven Schultz - sms@to.gd-es.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <err.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include </sys/dev/scsi/scsi.h>
|
|
||||||
#include </sys/dev/scsi/scsi_ioctl.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The msf_to_frame and frame_to_msf were yanked from libcdrom and inlined
|
|
||||||
* here so that -lcdrom doesn't have to be dragged in for something so simple.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FRAMES_PER_SECOND 75
|
|
||||||
#define FRAMES_PER_MINUTE (FRAMES_PER_SECOND * 60)
|
|
||||||
|
|
||||||
int
|
|
||||||
msf_to_frame(int minute, int second, int frame)
|
|
||||||
{
|
|
||||||
return (minute * FRAMES_PER_MINUTE + second * FRAMES_PER_SECOND + frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
frame_to_msf(int frame, int *minp, int *secp, int *framep)
|
|
||||||
{
|
|
||||||
*minp = frame / FRAMES_PER_MINUTE;
|
|
||||||
*secp = (frame % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND;
|
|
||||||
*framep = frame % FRAMES_PER_SECOND;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
typedef struct scsi_cdb cdb_t;
|
|
||||||
|
|
||||||
static int
|
|
||||||
scsi_cmd(int fd,
|
|
||||||
struct scsi_cdb *cdb,
|
|
||||||
int cdblen,
|
|
||||||
int rw, caddr_t data, int datalen, struct scsi_user_cdb *sus)
|
|
||||||
{
|
|
||||||
int scsistatus;
|
|
||||||
unsigned char *cp;
|
|
||||||
struct scsi_user_cdb suc;
|
|
||||||
|
|
||||||
/* safety checks */
|
|
||||||
if (!cdb)
|
|
||||||
return (-1);
|
|
||||||
if (rw != SUC_READ && rw != SUC_WRITE)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
suc.suc_flags = rw;
|
|
||||||
suc.suc_cdblen = cdblen;
|
|
||||||
bcopy(cdb, suc.suc_cdb, cdblen);
|
|
||||||
suc.suc_datalen = datalen;
|
|
||||||
suc.suc_data = data;
|
|
||||||
suc.suc_timeout = 10; /* 10 secs max for TUR or SENSE */
|
|
||||||
if (ioctl(fd, SCSIRAWCDB, &suc) == -1)
|
|
||||||
return (-11);
|
|
||||||
scsistatus = suc.suc_sus.sus_status;
|
|
||||||
cp = suc.suc_sus.sus_sense;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If a place to copy the sense data back to has been provided then the
|
|
||||||
* caller is responsible for checking the errors and printing any information
|
|
||||||
* out if the status was not successful.
|
|
||||||
*/
|
|
||||||
if (scsistatus != 0 && !sus) {
|
|
||||||
fprintf(stderr, "scsistatus = %x cmd = %x\n", scsistatus, cdb[0]);
|
|
||||||
fprintf(stderr,
|
|
||||||
"sense %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
|
|
||||||
cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7],
|
|
||||||
cp[8], cp[9], cp[10], cp[11], cp[12], cp[13], cp[14], cp[15]);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
if (sus)
|
|
||||||
bcopy(&suc, sus, sizeof(struct scsi_user_cdb));
|
|
||||||
if (scsistatus)
|
|
||||||
return (1); /* Return non-zero for unsuccessful status */
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* request vendor brand and model */
|
|
||||||
unsigned char *
|
|
||||||
Inquiry(int fd)
|
|
||||||
{
|
|
||||||
static struct scsi_cdb6 cdb = {
|
|
||||||
0x12,
|
|
||||||
0, 0, 0,
|
|
||||||
56,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
static unsigned char Inqbuffer[56];
|
|
||||||
|
|
||||||
if (scsi_cmd(fd, (cdb_t *) & cdb, 6, SUC_READ, Inqbuffer,
|
|
||||||
sizeof(Inqbuffer), 0))
|
|
||||||
return ("\377");
|
|
||||||
return (Inqbuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ADD_SENSECODE 12
|
|
||||||
#define ADD_SC_QUALIFIER 13
|
|
||||||
|
|
||||||
int
|
|
||||||
TestForMedium(int fd)
|
|
||||||
{
|
|
||||||
int sts, asc, ascq;
|
|
||||||
struct scsi_user_cdb sus;
|
|
||||||
static struct scsi_cdb6 cdb = {
|
|
||||||
CMD_TEST_UNIT_READY, /* command */
|
|
||||||
0, /* reserved */
|
|
||||||
0, /* reserved */
|
|
||||||
0, /* reserved */
|
|
||||||
0, /* reserved */
|
|
||||||
0 /* reserved */
|
|
||||||
};
|
|
||||||
|
|
||||||
again:sts = scsi_cmd(fd, (cdb_t *) & cdb, 6, SUC_READ, 0, 0, &sus);
|
|
||||||
asc = sus.suc_sus.sus_sense[ADD_SENSECODE];
|
|
||||||
ascq = sus.suc_sus.sus_sense[ADD_SC_QUALIFIER];
|
|
||||||
if (asc == 0x3a && ascq == 0x0) /* no medium */
|
|
||||||
return (0);
|
|
||||||
if (asc == 0x28 && ascq == 0x0) /* medium changed */
|
|
||||||
goto again;
|
|
||||||
if (asc == 0x4 && ascq == 0x1) { /* coming ready */
|
|
||||||
sleep(2);
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int is_cd = 0, cdfd;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, stbuf) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
|
||||||
cdfd = open(drive, (O_RDONLY | O_EXCL | O_NONBLOCK), 0);
|
|
||||||
if (cdfd >= 0) {
|
|
||||||
p = Inquiry(cdfd);
|
|
||||||
if (*p == TYPE_ROM)
|
|
||||||
is_cd = 1;
|
|
||||||
close(cdfd);
|
|
||||||
}
|
|
||||||
return (is_cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Check to make sure it's not already in our list.
|
|
||||||
This can happen when we see a drive via symbolic link.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
if (stbuf->st_rdev == SDL_cdmode[i]) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Duplicate drive detected: %s == %s\n",
|
|
||||||
drive, SDL_cdlist[i]);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_cdmode[i] = stbuf->st_rdev;
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* checklist: /dev/rsr?c */
|
|
||||||
static char *checklist[] = {
|
|
||||||
"?0 rsr?", NULL
|
|
||||||
};
|
|
||||||
char *SDLcdrom;
|
|
||||||
int i, j, exists;
|
|
||||||
char drive[32];
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
if (CheckDrive(SDLcdrom, &stbuf) > 0) {
|
|
||||||
AddDrive(SDLcdrom, &stbuf);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives */
|
|
||||||
for (i = 0; checklist[i]; ++i) {
|
|
||||||
if (checklist[i][0] == '?') {
|
|
||||||
char *insert;
|
|
||||||
exists = 1;
|
|
||||||
for (j = checklist[i][1]; exists; ++j) {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc",
|
|
||||||
&checklist[i][3]);
|
|
||||||
insert = SDL_strchr(drive, '?');
|
|
||||||
if (insert != NULL) {
|
|
||||||
*insert = j;
|
|
||||||
}
|
|
||||||
switch (CheckDrive(drive, &stbuf)) {
|
|
||||||
/* Drive exists and is a CD-ROM */
|
|
||||||
case 1:
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
break;
|
|
||||||
/* Drive exists, but isn't a CD-ROM */
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
/* Drive doesn't exist */
|
|
||||||
case -1:
|
|
||||||
exists = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
checklist[i]);
|
|
||||||
if (CheckDrive(drive, &stbuf) > 0) {
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
return (open(SDL_cdlist[drive], O_RDONLY | O_NONBLOCK | O_EXCL, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
u_char cdb[10], buf[4], *p, *toc;
|
|
||||||
struct scsi_user_cdb sus;
|
|
||||||
int i, sts, first_track, last_track, ntracks, toc_size;
|
|
||||||
|
|
||||||
bzero(cdb, sizeof(cdb));
|
|
||||||
cdb[0] = 0x43; /* Read TOC */
|
|
||||||
cdb[1] = 0x2; /* MSF */
|
|
||||||
cdb[8] = 4; /* size TOC header */
|
|
||||||
sts = scsi_cmd(cdrom->id, (cdb_t *) cdb, 10, SUC_READ, buf, 4, &sus);
|
|
||||||
if (sts < 0)
|
|
||||||
return (-1);
|
|
||||||
first_track = buf[2];
|
|
||||||
last_track = buf[3];
|
|
||||||
ntracks = last_track - first_track + 1;
|
|
||||||
cdrom->numtracks = ntracks;
|
|
||||||
toc_size = 4 + (ntracks + 1) * 8;
|
|
||||||
toc = (u_char *) SDL_malloc(toc_size);
|
|
||||||
if (toc == NULL)
|
|
||||||
return (-1);
|
|
||||||
bzero(cdb, sizeof(cdb));
|
|
||||||
cdb[0] = 0x43;
|
|
||||||
cdb[1] = 0x2;
|
|
||||||
cdb[6] = first_track;
|
|
||||||
cdb[7] = toc_size >> 8;
|
|
||||||
cdb[8] = toc_size & 0xff;
|
|
||||||
sts = scsi_cmd(cdrom->id, (cdb_t *) cdb, 10, SUC_READ, toc, toc_size,
|
|
||||||
&sus);
|
|
||||||
if (sts < 0) {
|
|
||||||
SDL_free(toc);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, p = toc + 4; i <= ntracks; i++, p += 8) {
|
|
||||||
if (i == ntracks)
|
|
||||||
cdrom->track[i].id = 0xAA; /* Leadout */
|
|
||||||
else
|
|
||||||
cdrom->track[i].id = first_track + i;
|
|
||||||
if (p[1] & 0x20)
|
|
||||||
cdrom->track[i].type = SDL_DATA_TRACK;
|
|
||||||
else
|
|
||||||
cdrom->track[i].type = SDL_AUDIO_TRACK;
|
|
||||||
cdrom->track[i].offset = msf_to_frame(p[5], p[6], p[7]);
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0)
|
|
||||||
cdrom->track[i - 1].length = cdrom->track[i].offset -
|
|
||||||
cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
SDL_free(toc);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
u_char cdb[10], buf[16];
|
|
||||||
int sts;
|
|
||||||
struct scsi_user_cdb sus;
|
|
||||||
|
|
||||||
bzero(cdb, sizeof(cdb));
|
|
||||||
cdb[0] = 0x42; /* read subq */
|
|
||||||
cdb[1] = 0x2; /* MSF */
|
|
||||||
cdb[2] = 0x40; /* q channel */
|
|
||||||
cdb[3] = 1; /* current pos */
|
|
||||||
cdb[7] = sizeof(buf) >> 8;
|
|
||||||
cdb[8] = sizeof(buf) & 0xff;
|
|
||||||
sts = scsi_cmd(cdrom->id, (cdb_t *) cdb, 10, SUC_READ, buf, sizeof(buf),
|
|
||||||
&sus);
|
|
||||||
if (sts < 0)
|
|
||||||
return (-1);
|
|
||||||
if (sts) {
|
|
||||||
if (TestForMedium(cdrom->id) == 0)
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
else
|
|
||||||
status = CD_ERROR;
|
|
||||||
} else {
|
|
||||||
switch (buf[1]) {
|
|
||||||
case 0x11:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case 0x12:
|
|
||||||
status = CD_PAUSED;
|
|
||||||
break;
|
|
||||||
case 0x13:
|
|
||||||
case 0x14:
|
|
||||||
case 0x15:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED))
|
|
||||||
*position = msf_to_frame(buf[9], buf[10], buf[11]);
|
|
||||||
else
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
u_char cdb[10];
|
|
||||||
int sts, minute, second, frame, eminute, esecond, eframe;
|
|
||||||
struct scsi_user_cdb sus;
|
|
||||||
|
|
||||||
bzero(cdb, sizeof(cdb));
|
|
||||||
cdb[0] = 0x47; /* Play */
|
|
||||||
frame_to_msf(start, &minute, &second, &frame);
|
|
||||||
frame_to_msf(start + length, &eminute, &esecond, &eframe);
|
|
||||||
cdb[3] = minute;
|
|
||||||
cdb[4] = second;
|
|
||||||
cdb[5] = frame;
|
|
||||||
cdb[6] = eminute;
|
|
||||||
cdb[7] = esecond;
|
|
||||||
cdb[8] = eframe;
|
|
||||||
sts = scsi_cmd(cdrom->id, (cdb_t *) cdb, 10, SUC_READ, 0, 0, &sus);
|
|
||||||
return (sts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
pauseresume(SDL_CD * cdrom, int flag)
|
|
||||||
{
|
|
||||||
u_char cdb[10];
|
|
||||||
struct scsi_user_cdb sus;
|
|
||||||
|
|
||||||
bzero(cdb, sizeof(cdb));
|
|
||||||
cdb[0] = 0x4b;
|
|
||||||
cdb[8] = flag & 0x1;
|
|
||||||
return (scsi_cmd(cdrom->id, (cdb_t *) cdb, 10, SUC_READ, 0, 0, &sus));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (pauseresume(cdrom, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (pauseresume(cdrom, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
u_char cdb[6];
|
|
||||||
struct scsi_user_cdb sus;
|
|
||||||
|
|
||||||
bzero(cdb, sizeof(cdb));
|
|
||||||
cdb[0] = 0x1b; /* stop */
|
|
||||||
cdb[1] = 1; /* immediate */
|
|
||||||
return (scsi_cmd(cdrom->id, (cdb_t *) cdb, 6, SUC_READ, 0, 0, &sus));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
u_char cdb[6];
|
|
||||||
struct scsi_user_cdb sus;
|
|
||||||
|
|
||||||
bzero(cdb, sizeof(cdb));
|
|
||||||
cdb[0] = 0x1b; /* stop */
|
|
||||||
cdb[1] = 1; /* immediate */
|
|
||||||
cdb[4] = 2; /* eject */
|
|
||||||
return (scsi_cmd(cdrom->id, (cdb_t *) cdb, 6, SUC_READ, 0, 0, &sus));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_BSDI */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,187 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_DC
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#include <dc/cdrom.h>
|
|
||||||
#include <dc/spu.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return "/cd";
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
return (drive);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TRACK_CDDA 0
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
CDROM_TOC toc;
|
|
||||||
int ret, i;
|
|
||||||
|
|
||||||
ret = cdrom_read_toc(&toc, 0);
|
|
||||||
if (ret != ERR_OK) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cdrom->numtracks = TOC_TRACK(toc.last) - TOC_TRACK(toc.first) + 1;
|
|
||||||
for (i = 0; i < cdrom->numtracks; i++) {
|
|
||||||
unsigned long entry = toc.entry[i];
|
|
||||||
cdrom->track[i].id = i + 1;
|
|
||||||
cdrom->track[i].type =
|
|
||||||
(TOC_CTRL(toc.entry[i]) ==
|
|
||||||
TRACK_CDDA) ? SDL_AUDIO_TRACK : SDL_DATA_TRACK;
|
|
||||||
cdrom->track[i].offset = TOC_LBA(entry) - 150;
|
|
||||||
cdrom->track[i].length =
|
|
||||||
TOC_LBA((i + 1 <
|
|
||||||
toc.last) ? toc.entry[i + 1] : toc.leadout_sector) -
|
|
||||||
TOC_LBA(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
int ret, dc_status, disc_type;
|
|
||||||
|
|
||||||
ret = cdrom_get_status(&dc_status, &disc_type);
|
|
||||||
if (ret != ERR_OK)
|
|
||||||
return CD_ERROR;
|
|
||||||
|
|
||||||
switch (dc_status) {
|
|
||||||
// case CD_STATUS_BUSY:
|
|
||||||
case CD_STATUS_PAUSED:
|
|
||||||
return CD_PAUSED;
|
|
||||||
case CD_STATUS_STANDBY:
|
|
||||||
return CD_STOPPED;
|
|
||||||
case CD_STATUS_PLAYING:
|
|
||||||
return CD_PLAYING;
|
|
||||||
// case CD_STATUS_SEEKING:
|
|
||||||
// case CD_STATUS_SCANING:
|
|
||||||
case CD_STATUS_OPEN:
|
|
||||||
case CD_STATUS_NO_DISC:
|
|
||||||
return CD_TRAYEMPTY;
|
|
||||||
default:
|
|
||||||
return CD_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
int ret =
|
|
||||||
cdrom_cdda_play(start - 150, start - 150 + length, 1, CDDA_SECTORS);
|
|
||||||
return ret == ERR_OK ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
int ret = cdrom_cdda_pause();
|
|
||||||
return ret == ERR_OK ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
int ret = cdrom_cdda_resume();
|
|
||||||
return ret == ERR_OK ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
int ret = cdrom_spin_down();
|
|
||||||
return ret == ERR_OK ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_DC */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#if defined(SDL_CDROM_DUMMY) || defined(SDL_CDROM_DISABLED)
|
|
||||||
|
|
||||||
/* Stub functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_DUMMY || SDL_CDROM_DISABLED */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,422 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_FREEBSD
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/cdio.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Some ioctl() errno values which occur when the tray is empty */
|
|
||||||
#define ERRNO_TRAYEMPTY(errno) \
|
|
||||||
((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int is_cd, cdfd;
|
|
||||||
struct ioc_read_subchannel info;
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, stbuf) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
|
||||||
is_cd = 0;
|
|
||||||
if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode)) {
|
|
||||||
cdfd = open(drive, (O_RDONLY | O_EXCL | O_NONBLOCK), 0);
|
|
||||||
if (cdfd >= 0) {
|
|
||||||
info.address_format = CD_MSF_FORMAT;
|
|
||||||
info.data_format = CD_CURRENT_POSITION;
|
|
||||||
info.data_len = 0;
|
|
||||||
info.data = NULL;
|
|
||||||
/* Under Linux, EIO occurs when a disk is not present.
|
|
||||||
This isn't 100% reliable, so we use the USE_MNTENT
|
|
||||||
code above instead.
|
|
||||||
*/
|
|
||||||
if ((ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) ||
|
|
||||||
ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
close(cdfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (is_cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Check to make sure it's not already in our list.
|
|
||||||
This can happen when we see a drive via symbolic link.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
if (stbuf->st_rdev == SDL_cdmode[i]) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Duplicate drive detected: %s == %s\n",
|
|
||||||
drive, SDL_cdlist[i]);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_cdmode[i] = stbuf->st_rdev;
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* checklist: /dev/cdrom,/dev/cd?c /dev/acd?c
|
|
||||||
/dev/matcd?c /dev/mcd?c /dev/scd?c */
|
|
||||||
static char *checklist[] = {
|
|
||||||
"cdrom", "?0 cd?", "?0 acd?", "?0 matcd?", "?0 mcd?", "?0 scd?", NULL
|
|
||||||
};
|
|
||||||
char *SDLcdrom;
|
|
||||||
int i, j, exists;
|
|
||||||
char drive[32];
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
if (CheckDrive(SDLcdrom, &stbuf) > 0) {
|
|
||||||
AddDrive(SDLcdrom, &stbuf);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives */
|
|
||||||
for (i = 0; checklist[i]; ++i) {
|
|
||||||
if (checklist[i][0] == '?') {
|
|
||||||
char *insert;
|
|
||||||
exists = 1;
|
|
||||||
for (j = checklist[i][1]; exists; ++j) {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc",
|
|
||||||
&checklist[i][3]);
|
|
||||||
insert = SDL_strchr(drive, '?');
|
|
||||||
if (insert != NULL) {
|
|
||||||
*insert = j;
|
|
||||||
}
|
|
||||||
switch (CheckDrive(drive, &stbuf)) {
|
|
||||||
/* Drive exists and is a CD-ROM */
|
|
||||||
case 1:
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
break;
|
|
||||||
/* Drive exists, but isn't a CD-ROM */
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
/* Drive doesn't exist */
|
|
||||||
case -1:
|
|
||||||
exists = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
checklist[i]);
|
|
||||||
if (CheckDrive(drive, &stbuf) > 0) {
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General ioctl() CD-ROM command function */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDioctl(int id, int command, void *arg)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = ioctl(id, command, arg);
|
|
||||||
if (retval < 0) {
|
|
||||||
SDL_SetError("ioctl() error: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
return (open(SDL_cdlist[drive], (O_RDONLY | O_EXCL | O_NONBLOCK), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct ioc_toc_header toc;
|
|
||||||
int i, okay;
|
|
||||||
struct ioc_read_toc_entry entry;
|
|
||||||
struct cd_toc_entry data;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0) {
|
|
||||||
cdrom->numtracks = toc.ending_track - toc.starting_track + 1;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
/* Read all the track TOC entries */
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].id = toc.starting_track + i;
|
|
||||||
}
|
|
||||||
entry.starting_track = cdrom->track[i].id;
|
|
||||||
entry.address_format = CD_MSF_FORMAT;
|
|
||||||
entry.data_len = sizeof(data);
|
|
||||||
entry.data = &data;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS, &entry) < 0) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].type = data.control;
|
|
||||||
cdrom->track[i].offset =
|
|
||||||
MSF_TO_FRAMES(data.addr.msf.minute,
|
|
||||||
data.addr.msf.second, data.addr.msf.frame);
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == (cdrom->numtracks + 1)) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
struct ioc_toc_header toc;
|
|
||||||
struct ioc_read_subchannel info;
|
|
||||||
struct cd_sub_channel_info data;
|
|
||||||
|
|
||||||
info.address_format = CD_MSF_FORMAT;
|
|
||||||
info.data_format = CD_CURRENT_POSITION;
|
|
||||||
info.track = 0;
|
|
||||||
info.data_len = sizeof(data);
|
|
||||||
info.data = &data;
|
|
||||||
if (ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0) {
|
|
||||||
if (ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
} else {
|
|
||||||
status = CD_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (data.header.audio_status) {
|
|
||||||
case CD_AS_AUDIO_INVALID:
|
|
||||||
case CD_AS_NO_STATUS:
|
|
||||||
/* Try to determine if there's a CD available */
|
|
||||||
if (ioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0)
|
|
||||||
status = CD_STOPPED;
|
|
||||||
else
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
break;
|
|
||||||
case CD_AS_PLAY_COMPLETED:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case CD_AS_PLAY_IN_PROGRESS:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case CD_AS_PLAY_PAUSED:
|
|
||||||
status = CD_PAUSED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
*position =
|
|
||||||
MSF_TO_FRAMES(data.what.position.absaddr.msf.minute,
|
|
||||||
data.what.position.absaddr.msf.second,
|
|
||||||
data.what.position.absaddr.msf.frame);
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
struct ioc_play_msf playtime;
|
|
||||||
|
|
||||||
FRAMES_TO_MSF(start,
|
|
||||||
&playtime.start_m, &playtime.start_s, &playtime.start_f);
|
|
||||||
FRAMES_TO_MSF(start + length,
|
|
||||||
&playtime.end_m, &playtime.end_s, &playtime.end_f);
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
|
|
||||||
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
|
|
||||||
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
|
|
||||||
#endif
|
|
||||||
ioctl(cdrom->id, CDIOCSTART, 0);
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_FREEBSD */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,585 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_LINUX
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#include <string.h> /* For strerror() */
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#ifdef __LINUX__
|
|
||||||
#ifdef HAVE_LINUX_VERSION_H
|
|
||||||
/* linux 2.6.9 workaround */
|
|
||||||
#include <linux/version.h>
|
|
||||||
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,9)
|
|
||||||
#include <asm/types.h>
|
|
||||||
#define __le64 __u64
|
|
||||||
#define __le32 __u32
|
|
||||||
#define __le16 __u16
|
|
||||||
#define __be64 __u64
|
|
||||||
#define __be32 __u32
|
|
||||||
#define __be16 __u16
|
|
||||||
#endif /* linux 2.6.9 workaround */
|
|
||||||
#endif /* HAVE_LINUX_VERSION_H */
|
|
||||||
#include <linux/cdrom.h>
|
|
||||||
#endif
|
|
||||||
#ifdef __SVR4
|
|
||||||
#include <sys/cdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define this to use the alternative getmntent() code */
|
|
||||||
#ifndef __SVR4
|
|
||||||
#define USE_MNTENT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_MNTENT
|
|
||||||
#if defined(__USLC__)
|
|
||||||
#include <sys/mntent.h>
|
|
||||||
#else
|
|
||||||
#include <mntent.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _PATH_MNTTAB
|
|
||||||
#ifdef MNTTAB
|
|
||||||
#define _PATH_MNTTAB MNTTAB
|
|
||||||
#else
|
|
||||||
#define _PATH_MNTTAB "/etc/fstab"
|
|
||||||
#endif
|
|
||||||
#endif /* !_PATH_MNTTAB */
|
|
||||||
|
|
||||||
#ifndef _PATH_MOUNTED
|
|
||||||
#define _PATH_MOUNTED "/etc/mtab"
|
|
||||||
#endif /* !_PATH_MOUNTED */
|
|
||||||
|
|
||||||
#ifndef MNTTYPE_CDROM
|
|
||||||
#define MNTTYPE_CDROM "iso9660"
|
|
||||||
#endif
|
|
||||||
#ifndef MNTTYPE_SUPER
|
|
||||||
#define MNTTYPE_SUPER "supermount"
|
|
||||||
#endif
|
|
||||||
#endif /* USE_MNTENT */
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Some ioctl() errno values which occur when the tray is empty */
|
|
||||||
#ifndef ENOMEDIUM
|
|
||||||
#define ENOMEDIUM ENOENT
|
|
||||||
#endif
|
|
||||||
#define ERRNO_TRAYEMPTY(errno) \
|
|
||||||
((errno == EIO) || (errno == ENOENT) || \
|
|
||||||
(errno == EINVAL) || (errno == ENOMEDIUM))
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive, char *mnttype, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int is_cd, cdfd;
|
|
||||||
struct cdrom_subchnl info;
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, stbuf) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
|
||||||
is_cd = 0;
|
|
||||||
if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode)) {
|
|
||||||
cdfd = open(drive, (O_RDONLY | O_NONBLOCK), 0);
|
|
||||||
if (cdfd >= 0) {
|
|
||||||
info.cdsc_format = CDROM_MSF;
|
|
||||||
/* Under Linux, EIO occurs when a disk is not present.
|
|
||||||
*/
|
|
||||||
if ((ioctl(cdfd, CDROMSUBCHNL, &info) == 0) ||
|
|
||||||
ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
close(cdfd);
|
|
||||||
}
|
|
||||||
#ifdef USE_MNTENT
|
|
||||||
/* Even if we can't read it, it might be mounted */
|
|
||||||
else if (mnttype && (SDL_strcmp(mnttype, MNTTYPE_CDROM) == 0)) {
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return (is_cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Check to make sure it's not already in our list.
|
|
||||||
This can happen when we see a drive via symbolic link.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
if (stbuf->st_rdev == SDL_cdmode[i]) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Duplicate drive detected: %s == %s\n",
|
|
||||||
drive, SDL_cdlist[i]);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_cdmode[i] = stbuf->st_rdev;
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_MNTENT
|
|
||||||
static void
|
|
||||||
CheckMounts(const char *mtab)
|
|
||||||
{
|
|
||||||
FILE *mntfp;
|
|
||||||
struct mntent *mntent;
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
mntfp = setmntent(mtab, "r");
|
|
||||||
if (mntfp != NULL) {
|
|
||||||
char *tmp;
|
|
||||||
char *mnt_type;
|
|
||||||
size_t mnt_type_len;
|
|
||||||
char *mnt_dev;
|
|
||||||
size_t mnt_dev_len;
|
|
||||||
|
|
||||||
while ((mntent = getmntent(mntfp)) != NULL) {
|
|
||||||
mnt_type_len = SDL_strlen(mntent->mnt_type) + 1;
|
|
||||||
mnt_type = SDL_stack_alloc(char, mnt_type_len);
|
|
||||||
if (mnt_type == NULL)
|
|
||||||
continue; /* maybe you'll get lucky next time. */
|
|
||||||
|
|
||||||
mnt_dev_len = SDL_strlen(mntent->mnt_fsname) + 1;
|
|
||||||
mnt_dev = SDL_stack_alloc(char, mnt_dev_len);
|
|
||||||
if (mnt_dev == NULL) {
|
|
||||||
SDL_stack_free(mnt_type);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_strlcpy(mnt_type, mntent->mnt_type, mnt_type_len);
|
|
||||||
SDL_strlcpy(mnt_dev, mntent->mnt_fsname, mnt_dev_len);
|
|
||||||
|
|
||||||
/* Handle "supermount" filesystem mounts */
|
|
||||||
if (SDL_strcmp(mnt_type, MNTTYPE_SUPER) == 0) {
|
|
||||||
tmp = SDL_strstr(mntent->mnt_opts, "fs=");
|
|
||||||
if (tmp) {
|
|
||||||
SDL_stack_free(mnt_type);
|
|
||||||
mnt_type = SDL_strdup(tmp + SDL_strlen("fs="));
|
|
||||||
if (mnt_type) {
|
|
||||||
tmp = SDL_strchr(mnt_type, ',');
|
|
||||||
if (tmp) {
|
|
||||||
*tmp = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp = SDL_strstr(mntent->mnt_opts, "dev=");
|
|
||||||
if (tmp) {
|
|
||||||
SDL_stack_free(mnt_dev);
|
|
||||||
mnt_dev = SDL_strdup(tmp + SDL_strlen("dev="));
|
|
||||||
if (mnt_dev) {
|
|
||||||
tmp = SDL_strchr(mnt_dev, ',');
|
|
||||||
if (tmp) {
|
|
||||||
*tmp = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (SDL_strcmp(mnt_type, MNTTYPE_CDROM) == 0) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Checking mount path from %s: %s mounted on %s of %s\n",
|
|
||||||
mtab, mnt_dev, mntent->mnt_dir, mnt_type);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(mnt_dev, mnt_type, &stbuf) > 0) {
|
|
||||||
AddDrive(mnt_dev, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SDL_stack_free(mnt_dev);
|
|
||||||
SDL_stack_free(mnt_type);
|
|
||||||
}
|
|
||||||
endmntent(mntfp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* USE_MNTENT */
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* checklist: /dev/cdrom, /dev/hd?, /dev/scd? /dev/sr? */
|
|
||||||
static char *checklist[] = {
|
|
||||||
"cdrom", "?a hd?", "?0 scd?", "?0 sr?", NULL
|
|
||||||
};
|
|
||||||
char *SDLcdrom;
|
|
||||||
int i, j, exists;
|
|
||||||
char drive[32];
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr,
|
|
||||||
"Checking CD-ROM drive from SDL_CDROM: %s\n",
|
|
||||||
SDLcdrom);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(SDLcdrom, NULL, &stbuf) > 0) {
|
|
||||||
AddDrive(SDLcdrom, &stbuf);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef USE_MNTENT
|
|
||||||
/* Check /dev/cdrom first :-) */
|
|
||||||
if (CheckDrive("/dev/cdrom", NULL, &stbuf) > 0) {
|
|
||||||
AddDrive("/dev/cdrom", &stbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now check the currently mounted CD drives */
|
|
||||||
CheckMounts(_PATH_MOUNTED);
|
|
||||||
|
|
||||||
/* Finally check possible mountable drives in /etc/fstab */
|
|
||||||
CheckMounts(_PATH_MNTTAB);
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
#endif /* USE_MNTENT */
|
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives.
|
|
||||||
Not always 100% reliable, so use the USE_MNTENT code above first.
|
|
||||||
*/
|
|
||||||
for (i = 0; checklist[i]; ++i) {
|
|
||||||
if (checklist[i][0] == '?') {
|
|
||||||
char *insert;
|
|
||||||
exists = 1;
|
|
||||||
for (j = checklist[i][1]; exists; ++j) {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
&checklist[i][3]);
|
|
||||||
insert = SDL_strchr(drive, '?');
|
|
||||||
if (insert != NULL) {
|
|
||||||
*insert = j;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Checking possible CD-ROM drive: %s\n",
|
|
||||||
drive);
|
|
||||||
#endif
|
|
||||||
switch (CheckDrive(drive, NULL, &stbuf)) {
|
|
||||||
/* Drive exists and is a CD-ROM */
|
|
||||||
case 1:
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
break;
|
|
||||||
/* Drive exists, but isn't a CD-ROM */
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
/* Drive doesn't exist */
|
|
||||||
case -1:
|
|
||||||
exists = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
checklist[i]);
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(drive, NULL, &stbuf) > 0) {
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General ioctl() CD-ROM command function */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDioctl(int id, int command, void *arg)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = ioctl(id, command, arg);
|
|
||||||
if (retval < 0) {
|
|
||||||
SDL_SetError("ioctl() error: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
return (open(SDL_cdlist[drive], (O_RDONLY | O_NONBLOCK), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct cdrom_tochdr toc;
|
|
||||||
int i, okay;
|
|
||||||
struct cdrom_tocentry entry;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc) == 0) {
|
|
||||||
cdrom->numtracks = toc.cdth_trk1 - toc.cdth_trk0 + 1;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
/* Read all the track TOC entries */
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
cdrom->track[i].id = CDROM_LEADOUT;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].id = toc.cdth_trk0 + i;
|
|
||||||
}
|
|
||||||
entry.cdte_track = cdrom->track[i].id;
|
|
||||||
entry.cdte_format = CDROM_MSF;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY, &entry) < 0) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (entry.cdte_ctrl & CDROM_DATA_TRACK) {
|
|
||||||
cdrom->track[i].type = SDL_DATA_TRACK;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].type = SDL_AUDIO_TRACK;
|
|
||||||
}
|
|
||||||
cdrom->track[i].offset =
|
|
||||||
MSF_TO_FRAMES(entry.cdte_addr.msf.minute,
|
|
||||||
entry.cdte_addr.msf.second,
|
|
||||||
entry.cdte_addr.msf.frame);
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == (cdrom->numtracks + 1)) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
struct cdrom_tochdr toc;
|
|
||||||
struct cdrom_subchnl info;
|
|
||||||
|
|
||||||
info.cdsc_format = CDROM_MSF;
|
|
||||||
if (ioctl(cdrom->id, CDROMSUBCHNL, &info) < 0) {
|
|
||||||
if (ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
} else {
|
|
||||||
status = CD_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (info.cdsc_audiostatus) {
|
|
||||||
case CDROM_AUDIO_INVALID:
|
|
||||||
case CDROM_AUDIO_NO_STATUS:
|
|
||||||
/* Try to determine if there's a CD available */
|
|
||||||
if (ioctl(cdrom->id, CDROMREADTOCHDR, &toc) == 0)
|
|
||||||
status = CD_STOPPED;
|
|
||||||
else
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_COMPLETED:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_PLAY:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_PAUSED:
|
|
||||||
/* Workaround buggy CD-ROM drive */
|
|
||||||
if (info.cdsc_trk == CDROM_LEADOUT) {
|
|
||||||
status = CD_STOPPED;
|
|
||||||
} else {
|
|
||||||
status = CD_PAUSED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
*position = MSF_TO_FRAMES(info.cdsc_absaddr.msf.minute,
|
|
||||||
info.cdsc_absaddr.msf.second,
|
|
||||||
info.cdsc_absaddr.msf.frame);
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
struct cdrom_msf playtime;
|
|
||||||
|
|
||||||
FRAMES_TO_MSF(start,
|
|
||||||
&playtime.cdmsf_min0, &playtime.cdmsf_sec0,
|
|
||||||
&playtime.cdmsf_frame0);
|
|
||||||
FRAMES_TO_MSF(start + length, &playtime.cdmsf_min1, &playtime.cdmsf_sec1,
|
|
||||||
&playtime.cdmsf_frame1);
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
|
|
||||||
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
|
|
||||||
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
|
|
||||||
#endif
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_LINUX */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,397 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
|
|
||||||
This file based on Apple sample code. We haven't changed the file name,
|
|
||||||
so if you want to see the original search for it on apple.com/developer
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
AudioFilePlayer.cpp
|
|
||||||
*/
|
|
||||||
#include "AudioFilePlayer.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
void ThrowResult (OSStatus result, const char* str)
|
|
||||||
{
|
|
||||||
SDL_SetError ("Error: %s %d", str, result);
|
|
||||||
throw result;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
static void
|
|
||||||
PrintStreamDesc(AudioStreamBasicDescription * inDesc)
|
|
||||||
{
|
|
||||||
if (!inDesc) {
|
|
||||||
printf("Can't print a NULL desc!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("- - - - - - - - - - - - - - - - - - - -\n");
|
|
||||||
printf(" Sample Rate:%f\n", inDesc->mSampleRate);
|
|
||||||
printf(" Format ID:%s\n", (char *) &inDesc->mFormatID);
|
|
||||||
printf(" Format Flags:%lX\n", inDesc->mFormatFlags);
|
|
||||||
printf(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
|
|
||||||
printf(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
|
|
||||||
printf(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
|
|
||||||
printf(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
|
|
||||||
printf(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
|
|
||||||
printf("- - - - - - - - - - - - - - - - - - - -\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
AudioFilePlayer_SetDestination(AudioFilePlayer * afp, AudioUnit * inDestUnit)
|
|
||||||
{
|
|
||||||
/*if (afp->mConnected) throw static_cast<OSStatus>(-1); *//* can't set dest if already engaged */
|
|
||||||
if (afp->mConnected)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
SDL_memcpy(&afp->mPlayUnit, inDestUnit, sizeof(afp->mPlayUnit));
|
|
||||||
|
|
||||||
OSStatus result = noErr;
|
|
||||||
|
|
||||||
|
|
||||||
/* we can "down" cast a component instance to a component */
|
|
||||||
ComponentDescription desc;
|
|
||||||
result = GetComponentInfo((Component) * inDestUnit, &desc, 0, 0, 0);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("GetComponentInfo") */
|
|
||||||
|
|
||||||
/* we're going to use this to know which convert routine to call
|
|
||||||
a v1 audio unit will have a type of 'aunt'
|
|
||||||
a v2 audio unit will have one of several different types. */
|
|
||||||
if (desc.componentType != kAudioUnitComponentType) {
|
|
||||||
result = badComponentInstance;
|
|
||||||
/*THROW_RESULT("BAD COMPONENT") */
|
|
||||||
if (result)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the input format of the audio unit. */
|
|
||||||
result = AudioUnitSetProperty(*inDestUnit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&afp->mFileDescription,
|
|
||||||
sizeof(afp->mFileDescription));
|
|
||||||
/*THROW_RESULT("AudioUnitSetProperty") */
|
|
||||||
if (result)
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFilePlayer_SetNotifier(AudioFilePlayer * afp,
|
|
||||||
AudioFilePlayNotifier inNotifier, void *inRefCon)
|
|
||||||
{
|
|
||||||
afp->mNotifier = inNotifier;
|
|
||||||
afp->mRefCon = inRefCon;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
AudioFilePlayer_IsConnected(AudioFilePlayer * afp)
|
|
||||||
{
|
|
||||||
return afp->mConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AudioUnit
|
|
||||||
AudioFilePlayer_GetDestUnit(AudioFilePlayer * afp)
|
|
||||||
{
|
|
||||||
return afp->mPlayUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFilePlayer_Print(AudioFilePlayer * afp)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
printf("Is Connected:%s\n", (IsConnected()? "true" : "false"));
|
|
||||||
printf("- - - - - - - - - - - - - - \n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFilePlayer_SetStartFrame(AudioFilePlayer * afp, int frame)
|
|
||||||
{
|
|
||||||
SInt64 position = frame * 2352;
|
|
||||||
|
|
||||||
afp->mStartFrame = frame;
|
|
||||||
afp->mAudioFileManager->SetPosition(afp->mAudioFileManager, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
AudioFilePlayer_GetCurrentFrame(AudioFilePlayer * afp)
|
|
||||||
{
|
|
||||||
return afp->mStartFrame +
|
|
||||||
(afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) /
|
|
||||||
2352);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFilePlayer_SetStopFrame(AudioFilePlayer * afp, int frame)
|
|
||||||
{
|
|
||||||
SInt64 position = frame * 2352;
|
|
||||||
|
|
||||||
afp->mAudioFileManager->SetEndOfFile(afp->mAudioFileManager, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
delete_AudioFilePlayer(AudioFilePlayer * afp)
|
|
||||||
{
|
|
||||||
if (afp != NULL) {
|
|
||||||
afp->Disconnect(afp);
|
|
||||||
|
|
||||||
if (afp->mAudioFileManager) {
|
|
||||||
delete_AudioFileManager(afp->mAudioFileManager);
|
|
||||||
afp->mAudioFileManager = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (afp->mForkRefNum) {
|
|
||||||
FSCloseFork(afp->mForkRefNum);
|
|
||||||
afp->mForkRefNum = 0;
|
|
||||||
}
|
|
||||||
SDL_free(afp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
AudioFilePlayer_Connect(AudioFilePlayer * afp)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
printf("Connect:%x, engaged=%d\n", (int) afp->mPlayUnit,
|
|
||||||
(afp->mConnected ? 1 : 0));
|
|
||||||
#endif
|
|
||||||
if (!afp->mConnected) {
|
|
||||||
if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* set the render callback for the file data to be supplied to the sound converter AU */
|
|
||||||
afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc;
|
|
||||||
afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager;
|
|
||||||
|
|
||||||
OSStatus result = AudioUnitSetProperty(afp->mPlayUnit,
|
|
||||||
kAudioUnitProperty_SetInputCallback,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&afp->mInputCallback,
|
|
||||||
sizeof(afp->mInputCallback));
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioUnitSetProperty") */
|
|
||||||
afp->mConnected = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* warning noted, now please go away ;-) */
|
|
||||||
/* #warning This should redirect the calling of notification code to some other thread */
|
|
||||||
static void
|
|
||||||
AudioFilePlayer_DoNotification(AudioFilePlayer * afp, OSStatus inStatus)
|
|
||||||
{
|
|
||||||
if (afp->mNotifier) {
|
|
||||||
(*afp->mNotifier) (afp->mRefCon, inStatus);
|
|
||||||
} else {
|
|
||||||
SDL_SetError("Notification posted with no notifier in place");
|
|
||||||
|
|
||||||
if (inStatus == kAudioFilePlay_FileIsFinished)
|
|
||||||
afp->Disconnect(afp);
|
|
||||||
else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun)
|
|
||||||
afp->Disconnect(afp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFilePlayer_Disconnect(AudioFilePlayer * afp)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
printf("Disconnect:%x,%ld, engaged=%d\n", (int) afp->mPlayUnit, 0,
|
|
||||||
(afp->mConnected ? 1 : 0));
|
|
||||||
#endif
|
|
||||||
if (afp->mConnected) {
|
|
||||||
afp->mConnected = 0;
|
|
||||||
|
|
||||||
afp->mInputCallback.inputProc = 0;
|
|
||||||
afp->mInputCallback.inputProcRefCon = 0;
|
|
||||||
OSStatus result = AudioUnitSetProperty(afp->mPlayUnit,
|
|
||||||
kAudioUnitProperty_SetInputCallback,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&afp->mInputCallback,
|
|
||||||
sizeof(afp->mInputCallback));
|
|
||||||
if (result)
|
|
||||||
SDL_SetError("AudioUnitSetProperty:RemoveInputCallback:%ld",
|
|
||||||
result);
|
|
||||||
|
|
||||||
afp->mAudioFileManager->Disconnect(afp->mAudioFileManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
UInt32 offset;
|
|
||||||
UInt32 blockSize;
|
|
||||||
} SSNDData;
|
|
||||||
|
|
||||||
static int
|
|
||||||
AudioFilePlayer_OpenFile(AudioFilePlayer * afp, const FSRef * inRef,
|
|
||||||
SInt64 * outFileDataSize)
|
|
||||||
{
|
|
||||||
ContainerChunk chunkHeader;
|
|
||||||
ChunkHeader chunk;
|
|
||||||
SSNDData ssndData;
|
|
||||||
|
|
||||||
OSErr result;
|
|
||||||
HFSUniStr255 dfName;
|
|
||||||
ByteCount actual;
|
|
||||||
SInt64 offset;
|
|
||||||
|
|
||||||
/* Open the data fork of the input file */
|
|
||||||
result = FSGetDataForkName(&dfName);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName") */
|
|
||||||
|
|
||||||
result =
|
|
||||||
FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm,
|
|
||||||
&afp->mForkRefNum);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork") */
|
|
||||||
|
|
||||||
/* Read the file header, and check if it's indeed an AIFC file */
|
|
||||||
result =
|
|
||||||
FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(chunkHeader),
|
|
||||||
&chunkHeader, &actual);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") */
|
|
||||||
|
|
||||||
if (chunkHeader.ckID != 'FORM') {
|
|
||||||
result = -1;
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'"); */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chunkHeader.formType != 'AIFC') {
|
|
||||||
result = -1;
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'"); */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search for the SSND chunk. We ignore all compression etc. information
|
|
||||||
in other chunks. Of course that is kind of evil, but for now we are lazy
|
|
||||||
and rely on the cdfs to always give us the same fixed format.
|
|
||||||
TODO: Parse the COMM chunk we currently skip to fill in mFileDescription.
|
|
||||||
*/
|
|
||||||
offset = 0;
|
|
||||||
do {
|
|
||||||
result =
|
|
||||||
FSReadFork(afp->mForkRefNum, fsFromMark, offset,
|
|
||||||
sizeof(chunk), &chunk, &actual);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") */
|
|
||||||
|
|
||||||
/* Skip the chunk data */
|
|
||||||
offset = chunk.ckSize;
|
|
||||||
} while (chunk.ckID != 'SSND');
|
|
||||||
|
|
||||||
/* Read the header of the SSND chunk. After this, we are positioned right
|
|
||||||
at the start of the audio data. */
|
|
||||||
result =
|
|
||||||
FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(ssndData),
|
|
||||||
&ssndData, &actual);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork") */
|
|
||||||
|
|
||||||
result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition") */
|
|
||||||
|
|
||||||
/* Data size */
|
|
||||||
*outFileDataSize = chunk.ckSize - ssndData.offset - 8;
|
|
||||||
|
|
||||||
/* File format */
|
|
||||||
afp->mFileDescription.mSampleRate = 44100;
|
|
||||||
afp->mFileDescription.mFormatID = kAudioFormatLinearPCM;
|
|
||||||
afp->mFileDescription.mFormatFlags =
|
|
||||||
kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
|
|
||||||
afp->mFileDescription.mBytesPerPacket = 4;
|
|
||||||
afp->mFileDescription.mFramesPerPacket = 1;
|
|
||||||
afp->mFileDescription.mBytesPerFrame = 4;
|
|
||||||
afp->mFileDescription.mChannelsPerFrame = 2;
|
|
||||||
afp->mFileDescription.mBitsPerChannel = 16;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioFilePlayer *
|
|
||||||
new_AudioFilePlayer(const FSRef * inFileRef)
|
|
||||||
{
|
|
||||||
SInt64 fileDataSize = 0;
|
|
||||||
|
|
||||||
AudioFilePlayer *afp =
|
|
||||||
(AudioFilePlayer *) SDL_malloc(sizeof(AudioFilePlayer));
|
|
||||||
if (afp == NULL)
|
|
||||||
return NULL;
|
|
||||||
SDL_memset(afp, '\0', sizeof(*afp));
|
|
||||||
|
|
||||||
#define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(SetDestination);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(SetNotifier);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(SetStartFrame);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(GetCurrentFrame);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(SetStopFrame);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(Connect);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(Disconnect);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(DoNotification);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(IsConnected);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(GetDestUnit);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(Print);
|
|
||||||
SET_AUDIOFILEPLAYER_METHOD(OpenFile);
|
|
||||||
#undef SET_AUDIOFILEPLAYER_METHOD
|
|
||||||
|
|
||||||
if (!afp->OpenFile(afp, inFileRef, &fileDataSize)) {
|
|
||||||
SDL_free(afp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we want about 4 seconds worth of data for the buffer */
|
|
||||||
int bytesPerSecond =
|
|
||||||
(UInt32) (4 * afp->mFileDescription.mSampleRate *
|
|
||||||
afp->mFileDescription.mBytesPerFrame);
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
printf("File format:\n");
|
|
||||||
PrintStreamDesc(&afp->mFileDescription);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum,
|
|
||||||
fileDataSize,
|
|
||||||
bytesPerSecond);
|
|
||||||
if (afp->mAudioFileManager == NULL) {
|
|
||||||
delete_AudioFilePlayer(afp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return afp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,178 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
|
|
||||||
This file based on Apple sample code. We haven't changed the file name,
|
|
||||||
so if you want to see the original search for it on apple.com/developer
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
AudioFilePlayer.h
|
|
||||||
*/
|
|
||||||
#ifndef __AudioFilePlayer_H__
|
|
||||||
#define __AudioFilePlayer_H__
|
|
||||||
|
|
||||||
#include <CoreServices/CoreServices.h>
|
|
||||||
|
|
||||||
#include <AudioUnit/AudioUnit.h>
|
|
||||||
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
|
|
||||||
#include <AudioUnit/AUNTComponent.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "SDL_error.h"
|
|
||||||
|
|
||||||
const char *AudioFilePlayerErrorStr(OSStatus error);
|
|
||||||
|
|
||||||
/*
|
|
||||||
void ThrowResult (OSStatus result, const char *str);
|
|
||||||
|
|
||||||
#define THROW_RESULT(str) \
|
|
||||||
if (result) { \
|
|
||||||
ThrowResult (result, str); \
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef void (*AudioFilePlayNotifier) (void *inRefCon, OSStatus inStatus);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
kAudioFilePlayErr_FilePlayUnderrun = -10000,
|
|
||||||
kAudioFilePlay_FileIsFinished = -10001,
|
|
||||||
kAudioFilePlay_PlayerIsUninitialized = -10002
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct S_AudioFileManager;
|
|
||||||
|
|
||||||
#pragma mark __________ AudioFilePlayer
|
|
||||||
typedef struct S_AudioFilePlayer
|
|
||||||
{
|
|
||||||
/*public:*/
|
|
||||||
int (*SetDestination) (struct S_AudioFilePlayer * afp,
|
|
||||||
AudioUnit * inDestUnit);
|
|
||||||
void (*SetNotifier) (struct S_AudioFilePlayer * afp,
|
|
||||||
AudioFilePlayNotifier inNotifier, void *inRefCon);
|
|
||||||
void (*SetStartFrame) (struct S_AudioFilePlayer * afp, int frame); /* seek in the file */
|
|
||||||
int (*GetCurrentFrame) (struct S_AudioFilePlayer * afp); /* get the current frame position */
|
|
||||||
void (*SetStopFrame) (struct S_AudioFilePlayer * afp, int frame); /* set limit in the file */
|
|
||||||
int (*Connect) (struct S_AudioFilePlayer * afp);
|
|
||||||
void (*Disconnect) (struct S_AudioFilePlayer * afp);
|
|
||||||
void (*DoNotification) (struct S_AudioFilePlayer * afp, OSStatus inError);
|
|
||||||
int (*IsConnected) (struct S_AudioFilePlayer * afp);
|
|
||||||
AudioUnit(*GetDestUnit) (struct S_AudioFilePlayer * afp);
|
|
||||||
void (*Print) (struct S_AudioFilePlayer * afp);
|
|
||||||
|
|
||||||
/*private:*/
|
|
||||||
AudioUnit mPlayUnit;
|
|
||||||
SInt16 mForkRefNum;
|
|
||||||
|
|
||||||
AudioUnitInputCallback mInputCallback;
|
|
||||||
|
|
||||||
AudioStreamBasicDescription mFileDescription;
|
|
||||||
|
|
||||||
int mConnected;
|
|
||||||
|
|
||||||
struct S_AudioFileManager *mAudioFileManager;
|
|
||||||
|
|
||||||
AudioFilePlayNotifier mNotifier;
|
|
||||||
void *mRefCon;
|
|
||||||
|
|
||||||
int mStartFrame;
|
|
||||||
|
|
||||||
#pragma mark __________ Private_Methods
|
|
||||||
|
|
||||||
int (*OpenFile) (struct S_AudioFilePlayer * afp, const FSRef * inRef,
|
|
||||||
SInt64 * outFileSize);
|
|
||||||
} AudioFilePlayer;
|
|
||||||
|
|
||||||
|
|
||||||
AudioFilePlayer *new_AudioFilePlayer(const FSRef * inFileRef);
|
|
||||||
void delete_AudioFilePlayer(AudioFilePlayer * afp);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark __________ AudioFileManager
|
|
||||||
typedef struct S_AudioFileManager
|
|
||||||
{
|
|
||||||
/*public:*/
|
|
||||||
/* this method should NOT be called by an object of this class
|
|
||||||
as it is called by the parent's Disconnect() method */
|
|
||||||
void (*Disconnect) (struct S_AudioFileManager * afm);
|
|
||||||
int (*DoConnect) (struct S_AudioFileManager * afm);
|
|
||||||
OSStatus(*Read) (struct S_AudioFileManager * afm, char *buffer,
|
|
||||||
UInt32 * len);
|
|
||||||
const char *(*GetFileBuffer) (struct S_AudioFileManager * afm);
|
|
||||||
const AudioFilePlayer *(*GetParent) (struct S_AudioFileManager * afm);
|
|
||||||
void (*SetPosition) (struct S_AudioFileManager * afm, SInt64 pos); /* seek/rewind in the file */
|
|
||||||
int (*GetByteCounter) (struct S_AudioFileManager * afm); /* return actual bytes streamed to audio hardware */
|
|
||||||
void (*SetEndOfFile) (struct S_AudioFileManager * afm, SInt64 pos); /* set the "EOF" (will behave just like it reached eof) */
|
|
||||||
|
|
||||||
/*protected:*/
|
|
||||||
AudioFilePlayer *mParent;
|
|
||||||
SInt16 mForkRefNum;
|
|
||||||
SInt64 mAudioDataOffset;
|
|
||||||
|
|
||||||
char *mFileBuffer;
|
|
||||||
|
|
||||||
int mByteCounter;
|
|
||||||
|
|
||||||
int mReadFromFirstBuffer;
|
|
||||||
int mLockUnsuccessful;
|
|
||||||
int mIsEngaged;
|
|
||||||
|
|
||||||
int mNumTimesAskedSinceFinished;
|
|
||||||
|
|
||||||
|
|
||||||
void *mTmpBuffer;
|
|
||||||
UInt32 mBufferSize;
|
|
||||||
UInt32 mBufferOffset;
|
|
||||||
/*public:*/
|
|
||||||
UInt32 mChunkSize;
|
|
||||||
SInt64 mFileLength;
|
|
||||||
SInt64 mReadFilePosition;
|
|
||||||
int mWriteToFirstBuffer;
|
|
||||||
int mFinishedReadingData;
|
|
||||||
|
|
||||||
/*protected:*/
|
|
||||||
OSStatus(*Render) (struct S_AudioFileManager * afm,
|
|
||||||
AudioBuffer * ioData);
|
|
||||||
OSStatus(*GetFileData) (struct S_AudioFileManager * afm,
|
|
||||||
void **inOutData, UInt32 * inOutDataSize);
|
|
||||||
void (*AfterRender) (struct S_AudioFileManager * afm);
|
|
||||||
|
|
||||||
/*public:*/
|
|
||||||
/*static */
|
|
||||||
OSStatus(*FileInputProc) (void *inRefCon,
|
|
||||||
AudioUnitRenderActionFlags inActionFlags,
|
|
||||||
const AudioTimeStamp * inTimeStamp,
|
|
||||||
UInt32 inBusNumber, AudioBuffer * ioData);
|
|
||||||
} AudioFileManager;
|
|
||||||
|
|
||||||
|
|
||||||
AudioFileManager *new_AudioFileManager(AudioFilePlayer * inParent,
|
|
||||||
SInt16 inForkRefNum,
|
|
||||||
SInt64 inFileLength,
|
|
||||||
UInt32 inChunkSize);
|
|
||||||
|
|
||||||
void delete_AudioFileManager(AudioFileManager * afm);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,657 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
|
|
||||||
This file based on Apple sample code. We haven't changed the file name,
|
|
||||||
so if you want to see the original search for it on apple.com/developer
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
AudioFileManager.cpp
|
|
||||||
*/
|
|
||||||
#include "AudioFilePlayer.h"
|
|
||||||
#include <mach/mach.h> /* used for setting policy of thread */
|
|
||||||
#include "SDLOSXCAGuard.h"
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
/*#include <list>*/
|
|
||||||
|
|
||||||
/*typedef void *FileData;*/
|
|
||||||
typedef struct S_FileData
|
|
||||||
{
|
|
||||||
AudioFileManager *obj;
|
|
||||||
struct S_FileData *next;
|
|
||||||
} FileData;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct S_FileReaderThread
|
|
||||||
{
|
|
||||||
/*public:*/
|
|
||||||
SDLOSXCAGuard *(*GetGuard) (struct S_FileReaderThread * frt);
|
|
||||||
void (*AddReader) (struct S_FileReaderThread * frt);
|
|
||||||
void (*RemoveReader) (struct S_FileReaderThread * frt,
|
|
||||||
AudioFileManager * inItem);
|
|
||||||
int (*TryNextRead) (struct S_FileReaderThread * frt,
|
|
||||||
AudioFileManager * inItem);
|
|
||||||
|
|
||||||
int mThreadShouldDie;
|
|
||||||
|
|
||||||
/*private:*/
|
|
||||||
/*typedef std::list<AudioFileManager*> FileData; */
|
|
||||||
|
|
||||||
SDLOSXCAGuard *mGuard;
|
|
||||||
UInt32 mThreadPriority;
|
|
||||||
|
|
||||||
int mNumReaders;
|
|
||||||
FileData *mFileData;
|
|
||||||
|
|
||||||
|
|
||||||
void (*ReadNextChunk) (struct S_FileReaderThread * frt);
|
|
||||||
int (*StartFixedPriorityThread) (struct S_FileReaderThread * frt);
|
|
||||||
/*static */
|
|
||||||
UInt32(*GetThreadBasePriority) (pthread_t inThread);
|
|
||||||
/*static */
|
|
||||||
void *(*DiskReaderEntry) (void *inRefCon);
|
|
||||||
} FileReaderThread;
|
|
||||||
|
|
||||||
|
|
||||||
static SDLOSXCAGuard *
|
|
||||||
FileReaderThread_GetGuard(FileReaderThread * frt)
|
|
||||||
{
|
|
||||||
return frt->mGuard;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns 1 if succeeded */
|
|
||||||
static int
|
|
||||||
FileReaderThread_TryNextRead(FileReaderThread * frt,
|
|
||||||
AudioFileManager * inItem)
|
|
||||||
{
|
|
||||||
int didLock = 0;
|
|
||||||
int succeeded = 0;
|
|
||||||
if (frt->mGuard->Try(frt->mGuard, &didLock)) {
|
|
||||||
/*frt->mFileData.push_back (inItem); */
|
|
||||||
/* !!! FIXME: this could be faster with a "tail" member. --ryan. */
|
|
||||||
FileData *i = frt->mFileData;
|
|
||||||
FileData *prev = NULL;
|
|
||||||
|
|
||||||
FileData *newfd = (FileData *) SDL_malloc(sizeof(FileData));
|
|
||||||
newfd->obj = inItem;
|
|
||||||
newfd->next = NULL;
|
|
||||||
|
|
||||||
while (i != NULL) {
|
|
||||||
prev = i;
|
|
||||||
i = i->next;
|
|
||||||
}
|
|
||||||
if (prev == NULL)
|
|
||||||
frt->mFileData = newfd;
|
|
||||||
else
|
|
||||||
prev->next = newfd;
|
|
||||||
|
|
||||||
frt->mGuard->Notify(frt->mGuard);
|
|
||||||
succeeded = 1;
|
|
||||||
|
|
||||||
if (didLock)
|
|
||||||
frt->mGuard->Unlock(frt->mGuard);
|
|
||||||
}
|
|
||||||
|
|
||||||
return succeeded;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
FileReaderThread_AddReader(FileReaderThread * frt)
|
|
||||||
{
|
|
||||||
if (frt->mNumReaders == 0) {
|
|
||||||
frt->mThreadShouldDie = 0;
|
|
||||||
frt->StartFixedPriorityThread(frt);
|
|
||||||
}
|
|
||||||
frt->mNumReaders++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
FileReaderThread_RemoveReader(FileReaderThread * frt,
|
|
||||||
AudioFileManager * inItem)
|
|
||||||
{
|
|
||||||
if (frt->mNumReaders > 0) {
|
|
||||||
int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
|
|
||||||
|
|
||||||
/*frt->mFileData.remove (inItem); */
|
|
||||||
FileData *i = frt->mFileData;
|
|
||||||
FileData *prev = NULL;
|
|
||||||
while (i != NULL) {
|
|
||||||
FileData *next = i->next;
|
|
||||||
if (i->obj != inItem)
|
|
||||||
prev = i;
|
|
||||||
else {
|
|
||||||
if (prev == NULL)
|
|
||||||
frt->mFileData = next;
|
|
||||||
else
|
|
||||||
prev->next = next;
|
|
||||||
SDL_free(i);
|
|
||||||
}
|
|
||||||
i = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (--frt->mNumReaders == 0) {
|
|
||||||
frt->mThreadShouldDie = 1;
|
|
||||||
frt->mGuard->Notify(frt->mGuard); /* wake up thread so it will quit */
|
|
||||||
frt->mGuard->Wait(frt->mGuard); /* wait for thread to die */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bNeedsRelease)
|
|
||||||
frt->mGuard->Unlock(frt->mGuard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
FileReaderThread_StartFixedPriorityThread(FileReaderThread * frt)
|
|
||||||
{
|
|
||||||
pthread_attr_t theThreadAttrs;
|
|
||||||
pthread_t pThread;
|
|
||||||
|
|
||||||
OSStatus result = pthread_attr_init(&theThreadAttrs);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("pthread_attr_init - Thread attributes could not be created.") */
|
|
||||||
|
|
||||||
result =
|
|
||||||
pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.") */
|
|
||||||
|
|
||||||
result =
|
|
||||||
pthread_create(&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("pthread_create - Create and start the thread.") */
|
|
||||||
|
|
||||||
pthread_attr_destroy(&theThreadAttrs);
|
|
||||||
|
|
||||||
/* we've now created the thread and started it
|
|
||||||
we'll now set the priority of the thread to the nominated priority
|
|
||||||
and we'll also make the thread fixed */
|
|
||||||
thread_extended_policy_data_t theFixedPolicy;
|
|
||||||
thread_precedence_policy_data_t thePrecedencePolicy;
|
|
||||||
SInt32 relativePriority;
|
|
||||||
|
|
||||||
/* make thread fixed */
|
|
||||||
theFixedPolicy.timeshare = 0; /* set to 1 for a non-fixed thread */
|
|
||||||
result =
|
|
||||||
thread_policy_set(pthread_mach_thread_np(pThread),
|
|
||||||
THREAD_EXTENDED_POLICY,
|
|
||||||
(thread_policy_t) & theFixedPolicy,
|
|
||||||
THREAD_EXTENDED_POLICY_COUNT);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.") */
|
|
||||||
/* set priority */
|
|
||||||
/* precedency policy's "importance" value is relative to spawning thread's priority */
|
|
||||||
relativePriority =
|
|
||||||
frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self());
|
|
||||||
|
|
||||||
thePrecedencePolicy.importance = relativePriority;
|
|
||||||
result =
|
|
||||||
thread_policy_set(pthread_mach_thread_np(pThread),
|
|
||||||
THREAD_PRECEDENCE_POLICY,
|
|
||||||
(thread_policy_t) & thePrecedencePolicy,
|
|
||||||
THREAD_PRECEDENCE_POLICY_COUNT);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("thread_policy - Couldn't set thread priority.") */
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UInt32
|
|
||||||
FileReaderThread_GetThreadBasePriority(pthread_t inThread)
|
|
||||||
{
|
|
||||||
thread_basic_info_data_t threadInfo;
|
|
||||||
policy_info_data_t thePolicyInfo;
|
|
||||||
unsigned int count;
|
|
||||||
|
|
||||||
/* get basic info */
|
|
||||||
count = THREAD_BASIC_INFO_COUNT;
|
|
||||||
thread_info(pthread_mach_thread_np(inThread), THREAD_BASIC_INFO,
|
|
||||||
(integer_t *) & threadInfo, &count);
|
|
||||||
|
|
||||||
switch (threadInfo.policy) {
|
|
||||||
case POLICY_TIMESHARE:
|
|
||||||
count = POLICY_TIMESHARE_INFO_COUNT;
|
|
||||||
thread_info(pthread_mach_thread_np(inThread),
|
|
||||||
THREAD_SCHED_TIMESHARE_INFO,
|
|
||||||
(integer_t *) & (thePolicyInfo.ts), &count);
|
|
||||||
return thePolicyInfo.ts.base_priority;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case POLICY_FIFO:
|
|
||||||
count = POLICY_FIFO_INFO_COUNT;
|
|
||||||
thread_info(pthread_mach_thread_np(inThread),
|
|
||||||
THREAD_SCHED_FIFO_INFO,
|
|
||||||
(integer_t *) & (thePolicyInfo.fifo), &count);
|
|
||||||
if (thePolicyInfo.fifo.depressed) {
|
|
||||||
return thePolicyInfo.fifo.depress_priority;
|
|
||||||
} else {
|
|
||||||
return thePolicyInfo.fifo.base_priority;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case POLICY_RR:
|
|
||||||
count = POLICY_RR_INFO_COUNT;
|
|
||||||
thread_info(pthread_mach_thread_np(inThread),
|
|
||||||
THREAD_SCHED_RR_INFO,
|
|
||||||
(integer_t *) & (thePolicyInfo.rr), &count);
|
|
||||||
if (thePolicyInfo.rr.depressed) {
|
|
||||||
return thePolicyInfo.rr.depress_priority;
|
|
||||||
} else {
|
|
||||||
return thePolicyInfo.rr.base_priority;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
FileReaderThread_DiskReaderEntry(void *inRefCon)
|
|
||||||
{
|
|
||||||
FileReaderThread *frt = (FileReaderThread *) inRefCon;
|
|
||||||
frt->ReadNextChunk(frt);
|
|
||||||
#if DEBUG
|
|
||||||
printf("finished with reading file\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
FileReaderThread_ReadNextChunk(FileReaderThread * frt)
|
|
||||||
{
|
|
||||||
OSStatus result;
|
|
||||||
UInt32 dataChunkSize;
|
|
||||||
AudioFileManager *theItem = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
{ /* this is a scoped based lock */
|
|
||||||
int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
|
|
||||||
|
|
||||||
if (frt->mThreadShouldDie) {
|
|
||||||
frt->mGuard->Notify(frt->mGuard);
|
|
||||||
if (bNeedsRelease)
|
|
||||||
frt->mGuard->Unlock(frt->mGuard);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*if (frt->mFileData.empty()) */
|
|
||||||
if (frt->mFileData == NULL) {
|
|
||||||
frt->mGuard->Wait(frt->mGuard);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* kill thread */
|
|
||||||
if (frt->mThreadShouldDie) {
|
|
||||||
|
|
||||||
frt->mGuard->Notify(frt->mGuard);
|
|
||||||
if (bNeedsRelease)
|
|
||||||
frt->mGuard->Unlock(frt->mGuard);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*theItem = frt->mFileData.front(); */
|
|
||||||
/*frt->mFileData.pop_front(); */
|
|
||||||
theItem = NULL;
|
|
||||||
if (frt->mFileData != NULL) {
|
|
||||||
FileData *next = frt->mFileData->next;
|
|
||||||
theItem = frt->mFileData->obj;
|
|
||||||
SDL_free(frt->mFileData);
|
|
||||||
frt->mFileData = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bNeedsRelease)
|
|
||||||
frt->mGuard->Unlock(frt->mGuard);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((theItem->mFileLength - theItem->mReadFilePosition) <
|
|
||||||
theItem->mChunkSize)
|
|
||||||
dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
|
|
||||||
else
|
|
||||||
dataChunkSize = theItem->mChunkSize;
|
|
||||||
|
|
||||||
/* this is the exit condition for the thread */
|
|
||||||
if (dataChunkSize <= 0) {
|
|
||||||
theItem->mFinishedReadingData = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* construct pointer */
|
|
||||||
char *writePtr = (char *) (theItem->GetFileBuffer(theItem) +
|
|
||||||
(theItem->mWriteToFirstBuffer ? 0 :
|
|
||||||
theItem->mChunkSize));
|
|
||||||
|
|
||||||
/* read data */
|
|
||||||
result = theItem->Read(theItem, writePtr, &dataChunkSize);
|
|
||||||
if (result != noErr && result != eofErr) {
|
|
||||||
AudioFilePlayer *afp =
|
|
||||||
(AudioFilePlayer *) theItem->GetParent(theItem);
|
|
||||||
afp->DoNotification(afp, result);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataChunkSize != theItem->mChunkSize) {
|
|
||||||
writePtr += dataChunkSize;
|
|
||||||
|
|
||||||
/* can't exit yet.. we still have to pass the partial buffer back */
|
|
||||||
SDL_memset(writePtr, 0, (theItem->mChunkSize - dataChunkSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; /* switch buffers */
|
|
||||||
|
|
||||||
if (result == eofErr)
|
|
||||||
theItem->mReadFilePosition = theItem->mFileLength;
|
|
||||||
else
|
|
||||||
theItem->mReadFilePosition += dataChunkSize; /* increment count */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
delete_FileReaderThread(FileReaderThread * frt)
|
|
||||||
{
|
|
||||||
if (frt != NULL) {
|
|
||||||
delete_SDLOSXCAGuard(frt->mGuard);
|
|
||||||
SDL_free(frt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileReaderThread *
|
|
||||||
new_FileReaderThread()
|
|
||||||
{
|
|
||||||
FileReaderThread *frt =
|
|
||||||
(FileReaderThread *) SDL_malloc(sizeof(FileReaderThread));
|
|
||||||
if (frt == NULL)
|
|
||||||
return NULL;
|
|
||||||
SDL_memset(frt, '\0', sizeof(*frt));
|
|
||||||
|
|
||||||
frt->mGuard = new_SDLOSXCAGuard();
|
|
||||||
if (frt->mGuard == NULL) {
|
|
||||||
SDL_free(frt);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m
|
|
||||||
SET_FILEREADERTHREAD_METHOD(GetGuard);
|
|
||||||
SET_FILEREADERTHREAD_METHOD(AddReader);
|
|
||||||
SET_FILEREADERTHREAD_METHOD(RemoveReader);
|
|
||||||
SET_FILEREADERTHREAD_METHOD(TryNextRead);
|
|
||||||
SET_FILEREADERTHREAD_METHOD(ReadNextChunk);
|
|
||||||
SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread);
|
|
||||||
SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority);
|
|
||||||
SET_FILEREADERTHREAD_METHOD(DiskReaderEntry);
|
|
||||||
#undef SET_FILEREADERTHREAD_METHOD
|
|
||||||
|
|
||||||
frt->mThreadPriority = 62;
|
|
||||||
return frt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static FileReaderThread *sReaderThread;
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
AudioFileManager_DoConnect(AudioFileManager * afm)
|
|
||||||
{
|
|
||||||
if (!afm->mIsEngaged) {
|
|
||||||
OSStatus result;
|
|
||||||
|
|
||||||
/*afm->mReadFilePosition = 0; */
|
|
||||||
afm->mFinishedReadingData = 0;
|
|
||||||
|
|
||||||
afm->mNumTimesAskedSinceFinished = 0;
|
|
||||||
afm->mLockUnsuccessful = 0;
|
|
||||||
|
|
||||||
UInt32 dataChunkSize;
|
|
||||||
|
|
||||||
if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize)
|
|
||||||
dataChunkSize = afm->mFileLength - afm->mReadFilePosition;
|
|
||||||
else
|
|
||||||
dataChunkSize = afm->mChunkSize;
|
|
||||||
|
|
||||||
result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize);
|
|
||||||
if (result)
|
|
||||||
return 0; /*THROW_RESULT("AudioFileManager::DoConnect(): Read") */
|
|
||||||
|
|
||||||
afm->mReadFilePosition += dataChunkSize;
|
|
||||||
|
|
||||||
afm->mWriteToFirstBuffer = 0;
|
|
||||||
afm->mReadFromFirstBuffer = 1;
|
|
||||||
|
|
||||||
sReaderThread->AddReader(sReaderThread);
|
|
||||||
|
|
||||||
afm->mIsEngaged = 1;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
else
|
|
||||||
throw static_cast<OSStatus>(-1); *//* thread has already been started */
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFileManager_Disconnect(AudioFileManager * afm)
|
|
||||||
{
|
|
||||||
if (afm->mIsEngaged) {
|
|
||||||
sReaderThread->RemoveReader(sReaderThread, afm);
|
|
||||||
afm->mIsEngaged = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus
|
|
||||||
AudioFileManager_Read(AudioFileManager * afm, char *buffer, UInt32 * len)
|
|
||||||
{
|
|
||||||
return FSReadFork(afm->mForkRefNum,
|
|
||||||
fsFromStart,
|
|
||||||
afm->mReadFilePosition + afm->mAudioDataOffset,
|
|
||||||
*len, buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus
|
|
||||||
AudioFileManager_GetFileData(AudioFileManager * afm, void **inOutData,
|
|
||||||
UInt32 * inOutDataSize)
|
|
||||||
{
|
|
||||||
if (afm->mFinishedReadingData) {
|
|
||||||
++afm->mNumTimesAskedSinceFinished;
|
|
||||||
*inOutDataSize = 0;
|
|
||||||
*inOutData = 0;
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) {
|
|
||||||
#if DEBUG
|
|
||||||
printf("* * * * * * * Can't keep up with reading file\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
afm->mParent->DoNotification(afm->mParent,
|
|
||||||
kAudioFilePlayErr_FilePlayUnderrun);
|
|
||||||
*inOutDataSize = 0;
|
|
||||||
*inOutData = 0;
|
|
||||||
} else {
|
|
||||||
*inOutDataSize = afm->mChunkSize;
|
|
||||||
*inOutData =
|
|
||||||
afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer +
|
|
||||||
afm->mChunkSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
afm->mLockUnsuccessful = !sReaderThread->TryNextRead(sReaderThread, afm);
|
|
||||||
|
|
||||||
afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer;
|
|
||||||
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFileManager_AfterRender(AudioFileManager * afm)
|
|
||||||
{
|
|
||||||
if (afm->mNumTimesAskedSinceFinished > 0) {
|
|
||||||
int didLock = 0;
|
|
||||||
SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread);
|
|
||||||
if (guard->Try(guard, &didLock)) {
|
|
||||||
afm->mParent->DoNotification(afm->mParent,
|
|
||||||
kAudioFilePlay_FileIsFinished);
|
|
||||||
if (didLock)
|
|
||||||
guard->Unlock(guard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (afm->mLockUnsuccessful)
|
|
||||||
afm->mLockUnsuccessful =
|
|
||||||
!sReaderThread->TryNextRead(sReaderThread, afm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFileManager_SetPosition(AudioFileManager * afm, SInt64 pos)
|
|
||||||
{
|
|
||||||
if (pos < 0 || pos >= afm->mFileLength) {
|
|
||||||
SDL_SetError
|
|
||||||
("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n",
|
|
||||||
(unsigned int) pos, (unsigned int) afm->mFileLength);
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
afm->mReadFilePosition = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AudioFileManager_SetEndOfFile(AudioFileManager * afm, SInt64 pos)
|
|
||||||
{
|
|
||||||
if (pos <= 0 || pos > afm->mFileLength) {
|
|
||||||
SDL_SetError
|
|
||||||
("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
|
|
||||||
pos = afm->mFileLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
afm->mFileLength = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
AudioFileManager_GetFileBuffer(AudioFileManager * afm)
|
|
||||||
{
|
|
||||||
return afm->mFileBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AudioFilePlayer *
|
|
||||||
AudioFileManager_GetParent(AudioFileManager * afm)
|
|
||||||
{
|
|
||||||
return afm->mParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
AudioFileManager_GetByteCounter(AudioFileManager * afm)
|
|
||||||
{
|
|
||||||
return afm->mByteCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static OSStatus
|
|
||||||
AudioFileManager_FileInputProc(void *inRefCon,
|
|
||||||
AudioUnitRenderActionFlags inActionFlags,
|
|
||||||
const AudioTimeStamp * inTimeStamp,
|
|
||||||
UInt32 inBusNumber, AudioBuffer * ioData)
|
|
||||||
{
|
|
||||||
AudioFileManager *afm = (AudioFileManager *) inRefCon;
|
|
||||||
return afm->Render(afm, ioData);
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus
|
|
||||||
AudioFileManager_Render(AudioFileManager * afm, AudioBuffer * ioData)
|
|
||||||
{
|
|
||||||
OSStatus result = noErr;
|
|
||||||
|
|
||||||
if (afm->mBufferOffset >= afm->mBufferSize) {
|
|
||||||
result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize);
|
|
||||||
if (result) {
|
|
||||||
SDL_SetError("AudioConverterFillBuffer:%ld\n", result);
|
|
||||||
afm->mParent->DoNotification(afm->mParent, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
afm->mBufferOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioData->mDataByteSize > afm->mBufferSize - afm->mBufferOffset)
|
|
||||||
ioData->mDataByteSize = afm->mBufferSize - afm->mBufferOffset;
|
|
||||||
ioData->mData = (char *) afm->mTmpBuffer + afm->mBufferOffset;
|
|
||||||
afm->mBufferOffset += ioData->mDataByteSize;
|
|
||||||
|
|
||||||
afm->mByteCounter += ioData->mDataByteSize;
|
|
||||||
afm->AfterRender(afm);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
delete_AudioFileManager(AudioFileManager * afm)
|
|
||||||
{
|
|
||||||
if (afm != NULL) {
|
|
||||||
if (afm->mFileBuffer) {
|
|
||||||
free(afm->mFileBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_free(afm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AudioFileManager *
|
|
||||||
new_AudioFileManager(AudioFilePlayer * inParent,
|
|
||||||
SInt16 inForkRefNum,
|
|
||||||
SInt64 inFileLength, UInt32 inChunkSize)
|
|
||||||
{
|
|
||||||
AudioFileManager *afm;
|
|
||||||
|
|
||||||
if (sReaderThread == NULL) {
|
|
||||||
sReaderThread = new_FileReaderThread();
|
|
||||||
if (sReaderThread == NULL)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
afm = (AudioFileManager *) SDL_malloc(sizeof(AudioFileManager));
|
|
||||||
if (afm == NULL)
|
|
||||||
return NULL;
|
|
||||||
SDL_memset(afm, '\0', sizeof(*afm));
|
|
||||||
|
|
||||||
#define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(Disconnect);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(DoConnect);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(Read);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(GetParent);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(SetPosition);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(GetByteCounter);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(Render);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(GetFileData);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(AfterRender);
|
|
||||||
SET_AUDIOFILEMANAGER_METHOD(FileInputProc);
|
|
||||||
#undef SET_AUDIOFILEMANAGER_METHOD
|
|
||||||
|
|
||||||
afm->mParent = inParent;
|
|
||||||
afm->mForkRefNum = inForkRefNum;
|
|
||||||
afm->mBufferSize = inChunkSize;
|
|
||||||
afm->mBufferOffset = inChunkSize;
|
|
||||||
afm->mChunkSize = inChunkSize;
|
|
||||||
afm->mFileLength = inFileLength;
|
|
||||||
afm->mFileBuffer = (char *) SDL_malloc(afm->mChunkSize * 2);
|
|
||||||
FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset);
|
|
||||||
assert(afm->mFileBuffer != NULL);
|
|
||||||
return afm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,669 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#include "CDPlayer.h"
|
|
||||||
#include "AudioFilePlayer.h"
|
|
||||||
#include "SDLOSXCAGuard.h"
|
|
||||||
|
|
||||||
/* we're exporting these functions into C land for SDL_syscdrom.c */
|
|
||||||
/*extern "C" {*/
|
|
||||||
|
|
||||||
/*///////////////////////////////////////////////////////////////////////////
|
|
||||||
Constants
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
#define kAudioCDFilesystemID (UInt16)(('J' << 8) | 'H') /* 'JH'; this avoids compiler warning */
|
|
||||||
|
|
||||||
/* XML PList keys */
|
|
||||||
#define kRawTOCDataString "Format 0x02 TOC Data"
|
|
||||||
#define kSessionsString "Sessions"
|
|
||||||
#define kSessionTypeString "Session Type"
|
|
||||||
#define kTrackArrayString "Track Array"
|
|
||||||
#define kFirstTrackInSessionString "First Track"
|
|
||||||
#define kLastTrackInSessionString "Last Track"
|
|
||||||
#define kLeadoutBlockString "Leadout Block"
|
|
||||||
#define kDataKeyString "Data"
|
|
||||||
#define kPointKeyString "Point"
|
|
||||||
#define kSessionNumberKeyString "Session Number"
|
|
||||||
#define kStartBlockKeyString "Start Block"
|
|
||||||
|
|
||||||
/*///////////////////////////////////////////////////////////////////////////
|
|
||||||
Globals
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
#pragma mark -- Globals --
|
|
||||||
|
|
||||||
static int playBackWasInit = 0;
|
|
||||||
static AudioUnit theUnit;
|
|
||||||
static AudioFilePlayer *thePlayer = NULL;
|
|
||||||
static CDPlayerCompletionProc completionProc = NULL;
|
|
||||||
static SDL_mutex *apiMutex = NULL;
|
|
||||||
static SDL_sem *callbackSem;
|
|
||||||
static SDL_CD *theCDROM;
|
|
||||||
|
|
||||||
/*///////////////////////////////////////////////////////////////////////////
|
|
||||||
Prototypes
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
#pragma mark -- Prototypes --
|
|
||||||
|
|
||||||
static OSStatus CheckInit();
|
|
||||||
|
|
||||||
static void FilePlayNotificationHandler(void *inRefCon, OSStatus inStatus);
|
|
||||||
|
|
||||||
static int RunCallBackThread(void *inRefCon);
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -- Public Functions --
|
|
||||||
|
|
||||||
void
|
|
||||||
Lock()
|
|
||||||
{
|
|
||||||
if (!apiMutex) {
|
|
||||||
apiMutex = SDL_CreateMutex();
|
|
||||||
}
|
|
||||||
SDL_mutexP(apiMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Unlock()
|
|
||||||
{
|
|
||||||
SDL_mutexV(apiMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
DetectAudioCDVolumes(FSVolumeRefNum * volumes, int numVolumes)
|
|
||||||
{
|
|
||||||
int volumeIndex;
|
|
||||||
int cdVolumeCount = 0;
|
|
||||||
OSStatus result = noErr;
|
|
||||||
|
|
||||||
for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++) {
|
|
||||||
FSVolumeRefNum actualVolume;
|
|
||||||
FSVolumeInfo volumeInfo;
|
|
||||||
|
|
||||||
memset(&volumeInfo, 0, sizeof(volumeInfo));
|
|
||||||
|
|
||||||
result = FSGetVolumeInfo(kFSInvalidVolumeRefNum,
|
|
||||||
volumeIndex,
|
|
||||||
&actualVolume,
|
|
||||||
kFSVolInfoFSInfo, &volumeInfo, NULL, NULL);
|
|
||||||
|
|
||||||
if (result == noErr) {
|
|
||||||
if (volumeInfo.filesystemID == kAudioCDFilesystemID) { /* It's an audio CD */
|
|
||||||
if (volumes != NULL && cdVolumeCount < numVolumes)
|
|
||||||
volumes[cdVolumeCount] = actualVolume;
|
|
||||||
|
|
||||||
cdVolumeCount++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* I'm commenting this out because it seems to be harmless */
|
|
||||||
/*SDL_SetError ("DetectAudioCDVolumes: FSGetVolumeInfo returned %d", result); */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cdVolumeCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ReadTOCData(FSVolumeRefNum theVolume, SDL_CD * theCD)
|
|
||||||
{
|
|
||||||
HFSUniStr255 dataForkName;
|
|
||||||
OSStatus theErr;
|
|
||||||
SInt16 forkRefNum;
|
|
||||||
SInt64 forkSize;
|
|
||||||
Ptr forkData = 0;
|
|
||||||
ByteCount actualRead;
|
|
||||||
CFDataRef dataRef = 0;
|
|
||||||
CFPropertyListRef propertyListRef = 0;
|
|
||||||
|
|
||||||
FSRefParam fsRefPB;
|
|
||||||
FSRef tocPlistFSRef;
|
|
||||||
|
|
||||||
const char *error = "Unspecified Error";
|
|
||||||
|
|
||||||
/* get stuff from .TOC.plist */
|
|
||||||
fsRefPB.ioCompletion = NULL;
|
|
||||||
fsRefPB.ioNamePtr = "\p.TOC.plist";
|
|
||||||
fsRefPB.ioVRefNum = theVolume;
|
|
||||||
fsRefPB.ioDirID = 0;
|
|
||||||
fsRefPB.newRef = &tocPlistFSRef;
|
|
||||||
|
|
||||||
theErr = PBMakeFSRefSync(&fsRefPB);
|
|
||||||
if (theErr != noErr) {
|
|
||||||
error = "PBMakeFSRefSync";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load and parse the TOC XML data */
|
|
||||||
|
|
||||||
theErr = FSGetDataForkName(&dataForkName);
|
|
||||||
if (theErr != noErr) {
|
|
||||||
error = "FSGetDataForkName";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
theErr =
|
|
||||||
FSOpenFork(&tocPlistFSRef, dataForkName.length, dataForkName.unicode,
|
|
||||||
fsRdPerm, &forkRefNum);
|
|
||||||
if (theErr != noErr) {
|
|
||||||
error = "FSOpenFork";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
theErr = FSGetForkSize(forkRefNum, &forkSize);
|
|
||||||
if (theErr != noErr) {
|
|
||||||
error = "FSGetForkSize";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate some memory for the XML data */
|
|
||||||
forkData = NewPtr(forkSize);
|
|
||||||
if (forkData == NULL) {
|
|
||||||
error = "NewPtr";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
theErr = FSReadFork(forkRefNum, fsFromStart, 0 /* offset location */ ,
|
|
||||||
forkSize, forkData, &actualRead);
|
|
||||||
if (theErr != noErr) {
|
|
||||||
error = "FSReadFork";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
dataRef = CFDataCreate(kCFAllocatorDefault, (UInt8 *) forkData, forkSize);
|
|
||||||
if (dataRef == 0) {
|
|
||||||
error = "CFDataCreate";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
propertyListRef = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
|
|
||||||
dataRef,
|
|
||||||
kCFPropertyListImmutable,
|
|
||||||
NULL);
|
|
||||||
if (propertyListRef == NULL) {
|
|
||||||
error = "CFPropertyListCreateFromXMLData";
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we got the Property List in memory. Parse it. */
|
|
||||||
|
|
||||||
/* First, make sure the root item is a CFDictionary. If not, release and bail. */
|
|
||||||
if (CFGetTypeID(propertyListRef) == CFDictionaryGetTypeID()) {
|
|
||||||
CFDictionaryRef dictRef = (CFDictionaryRef) propertyListRef;
|
|
||||||
|
|
||||||
CFDataRef theRawTOCDataRef;
|
|
||||||
CFArrayRef theSessionArrayRef;
|
|
||||||
CFIndex numSessions;
|
|
||||||
CFIndex index;
|
|
||||||
|
|
||||||
/* This is how we get the Raw TOC Data */
|
|
||||||
theRawTOCDataRef =
|
|
||||||
(CFDataRef) CFDictionaryGetValue(dictRef,
|
|
||||||
CFSTR(kRawTOCDataString));
|
|
||||||
|
|
||||||
/* Get the session array info. */
|
|
||||||
theSessionArrayRef =
|
|
||||||
(CFArrayRef) CFDictionaryGetValue(dictRef,
|
|
||||||
CFSTR(kSessionsString));
|
|
||||||
|
|
||||||
/* Find out how many sessions there are. */
|
|
||||||
numSessions = CFArrayGetCount(theSessionArrayRef);
|
|
||||||
|
|
||||||
/* Initialize the total number of tracks to 0 */
|
|
||||||
theCD->numtracks = 0;
|
|
||||||
|
|
||||||
/* Iterate over all sessions, collecting the track data */
|
|
||||||
for (index = 0; index < numSessions; index++) {
|
|
||||||
CFDictionaryRef theSessionDict;
|
|
||||||
CFNumberRef leadoutBlock;
|
|
||||||
CFArrayRef trackArray;
|
|
||||||
CFIndex numTracks;
|
|
||||||
CFIndex trackIndex;
|
|
||||||
UInt32 value = 0;
|
|
||||||
|
|
||||||
theSessionDict = (CFDictionaryRef)
|
|
||||||
CFArrayGetValueAtIndex(theSessionArrayRef, index);
|
|
||||||
leadoutBlock =
|
|
||||||
(CFNumberRef) CFDictionaryGetValue(theSessionDict,
|
|
||||||
CFSTR
|
|
||||||
(kLeadoutBlockString));
|
|
||||||
|
|
||||||
trackArray =
|
|
||||||
(CFArrayRef) CFDictionaryGetValue(theSessionDict,
|
|
||||||
CFSTR(kTrackArrayString));
|
|
||||||
|
|
||||||
numTracks = CFArrayGetCount(trackArray);
|
|
||||||
|
|
||||||
for (trackIndex = 0; trackIndex < numTracks; trackIndex++) {
|
|
||||||
|
|
||||||
CFDictionaryRef theTrackDict;
|
|
||||||
CFNumberRef trackNumber;
|
|
||||||
CFNumberRef sessionNumber;
|
|
||||||
CFNumberRef startBlock;
|
|
||||||
CFBooleanRef isDataTrack;
|
|
||||||
UInt32 value;
|
|
||||||
|
|
||||||
theTrackDict = (CFDictionaryRef)
|
|
||||||
CFArrayGetValueAtIndex(trackArray, trackIndex);
|
|
||||||
|
|
||||||
trackNumber =
|
|
||||||
(CFNumberRef) CFDictionaryGetValue(theTrackDict,
|
|
||||||
CFSTR
|
|
||||||
(kPointKeyString));
|
|
||||||
sessionNumber =
|
|
||||||
(CFNumberRef) CFDictionaryGetValue(theTrackDict,
|
|
||||||
CFSTR
|
|
||||||
(kSessionNumberKeyString));
|
|
||||||
startBlock =
|
|
||||||
(CFNumberRef) CFDictionaryGetValue(theTrackDict,
|
|
||||||
CFSTR
|
|
||||||
(kStartBlockKeyString));
|
|
||||||
isDataTrack =
|
|
||||||
(CFBooleanRef) CFDictionaryGetValue(theTrackDict,
|
|
||||||
CFSTR
|
|
||||||
(kDataKeyString));
|
|
||||||
|
|
||||||
/* Fill in the SDL_CD struct */
|
|
||||||
int idx = theCD->numtracks++;
|
|
||||||
|
|
||||||
CFNumberGetValue(trackNumber, kCFNumberSInt32Type, &value);
|
|
||||||
theCD->track[idx].id = value;
|
|
||||||
|
|
||||||
CFNumberGetValue(startBlock, kCFNumberSInt32Type, &value);
|
|
||||||
theCD->track[idx].offset = value;
|
|
||||||
|
|
||||||
theCD->track[idx].type =
|
|
||||||
(isDataTrack ==
|
|
||||||
kCFBooleanTrue) ? SDL_DATA_TRACK : SDL_AUDIO_TRACK;
|
|
||||||
|
|
||||||
/* Since the track lengths are not stored in .TOC.plist we compute them. */
|
|
||||||
if (trackIndex > 0) {
|
|
||||||
theCD->track[idx - 1].length =
|
|
||||||
theCD->track[idx].offset - theCD->track[idx -
|
|
||||||
1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute the length of the last track */
|
|
||||||
CFNumberGetValue(leadoutBlock, kCFNumberSInt32Type, &value);
|
|
||||||
|
|
||||||
theCD->track[theCD->numtracks - 1].length =
|
|
||||||
value - theCD->track[theCD->numtracks - 1].offset;
|
|
||||||
|
|
||||||
/* Set offset to leadout track */
|
|
||||||
theCD->track[theCD->numtracks].offset = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
theErr = 0;
|
|
||||||
goto cleanup;
|
|
||||||
bail:
|
|
||||||
SDL_SetError("ReadTOCData: %s returned %d", error, theErr);
|
|
||||||
theErr = -1;
|
|
||||||
cleanup:
|
|
||||||
|
|
||||||
if (propertyListRef != NULL)
|
|
||||||
CFRelease(propertyListRef);
|
|
||||||
if (dataRef != NULL)
|
|
||||||
CFRelease(dataRef);
|
|
||||||
if (forkData != NULL)
|
|
||||||
DisposePtr(forkData);
|
|
||||||
|
|
||||||
FSCloseFork(forkRefNum);
|
|
||||||
|
|
||||||
return theErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ListTrackFiles(FSVolumeRefNum theVolume, FSRef * trackFiles, int numTracks)
|
|
||||||
{
|
|
||||||
OSStatus result = -1;
|
|
||||||
FSIterator iterator;
|
|
||||||
ItemCount actualObjects;
|
|
||||||
FSRef rootDirectory;
|
|
||||||
FSRef ref;
|
|
||||||
HFSUniStr255 nameStr;
|
|
||||||
|
|
||||||
result = FSGetVolumeInfo(theVolume,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
kFSVolInfoFSInfo, NULL, NULL, &rootDirectory);
|
|
||||||
|
|
||||||
if (result != noErr) {
|
|
||||||
SDL_SetError("ListTrackFiles: FSGetVolumeInfo returned %d", result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = FSOpenIterator(&rootDirectory, kFSIterateFlat, &iterator);
|
|
||||||
if (result == noErr) {
|
|
||||||
do {
|
|
||||||
result = FSGetCatalogInfoBulk(iterator, 1, &actualObjects,
|
|
||||||
NULL, kFSCatInfoNone, NULL,
|
|
||||||
&ref, NULL, &nameStr);
|
|
||||||
if (result == noErr) {
|
|
||||||
|
|
||||||
CFStringRef name;
|
|
||||||
name =
|
|
||||||
CFStringCreateWithCharacters(NULL, nameStr.unicode,
|
|
||||||
nameStr.length);
|
|
||||||
|
|
||||||
/* Look for .aiff extension */
|
|
||||||
if (CFStringHasSuffix(name, CFSTR(".aiff")) ||
|
|
||||||
CFStringHasSuffix(name, CFSTR(".cdda"))) {
|
|
||||||
|
|
||||||
/* Extract the track id from the filename */
|
|
||||||
int trackID = 0, i = 0;
|
|
||||||
while (i < nameStr.length && !isdigit(nameStr.unicode[i])) {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
while (i < nameStr.length && isdigit(nameStr.unicode[i])) {
|
|
||||||
trackID = 10 * trackID + (nameStr.unicode[i] - '0');
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG_CDROM
|
|
||||||
printf("Found AIFF for track %d: '%s'\n",
|
|
||||||
trackID, CFStringGetCStringPtr(name,
|
|
||||||
CFStringGetSystemEncoding
|
|
||||||
()));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Track ID's start at 1, but we want to start at 0 */
|
|
||||||
trackID--;
|
|
||||||
|
|
||||||
assert(0 <= trackID && trackID <= SDL_MAX_TRACKS);
|
|
||||||
|
|
||||||
if (trackID < numTracks)
|
|
||||||
memcpy(&trackFiles[trackID], &ref, sizeof(FSRef));
|
|
||||||
}
|
|
||||||
CFRelease(name);
|
|
||||||
}
|
|
||||||
} while (noErr == result);
|
|
||||||
FSCloseIterator(iterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
LoadFile(const FSRef * ref, int startFrame, int stopFrame)
|
|
||||||
{
|
|
||||||
int error = -1;
|
|
||||||
|
|
||||||
if (CheckInit() < 0)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
/* release any currently playing file */
|
|
||||||
if (ReleaseFile() < 0)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
#if DEBUG_CDROM
|
|
||||||
printf("LoadFile: %d %d\n", startFrame, stopFrame);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*try { */
|
|
||||||
|
|
||||||
/* create a new player, and attach to the audio unit */
|
|
||||||
|
|
||||||
thePlayer = new_AudioFilePlayer(ref);
|
|
||||||
if (thePlayer == NULL) {
|
|
||||||
SDL_SetError("LoadFile: Could not create player");
|
|
||||||
return -3; /*throw (-3); */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!thePlayer->SetDestination(thePlayer, &theUnit))
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
if (startFrame >= 0)
|
|
||||||
thePlayer->SetStartFrame(thePlayer, startFrame);
|
|
||||||
|
|
||||||
if (stopFrame >= 0 && stopFrame > startFrame)
|
|
||||||
thePlayer->SetStopFrame(thePlayer, stopFrame);
|
|
||||||
|
|
||||||
/* we set the notifier later */
|
|
||||||
/*thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL); */
|
|
||||||
|
|
||||||
if (!thePlayer->Connect(thePlayer))
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
#if DEBUG_CDROM
|
|
||||||
thePlayer->Print(thePlayer);
|
|
||||||
fflush(stdout);
|
|
||||||
#endif
|
|
||||||
/*}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
goto bail;
|
|
||||||
} */
|
|
||||||
|
|
||||||
error = 0;
|
|
||||||
|
|
||||||
bail:
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ReleaseFile()
|
|
||||||
{
|
|
||||||
int error = -1;
|
|
||||||
|
|
||||||
/* (Don't see any way that the original C++ code could throw here.) --ryan. */
|
|
||||||
/*try { */
|
|
||||||
if (thePlayer != NULL) {
|
|
||||||
|
|
||||||
thePlayer->Disconnect(thePlayer);
|
|
||||||
|
|
||||||
delete_AudioFilePlayer(thePlayer);
|
|
||||||
|
|
||||||
thePlayer = NULL;
|
|
||||||
}
|
|
||||||
/*}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
goto bail;
|
|
||||||
} */
|
|
||||||
|
|
||||||
error = 0;
|
|
||||||
|
|
||||||
/* bail: */
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
PlayFile()
|
|
||||||
{
|
|
||||||
OSStatus result = -1;
|
|
||||||
|
|
||||||
if (CheckInit() < 0)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
/*try { */
|
|
||||||
|
|
||||||
// start processing of the audio unit
|
|
||||||
result = AudioOutputUnitStart(theUnit);
|
|
||||||
if (result)
|
|
||||||
goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart")
|
|
||||||
|
|
||||||
/*}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
goto bail;
|
|
||||||
} */
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
|
|
||||||
bail:
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
PauseFile()
|
|
||||||
{
|
|
||||||
OSStatus result = -1;
|
|
||||||
|
|
||||||
if (CheckInit() < 0)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
/*try { */
|
|
||||||
|
|
||||||
/* stop processing the audio unit */
|
|
||||||
result = AudioOutputUnitStop(theUnit);
|
|
||||||
if (result)
|
|
||||||
goto bail; /*THROW_RESULT("PauseFile: AudioOutputUnitStop") */
|
|
||||||
/*}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
goto bail;
|
|
||||||
} */
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
bail:
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SetCompletionProc(CDPlayerCompletionProc proc, SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
assert(thePlayer != NULL);
|
|
||||||
|
|
||||||
theCDROM = cdrom;
|
|
||||||
completionProc = proc;
|
|
||||||
thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, cdrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
GetCurrentFrame()
|
|
||||||
{
|
|
||||||
int frame;
|
|
||||||
|
|
||||||
if (thePlayer == NULL)
|
|
||||||
frame = 0;
|
|
||||||
else
|
|
||||||
frame = thePlayer->GetCurrentFrame(thePlayer);
|
|
||||||
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -- Private Functions --
|
|
||||||
|
|
||||||
static OSStatus
|
|
||||||
CheckInit()
|
|
||||||
{
|
|
||||||
if (playBackWasInit)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
OSStatus result = noErr;
|
|
||||||
|
|
||||||
/* Create the callback semaphore */
|
|
||||||
callbackSem = SDL_CreateSemaphore(0);
|
|
||||||
|
|
||||||
/* Start callback thread */
|
|
||||||
SDL_CreateThread(RunCallBackThread, NULL);
|
|
||||||
|
|
||||||
{ /*try { */
|
|
||||||
ComponentDescription desc;
|
|
||||||
|
|
||||||
desc.componentType = kAudioUnitComponentType;
|
|
||||||
desc.componentSubType = kAudioUnitSubType_Output;
|
|
||||||
desc.componentManufacturer = kAudioUnitID_DefaultOutput;
|
|
||||||
desc.componentFlags = 0;
|
|
||||||
desc.componentFlagsMask = 0;
|
|
||||||
|
|
||||||
Component comp = FindNextComponent(NULL, &desc);
|
|
||||||
if (comp == NULL) {
|
|
||||||
SDL_SetError("CheckInit: FindNextComponent returned NULL");
|
|
||||||
if (result)
|
|
||||||
return -1; //throw(internalComponentErr);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = OpenAComponent(comp, &theUnit);
|
|
||||||
if (result)
|
|
||||||
return -1; //THROW_RESULT("CheckInit: OpenAComponent")
|
|
||||||
|
|
||||||
// you need to initialize the output unit before you set it as a destination
|
|
||||||
result = AudioUnitInitialize(theUnit);
|
|
||||||
if (result)
|
|
||||||
return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize")
|
|
||||||
|
|
||||||
|
|
||||||
playBackWasInit = true;
|
|
||||||
}
|
|
||||||
/*catch (...)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
} */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
FilePlayNotificationHandler(void *inRefCon, OSStatus inStatus)
|
|
||||||
{
|
|
||||||
if (inStatus == kAudioFilePlay_FileIsFinished) {
|
|
||||||
|
|
||||||
/* notify non-CA thread to perform the callback */
|
|
||||||
SDL_SemPost(callbackSem);
|
|
||||||
|
|
||||||
} else if (inStatus == kAudioFilePlayErr_FilePlayUnderrun) {
|
|
||||||
|
|
||||||
SDL_SetError("CDPlayer Notification: buffer underrun");
|
|
||||||
} else if (inStatus == kAudioFilePlay_PlayerIsUninitialized) {
|
|
||||||
|
|
||||||
SDL_SetError("CDPlayer Notification: player is uninitialized");
|
|
||||||
} else {
|
|
||||||
|
|
||||||
SDL_SetError("CDPlayer Notification: unknown error %ld", inStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
RunCallBackThread(void *param)
|
|
||||||
{
|
|
||||||
for (;;) {
|
|
||||||
|
|
||||||
SDL_SemWait(callbackSem);
|
|
||||||
|
|
||||||
if (completionProc && theCDROM) {
|
|
||||||
#if DEBUG_CDROM
|
|
||||||
printf("callback!\n");
|
|
||||||
#endif
|
|
||||||
(*completionProc) (theCDROM);
|
|
||||||
} else {
|
|
||||||
#if DEBUG_CDROM
|
|
||||||
printf("callback?\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG_CDROM
|
|
||||||
printf("thread dying now...\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*}; // extern "C" */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifndef __CDPlayer__H__
|
|
||||||
#define __CDPlayer__H__ 1
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <Carbon/Carbon.h>
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include <AudioUnit/AudioUnit.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "SDL_thread.h"
|
|
||||||
#include "SDL_mutex.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void (*CDPlayerCompletionProc) (SDL_CD * cdrom);
|
|
||||||
|
|
||||||
void Lock();
|
|
||||||
|
|
||||||
void Unlock();
|
|
||||||
|
|
||||||
int LoadFile(const FSRef * ref, int startFrame, int endFrame); /* pass -1 to do nothing */
|
|
||||||
|
|
||||||
int ReleaseFile();
|
|
||||||
|
|
||||||
int PlayFile();
|
|
||||||
|
|
||||||
int PauseFile();
|
|
||||||
|
|
||||||
void SetCompletionProc(CDPlayerCompletionProc proc, SDL_CD * cdrom);
|
|
||||||
|
|
||||||
int ReadTOCData(FSVolumeRefNum theVolume, SDL_CD * theCD);
|
|
||||||
|
|
||||||
int ListTrackFiles(FSVolumeRefNum theVolume, FSRef * trackFiles,
|
|
||||||
int numTracks);
|
|
||||||
|
|
||||||
int DetectAudioCDVolumes(FSVolumeRefNum * volumes, int numVolumes);
|
|
||||||
|
|
||||||
int GetCurrentFrame();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __CD_Player__H__ */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,205 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
|
|
||||||
|
|
||||||
Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
|
|
||||||
|
|
||||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
|
||||||
("Apple") in consideration of your agreement to the following terms, and your
|
|
||||||
use, installation, modification or redistribution of this Apple software
|
|
||||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
|
||||||
please do not use, install, modify or redistribute this Apple software.
|
|
||||||
|
|
||||||
In consideration of your agreement to abide by the following terms, and subject
|
|
||||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
|
||||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
|
||||||
reproduce, modify and redistribute the Apple Software, with or without
|
|
||||||
modifications, in source and/or binary forms; provided that if you redistribute
|
|
||||||
the Apple Software in its entirety and without modifications, you must retain
|
|
||||||
this notice and the following text and disclaimers in all such redistributions of
|
|
||||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
|
||||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
|
||||||
Apple Software without specific prior written permission from Apple. Except as
|
|
||||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
|
||||||
are granted by Apple herein, including but not limited to any patent rights that
|
|
||||||
may be infringed by your derivative works or by other works in which the Apple
|
|
||||||
Software may be incorporated.
|
|
||||||
|
|
||||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
|
||||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
|
||||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
|
||||||
COMBINATION WITH YOUR PRODUCTS.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
||||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
|
||||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
|
||||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
/*=============================================================================
|
|
||||||
CAGuard.cp
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
Includes
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
*/
|
|
||||||
#include "SDL_stdinc.h"
|
|
||||||
|
|
||||||
/*#define NDEBUG 1*/
|
|
||||||
/*
|
|
||||||
#include <assert.h>
|
|
||||||
*/
|
|
||||||
#define assert(X)
|
|
||||||
|
|
||||||
|
|
||||||
#include "SDLOSXCAGuard.h"
|
|
||||||
|
|
||||||
/*#warning Need a try-based Locker too*/
|
|
||||||
/*=============================================================================
|
|
||||||
SDLOSXCAGuard
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDLOSXCAGuard_Lock(SDLOSXCAGuard * cag)
|
|
||||||
{
|
|
||||||
int theAnswer = 0;
|
|
||||||
|
|
||||||
if (pthread_self() != cag->mOwner) {
|
|
||||||
OSStatus theError = pthread_mutex_lock(&cag->mMutex);
|
|
||||||
(void) theError;
|
|
||||||
assert(theError == 0);
|
|
||||||
cag->mOwner = pthread_self();
|
|
||||||
theAnswer = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return theAnswer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SDLOSXCAGuard_Unlock(SDLOSXCAGuard * cag)
|
|
||||||
{
|
|
||||||
OSStatus theError;
|
|
||||||
assert(pthread_self() == cag->mOwner);
|
|
||||||
|
|
||||||
cag->mOwner = 0;
|
|
||||||
theError = pthread_mutex_unlock(&cag->mMutex);
|
|
||||||
(void) theError;
|
|
||||||
assert(theError == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDLOSXCAGuard_Try(SDLOSXCAGuard * cag, int *outWasLocked)
|
|
||||||
{
|
|
||||||
int theAnswer = 0;
|
|
||||||
*outWasLocked = 0;
|
|
||||||
|
|
||||||
if (pthread_self() == cag->mOwner) {
|
|
||||||
theAnswer = 1;
|
|
||||||
*outWasLocked = 0;
|
|
||||||
} else {
|
|
||||||
OSStatus theError = pthread_mutex_trylock(&cag->mMutex);
|
|
||||||
if (theError == 0) {
|
|
||||||
cag->mOwner = pthread_self();
|
|
||||||
theAnswer = 1;
|
|
||||||
*outWasLocked = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return theAnswer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SDLOSXCAGuard_Wait(SDLOSXCAGuard * cag)
|
|
||||||
{
|
|
||||||
OSStatus theError;
|
|
||||||
assert(pthread_self() == cag->mOwner);
|
|
||||||
|
|
||||||
cag->mOwner = 0;
|
|
||||||
|
|
||||||
theError = pthread_cond_wait(&cag->mCondVar, &cag->mMutex);
|
|
||||||
(void) theError;
|
|
||||||
assert(theError == 0);
|
|
||||||
cag->mOwner = pthread_self();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SDLOSXCAGuard_Notify(SDLOSXCAGuard * cag)
|
|
||||||
{
|
|
||||||
OSStatus theError = pthread_cond_signal(&cag->mCondVar);
|
|
||||||
(void) theError;
|
|
||||||
assert(theError == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SDLOSXCAGuard *
|
|
||||||
new_SDLOSXCAGuard(void)
|
|
||||||
{
|
|
||||||
OSStatus theError;
|
|
||||||
SDLOSXCAGuard *cag = (SDLOSXCAGuard *) SDL_malloc(sizeof(SDLOSXCAGuard));
|
|
||||||
if (cag == NULL)
|
|
||||||
return NULL;
|
|
||||||
SDL_memset(cag, '\0', sizeof(*cag));
|
|
||||||
|
|
||||||
#define SET_SDLOSXCAGUARD_METHOD(m) cag->m = SDLOSXCAGuard_##m
|
|
||||||
SET_SDLOSXCAGUARD_METHOD(Lock);
|
|
||||||
SET_SDLOSXCAGUARD_METHOD(Unlock);
|
|
||||||
SET_SDLOSXCAGUARD_METHOD(Try);
|
|
||||||
SET_SDLOSXCAGUARD_METHOD(Wait);
|
|
||||||
SET_SDLOSXCAGUARD_METHOD(Notify);
|
|
||||||
#undef SET_SDLOSXCAGUARD_METHOD
|
|
||||||
|
|
||||||
theError = pthread_mutex_init(&cag->mMutex, NULL);
|
|
||||||
(void) theError;
|
|
||||||
assert(theError == 0);
|
|
||||||
|
|
||||||
theError = pthread_cond_init(&cag->mCondVar, NULL);
|
|
||||||
(void) theError;
|
|
||||||
assert(theError == 0);
|
|
||||||
|
|
||||||
cag->mOwner = 0;
|
|
||||||
return cag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
delete_SDLOSXCAGuard(SDLOSXCAGuard * cag)
|
|
||||||
{
|
|
||||||
if (cag != NULL) {
|
|
||||||
pthread_mutex_destroy(&cag->mMutex);
|
|
||||||
pthread_cond_destroy(&cag->mCondVar);
|
|
||||||
SDL_free(cag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
|
|
||||||
|
|
||||||
|
|
||||||
Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
|
|
||||||
|
|
||||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
|
||||||
("Apple") in consideration of your agreement to the following terms, and your
|
|
||||||
use, installation, modification or redistribution of this Apple software
|
|
||||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
|
||||||
please do not use, install, modify or redistribute this Apple software.
|
|
||||||
|
|
||||||
In consideration of your agreement to abide by the following terms, and subject
|
|
||||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
|
||||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
|
||||||
reproduce, modify and redistribute the Apple Software, with or without
|
|
||||||
modifications, in source and/or binary forms; provided that if you redistribute
|
|
||||||
the Apple Software in its entirety and without modifications, you must retain
|
|
||||||
this notice and the following text and disclaimers in all such redistributions of
|
|
||||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
|
||||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
|
||||||
Apple Software without specific prior written permission from Apple. Except as
|
|
||||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
|
||||||
are granted by Apple herein, including but not limited to any patent rights that
|
|
||||||
may be infringed by your derivative works or by other works in which the Apple
|
|
||||||
Software may be incorporated.
|
|
||||||
|
|
||||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
|
||||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
|
||||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
|
||||||
COMBINATION WITH YOUR PRODUCTS.
|
|
||||||
|
|
||||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
||||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
|
||||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
|
||||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
/*=============================================================================
|
|
||||||
CAGuard.h
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
#if !defined(__CAGuard_h__)
|
|
||||||
#define __CAGuard_h__
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
Includes
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
#include <CoreAudio/CoreAudioTypes.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
CAGuard
|
|
||||||
|
|
||||||
This is your typical mutex with signalling implemented via pthreads.
|
|
||||||
Lock() will return true if and only if the guard is locked on that call.
|
|
||||||
A thread that already has the guard will receive 'false' if it locks it
|
|
||||||
again. Use of the stack-based CAGuard::Locker class is highly recommended
|
|
||||||
to properly manage the recursive nesting. The Wait calls with timeouts
|
|
||||||
will return true if and only if the timeout period expired. They will
|
|
||||||
return false if they receive notification any other way.
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
typedef struct S_SDLOSXCAGuard
|
|
||||||
{
|
|
||||||
|
|
||||||
/* Construction/Destruction */
|
|
||||||
/*public:*/
|
|
||||||
/* Actions */
|
|
||||||
/*public:*/
|
|
||||||
int (*Lock) (struct S_SDLOSXCAGuard * cag);
|
|
||||||
void (*Unlock) (struct S_SDLOSXCAGuard * cag);
|
|
||||||
int (*Try) (struct S_SDLOSXCAGuard * cag, int *outWasLocked); /* returns true if lock is free, false if not */
|
|
||||||
void (*Wait) (struct S_SDLOSXCAGuard * cag);
|
|
||||||
void (*Notify) (struct S_SDLOSXCAGuard * cag);
|
|
||||||
|
|
||||||
/* Implementation */
|
|
||||||
/*protected:*/
|
|
||||||
pthread_mutex_t mMutex;
|
|
||||||
pthread_cond_t mCondVar;
|
|
||||||
pthread_t mOwner;
|
|
||||||
} SDLOSXCAGuard;
|
|
||||||
|
|
||||||
SDLOSXCAGuard *new_SDLOSXCAGuard(void);
|
|
||||||
void delete_SDLOSXCAGuard(SDLOSXCAGuard * cag);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,523 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_MACOSX
|
|
||||||
|
|
||||||
#include "SDL_syscdrom_c.h"
|
|
||||||
|
|
||||||
#pragma mark -- Globals --
|
|
||||||
|
|
||||||
static FSRef **tracks;
|
|
||||||
static FSVolumeRefNum *volumes;
|
|
||||||
static CDstatus status;
|
|
||||||
static int nextTrackFrame;
|
|
||||||
static int nextTrackFramesRemaining;
|
|
||||||
static int fakeCD;
|
|
||||||
static int currentTrack;
|
|
||||||
static int didReadTOC;
|
|
||||||
static int cacheTOCNumTracks;
|
|
||||||
static int currentDrive; /* Only allow 1 drive in use at a time */
|
|
||||||
|
|
||||||
#pragma mark -- Prototypes --
|
|
||||||
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
#pragma mark -- Helper Functions --
|
|
||||||
|
|
||||||
/* Read a list of tracks from the volume */
|
|
||||||
static int
|
|
||||||
LoadTracks(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
/* Check if tracks are already loaded */
|
|
||||||
if (tracks[cdrom->id] != NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Allocate memory for tracks */
|
|
||||||
tracks[cdrom->id] =
|
|
||||||
(FSRef *) SDL_calloc(1, sizeof(**tracks) * cdrom->numtracks);
|
|
||||||
if (tracks[cdrom->id] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load tracks */
|
|
||||||
if (ListTrackFiles
|
|
||||||
(volumes[cdrom->id], tracks[cdrom->id], cdrom->numtracks) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find a file for a given start frame and length */
|
|
||||||
static FSRef *
|
|
||||||
GetFileForOffset(SDL_CD * cdrom, int start, int length, int *outStartFrame,
|
|
||||||
int *outStopFrame)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < cdrom->numtracks; i++) {
|
|
||||||
|
|
||||||
if (cdrom->track[i].offset <= start &&
|
|
||||||
start < (cdrom->track[i].offset + cdrom->track[i].length))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == cdrom->numtracks)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
currentTrack = i;
|
|
||||||
|
|
||||||
*outStartFrame = start - cdrom->track[i].offset;
|
|
||||||
|
|
||||||
if ((*outStartFrame + length) < cdrom->track[i].length) {
|
|
||||||
*outStopFrame = *outStartFrame + length;
|
|
||||||
length = 0;
|
|
||||||
nextTrackFrame = -1;
|
|
||||||
nextTrackFramesRemaining = -1;
|
|
||||||
} else {
|
|
||||||
*outStopFrame = -1;
|
|
||||||
length -= cdrom->track[i].length - *outStartFrame;
|
|
||||||
nextTrackFrame = cdrom->track[i + 1].offset;
|
|
||||||
nextTrackFramesRemaining = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &tracks[cdrom->id][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup another file for playback, or stop playback (called from another thread) */
|
|
||||||
static void
|
|
||||||
CompletionProc(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
|
|
||||||
if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
|
|
||||||
|
|
||||||
/* Load the next file to play */
|
|
||||||
int startFrame, stopFrame;
|
|
||||||
FSRef *file;
|
|
||||||
|
|
||||||
PauseFile();
|
|
||||||
ReleaseFile();
|
|
||||||
|
|
||||||
file = GetFileForOffset(cdrom, nextTrackFrame,
|
|
||||||
nextTrackFramesRemaining, &startFrame,
|
|
||||||
&stopFrame);
|
|
||||||
|
|
||||||
if (file == NULL) {
|
|
||||||
status = CD_STOPPED;
|
|
||||||
Unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadFile(file, startFrame, stopFrame);
|
|
||||||
|
|
||||||
SetCompletionProc(CompletionProc, cdrom);
|
|
||||||
|
|
||||||
PlayFile();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* Release the current file */
|
|
||||||
PauseFile();
|
|
||||||
ReleaseFile();
|
|
||||||
status = CD_STOPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -- Driver Functions --
|
|
||||||
|
|
||||||
/* Initialize */
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* Initialize globals */
|
|
||||||
volumes = NULL;
|
|
||||||
tracks = NULL;
|
|
||||||
status = CD_STOPPED;
|
|
||||||
nextTrackFrame = -1;
|
|
||||||
nextTrackFramesRemaining = -1;
|
|
||||||
fakeCD = SDL_FALSE;
|
|
||||||
currentTrack = -1;
|
|
||||||
didReadTOC = SDL_FALSE;
|
|
||||||
cacheTOCNumTracks = -1;
|
|
||||||
currentDrive = -1;
|
|
||||||
|
|
||||||
/* Fill in function pointers */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Read the list of "drives"
|
|
||||||
|
|
||||||
This is currently a hack that infers drives from
|
|
||||||
mounted audio CD volumes, rather than
|
|
||||||
actual CD-ROM devices - which means it may not
|
|
||||||
act as expected sometimes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Find out how many cd volumes are mounted */
|
|
||||||
SDL_numcds = DetectAudioCDVolumes(NULL, 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
If there are no volumes, fake a cd device
|
|
||||||
so tray empty can be reported.
|
|
||||||
*/
|
|
||||||
if (SDL_numcds == 0) {
|
|
||||||
|
|
||||||
fakeCD = SDL_TRUE;
|
|
||||||
SDL_numcds = 1;
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate space for volumes */
|
|
||||||
volumes = (FSVolumeRefNum *) SDL_calloc(1, sizeof(*volumes) * SDL_numcds);
|
|
||||||
if (volumes == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate space for tracks */
|
|
||||||
tracks = (FSRef **) SDL_calloc(1, sizeof(*tracks) * (SDL_numcds + 1));
|
|
||||||
if (tracks == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark the end of the tracks array */
|
|
||||||
tracks[SDL_numcds] = (FSRef *) - 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Redetect, now save all volumes for later
|
|
||||||
Update SDL_numcds just in case it changed
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
int numVolumes = SDL_numcds;
|
|
||||||
|
|
||||||
SDL_numcds = DetectAudioCDVolumes(volumes, numVolumes);
|
|
||||||
|
|
||||||
/* If more cds suddenly show up, ignore them */
|
|
||||||
if (SDL_numcds > numVolumes) {
|
|
||||||
SDL_SetError("Some CD's were added but they will be ignored");
|
|
||||||
SDL_numcds = numVolumes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shutdown and cleanup */
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
ReleaseFile();
|
|
||||||
|
|
||||||
if (volumes != NULL)
|
|
||||||
free(volumes);
|
|
||||||
|
|
||||||
if (tracks != NULL) {
|
|
||||||
|
|
||||||
FSRef **ptr;
|
|
||||||
for (ptr = tracks; *ptr != (FSRef *) - 1; ptr++)
|
|
||||||
if (*ptr != NULL)
|
|
||||||
free(*ptr);
|
|
||||||
|
|
||||||
free(tracks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the Unix disk name of the volume */
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
OSStatus err = noErr;
|
|
||||||
HParamBlockRec pb;
|
|
||||||
GetVolParmsInfoBuffer volParmsInfo;
|
|
||||||
|
|
||||||
if (fakeCD)
|
|
||||||
return "Fake CD-ROM Device";
|
|
||||||
|
|
||||||
pb.ioParam.ioNamePtr = NULL;
|
|
||||||
pb.ioParam.ioVRefNum = volumes[drive];
|
|
||||||
pb.ioParam.ioBuffer = (Ptr) & volParmsInfo;
|
|
||||||
pb.ioParam.ioReqCount = (SInt32) sizeof(volParmsInfo);
|
|
||||||
err = PBHGetVolParmsSync(&pb);
|
|
||||||
|
|
||||||
if (err != noErr) {
|
|
||||||
SDL_SetError("PBHGetVolParmsSync returned %d", err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return volParmsInfo.vMDeviceID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the "device" */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
/* Only allow 1 device to be open */
|
|
||||||
if (currentDrive >= 0) {
|
|
||||||
SDL_SetError("Only one cdrom is supported");
|
|
||||||
return -1;
|
|
||||||
} else
|
|
||||||
currentDrive = drive;
|
|
||||||
|
|
||||||
return drive;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the table of contents */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (fakeCD) {
|
|
||||||
SDL_SetError(kErrorFakeDevice);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (didReadTOC) {
|
|
||||||
cdrom->numtracks = cacheTOCNumTracks;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ReadTOCData(volumes[cdrom->id], cdrom);
|
|
||||||
didReadTOC = SDL_TRUE;
|
|
||||||
cacheTOCNumTracks = cdrom->numtracks;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
if (position) {
|
|
||||||
int trackFrame;
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
trackFrame = GetCurrentFrame();
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
*position = cdrom->track[currentTrack].offset + trackFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start playback */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
int startFrame, stopFrame;
|
|
||||||
FSRef *ref;
|
|
||||||
|
|
||||||
if (fakeCD) {
|
|
||||||
SDL_SetError(kErrorFakeDevice);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
|
|
||||||
if (LoadTracks(cdrom) < 0)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
if (PauseFile() < 0)
|
|
||||||
return -3;
|
|
||||||
|
|
||||||
if (ReleaseFile() < 0)
|
|
||||||
return -4;
|
|
||||||
|
|
||||||
ref = GetFileForOffset(cdrom, start, length, &startFrame, &stopFrame);
|
|
||||||
if (ref == NULL) {
|
|
||||||
SDL_SetError("SDL_SYS_CDPlay: No file for start=%d, length=%d",
|
|
||||||
start, length);
|
|
||||||
return -5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LoadFile(ref, startFrame, stopFrame) < 0)
|
|
||||||
return -6;
|
|
||||||
|
|
||||||
SetCompletionProc(CompletionProc, cdrom);
|
|
||||||
|
|
||||||
if (PlayFile() < 0)
|
|
||||||
return -7;
|
|
||||||
|
|
||||||
status = CD_PLAYING;
|
|
||||||
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause playback */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (fakeCD) {
|
|
||||||
SDL_SetError(kErrorFakeDevice);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
|
|
||||||
if (PauseFile() < 0) {
|
|
||||||
Unlock();
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = CD_PAUSED;
|
|
||||||
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume playback */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (fakeCD) {
|
|
||||||
SDL_SetError(kErrorFakeDevice);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
|
|
||||||
if (PlayFile() < 0) {
|
|
||||||
Unlock();
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = CD_PLAYING;
|
|
||||||
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop playback */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (fakeCD) {
|
|
||||||
SDL_SetError(kErrorFakeDevice);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
|
|
||||||
if (PauseFile() < 0) {
|
|
||||||
Unlock();
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReleaseFile() < 0) {
|
|
||||||
Unlock();
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = CD_STOPPED;
|
|
||||||
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM (Unmount the volume) */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
OSStatus err;
|
|
||||||
pid_t dissenter;
|
|
||||||
|
|
||||||
if (fakeCD) {
|
|
||||||
SDL_SetError(kErrorFakeDevice);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock();
|
|
||||||
|
|
||||||
if (PauseFile() < 0) {
|
|
||||||
Unlock();
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReleaseFile() < 0) {
|
|
||||||
Unlock();
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = CD_STOPPED;
|
|
||||||
|
|
||||||
/* Eject the volume */
|
|
||||||
err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter);
|
|
||||||
|
|
||||||
if (err != noErr) {
|
|
||||||
Unlock();
|
|
||||||
SDL_SetError("PBUnmountVol returned %d", err);
|
|
||||||
return -4;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
|
|
||||||
/* Invalidate volume and track info */
|
|
||||||
volumes[cdrom->id] = 0;
|
|
||||||
free(tracks[cdrom->id]);
|
|
||||||
tracks[cdrom->id] = NULL;
|
|
||||||
|
|
||||||
Unlock();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
currentDrive = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_MACOSX */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
/* This is the Mac OS X / CoreAudio specific header for the SDL CD-ROM API
|
|
||||||
Contributed by Darrell Walisser and Max Horn
|
|
||||||
*/
|
|
||||||
|
|
||||||
/***********************************************************************************
|
|
||||||
Implementation Notes
|
|
||||||
*********************
|
|
||||||
|
|
||||||
This code has several limitations currently (all of which are proabaly fixable):
|
|
||||||
|
|
||||||
1. A CD-ROM device is inferred from a mounted cdfs volume, so device 0 is
|
|
||||||
not necessarily the first CD-ROM device on the system. (Somewhat easy to fix
|
|
||||||
by useing the device name from the volume id's to reorder the volumes)
|
|
||||||
|
|
||||||
2. You can only open and control 1 CD-ROM device at a time. (Challenging to fix,
|
|
||||||
due to extensive code restructuring)
|
|
||||||
|
|
||||||
3. The status reported by SDL_CDStatus only changes to from CD_PLAYING to CD_STOPPED in
|
|
||||||
1-second intervals (because the audio is buffered in 1-second chunks) If
|
|
||||||
the audio data is less than 1 second, the remainder is filled with silence.
|
|
||||||
|
|
||||||
If you need to play sequences back-to-back that are less that 1 second long,
|
|
||||||
use the frame position to determine when to play the next sequence, instead
|
|
||||||
of SDL_CDStatus.
|
|
||||||
|
|
||||||
This may be possible to fix with a clever usage of the AudioUnit API.
|
|
||||||
|
|
||||||
4. When new volumes are inserted, our volume information is not updated. The only way
|
|
||||||
to refresh this information is to reinit the CD-ROM subsystem of SDL. To fix this,
|
|
||||||
one would probably have to fix point 1 above first, then figure out how to register
|
|
||||||
for a notification when new media is mounted in order to perform an automatic
|
|
||||||
rescan for cdfs volumes.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
So, here comes a description of how this all works.
|
|
||||||
|
|
||||||
< Initializing >
|
|
||||||
|
|
||||||
To get things rolling, we have to locate mounted volumes that contain
|
|
||||||
audio (since nearly all Macs don't have analog audio-in on the sound card).
|
|
||||||
That's easy, since these volumes have a flag that indicates this special
|
|
||||||
filesystem. See DetectAudioCDVolumes() in CDPlayer.cpp for this code.
|
|
||||||
|
|
||||||
Next, we parse the invisible .TOC.plist in the root of the volume, which gets us
|
|
||||||
the track information (number, offset, length, leadout, etc). See ReadTOCData() in
|
|
||||||
CDPlayer.cpp for the skinny on this.
|
|
||||||
|
|
||||||
|
|
||||||
< The Playback Loop >
|
|
||||||
|
|
||||||
Now come the tricky parts. Let's start with basic audio playback. When a frame
|
|
||||||
range to play is requested, we must first find the .aiff files on the volume,
|
|
||||||
hopefully in the right order. Since these files all begin with a number "1 Audio Track",
|
|
||||||
etc, this is used to determine the correct track order.
|
|
||||||
|
|
||||||
Once all files are determined, we have to find what file corresponds to the start
|
|
||||||
and length parameter to SDL_SYS_CDPlay(). Again, this is quite simple by walking the
|
|
||||||
cdrom's track list. At this point, we also save the offset to the next track and frames
|
|
||||||
remaining, if we're going to have to play another file after the first one. See
|
|
||||||
GetFileForOffset() for this code.
|
|
||||||
|
|
||||||
At this point we have all info needed to start playback, so we hand off to the LoadFile()
|
|
||||||
function, which proceeds to do its magic and plays back the file.
|
|
||||||
|
|
||||||
When the file is finished playing, CompletionProc() is invoked, at which time we can
|
|
||||||
play the next file if the previously saved next track and frames remaining
|
|
||||||
indicates that we should.
|
|
||||||
|
|
||||||
|
|
||||||
< Magic >
|
|
||||||
|
|
||||||
OK, so it's not really magic, but since I don't fully understand all the hidden details it
|
|
||||||
seems like it to me ;-) The API's involved are the AudioUnit and AudioFile API's. These
|
|
||||||
appear to be an extension of CoreAudio for creating modular playback and f/x entities.
|
|
||||||
The important thing is that CPU usage is very low and reliability is very high. You'd
|
|
||||||
be hard-pressed to find a way to stutter the playback with other CPU-intensive tasks.
|
|
||||||
|
|
||||||
One part of this magic is that it uses multiple threads, which carries the usual potential
|
|
||||||
for disaster if not handled carefully. Playback currently requires 4 additional threads:
|
|
||||||
1. The coreaudio runloop thread
|
|
||||||
2. The coreaudio device i/o thread
|
|
||||||
3. The file streaming thread
|
|
||||||
4. The notification/callback thread
|
|
||||||
|
|
||||||
The first 2 threads are necessary evil - CoreAudio creates this no matter what the situation
|
|
||||||
is (even the SDL sound implementation creates theses suckers). The last two are are created
|
|
||||||
by us.
|
|
||||||
|
|
||||||
The file is streamed from disk using a threaded double-buffer approach.
|
|
||||||
This way, the high latency operation of reading from disk can be performed without interrupting
|
|
||||||
the real-time device thread (which amounts to avoiding dropouts). The device thread grabs the
|
|
||||||
buffer that isn't being read and sends it to the CoreAudio mixer where it eventually gets
|
|
||||||
to the sound card.
|
|
||||||
|
|
||||||
The device thread posts a notification when the file streaming thread is out of data. This
|
|
||||||
notification must be handled in a separate thread to avoid potential deadlock in the
|
|
||||||
device thread. That's where the notification thread comes in. This thread is signaled
|
|
||||||
whenever a notification needs to be processed, so another file can be played back if need be.
|
|
||||||
|
|
||||||
The API in CDPlayer.cpp contains synchronization because otherwise both the notification thread
|
|
||||||
and main thread (or another other thread using the SDL CD api) can potentially call it at the same time.
|
|
||||||
|
|
||||||
************************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
#include "CDPlayer.h"
|
|
||||||
|
|
||||||
#define kErrorFakeDevice "Error: Cannot proceed since we're faking a CD-ROM device. Reinit the CD-ROM subsystem to scan for new volumes."
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,339 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_MINT
|
|
||||||
|
|
||||||
/*
|
|
||||||
Atari MetaDOS CD-ROM functions
|
|
||||||
|
|
||||||
Patrice Mandin
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <cdromio.h>
|
|
||||||
#include <metados.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/* Some ioctl() errno values which occur when the tray is empty */
|
|
||||||
#ifndef ENOMEDIUM
|
|
||||||
#define ENOMEDIUM ENOENT
|
|
||||||
#endif
|
|
||||||
#define ERRNO_TRAYEMPTY(errno) \
|
|
||||||
((errno == EIO) || (errno == ENOENT) || \
|
|
||||||
(errno == EINVAL) || (errno == ENOMEDIUM))
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 32
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned char device[3]; /* Physical device letter + ':' + '\0' */
|
|
||||||
metaopen_t metaopen; /* Infos on opened drive */
|
|
||||||
} metados_drive_t;
|
|
||||||
|
|
||||||
static metados_drive_t metados_drives[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDioctl(int id, int command, void *arg);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
metainit_t metainit = { 0, 0, 0, 0 };
|
|
||||||
metaopen_t metaopen;
|
|
||||||
int i, handle;
|
|
||||||
struct cdrom_subchnl info;
|
|
||||||
|
|
||||||
Metainit(&metainit);
|
|
||||||
if (metainit.version == NULL) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "MetaDOS not installed\n");
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metainit.drives_map == 0) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "No MetaDOS devices present\n");
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_numcds = 0;
|
|
||||||
|
|
||||||
for (i = 'A'; i <= 'Z'; i++) {
|
|
||||||
metados_drives[SDL_numcds].device[0] = 0;
|
|
||||||
metados_drives[SDL_numcds].device[1] = ':';
|
|
||||||
metados_drives[SDL_numcds].device[2] = 0;
|
|
||||||
|
|
||||||
if (metainit.drives_map & (1 << (i - 'A'))) {
|
|
||||||
handle = Metaopen(i, &metaopen);
|
|
||||||
if (handle == 0) {
|
|
||||||
|
|
||||||
info.cdsc_format = CDROM_MSF;
|
|
||||||
if ((Metaioctl
|
|
||||||
(i, METADOS_IOCTL_MAGIC, CDROMSUBCHNL, &info) == 0)
|
|
||||||
|| ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
metados_drives[SDL_numcds].device[0] = i;
|
|
||||||
++SDL_numcds;
|
|
||||||
}
|
|
||||||
|
|
||||||
Metaclose(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (metados_drives[drive].device);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
int handle;
|
|
||||||
|
|
||||||
handle =
|
|
||||||
Metaopen(metados_drives[drive].device[0],
|
|
||||||
&(metados_drives[drive].metaopen));
|
|
||||||
if (handle == 0) {
|
|
||||||
return drive;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
Metaclose(metados_drives[cdrom->id].device[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDioctl(int id, int command, void *arg)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval =
|
|
||||||
Metaioctl(metados_drives[id].device[0], METADOS_IOCTL_MAGIC, command,
|
|
||||||
arg);
|
|
||||||
if (retval < 0) {
|
|
||||||
SDL_SetError("ioctl() error: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
int i, okay;
|
|
||||||
struct cdrom_tochdr toc;
|
|
||||||
struct cdrom_tocentry entry;
|
|
||||||
|
|
||||||
/* Use standard ioctl() */
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cdrom->numtracks = toc.cdth_trk1 - toc.cdth_trk0 + 1;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read all the track TOC entries */
|
|
||||||
okay = 1;
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
cdrom->track[i].id = CDROM_LEADOUT;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].id = toc.cdth_trk0 + i;
|
|
||||||
}
|
|
||||||
entry.cdte_track = cdrom->track[i].id;
|
|
||||||
entry.cdte_format = CDROM_MSF;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY, &entry) < 0) {
|
|
||||||
okay = 0;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (entry.cdte_ctrl & CDROM_DATA_TRACK) {
|
|
||||||
cdrom->track[i].type = SDL_DATA_TRACK;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].type = SDL_AUDIO_TRACK;
|
|
||||||
}
|
|
||||||
cdrom->track[i].offset =
|
|
||||||
MSF_TO_FRAMES(entry.cdte_addr.msf.minute,
|
|
||||||
entry.cdte_addr.msf.second,
|
|
||||||
entry.cdte_addr.msf.frame);
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
struct cdrom_tochdr toc;
|
|
||||||
struct cdrom_subchnl info;
|
|
||||||
|
|
||||||
info.cdsc_format = CDROM_MSF;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDROMSUBCHNL, &info) < 0) {
|
|
||||||
if (ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
} else {
|
|
||||||
status = CD_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (info.cdsc_audiostatus) {
|
|
||||||
case CDROM_AUDIO_INVALID:
|
|
||||||
case CDROM_AUDIO_NO_STATUS:
|
|
||||||
/* Try to determine if there's a CD available */
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc) == 0) {
|
|
||||||
status = CD_STOPPED;
|
|
||||||
} else {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_COMPLETED:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_PLAY:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_PAUSED:
|
|
||||||
/* Workaround buggy CD-ROM drive */
|
|
||||||
if (info.cdsc_trk == CDROM_LEADOUT) {
|
|
||||||
status = CD_STOPPED;
|
|
||||||
} else {
|
|
||||||
status = CD_PAUSED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
*position = MSF_TO_FRAMES(info.cdsc_absaddr.msf.minute,
|
|
||||||
info.cdsc_absaddr.msf.second,
|
|
||||||
info.cdsc_absaddr.msf.frame);
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
struct cdrom_msf playtime;
|
|
||||||
|
|
||||||
FRAMES_TO_MSF(start,
|
|
||||||
&playtime.cdmsf_min0, &playtime.cdmsf_sec0,
|
|
||||||
&playtime.cdmsf_frame0);
|
|
||||||
FRAMES_TO_MSF(start + length, &playtime.cdmsf_min1, &playtime.cdmsf_sec1,
|
|
||||||
&playtime.cdmsf_frame1);
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
|
|
||||||
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
|
|
||||||
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_MINT */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,430 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_OPENBSD
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/cdio.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Some ioctl() errno values which occur when the tray is empty */
|
|
||||||
#define ERRNO_TRAYEMPTY(errno) \
|
|
||||||
((errno == EIO) || (errno == ENOENT) || (errno == EINVAL) || \
|
|
||||||
(errno == ENODEV))
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int is_cd, cdfd;
|
|
||||||
struct ioc_read_subchannel info;
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, stbuf) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
|
||||||
is_cd = 0;
|
|
||||||
if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode)) {
|
|
||||||
cdfd = open(drive, (O_RDONLY | O_EXCL | O_NONBLOCK), 0);
|
|
||||||
if (cdfd >= 0) {
|
|
||||||
info.address_format = CD_MSF_FORMAT;
|
|
||||||
info.data_format = CD_CURRENT_POSITION;
|
|
||||||
info.data_len = 0;
|
|
||||||
info.data = NULL;
|
|
||||||
/* Under Linux, EIO occurs when a disk is not present.
|
|
||||||
This isn't 100% reliable, so we use the USE_MNTENT
|
|
||||||
code above instead.
|
|
||||||
*/
|
|
||||||
if ((ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) ||
|
|
||||||
ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
close(cdfd);
|
|
||||||
} else if (ERRNO_TRAYEMPTY(errno))
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
return (is_cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Check to make sure it's not already in our list.
|
|
||||||
This can happen when we see a drive via symbolic link.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
if (stbuf->st_rdev == SDL_cdmode[i]) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Duplicate drive detected: %s == %s\n",
|
|
||||||
drive, SDL_cdlist[i]);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_cdmode[i] = stbuf->st_rdev;
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
static char *checklist[] = {
|
|
||||||
#if defined(__OPENBSD__)
|
|
||||||
"?0 cd?c", "cdrom", NULL
|
|
||||||
#elif defined(__NETBSD__)
|
|
||||||
"?0 cd?d", "?0 cd?c", "cdrom", NULL
|
|
||||||
#else
|
|
||||||
"?0 cd?c", "?0 acd?c", "cdrom", NULL
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
char *SDLcdrom;
|
|
||||||
int i, j, exists;
|
|
||||||
char drive[32];
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
if (CheckDrive(SDLcdrom, &stbuf) > 0) {
|
|
||||||
AddDrive(SDLcdrom, &stbuf);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives */
|
|
||||||
for (i = 0; checklist[i]; ++i) {
|
|
||||||
if (checklist[i][0] == '?') {
|
|
||||||
char *insert;
|
|
||||||
exists = 1;
|
|
||||||
for (j = checklist[i][1]; exists; ++j) {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
&checklist[i][3]);
|
|
||||||
insert = SDL_strchr(drive, '?');
|
|
||||||
if (insert != NULL) {
|
|
||||||
*insert = j;
|
|
||||||
}
|
|
||||||
switch (CheckDrive(drive, &stbuf)) {
|
|
||||||
/* Drive exists and is a CD-ROM */
|
|
||||||
case 1:
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
break;
|
|
||||||
/* Drive exists, but isn't a CD-ROM */
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
/* Drive doesn't exist */
|
|
||||||
case -1:
|
|
||||||
exists = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
checklist[i]);
|
|
||||||
if (CheckDrive(drive, &stbuf) > 0) {
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General ioctl() CD-ROM command function */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDioctl(int id, int command, void *arg)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = ioctl(id, command, arg);
|
|
||||||
if (retval < 0) {
|
|
||||||
SDL_SetError("ioctl() error: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
return (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
return (open(SDL_cdlist[drive], (O_RDONLY | O_EXCL | O_NONBLOCK), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct ioc_toc_header toc;
|
|
||||||
int i, okay;
|
|
||||||
struct ioc_read_toc_entry entry;
|
|
||||||
struct cd_toc_entry data;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0) {
|
|
||||||
cdrom->numtracks = toc.ending_track - toc.starting_track + 1;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
/* Read all the track TOC entries */
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].id = toc.starting_track + i;
|
|
||||||
}
|
|
||||||
entry.starting_track = cdrom->track[i].id;
|
|
||||||
entry.address_format = CD_MSF_FORMAT;
|
|
||||||
entry.data_len = sizeof(data);
|
|
||||||
entry.data = &data;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS, &entry) < 0) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].type = data.control;
|
|
||||||
cdrom->track[i].offset =
|
|
||||||
MSF_TO_FRAMES(data.addr.msf.minute,
|
|
||||||
data.addr.msf.second, data.addr.msf.frame);
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == (cdrom->numtracks + 1)) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
struct ioc_toc_header toc;
|
|
||||||
struct ioc_read_subchannel info;
|
|
||||||
struct cd_sub_channel_info data;
|
|
||||||
|
|
||||||
info.address_format = CD_MSF_FORMAT;
|
|
||||||
info.data_format = CD_CURRENT_POSITION;
|
|
||||||
info.track = 0;
|
|
||||||
info.data_len = sizeof(data);
|
|
||||||
info.data = &data;
|
|
||||||
if (ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0) {
|
|
||||||
if (ERRNO_TRAYEMPTY(errno)) {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
} else {
|
|
||||||
status = CD_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (data.header.audio_status) {
|
|
||||||
case CD_AS_AUDIO_INVALID:
|
|
||||||
case CD_AS_NO_STATUS:
|
|
||||||
/* Try to determine if there's a CD available */
|
|
||||||
if (ioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0)
|
|
||||||
status = CD_STOPPED;
|
|
||||||
else
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
break;
|
|
||||||
case CD_AS_PLAY_COMPLETED:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case CD_AS_PLAY_IN_PROGRESS:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case CD_AS_PLAY_PAUSED:
|
|
||||||
status = CD_PAUSED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
*position =
|
|
||||||
MSF_TO_FRAMES(data.what.position.absaddr.msf.minute,
|
|
||||||
data.what.position.absaddr.msf.second,
|
|
||||||
data.what.position.absaddr.msf.frame);
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
struct ioc_play_msf playtime;
|
|
||||||
|
|
||||||
FRAMES_TO_MSF(start,
|
|
||||||
&playtime.start_m, &playtime.start_s, &playtime.start_f);
|
|
||||||
FRAMES_TO_MSF(start + length,
|
|
||||||
&playtime.end_m, &playtime.end_s, &playtime.end_f);
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
|
|
||||||
playtime.start_m, playtime.start_s, playtime.start_f,
|
|
||||||
playtime.end_m, playtime.end_s, playtime.end_f);
|
|
||||||
#endif
|
|
||||||
ioctl(cdrom->id, CDIOCSTART, 0);
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_OPENBSD */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,442 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_OS2
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#define INCL_MCIOS2
|
|
||||||
#include <os2.h>
|
|
||||||
#include <os2me.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/* Size of MCI result buffer (in bytes) */
|
|
||||||
#define MCI_CMDRETBUFSIZE 128
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
//static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* MCI Timing Functions */
|
|
||||||
#define MCI_MMTIMEPERSECOND 3000
|
|
||||||
#define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND)
|
|
||||||
|
|
||||||
|
|
||||||
/* Ready for MCI CDAudio Devices */
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
int i; /* generig counter */
|
|
||||||
MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */
|
|
||||||
CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Get the number of CD ROMs in the System */
|
|
||||||
/* Clean SysInfo structure */
|
|
||||||
SDL_memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS));
|
|
||||||
/* Prepare structure to Ask Numer of Audio CDs */
|
|
||||||
msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */
|
|
||||||
msp.pszReturn = (PSZ) & SysInfoRet; /* Return Structure */
|
|
||||||
msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(0, MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID) & msp,
|
|
||||||
0)) != MCIERR_SUCCESS)
|
|
||||||
return (CD_ERROR);
|
|
||||||
SDL_numcds = atoi(SysInfoRet);
|
|
||||||
if (SDL_numcds > MAX_DRIVES)
|
|
||||||
SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */
|
|
||||||
|
|
||||||
/* Get and Add their system name to the SDL_cdlist */
|
|
||||||
msp.pszReturn = (PSZ) & SysInfoRet; /* Return Structure */
|
|
||||||
msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */
|
|
||||||
msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */
|
|
||||||
for (i = 0; i < SDL_numcds; i++) {
|
|
||||||
msp.ulNumber = i + 1;
|
|
||||||
mciSendCommand(0, MCI_SYSINFO, MCI_SYSINFO_NAME | MCI_WAIT, &msp, 0);
|
|
||||||
SDL_cdlist[i] = SDL_strdup(SysInfoRet);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return CDAudio System Dependent Device Name - Ready for MCI*/
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open CDAudio Device - Ready for MCI */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
MCI_OPEN_PARMS mop;
|
|
||||||
MCI_SET_PARMS msp;
|
|
||||||
MCI_GENERIC_PARMS mgp;
|
|
||||||
|
|
||||||
/* Open the device */
|
|
||||||
mop.hwndCallback = (HWND) NULL; // None
|
|
||||||
mop.usDeviceID = (USHORT) NULL; // Will be returned.
|
|
||||||
mop.pszDeviceType = (PSZ) SDL_cdlist[drive]; // CDAudio Device
|
|
||||||
if (LOUSHORT(mciSendCommand(0, MCI_OPEN, MCI_WAIT, &mop, 0)) !=
|
|
||||||
MCIERR_SUCCESS)
|
|
||||||
return (CD_ERROR);
|
|
||||||
/* Set time format */
|
|
||||||
msp.hwndCallback = (HWND) NULL; // None
|
|
||||||
msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure
|
|
||||||
msp.ulSpeedFormat = (ULONG) NULL; // No change
|
|
||||||
msp.ulAudio = (ULONG) NULL; // No Channel
|
|
||||||
msp.ulLevel = (ULONG) NULL; // No Volume
|
|
||||||
msp.ulOver = (ULONG) NULL; // No Delay
|
|
||||||
msp.ulItem = (ULONG) NULL; // No item
|
|
||||||
msp.ulValue = (ULONG) NULL; // No value for item flag
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(mop.usDeviceID, MCI_SET, MCI_WAIT | MCI_SET_TIME_FORMAT, &msp,
|
|
||||||
0)) == MCIERR_SUCCESS)
|
|
||||||
return (mop.usDeviceID);
|
|
||||||
/* Error setting time format? - Close opened device */
|
|
||||||
mgp.hwndCallback = (HWND) NULL; // None
|
|
||||||
mciSendCommand(mop.usDeviceID, MCI_CLOSE, MCI_WAIT, &mgp, 0);
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD Table Of Contents - Ready for MCI */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
MCI_TOC_PARMS mtp;
|
|
||||||
MCI_STATUS_PARMS msp;
|
|
||||||
MCI_TOC_REC *mtr;
|
|
||||||
INT i;
|
|
||||||
|
|
||||||
/* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */
|
|
||||||
if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Get Number of Tracks */
|
|
||||||
msp.hwndCallback = (HWND) NULL; /* None */
|
|
||||||
msp.ulReturn = (ULONG) NULL; /* We want this information */
|
|
||||||
msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS;
|
|
||||||
msp.ulValue = (ULONG) NULL; /* No additional information */
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(cdrom->id, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, &msp,
|
|
||||||
0)) != MCIERR_SUCCESS)
|
|
||||||
return (CD_ERROR);
|
|
||||||
cdrom->numtracks = msp.ulReturn;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
/* Alocate space for TOC data */
|
|
||||||
mtr = (MCI_TOC_REC *) SDL_malloc(cdrom->numtracks * sizeof(MCI_TOC_REC));
|
|
||||||
if (mtr == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
/* Get TOC from CD */
|
|
||||||
mtp.pBuf = mtr;
|
|
||||||
mtp.ulBufSize = cdrom->numtracks * sizeof(MCI_TOC_REC);
|
|
||||||
if (LOUSHORT(mciSendCommand(cdrom->id, MCI_GETTOC, MCI_WAIT, &mtp, 0))
|
|
||||||
!= MCIERR_SUCCESS) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
SDL_free(mtr);
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
/* Fill SDL Tracks Structure */
|
|
||||||
for (i = 0; i < cdrom->numtracks; i++) {
|
|
||||||
/* Set Track ID */
|
|
||||||
cdrom->track[i].id = (mtr + i)->TrackNum;
|
|
||||||
/* Set Track Type */
|
|
||||||
msp.hwndCallback = (HWND) NULL; /* None */
|
|
||||||
msp.ulReturn = (ULONG) NULL; /* We want this information */
|
|
||||||
msp.ulItem = MCI_CD_STATUS_TRACK_TYPE;
|
|
||||||
msp.ulValue = (ULONG) ((mtr + i)->TrackNum); /* Track Number? */
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(cdrom->id, MCI_STATUS, MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,
|
|
||||||
&msp, 0)) != MCIERR_SUCCESS) {
|
|
||||||
SDL_free(mtr);
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
if (msp.ulReturn == MCI_CD_TRACK_AUDIO)
|
|
||||||
cdrom->track[i].type = SDL_AUDIO_TRACK;
|
|
||||||
else
|
|
||||||
cdrom->track[i].type = SDL_DATA_TRACK;
|
|
||||||
/* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */
|
|
||||||
cdrom->track[i].length =
|
|
||||||
FRAMESFROMMM((mtr + i)->ulEndAddr - (mtr + i)->ulStartAddr);
|
|
||||||
/* Set Track Offset */
|
|
||||||
cdrom->track[i].offset = FRAMESFROMMM((mtr + i)->ulStartAddr);
|
|
||||||
}
|
|
||||||
SDL_free(mtr);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Get CD-ROM status - Ready for MCI */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
MCI_STATUS_PARMS msp;
|
|
||||||
|
|
||||||
/* Get Status from MCI */
|
|
||||||
msp.hwndCallback = (HWND) NULL; /* None */
|
|
||||||
msp.ulReturn = (ULONG) NULL; /* We want this information */
|
|
||||||
msp.ulItem = MCI_STATUS_MODE;
|
|
||||||
msp.ulValue = (ULONG) NULL; /* No additional information */
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(cdrom->id, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, &msp,
|
|
||||||
0)) != MCIERR_SUCCESS)
|
|
||||||
status = CD_ERROR;
|
|
||||||
else {
|
|
||||||
switch (msp.ulReturn) {
|
|
||||||
case MCI_MODE_NOT_READY:
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
break;
|
|
||||||
case MCI_MODE_PAUSE:
|
|
||||||
status = CD_PAUSED;
|
|
||||||
break;
|
|
||||||
case MCI_MODE_PLAY:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case MCI_MODE_STOP:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
/* These cases should not occour */
|
|
||||||
case MCI_MODE_RECORD:
|
|
||||||
case MCI_MODE_SEEK:
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine position */
|
|
||||||
if (position != NULL) { /* The SDL $&$&%# CDROM call sends NULL pointer here! */
|
|
||||||
if ((status == CD_PLAYING) || (status == CD_PAUSED)) {
|
|
||||||
/* Get Position */
|
|
||||||
msp.hwndCallback = (HWND) NULL; /* None */
|
|
||||||
msp.ulReturn = (ULONG) NULL; /* We want this information */
|
|
||||||
msp.ulItem = MCI_STATUS_POSITION;
|
|
||||||
msp.ulValue = (ULONG) NULL; /* No additiona info */
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(cdrom->id, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, &msp,
|
|
||||||
0)) != MCIERR_SUCCESS)
|
|
||||||
return (CD_ERROR);
|
|
||||||
/* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */
|
|
||||||
*position =
|
|
||||||
MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),
|
|
||||||
MSF_SECOND(msp.ulReturn),
|
|
||||||
MSF_FRAME(msp.ulReturn));
|
|
||||||
} else
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play - Ready for MCI */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
MCI_GENERIC_PARMS mgp;
|
|
||||||
MCI_STATUS_PARMS msp;
|
|
||||||
MCI_PLAY_PARMS mpp;
|
|
||||||
ULONG min, sec, frm;
|
|
||||||
|
|
||||||
/* Start MSF */
|
|
||||||
FRAMES_TO_MSF(start, &min, &sec, &frm);
|
|
||||||
MSF_MINUTE(mpp.ulFrom) = min;
|
|
||||||
MSF_SECOND(mpp.ulFrom) = sec;
|
|
||||||
MSF_FRAME(mpp.ulFrom) = frm;
|
|
||||||
/* End MSF */
|
|
||||||
FRAMES_TO_MSF(start + length, &min, &sec, &frm);
|
|
||||||
MSF_MINUTE(mpp.ulTo) = min;
|
|
||||||
MSF_SECOND(mpp.ulTo) = sec;
|
|
||||||
MSF_FRAME(mpp.ulTo) = frm;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
|
|
||||||
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
|
|
||||||
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
|
|
||||||
#endif
|
|
||||||
/* Verifies if it is paused first... and if it is, unpause before stopping it. */
|
|
||||||
msp.hwndCallback = (HWND) NULL; /* None */
|
|
||||||
msp.ulReturn = (ULONG) NULL; /* We want this information */
|
|
||||||
msp.ulItem = MCI_STATUS_MODE;
|
|
||||||
msp.ulValue = (ULONG) NULL; /* No additional information */
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(cdrom->id, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, &msp,
|
|
||||||
0)) == MCIERR_SUCCESS) {
|
|
||||||
if (msp.ulReturn == MCI_MODE_PAUSE) {
|
|
||||||
mgp.hwndCallback = (HWND) NULL; // None
|
|
||||||
mciSendCommand(cdrom->id, MCI_RESUME, 0, &mgp, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Now play it. */
|
|
||||||
mpp.hwndCallback = (HWND) NULL; // We do not want the info. temp
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand(cdrom->id, MCI_PLAY, MCI_FROM | MCI_TO, &mpp, 0)) ==
|
|
||||||
MCIERR_SUCCESS)
|
|
||||||
return 0;
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play - Ready for MCI */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
MCI_GENERIC_PARMS mgp;
|
|
||||||
|
|
||||||
mgp.hwndCallback = (HWND) NULL; // None
|
|
||||||
if (LOUSHORT(mciSendCommand(cdrom->id, MCI_PAUSE, MCI_WAIT, &mgp, 0)) ==
|
|
||||||
MCIERR_SUCCESS)
|
|
||||||
return 0;
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play - Ready for MCI */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
MCI_GENERIC_PARMS mgp;
|
|
||||||
|
|
||||||
mgp.hwndCallback = (HWND) NULL; // None
|
|
||||||
if (LOUSHORT(mciSendCommand(cdrom->id, MCI_RESUME, MCI_WAIT, &mgp, 0))
|
|
||||||
== MCIERR_SUCCESS)
|
|
||||||
return 0;
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play - Ready for MCI */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
MCI_GENERIC_PARMS mgp;
|
|
||||||
MCI_STATUS_PARMS msp;
|
|
||||||
|
|
||||||
/* Verifies if it is paused first... and if it is, unpause before stopping it. */
|
|
||||||
msp.hwndCallback = (HWND) NULL; /* None */
|
|
||||||
msp.ulReturn = (ULONG) NULL; /* We want this information */
|
|
||||||
msp.ulItem = MCI_STATUS_MODE;
|
|
||||||
msp.ulValue = (ULONG) NULL; /* No additional information */
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(cdrom->id, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, &msp,
|
|
||||||
0)) == MCIERR_SUCCESS) {
|
|
||||||
if (msp.ulReturn == MCI_MODE_PAUSE) {
|
|
||||||
mgp.hwndCallback = (HWND) NULL; // None
|
|
||||||
mciSendCommand(cdrom->id, MCI_RESUME, 0, &mgp, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Now stops the media */
|
|
||||||
mgp.hwndCallback = (HWND) NULL; // None
|
|
||||||
if (LOUSHORT(mciSendCommand(cdrom->id, MCI_STOP, MCI_WAIT, &mgp, 0)) ==
|
|
||||||
MCIERR_SUCCESS)
|
|
||||||
return 0;
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM - Ready for MCI */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
MCI_SET_PARMS msp;
|
|
||||||
|
|
||||||
msp.hwndCallback = (HWND) NULL; // None
|
|
||||||
msp.ulTimeFormat = (ULONG) NULL; // No change
|
|
||||||
msp.ulSpeedFormat = (ULONG) NULL; // No change
|
|
||||||
msp.ulAudio = (ULONG) NULL; // No Channel
|
|
||||||
msp.ulLevel = (ULONG) NULL; // No Volume
|
|
||||||
msp.ulOver = (ULONG) NULL; // No Delay
|
|
||||||
msp.ulItem = (ULONG) NULL; // No item
|
|
||||||
msp.ulValue = (ULONG) NULL; // No value for item flag
|
|
||||||
if (LOUSHORT
|
|
||||||
(mciSendCommand
|
|
||||||
(cdrom->id, MCI_SET, MCI_WAIT | MCI_SET_DOOR_OPEN, &msp,
|
|
||||||
0)) == MCIERR_SUCCESS)
|
|
||||||
return 0;
|
|
||||||
return (CD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle - Ready for MCI */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
MCI_GENERIC_PARMS mgp;
|
|
||||||
|
|
||||||
mgp.hwndCallback = (HWND) NULL; // None
|
|
||||||
mciSendCommand(cdrom->id, MCI_CLOSE, MCI_WAIT, &mgp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finalize CDROM Subsystem - Ready for MCI */
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_OS2 */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,464 +0,0 @@
|
||||||
/*
|
|
||||||
Tru64 audio module for SDL (Simple DirectMedia Layer)
|
|
||||||
Copyright (C) 2003
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the Free
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_OSF
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
/* #define DEBUG_CDROM 1 */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <io/cam/cdrom.h>
|
|
||||||
#include <io/cam/rzdisk.h>
|
|
||||||
#include <io/common/devgetinfo.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
/* Caution!! Not tested. */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int cdfd, is_cd = 0;
|
|
||||||
struct mode_sel_sns_params msp;
|
|
||||||
struct inquiry_info inq;
|
|
||||||
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
char *devtype[] = { "Disk", "Tape", "Printer", "Processor", "WORM",
|
|
||||||
"CD-ROM", "Scanner", "Optical", "Changer", "Comm", "Unknown"
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bzero(&msp, sizeof(msp));
|
|
||||||
bzero(&inq, sizeof(inq));
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, stbuf) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cdfd = open(drive, (O_RDWR | O_NDELAY), 0)) >= 0) {
|
|
||||||
msp.msp_addr = (caddr_t) & inq;
|
|
||||||
msp.msp_pgcode = 0;
|
|
||||||
msp.msp_pgctrl = 0;
|
|
||||||
msp.msp_length = sizeof(inq);
|
|
||||||
msp.msp_setps = 0;
|
|
||||||
|
|
||||||
if (ioctl(cdfd, SCSI_GET_INQUIRY_DATA, &msp))
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Device Type: %s\n", devtype[inq.perfdt]);
|
|
||||||
fprintf(stderr, "Vendor: %.8s\n", inq.vndrid);
|
|
||||||
fprintf(stderr, "Product: %.8s\n", inq.prodid);
|
|
||||||
fprintf(stderr, "Revision: %.8s\n", inq.revlvl);
|
|
||||||
#endif
|
|
||||||
if (inq.perfdt == DTYPE_RODIRECT)
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (is_cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Check to make sure it's not already in our list.
|
|
||||||
* This can happen when we see a drive via symbolic link.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
if (stbuf->st_rdev == SDL_cdmode[i]) {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Duplicate drive detected: %s == %s\n",
|
|
||||||
drive, SDL_cdlist[i]);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_cdmode[i] = stbuf->st_rdev;
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* checklist:
|
|
||||||
*
|
|
||||||
* Tru64 5.X (/dev/rdisk/cdrom?c)
|
|
||||||
* dir: /dev/rdisk, name: cdrom
|
|
||||||
*
|
|
||||||
* Digital UNIX 4.0X (/dev/rrz?c)
|
|
||||||
* dir: /dev, name: rrz
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char *dir;
|
|
||||||
char *name;
|
|
||||||
} checklist[] = {
|
|
||||||
{
|
|
||||||
"/dev/rdisk", "cdrom"}, {
|
|
||||||
"/dev", "rrz"}, {
|
|
||||||
NULL, NULL}};
|
|
||||||
char drive[32];
|
|
||||||
char *SDLcdrom;
|
|
||||||
int i, j, exists;
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
if (CheckDrive(SDLcdrom, &stbuf) > 0) {
|
|
||||||
AddDrive(SDLcdrom, &stbuf);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Scan the system for CD-ROM drives */
|
|
||||||
for (i = 0; checklist[i].dir; ++i) {
|
|
||||||
DIR *devdir;
|
|
||||||
struct dirent *devent;
|
|
||||||
int name_len;
|
|
||||||
|
|
||||||
devdir = opendir(checklist[i].dir);
|
|
||||||
if (devdir) {
|
|
||||||
name_len = SDL_strlen(checklist[i].name);
|
|
||||||
while (devent = readdir(devdir))
|
|
||||||
if (SDL_memcmp
|
|
||||||
(checklist[i].name, devent->d_name, name_len) == 0)
|
|
||||||
if (devent->d_name[devent->d_namlen - 1] == 'c') {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive),
|
|
||||||
"%s/%s", checklist[i].dir,
|
|
||||||
devent->d_name);
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "Try to add drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
if (CheckDrive(drive, &stbuf) > 0)
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
}
|
|
||||||
closedir(devdir);
|
|
||||||
} else {
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "cannot open dir: %s\n", checklist[i].dir);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
/* O_RDWR: To use ioctl(fd, SCSI_STOP_UNIT) */
|
|
||||||
return (open(SDL_cdlist[drive], (O_RDWR | O_NDELAY), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
struct cd_toc toc;
|
|
||||||
struct cd_toc_header hdr;
|
|
||||||
struct cd_toc_entry *cdte;
|
|
||||||
int i;
|
|
||||||
int okay = 0;
|
|
||||||
if (ioctl(cdrom->id, CDROM_TOC_HEADER, &hdr)) {
|
|
||||||
fprintf(stderr, "ioctl error CDROM_TOC_HEADER\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cdrom->numtracks = hdr.th_ending_track - hdr.th_starting_track + 1;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "hdr.th_data_len1 = %d\n", hdr.th_data_len1);
|
|
||||||
fprintf(stderr, "hdr.th_data_len0 = %d\n", hdr.th_data_len0);
|
|
||||||
fprintf(stderr, "hdr.th_starting_track = %d\n", hdr.th_starting_track);
|
|
||||||
fprintf(stderr, "hdr.th_ending_track = %d\n", hdr.th_ending_track);
|
|
||||||
fprintf(stderr, "cdrom->numtracks = %d\n", cdrom->numtracks);
|
|
||||||
#endif
|
|
||||||
toc.toc_address_format = CDROM_LBA_FORMAT;
|
|
||||||
toc.toc_starting_track = 0;
|
|
||||||
toc.toc_alloc_length = (hdr.th_data_len1 << 8) +
|
|
||||||
hdr.th_data_len0 + sizeof(hdr);
|
|
||||||
if ((toc.toc_buffer = alloca(toc.toc_alloc_length)) == NULL) {
|
|
||||||
fprintf(stderr, "cannot allocate toc.toc_buffer\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bzero(toc.toc_buffer, toc.toc_alloc_length);
|
|
||||||
if (ioctl(cdrom->id, CDROM_TOC_ENTRYS, &toc)) {
|
|
||||||
fprintf(stderr, "ioctl error CDROM_TOC_ENTRYS\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cdte = (struct cd_toc_entry *) ((char *) toc.toc_buffer + sizeof(hdr));
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
cdrom->track[i].id = 0xAA;;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].id = hdr.th_starting_track + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
cdrom->track[i].type = cdte[i].te_control & CDROM_DATA_TRACK;
|
|
||||||
cdrom->track[i].offset =
|
|
||||||
cdte[i].te_absaddr.lba.addr3 << 24 |
|
|
||||||
cdte[i].te_absaddr.lba.addr2 << 16 |
|
|
||||||
cdte[i].te_absaddr.lba.addr1 << 8 | cdte[i].te_absaddr.lba.addr0;
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
for (i = 0; i <= cdrom->numtracks; i++) {
|
|
||||||
fprintf(stderr, "toc_entry[%d].te_track_number = %d\n",
|
|
||||||
i, cdte[i].te_track_number);
|
|
||||||
fprintf(stderr, "cdrom->track[%d].id = %d\n", i, cdrom->track[i].id);
|
|
||||||
fprintf(stderr, "cdrom->track[%d].type = %x\n", i,
|
|
||||||
cdrom->track[i].type);
|
|
||||||
fprintf(stderr, "cdrom->track[%d].offset = %d\n", i,
|
|
||||||
cdrom->track[i].offset);
|
|
||||||
fprintf(stderr, "cdrom->track[%d].length = %d\n", i,
|
|
||||||
cdrom->track[i].length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (i == (cdrom->numtracks + 1)) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
struct cd_sub_channel sc;
|
|
||||||
struct cd_subc_channel_data scd;
|
|
||||||
|
|
||||||
sc.sch_address_format = CDROM_LBA_FORMAT;
|
|
||||||
sc.sch_data_format = CDROM_CURRENT_POSITION;
|
|
||||||
sc.sch_track_number = 0;
|
|
||||||
sc.sch_alloc_length = sizeof(scd);
|
|
||||||
sc.sch_buffer = (caddr_t) & scd;
|
|
||||||
if (ioctl(cdrom->id, CDROM_READ_SUBCHANNEL, &sc)) {
|
|
||||||
status = CD_ERROR;
|
|
||||||
fprintf(stderr, "ioctl error CDROM_READ_SUBCHANNEL \n");
|
|
||||||
} else {
|
|
||||||
switch (scd.scd_header.sh_audio_status) {
|
|
||||||
case AS_AUDIO_INVALID:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case AS_PLAY_IN_PROGRESS:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case AS_PLAY_PAUSED:
|
|
||||||
status = CD_PAUSED;
|
|
||||||
break;
|
|
||||||
case AS_PLAY_COMPLETED:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case AS_PLAY_ERROR:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
case AS_NO_STATUS:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_CDROM
|
|
||||||
fprintf(stderr, "scd.scd_header.sh_audio_status = %x\n",
|
|
||||||
scd.scd_header.sh_audio_status);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
*position =
|
|
||||||
scd.scd_position_data.scp_absaddr.lba.addr3 << 24 |
|
|
||||||
scd.scd_position_data.scp_absaddr.lba.addr2 << 16 |
|
|
||||||
scd.scd_position_data.scp_absaddr.lba.addr1 << 8 |
|
|
||||||
scd.scd_position_data.scp_absaddr.lba.addr0;
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Play MSF
|
|
||||||
*/
|
|
||||||
struct cd_play_audio_msf msf;
|
|
||||||
int end;
|
|
||||||
|
|
||||||
bzero(&msf, sizeof(msf));
|
|
||||||
end = start + length;
|
|
||||||
FRAMES_TO_MSF(start + 150, /* LBA = 4500*M + 75*S + F - 150 */
|
|
||||||
&msf.msf_starting_M_unit,
|
|
||||||
&msf.msf_starting_S_unit, &msf.msf_starting_F_unit);
|
|
||||||
FRAMES_TO_MSF(end + 150, /* LBA = 4500*M + 75*S + F - 150 */
|
|
||||||
&msf.msf_ending_M_unit,
|
|
||||||
&msf.msf_ending_S_unit, &msf.msf_ending_F_unit);
|
|
||||||
|
|
||||||
return (ioctl(cdrom->id, CDROM_PLAY_AUDIO_MSF, &msf));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (ioctl(cdrom->id, CDROM_PAUSE_PLAY));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (ioctl(cdrom->id, CDROM_RESUME_PLAY));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (ioctl(cdrom->id, SCSI_STOP_UNIT));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (ioctl(cdrom->id, CDROM_EJECT_CADDY));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_OSF */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,507 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_QNX
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/cdrom.h>
|
|
||||||
#include <sys/dcmd_cam.h>
|
|
||||||
|
|
||||||
#include "SDL_timer.h"
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect */
|
|
||||||
#define MAX_DRIVES 16
|
|
||||||
|
|
||||||
#define QNX_CD_OPENMODE O_RDONLY | O_EXCL
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static dev_t SDL_cdmode[MAX_DRIVES];
|
|
||||||
static int SDL_cdopen[MAX_DRIVES];
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
/* Check a drive to see if it is a CD-ROM */
|
|
||||||
static int
|
|
||||||
CheckDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int is_cd, cdfd;
|
|
||||||
cam_devinfo_t dinfo;
|
|
||||||
int devctlret = 0;
|
|
||||||
|
|
||||||
int atapi;
|
|
||||||
int removable;
|
|
||||||
int cdb10;
|
|
||||||
|
|
||||||
/* If it doesn't exist, return -1 */
|
|
||||||
if (stat(drive, stbuf) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If it does exist, verify that it's an available CD-ROM */
|
|
||||||
is_cd = 0;
|
|
||||||
|
|
||||||
if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode)) {
|
|
||||||
cdfd = open(drive, QNX_CD_OPENMODE);
|
|
||||||
if (cdfd >= 0) {
|
|
||||||
devctlret =
|
|
||||||
devctl(cdfd, DCMD_CAM_DEVINFO, &dinfo,
|
|
||||||
sizeof(cam_devinfo_t), NULL);
|
|
||||||
|
|
||||||
if (devctlret == EOK) {
|
|
||||||
atapi = dinfo.flags & DEV_ATAPI;
|
|
||||||
removable = dinfo.flags & DEV_REMOVABLE;
|
|
||||||
cdb10 = dinfo.flags & DEV_CDB_10; /* I'm not sure about that flag */
|
|
||||||
|
|
||||||
/* in the near future need to add more checks for splitting cdroms from other devices */
|
|
||||||
if ((atapi) && (removable)) {
|
|
||||||
is_cd = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(cdfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (is_cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Check to make sure it's not already in our list.
|
|
||||||
This can happen when we see a drive via symbolic link. */
|
|
||||||
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
if (stbuf->st_rdev == SDL_cdmode[i]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add this drive to our list */
|
|
||||||
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SDL_cdmode[i] = stbuf->st_rdev;
|
|
||||||
++SDL_numcds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* checklist: /dev/cdrom, /dev/cd?, /dev/scd? */
|
|
||||||
static char *checklist[] =
|
|
||||||
{ "cdrom", "?0 cd?", "?1 cd?", "?0 scd?", NULL };
|
|
||||||
|
|
||||||
char *SDLcdrom;
|
|
||||||
int i, j, exists;
|
|
||||||
char drive[32];
|
|
||||||
struct stat stbuf;
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* clearing device open status */
|
|
||||||
for (i = 0; i < MAX_DRIVES; i++) {
|
|
||||||
SDL_cdopen[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look in the environment for our CD-ROM drive list */
|
|
||||||
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
|
|
||||||
if (SDLcdrom != NULL) {
|
|
||||||
char *cdpath, *delim;
|
|
||||||
size_t len = SDL_strlen(SDLcdrom) + 1;
|
|
||||||
cdpath = SDL_stack_alloc(char, len);
|
|
||||||
if (cdpath != NULL) {
|
|
||||||
SDL_strlcpy(cdpath, SDLcdrom, len);
|
|
||||||
SDLcdrom = cdpath;
|
|
||||||
do {
|
|
||||||
delim = SDL_strchr(SDLcdrom, ':');
|
|
||||||
if (delim) {
|
|
||||||
*delim++ = '\0';
|
|
||||||
}
|
|
||||||
if (CheckDrive(SDLcdrom, &stbuf) > 0) {
|
|
||||||
AddDrive(SDLcdrom, &stbuf);
|
|
||||||
}
|
|
||||||
if (delim) {
|
|
||||||
SDLcdrom = delim;
|
|
||||||
} else {
|
|
||||||
SDLcdrom = NULL;
|
|
||||||
}
|
|
||||||
} while (SDLcdrom);
|
|
||||||
SDL_stack_free(cdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found our drives, there's nothing left to do */
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives */
|
|
||||||
for (i = 0; checklist[i]; ++i) {
|
|
||||||
if (checklist[i][0] == '?') {
|
|
||||||
char *insert;
|
|
||||||
exists = 1;
|
|
||||||
|
|
||||||
for (j = checklist[i][1]; exists; ++j) {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
&checklist[i][3]);
|
|
||||||
insert = SDL_strchr(drive, '?');
|
|
||||||
if (insert != NULL) {
|
|
||||||
*insert = j;
|
|
||||||
}
|
|
||||||
switch (CheckDrive(drive, &stbuf)) {
|
|
||||||
/* Drive exists and is a CD-ROM */
|
|
||||||
case 1:
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
break;
|
|
||||||
/* Drive exists, but isn't a CD-ROM */
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
/* Drive doesn't exist */
|
|
||||||
case -1:
|
|
||||||
exists = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s",
|
|
||||||
checklist[i]);
|
|
||||||
if (CheckDrive(drive, &stbuf) > 0) {
|
|
||||||
AddDrive(drive, &stbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
int handle;
|
|
||||||
|
|
||||||
handle = open(SDL_cdlist[drive], QNX_CD_OPENMODE);
|
|
||||||
|
|
||||||
if (handle > 0) {
|
|
||||||
SDL_cdopen[drive] = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
cdrom_read_toc_t toc;
|
|
||||||
int i, okay;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), NULL) ==
|
|
||||||
0) {
|
|
||||||
cdrom->numtracks = toc.last_track - toc.first_track + 1;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
/* Read all the track TOC entries */
|
|
||||||
for (i = 0; i <= cdrom->numtracks; ++i) {
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
cdrom->track[i].id = CDROM_LEADOUT;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].id = toc.first_track + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
cdrom->track[i].type = toc.toc_entry[i].control_adr & 0x0F;
|
|
||||||
cdrom->track[i].offset = toc.toc_entry[i].addr.lba;
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == (cdrom->numtracks + 1)) {
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
|
|
||||||
cdrom_read_toc_t toc;
|
|
||||||
cdrom_subch_data_t info;
|
|
||||||
cam_devinfo_t dinfo;
|
|
||||||
|
|
||||||
int devctlret = 0;
|
|
||||||
int drive = -1;
|
|
||||||
int i;
|
|
||||||
int eagaincnt = 0;
|
|
||||||
|
|
||||||
/* check media presence before read subchannel call, some cdroms can lockups */
|
|
||||||
/* if no media, while calling read subchannel functions. */
|
|
||||||
devctlret =
|
|
||||||
devctl(cdrom->id, DCMD_CAM_DEVINFO, &dinfo, sizeof(cam_devinfo_t),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (devctlret == EOK) {
|
|
||||||
if ((dinfo.flags & DEV_NO_MEDIA) != 0) {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
if (position) {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if media exists, then do other stuff */
|
|
||||||
|
|
||||||
SDL_memset(&info, 0x00, sizeof(info));
|
|
||||||
info.subch_command.data_format = CDROM_SUBCH_CURRENT_POSITION;
|
|
||||||
|
|
||||||
do {
|
|
||||||
devctlret =
|
|
||||||
devctl(cdrom->id, DCMD_CAM_CDROMSUBCHNL, &info, sizeof(info),
|
|
||||||
NULL);
|
|
||||||
if (devctlret == EIO) {
|
|
||||||
/* big workaround for media change, handle is unusable after that,
|
|
||||||
that bug was found in QNX 6.2, 6.2.1 is not released yet. */
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DRIVES; i++) {
|
|
||||||
if (SDL_cdopen[i] == cdrom->id) {
|
|
||||||
drive = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (drive == -1) {
|
|
||||||
/* that cannot happen, but ... */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
close(cdrom->id);
|
|
||||||
cdrom->id = open(SDL_cdlist[drive], QNX_CD_OPENMODE);
|
|
||||||
devctlret = EAGAIN;
|
|
||||||
}
|
|
||||||
if (devctlret == EAGAIN) {
|
|
||||||
eagaincnt++;
|
|
||||||
}
|
|
||||||
if (eagaincnt == 2) {
|
|
||||||
/* workaround for broken cdroms, which can return always EAGAIN when its not ready, */
|
|
||||||
/* that mean errornous media or just no media avail */
|
|
||||||
devctlret = ENXIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while ((devctlret == EAGAIN) || (devctlret == ESTALE));
|
|
||||||
|
|
||||||
if (devctlret != 0) {
|
|
||||||
if (devctlret == ENXIO) {
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
} else {
|
|
||||||
status = CD_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (info.current_position.header.audio_status) {
|
|
||||||
case CDROM_AUDIO_INVALID:
|
|
||||||
case CDROM_AUDIO_NO_STATUS:
|
|
||||||
/* Try to determine if there's a CD available */
|
|
||||||
if (devctl
|
|
||||||
(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc),
|
|
||||||
NULL) == 0)
|
|
||||||
status = CD_STOPPED;
|
|
||||||
else
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_COMPLETED:
|
|
||||||
status = CD_STOPPED;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_PLAY:
|
|
||||||
status = CD_PLAYING;
|
|
||||||
break;
|
|
||||||
case CDROM_AUDIO_PAUSED:
|
|
||||||
/* Workaround buggy CD-ROM drive */
|
|
||||||
if (info.current_position.data_format == CDROM_LEADOUT) {
|
|
||||||
status = CD_STOPPED;
|
|
||||||
} else {
|
|
||||||
status = CD_PAUSED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
*position =
|
|
||||||
MSF_TO_FRAMES(info.current_position.addr.msf.minute,
|
|
||||||
info.current_position.addr.msf.second,
|
|
||||||
info.current_position.addr.msf.frame);
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
cdrom_playmsf_t playtime;
|
|
||||||
|
|
||||||
FRAMES_TO_MSF(start, &playtime.start_minute, &playtime.start_second,
|
|
||||||
&playtime.start_frame);
|
|
||||||
FRAMES_TO_MSF(start + length, &playtime.end_minute, &playtime.end_second,
|
|
||||||
&playtime.end_frame);
|
|
||||||
|
|
||||||
if (devctl
|
|
||||||
(cdrom->id, DCMD_CAM_CDROMPLAYMSF, &playtime, sizeof(playtime),
|
|
||||||
NULL) != 0) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (devctl(cdrom->id, DCMD_CAM_CDROMPAUSE, NULL, 0, NULL) != 0) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (devctl(cdrom->id, DCMD_CAM_CDROMRESUME, NULL, 0, NULL) != 0) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (devctl(cdrom->id, DCMD_CAM_CDROMSTOP, NULL, 0, NULL) != 0) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
if (devctl(cdrom->id, DCMD_CAM_EJECT_MEDIA, NULL, 0, NULL) != 0) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DRIVES; i++) {
|
|
||||||
if (SDL_cdopen[i] == cdrom->id) {
|
|
||||||
SDL_cdopen[i] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(cdrom->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_QNX */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -1,400 +0,0 @@
|
||||||
/*
|
|
||||||
SDL - Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2009 Sam Lantinga
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Sam Lantinga
|
|
||||||
slouken@libsdl.org
|
|
||||||
*/
|
|
||||||
#include "SDL_config.h"
|
|
||||||
|
|
||||||
#ifdef SDL_CDROM_WIN32
|
|
||||||
|
|
||||||
/* Functions for system-level CD-ROM audio control */
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#include <mmsystem.h>
|
|
||||||
|
|
||||||
#include "SDL_cdrom.h"
|
|
||||||
#include "../SDL_syscdrom.h"
|
|
||||||
|
|
||||||
/* This really broken?? */
|
|
||||||
#define BROKEN_MCI_PAUSE /* Pausing actually stops play -- Doh! */
|
|
||||||
|
|
||||||
/* The maximum number of CD-ROM drives we'll detect (Don't change!) */
|
|
||||||
#define MAX_DRIVES 26
|
|
||||||
|
|
||||||
/* A list of available CD-ROM drives */
|
|
||||||
static char *SDL_cdlist[MAX_DRIVES];
|
|
||||||
static MCIDEVICEID SDL_mciID[MAX_DRIVES];
|
|
||||||
#ifdef BROKEN_MCI_PAUSE
|
|
||||||
static int SDL_paused[MAX_DRIVES];
|
|
||||||
#endif
|
|
||||||
static int SDL_CD_end_position;
|
|
||||||
|
|
||||||
/* The system-dependent CD control functions */
|
|
||||||
static const char *SDL_SYS_CDName(int drive);
|
|
||||||
static int SDL_SYS_CDOpen(int drive);
|
|
||||||
static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
|
|
||||||
static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
|
|
||||||
static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
|
|
||||||
static int SDL_SYS_CDPause(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDResume(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDStop(SDL_CD * cdrom);
|
|
||||||
static int SDL_SYS_CDEject(SDL_CD * cdrom);
|
|
||||||
static void SDL_SYS_CDClose(SDL_CD * cdrom);
|
|
||||||
|
|
||||||
|
|
||||||
/* Add a CD-ROM drive to our list of valid drives */
|
|
||||||
static void
|
|
||||||
AddDrive(char *drive)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds < MAX_DRIVES) {
|
|
||||||
/* Add this drive to our list */
|
|
||||||
i = SDL_numcds;
|
|
||||||
SDL_cdlist[i] = SDL_strdup(drive);
|
|
||||||
if (SDL_cdlist[i] == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++SDL_numcds;
|
|
||||||
#ifdef CDROM_DEBUG
|
|
||||||
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
SDL_SYS_CDInit(void)
|
|
||||||
{
|
|
||||||
/* checklist: Drive 'A' - 'Z' */
|
|
||||||
int i;
|
|
||||||
char drive[4];
|
|
||||||
|
|
||||||
/* Fill in our driver capabilities */
|
|
||||||
SDL_CDcaps.Name = SDL_SYS_CDName;
|
|
||||||
SDL_CDcaps.Open = SDL_SYS_CDOpen;
|
|
||||||
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
|
|
||||||
SDL_CDcaps.Status = SDL_SYS_CDStatus;
|
|
||||||
SDL_CDcaps.Play = SDL_SYS_CDPlay;
|
|
||||||
SDL_CDcaps.Pause = SDL_SYS_CDPause;
|
|
||||||
SDL_CDcaps.Resume = SDL_SYS_CDResume;
|
|
||||||
SDL_CDcaps.Stop = SDL_SYS_CDStop;
|
|
||||||
SDL_CDcaps.Eject = SDL_SYS_CDEject;
|
|
||||||
SDL_CDcaps.Close = SDL_SYS_CDClose;
|
|
||||||
|
|
||||||
/* Scan the system for CD-ROM drives */
|
|
||||||
for (i = 'A'; i <= 'Z'; ++i) {
|
|
||||||
SDL_snprintf(drive, SDL_arraysize(drive), "%c:\\", i);
|
|
||||||
if (GetDriveType(drive) == DRIVE_CDROM) {
|
|
||||||
AddDrive(drive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SDL_memset(SDL_mciID, 0, sizeof(SDL_mciID));
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General ioctl() CD-ROM command function */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDioctl(int id, UINT msg, DWORD flags, void *arg)
|
|
||||||
{
|
|
||||||
MCIERROR mci_error;
|
|
||||||
|
|
||||||
mci_error = mciSendCommand(SDL_mciID[id], msg, flags, (DWORD_PTR) arg);
|
|
||||||
if (mci_error) {
|
|
||||||
char error[256];
|
|
||||||
|
|
||||||
mciGetErrorString(mci_error, error, 256);
|
|
||||||
SDL_SetError("mciSendCommand() error: %s", error);
|
|
||||||
}
|
|
||||||
return (!mci_error ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
SDL_SYS_CDName(int drive)
|
|
||||||
{
|
|
||||||
return (SDL_cdlist[drive]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDOpen(int drive)
|
|
||||||
{
|
|
||||||
MCI_OPEN_PARMS mci_open;
|
|
||||||
MCI_SET_PARMS mci_set;
|
|
||||||
char device[3];
|
|
||||||
DWORD flags;
|
|
||||||
|
|
||||||
/* Open the requested device */
|
|
||||||
mci_open.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
|
|
||||||
device[0] = *SDL_cdlist[drive];
|
|
||||||
device[1] = ':';
|
|
||||||
device[2] = '\0';
|
|
||||||
mci_open.lpstrElementName = device;
|
|
||||||
flags =
|
|
||||||
(MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID |
|
|
||||||
MCI_OPEN_ELEMENT);
|
|
||||||
if (SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0) {
|
|
||||||
flags &= ~MCI_OPEN_SHAREABLE;
|
|
||||||
if (SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SDL_mciID[drive] = mci_open.wDeviceID;
|
|
||||||
|
|
||||||
/* Set the minute-second-frame time format */
|
|
||||||
mci_set.dwTimeFormat = MCI_FORMAT_MSF;
|
|
||||||
SDL_SYS_CDioctl(drive, MCI_SET, MCI_SET_TIME_FORMAT, &mci_set);
|
|
||||||
|
|
||||||
#ifdef BROKEN_MCI_PAUSE
|
|
||||||
SDL_paused[drive] = 0;
|
|
||||||
#endif
|
|
||||||
return (drive);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDGetTOC(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
MCI_STATUS_PARMS mci_status;
|
|
||||||
int i, okay;
|
|
||||||
DWORD flags;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
mci_status.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
|
|
||||||
flags = MCI_STATUS_ITEM | MCI_WAIT;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0) {
|
|
||||||
cdrom->numtracks = mci_status.dwReturn;
|
|
||||||
if (cdrom->numtracks > SDL_MAX_TRACKS) {
|
|
||||||
cdrom->numtracks = SDL_MAX_TRACKS;
|
|
||||||
}
|
|
||||||
/* Read all the track TOC entries */
|
|
||||||
flags = MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT;
|
|
||||||
for (i = 0; i < cdrom->numtracks; ++i) {
|
|
||||||
cdrom->track[i].id = i + 1;
|
|
||||||
mci_status.dwTrack = cdrom->track[i].id;
|
|
||||||
#ifdef MCI_CDA_STATUS_TYPE_TRACK
|
|
||||||
mci_status.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
|
|
||||||
&mci_status) < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (mci_status.dwReturn == MCI_CDA_TRACK_AUDIO) {
|
|
||||||
cdrom->track[i].type = SDL_AUDIO_TRACK;
|
|
||||||
} else {
|
|
||||||
cdrom->track[i].type = SDL_DATA_TRACK;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
cdrom->track[i].type = SDL_AUDIO_TRACK;
|
|
||||||
#endif
|
|
||||||
mci_status.dwItem = MCI_STATUS_POSITION;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
|
|
||||||
&mci_status) < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cdrom->track[i].offset =
|
|
||||||
MSF_TO_FRAMES(MCI_MSF_MINUTE(mci_status.dwReturn),
|
|
||||||
MCI_MSF_SECOND(mci_status.dwReturn),
|
|
||||||
MCI_MSF_FRAME(mci_status.dwReturn));
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
cdrom->track[i].offset - cdrom->track[i - 1].offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == cdrom->numtracks) {
|
|
||||||
mci_status.dwTrack = cdrom->track[i - 1].id;
|
|
||||||
mci_status.dwItem = MCI_STATUS_LENGTH;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
|
|
||||||
&mci_status) == 0) {
|
|
||||||
cdrom->track[i - 1].length =
|
|
||||||
MSF_TO_FRAMES(MCI_MSF_MINUTE(mci_status.dwReturn),
|
|
||||||
MCI_MSF_SECOND(mci_status.dwReturn),
|
|
||||||
MCI_MSF_FRAME(mci_status.dwReturn));
|
|
||||||
/* compute lead-out offset */
|
|
||||||
cdrom->track[i].offset = cdrom->track[i - 1].offset +
|
|
||||||
cdrom->track[i - 1].length;
|
|
||||||
cdrom->track[i].length = 0;
|
|
||||||
okay = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get CD-ROM status */
|
|
||||||
static CDstatus
|
|
||||||
SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
MCI_STATUS_PARMS mci_status;
|
|
||||||
DWORD flags;
|
|
||||||
|
|
||||||
flags = MCI_STATUS_ITEM | MCI_WAIT;
|
|
||||||
mci_status.dwItem = MCI_STATUS_MODE;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) < 0) {
|
|
||||||
status = CD_ERROR;
|
|
||||||
} else {
|
|
||||||
switch (mci_status.dwReturn) {
|
|
||||||
case MCI_MODE_NOT_READY:
|
|
||||||
case MCI_MODE_OPEN:
|
|
||||||
status = CD_TRAYEMPTY;
|
|
||||||
break;
|
|
||||||
case MCI_MODE_STOP:
|
|
||||||
#ifdef BROKEN_MCI_PAUSE
|
|
||||||
if (SDL_paused[cdrom->id]) {
|
|
||||||
status = CD_PAUSED;
|
|
||||||
} else {
|
|
||||||
status = CD_STOPPED;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
status = CD_STOPPED;
|
|
||||||
#endif /* BROKEN_MCI_PAUSE */
|
|
||||||
break;
|
|
||||||
case MCI_MODE_PLAY:
|
|
||||||
#ifdef BROKEN_MCI_PAUSE
|
|
||||||
if (SDL_paused[cdrom->id]) {
|
|
||||||
status = CD_PAUSED;
|
|
||||||
} else {
|
|
||||||
status = CD_PLAYING;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
status = CD_PLAYING;
|
|
||||||
#endif /* BROKEN_MCI_PAUSE */
|
|
||||||
break;
|
|
||||||
case MCI_MODE_PAUSE:
|
|
||||||
status = CD_PAUSED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = CD_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (position) {
|
|
||||||
if (status == CD_PLAYING || (status == CD_PAUSED)) {
|
|
||||||
mci_status.dwItem = MCI_STATUS_POSITION;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
|
|
||||||
&mci_status) == 0) {
|
|
||||||
*position =
|
|
||||||
MSF_TO_FRAMES(MCI_MSF_MINUTE(mci_status.dwReturn),
|
|
||||||
MCI_MSF_SECOND(mci_status.dwReturn),
|
|
||||||
MCI_MSF_FRAME(mci_status.dwReturn));
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
|
|
||||||
{
|
|
||||||
MCI_PLAY_PARMS mci_play;
|
|
||||||
int m, s, f;
|
|
||||||
DWORD flags;
|
|
||||||
|
|
||||||
flags = MCI_FROM | MCI_TO | MCI_NOTIFY;
|
|
||||||
mci_play.dwCallback = 0;
|
|
||||||
FRAMES_TO_MSF(start, &m, &s, &f);
|
|
||||||
mci_play.dwFrom = MCI_MAKE_MSF(m, s, f);
|
|
||||||
FRAMES_TO_MSF(start + length, &m, &s, &f);
|
|
||||||
mci_play.dwTo = MCI_MAKE_MSF(m, s, f);
|
|
||||||
SDL_CD_end_position = mci_play.dwTo;
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, MCI_PLAY, flags, &mci_play));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pause play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDPause(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
#ifdef BROKEN_MCI_PAUSE
|
|
||||||
SDL_paused[cdrom->id] = 1;
|
|
||||||
#endif
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, MCI_PAUSE, MCI_WAIT, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resume play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDResume(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
#ifdef BROKEN_MCI_PAUSE
|
|
||||||
MCI_STATUS_PARMS mci_status;
|
|
||||||
int okay;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
okay = 0;
|
|
||||||
/* Play from the current play position to the end position set earlier */
|
|
||||||
flags = MCI_STATUS_ITEM | MCI_WAIT;
|
|
||||||
mci_status.dwItem = MCI_STATUS_POSITION;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0) {
|
|
||||||
MCI_PLAY_PARMS mci_play;
|
|
||||||
|
|
||||||
flags = MCI_FROM | MCI_TO | MCI_NOTIFY;
|
|
||||||
mci_play.dwCallback = 0;
|
|
||||||
mci_play.dwFrom = mci_status.dwReturn;
|
|
||||||
mci_play.dwTo = SDL_CD_end_position;
|
|
||||||
if (SDL_SYS_CDioctl(cdrom->id, MCI_PLAY, flags, &mci_play) == 0) {
|
|
||||||
okay = 1;
|
|
||||||
SDL_paused[cdrom->id] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (okay ? 0 : -1);
|
|
||||||
#else
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, MCI_RESUME, MCI_WAIT, NULL));
|
|
||||||
#endif /* BROKEN_MCI_PAUSE */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop play */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDStop(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, MCI_STOP, MCI_WAIT, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eject the CD-ROM */
|
|
||||||
static int
|
|
||||||
SDL_SYS_CDEject(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
return (SDL_SYS_CDioctl(cdrom->id, MCI_SET, MCI_SET_DOOR_OPEN, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close the CD-ROM handle */
|
|
||||||
static void
|
|
||||||
SDL_SYS_CDClose(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
SDL_SYS_CDioctl(cdrom->id, MCI_CLOSE, MCI_WAIT, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SDL_SYS_CDQuit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (SDL_numcds > 0) {
|
|
||||||
for (i = 0; i < SDL_numcds; ++i) {
|
|
||||||
SDL_free(SDL_cdlist[i]);
|
|
||||||
}
|
|
||||||
SDL_numcds = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SDL_CDROM_WIN32 */
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
|
@ -7,7 +7,7 @@ EXE = @EXE@
|
||||||
CFLAGS = @CFLAGS@
|
CFLAGS = @CFLAGS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
|
|
||||||
TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testresample$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testpower$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testintersections$(EXE) testdraw2$(EXE) testdyngl$(EXE) testdyngles$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testgles$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) testhaptic$(EXE) testmmousetablet$(EXE) testatomic$(EXE)
|
TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testresample$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testpower$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcursor$(EXE) testintersections$(EXE) testdraw2$(EXE) testdyngl$(EXE) testdyngles$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testgles$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) testhaptic$(EXE) testmmousetablet$(EXE) testatomic$(EXE)
|
||||||
|
|
||||||
all: Makefile $(TARGETS)
|
all: Makefile $(TARGETS)
|
||||||
|
|
||||||
|
@ -44,9 +44,6 @@ testbitmap$(EXE): $(srcdir)/testbitmap.c
|
||||||
testblitspeed$(EXE): $(srcdir)/testblitspeed.c
|
testblitspeed$(EXE): $(srcdir)/testblitspeed.c
|
||||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
testcdrom$(EXE): $(srcdir)/testcdrom.c
|
|
||||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
|
||||||
|
|
||||||
testcursor$(EXE): $(srcdir)/testcursor.c
|
testcursor$(EXE): $(srcdir)/testcursor.c
|
||||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
|
203
test/testcdrom.c
203
test/testcdrom.c
|
@ -1,203 +0,0 @@
|
||||||
|
|
||||||
/* Test the SDL CD-ROM audio functions */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "SDL.h"
|
|
||||||
|
|
||||||
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
|
|
||||||
static void
|
|
||||||
quit(int rc)
|
|
||||||
{
|
|
||||||
SDL_Quit();
|
|
||||||
exit(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
PrintStatus(int driveindex, SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
CDstatus status;
|
|
||||||
char *status_str;
|
|
||||||
|
|
||||||
status = SDL_CDStatus(cdrom);
|
|
||||||
switch (status) {
|
|
||||||
case CD_TRAYEMPTY:
|
|
||||||
status_str = "tray empty";
|
|
||||||
break;
|
|
||||||
case CD_STOPPED:
|
|
||||||
status_str = "stopped";
|
|
||||||
break;
|
|
||||||
case CD_PLAYING:
|
|
||||||
status_str = "playing";
|
|
||||||
break;
|
|
||||||
case CD_PAUSED:
|
|
||||||
status_str = "paused";
|
|
||||||
break;
|
|
||||||
case CD_ERROR:
|
|
||||||
status_str = "error state";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
printf("Drive %d status: %s\n", driveindex, status_str);
|
|
||||||
if (status >= CD_PLAYING) {
|
|
||||||
int m, s, f;
|
|
||||||
FRAMES_TO_MSF(cdrom->cur_frame, &m, &s, &f);
|
|
||||||
printf("Currently playing track %d, %d:%2.2d\n",
|
|
||||||
cdrom->track[cdrom->cur_track].id, m, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ListTracks(SDL_CD * cdrom)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int m, s, f;
|
|
||||||
char *trtype;
|
|
||||||
|
|
||||||
SDL_CDStatus(cdrom);
|
|
||||||
printf("Drive tracks: %d\n", cdrom->numtracks);
|
|
||||||
for (i = 0; i < cdrom->numtracks; ++i) {
|
|
||||||
FRAMES_TO_MSF(cdrom->track[i].length, &m, &s, &f);
|
|
||||||
if (f > 0)
|
|
||||||
++s;
|
|
||||||
switch (cdrom->track[i].type) {
|
|
||||||
case SDL_AUDIO_TRACK:
|
|
||||||
trtype = "audio";
|
|
||||||
break;
|
|
||||||
case SDL_DATA_TRACK:
|
|
||||||
trtype = "data";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
trtype = "unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
printf("\tTrack (index %d) %d: %d:%2.2d / %d [%s track]\n", i,
|
|
||||||
cdrom->track[i].id, m, s, cdrom->track[i].length, trtype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
PrintUsage(char *argv0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage: %s [drive#] [command] [command] ...\n", argv0);
|
|
||||||
fprintf(stderr, "Where 'command' is one of:\n");
|
|
||||||
fprintf(stderr, " -status\n");
|
|
||||||
fprintf(stderr, " -list\n");
|
|
||||||
fprintf(stderr,
|
|
||||||
" -play [first_track] [first_frame] [num_tracks] [num_frames]\n");
|
|
||||||
fprintf(stderr, " -pause\n");
|
|
||||||
fprintf(stderr, " -resume\n");
|
|
||||||
fprintf(stderr, " -stop\n");
|
|
||||||
fprintf(stderr, " -eject\n");
|
|
||||||
fprintf(stderr, " -sleep <milliseconds>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int drive;
|
|
||||||
int i;
|
|
||||||
SDL_CD *cdrom;
|
|
||||||
|
|
||||||
/* Initialize SDL first */
|
|
||||||
if (SDL_Init(SDL_INIT_CDROM) < 0) {
|
|
||||||
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find out how many CD-ROM drives are connected to the system */
|
|
||||||
if (SDL_CDNumDrives() == 0) {
|
|
||||||
printf("No CD-ROM devices detected\n");
|
|
||||||
quit(0);
|
|
||||||
}
|
|
||||||
printf("Drives available: %d\n", SDL_CDNumDrives());
|
|
||||||
for (i = 0; i < SDL_CDNumDrives(); ++i) {
|
|
||||||
printf("Drive %d: \"%s\"\n", i, SDL_CDName(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the CD-ROM */
|
|
||||||
drive = 0;
|
|
||||||
i = 1;
|
|
||||||
if (argv[i] && isdigit(argv[i][0])) {
|
|
||||||
drive = atoi(argv[i++]);
|
|
||||||
}
|
|
||||||
cdrom = SDL_CDOpen(drive);
|
|
||||||
if (cdrom == NULL) {
|
|
||||||
fprintf(stderr, "Couldn't open drive %d: %s\n", drive,
|
|
||||||
SDL_GetError());
|
|
||||||
quit(2);
|
|
||||||
}
|
|
||||||
#ifdef TEST_NULLCD
|
|
||||||
cdrom = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Find out which function to perform */
|
|
||||||
for (; argv[i]; ++i) {
|
|
||||||
if (strcmp(argv[i], "-status") == 0) {
|
|
||||||
/* PrintStatus(drive, cdrom); */
|
|
||||||
} else if (strcmp(argv[i], "-list") == 0) {
|
|
||||||
ListTracks(cdrom);
|
|
||||||
} else if (strcmp(argv[i], "-play") == 0) {
|
|
||||||
int strack, sframe;
|
|
||||||
int ntrack, nframe;
|
|
||||||
|
|
||||||
strack = 0;
|
|
||||||
if (argv[i + 1] && isdigit(argv[i + 1][0])) {
|
|
||||||
strack = atoi(argv[++i]);
|
|
||||||
}
|
|
||||||
sframe = 0;
|
|
||||||
if (argv[i + 1] && isdigit(argv[i + 1][0])) {
|
|
||||||
sframe = atoi(argv[++i]);
|
|
||||||
}
|
|
||||||
ntrack = 0;
|
|
||||||
if (argv[i + 1] && isdigit(argv[i + 1][0])) {
|
|
||||||
ntrack = atoi(argv[++i]);
|
|
||||||
}
|
|
||||||
nframe = 0;
|
|
||||||
if (argv[i + 1] && isdigit(argv[i + 1][0])) {
|
|
||||||
nframe = atoi(argv[++i]);
|
|
||||||
}
|
|
||||||
if (CD_INDRIVE(SDL_CDStatus(cdrom))) {
|
|
||||||
if (SDL_CDPlayTracks(cdrom, strack, sframe,
|
|
||||||
ntrack, nframe) < 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Couldn't play tracks %d/%d for %d/%d: %s\n",
|
|
||||||
strack, sframe, ntrack, nframe, SDL_GetError());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "No CD in drive!\n");
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-pause") == 0) {
|
|
||||||
if (SDL_CDPause(cdrom) < 0) {
|
|
||||||
fprintf(stderr, "Couldn't pause CD: %s\n", SDL_GetError());
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-resume") == 0) {
|
|
||||||
if (SDL_CDResume(cdrom) < 0) {
|
|
||||||
fprintf(stderr, "Couldn't resume CD: %s\n", SDL_GetError());
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-stop") == 0) {
|
|
||||||
if (SDL_CDStop(cdrom) < 0) {
|
|
||||||
fprintf(stderr, "Couldn't eject CD: %s\n", SDL_GetError());
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[i], "-eject") == 0) {
|
|
||||||
if (SDL_CDEject(cdrom) < 0) {
|
|
||||||
fprintf(stderr, "Couldn't eject CD: %s\n", SDL_GetError());
|
|
||||||
}
|
|
||||||
} else if ((strcmp(argv[i], "-sleep") == 0) &&
|
|
||||||
(argv[i + 1] && isdigit(argv[i + 1][0]))) {
|
|
||||||
SDL_Delay(atoi(argv[++i]));
|
|
||||||
printf("Delayed %d milliseconds\n", atoi(argv[i]));
|
|
||||||
} else {
|
|
||||||
PrintUsage(argv[0]);
|
|
||||||
SDL_CDClose(cdrom);
|
|
||||||
quit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrintStatus(drive, cdrom);
|
|
||||||
SDL_CDClose(cdrom);
|
|
||||||
SDL_Quit();
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue