Subject: bin/13682: cdplay(1) does not support random playing mode.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <svs@ropnet.ru>
List: netbsd-bugs
Date: 08/11/2001 07:43:16
>Number:         13682
>Category:       bin
>Synopsis:       cdplay(1) does not support random playing mode.
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Aug 11 07:40:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Sergey Svishchev
>Release:        1.5X
>Organization:
>Environment:
>Description:
cdplay(1) can only play single tracks, track ranges, but not tracks 
chosen randomly.

Also, it does not report current index when playing a CD that has them.
>How-To-Repeat:

>Fix:
Index: cdplay.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/cdplay/cdplay.c,v
retrieving revision 1.13
diff -u -r1.13 cdplay.c
--- cdplay.c	2001/07/01 05:04:26	1.13
+++ cdplay.c	2001/08/11 14:07:07
@@ -68,6 +68,7 @@
 #include <err.h>
 #include <errno.h>
 #include <histedit.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -99,6 +100,7 @@
 #define CMD_STATUS      14
 #define CMD_NEXT	15
 #define CMD_PREV	16
+#define CMD_SHUFFLE	17
 #define STATUS_AUDIO    0x1
 #define STATUS_MEDIA    0x2
 #define STATUS_VOLUME   0x4
@@ -114,17 +116,18 @@
 { CMD_HELP,     "?",            1, 0 },
 { CMD_HELP,     "help",         1, "" },
 { CMD_INFO,     "info",         1, "" },
