1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: snd_audiocd_bsd.cpp 3866 2008-11-17 18:58:49Z dj_jl $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 // This is not compatible with Solaris
29 #ifndef __sun__
30
31 #include <unistd.h>
32 #include <sys/ioctl.h>
33 #include <sys/file.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <time.h>
37 #include <errno.h>
38 #include <sys/cdio.h>
39
40 #include "gamedefs.h"
41 #include "snd_local.h"
42
43 // MACROS ------------------------------------------------------------------
44
45 // TYPES -------------------------------------------------------------------
46
47 class VBsdCDAudioDevice : public VCDAudioDevice
48 {
49 public:
50 int CDFile;
51
52 void Init();
53 void Update();
54 void Shutdown();
55 void GetInfo();
56 void Play(int, bool);
57 void Pause();
58 void Resume();
59 void Stop();
60 void OpenDoor();
61 void CloseDoor();
62 };
63
64 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
65
66 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
67
68 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
69
70 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
71
72 // PUBLIC DATA DEFINITIONS -------------------------------------------------
73
74 IMPLEMENT_CD_AUDIO_DEVICE(VBsdCDAudioDevice, CDDRV_Default, "Default",
75 "BSD CD audio device", NULL);
76
77 // PRIVATE DATA DEFINITIONS ------------------------------------------------
78
79 // CODE --------------------------------------------------------------------
80
81 //==========================================================================
82 //
83 // VBsdCDAudioDevice::Init
84 //
85 //==========================================================================
86
Init()87 void VBsdCDAudioDevice::Init()
88 {
89 guard(VBsdCDAudioDevice::Init);
90 int i;
91
92 if (GArgs.CheckParm("-nosound") || GArgs.CheckParm("-nocdaudio"))
93 {
94 return;
95 }
96
97 VStr cd_dev = "/dev/cdrom";
98 const char* p = GArgs.CheckValue("-cddev");
99 if (p)
100 {
101 cd_dev = p;
102 }
103
104 CDFile = open(*cd_dev, O_RDONLY);
105 if (CDFile == -1)
106 {
107 GCon->Logf(NAME_Init, "CD_Init: open of \"%s\" failed (%d)",
108 *cd_dev, errno);
109 CDFile = -1;
110 return;
111 }
112
113 for (i = 0; i < 100; i++)
114 Remap[i] = i;
115 Initialised = true;
116 Enabled = true;
117
118 GetInfo();
119 if (!CDValid)
120 {
121 GCon->Log(NAME_Init, "CD_Init: No CD in player.");
122 }
123
124 GCon->Log(NAME_Init, "CD Audio Initialised");
125 unguard;
126 }
127
128 //==========================================================================
129 //
130 // VBsdCDAudioDevice::Update
131 //
132 //==========================================================================
133
Update()134 void VBsdCDAudioDevice::Update()
135 {
136 guard(VBsdCDAudioDevice::Update);
137 struct ioc_read_subchannel subchnl;
138 struct cd_sub_channel_info data;
139 static time_t lastchk;
140
141 if (!Initialised)
142 return;
143
144 if (!Enabled)
145 return;
146
147 if (Playing && lastchk < time(NULL))
148 {
149 lastchk = time(NULL) + 2; //two seconds between chks
150 subchnl.data = &data;
151 subchnl.data_len = sizeof(data);
152 subchnl.address_format = CD_MSF_FORMAT;
153 subchnl.data_format = CD_CURRENT_POSITION;
154 if (ioctl(CDFile, CDIOCREADSUBCHANNEL, (char*) &subchnl) == -1 )
155 {
156 GCon->Log(NAME_Dev, "ioctl CDIOCREADSUBCHANNEL failed");
157 Playing = false;
158 return;
159 }
160 if (subchnl.data->header.audio_status != CD_AS_PLAY_IN_PROGRESS &&
161 subchnl.data->header.audio_status != CD_AS_PLAY_PAUSED)
162 {
163 Playing = false;
164 if (PlayLooping)
165 Play(PlayTrack, true);
166 }
167 }
168 unguard;
169 }
170
171 //==========================================================================
172 //
173 // VBsdCDAudioDevice::Shutdown
174 //
175 //==========================================================================
176
Shutdown()177 void VBsdCDAudioDevice::Shutdown()
178 {
179 guard(VBsdCDAudioDevice::Shutdown);
180 if (!Initialised)
181 return;
182
183 Stop();
184 close(CDFile);
185 CDFile = -1;
186 Initialised = false;
187 unguard;
188 }
189
190 //==========================================================================
191 //
192 // VBsdCDAudioDevice::GetInfo
193 //
194 //==========================================================================
195
GetInfo()196 void VBsdCDAudioDevice::GetInfo()
197 {
198 guard(VBsdCDAudioDevice::GetInfo);
199 struct ioc_toc_header tochdr;
200
201 CDValid = false;
202
203 if (ioctl(CDFile, CDIOREADTOCHEADER, &tochdr) == -1)
204 {
205 GCon->Log(NAME_Dev, "ioctl CDIOREADTOCHEADER failed");
206 return;
207 }
208
209 if (tochdr.starting_track < 1)
210 {
211 GCon->Log(NAME_Dev, "CDAudio: no music tracks");
212 return;
213 }
214
215 CDValid = true;
216 MaxTrack = tochdr.ending_track;
217 unguard;
218 }
219
220 //==========================================================================
221 //
222 // VBsdCDAudioDevice::Play
223 //
224 //==========================================================================
225
Play(int track,bool looping)226 void VBsdCDAudioDevice::Play(int track, bool looping)
227 {
228 guard(VBsdCDAudioDevice::Play);
229 struct ioc_play_track ti;
230
231 if (!CDValid)
232 {
233 GetInfo();
234 if (!CDValid)
235 return;
236 }
237
238 track = Remap[track];
239
240 if (track < 1 || track > MaxTrack)
241 {
242 GCon->Logf(NAME_Dev, "CDAudio: Bad track number %d.", track);
243 return;
244 }
245
246 /*
247 // don't try to play a non-audio track
248 struct ioc_read_toc_single_entry entry;
249 entry.cdte_track = track;
250 entry.cdte_format = CDROM_MSF;
251 if (ioctl(CDFile, CDROMREADTOCENTRY, &entry) == -1)
252 {
253 GCon->Log(NAME_Dev, "ioctl cdromreadtocentry failed");
254 return;
255 }
256 if (entry.cdte_ctrl == CDROM_DATA_TRACK)
257 {
258 GCon->Logf("CDAudio: track %d is not audio", track);
259 return;
260 }
261 */
262 if (Playing)
263 {
264 if (PlayTrack == track)
265 return;
266 Stop();
267 }
268
269 ti.start_track = track;
270 ti.end_track = track;
271 ti.start_index = 1;
272 ti.end_index = 99;
273
274 if (ioctl(CDFile, CDIOCPLAYTRACKS, &ti) == -1)
275 {
276 GCon->Log(NAME_Dev, "ioctl CDIOCPLAYTRACKS failed");
277 return;
278 }
279
280 if (ioctl(CDFile, CDIOCRESUME) == -1)
281 GCon->Log(NAME_Dev, "ioctl CDIOCRESUME failed");
282
283 PlayLooping = looping;
284 PlayTrack = track;
285 Playing = true;
286 unguard;
287 }
288
289 //==========================================================================
290 //
291 // VBsdCDAudioDevice::Pause
292 //
293 //==========================================================================
294
Pause()295 void VBsdCDAudioDevice::Pause()
296 {
297 guard(VBsdCDAudioDevice::Pause);
298 if (!Playing)
299 return;
300
301 if (ioctl(CDFile, CDIOCPAUSE) == -1)
302 GCon->Log(NAME_Dev, "ioctl CDIOCPAUSE failed");
303
304 WasPlaying = Playing;
305 Playing = false;
306 unguard;
307 }
308
309 //==========================================================================
310 //
311 // VBsdCDAudioDevice::Resume
312 //
313 //==========================================================================
314
Resume()315 void VBsdCDAudioDevice::Resume()
316 {
317 guard(VBsdCDAudioDevice::Resume);
318 if (!WasPlaying)
319 return;
320
321 if (ioctl(CDFile, CDIOCRESUME) == -1)
322 GCon->Log(NAME_Dev, "ioctl CDIOCRESUME failed");
323
324 Playing = true;
325 unguard;
326 }
327
328 //==========================================================================
329 //
330 // VBsdCDAudioDevice::Stop
331 //
332 //==========================================================================
333
Stop()334 void VBsdCDAudioDevice::Stop()
335 {
336 guard(VBsdCDAudioDevice::Stop);
337 if (!Playing)
338 return;
339
340 if (ioctl(CDFile, CDIOCSTOP) == -1)
341 GCon->Log(NAME_Dev, "ioctl CDIOCSTOP failed");
342
343 WasPlaying = false;
344 Playing = false;
345 unguard;
346 }
347
348 //==========================================================================
349 //
350 // VBsdCDAudioDevice::OpenDoor
351 //
352 //==========================================================================
353
OpenDoor()354 void VBsdCDAudioDevice::OpenDoor()
355 {
356 guard(VBsdCDAudioDevice::OpenDoor);
357 if (ioctl(CDFile, CDIOCEJECT) == -1)
358 GCon->Log(NAME_Dev, "ioctl CDIOCEJECT failed");
359 unguard;
360 }
361
362 //==========================================================================
363 //
364 // VBsdCDAudioDevice::CloseDoor
365 //
366 //==========================================================================
367
CloseDoor()368 void VBsdCDAudioDevice::CloseDoor()
369 {
370 guard(VBsdCDAudioDevice::CloseDoor);
371 if (ioctl(CDFile, CDIOCCLOSE) == -1)
372 GCon->Log(NAME_Dev, "ioctl CDIOCCLOSE failed");
373 unguard;
374 }
375
376 #endif
377