mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 23:32:09 +00:00
5f93c115ff
They're now an enum, and the flag part of the name is all lowercase, but now the flag definitions and names list will never get out of sync.
532 lines
11 KiB
C
532 lines
11 KiB
C
/*
|
|
xmms_cd.c
|
|
|
|
XMMS Player support, disguised as a cdrom.
|
|
|
|
Copyright (C) 2001 Alexis Paul Musgrave
|
|
|
|
Author: Alexis Paul Musgrave
|
|
Date: 2001/09/28
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_IOCTL_H
|
|
# include <sys/ioctl.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <xmmsctrl.h>
|
|
|
|
#include "QF/cdaudio.h"
|
|
#include "QF/cmd.h"
|
|
#include "QF/cvar.h"
|
|
#include "QF/qargs.h"
|
|
#include "QF/sound.h"
|
|
#include "QF/sys.h"
|
|
|
|
#include "QF/plugin/general.h"
|
|
#include "QF/plugin/cd.h"
|
|
|
|
#include "compat.h"
|
|
|
|
static plugin_t plugin_info;
|
|
static plugin_data_t plugin_info_data;
|
|
static plugin_funcs_t plugin_info_funcs;
|
|
static general_data_t plugin_info_general_data;
|
|
static general_funcs_t plugin_info_general_funcs;
|
|
|
|
static cd_funcs_t plugin_info_cd_funcs;
|
|
|
|
static const char *xmms_cmd = "xmms";
|
|
static const char *xmms_args[] = {"xmms", 0};
|
|
// Session number, gets set to 0 in I_XMMS_Init if not set
|
|
static int sessionNo;
|
|
|
|
// don't need either of these now
|
|
//static int xmmsPid = '0';
|
|
//static int sigNo = '2';
|
|
|
|
static qboolean playing = false;
|
|
|
|
// no idea why I have wasPlaying, pbly this code was based on cd_linux.c :/
|
|
static qboolean wasPlaying = false;
|
|
static qboolean musEnabled = true;
|
|
|
|
static void I_XMMS_Running(void);
|
|
static void I_XMMS_Stop(void);
|
|
static void I_XMMS_Play(int, qboolean);
|
|
static void I_XMMS_Pause(void);
|
|
static void I_XMMS_Resume(void);
|
|
static void I_XMMS_Next(void);
|
|
static void I_XMMS_Prev(void);
|
|
static void I_XMMS_Update(void);
|
|
static void XMMS_SessionChg(cvar_t *);
|
|
static void I_XMMS_Init(void);
|
|
static void I_XMMS_Shutdown(void);
|
|
static void I_XMMS_Kill(void);
|
|
static void I_XMMS_On(void);
|
|
static void I_XMMS_Off(void);
|
|
static void I_XMMS_Shuffle(void);
|
|
static void I_XMMS_Repeat(void);
|
|
static void I_XMMS_Pos(int);
|
|
static void I_XMMS_Info(void);
|
|
static void I_XMMS_f(void);
|
|
plugin_t *cd_xmms_PluginInfo (void);
|
|
|
|
//static float cdvolume;
|
|
//static byte remap[100];
|
|
//static byte playTrack;
|
|
//static byte maxTrack;
|
|
|
|
// FIXME: All of this code assumes that the xmms_remote_* functions succeed
|
|
// FIXME: shouldn't I use gint for all the xmms stuff like
|
|
// FIXME (cont): /usr/include/xmms/xmmsctrl.h says?
|
|
|
|
static void
|
|
I_XMMS_Running (void)
|
|
{
|
|
int res, i;
|
|
int fd_size = getdtablesize ();
|
|
|
|
if (!xmms_remote_is_running (sessionNo)) {
|
|
// this method is used over a system() call, so that we know child's
|
|
// pid (not that is particularly important) but so we can close
|
|
// unneeded descriptors
|
|
|
|
res = fork ();
|
|
|
|
switch (res) {
|
|
case 0: // Child
|
|
// Well, we don't want the child to be running about with
|
|
// 27001 still open
|
|
|
|
for (i = 3; i < fd_size; i++)
|
|
close (i);
|
|
|
|
// run xmms
|
|
if (execvp (xmms_cmd, (char **)xmms_args)) {
|
|
// Oh dear, can we even use Sys_DPrinf? We are child so
|
|
// we have access to them? But wouldn't it just try
|
|
// rendering it and screw stuff up? Better not find out.
|
|
|
|
exit (1); // Well, we can't just hang about
|
|
// causing trouble can we ?
|
|
}
|
|
break;
|
|
case -1: // ICH!
|
|
// inform user
|
|
Sys_MaskPrintf (SYS_snd, "XMMSAudio: error, can't fork!?\n");
|
|
break;
|
|
default: // Parent
|
|
// don't need now :/
|
|
// xmmsPid = res; // so we can kill it later
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
I_XMMS_Stop (void) // stop playing
|
|
{
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
if (!xmms_remote_is_playing (sessionNo))
|
|
return; // check that its actually playing
|
|
|
|
xmms_remote_stop (sessionNo); // stop it
|
|
|
|
wasPlaying = playing;
|
|
playing = false;
|
|
}
|
|
|
|
// Play
|
|
// start it playing, (unless disabled)
|
|
static void
|
|
I_XMMS_Play (int track, qboolean looping) // looping for compatability
|
|
{
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
// I think this will fix some wierdness
|
|
if (xmms_remote_is_paused (sessionNo)) {
|
|
xmms_remote_pause (sessionNo);
|
|
return;
|
|
}
|
|
|
|
if (track >= 0)
|
|
xmms_remote_set_playlist_pos (sessionNo, track);
|
|
|
|
if (xmms_remote_is_playing (sessionNo))
|
|
return;
|
|
|
|
xmms_remote_play (sessionNo);
|
|
|
|
wasPlaying = playing;
|
|
playing = true;
|
|
return;
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Pause (void)
|
|
{
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
if (!xmms_remote_is_playing (sessionNo))
|
|
return;
|
|
|
|
xmms_remote_pause (sessionNo);
|
|
|
|
wasPlaying = playing;
|
|
playing = false;
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Resume (void)
|
|
{
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
// i think this will fix some wierdness
|
|
if (xmms_remote_is_paused (sessionNo)) {
|
|
xmms_remote_pause (sessionNo);
|
|
return;
|
|
}
|
|
if (xmms_remote_is_playing (sessionNo))
|
|
return;
|
|
|
|
xmms_remote_play (sessionNo);
|
|
wasPlaying = playing;
|
|
playing = true;
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Prev (void)
|
|
{
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
xmms_remote_playlist_prev (sessionNo);
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Next (void)
|
|
{
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
xmms_remote_playlist_next (sessionNo);
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Update (void)
|
|
{
|
|
}
|
|
|
|
static void
|
|
XMMS_SessionChg(cvar_t *xmms_session)
|
|
{
|
|
sessionNo = xmms_session->int_val;
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Init (void)
|
|
{
|
|
cvar_t *tmp;
|
|
|
|
I_XMMS_Running ();
|
|
Cmd_AddCommand ("xmms", I_XMMS_f, "Control the XMMS player.\n"
|
|
"Commands:\n"
|
|
"resume - Will resume playback after pause.\n"
|
|
"off - Stops control and playback of XMMS.\n"
|
|
"on - Starts XMMS if not running, or enables playback.\n"
|
|
"pause - Pause the XMMS playback.\n"
|
|
"play (position) - Begins playing tracks (from position) "
|
|
"according to the playlist.\n"
|
|
"stop - Stops the currently playing track.\n"
|
|
"next - Plays the next track in the playlist.\n"
|
|
"prev - Plays the previous track in the playlist.\n"
|
|
"shuffle - Toggle shuffling the playlist.\n"
|
|
"repeat - Toggle repeating of the playlist.\n"
|
|
"pos - Set playlist position.\n"
|
|
"info - Get information about currently playing song.");
|
|
|
|
tmp = Cvar_Get ("xmms_session", "0", CVAR_NONE, XMMS_SessionChg,
|
|
"XMMS Session number to use");
|
|
|
|
sessionNo = tmp->int_val;
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Shutdown (void)
|
|
{
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Kill (void)
|
|
{
|
|
xmms_remote_quit (sessionNo);
|
|
}
|
|
|
|
static void
|
|
I_XMMS_On (void)
|
|
{
|
|
musEnabled = true;
|
|
I_XMMS_Running ();
|
|
}
|
|
|
|
static void
|
|
I_XMMS_Off (void)
|
|
{
|
|
musEnabled = false;
|
|
I_XMMS_Kill ();
|
|
}
|
|
|
|
static void // Toggle Shuffling
|
|
I_XMMS_Shuffle (void)
|
|
{
|
|
int shuf;
|
|
|
|
// for some reason, it reports shuffle wrong,
|
|
// probably because it relies on a timer that doesn't time out straight
|
|
// after change, and before the check
|
|
|
|
// SO, we check before, and assuming it works, we know that it will be the
|
|
// opposite of what it _WAS_, if you get my meaning :/
|
|
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
shuf = xmms_remote_is_shuffle (sessionNo);
|
|
xmms_remote_toggle_shuffle (sessionNo);
|
|
if (shuf == 1) {
|
|
Sys_Printf ("XMMSAudio: Shuffling Disabled\n");
|
|
} else if (shuf == 0) {
|
|
Sys_Printf ("XMMSAudio: Shuffling Enabled\n");
|
|
}
|
|
}
|
|
|
|
static void // toggles playlist repeating
|
|
I_XMMS_Repeat (void)
|
|
{
|
|
// Similar situation as with I_XMMS_Shuffle() -- same code too :)
|
|
int rep;
|
|
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
rep = xmms_remote_is_repeat (sessionNo);
|
|
xmms_remote_toggle_repeat (sessionNo);
|
|
if (rep == 1) {
|
|
Sys_Printf ("XMMSAudio: Repeat Disabled\n");
|
|
} else if (rep == 0) {
|
|
Sys_Printf ("XMMSAudio: Repeat Enabled\n");
|
|
}
|
|
}
|
|
|
|
static void // sets playlist position
|
|
I_XMMS_Pos (int track)
|
|
{
|
|
if (!musEnabled)
|
|
return;
|
|
if (track < 0)
|
|
return; // -ve track numbers are dumb
|
|
xmms_remote_set_playlist_pos (sessionNo, track);
|
|
}
|
|
|
|
static void // returns info about track playing and list progress
|
|
I_XMMS_Info (void) // this is untested with really long tracks, prolly works
|
|
{
|
|
int pos;
|
|
char *title;
|
|
unsigned int ctime; // -ve times are dumb, will this help ?
|
|
unsigned int cmin; // current no of mins
|
|
byte csecs; // current no of secs
|
|
unsigned int ttime; // total track time
|
|
unsigned int tmin; // total no of mins
|
|
byte tsecs; // total no of secs
|
|
unsigned int len; // playlist length
|
|
|
|
if (!musEnabled)
|
|
return;
|
|
I_XMMS_Running ();
|
|
|
|
pos = xmms_remote_get_playlist_pos (sessionNo); // get playlist position
|
|
len = xmms_remote_get_playlist_length (sessionNo); // playlist length
|
|
title = xmms_remote_get_playlist_title (sessionNo, pos); // get track title
|
|
ctime = xmms_remote_get_output_time (sessionNo); // get track elapsed time
|
|
ttime = xmms_remote_get_playlist_time (sessionNo, pos);
|
|
|
|
// The time returned by xmms_remote_get_output_time is in milliseconds
|
|
// elapsed, so, divide by (60*1000) to get mins (its an int, no decimals)
|
|
// and divide by 1000 mod 60 to get seconds. its a byte, no decimals too.
|
|
cmin = ctime / 60000;
|
|
csecs = ctime / 1000 % 60;
|
|
|
|
tmin = ttime / 60000;
|
|
tsecs = ttime / 1000 % 60;
|
|
|
|
// tell the user.
|
|
Sys_Printf ("XMMS: %d/%d %s %d:%02d/%d:%02d\n",
|
|
pos, len, title, cmin, csecs, tmin, tsecs);
|
|
free (title);
|
|
}
|
|
|
|
static void
|
|
I_XMMS_f (void)
|
|
{
|
|
const char *command;
|
|
|
|
if (Cmd_Argc () < 2)
|
|
return;
|
|
command = Cmd_Argv (1);
|
|
|
|
if (strequal (command, "play")) {
|
|
I_XMMS_Play ((atoi (Cmd_Argv (2)) -1), 0);
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "on")) {
|
|
I_XMMS_On ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "off")) {
|
|
I_XMMS_Off ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "stop")) {
|
|
I_XMMS_Stop ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "pause")) {
|
|
I_XMMS_Pause ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "resume")) {
|
|
I_XMMS_Resume ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "next")) {
|
|
I_XMMS_Next ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "prev")) {
|
|
I_XMMS_Prev ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "shuffle")) {
|
|
I_XMMS_Shuffle ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "repeat")) {
|
|
I_XMMS_Repeat ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "pos")) {
|
|
I_XMMS_Pos (atoi (Cmd_Argv (2)) - 1);
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "info")) {
|
|
I_XMMS_Info ();
|
|
return;
|
|
}
|
|
|
|
if (strequal (command, "help")) {
|
|
Sys_Printf ("Try \"help xmms\".\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
static general_funcs_t plugin_info_general_funcs = {
|
|
I_XMMS_Init,
|
|
I_XMMS_Shutdown,
|
|
};
|
|
|
|
static cd_funcs_t plugin_info_cd_funcs = {
|
|
I_XMMS_f,
|
|
I_XMMS_Pause,
|
|
I_XMMS_Play,
|
|
I_XMMS_Resume,
|
|
I_XMMS_Update,
|
|
};
|
|
|
|
static plugin_funcs_t plugin_info_funcs = {
|
|
&plugin_info_general_funcs,
|
|
0,
|
|
&plugin_info_cd_funcs,
|
|
0,
|
|
0,
|
|
0,
|
|
};
|
|
|
|
static plugin_data_t plugin_info_data = {
|
|
&plugin_info_general_data,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
};
|
|
|
|
static plugin_t plugin_info = {
|
|
qfp_cd,
|
|
0,
|
|
QFPLUGIN_VERSION,
|
|
"0.1",
|
|
"Linux XMMS Audio output\n",
|
|
"Copyright (C) 2001 contributors of the QuakeForge project\n"
|
|
"Please see the file \"AUTHORS\" for a list of contributors\n",
|
|
&plugin_info_funcs,
|
|
&plugin_info_data,
|
|
};
|
|
|
|
PLUGIN_INFO (cd, xmms)
|
|
{
|
|
return &plugin_info;
|
|
}
|