quakeforge/libs/audio/cd_xmms.c
Bill Currie 5f93c115ff [util] Make developer flag names easier to manage
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.
2021-03-29 22:38:47 +09:00

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;
}