1/* ++++++++++
2	play.cpp
3	Copyright (C) 1995 Be Incorporated.  All Rights Reserved.
4
5	modified on November 03, 2003 by Jerome Duval
6+++++ */
7/*
8 * was released as sample code; source:
9 * ftp://planetmirror.com/raid/13/beos/samples/media_kit/obsolete/play.cpp
10 */
11
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <scsi.h>
17#include <unistd.h>
18#include <Directory.h>
19#include <Entry.h>
20#include <Path.h>
21
22
23/* ----------
24	play requested track
25----- */
26
27void
28play(int id, scsi_play_track *track)
29{
30	track->start_index = 1;
31	track->end_track = 99;
32	track->end_index = 1;
33	if (!ioctl(id, B_SCSI_PLAY_TRACK, track))
34		printf("Playing audio...\n");
35	else
36		printf("Play audio failed\n");
37}
38
39
40/* ----------
41	show valid cd-rom id's
42	(from /boot/optional/sample-code/interface_kit/CDButton/CDEngine.cpp)
43----- */
44
45static void
46try_dir(const char *directory, long *count, bool show)
47{
48	bool add = false;
49	BDirectory dir;
50	dir.SetTo(directory);
51	if(dir.InitCheck() != B_NO_ERROR) {
52		return;
53	}
54	dir.Rewind();
55	BEntry entry;
56	while(dir.GetNextEntry(&entry) >= 0) {
57		BPath path;
58		const char *name;
59		entry_ref e;
60
61		if(entry.GetPath(&path) != B_NO_ERROR)
62			continue;
63		name = path.Path();
64
65		if(entry.GetRef(&e) != B_NO_ERROR)
66			continue;
67
68		if(entry.IsDirectory()) {
69			if(strcmp(e.name, "floppy") == 0)
70				continue; // ignore floppy (it is not silent)
71			try_dir(name, count, show);
72		}
73		else {
74			int devfd;
75			device_geometry g;
76
77			if(strcmp(e.name, "raw") != 0)
78				continue; // ignore partitions
79
80			devfd = open(name, O_RDONLY);
81			if(devfd < 0)
82				continue;
83
84			if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
85				if(g.device_type == B_CD)
86				{
87					add = true;
88				}
89			}
90			close(devfd);
91		}
92		if (add) {
93			*count += 1;
94			if (show)
95				printf("   %s\n", name);
96		}
97	}
98}
99
100/* ----------
101	show valid cd-rom id's
102----- */
103
104int count_ids(bool show)
105{
106	long		count = 0;
107
108	try_dir("/dev/disk", &count, show);
109	return (count);
110}
111
112
113/* ----------
114	main
115----- */
116
117int
118main (int argc, char **argv)
119{
120	int					id;
121	int					i;
122	int					length;
123	int					start;
124	long				command;
125	long				req_track = 0;
126	long				vol;
127	long				index;
128	ulong				frames;
129	short				tmp;
130	uchar				*buf;
131	scsi_toc			toc;
132	scsi_play_track		track;
133	scsi_volume			volume;
134	scsi_position		position;
135	scsi_read_cd		read_cd;
136	scsi_scan			scan;
137	FILE				*f;
138
139	length = count_ids(FALSE);
140	if (!length) {
141		printf("No CD-ROM drive present.\n");
142		return 0;
143	}
144	errno = 0;
145
146	if (argc > 2)
147		command = strtol (argv[2], 0, 0);
148	else
149		command = 0;
150
151	if ((argc < 2) || (errno) ||
152		(command < 0) || (command > 8)) {
153		printf("Usage:  play device [command [param]]\n\n");
154		printf(" Valid devices:\n");
155		count_ids(TRUE);
156		printf("\n");
157		printf(" Valid commands:\n");
158		printf("   0 [n] - play from track n [1]\n");
159		printf("   1     - pause\n");
160		printf("   2     - resume\n");
161		printf("   3     - stop\n");
162		printf("   4     - eject\n");
163		printf("   5 n   - set volume to n (0 <= n <= 255)\n");
164		printf("   6     - current position\n");
165		printf("   7 n s - save track n to file s\n");
166		printf("   8 [c] - scan in direction c (f = forward, b = backward)\n\n");
167		return 0;
168	}
169
170	if ((id = open(argv[1], 0)) >= 0) {
171		switch (command) {
172			case 0:
173				if (!ioctl(id, B_SCSI_GET_TOC, &toc)) {
174					track.start_track = 0;
175					for (i = toc.toc_data[2]; i <= toc.toc_data[3]; i++) {
176						length = (toc.toc_data[(((i + 1) - toc.toc_data[2]) * 8) + 4 + 5] * 60) +
177						 (toc.toc_data[(((i + 1) - toc.toc_data[2]) * 8) + 4 + 6]);
178						length -= ((toc.toc_data[((i - toc.toc_data[2]) * 8) + 4 + 5] * 60) +
179						  (toc.toc_data[((i - toc.toc_data[2]) * 8) + 4 + 6]));
180						printf(" Track %.2d: %.2d:%.2d - ", i, length / 60, length % 60);
181						if (toc.toc_data[((i - toc.toc_data[2]) * 8) + 4 + 1] & 4)
182							printf("DATA\n");
183						else {
184							printf("AUDIO\n");
185							if (!track.start_track)
186								track.start_track = i;
187						}
188					}
189					if (track.start_track) {
190						if (argc > 3) {
191							req_track = strtol (argv[3], 0, 0);
192							if ((req_track < toc.toc_data[2]) || (req_track > toc.toc_data[3]))
193								printf("Requested track is out of range\n");
194							else
195							if (toc.toc_data[((req_track - toc.toc_data[2]) * 8) + 4 + 1] & 4)
196								printf("Requested track is not an audio track\n");
197							else {
198								track.start_track = req_track;
199								play(id, &track);
200							}
201						}
202						else
203							play(id, &track);
204					}
205					else
206						printf("No audio tracks on CD\n");
207				}
208				else
209					printf("Could not read table of contents on CD\n");
210				break;
211
212			case 1:
213				printf("Pausing audio\n");
214				ioctl(id, B_SCSI_PAUSE_AUDIO);
215				break;
216
217			case 2:
218				printf("Resuming audio\n");
219				ioctl(id, B_SCSI_RESUME_AUDIO);
220				break;
221
222			case 3:
223				printf("Stopping audio\n");
224				ioctl(id, B_SCSI_STOP_AUDIO);
225				break;
226
227			case 4:
228				printf("Ejecting CD\n");
229				ioctl(id, B_SCSI_EJECT);
230				break;
231
232			case 5:
233				if (argc < 4)
234					printf("Specify the volume\n");
235				else {
236					vol = strtol (argv[3], 0, 0);
237					if ((vol < 0) || (vol > 255))
238						printf("Volume is out of range (0 - 255)\n");
239					else {
240						printf("Setting volume to %ld\n", vol);
241						volume.port0_volume = vol;
242						volume.port1_volume = vol;
243						volume.flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME;
244						ioctl(id, B_SCSI_SET_VOLUME, &volume);
245					}
246				}
247				break;
248
249			case 6:
250				if (ioctl(id, B_SCSI_GET_POSITION, &position) == B_ERROR)
251					printf("Could not get current position\n");
252				else {
253					switch(position.position[1]) {
254						case 0x00:
255							printf("Position not supported by device\n");
256							break;
257
258						case 0x11:
259							printf("Playing track %d (%.2d:%.2d:%.2d)\n",
260								position.position[6],
261								position.position[9],
262								position.position[10],
263								position.position[11]);
264							break;
265
266						case 0x12:
267							printf("Paused at track %d (%.2d:%.2d:%.2d)\n",
268								position.position[6],
269								position.position[9],
270								position.position[10],
271								position.position[11]);
272							break;
273
274						case 0x13:
275							printf("Play has been completed\n");
276							break;
277
278						case 0x14:
279							printf("Play stopped due to error\n");
280							break;
281
282						case 0x15:
283							printf("No status to return\n");
284							break;
285
286						default:
287							printf("Unexpected result: %.2x\n",
288								position.position[1]);
289					}
290				}
291				break;
292
293			case 7:
294				if (argc < 4) {
295					printf("Specify the track to save\n");
296					break;
297				}
298
299				if (argc < 5) {
300					printf("Specify a file to save to\n");
301					break;
302				}
303
304				f = fopen(argv[4], "w");
305				if (f == NULL) {
306					printf("Un-able to create %s\n", argv[4]);
307					break;
308				}
309
310				req_track = strtol (argv[3], 0, 0);
311				if (!ioctl(id, B_SCSI_GET_TOC, &toc)) {
312					if (req_track > toc.toc_data[3]) {
313						printf("Track %ld is out of range [%d-%d]\n", req_track,
314								toc.toc_data[2], toc.toc_data[3]);
315						break;
316					}
317					index = 0;
318					while (toc.toc_data[4 + (index * 8) + 2] != req_track) {
319						index++;
320					}
321					start = (toc.toc_data[4 + (index * 8) + 5] * 60 * 75) +
322							(toc.toc_data[4 + (index * 8) + 6] * 75) +
323							 toc.toc_data[4 + (index * 8) + 7];
324					index++;
325					length = ((toc.toc_data[4 + (index * 8) + 5] * 60 * 75) +
326							  (toc.toc_data[4 + (index * 8) + 6] * 75) +
327							   toc.toc_data[4 + (index * 8) + 7]) - start;
328
329					frames = min_c(1 * 75, (int) length);
330					read_cd.buffer = (char *)malloc(frames * 2352);
331
332					printf("Saving track %ld to %s...\n", req_track, argv[4]);
333					while (length) {
334						index = start;
335						read_cd.start_m = index / (60 * 75);
336						index %= (60 * 75);
337						read_cd.start_s = index / 75;
338						index %= 75;
339						read_cd.start_f = index;
340
341						index = min_c((int)frames, length);
342						read_cd.buffer_length = index * 2352;
343						length -= index;
344						start += index;
345
346						read_cd.length_m = index / (60 * 75);
347						index %= (60 * 75);
348						read_cd.length_s = index / 75;
349						index %= 75;
350						read_cd.length_f = index;
351
352						for (i = 0; i < 5; i++)
353							if (ioctl(id, B_SCSI_READ_CD, &read_cd) == B_NO_ERROR)
354								break;
355						if (i == 5) {
356							printf("Error reading CD-DA\n");
357							break;
358						}
359						buf = (uchar *)read_cd.buffer;
360						for (i = 0; i < read_cd.buffer_length; i += 2) {
361							tmp = (short)((buf[1] << 8) | buf[0]);
362							*(short *)(&buf[0]) = tmp;
363							buf += 2;
364						}
365						fwrite(read_cd.buffer, read_cd.buffer_length, 1, f);
366					}
367					free(read_cd.buffer);
368					fclose(f);
369				}
370				else
371					printf("Failed to read table of contents\n");
372				break;
373
374			case 8:
375				if (argc == 4) {
376					if (!strcmp(argv[3], "f") || !strcmp(argv[3], "F"))
377						scan.direction = 1;
378					else if (!strcmp(argv[3], "b") || !strcmp(argv[3], "B"))
379						scan.direction = -1;
380					else {
381						printf("Use 'f' to scan forward, 'b' to scan backwards\n");
382						break;
383					}
384				}
385				else
386					scan.direction = 0;
387				scan.speed = 0;
388				if (ioctl(id, B_SCSI_SCAN, &scan) == B_ERROR)
389					printf("Error trying to scan\n");
390				else
391					printf("Scanning...\n");
392				break;
393		}
394		close(id);
395	}
396	else
397		printf("CD player is empty or invalid scsi-id\n");
398	return 0;
399}
400