+{ CMD_NEXT,	"next",		1, "" },
 { CMD_PAUSE,    "pause",        2, "" },
 { CMD_PLAY,     "play",         1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" },
 { CMD_PLAY,     "play",         1, "track1[.index1] [track2[.index2]]" },
 { CMD_PLAY,     "play",         1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" },
 { CMD_PLAY,     "play",         1, "[#block [len]]" },
 { CMD_PREV,	"prev",		2, "" },
-{ CMD_NEXT,	"next",		1, "" },
 { CMD_QUIT,     "quit",         1, "" },
 { CMD_RESET,    "reset",        4, "" },
 { CMD_RESUME,   "resume",       1, "" },
 { CMD_SET,      "set",          2, "msf | lba" },
+{ CMD_SHUFFLE,  "shuffle",      2, "" },
 { CMD_STATUS,   "status",       1, "[audio | media | volume]" },
 { CMD_STOP,     "stop",         3, "" },
 { CMD_VOLUME,   "volume",       1, "<l> <r> | left | right | mute | mono | stereo" },
@@ -136,6 +139,9 @@
 const char *cdname;
 int     fd = -1;
 int     msf = 1;
+int     shuffle = 0;
+int     interactive = 1;
+struct itimerval itv_timer;
 
 /* for histedit */
 History *hist;
@@ -147,7 +153,7 @@
 int	play_msf __P((int, int, int, int, int, int));
 int	play_track __P((int, int, int, int));
 int	get_vol __P((int *, int *));
-int	status __P((int *, int *, int *, int *));
+int	status __P((int *, int *, int *, int *, int *));
 int	opencd __P((void));
 int	play __P((char *));
 int	skip __P((int));
@@ -163,6 +169,7 @@
 void	help __P((void));
 void 	usage __P((void));
 char   *strstatus __P((int));
+void	sig_timer __P((int, int, struct sigcontext *));
 int 	main __P((int, char **));
 
 void
@@ -209,7 +216,8 @@
 	int cmd, len;
 	char *line;
 	const char *elline;
-	int scratch;
+	int scratch, rc;
+	struct sigaction sa_timer;
 
 	cdname = getenv("MUSIC_CD");
 	if (!cdname)
@@ -244,8 +252,10 @@
 	}
 	
 	opencd();
+	srandom(time(NULL));
 
 	if (argc > 0) {
+		interactive = 0;
 		for (p = buf; argc-- > 0; ++argv) {
 			len = strlen(*argv);
 
@@ -273,6 +283,13 @@
 	el_set(elptr, EL_HIST, history, hist);
 	el_source(elptr, NULL);
 
+	sigemptyset(&sa_timer.sa_mask);
+	sa_timer.sa_handler = (void (*)(int)) sig_timer;
+	sa_timer.sa_flags = SA_RESTART;
+	rc = sigaction(SIGALRM, &sa_timer, NULL);
+	if (rc < 0)
+		perror("sigaction");
+
 	for (;;) {
 		line = NULL;
 		do {
@@ -316,11 +333,8 @@
 	case CMD_CLOSE:
 		if (fd >= 0) {
 			ioctl(fd, CDIOCALLOW);
-			if ((rc = ioctl(fd, CDIOCCLOSE)) < 0)
-				return (rc);
-			close(fd);
-			fd = -1;
-			return (0);
+			ioctl(fd, CDIOCCLOSE);
+			return (-1);	/* close(fd) will get called if run() returns -1 */
 		}
 		break;
 	}
@@ -355,6 +369,8 @@
 
 	case CMD_EJECT:
 		ioctl(fd, CDIOCALLOW);
+		if (shuffle)
+			run(CMD_SHUFFLE, NULL);
 		if ((rc = ioctl(fd, CDIOCEJECT)) < 0)
 			return (rc);
 		return (0);
@@ -378,6 +394,25 @@
 	case CMD_NEXT:
 		return (skip(1));
 	
+	case CMD_SHUFFLE:
+		if (interactive == 0)
+			return (-1);
+		if (shuffle == 0) {
+			itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 1;
+			itv_timer.it_interval.tv_usec = itv_timer.it_value.tv_usec = 0;
+			rc = setitimer(ITIMER_REAL, &itv_timer, NULL);
+			if (rc == 0) {
+				shuffle = 1;
+				skip (0);
+			}
+		} else {
+			itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 0;
+			itv_timer.it_interval.tv_usec = itv_timer.it_value.tv_usec = 0;
+			rc = setitimer(ITIMER_REAL, &itv_timer, NULL);
+			shuffle = 0;
+		}
+		return (0);
+
 	case CMD_SET:
 		if (!strcasecmp(arg, "msf"))
 			msf = 1;
@@ -441,7 +476,7 @@
 
 	if (!arg || !*arg) {
 		/* Play the whole disc */
-		return (play_track(h.starting_track, 1, h.ending_track, 1));
+		return (play_track(h.starting_track, 1, h.ending_track, 99));
 	}
 	
 	if (strchr(arg, '#')) {
@@ -497,6 +532,11 @@
 			goto Play_Relative_Addresses;
 
 		tr2 = m2 = s2 = f2 = f1 = 0;
+		if (6 == sscanf(arg, "%d %d:%d %d %d:%d", &tr1, &m1, &s1, 
+		    &tr2, &m2, &s2))
+			goto Play_Relative_Addresses;
+
+		tr2 = m2 = s2 = f2 = f1 = 0;
 		if (6 == sscanf(arg, "%d %d:%d.%d %d:%d", &tr1, &m1, &s1, &f1,
 		    &m2, &s2))
 			goto Play_Relative_Addresses;
@@ -688,25 +728,47 @@
 	return (0);
 }
 
+void	
+sig_timer (sig, code, scp)
+	int sig, code;
+	struct sigcontext *scp;
+{
+	sigset_t anymore;
+
+	sigpending(&anymore);
+	if (sigismember(&anymore, SIGALRM)) 
+		return;
+	setitimer(ITIMER_REAL, &itv_timer, NULL);
+	if (fd != -1)
+		skip (0);
+}
+
 int
 skip(dir)
 	int dir;
 {
-	char str[4];
-	int rc, trk, m, s, f;
+	char str[8];
+	int rc, trk, idx, m, s, f;
 	struct ioc_toc_header h;
 	
 	if ((rc = ioctl(fd, CDIOREADTOCHEADER, &h)) <  0) {
-		printf("ioctl failed\n");
+		perror("skip: ioctl failed");
 		return (rc);
 	}
-	if ((rc = status(&trk, &m, &s, &f)) < 0) {
+	if ((rc = status(&trk, &idx, &m, &s, &f)) < 0) {
 		printf("status failed\n");
 		return (rc);
 	}
-	if (trk+dir > h.ending_track || trk+dir < h.starting_track)
-		return (0);
-	sprintf(str, "%d", trk+dir);
+	if (shuffle) {
+		if (dir == 0 && (rc == ASTS_PLAYING || rc == ASTS_PAUSED))
+			return 0;
+		dir = h.starting_track + random() % (h.ending_track - h.starting_track + 1);
+		snprintf(str, sizeof(str), "%d %d", dir, dir);
+	} else {
+		if (trk+dir > h.ending_track || trk+dir < h.starting_track)
+			return (0);
+		snprintf(str, sizeof(str), "%d", trk+dir);
+	}
 	return (play(str));
 }
 
@@ -739,7 +801,7 @@
 {
 	struct cd_sub_channel_info data;
 	struct ioc_read_subchannel ss;
-	int rc, trk, m, s, f;
+	int rc, trk, idx, m, s, f;
 	struct ioc_vol v;
 	int what = 0;
 	char *p;
@@ -764,13 +826,15 @@
 	if (!what)
 		what = STATUS_AUDIO | STATUS_MEDIA | STATUS_VOLUME;
 	if (what & STATUS_AUDIO) {
-		rc = status(&trk, &m, &s, &f);
+		rc = status(&trk, &idx, &m, &s, &f);
 		if (rc >= 0) {
 			printf("Audio status:\t%s\n", strstatus(rc));
 			printf("Current track:\t%d\n", trk);
+			printf("Current index:\t%d\n", idx);
 			printf("Position:\t%d:%02d.%02d\n", m, s, f);
 		} else
 			printf("Audio status:\tno info available\n");
+		printf("Shuffle play:\t%s\n", shuffle ? "on":"off");
 	}
 	if (what & STATUS_MEDIA) {
 		bzero(&ss, sizeof(ss));
@@ -920,6 +984,22 @@
 }
 
 int 
+play_msf(start_m, start_s, start_f, end_m, end_s, end_f)
+	int start_m, start_s, start_f, end_m, end_s, end_f;
+{
+	struct ioc_play_msf a;
+
+	a.start_m = start_m;
+	a.start_s = start_s;
+	a.start_f = start_f;
+	a.end_m = end_m;
+	a.end_s = end_s;
+	a.end_f = end_f;
+
+	return (ioctl(fd, CDIOCPLAYMSF, (char *) &a));
+}
+
+int 
 setvol(left, right)
 	int left, right;
 {
@@ -947,25 +1027,9 @@
 	return (ioctl(fd, CDIOREADTOCENTRYS, (char *)&t));
 }
 
-int 
-play_msf(start_m, start_s, start_f, end_m, end_s, end_f)
-	int start_m, start_s, start_f, end_m, end_s, end_f;
-{
-	struct ioc_play_msf a;
-
-	a.start_m = start_m;
-	a.start_s = start_s;
-	a.start_f = start_f;
-	a.end_m = end_m;
-	a.end_s = end_s;
-	a.end_f = end_f;
-
-	return (ioctl(fd, CDIOCPLAYMSF, (char *) &a));
-}
-
 int 
-status(trk, min, sec, frame)
-	int *trk, *min, *sec, *frame;
+status(trk, idx, min, sec, frame)
+	int *trk, *idx, *min, *sec, *frame;
 {
 	struct ioc_read_subchannel s;
 	struct cd_sub_channel_info data;
@@ -981,6 +1045,7 @@
 		return -1;
 
 	*trk = s.data->what.position.track_number;
+	*idx = s.data->what.position.index_number;
 	if (msf) {
 		*min = s.data->what.position.reladdr.msf.minute;
 		*sec = s.data->what.position.reladdr.msf.second;

>Release-Note:
>Audit-Trail:
>Unformatted: