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