1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the included (GNU.txt) GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All 21// rights reserved. 22 23#include <stdio.h> 24#include <unistd.h> 25#include <stdlib.h> 26#include <sys/ioctl.h> 27#include <sys/file.h> 28#include <sys/types.h> 29#include <fcntl.h> 30#include <string.h> 31#include <time.h> 32#include <errno.h> 33 34#include <linux/cdrom.h> 35 36#include "quakedef.h" 37 38static qboolean cdValid = false; 39static qboolean playing = false; 40static qboolean wasPlaying = false; 41static qboolean initialized = false; 42static qboolean enabled = true; 43static qboolean playLooping = false; 44static float cdvolume; 45static byte remap[100]; 46static byte playTrack; 47static byte maxTrack; 48 49static int cdfile = -1; 50static char cd_dev[64] = "/dev/cdrom"; 51 52static void CDAudio_Eject(void) 53{ 54 if (cdfile == -1 || !enabled) 55 return; // no cd init'd 56 57 if ( ioctl(cdfile, CDROMEJECT) == -1 ) 58 Con_DPrintf("ioctl cdromeject failed\n"); 59} 60 61 62static void CDAudio_CloseDoor(void) 63{ 64 if (cdfile == -1 || !enabled) 65 return; // no cd init'd 66 67 if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 ) 68 Con_DPrintf("ioctl cdromclosetray failed\n"); 69} 70 71static int CDAudio_GetAudioDiskInfo(void) 72{ 73 struct cdrom_tochdr tochdr; 74 75 cdValid = false; 76 77 if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 ) 78 { 79 Con_DPrintf("ioctl cdromreadtochdr failed\n"); 80 return -1; 81 } 82 83 if (tochdr.cdth_trk0 < 1) 84 { 85 Con_DPrintf("CDAudio: no music tracks\n"); 86 return -1; 87 } 88 89 cdValid = true; 90 maxTrack = tochdr.cdth_trk1; 91 92 return 0; 93} 94 95 96void CDAudio_Play(byte track, qboolean looping) 97{ 98 struct cdrom_tocentry entry; 99 struct cdrom_ti ti; 100 101 if (cdfile == -1 || !enabled) 102 return; 103 104 if (!cdValid) 105 { 106 CDAudio_GetAudioDiskInfo(); 107 if (!cdValid) 108 return; 109 } 110 111 track = remap[track]; 112 113 if (track < 1 || track > maxTrack) 114 { 115 Con_DPrintf("CDAudio: Bad track number %u.\n", track); 116 return; 117 } 118 119 // don't try to play a non-audio track 120 entry.cdte_track = track; 121 entry.cdte_format = CDROM_MSF; 122 if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 ) 123 { 124 Con_DPrintf("ioctl cdromreadtocentry failed\n"); 125 return; 126 } 127 if (entry.cdte_ctrl == CDROM_DATA_TRACK) 128 { 129 Con_Printf("CDAudio: track %i is not audio\n", track); 130 return; 131 } 132 133 if (playing) 134 { 135 if (playTrack == track) 136 return; 137 CDAudio_Stop(); 138 } 139 140 ti.cdti_trk0 = track; 141 ti.cdti_trk1 = track; 142 ti.cdti_ind0 = 1; 143 ti.cdti_ind1 = 99; 144 145 if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 ) 146 { 147 Con_DPrintf("ioctl cdromplaytrkind failed\n"); 148 return; 149 } 150 151 if ( ioctl(cdfile, CDROMRESUME) == -1 ) 152 Con_DPrintf("ioctl cdromresume failed\n"); 153 154 playLooping = looping; 155 playTrack = track; 156 playing = true; 157 158 if (cdvolume == 0.0) 159 CDAudio_Pause (); 160} 161 162 163void CDAudio_Stop(void) 164{ 165 if (cdfile == -1 || !enabled) 166 return; 167 168 if (!playing) 169 return; 170 171 if ( ioctl(cdfile, CDROMSTOP) == -1 ) 172 Con_DPrintf("ioctl cdromstop failed (%d)\n", errno); 173 174 wasPlaying = false; 175 playing = false; 176} 177 178void CDAudio_Pause(void) 179{ 180 if (cdfile == -1 || !enabled) 181 return; 182 183 if (!playing) 184 return; 185 186 if ( ioctl(cdfile, CDROMPAUSE) == -1 ) 187 Con_DPrintf("ioctl cdrompause failed\n"); 188 189 wasPlaying = playing; 190 playing = false; 191} 192 193 194void CDAudio_Resume(void) 195{ 196 if (cdfile == -1 || !enabled) 197 return; 198 199 if (!cdValid) 200 return; 201 202 if (!wasPlaying) 203 return; 204 205 if ( ioctl(cdfile, CDROMRESUME) == -1 ) 206 Con_DPrintf("ioctl cdromresume failed\n"); 207 playing = true; 208} 209 210static void CD_f (void) 211{ 212 char *command; 213 int ret; 214 int n; 215 216 if (Cmd_Argc() < 2) 217 return; 218 219 command = Cmd_Argv (1); 220 221 if (Q_strcasecmp(command, "on") == 0) 222 { 223 enabled = true; 224 return; 225 } 226 227 if (Q_strcasecmp(command, "off") == 0) 228 { 229 if (playing) 230 CDAudio_Stop(); 231 enabled = false; 232 return; 233 } 234 235 if (Q_strcasecmp(command, "reset") == 0) 236 { 237 enabled = true; 238 if (playing) 239 CDAudio_Stop(); 240 for (n = 0; n < 100; n++) 241 remap[n] = n; 242 CDAudio_GetAudioDiskInfo(); 243 return; 244 } 245 246 if (Q_strcasecmp(command, "remap") == 0) 247 { 248 ret = Cmd_Argc() - 2; 249 if (ret <= 0) 250 { 251 for (n = 1; n < 100; n++) 252 if (remap[n] != n) 253 Con_Printf(" %u -> %u\n", n, remap[n]); 254 return; 255 } 256 for (n = 1; n <= ret; n++) 257 remap[n] = Q_atoi(Cmd_Argv (n+1)); 258 return; 259 } 260 261 if (Q_strcasecmp(command, "close") == 0) 262 { 263 CDAudio_CloseDoor(); 264 return; 265 } 266 267 if (!cdValid) 268 { 269 CDAudio_GetAudioDiskInfo(); 270 if (!cdValid) 271 { 272 Con_Printf("No CD in player.\n"); 273 return; 274 } 275 } 276 277 if (Q_strcasecmp(command, "play") == 0) 278 { 279 CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), false); 280 return; 281 } 282 283 if (Q_strcasecmp(command, "loop") == 0) 284 { 285 CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), true); 286 return; 287 } 288 289 if (Q_strcasecmp(command, "stop") == 0) 290 { 291 CDAudio_Stop(); 292 return; 293 } 294 295 if (Q_strcasecmp(command, "pause") == 0) 296 { 297 CDAudio_Pause(); 298 return; 299 } 300 301 if (Q_strcasecmp(command, "resume") == 0) 302 { 303 CDAudio_Resume(); 304 return; 305 } 306 307 if (Q_strcasecmp(command, "eject") == 0) 308 { 309 if (playing) 310 CDAudio_Stop(); 311 CDAudio_Eject(); 312 cdValid = false; 313 return; 314 } 315 316 if (Q_strcasecmp(command, "info") == 0) 317 { 318 Con_Printf("%u tracks\n", maxTrack); 319 if (playing) 320 Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); 321 else if (wasPlaying) 322 Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack); 323 Con_Printf("Volume is %f\n", cdvolume); 324 return; 325 } 326} 327 328void CDAudio_Update(void) 329{ 330 struct cdrom_subchnl subchnl; 331 static time_t lastchk; 332 333 if (!enabled) 334 return; 335 336 if (bgmvolume.value != cdvolume) 337 { 338 if (cdvolume) 339 { 340 Cvar_SetValue ("bgmvolume", 0.0); 341 cdvolume = bgmvolume.value; 342 CDAudio_Pause (); 343 } 344 else 345 { 346 Cvar_SetValue ("bgmvolume", 1.0); 347 cdvolume = bgmvolume.value; 348 CDAudio_Resume (); 349 } 350 } 351 352 if (playing && lastchk < time(NULL)) { 353 lastchk = time(NULL) + 2; //two seconds between chks 354 subchnl.cdsc_format = CDROM_MSF; 355 if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) { 356 Con_DPrintf("ioctl cdromsubchnl failed\n"); 357 playing = false; 358 return; 359 } 360 if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY && 361 subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) { 362 playing = false; 363 if (playLooping) 364 CDAudio_Play(playTrack, true); 365 } 366 } 367} 368 369int CDAudio_Init(void) 370{ 371 int i; 372 373#if 0 374 if (cls.state == ca_dedicated) 375 return -1; 376#endif 377 378 if (COM_CheckParm("-nocdaudio")) 379 return -1; 380 381 if ((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) { 382 strncpy(cd_dev, com_argv[i + 1], sizeof(cd_dev)); 383 cd_dev[sizeof(cd_dev) - 1] = 0; 384 } 385 386 if ((cdfile = open(cd_dev, O_RDONLY)) == -1) { 387 Con_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno); 388 cdfile = -1; 389 return -1; 390 } 391 392 for (i = 0; i < 100; i++) 393 remap[i] = i; 394 initialized = true; 395 enabled = true; 396 397 if (CDAudio_GetAudioDiskInfo()) 398 { 399 Con_Printf("CDAudio_Init: No CD in player.\n"); 400 cdValid = false; 401 } 402 403 Cmd_AddCommand ("cd", CD_f); 404 405 Con_Printf("CD Audio Initialized\n"); 406 407 return 0; 408} 409 410 411void CDAudio_Shutdown(void) 412{ 413 if (!initialized) 414 return; 415 CDAudio_Stop(); 416 close(cdfile); 417 cdfile = -1; 418} 419