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