mirror of
https://github.com/joel16/SDL2.git
synced 2025-02-25 14:11:06 +00:00
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
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.
|
||||
|
||||
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
|
||||
SOURCES="$SOURCES $srcdir/src/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/audio/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/cdrom/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/cpuinfo/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/events/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/file/*.c"
|
||||
@ -265,12 +264,6 @@ if test x$enable_power != xyes; then
|
||||
else
|
||||
SOURCES="$SOURCES $srcdir/src/power/*.c"
|
||||
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_HELP_STRING([--enable-threads], [Enable the threading subsystem [[default=yes]]]),
|
||||
, enable_threads=yes)
|
||||
@ -2481,41 +2474,6 @@ case "$host" in
|
||||
;;
|
||||
esac
|
||||
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
|
||||
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)
|
||||
@ -2560,12 +2518,6 @@ case "$host" in
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lasound"
|
||||
have_audio=yes
|
||||
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
|
||||
if test x$enable_timers = xyes; then
|
||||
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"
|
||||
have_power=yes
|
||||
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
|
||||
if test x$enable_threads = xyes; then
|
||||
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"
|
||||
have_joystick=yes
|
||||
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
|
||||
if test x$enable_threads = xyes; then
|
||||
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"
|
||||
have_power=yes
|
||||
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
|
||||
if test x$enable_timers = xyes; then
|
||||
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,IOKit"
|
||||
# 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"
|
||||
fi
|
||||
;;
|
||||
@ -2959,12 +2893,6 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
||||
SOURCES="$SOURCES $srcdir/src/joystick/mint/*.c"
|
||||
have_joystick=yes
|
||||
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
|
||||
if test x$enable_timers = 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
|
||||
SOURCES="$SOURCES $srcdir/src/haptic/dummy/*.c"
|
||||
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$enable_threads = xyes; then
|
||||
AC_DEFINE(SDL_THREADS_DISABLED)
|
||||
|
@ -78,7 +78,6 @@ Enjoy!
|
||||
#include "SDL_stdinc.h"
|
||||
#include "SDL_atomic.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_cdrom.h"
|
||||
#include "SDL_cpuinfo.h"
|
||||
#include "SDL_endian.h"
|
||||
#include "SDL_error.h"
|
||||
@ -109,7 +108,6 @@ extern "C" {
|
||||
#define SDL_INIT_TIMER 0x00000001
|
||||
#define SDL_INIT_AUDIO 0x00000010
|
||||
#define SDL_INIT_VIDEO 0x00000020
|
||||
#define SDL_INIT_CDROM 0x00000100
|
||||
#define SDL_INIT_JOYSTICK 0x00000200
|
||||
#define SDL_INIT_HAPTIC 0x00001000
|
||||
#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 */
|
||||
#undef SDL_AUDIO_DISABLED
|
||||
#undef SDL_CDROM_DISABLED
|
||||
#undef SDL_CPUINFO_DISABLED
|
||||
#undef SDL_EVENTS_DISABLED
|
||||
#undef SDL_FILE_DISABLED
|
||||
@ -204,22 +203,6 @@
|
||||
#undef SDL_AUDIO_DRIVER_FUSIONSOUND
|
||||
#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 */
|
||||
#undef SDL_INPUT_LINUXEV
|
||||
#undef SDL_INPUT_TSLIB
|
||||
|
@ -88,9 +88,6 @@ typedef unsigned long uintptr_t;
|
||||
#define SDL_AUDIO_DRIVER_DISK 1
|
||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||
|
||||
/* Enable various cdrom drivers */
|
||||
#define SDL_CDROM_DC 1
|
||||
|
||||
/* Enable various input drivers */
|
||||
#define SDL_JOYSTICK_DC 1
|
||||
#define SDL_HAPTIC_DUMMY 1
|
||||
|
@ -106,9 +106,6 @@ typedef unsigned long uintptr_t;
|
||||
/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
|
||||
#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) */
|
||||
#define SDL_HAPTIC_DISABLED 1
|
||||
|
||||
|
@ -106,9 +106,6 @@
|
||||
#define SDL_AUDIO_DRIVER_DISK 1
|
||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||
|
||||
/* Enable various cdrom drivers */
|
||||
#define SDL_CDROM_MACOSX 1
|
||||
|
||||
/* Enable various input drivers */
|
||||
#define SDL_JOYSTICK_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) */
|
||||
#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) */
|
||||
#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_DUMMY 1 TODO: uncomment this later*/
|
||||
|
||||
/* DS doesn't have optical media */
|
||||
#define SDL_CDROM_DISABLED 1
|
||||
|
||||
/* Enable various input drivers */
|
||||
#define SDL_JOYSTICK_NDS 1
|
||||
/*#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_DUMMY 1
|
||||
|
||||
/* Enable various cdrom drivers */
|
||||
#define SDL_CDROM_OS2 1
|
||||
|
||||
/* Enable various input drivers */
|
||||
#define SDL_JOYSTICK_OS2 1
|
||||
#define SDL_HAPTIC_DUMMY 1
|
||||
|
@ -95,7 +95,6 @@
|
||||
#define HAVE_SETJMP 1
|
||||
#define HAVE_NANOSLEEP 1
|
||||
|
||||
#define SDL_CDROM_DISABLED 1
|
||||
#define SDL_AUDIO_DRIVER_DUMMY 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_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 */
|
||||
#ifdef _WIN32_WCE
|
||||
#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_HapticQuit(void);
|
||||
#endif
|
||||
#if !SDL_CDROM_DISABLED
|
||||
extern int SDL_CDROMInit(void);
|
||||
extern void SDL_CDROMQuit(void);
|
||||
#endif
|
||||
#if !SDL_TIMERS_DISABLED
|
||||
extern void SDL_StartTicks(void);
|
||||
extern int SDL_TimerInit(void);
|
||||
@ -145,22 +141,6 @@ SDL_InitSubSystem(Uint32 flags)
|
||||
return (-1);
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
@ -198,12 +178,6 @@ void
|
||||
SDL_QuitSubSystem(Uint32 flags)
|
||||
{
|
||||
/* 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 ((flags & SDL_initialized & SDL_INIT_JOYSTICK)) {
|
||||
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@
|
||||
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)
|
||||
|
||||
@ -44,9 +44,6 @@ testbitmap$(EXE): $(srcdir)/testbitmap.c
|
||||
testblitspeed$(EXE): $(srcdir)/testblitspeed.c
|
||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||
|
||||
testcdrom$(EXE): $(srcdir)/testcdrom.c
|
||||
$(CC) -o $@ $? $(CFLAGS) $(LIBS)
|
||||
|
||||
testcursor$(EXE): $(srcdir)/testcursor.c
|
||||
$(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…
x
Reference in New Issue
Block a user